Merge pull request #4190 from Snarling/testFixes

TESTS: Fixed tests for PRs and converted tests to TS.
This commit is contained in:
hydroflame 2022-10-04 11:44:29 -04:00 committed by GitHub
commit c4571efdbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 784 additions and 817 deletions

16
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "bitburner", "name": "bitburner",
"version": "1.7.0", "version": "2.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "bitburner", "name": "bitburner",
"version": "1.7.0", "version": "2.1.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"dependencies": { "dependencies": {
@ -6074,9 +6074,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001328", "version": "1.0.30001414",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001328.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
"integrity": "sha512-Ue55jHkR/s4r00FLNiX+hGMMuwml/QGqqzVeMQ5thUewznU2EdULFvI3JR7JJid6OrjJNfFvHY2G2dIjmRaDDQ==", "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -26801,9 +26801,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001328", "version": "1.0.30001414",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001328.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz",
"integrity": "sha512-Ue55jHkR/s4r00FLNiX+hGMMuwml/QGqqzVeMQ5thUewznU2EdULFvI3JR7JJid6OrjJNfFvHY2G2dIjmRaDDQ==" "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg=="
}, },
"caseless": { "caseless": {
"version": "0.12.0", "version": "0.12.0",

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers";
import { Player } from "../Player"; import { Player } from "../Player";
import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers";
import { IMap } from "../types"; import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
@ -30,422 +30,425 @@ class BitNode {
} }
export const BitNodes: IMap<BitNode> = {}; export const BitNodes: IMap<BitNode> = {};
export function initBitNodes() {
BitNodes["BitNode1"] = new BitNode( BitNodes["BitNode1"] = new BitNode(
1, 1,
0, 0,
"Source Genesis", "Source Genesis",
"The original BitNode", "The original BitNode",
( (
<> <>
The first BitNode created by the Enders to imprison the minds of humans. It became the prototype and The first BitNode created by the Enders to imprison the minds of humans. It became the prototype and
testing-grounds for all of the BitNodes that followed. testing-grounds for all of the BitNodes that followed.
<br /> <br />
<br /> <br />
This is the first BitNode that you play through. It has no special modifications or mechanics. This is the first BitNode that you play through. It has no special modifications or mechanics.
<br /> <br />
<br /> <br />
Destroying this BitNode will give you Source-File 1, or if you already have this Source-File it will upgrade its Destroying this BitNode will give you Source-File 1, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File lets the player start with 32GB of RAM on his/her home computer when level up to a maximum of 3. This Source-File lets the player start with 32GB of RAM on his/her home computer
entering a new BitNode, and also increases all of the player's multipliers by: when entering a new BitNode, and also increases all of the player's multipliers by:
<br /> <br />
<br /> <br />
Level 1: 16% Level 1: 16%
<br /> <br />
Level 2: 24% Level 2: 24%
<br /> <br />
Level 3: 28% Level 3: 28%
</> </>
), ),
); );
BitNodes["BitNode2"] = new BitNode( BitNodes["BitNode2"] = new BitNode(
2, 2,
0, 0,
"Rise of the Underworld", "Rise of the Underworld",
"From the shadows, they rose", //Gangs "From the shadows, they rose", //Gangs
( (
<> <>
From the shadows, they rose. From the shadows, they rose.
<br /> <br />
<br /> <br />
Organized crime groups quickly filled the void of power left behind from the collapse of Western government in the Organized crime groups quickly filled the void of power left behind from the collapse of Western government in
2050s. As society and civilization broke down, people quickly succumbed to the innate human impulse of evil and the 2050s. As society and civilization broke down, people quickly succumbed to the innate human impulse of evil
savagery. The organized crime factions quickly rose to the top of the modern world. and savagery. The organized crime factions quickly rose to the top of the modern world.
<br /> <br />
<br /> <br />
Certain Factions ({FactionNames.SlumSnakes}, {FactionNames.Tetrads}, {FactionNames.TheSyndicate},{" "} Certain Factions ({FactionNames.SlumSnakes}, {FactionNames.Tetrads}, {FactionNames.TheSyndicate},{" "}
{FactionNames.TheDarkArmy}, {FactionNames.SpeakersForTheDead}, {FactionNames.NiteSec}, {FactionNames.TheBlackHand} {FactionNames.TheDarkArmy}, {FactionNames.SpeakersForTheDead}, {FactionNames.NiteSec},{" "}
) give the player the ability to form and manage their own gangs. These gangs will earn the player money and {FactionNames.TheBlackHand}
reputation with the corresponding Faction ) give the player the ability to form and manage their own gangs. These gangs will earn the player money and
<br /> reputation with the corresponding Faction
Every Augmentation in the game will be available through the Factions listed above <br />
<br /> Every Augmentation in the game will be available through the Factions listed above
<br /> <br />
Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes once your karma decreases Destroying this BitNode will give you Source-File 2, or if you already have this Source-File it will upgrade its
to a certain value. It also increases the player's crime success rate, crime money, and charisma multipliers by: level up to a maximum of 3. This Source-File allows you to form gangs in other BitNodes once your karma
<br /> decreases to a certain value. It also increases the player's crime success rate, crime money, and charisma
<br /> multipliers by:
Level 1: 24% <br />
<br /> <br />
Level 2: 36% Level 1: 24%
<br /> <br />
Level 3: 42% Level 2: 36%
</> <br />
), Level 3: 42%
); </>
BitNodes["BitNode3"] = new BitNode( ),
3, );
0, BitNodes["BitNode3"] = new BitNode(
"Corporatocracy", 3,
"The Price of Civilization", 0,
( "Corporatocracy",
<> "The Price of Civilization",
Our greatest illusion is that a healthy society can revolve around a single-minded pursuit of wealth. (
<br /> <>
<br /> Our greatest illusion is that a healthy society can revolve around a single-minded pursuit of wealth.
Sometime in the early 21st century economic and political globalization turned the world into a corporatocracy, <br />
and it never looked back. Now, the privileged elite will happily bankrupt their own countrymen, decimate their own <br />
community, and evict their neighbors from houses in their desperate bid to increase their wealth. Sometime in the early 21st century economic and political globalization turned the world into a corporatocracy,
<br /> and it never looked back. Now, the privileged elite will happily bankrupt their own countrymen, decimate their
<br /> own community, and evict their neighbors from houses in their desperate bid to increase their wealth.
In this BitNode you can create and manage your own corporation. Running a successful corporation has the potential <br />
of generating massive profits. <br />
<br /> In this BitNode you can create and manage your own corporation. Running a successful corporation has the
<br /> potential of generating massive profits.
Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although some <br />
BitNodes will disable this mechanic) and level 3 permanently unlocks the full API. This Source-File also increases Destroying this BitNode will give you Source-File 3, or if you already have this Source-File it will upgrade its
your charisma and company salary multipliers by: level up to a maximum of 3. This Source-File lets you create corporations on other BitNodes (although some
<br /> BitNodes will disable this mechanic) and level 3 permanently unlocks the full API. This Source-File also
Level 1: 8% increases your charisma and company salary multipliers by:
<br /> <br />
Level 2: 12% Level 1: 8%
<br /> <br />
Level 3: 14% Level 2: 12%
</> <br />
), Level 3: 14%
); </>
BitNodes["BitNode4"] = new BitNode( ),
4, );
1, BitNodes["BitNode4"] = new BitNode(
"The Singularity", 4,
"The Man and the Machine", 1,
( "The Singularity",
<> "The Man and the Machine",
The Singularity has arrived. The human race is gone, replaced by artificially superintelligent beings that are (
more machine than man. <br /> <>
<br /> The Singularity has arrived. The human race is gone, replaced by artificially superintelligent beings that are
<br /> more machine than man. <br />
In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions. These <br />
functions allow you to control most aspects of the game through scripts, including working for factions/companies, <br />
purchasing/installing Augmentations, and creating programs. In this BitNode you will gain access to a new set of Netscript Functions known as Singularity Functions. These
<br /> functions allow you to control most aspects of the game through scripts, including working for
<br /> factions/companies, purchasing/installing Augmentations, and creating programs.
Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File lets you access and use the Singularity Functions in other BitNodes. <br />
Each level of this Source-File reduces the RAM cost of singularity functions: Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will upgrade its
<br /> level up to a maximum of 3. This Source-File lets you access and use the Singularity Functions in other
Level 1: 16x BitNodes. Each level of this Source-File reduces the RAM cost of singularity functions:
<br /> <br />
Level 2: 4x Level 1: 16x
<br /> <br />
Level 3: 1x Level 2: 4x
</> <br />
), Level 3: 1x
); </>
BitNodes["BitNode5"] = new BitNode( ),
5, );
1, BitNodes["BitNode5"] = new BitNode(
"Artificial Intelligence", 5,
"Posthuman", 1,
( "Artificial Intelligence",
<> "Posthuman",
They said it couldn't be done. They said the human brain, along with its consciousness and intelligence, couldn't (
be replicated. They said the complexity of the brain results from unpredictable, nonlinear interactions that <>
couldn't be modeled by 1's and 0's. They were wrong. They said it couldn't be done. They said the human brain, along with its consciousness and intelligence,
<br /> couldn't be replicated. They said the complexity of the brain results from unpredictable, nonlinear interactions
<br /> that couldn't be modeled by 1's and 0's. They were wrong.
Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. Intelligence is <br />
unique because it is permanent and persistent (it never gets reset back to 1). However gaining Intelligence Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will upgrade its
experience is much slower than other stats. Higher Intelligence levels will boost your production for many actions level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. Intelligence is
in the game. <br /> unique because it is permanent and persistent (it never gets reset back to 1). However gaining Intelligence
<br /> experience is much slower than other stats. Higher Intelligence levels will boost your production for many
In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with actions in the game. <br />
Formulas.exe, and will also raise all of your hacking-related multipliers by: <br />
<br /> In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with
<br /> Formulas.exe, and will also raise all of your hacking-related multipliers by:
Level 1: 8% <br />
<br /> <br />
Level 2: 12% Level 1: 8%
<br /> <br />
Level 3: 14% Level 2: 12%
</> <br />
), Level 3: 14%
); </>
BitNodes["BitNode6"] = new BitNode( ),
6, );
1, BitNodes["BitNode6"] = new BitNode(
FactionNames.Bladeburners, 6,
"Like Tears in Rain", 1,
( FactionNames.Bladeburners,
<> "Like Tears in Rain",
In the middle of the 21st century, {FactionNames.OmniTekIncorporated} began designing and manufacturing advanced (
synthetic androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth <>
generation of their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was In the middle of the 21st century, {FactionNames.OmniTekIncorporated} began designing and manufacturing advanced
the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more synthetic androids, or Synthoids for short. They achieved a major technological breakthrough in the sixth
intelligent than the humans that had created them. generation of their Synthoid design, called MK-VI, by developing a hyperintelligent AI. Many argue that this was
<br /> the first sentient AI ever created. This resulted in Synthoid models that were stronger, faster, and more
<br /> intelligent than the humans that had created them.
In this BitNode you will be able to access the {FactionNames.Bladeburners} Division at the NSA, which provides a <br />
new mechanic for progression. <br />
<br /> In this BitNode you will be able to access the {FactionNames.Bladeburners} Division at the NSA, which provides a
<br /> new mechanic for progression.
Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File allows you to access the NSA's {FactionNames.Bladeburners} Division <br />
in other BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade its
combat stats by: level up to a maximum of 3. This Source-File allows you to access the NSA's {FactionNames.Bladeburners} Division
<br /> in other BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your
<br /> combat stats by:
Level 1: 8% <br />
<br /> <br />
Level 2: 12% Level 1: 8%
<br /> <br />
Level 3: 14% Level 2: 12%
</> <br />
), Level 3: 14%
); </>
BitNodes["BitNode7"] = new BitNode( ),
7, );
2, BitNodes["BitNode7"] = new BitNode(
`${FactionNames.Bladeburners} 2079`, 7,
"More human than humans", 2,
( `${FactionNames.Bladeburners} 2079`,
<> "More human than humans",
In the middle of the 21st century, you were doing cutting-edge work at {FactionNames.OmniTekIncorporated} as part (
of the AI design team for advanced synthetic androids, or Synthoids for short. You helped achieve a major <>
technological breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing a In the middle of the 21st century, you were doing cutting-edge work at {FactionNames.OmniTekIncorporated} as
hyperintelligent AI. Many argue that this was the first sentient AI ever created. This resulted in Synthoid models part of the AI design team for advanced synthetic androids, or Synthoids for short. You helped achieve a major
that were stronger, faster, and more intelligent than the humans that had created them. technological breakthrough in the sixth generation of the company's Synthoid design, called MK-VI, by developing
<br /> a hyperintelligent AI. Many argue that this was the first sentient AI ever created. This resulted in Synthoid
<br /> models that were stronger, faster, and more intelligent than the humans that had created them.
In this BitNode you will be able to access the {FactionNames.Bladeburners} API, which allows you to access{" "} <br />
{FactionNames.Bladeburners} functionality through Netscript. <br />
<br /> In this BitNode you will be able to access the {FactionNames.Bladeburners} API, which allows you to access{" "}
<br /> {FactionNames.Bladeburners} functionality through Netscript.
Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File allows you to access the {FactionNames.Bladeburners} Netscript API in <br />
other BitNodes. In addition, this Source-File will increase all of your {FactionNames.Bladeburners} multipliers Destroying this BitNode will give you Source-File 7, or if you already have this Source-File it will upgrade its
by: level up to a maximum of 3. This Source-File allows you to access the {FactionNames.Bladeburners} Netscript API
<br /> in other BitNodes. In addition, this Source-File will increase all of your {FactionNames.Bladeburners}{" "}
<br /> multipliers by:
Level 1: 8% <br />
<br /> <br />
Level 2: 12% Level 1: 8%
<br /> <br />
Level 3: 14% Level 2: 12%
</> <br />
), Level 3: 14%
); </>
BitNodes["BitNode8"] = new BitNode( ),
8, );
2, BitNodes["BitNode8"] = new BitNode(
"Ghost of Wall Street", 8,
"Money never sleeps", 2,
( "Ghost of Wall Street",
<> "Money never sleeps",
You are trying to make a name for yourself as an up-and-coming hedge fund manager on Wall Street. (
<br /> <>
<br /> You are trying to make a name for yourself as an up-and-coming hedge fund manager on Wall Street.
In this BitNode: <br />
<br /> <br />
<br /> In this BitNode:
You start with $250 million <br />
<br /> <br />
You start with a WSE membership and access to the TIX API You start with $250 million
<br /> <br />
You are able to short stocks and place different types of orders (limit/stop) You start with a WSE membership and access to the TIX API
<br /> <br />
<br /> You are able to short stocks and place different types of orders (limit/stop)
Destroying this BitNode will give you Source-File 8, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File grants the following benefits: <br />
<br /> Destroying this BitNode will give you Source-File 8, or if you already have this Source-File it will upgrade its
<br /> level up to a maximum of 3. This Source-File grants the following benefits:
Level 1: Permanent access to WSE and TIX API <br />
<br /> <br />
Level 2: Ability to short stocks in other BitNodes Level 1: Permanent access to WSE and TIX API
<br /> <br />
Level 3: Ability to use limit/stop orders in other BitNodes Level 2: Ability to short stocks in other BitNodes
<br /> <br />
<br /> Level 3: Ability to use limit/stop orders in other BitNodes
This Source-File also increases your hacking growth multipliers by: <br />
<br /> <br />
Level 1: 12% This Source-File also increases your hacking growth multipliers by:
<br /> <br />
Level 2: 18% Level 1: 12%
<br /> <br />
Level 3: 21% Level 2: 18%
</> <br />
), Level 3: 21%
); </>
BitNodes["BitNode9"] = new BitNode( ),
9, );
2, BitNodes["BitNode9"] = new BitNode(
"Hacktocracy", 9,
"Hacknet Unleashed", 2,
( "Hacktocracy",
<> "Hacknet Unleashed",
When {FactionNames.FulcrumSecretTechnologies} released their open-source Linux distro Chapeau, it quickly became (
the OS of choice for the underground hacking community. Chapeau became especially notorious for powering the <>
Hacknet, a global, decentralized network used for nefarious purposes. {FactionNames.FulcrumSecretTechnologies}{" "} When {FactionNames.FulcrumSecretTechnologies} released their open-source Linux distro Chapeau, it quickly became
quickly abandoned the project and dissociated themselves from it. the OS of choice for the underground hacking community. Chapeau became especially notorious for powering the
<br /> Hacknet, a global, decentralized network used for nefarious purposes. {FactionNames.FulcrumSecretTechnologies}{" "}
<br /> quickly abandoned the project and dissociated themselves from it.
This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate hashes, <br />
which can be spent on a variety of different upgrades. <br />
<br /> This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate
<br /> hashes, which can be spent on a variety of different upgrades.
Destroying this BitNode will give you Source-File 9, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File grants the following benefits: <br />
<br /> Destroying this BitNode will give you Source-File 9, or if you already have this Source-File it will upgrade its
<br /> level up to a maximum of 3. This Source-File grants the following benefits:
Level 1: Permanently unlocks the Hacknet Server in other BitNodes <br />
<br /> <br />
Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode Level 1: Permanently unlocks the Hacknet Server in other BitNodes
<br /> <br />
Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode
<br /> <br />
<br /> Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing <br />
Augmentations) <br />
<br /> (Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing
<br /> Augmentations)
This Source-File also increases your hacknet multipliers by: <br />
<br /> <br />
Level 1: 8% This Source-File also increases your hacknet multipliers by:
<br /> <br />
Level 2: 12% Level 1: 8%
<br /> <br />
Level 3: 14% Level 2: 12%
</> <br />
), Level 3: 14%
); </>
BitNodes["BitNode10"] = new BitNode( ),
10, );
2, BitNodes["BitNode10"] = new BitNode(
"Digital Carbon", 10,
"Your body is not who you are", 2,
( "Digital Carbon",
<> "Your body is not who you are",
In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people to digitize their (
consciousness. Their consciousness could then be transferred into Synthoids or other bodies by trasmitting the <>
digitized data. Human bodies became nothing more than 'sleeves' for the human consciousness. Mankind had finally In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people to digitize their
achieved immortality - at least for those that could afford it. consciousness. Their consciousness could then be transferred into Synthoids or other bodies by transmitting the
<br /> digitized data. Human bodies became nothing more than 'sleeves' for the human consciousness. Mankind had finally
<br /> achieved immortality - at least for those that could afford it.
This BitNode unlocks Sleeve and grafting technologies. Sleeve technology allows you to: <br />
<br /> <br />
<br /> This BitNode unlocks Sleeve and grafting technologies. Sleeve technology allows you to:
1. Grafting: Visit VitaLife in New Tokyo to be able to obtain Augmentations without needing to install <br />
<br /> <br />
2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks 1. Grafting: Visit VitaLife in New Tokyo to be able to obtain Augmentations without needing to install
synchronously. <br />
<br /> 2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks
<br /> synchronously.
Grafting technology allows you to graft Augmentations, which is an alternative way of installing Augmentations. <br />
<br /> <br />
<br /> Grafting technology allows you to graft Augmentations, which is an alternative way of installing Augmentations.
Destroying this BitNode will give you Source-File 10, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File unlocks Sleeve technology, and the Grafting API in other BitNodes. <br />
Each level of this Source-File also grants you a Duplicate Sleeve Destroying this BitNode will give you Source-File 10, or if you already have this Source-File it will upgrade
</> its level up to a maximum of 3. This Source-File unlocks Sleeve technology, and the Grafting API in other
), BitNodes. Each level of this Source-File also grants you a Duplicate Sleeve
); </>
BitNodes["BitNode11"] = new BitNode( ),
11, );
1, BitNodes["BitNode11"] = new BitNode(
"The Big Crash", 11,
"Okay. Sell it all.", 1,
( "The Big Crash",
<> "Okay. Sell it all.",
The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around (
the world. It was this period of disorder that eventually lead to the governmental reformation of many global <>
superpowers, most notably the USA and China. But just as the world was slowly beginning to recover from these dark The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around
times, financial catastrophe hit. the world. It was this period of disorder that eventually lead to the governmental reformation of many global
<br /> superpowers, most notably the USA and China. But just as the world was slowly beginning to recover from these
<br /> dark times, financial catastrophe hit.
In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of <br />
this chaos and confusion, hackers were able to steal billions of dollars from the world's largest electronic <br />
banks, prompting an international banking crisis as governments were unable to bail out insolvent banks. Now, the In many countries, the high cost of trying to deal with the civil disorder bankrupted the governments. In all of
world is slowly crumbling in the middle of the biggest economic crisis of all time. this chaos and confusion, hackers were able to steal billions of dollars from the world's largest electronic
<br /> banks, prompting an international banking crisis as governments were unable to bail out insolvent banks. Now,
<br /> the world is slowly crumbling in the middle of the biggest economic crisis of all time.
Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH the player's salary and <br />
reputation gain rate at that company by 1% per favor (rather than just the reputation gain). This Source-File also Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will upgrade
increases the player's company salary and reputation gain multipliers by: its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH the player's
<br /> salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). This
<br /> Source-File also increases the player's company salary and reputation gain multipliers by:
Level 1: 32% <br />
<br /> <br />
Level 2: 48% Level 1: 32%
<br /> <br />
Level 3: 56% Level 2: 48%
<br /> <br />
<br /> Level 3: 56%
It also reduces the price increase for every aug bought by: <br />
<br /> <br />
<br /> It also reduces the price increase for every aug bought by:
Level 1: 4% <br />
<br /> <br />
Level 2: 6% Level 1: 4%
<br /> <br />
Level 3: 7% Level 2: 6%
</> <br />
), Level 3: 7%
); </>
BitNodes["BitNode12"] = new BitNode( ),
12, );
0, BitNodes["BitNode12"] = new BitNode(
"The Recursion", 12,
"Repeat.", 0,
( "The Recursion",
<> "Repeat.",
To iterate is human, to recurse divine. (
<br /> <>
<br /> To iterate is human, to recurse divine.
Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you <br />
Source-File 12, or if you already have this Source-File it will upgrade its level. There is no maximum level for <br />
Source-File 12. Each level of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you
level of this source file. Source-File 12, or if you already have this Source-File it will upgrade its level. There is no maximum level for
</> Source-File 12. Each level of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the
), level of this source file.
); </>
BitNodes["BitNode13"] = new BitNode( ),
13, );
2, BitNodes["BitNode13"] = new BitNode(
"They're lunatics", 13,
"1 step back, 2 steps forward", 2,
( "They're lunatics",
<> "1 step back, 2 steps forward",
With the invention of Augmentations in the 2040s a religious group known as the{" "} (
{FactionNames.ChurchOfTheMachineGod} has rallied far more support than anyone would have hoped. <>
<br /> With the invention of Augmentations in the 2040s a religious group known as the{" "}
<br /> {FactionNames.ChurchOfTheMachineGod} has rallied far more support than anyone would have hoped.
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any <br />
other. Find her in {CityName.Chongqing} and gain her trust. <br />
<br /> Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
<br /> other. Find her in {CityName.Chongqing} and gain her trust.
Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade its <br />
level up to a maximum of 3. This Source-File lets the {FactionNames.ChurchOfTheMachineGod} appear in other <br />
BitNodes. Destroying this BitNode will give you Source-File 13, or if you already have this Source-File it will upgrade
<br /> its level up to a maximum of 3. This Source-File lets the {FactionNames.ChurchOfTheMachineGod} appear in other
<br /> BitNodes.
Each level of this Source-File increases the size of Stanek's Gift. <br />
</> <br />
), Each level of this Source-File increases the size of Stanek's Gift.
); </>
),
);
}
export const defaultMultipliers: IBitNodeMultipliers = { export const defaultMultipliers: IBitNodeMultipliers = {
HackingLevelMultiplier: 1, HackingLevelMultiplier: 1,

@ -1,226 +1,231 @@
import React from "react"; import React from "react";
import { SourceFile } from "./SourceFile"; import { SourceFile } from "./SourceFile";
import { IMap } from "../types"; import { IMap } from "../types";
import { initBitNodes, initBitNodeMultipliers } from "../BitNode/BitNode";
export const SourceFiles: IMap<SourceFile> = {}; export const SourceFiles: IMap<SourceFile> = {};
/** Engine initializer for SourceFiles, BitNodes, and BitNodeMultipliers. Run once at engine load. */
SourceFiles["SourceFile1"] = new SourceFile( export function initSourceFiles() {
1, initBitNodes();
( initBitNodeMultipliers();
<> SourceFiles["SourceFile1"] = new SourceFile(
This Source-File lets the player start with 32GB of RAM on his/her home computer. It also increases all of the 1,
player's multipliers by: (
<br /> <>
<br /> This Source-File lets the player start with 32GB of RAM on his/her home computer. It also increases all of the
Level 1: 16% player's multipliers by:
<br /> <br />
Level 2: 24% <br />
<br /> Level 1: 16%
Level 3: 28% <br />
</> Level 2: 24%
), <br />
); Level 3: 28%
SourceFiles["SourceFile2"] = new SourceFile( </>
2, ),
( );
<> SourceFiles["SourceFile2"] = new SourceFile(
This Source-File allows you to form gangs in other BitNodes once your karma decreases to a certain value. It also 2,
increases the player's crime success rate, crime money, and charisma multipliers by: (
<br /> <>
<br /> This Source-File allows you to form gangs in other BitNodes once your karma decreases to a certain value. It
Level 1: 24% also increases the player's crime success rate, crime money, and charisma multipliers by:
<br /> <br />
Level 2: 36% <br />
<br /> Level 1: 24%
Level 3: 42% <br />
</> Level 2: 36%
), <br />
); Level 3: 42%
SourceFiles["SourceFile3"] = new SourceFile( </>
3, ),
( );
<> SourceFiles["SourceFile3"] = new SourceFile(
This Source-File lets you create corporations on other BitNodes (although some BitNodes will disable this 3,
mechanic) and level 3 permanently unlocks the full API. This Source-File also increases your charisma and company (
salary multipliers by: <>
<br /> This Source-File lets you create corporations on other BitNodes (although some BitNodes will disable this
Level 1: 8% mechanic) and level 3 permanently unlocks the full API. This Source-File also increases your charisma and
<br /> company salary multipliers by:
Level 2: 12% <br />
<br /> Level 1: 8%
Level 3: 14% <br />
</> Level 2: 12%
), <br />
); Level 3: 14%
SourceFiles["SourceFile4"] = new SourceFile( </>
4, ),
( );
<> SourceFiles["SourceFile4"] = new SourceFile(
This Source-File lets you access and use the Singularity Functions in every BitNode. Every level of this 4,
Source-File reduces the RAM cost of Singularity functions: (
<br /> <>
Level 1: 16x This Source-File lets you access and use the Singularity Functions in every BitNode. Every level of this
<br /> Source-File reduces the RAM cost of Singularity functions:
Level 2: 4x <br />
<br /> Level 1: 16x
Level 3: 1x <br />
</> Level 2: 4x
), <br />
); Level 3: 1x
SourceFiles["SourceFile5"] = new SourceFile( </>
5, ),
( );
<> SourceFiles["SourceFile5"] = new SourceFile(
This Source-File grants a special new stat called Intelligence. Intelligence is unique because it is permanent and 5,
persistent (it never gets reset back to 1). However, gaining Intelligence experience is much slower than other (
stats. Higher Intelligence levels will boost your production for many actions in the game. In addition, this <>
Source-File will unlock: This Source-File grants a special new stat called Intelligence. Intelligence is unique because it is permanent
<br /> and persistent (it never gets reset back to 1). However, gaining Intelligence experience is much slower than
<ul> other stats. Higher Intelligence levels will boost your production for many actions in the game. In addition,
<li> this Source-File will unlock:
The <code>getBitNodeMultipliers()</code> Netscript function <br />
</li> <ul>
<li>Permanent access to Formulas.exe</li> <li>
<li> The <code>getBitNodeMultipliers()</code> Netscript function
Access to BitNode multiplier information on the <b>Stats</b> page </li>
</li> <li>Permanent access to Formulas.exe</li>
</ul> <li>
It will also raise all of your hacking-related multipliers by: Access to BitNode multiplier information on the <b>Stats</b> page
<br /> </li>
<br /> </ul>
Level 1: 8% It will also raise all of your hacking-related multipliers by:
<br /> <br />
Level 2: 12% <br />
<br /> Level 1: 8%
Level 3: 14% <br />
</> Level 2: 12%
), <br />
); Level 3: 14%
SourceFiles["SourceFile6"] = new SourceFile( </>
6, ),
( );
<> SourceFiles["SourceFile6"] = new SourceFile(
This Source-File allows you to access the NSA's Bladeburner Division in other BitNodes. In addition, this 6,
Source-File will raise both the level and experience gain rate of all your combat stats by: (
<br /> <>
<br /> This Source-File allows you to access the NSA's Bladeburner Division in other BitNodes. In addition, this
Level 1: 8% Source-File will raise both the level and experience gain rate of all your combat stats by:
<br /> <br />
Level 2: 12% <br />
<br /> Level 1: 8%
Level 3: 14% <br />
</> Level 2: 12%
), <br />
); Level 3: 14%
SourceFiles["SourceFile7"] = new SourceFile( </>
7, ),
( );
<> SourceFiles["SourceFile7"] = new SourceFile(
This Source-File allows you to access the Bladeburner Netscript API in other BitNodes. In addition, this 7,
Source-File will increase all of your Bladeburner multipliers by: (
<br /> <>
<br /> This Source-File allows you to access the Bladeburner Netscript API in other BitNodes. In addition, this
Level 1: 8% Source-File will increase all of your Bladeburner multipliers by:
<br /> <br />
Level 2: 12% <br />
<br /> Level 1: 8%
Level 3: 14% <br />
</> Level 2: 12%
), <br />
); Level 3: 14%
SourceFiles["SourceFile8"] = new SourceFile( </>
8, ),
( );
<> SourceFiles["SourceFile8"] = new SourceFile(
This Source-File grants the following benefits: 8,
<br /> (
<br /> <>
Level 1: Permanent access to WSE and TIX API This Source-File grants the following benefits:
<br /> <br />
Level 2: Ability to short stocks in other BitNodes <br />
<br /> Level 1: Permanent access to WSE and TIX API
Level 3: Ability to use limit/stop orders in other BitNodes <br />
<br /> Level 2: Ability to short stocks in other BitNodes
<br /> <br />
This Source-File also increases your hacking growth multipliers by: Level 3: Ability to use limit/stop orders in other BitNodes
<br /> <br />
Level 1: 12% <br />
<br /> This Source-File also increases your hacking growth multipliers by:
Level 2: 18% <br />
<br /> Level 1: 12%
Level 3: 21% <br />
</> Level 2: 18%
), <br />
); Level 3: 21%
SourceFiles["SourceFile9"] = new SourceFile( </>
9, ),
( );
<> SourceFiles["SourceFile9"] = new SourceFile(
This Source-File grants the following benefits: 9,
<br /> (
<br /> <>
Level 1: Permanently unlocks the Hacknet Server in other BitNodes This Source-File grants the following benefits:
<br /> <br />
Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode <br />
<br /> Level 1: Permanently unlocks the Hacknet Server in other BitNodes
Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode <br />
<br /> Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode
<br /> <br />
(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode
Augmentations) <br />
<br /> <br />
<br /> (Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing
This Source-File also increases your hacknet multipliers by: Augmentations)
<br /> <br />
Level 1: 8% <br />
<br /> This Source-File also increases your hacknet multipliers by:
Level 2: 12% <br />
<br /> Level 1: 8%
Level 3: 14% <br />
</> Level 2: 12%
), <br />
); Level 3: 14%
SourceFiles["SourceFile10"] = new SourceFile( </>
10, ),
( );
<> SourceFiles["SourceFile10"] = new SourceFile(
This Source-File unlocks Sleeve technology, and the Grafting API in other BitNodes. Each level of this Source-File 10,
also grants you a Duplicate Sleeve (
</> <>
), This Source-File unlocks Sleeve technology, and the Grafting API in other BitNodes. Each level of this
); Source-File also grants you a Duplicate Sleeve
SourceFiles["SourceFile11"] = new SourceFile( </>
11, ),
( );
<> SourceFiles["SourceFile11"] = new SourceFile(
This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate at 11,
that company by 1% per favor (rather than just the reputation gain). This Source-File also increases the player's (
company salary and reputation gain multipliers by: <>
<br /> This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate at
<br /> that company by 1% per favor (rather than just the reputation gain). This Source-File also increases the
Level 1: 32% player's company salary and reputation gain multipliers by:
<br /> <br />
Level 2: 48% <br />
<br /> Level 1: 32%
Level 3: 56% <br />
<br /> Level 2: 48%
<br /> <br />
It also reduces the price increase for every aug bought by: Level 3: 56%
<br /> <br />
<br /> <br />
Level 1: 4% It also reduces the price increase for every aug bought by:
<br /> <br />
Level 2: 6% <br />
<br /> Level 1: 4%
Level 3: 7% <br />
</> Level 2: 6%
), <br />
); Level 3: 7%
SourceFiles["SourceFile12"] = new SourceFile( </>
12, ),
<>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.</>, );
); SourceFiles["SourceFile12"] = new SourceFile(
SourceFiles["SourceFile13"] = new SourceFile( 12,
13, <>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.</>,
<>Each level of this Source-File increases the size of Stanek's Gift.</>, );
); SourceFiles["SourceFile13"] = new SourceFile(
13,
<>Each level of this Source-File increases the size of Stanek's Gift.</>,
);
}

@ -4,7 +4,7 @@
import { convertTimeMsToTimeElapsedString } from "./utils/StringHelperFunctions"; import { convertTimeMsToTimeElapsedString } from "./utils/StringHelperFunctions";
import { initAugmentations } from "./Augmentation/AugmentationHelpers"; import { initAugmentations } from "./Augmentation/AugmentationHelpers";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import { initBitNodeMultipliers } from "./BitNode/BitNode"; import { initSourceFiles } from "./SourceFile/SourceFiles";
import { initDarkWebItems } from "./DarkWeb/DarkWebItems"; import { initDarkWebItems } from "./DarkWeb/DarkWebItems";
import { generateRandomContract } from "./CodingContractGenerator"; import { generateRandomContract } from "./CodingContractGenerator";
import { initCompanies } from "./Company/Companies"; import { initCompanies } from "./Company/Companies";
@ -230,8 +230,7 @@ const Engine: {
if (loadGame(saveString)) { if (loadGame(saveString)) {
ThemeEvents.emit(); ThemeEvents.emit();
initSourceFiles();
initBitNodeMultipliers();
initDarkWebItems(); initDarkWebItems();
initAugmentations(); // Also calls Player.reapplyAllAugmentations() initAugmentations(); // Also calls Player.reapplyAllAugmentations()
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
@ -370,7 +369,7 @@ const Engine: {
); );
} else { } else {
// No save found, start new game // No save found, start new game
initBitNodeMultipliers(); initSourceFiles();
initDarkWebItems(); initDarkWebItems();
Engine.start(); // Run main game loop and Scripts loop Engine.start(); // Run main game loop and Scripts loop
Player.init(); Player.init();

@ -38,9 +38,9 @@ class NumeralFormatter {
return true; return true;
} }
format(n: number, format: string): string { format(n: number | string, format?: string): string {
// numeraljs doesnt properly format numbers that are too big or too small // numeral.js doesn't properly format numbers that are too big or too small
if (Math.abs(n) < 1e-6) { if (Math.abs(n as number) < 1e-6) {
n = 0; n = 0;
} }
const answer = numeral(n).format(format); const answer = numeral(n).format(format);
@ -50,19 +50,19 @@ class NumeralFormatter {
return answer; return answer;
} }
formatBigNumber(n: number): string { formatBigNumber(n: number | string): string {
return this.format(n, "0.000a"); return this.format(n, "0.000a");
} }
// TODO: leverage numeral.js to do it. This function also implies you can // TODO: leverage numeral.js to do it. This function also implies you can
// use this format in some text field but you can't. ( "1t" will parse but // use this format in some text field but you can't. ( "1t" will parse but
// "1s" will not) // "1s" will not)
formatReallyBigNumber(n: number, decimalPlaces = 3): string { formatReallyBigNumber(n: number | string, decimalPlaces = 3): string {
const nAbs = Math.abs(n); const nAbs = Math.abs(n as number);
if (n === Infinity) return "∞"; if (n === Infinity) return "∞";
for (let i = 0; i < extraFormats.length; i++) { for (let i = 0; i < extraFormats.length; i++) {
if (extraFormats[i] < nAbs && nAbs <= extraFormats[i] * 1000) { if (extraFormats[i] < nAbs && nAbs <= extraFormats[i] * 1000) {
return this.format(n / extraFormats[i], "0." + "0".repeat(decimalPlaces)) + extraNotations[i]; return this.format((n as number) / extraFormats[i], "0." + "0".repeat(decimalPlaces)) + extraNotations[i];
} }
} }
if (nAbs < 1000) { if (nAbs < 1000) {
@ -118,7 +118,7 @@ class NumeralFormatter {
return this.format(n * gigaMultiplier.standard, "0.00b"); return this.format(n * gigaMultiplier.standard, "0.00b");
} }
formatPercentage(n: number, decimalPlaces = 2): string { formatPercentage(n: number | string, decimalPlaces = 2): string {
const formatter: string = "0." + "0".repeat(decimalPlaces) + "%"; const formatter: string = "0." + "0".repeat(decimalPlaces) + "%";
return this.format(n, formatter); return this.format(n, formatter);
} }

@ -1,27 +1,22 @@
import { Player } from "../../../src/Player";
import { NetscriptFunctions } from "../../../src/NetscriptFunctions"; import { NetscriptFunctions } from "../../../src/NetscriptFunctions";
import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator"; import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
import { Environment } from "../../../src/Netscript/Environment"; import { Environment } from "../../../src/Netscript/Environment";
import { RunningScript } from "../../../src/Script/RunningScript"; import { RunningScript } from "../../../src/Script/RunningScript";
import { Script } from "../../../src/Script/Script"; import { Script } from "../../../src/Script/Script";
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true,
});
const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;
describe("Netscript Dynamic RAM Calculation/Generation Tests", function () { describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;
// Creates a mock RunningScript object // Creates a mock RunningScript object
/** /**
* *
* @param {string} code * @param {string} code
* @returns * @returns
*/ */
async function createRunningScript(code) { function createRunningScript(code: string) {
const script = new Script(); const script = new Script();
script.code = code; script.code = code;
await script.updateRamUsage(Player, []); script.updateRamUsage([]);
const runningScript = new RunningScript(script); const runningScript = new RunningScript(script);
@ -34,7 +29,7 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
* @param {number} val * @param {number} val
* @param {number} expected * @param {number} expected
*/ */
function testEquality(val, expected) { function testEquality(val: number, expected: number) {
expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON);
expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON); expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON);
} }
@ -46,7 +41,10 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
* @param {(...args: unknown[]) => unknown} fn * @param {(...args: unknown[]) => unknown} fn
* @param {unknown[]} args * @param {unknown[]} args
*/ */
function runPotentiallyAsyncFunction(fn, ...args) { function runPotentiallyAsyncFunction(
fn: (...args: (string | number | boolean)[]) => unknown,
...args: (string | number | boolean)[]
) {
const res = fn(...args); const res = fn(...args);
if (res instanceof Promise) { if (res instanceof Promise) {
res.catch(() => undefined); res.catch(() => undefined);
@ -61,43 +59,39 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
* @param {string[]} fnDesc - describes the name of the function being tested, * @param {string[]} fnDesc - describes the name of the function being tested,
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function testNonzeroDynamicRamCost(fnDesc, ...args) { async function testNonzeroDynamicRamCost(fnDesc: string[], ...args: (string | number | boolean)[]) {
if (!Array.isArray(fnDesc)) { if (!Array.isArray(fnDesc)) {
throw new Error("Non-array passed to testNonzeroDynamicRamCost()"); throw new Error("Non-array passed to testNonzeroDynamicRamCost()");
} }
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(...fnDesc);
expect(expected).toBeGreaterThan(0); expect(expected).toBeGreaterThan(0);
const code = `${fnDesc.join(".")}();`; const code = `${fnDesc.join(".")}();`;
const runningScript = await createRunningScript(code); const runningScript = createRunningScript(code);
// We don't need a real WorkerScript // We don't need a real WorkerScript
const workerScript = { const workerScript = {
args: args, args: args,
code: code, code: code,
delay: null,
dynamicLoadedFns: {}, dynamicLoadedFns: {},
dynamicRamUsage: RamCostConstants.ScriptBaseRamCost, dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
env: new Environment(null), env: new Environment(),
ramUsage: runningScript.ramUsage, ramUsage: runningScript.ramUsage,
scriptRef: runningScript, scriptRef: runningScript,
}; };
workerScript.env.vars = NetscriptFunctions(workerScript); workerScript.env.vars = NetscriptFunctions(workerScript as WorkerScript);
// Run the function through the workerscript's args // Run the function through the workerscript's args
const scope = workerScript.env.vars; const scope = workerScript.env.vars;
let curr = scope[fnDesc[0]]; const curr = fnDesc.reduce((prev, curr) => {
for (let i = 1; i < fnDesc.length; ++i) { try {
if (curr == null) { return prev[curr];
throw new Error(`Invalid function specified: [${fnDesc}]`); } catch {
throw new Error(`Invalid function: [${fnDesc}]`);
} }
}, scope as any);
if (typeof curr === "function") {
break;
}
curr = curr[fnDesc[i]];
}
if (typeof curr === "function") { if (typeof curr === "function") {
// We use a try/catch because the function will probably fail since the game isn't // We use a try/catch because the function will probably fail since the game isn't
@ -126,17 +120,17 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
* @param {string[]} fnDesc - describes the name of the function being tested, * @param {string[]} fnDesc - describes the name of the function being tested,
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function testZeroDynamicRamCost(fnDesc, skipRun = false) { async function testZeroDynamicRamCost(fnDesc: string[], skipRun = false) {
if (!Array.isArray(fnDesc)) { if (!Array.isArray(fnDesc)) {
throw new Error("Non-array passed to testZeroDynamicRamCost()"); throw new Error("Non-array passed to testZeroDynamicRamCost()");
} }
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(...fnDesc);
expect(expected).toEqual(0); expect(expected).toEqual(0);
if (skipRun) return; if (skipRun) return;
const code = `${fnDesc.join(".")}();`; const code = `${fnDesc.join(".")}();`;
const runningScript = await createRunningScript(code); const runningScript = createRunningScript(code);
// We don't need a real WorkerScript // We don't need a real WorkerScript
const workerScript = { const workerScript = {
@ -144,26 +138,21 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function () {
code: code, code: code,
dynamicLoadedFns: {}, dynamicLoadedFns: {},
dynamicRamUsage: RamCostConstants.ScriptBaseRamCost, dynamicRamUsage: RamCostConstants.ScriptBaseRamCost,
env: new Environment(null), env: new Environment(),
ramUsage: runningScript.ramUsage, ramUsage: runningScript.ramUsage,
scriptRef: runningScript, scriptRef: runningScript,
}; };
workerScript.env.vars = NetscriptFunctions(workerScript); workerScript.env.vars = NetscriptFunctions(workerScript as unknown as WorkerScript);
// Run the function through the workerscript's args // Run the function through the workerscript's args
const scope = workerScript.env.vars; const scope = workerScript.env.vars;
let curr = scope[fnDesc[0]]; const curr = fnDesc.reduce((prev, curr) => {
for (let i = 1; i < fnDesc.length; ++i) { try {
if (curr == null) { return prev[curr];
throw new Error(`Invalid function specified: [${fnDesc}]`); } catch {
throw new Error(`Invalid function: [${fnDesc}]`);
} }
}, scope as any);
if (typeof curr === "function") {
break;
}
curr = curr[fnDesc[i]];
}
if (typeof curr === "function") { if (typeof curr === "function") {
// We use a try/catch because the function will probably fail since the game isn't // We use a try/catch because the function will probably fail since the game isn't

@ -2,10 +2,6 @@ import { Player } from "../../../src/Player";
import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator"; import { getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
import { calculateRamUsage } from "../../../src/Script/RamCalculations"; import { calculateRamUsage } from "../../../src/Script/RamCalculations";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true,
});
const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost; const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;
const HacknetNamespaceCost = RamCostConstants.ScriptHacknetNodesRamCost; const HacknetNamespaceCost = RamCostConstants.ScriptHacknetNodesRamCost;
@ -16,7 +12,7 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* @param {number} val * @param {number} val
* @param {number} expected * @param {number} expected
*/ */
function testEquality(val, expected) { function testEquality(val: number, expected: number) {
expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expected - 100 * Number.EPSILON);
expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON); expect(val).toBeLessThanOrEqual(expected + 100 * Number.EPSILON);
} }
@ -29,17 +25,17 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* @param {string[]} fnDesc - describes the name of the function being tested, * @param {string[]} fnDesc - describes the name of the function being tested,
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function expectNonZeroRamCost(fnDesc) { async function expectNonZeroRamCost(fnDesc: string[]) {
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(...fnDesc);
expect(expected).toBeGreaterThan(0); expect(expected).toBeGreaterThan(0);
const code = fnDesc.join(".") + "(); "; const code = fnDesc.join(".") + "(); ";
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
testEquality(calculated, expected + ScriptBaseCost); testEquality(calculated, expected + ScriptBaseCost);
const multipleCallsCode = code.repeat(3); const multipleCallsCode = code.repeat(3);
const multipleCallsCalculated = (await calculateRamUsage(Player, multipleCallsCode, [])).cost; const multipleCallsCalculated = calculateRamUsage(multipleCallsCode, []).cost;
expect(multipleCallsCalculated).toEqual(calculated); expect(multipleCallsCalculated).toEqual(calculated);
} }
@ -51,27 +47,21 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* @param {string[]} fnDesc - describes the name of the function being tested, * @param {string[]} fnDesc - describes the name of the function being tested,
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
*/ */
async function expectZeroRamCost(fnDesc) { async function expectZeroRamCost(fnDesc: string[]) {
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(...fnDesc);
expect(expected).toEqual(0); expect(expected).toEqual(0);
const code = fnDesc.join(".") + "(); "; const code = fnDesc.join(".") + "(); ";
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
testEquality(calculated, ScriptBaseCost); testEquality(calculated, ScriptBaseCost);
const multipleCallsCalculated = (await calculateRamUsage(Player, code, [])).cost; const multipleCallsCalculated = calculateRamUsage(code, []).cost;
expect(multipleCallsCalculated).toEqual(ScriptBaseCost); expect(multipleCallsCalculated).toEqual(ScriptBaseCost);
} }
/** function SF4Cost(cost: number) {
* if (Player.bitNodeN === 4) return cost;
* @param {Player} player const sf4 = Player.sourceFileLvl(4);
* @param {number} cost
* @returns
*/
function SF4Cost(player, cost) {
if (player.bitNodeN === 4) return cost;
const sf4 = player.sourceFileLvl(4);
if (sf4 <= 1) return cost * 16; if (sf4 <= 1) return cost * 16;
if (sf4 === 2) return cost * 4; if (sf4 === 2) return cost * 4;
return cost; return cost;
@ -86,16 +76,16 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
* including the namespace(s). e.g. ["gang", "getMemberNames"] * including the namespace(s). e.g. ["gang", "getMemberNames"]
* @param {number} cost - expected cost * @param {number} cost - expected cost
*/ */
async function expectSpecificRamCost(fnDesc, cost) { async function expectSpecificRamCost(fnDesc: string[], cost: number) {
const expected = getRamCost(Player, ...fnDesc); const expected = getRamCost(...fnDesc);
expect(expected).toEqual(SF4Cost(Player, cost)); expect(expected).toEqual(SF4Cost(cost));
const code = fnDesc.join(".") + "(); "; const code = fnDesc.join(".") + "(); ";
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
testEquality(calculated, ScriptBaseCost + SF4Cost(Player, cost)); testEquality(calculated, ScriptBaseCost + SF4Cost(cost));
const multipleCallsCalculated = (await calculateRamUsage(Player, code, [])).cost; const multipleCallsCalculated = calculateRamUsage(code, []).cost;
expect(multipleCallsCalculated).toEqual(ScriptBaseCost + SF4Cost(Player, cost)); expect(multipleCallsCalculated).toEqual(ScriptBaseCost + SF4Cost(cost));
} }
describe("Basic Functions", function () { describe("Basic Functions", function () {
@ -535,7 +525,7 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
]; ];
it("should have zero RAM cost for all functions", function () { it("should have zero RAM cost for all functions", function () {
for (const fn of apiFunctions) { for (const fn of apiFunctions) {
expect(getRamCost(Player, "hacknet", fn)).toEqual(0); expect(getRamCost("hacknet", fn)).toEqual(0);
} }
}); });
@ -545,7 +535,7 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
code += "hacknet." + fn + "(); "; code += "hacknet." + fn + "(); ";
} }
const calculated = await calculateRamUsage(Player, code, []); const calculated = calculateRamUsage(code, []);
testEquality(calculated.cost, ScriptBaseCost + HacknetNamespaceCost); testEquality(calculated.cost, ScriptBaseCost + HacknetNamespaceCost);
}); });
}); });

@ -1,14 +1,7 @@
// Player is needed for calculating costs like Singularity functions, that depend on acquired source files
import { Player } from "../../../src/Player";
import { RamCostConstants } from "../../../src/Netscript/RamCostGenerator"; import { RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
import { calculateRamUsage } from "../../../src/Script/RamCalculations"; import { calculateRamUsage } from "../../../src/Script/RamCalculations";
import { Script } from "../../../src/Script/Script"; import { Script } from "../../../src/Script/Script";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true,
});
const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost; const ScriptBaseCost = RamCostConstants.ScriptBaseRamCost;
const HackCost = 0.1; const HackCost = 0.1;
const GrowCost = 0.15; const GrowCost = 0.15;
@ -17,13 +10,8 @@ const HacknetCost = 4;
const CorpCost = 1024 - ScriptBaseCost; const CorpCost = 1024 - ScriptBaseCost;
describe("Parsing NetScript code to work out static RAM costs", function () { describe("Parsing NetScript code to work out static RAM costs", function () {
// Tests numeric equality, allowing for floating point imprecision - and includes script base cost /** Tests numeric equality, allowing for floating point imprecision - and includes script base cost */
/** function expectCost(val: number, expected: number) {
*
* @param {number} val
* @param {number} expected
*/
function expectCost(val, expected) {
const expectedWithBase = expected + ScriptBaseCost; const expectedWithBase = expected + ScriptBaseCost;
expect(val).toBeGreaterThanOrEqual(expectedWithBase - 100 * Number.EPSILON); expect(val).toBeGreaterThanOrEqual(expectedWithBase - 100 * Number.EPSILON);
expect(val).toBeLessThanOrEqual(expectedWithBase + 100 * Number.EPSILON); expect(val).toBeLessThanOrEqual(expectedWithBase + 100 * Number.EPSILON);
@ -34,7 +22,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
const code = ` const code = `
export async function main(ns) { } export async function main(ns) { }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
@ -44,7 +32,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
ns.print("Slum snakes r00l!"); ns.print("Slum snakes r00l!");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
@ -54,7 +42,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await ns.hack("joesguns"); await ns.hack("joesguns");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -64,7 +52,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await X.hack("joesguns"); await X.hack("joesguns");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -75,7 +63,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await ns.hack("joesguns"); await ns.hack("joesguns");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -86,7 +74,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await ns.grow("joesguns"); await ns.grow("joesguns");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost + GrowCost); expectCost(calculated, HackCost + GrowCost);
}); });
@ -99,7 +87,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await ns.hack("joesguns"); await ns.hack("joesguns");
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -114,7 +102,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
async doHacking() { await this.ns.hack("joesguns"); } async doHacking() { await this.ns.hack("joesguns"); }
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -129,7 +117,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
async doHacking() { await this.#ns.hack("joesguns"); } async doHacking() { await this.#ns.hack("joesguns"); }
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
}); });
@ -142,7 +130,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
} }
function get() { return 0; } function get() { return 0; }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
@ -153,7 +141,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
} }
function purchaseNode() { return 0; } function purchaseNode() { return 0; }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
// Works at present, because the parser checks the namespace only, not the function name // Works at present, because the parser checks the namespace only, not the function name
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
@ -166,7 +154,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
} }
function getTask() { return 0; } function getTask() { return 0; }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
}); });
@ -178,7 +166,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
ns.hacknet.purchaseNode(0); ns.hacknet.purchaseNode(0);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, HacknetCost); expectCost(calculated, HacknetCost);
}); });
@ -188,7 +176,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
ns.corporation.getCorporation(); ns.corporation.getCorporation();
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, CorpCost); expectCost(calculated, CorpCost);
}); });
@ -199,7 +187,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
ns.hacknet.purchaseNode(0); ns.hacknet.purchaseNode(0);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, CorpCost + HacknetCost); expectCost(calculated, CorpCost + HacknetCost);
}); });
@ -209,7 +197,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
ns.sleeve.getTask(3); ns.sleeve.getTask(3);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [])).cost; const calculated = calculateRamUsage(code, []).cost;
expectCost(calculated, SleeveGetTaskCost); expectCost(calculated, SleeveGetTaskCost);
}); });
}); });
@ -219,7 +207,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
const libCode = ` const libCode = `
export function dummy() { return 0; } export function dummy() { return 0; }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import { dummy } from "libTest"; import { dummy } from "libTest";
@ -227,7 +215,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
dummy(); dummy();
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, 0); expectCost(calculated, 0);
}); });
@ -235,7 +223,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
const libCode = ` const libCode = `
export async function doHack(ns) { return await ns.hack("joesguns"); } export async function doHack(ns) { return await ns.hack("joesguns"); }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import { doHack } from "libTest"; import { doHack } from "libTest";
@ -243,7 +231,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await doHack(ns); await doHack(ns);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -252,7 +240,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
export async function doHack(ns) { return await ns.hack("joesguns"); } export async function doHack(ns) { return await ns.hack("joesguns"); }
export async function doGrow(ns) { return await ns.grow("joesguns"); } export async function doGrow(ns) { return await ns.grow("joesguns"); }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import { doHack } from "libTest"; import { doHack } from "libTest";
@ -260,7 +248,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await doHack(ns); await doHack(ns);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -269,7 +257,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
export async function doHack(ns) { return await ns.hack("joesguns"); } export async function doHack(ns) { return await ns.hack("joesguns"); }
export async function doGrow(ns) { return await ns.grow("joesguns"); } export async function doGrow(ns) { return await ns.grow("joesguns"); }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import * as test from "libTest"; import * as test from "libTest";
@ -277,7 +265,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await test.doHack(ns); await test.doHack(ns);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, HackCost + GrowCost); expectCost(calculated, HackCost + GrowCost);
}); });
@ -291,7 +279,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
async doGrow() { return await this.ns.grow("joesguns"); } async doGrow() { return await this.ns.grow("joesguns"); }
} }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import * as test from "libTest"; import * as test from "libTest";
@ -299,7 +287,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await test.doHack(ns); await test.doHack(ns);
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, HackCost); expectCost(calculated, HackCost);
}); });
@ -314,7 +302,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
return Grower; return Grower;
} }
`; `;
const lib = new Script(Player, "libTest.js", libCode, []); const lib = new Script("libTest.js", libCode);
const code = ` const code = `
import { createClass } from "libTest"; import { createClass } from "libTest";
@ -325,7 +313,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
await growerInstance.doGrow(); await growerInstance.doGrow();
} }
`; `;
const calculated = (await calculateRamUsage(Player, code, [lib])).cost; const calculated = calculateRamUsage(code, [lib]).cost;
expectCost(calculated, GrowCost); expectCost(calculated, GrowCost);
}); });
}); });

@ -1,9 +1,4 @@
import { Script } from "../../../src/Script/Script"; import { Script } from "../../../src/Script/Script";
import { Player } from "../../../src/Player";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true,
});
const code = `/** @param {NS} ns */ const code = `/** @param {NS} ns */
export async function main(ns) { export async function main(ns) {
@ -14,9 +9,8 @@ describe("Validate Save Script Works", function () {
it("Save", function () { it("Save", function () {
const server = "home"; const server = "home";
const filename = "test.js"; const filename = "test.js";
const player = Player;
const script = new Script(); const script = new Script();
script.saveScript(player, filename, code, server, []); script.saveScript(filename, code, server, []);
expect(script.filename).toEqual(filename); expect(script.filename).toEqual(filename);
expect(script.code).toEqual(code); expect(script.code).toEqual(code);

@ -224,10 +224,10 @@ describe("Terminal Directory Tests", function () {
}); });
it("should return false for invalid arguments", function () { it("should return false for invalid arguments", function () {
expect(isValidFilePath(null)).toEqual(false); expect(isValidFilePath(null as unknown as string)).toEqual(false);
expect(isValidFilePath()).toEqual(false); expect(isValidFilePath(undefined as unknown as string)).toEqual(false);
expect(isValidFilePath(5)).toEqual(false); expect(isValidFilePath(5 as unknown as string)).toEqual(false);
expect(isValidFilePath({})).toEqual(false); expect(isValidFilePath({} as unknown as string)).toEqual(false);
}); });
}); });
@ -283,8 +283,8 @@ describe("Terminal Directory Tests", function () {
}); });
it("should return false for invalid inputs (inputs that aren't filepaths)", function () { it("should return false for invalid inputs (inputs that aren't filepaths)", function () {
expect(isInRootDirectory(null)).toEqual(false); expect(isInRootDirectory(null as unknown as string)).toEqual(false);
expect(isInRootDirectory(undefined)).toEqual(false); expect(isInRootDirectory(undefined as unknown as string)).toEqual(false);
expect(isInRootDirectory("")).toEqual(false); expect(isInRootDirectory("")).toEqual(false);
expect(isInRootDirectory(" ")).toEqual(false); expect(isInRootDirectory(" ")).toEqual(false);
expect(isInRootDirectory("a")).toEqual(false); expect(isInRootDirectory("a")).toEqual(false);

@ -1,4 +1,3 @@
import { CityName } from "./../../../src/Locations/data/CityNames";
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { Player } from "../../../src/Player"; import { Player } from "../../../src/Player";
@ -7,10 +6,7 @@ import { Server } from "../../../src/Server/Server";
import { AddToAllServers, prestigeAllServers } from "../../../src/Server/AllServers"; import { AddToAllServers, prestigeAllServers } from "../../../src/Server/AllServers";
import { LocationName } from "../../../src/Locations/data/LocationNames"; import { LocationName } from "../../../src/Locations/data/LocationNames";
import { CodingContract } from "../../../src/CodingContracts"; import { CodingContract } from "../../../src/CodingContracts";
import { initDarkWebItems } from "../../../src/DarkWeb/DarkWebItems";
jest.mock(`!!raw-loader!../NetscriptDefinitions.d.ts`, () => "", {
virtual: true,
});
describe("determineAllPossibilitiesForTabCompletion", function () { describe("determineAllPossibilitiesForTabCompletion", function () {
let closeServer: Server; let closeServer: Server;
@ -18,6 +14,7 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
beforeEach(() => { beforeEach(() => {
prestigeAllServers(); prestigeAllServers();
initDarkWebItems();
Player.init(); Player.init();
closeServer = new Server({ closeServer = new Server({
@ -36,7 +33,7 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
hackDifficulty: 1, hackDifficulty: 1,
moneyAvailable: 70000, moneyAvailable: 70000,
numOpenPortsRequired: 0, numOpenPortsRequired: 0,
organizationName: CityName.Aevum, organizationName: LocationName.Sector12JoesGuns,
requiredHackingSkill: 1, requiredHackingSkill: 1,
serverGrowth: 3000, serverGrowth: 3000,
}); });
@ -49,12 +46,12 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
}); });
it("completes the connect command", async () => { it("completes the connect command", async () => {
const options = await determineAllPossibilitiesForTabCompletion(Player, "connect ", 0); const options = await determineAllPossibilitiesForTabCompletion("connect ", 0);
expect(options).toEqual(["near"]); expect(options).toEqual(["near"]);
}); });
it("completes the buy command", async () => { it("completes the buy command", async () => {
const options = await determineAllPossibilitiesForTabCompletion(Player, "buy ", 0); const options = await determineAllPossibilitiesForTabCompletion("buy ", 0);
expect(options.sort()).toEqual( expect(options.sort()).toEqual(
[ [
"BruteSSH.exe", "BruteSSH.exe",
@ -74,43 +71,43 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
it("completes the scp command", async () => { it("completes the scp command", async () => {
Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark"); Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark");
Player.getHomeComputer().messages.push("af.lit"); Player.getHomeComputer().messages.push("af.lit");
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
const options1 = await determineAllPossibilitiesForTabCompletion(Player, "scp ", 0); const options1 = await determineAllPossibilitiesForTabCompletion("scp ", 0);
expect(options1).toEqual(["/www/script.js", "af.lit", "note.txt", "www/"]); expect(options1).toEqual(["/www/script.js", "af.lit", "note.txt", "www/"]);
const options2 = await determineAllPossibilitiesForTabCompletion(Player, "scp note.txt ", 1); const options2 = await determineAllPossibilitiesForTabCompletion("scp note.txt ", 1);
expect(options2).toEqual(["home", "near", "far"]); expect(options2).toEqual(["home", "near", "far"]);
}); });
it("completes the kill, tail, mem, and check commands", async () => { it("completes the kill, tail, mem, and check commands", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
for (const command of ["kill", "tail", "mem", "check"]) { for (const command of ["kill", "tail", "mem", "check"]) {
const options = await determineAllPossibilitiesForTabCompletion(Player, `${command} `, 0); const options = await determineAllPossibilitiesForTabCompletion(`${command} `, 0);
expect(options).toEqual(["/www/script.js", "www/"]); expect(options).toEqual(["/www/script.js", "www/"]);
} }
}); });
it("completes the nano commands", async () => { it("completes the nano commands", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark"); Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark");
const options = await determineAllPossibilitiesForTabCompletion(Player, "nano ", 0); const options = await determineAllPossibilitiesForTabCompletion("nano ", 0);
expect(options).toEqual(["/www/script.js", "note.txt", "www/"]); expect(options).toEqual(["/www/script.js", "note.txt", "www/"]);
}); });
it("completes the rm command", async () => { it("completes the rm command", async () => {
Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark"); Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark");
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
Player.getHomeComputer().contracts.push(new CodingContract("linklist.cct")); Player.getHomeComputer().contracts.push(new CodingContract("linklist.cct"));
Player.getHomeComputer().messages.push("asl.msg"); Player.getHomeComputer().messages.push("asl.msg");
Player.getHomeComputer().messages.push("af.lit"); Player.getHomeComputer().messages.push("af.lit");
const options = await determineAllPossibilitiesForTabCompletion(Player, "rm ", 0); const options = await determineAllPossibilitiesForTabCompletion("rm ", 0);
expect(options).toEqual(["/www/script.js", "NUKE.exe", "af.lit", "note.txt", "linklist.cct", "www/"]); expect(options).toEqual(["/www/script.js", "NUKE.exe", "af.lit", "note.txt", "linklist.cct", "www/"]);
}); });
it("completes the run command", async () => { it("completes the run command", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
Player.getHomeComputer().contracts.push(new CodingContract("linklist.cct")); Player.getHomeComputer().contracts.push(new CodingContract("linklist.cct"));
const options = await determineAllPossibilitiesForTabCompletion(Player, "run ", 0); const options = await determineAllPossibilitiesForTabCompletion("run ", 0);
expect(options).toEqual(["/www/script.js", "NUKE.exe", "linklist.cct", "www/"]); expect(options).toEqual(["/www/script.js", "NUKE.exe", "linklist.cct", "www/"]);
}); });
@ -118,36 +115,36 @@ describe("determineAllPossibilitiesForTabCompletion", function () {
Player.getHomeComputer().writeToTextFile("/www/note.txt", "oh hai mark"); Player.getHomeComputer().writeToTextFile("/www/note.txt", "oh hai mark");
Player.getHomeComputer().messages.push("asl.msg"); Player.getHomeComputer().messages.push("asl.msg");
Player.getHomeComputer().messages.push("af.lit"); Player.getHomeComputer().messages.push("af.lit");
const options = await determineAllPossibilitiesForTabCompletion(Player, "cat ", 0); const options = await determineAllPossibilitiesForTabCompletion("cat ", 0);
expect(options).toEqual(["asl.msg", "af.lit", "/www/note.txt", "www/"]); expect(options).toEqual(["asl.msg", "af.lit", "/www/note.txt", "www/"]);
}); });
it("completes the download and mv commands", async () => { it("completes the download and mv commands", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark"); Player.getHomeComputer().writeToTextFile("note.txt", "oh hai mark");
for (const command of ["download", "mv"]) { for (const command of ["download", "mv"]) {
const options = await determineAllPossibilitiesForTabCompletion(Player, `${command} `, 0); const options = await determineAllPossibilitiesForTabCompletion(`${command} `, 0);
expect(options).toEqual(["/www/script.js", "note.txt", "www/"]); expect(options).toEqual(["/www/script.js", "note.txt", "www/"]);
} }
}); });
it("completes the cd command", async () => { it("completes the cd command", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
const options = await determineAllPossibilitiesForTabCompletion(Player, "cd ", 0); const options = await determineAllPossibilitiesForTabCompletion("cd ", 0);
expect(options).toEqual(["www/"]); expect(options).toEqual(["www/"]);
}); });
it("completes the ls and cd commands", async () => { it("completes the ls and cd commands", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
for (const command of ["ls", "cd"]) { for (const command of ["ls", "cd"]) {
const options = await determineAllPossibilitiesForTabCompletion(Player, `${command} `, 0); const options = await determineAllPossibilitiesForTabCompletion(`${command} `, 0);
expect(options).toEqual(["www/"]); expect(options).toEqual(["www/"]);
} }
}); });
it("completes commands starting with ./", async () => { it("completes commands starting with ./", async () => {
Player.getHomeComputer().writeToScriptFile(Player, "/www/script.js", "oh hai mark"); Player.getHomeComputer().writeToScriptFile("/www/script.js", "oh hai mark");
const options = await determineAllPossibilitiesForTabCompletion(Player, "run ./", 0); const options = await determineAllPossibilitiesForTabCompletion("run ./", 0);
expect(options).toEqual([".//www/script.js", "NUKE.exe", "./www/"]); expect(options).toEqual([".//www/script.js", "NUKE.exe", "./www/"]);
}); });
}); });

@ -1,6 +1,6 @@
import { numeralWrapper } from "../../../src/ui/numeralFormat"; import { numeralWrapper } from "../../../src/ui/numeralFormat";
let decimalFormat = "0.[000000]"; const decimalFormat = "0.[000000]";
describe("Numeral formatting for positive numbers", () => { describe("Numeral formatting for positive numbers", () => {
test("should not format too small numbers", () => { test("should not format too small numbers", () => {
@ -241,6 +241,8 @@ describe("Finding the number furthest away from 0", () => {
expect(numeralWrapper.largestAbsoluteNumber(789123, -123456, -456789)).toEqual(789123); expect(numeralWrapper.largestAbsoluteNumber(789123, -123456, -456789)).toEqual(789123);
}); });
test("Should return 0 for invalid input", () => { test("Should return 0 for invalid input", () => {
expect(numeralWrapper.largestAbsoluteNumber("abc", undefined, null)).toEqual(0); expect(
numeralWrapper.largestAbsoluteNumber("abc" as unknown as number, undefined, null as unknown as number),
).toEqual(0);
}); });
}); });