Fixed merge conflicts with dev

This commit is contained in:
danielyxie 2019-04-03 17:12:11 -07:00
commit b5ebbba43d
29 changed files with 613 additions and 436 deletions

File diff suppressed because one or more lines are too long

125
dist/engine.css vendored

@ -486,6 +486,7 @@ button {
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6); } box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6); }
.a-link-button-inactive, .a-link-button-inactive,
.std-button-disabled,
.std-button:disabled { .std-button:disabled {
text-decoration: none; text-decoration: none;
background-color: #333; background-color: #333;
@ -501,11 +502,15 @@ button {
.a-link-button-inactive:hover .tooltiptext, .a-link-button-inactive:hover .tooltiptext,
.a-link-button-inactive:hover .tooltiptexthigh, .a-link-button-inactive:hover .tooltiptexthigh,
.a-link-button-inactive:hover .tooltiptextleft, .a-link-button-inactive:hover .tooltiptextleft,
.std-button-disabled:hover .tooltiptext,
.std-button-disabled:hover .tooltiptexthigh,
.std-button-disabled:hover .tooltiptextleft,
.std-button:disabled:hover .tooltiptext, .std-button:disabled:hover .tooltiptext,
.std-button:disabled:hover .tooltiptexthigh, .std-button:disabled:hover .tooltiptexthigh,
.std-button:disabled:hover .tooltiptextleft { .std-button:disabled:hover .tooltiptextleft {
visibility: visible; } visibility: visible; }
.a-link-button-inactive:active, .a-link-button-inactive:active,
.std-button-disabled:active,
.std-button:disabled:active { .std-button:disabled:active {
pointer-events: none; } pointer-events: none; }
@ -671,7 +676,7 @@ button {
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/** /**
* Styling for the Character Overview Panel (top-right) * Styling for the Character Overview Panel (top-right panel)
*/ */
#character-overview-wrapper { #character-overview-wrapper {
position: relative; } position: relative; }
@ -927,6 +932,64 @@ button {
/* Specified overrides for Code mirror Editor are defined in codemirror-override.scss */ /* Specified overrides for Code mirror Editor are defined in codemirror-override.scss */
/* COLORS */
/* Attributes */
/**
* Styling for the Hacknet Nodes UI Page
*/
#hacknet-nodes-container {
position: fixed;
padding: 10px; }
.hacknet-general-info {
margin: 10px;
width: 70vw; }
#hacknet-nodes-container li {
float: left;
overflow: hidden;
white-space: nowrap; }
#hacknet-nodes-container li.hacknet-node {
-webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
-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);
margin: 6px;
padding: 7px;
width: 35vw;
border: 2px solid var(--my-highlight-color); }
#hacknet-nodes-list {
list-style: none;
width: 82vw; }
#hacknet-nodes-money {
margin: 10px;
float: left; }
#hacknet-nodes-money-multipliers-div {
display: inline-block;
width: 70vw; }
#hacknet-nodes-multipliers {
float: right; }
#hacknet-nodes-purchase-button {
display: inline-block; }
.hacknet-node-container {
display: inline-table; }
.hacknet-node-container .row {
display: table-row;
height: 30px; }
.hacknet-node-container .row p {
display: table-cell; }
.hacknet-node-container .upgradable-info {
display: inline-block;
margin: 0 4px;
/* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: 64px; }
/* COLORS */ /* COLORS */
/* Attributes */ /* Attributes */
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding /* CSS for different main menu pages, such as character info, script editor, etc (but excluding
@ -1044,64 +1107,6 @@ button {
color: #fff; color: #fff;
margin-left: 5%; } margin-left: 5%; }
/* Hacknet Nodes */
#hacknet-nodes-container {
position: fixed;
padding: 10px; }
#hacknet-nodes-text,
#hacknet-nodes-container li {
margin: 10px;
padding: 10px; }
#hacknet-nodes-container li {
float: left;
overflow: hidden;
white-space: nowrap; }
#hacknet-nodes-container li.hacknet-node {
-webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1), 0 0 16px rgba(0, 0, 0, 0.1);
-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);
margin: 6px;
padding: 7px;
width: 35vw;
border: 2px solid var(--my-highlight-color); }
#hacknet-nodes-list {
list-style: none;
width: 82vw; }
#hacknet-nodes-money {
margin: 10px;
float: left; }
#hacknet-nodes-money-multipliers-div {
display: inline-block;
width: 70vw; }
#hacknet-nodes-multipliers {
float: right; }
#hacknet-nodes-purchase-button {
display: inline-block; }
.hacknet-node-container {
display: inline-table; }
.hacknet-node-container .row {
display: table-row;
height: 30px; }
.hacknet-node-container .row p {
display: table-cell; }
.hacknet-node-container .upgradable-info {
display: inline-block;
margin: 0 4px;
/* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: 64px; }
.menu-page-text {
width: 70vw; }
/* World */ /* World */
#world-container { #world-container {
position: fixed; position: fixed;
@ -1402,7 +1407,7 @@ button {
/* Pop-up boxes */ /* Pop-up boxes */
.popup-box-container { .popup-box-container {
display: none; display: none;
/* Hidden by default */ /* Initially hidden */
position: fixed; position: fixed;
/* Stay in place */ /* Stay in place */
z-index: 10; z-index: 10;

130
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -3,6 +3,24 @@
Changelog Changelog
========= =========
v0.46.0 - 4/3/2019
------------------
* 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
* 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
v0.45.1 - 3/23/2019 v0.45.1 - 3/23/2019
------------------- -------------------
* Added two new Corporation Researches * Added two new Corporation Researches

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.45' version = '0.46'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.45.0' release = '0.46.0'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

@ -0,0 +1,17 @@
getCacheUpgradeCost() Netscript Function
========================================
.. warning:: This page contains spoilers for the game
.. js:function:: getCacheUpgradeCost(i, n)
:param number i: Index/Identifier of Hacknet Node. :ref:`See here for details <netscript_hacknetnodeapi_referencingahacknetnode>`
:param number n: Number of times to upgrade cache. Must be positive. Rounded to nearest integer
.. note:: This function is only applicable for Hacknet Servers (the upgraded version of
a Hacknet Node).
Returns the cost of upgrading the cache level of the specified Hacknet Server by *n*.
If an invalid value for *n* is provided, then this function returns 0. If the
specified Hacknet Server is already at the max cache level, then Infinity is returned.

@ -1,6 +1,8 @@
getNodeStats() Netscript Function getNodeStats() Netscript Function
================================= =================================
.. warning:: This page contains spoilers for the game
.. js:function:: getNodeStats(i) .. js:function:: getNodeStats(i)
:param number i: Index/Identifier of Hacknet Node. :ref:`See here for details <netscript_hacknetnodeapi_referencingahacknetnode>` :param number i: Index/Identifier of Hacknet Node. :ref:`See here for details <netscript_hacknetnodeapi_referencingahacknetnode>`
@ -12,7 +14,12 @@ getNodeStats() Netscript Function
level: Node's level, level: Node's level,
ram: Node's RAM, ram: Node's RAM,
cores: Node's number of cores, cores: Node's number of cores,
production: Node's money earned per second, cache: Cache level. Only applicable for Hacknet Servers
production: Node's production per second
timeOnline: Number of seconds since Node has been purchased, timeOnline: Number of seconds since Node has been purchased,
totalProduction: Total number of money Node has produced totalProduction: Total amount that the Node has produced
} }
.. note:: Note that for Hacknet Nodes, production refers to the amount of money the node generates.
For Hacknet Servers (the upgraded version of Hacknet Nodes), production refers to the amount
of hashes the node generates.

@ -0,0 +1,19 @@
upgradeCache() Netscript Function
=================================
.. warning:: This page contains spoilers for the game
.. js:function:: upgradeCache(i, n)
:param number i: Index/Identifier of Hacknet Node. :ref:`See here for details <netscript_hacknetnodeapi_referencingahacknetnode>`
:param number n: Number of cache levels to purchase. Must be positive. Rounded to nearest integer
.. note:: This function is only applicable for Hacknet Servers (the upgraded version of
a Hacknet Node).
Tries to upgrade the specified Hacknet Server's cache *n* times.
Returns true if it successfully upgrades the Server's cache *n* times, or if
it purchases some positive amount and the Server reaches its max cache level.
Returns false otherwise.

@ -31,9 +31,11 @@ In :ref:`netscriptjs`::
upgradeLevel() <hacknetnodeapi/upgradeLevel> upgradeLevel() <hacknetnodeapi/upgradeLevel>
upgradeRam() <hacknetnodeapi/upgradeRam> upgradeRam() <hacknetnodeapi/upgradeRam>
upgradeCore() <hacknetnodeapi/upgradeCore> upgradeCore() <hacknetnodeapi/upgradeCore>
upgradeCache() <hacknetnodeapi/upgradeCache>
getLevelUpgradeCost() <hacknetnodeapi/getLevelUpgradeCost> getLevelUpgradeCost() <hacknetnodeapi/getLevelUpgradeCost>
getRamUpgradeCost() <hacknetnodeapi/getRamUpgradeCost> getRamUpgradeCost() <hacknetnodeapi/getRamUpgradeCost>
getCoreUpgradeCost() <hacknetnodeapi/getCoreUpgradeCost> getCoreUpgradeCost() <hacknetnodeapi/getCoreUpgradeCost>
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
.. _netscript_hacknetnodeapi_referencingahacknetnode: .. _netscript_hacknetnodeapi_referencingahacknetnode:
@ -68,23 +70,25 @@ The following is an example of one way a script can be used to automate the
purchasing and upgrading of Hacknet Nodes. purchasing and upgrading of Hacknet Nodes.
This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then
it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 cores:: it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 cores
.. code:: javascript
function myMoney() { function myMoney() {
return getServerMoneyAvailable("home");() <hacknetnodeapi/ return getServerMoneyAvailable("home");> return getServerMoneyAvailable("home");
} }
}() <hacknetnodeapi/>
disableLog("getServerMoneyAvailable"); disableLog("getServerMoneyAvailable");
disableLog("sleep"); disableLog("sleep");
cnt = 8; var cnt = 8;
while(hacknet.numNodes() < cnt) { while(hacknet.numNodes() < cnt) {
res = hacknet.purchaseNode(); res = hacknet.purchaseNode();
print("Purchased hacknet Node with index " + res); print("Purchased hacknet Node with index " + res);
}; };
for (i = 0; i < cnt; i++) { for (var i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).level <= 80) { while (hacknet.getNodeStats(i).level <= 80) {
var cost = hacknet.getLevelUpgradeCost(i, 10); var cost = hacknet.getLevelUpgradeCost(i, 10);
while (myMoney() < cost) { while (myMoney() < cost) {
@ -95,9 +99,9 @@ it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 c
}; };
}; };
print("All nodes upgrade to level 80"); print("All nodes upgraded to level 80");
for (i = 0; i < cnt; i++) { for (var i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).ram < 16) { while (hacknet.getNodeStats(i).ram < 16) {
var cost = hacknet.getRamUpgradeCost(i, 2); var cost = hacknet.getRamUpgradeCost(i, 2);
while (myMoney() < cost) { while (myMoney() < cost) {
@ -108,43 +112,4 @@ it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 c
}; };
}; };
print("All nodes upgrade to 16GB RAM"); print("All nodes upgraded to 16GB RAM");
for (i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).level <= 140) {
var cost = hacknet.getLevelUpgradeCost(i, 5);
while (myMoney() < cost) {
print("Need $" + cost + " . Have $" + myMoney());
sleep(3000);
}
res = hacknet.upgradeLevel(i, 5);
};
};
print("All nodes upgrade to level 140");
for (i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).ram < 64) {
var cost = hacknet.getRamUpgradeCost(i, 2);
while (myMoney() < cost) {
print("Need $" + cost + " . Have $" + myMoney());
sleep(3000);
}
res = hacknet.upgradeRam(i, 2);
};
};
print("All nodes upgrade to 64GB RAM (MAX)");
for (i = 0; i < cnt; i++) {
while (hacknetnodes.getNodeStatsi(i).cores < 8) {
var cost = hacknet.getCoreUpgradeCost(7);
while (myMoney() < cost) {
print("Need $" + cost + " . Have $" + myMoney());
sleep(3000);
}
res = hacknet.upgradeCore(i, 7);
};
};
print("All nodes upgrade to 8 cores");

@ -201,35 +201,7 @@
<!-- Hacknet Nodes --> <!-- Hacknet Nodes -->
<div id="hacknet-nodes-container" class="generic-menupage-container"> <div id="hacknet-nodes-container" class="generic-menupage-container">
<h1 id="hacknet-nodes-title"> Hacknet Nodes </h1> <!-- React Component -->
<p id="hacknet-nodes-text" class="menu-page-text">
The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced.
<br/><br/>
Here, you can purchase a Hacknet Node, a specialized machine that can connect and contribute its
resources to the Hacknet network. This allows you to take a small percentage of profits
from hacks performed on the network. Essentially, you are renting out your Node's computing power.
<br/><br/>
Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node can be upgraded
in order to increase its computing power and thereby increase the profit you earn from it.
</p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br/>
<div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" class="money-gold"></span><br/>
<span>Total Hacknet Node Production:</span><span id="hacknet-nodes-total-production" class="money-gold"></span>
</p>
<span id="hacknet-nodes-multipliers">
<a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a>
<a id="hacknet-nodes-5x-multiplier" class="a-link-button"> x5 </a>
<a id="hacknet-nodes-10x-multiplier" class="a-link-button"> x10 </a>
<a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a>
</span>
</div>
<ul id="hacknet-nodes-list">
</ul>
</div> </div>
<!-- World --> <!-- World -->

@ -176,7 +176,21 @@ export function initBitNodes() {
BitNodes["BitNode9"] = new BitNode(9, "Hacktocracy", "Hacknet Unleashed", BitNodes["BitNode9"] = new BitNode(9, "Hacktocracy", "Hacknet Unleashed",
"When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly " + "When Fulcrum Technologies released their open-source Linux distro Chapeau, it quickly " +
"became the OS of choice for the underground hacking community. Chapeau became especially notorious for " + "became the OS of choice for the underground hacking community. Chapeau became especially notorious for " +
"powering the Hacknet, "); "powering the Hacknet, a global, decentralized network used for nefarious purposes. Fulcrum quickly " +
"abandoned the project and dissociated themselves from it.<br><br>" +
"This BitNode unlocks the Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers generate " +
"hashes, which can be spent on a variety of different upgrades.<br><br>" +
"In this BitNode:<br><br>" +
"Your stats are significantly decreased<br>" +
"You cannnot purchase additional servers<br>" +
"Hacking is significantly less profitable<br><br>" +
"Destroying this BitNode will give you Source-File 9, or if you already have this Source-File it will " +
"upgrade its level up to a maximum of 3. This Source-File grants the following benefits:<br><br>" +
"Level 1: Permanently unlocks the Hacknet Server in other BitNodes<br>" +
"Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode<br>" +
"Level 3: Grants a highly-upgraded Hacknet Server 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 Augmentations)");
BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are", BitNodes["BitNode10"] = new BitNode(10, "Digital Carbon", "Your body is not who you are",
"In 2084, VitaLife unveiled to the world the Persona Core, a technology that allowed people " + "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 " + "to digitize their consciousness. Their consciousness could then be transferred into Synthoids " +
@ -186,7 +200,7 @@ export function initBitNodes() {
"1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" + "1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" +
"2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" + "2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" +
"In this BitNode:<br><br>" + "In this BitNode:<br><br>" +
"Your stats are significantly decreased.<br>" + "Your stats are significantly decreased<br>" +
"All methods of gaining money are half as profitable (except Stock Market)<br>" + "All methods of gaining money are half as profitable (except Stock Market)<br>" +
"Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" + "Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" +
"Augmentations are 5x as expensive and require twice as much reputation<br><br>" + "Augmentations are 5x as expensive and require twice as much reputation<br><br>" +
@ -350,21 +364,25 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.CodingContractMoney = 0; BitNodeMultipliers.CodingContractMoney = 0;
break; break;
case 9: // Hacktocracy case 9: // Hacktocracy
BitNodeMultipliers.HackingLevelMultiplier = 0.4; BitNodeMultipliers.HackingLevelMultiplier = 0.4;
BitNodeMultipliers.StrengthLevelMultiplier = 0.45; BitNodeMultipliers.StrengthLevelMultiplier = 0.45;
BitNodeMultipliers.DefenseLevelMultiplier = 0.45; BitNodeMultipliers.DefenseLevelMultiplier = 0.45;
BitNodeMultipliers.DexterityLevelMultiplier = 0.45; BitNodeMultipliers.DexterityLevelMultiplier = 0.45;
BitNodeMultipliers.AgilityLevelMultiplier = 0.45; BitNodeMultipliers.AgilityLevelMultiplier = 0.45;
BitNodeMultipliers.CharismaLevelMultiplier = 0.45; BitNodeMultipliers.CharismaLevelMultiplier = 0.45;
BitNodeMultipliers.PurchasedServerLimit = 0; BitNodeMultipliers.PurchasedServerLimit = 0;
BitNodeMultipliers.HomeComputerRamCost = 5; BitNodeMultipliers.HomeComputerRamCost = 5;
BitNodeMultipliers.CrimeMoney = 0.5; BitNodeMultipliers.CrimeMoney = 0.5;
BitNodeMultipliers.ScriptHackMoney = 0.1; BitNodeMultipliers.ScriptHackMoney = 0.1;
BitNodeMultipliers.HackExpGain = 0.1; BitNodeMultipliers.HackExpGain = 0.05;
BitNodeMultipliers.ServerStartingMoney = 0.1; BitNodeMultipliers.ServerStartingMoney = 0.1;
BitNodeMultipliers.ServerMaxMoney = 0.1; BitNodeMultipliers.ServerMaxMoney = 0.1;
BitNodeMultipliers.ServerStartingSecurity = 2.5; BitNodeMultipliers.ServerStartingSecurity = 2.5;
BitNodeMultipliers.CorporationValuation = 0.5; BitNodeMultipliers.CorporationValuation = 0.5;
BitNodeMultipliers.FourSigmaMarketDataCost = 5;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
BitNodeMultipliers.BladeburnerRank = 0.9;
BitNodeMultipliers.BladeburnerSkillCost = 1.2;
break; break;
case 10: // Digital Carbon case 10: // Digital Carbon
BitNodeMultipliers.HackingLevelMultiplier = 0.2; BitNodeMultipliers.HackingLevelMultiplier = 0.2;

@ -6,7 +6,7 @@
import {IMap} from "./types"; import {IMap} from "./types";
export let CONSTANTS: IMap<any> = { export let CONSTANTS: IMap<any> = {
Version: "0.45.1", Version: "0.46.0",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //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 //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -285,6 +285,7 @@ export let CONSTANTS: IMap<any> = {
* Corporation Changes: * Corporation Changes:
** 'Demand' value of products decreases more slowly ** 'Demand' value of products decreases more slowly
** Bug Fix: Fixed a Corporation issue that broke the Market-TA2 Research ** 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: Money Statistics tracker was incorrectly recording profits when selling stocks manually
* Bug Fix: Fixed an issue with the job requirement tooltip for security jobs * Bug Fix: Fixed an issue with the job requirement tooltip for security jobs

@ -31,6 +31,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
import { KEY } from "../../../utils/helpers/keyCodes"; import { KEY } from "../../../utils/helpers/keyCodes";
import { clearSelector } from "../../../utils/uiHelpers/clearSelector"; import { clearSelector } from "../../../utils/uiHelpers/clearSelector";

1
src/Hacking/README.md Normal file

@ -0,0 +1 @@
Implementation of underlying Hacking mechanics

@ -0,0 +1,53 @@
/**
* Functions used to determine whether the target can be hacked (or grown/weakened).
* Meant to be used for Netscript implementation
*
* The returned status object's message should be used for logging in Netscript
*/
import { IReturnStatus } from "../types";
import { HacknetServer } from "../Hacknet/HacknetServer";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Server } from "../Server/Server";
function baseCheck(server: Server | HacknetServer, fnName: string): IReturnStatus {
if (server instanceof HacknetServer) {
return {
res: false,
msg: `Cannot ${fnName} ${server.hostname} server because it is a Hacknet Node`
}
}
if (server.hasAdminRights === false) {
return {
res: false,
msg: `Cannot ${fnName} ${server.hostname} server because you do not have root access`,
}
}
return { res: true }
}
export function netscriptCanHack(server: Server | HacknetServer, p: IPlayer): IReturnStatus {
const initialCheck = baseCheck(server, "hack");
if (!initialCheck.res) { return initialCheck; }
let s = <Server>server;
if (s.requiredHackingSkill > p.hacking_skill) {
return {
res: false,
msg: `Cannot hack ${server.hostname} server because your hacking skill is not high enough`,
}
}
return { res: true }
}
export function netscriptCanGrow(server: Server | HacknetServer): IReturnStatus {
return baseCheck(server, "grow");
}
export function netscriptCanWeaken(server: Server | HacknetServer): IReturnStatus {
return baseCheck(server, "weaken");
}

@ -45,6 +45,25 @@ export function hasHacknetServers() {
return (Player.bitNodeN === 9 || SourceFileFlags[9] > 0); 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() { export function purchaseHacknet() {
/* INTERACTIVE TUTORIAL */ /* INTERACTIVE TUTORIAL */
if (ITutorial.isRunning) { if (ITutorial.isRunning) {
@ -54,9 +73,9 @@ export function purchaseHacknet() {
return; return;
} }
} }
/* END INTERACTIVE TUTORIAL */ /* END INTERACTIVE TUTORIAL */
const numOwned = Player.hacknetNodes.length;
if (hasHacknetServers()) { if (hasHacknetServers()) {
const cost = getCostOfNextHacknetServer(); const cost = getCostOfNextHacknetServer();
if (isNaN(cost)) { if (isNaN(cost)) {
@ -64,24 +83,9 @@ export function purchaseHacknet() {
} }
if (!Player.canAfford(cost)) { return -1; } if (!Player.canAfford(cost)) { return -1; }
// Auto generate a hostname for this Server
const numOwned = Player.hacknetNodes.length;
const name = `hacknet-node-${numOwned}`;
const server = new HacknetServer({
adminRights: true,
hostname: name,
player: Player,
});
Player.loseMoney(cost); Player.loseMoney(cost);
Player.hacknetNodes.push(server.ip); const server = createHacknetServer();
Player.hashManager.updateCapacity(Player);
// 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 numOwned; return numOwned;
} else { } else {
@ -93,7 +97,6 @@ export function purchaseHacknet() {
if (!Player.canAfford(cost)) { return -1; } if (!Player.canAfford(cost)) { return -1; }
// Auto generate a name for the Node // Auto generate a name for the Node
const numOwned = Player.hacknetNodes.length;
const name = "hacknet-node-" + numOwned; const name = "hacknet-node-" + numOwned;
const node = new HacknetNode(name); const node = new HacknetNode(name);
node.updateMoneyGainRate(Player); node.updateMoneyGainRate(Player);
@ -396,11 +399,21 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
break; break;
} }
case "Exchange for Bladeburner Rank": { case "Exchange for Bladeburner Rank": {
// This will throw if player doesn't have a corporation // This will throw if player isnt in Bladeburner
try { try {
for (const division of Player.corporation.divisions) { Player.bladeburner.changeRank(upg.value);
division.sciResearch.qty += upg.value; } catch(e) {
} Player.hashManager.refundUpgrade(upgName);
return false;
}
break;
}
case "Exchange for Bladeburner SP": {
// This will throw if player isn't in Bladeburner
try {
// As long as we don't change `Bladeburner.totalSkillPoints`, this
// shouldn't affect anything else
Player.bladeburner.skillPoints += upg.value;
} catch(e) { } catch(e) {
Player.hashManager.refundUpgrade(upgName); Player.hashManager.refundUpgrade(upgName);
return false; return false;
@ -413,6 +426,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
} }
default: default:
console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`) console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`)
Player.hashManager.refundUpgrade(upgName);
return false; return false;
} }

@ -327,16 +327,17 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
updateHashRate(p: IPlayer): void { updateHashRate(p: IPlayer): void {
const baseGain = HacknetServerHashesPerLevel * this.level; const baseGain = HacknetServerHashesPerLevel * this.level;
const coreMultiplier = Math.pow(1.1, this.cores - 1); const ramMultiplier = Math.pow(1.07, Math.log2(this.maxRam));
const coreMultiplier = 1 + (this.cores - 1) / 5;
const ramRatio = (1 - this.ramUsed / this.maxRam); const ramRatio = (1 - this.ramUsed / this.maxRam);
const hashRate = baseGain * coreMultiplier * ramRatio; const hashRate = baseGain * ramMultiplier * coreMultiplier * ramRatio;
this.hashRate = hashRate * p.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney; this.hashRate = hashRate * p.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney;
if (isNaN(this.hashRate)) { if (isNaN(this.hashRate)) {
this.hashRate = 0; this.hashRate = 0;
dialogBoxCreate(`Error calculating Hacknet Server hash production. This is a bug. Please report to game dev`, false); console.error(`Error calculating Hacknet Server hash production. This is a bug. Please report to game dev`, false);
} }
} }

@ -84,9 +84,14 @@ export class HashManager {
return upg.getCost(currLevel); return upg.getCost(currLevel);
} }
storeHashes(numHashes: number): void { prestige(p: IPlayer): void {
this.hashes += numHashes; for (const name in HashUpgrades) {
this.hashes = Math.min(this.hashes, this.capacity); this.upgrades[name] = 0;
}
this.hashes = 0;
if (p != null) {
this.updateCapacity(p);
}
} }
/** /**
@ -106,6 +111,11 @@ export class HashManager {
this.hashes += cost; this.hashes += cost;
} }
storeHashes(numHashes: number): void {
this.hashes += numHashes;
this.hashes = Math.min(this.hashes, this.capacity);
}
updateCapacity(p: IPlayer): void { updateCapacity(p: IPlayer): void {
if (p.hacknetNodes.length <= 0) { if (p.hacknetNodes.length <= 0) {
this.capacity = 0; this.capacity = 0;

@ -3,7 +3,7 @@ import { IConstructorParams } from "../HashUpgrade";
export const HashUpgradesMetadata: IConstructorParams[] = [ export const HashUpgradesMetadata: IConstructorParams[] = [
{ {
costPerLevel: 2, costPerLevel: 1,
desc: "Sell hashes for $1m", desc: "Sell hashes for $1m",
name: "Sell for Money", name: "Sell for Money",
value: 1e6, value: 1e6,
@ -15,36 +15,36 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
value: 1e9, value: 1e9,
}, },
{ {
costPerLevel: 100, costPerLevel: 50,
desc: "Use hashes to decrease the minimum security of a single server by 5%. " + desc: "Use hashes to decrease the minimum security of a single server by 2%. " +
"Note that a server's minimum security cannot go below 1.", "Note that a server's minimum security cannot go below 1.",
hasTargetServer: true, hasTargetServer: true,
name: "Reduce Minimum Security", name: "Reduce Minimum Security",
value: 0.95, value: 0.98,
}, },
{ {
costPerLevel: 100, costPerLevel: 50,
desc: "Use hashes to increase the maximum amount of money on a single server by 5%", desc: "Use hashes to increase the maximum amount of money on a single server by 2%",
hasTargetServer: true, hasTargetServer: true,
name: "Increase Maximum Money", name: "Increase Maximum Money",
value: 1.05, value: 1.02,
}, },
{ {
costPerLevel: 100, costPerLevel: 50,
desc: "Use hashes to improve the experience earned when studying at a university. " + desc: "Use hashes to improve the experience earned when studying at a university by 20%. " +
"This effect persists until you install Augmentations", "This effect persists until you install Augmentations",
name: "Improve Studying", name: "Improve Studying",
value: 20, // Improves studying by value% value: 20, // Improves studying by value%
}, },
{ {
costPerLevel: 100, costPerLevel: 50,
desc: "Use hashes to improve the experience earned when training at the gym. This effect " + desc: "Use hashes to improve the experience earned when training at the gym by 20%. This effect " +
"persists until you install Augmentations", "persists until you install Augmentations",
name: "Improve Gym Training", name: "Improve Gym Training",
value: 20, // Improves training by value% value: 20, // Improves training by value%
}, },
{ {
costPerLevel: 250, costPerLevel: 200,
desc: "Exchange hashes for 1k Scientific Research in all of your Corporation's Industries", desc: "Exchange hashes for 1k Scientific Research in all of your Corporation's Industries",
name: "Exchange for Corporation Research", name: "Exchange for Corporation Research",
value: 1000, value: 1000,
@ -56,7 +56,13 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
value: 100, value: 100,
}, },
{ {
costPerLevel: 200, costPerLevel: 250,
desc: "Exchanges hashes for 10 Bladeburner Skill Points",
name: "Exchange for Bladeburner SP",
value: 10,
},
{
costPerLevel: 150,
desc: "Generate a random Coding Contract on your home computer", desc: "Generate a random Coding Contract on your home computer",
name: "Generate Coding Contract", name: "Generate Coding Contract",
value: 1, value: 1,

@ -3,21 +3,22 @@
*/ */
import React from "react"; import React from "react";
import { purchaseHashUpgrade } from "../HacknetHelpers"; import { purchaseHashUpgrade } from "../HacknetHelpers";
import { HashManager } from "../HashManager"; import { HashManager } from "../HashManager";
import { HashUpgrades } from "../HashUpgrades"; import { HashUpgrades } from "../HashUpgrades";
import { Player } from "../../Player"; import { Player } from "../../Player";
import { AllServers } from "../../Server/AllServers"; import { AllServers } from "../../Server/AllServers";
import { Server } from "../../Server/Server"; import { Server } from "../../Server/Server";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { removePopup } from "../../ui/React/createPopup"; import { removePopup } from "../../ui/React/createPopup";
import { PopupCloseButton } from "../../ui/React/PopupCloseButton";
import { ServerDropdown, import { ServerDropdown,
ServerType } from "../../ui/React/ServerDropdown" ServerType } from "../../ui/React/ServerDropdown"
import { dialogBoxCreate } from "../../../utils/DialogBox"; import { dialogBoxCreate } from "../../../utils/DialogBox";
class HashUpgrade extends React.Component { class HashUpgrade extends React.Component {
constructor(props) { constructor(props) {
@ -85,8 +86,6 @@ export class HashUpgradePopup extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.closePopup = this.closePopup.bind(this);
this.state = { this.state = {
totalHashes: Player.hashManager.hashes, totalHashes: Player.hashManager.hashes,
} }
@ -100,10 +99,6 @@ export class HashUpgradePopup extends React.Component {
clearInterval(this.interval); clearInterval(this.interval);
} }
closePopup() {
removePopup(this.props.popupId);
}
tick() { tick() {
this.setState({ this.setState({
totalHashes: Player.hashManager.hashes, totalHashes: Player.hashManager.hashes,
@ -125,9 +120,7 @@ export class HashUpgradePopup extends React.Component {
return ( return (
<div> <div>
<button className={"std-button"} onClick={this.closePopup}> <PopupCloseButton popup={this.props.popupId} text={"Close"} />
Close
</button>
<p>Spend your hashes on a variety of different upgrades</p> <p>Spend your hashes on a variety of different upgrades</p>
<p>Hashes: {numeralWrapper.formatBigNumber(this.state.totalHashes)}</p> <p>Hashes: {numeralWrapper.formatBigNumber(this.state.totalHashes)}</p>
{upgradeElems} {upgradeElems}

@ -89,7 +89,6 @@ export class HacknetRoot extends React.Component {
const purchaseOnClick = () => { const purchaseOnClick = () => {
if (purchaseHacknet() >= 0) { if (purchaseHacknet() >= 0) {
this.recalculateTotalProduction(); this.recalculateTotalProduction();
Player.hashManager.updateCapacity(Player);
} }
} }

@ -29,10 +29,19 @@ import { Factions,
import { joinFaction, import { joinFaction,
purchaseAugmentation } from "./Faction/FactionHelpers"; purchaseAugmentation } from "./Faction/FactionHelpers";
import { FactionWorkType } from "./Faction/FactionWorkTypeEnum"; import { FactionWorkType } from "./Faction/FactionWorkTypeEnum";
import { netscriptCanGrow,
netscriptCanHack,
netscriptCanWeaken } from "./Hacking/netscriptCanHack";
import { getCostOfNextHacknetNode, import { getCostOfNextHacknetNode,
purchaseHacknet } from "./Hacknet/HacknetNode"; getCostOfNextHacknetServer,
purchaseHacknet,
hasHacknetServers } from "./Hacknet/HacknetHelpers";
import { CityName } from "./Locations/data/CityNames"; import { CityName } from "./Locations/data/CityNames";
import { LocationName } from "./Locations/data/LocationNames"; import { LocationName } from "./Locations/data/LocationNames";
import { HacknetServer } from "./Hacknet/HacknetServer";
import {Locations} from "./Locations";
import { Message } from "./Message/Message"; import { Message } from "./Message/Message";
import { Messages } from "./Message/MessageHelpers"; import { Messages } from "./Message/MessageHelpers";
import {inMission} from "./Missions"; import {inMission} from "./Missions";
@ -195,11 +204,11 @@ function initSingularitySFFlags() {
} }
function NetscriptFunctions(workerScript) { function NetscriptFunctions(workerScript) {
var updateDynamicRam = function(fnName, ramCost) { const updateDynamicRam = function(fnName, ramCost) {
if (workerScript.dynamicLoadedFns[fnName]) {return;} if (workerScript.dynamicLoadedFns[fnName]) {return;}
workerScript.dynamicLoadedFns[fnName] = true; workerScript.dynamicLoadedFns[fnName] = true;
const threads = workerScript.scriptRef.threads; let threads = workerScript.scriptRef.threads;
if (typeof threads !== 'number') { if (typeof threads !== 'number') {
console.warn(`WorkerScript detected NaN for threadcount for ${workerScript.name} on ${workerScript.serverIp}`); console.warn(`WorkerScript detected NaN for threadcount for ${workerScript.name} on ${workerScript.serverIp}`);
threads = 1; threads = 1;
@ -216,7 +225,7 @@ function NetscriptFunctions(workerScript) {
} }
}; };
var updateStaticRam = function(fnName, ramCost) { const updateStaticRam = function(fnName, ramCost) {
if (workerScript.loadedFns[fnName]) { if (workerScript.loadedFns[fnName]) {
return 0; return 0;
} else { } else {
@ -229,28 +238,56 @@ function NetscriptFunctions(workerScript) {
* Gets the Server for a specific hostname/ip, throwing an error * Gets the Server for a specific hostname/ip, throwing an error
* if the server doesn't exist. * if the server doesn't exist.
* @param {string} Hostname or IP of the server * @param {string} Hostname or IP of the server
* @param {string} callingFnName - Name of calling function. For logging purposes
* @returns {Server} The specified Server * @returns {Server} The specified Server
*/ */
var safeGetServer = function(ip, callingFnName="") { const safeGetServer = function(ip, callingFnName="") {
var server = getServer(ip); var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.log(`ERROR: Invalid IP or hostname passed into ${callingFnName}()`);
throw makeRuntimeRejectMsg(workerScript, `Invalid IP or hostname passed into ${callingFnName}() function`); throw makeRuntimeRejectMsg(workerScript, `Invalid IP or hostname passed into ${callingFnName}() function`);
} }
return server; return server;
} }
/**
* Used to fail a function if the function's target is a Hacknet Server.
* This is used for functions that should run on normal Servers, but not Hacknet Servers
* @param {Server} server - Target server
* @param {string} callingFn - Name of calling function. For logging purposes
* @returns {boolean} True if the server is a Hacknet Server, false otherwise
*/
const failOnHacknetServer = function(server, callingFn="") {
if (server instanceof HacknetServer) {
workerScript.log(`ERROR: ${callingFn}() failed because it does not work on Hacknet Servers`);
return true;
} else {
return false;
}
}
// Utility function to get Hacknet Node object // Utility function to get Hacknet Node object
var getHacknetNode = function(i) { const getHacknetNode = function(i) {
if (isNaN(i)) { if (isNaN(i)) {
throw makeRuntimeRejectMsg(workerScript, "Invalid index specified for Hacknet Node: " + i); throw makeRuntimeRejectMsg(workerScript, "Invalid index specified for Hacknet Node: " + i);
} }
if (i < 0 || i >= Player.hacknetNodes.length) { if (i < 0 || i >= Player.hacknetNodes.length) {
throw makeRuntimeRejectMsg(workerScript, "Index specified for Hacknet Node is out-of-bounds: " + i); throw makeRuntimeRejectMsg(workerScript, "Index specified for Hacknet Node is out-of-bounds: " + i);
} }
return Player.hacknetNodes[i];
if (hasHacknetServers()) {
const hserver = AllServers[Player.hacknetNodes[i]];
if (hserver == null) {
throw makeRuntimeRejectMsg(workerScript, `Could not get Hacknet Server for index ${i}. This is probably a bug, please report to game dev`);
}
return hserver;
} else {
return Player.hacknetNodes[i];
}
}; };
var getCodingContract = function(fn, ip) { const getCodingContract = function(fn, ip) {
var server = safeGetServer(ip, "getCodingContract"); var server = safeGetServer(ip, "getCodingContract");
return server.getContract(fn); return server.getContract(fn);
} }
@ -264,43 +301,68 @@ function NetscriptFunctions(workerScript) {
return purchaseHacknet(); return purchaseHacknet();
}, },
getPurchaseNodeCost : function() { getPurchaseNodeCost : function() {
return getCostOfNextHacknetNode(); if (hasHacknetServers()) {
return getCostOfNextHacknetServer();
} else {
return getCostOfNextHacknetNode();
}
}, },
getNodeStats : function(i) { getNodeStats : function(i) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return { const hasUpgraded = hasHacknetServers();
const res = {
name: node.name, name: node.name,
level: node.level, level: node.level,
ram: node.ram, ram: hasUpgraded ? node.maxRam : node.ram,
cores: node.cores, cores: node.cores,
production: node.moneyGainRatePerSecond, production: hasUpgraded ? node.hashRate : node.moneyGainRatePerSecond,
timeOnline: node.onlineTimeSeconds, timeOnline: node.onlineTimeSeconds,
totalProduction: node.totalMoneyGenerated, totalProduction: hasUpgraded ? node.totalHashesGenerated : node.totalMoneyGenerated,
}; };
if (hasUpgraded) {
res.cache = node.cache;
}
return res;
}, },
upgradeLevel : function(i, n) { upgradeLevel : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.purchaseLevelUpgrade(n, Player); return node.purchaseLevelUpgrade(n, Player);
}, },
upgradeRam : function(i, n) { upgradeRam : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.purchaseRamUpgrade(n, Player); return node.purchaseRamUpgrade(n, Player);
}, },
upgradeCore : function(i, n) { upgradeCore : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.purchaseCoreUpgrade(n, Player); return node.purchaseCoreUpgrade(n, Player);
}, },
upgradeCache : function(i, n) {
if (!hasHacknetServers()) { return false; }
const node = getHacknetNode(i);
const res = node.purchaseCacheUpgrade(n, Player);
if (res) {
Player.hashManager.updateCapacity(Player);
}
return res;
},
getLevelUpgradeCost : function(i, n) { getLevelUpgradeCost : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.calculateLevelUpgradeCost(n, Player); return node.calculateLevelUpgradeCost(n, Player);
}, },
getRamUpgradeCost : function(i, n) { getRamUpgradeCost : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.calculateRamUpgradeCost(n, Player); return node.calculateRamUpgradeCost(n, Player);
}, },
getCoreUpgradeCost : function(i, n) { getCoreUpgradeCost : function(i, n) {
var node = getHacknetNode(i); const node = getHacknetNode(i);
return node.calculateCoreUpgradeCost(n, Player); return node.calculateCoreUpgradeCost(n, Player);
},
getCacheUpgradeCost : function(i, n) {
if (!hasHacknetServers()) { return Infinity; }
const node = getHacknetNode(i);
return node.calculateCacheUpgradeCost(n);
} }
}, },
sprintf : sprintf, sprintf : sprintf,
@ -352,19 +414,16 @@ function NetscriptFunctions(workerScript) {
var hackingTime = calculateHackingTime(server); //This is in seconds var hackingTime = calculateHackingTime(server); //This is in seconds
//No root access or skill level too low //No root access or skill level too low
if (server.hasAdminRights == false) { const canHack = netscriptCanHack(server, Player);
workerScript.scriptRef.log("Cannot hack this server (" + server.hostname + ") because user does not have root access"); if (!canHack.res) {
throw makeRuntimeRejectMsg(workerScript, "Cannot hack this server (" + server.hostname + ") because user does not have root access"); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
} throw makeRuntimeRejectMsg(workerScript, canHack.msg);
if (server.requiredHackingSkill > Player.hacking_skill) {
workerScript.scriptRef.log("Cannot hack this server (" + server.hostname + ") because user's hacking skill is not high enough");
throw makeRuntimeRejectMsg(workerScript, "Cannot hack this server (" + server.hostname + ") because user's hacking skill is not high enough");
} }
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.hack == null) { if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.hack == null) {
workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds (t=" + threads + ")"); workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds (t=" + threads + ")");
} }
return netscriptDelay(hackingTime * 1000, workerScript).then(function() { return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);} if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
var hackChance = calculateHackingChance(server); var hackChance = calculateHackingChance(server);
@ -483,9 +542,10 @@ function NetscriptFunctions(workerScript) {
} }
//No root access or skill level too low //No root access or skill level too low
if (server.hasAdminRights == false) { const canHack = netscriptCanGrow(server);
workerScript.scriptRef.log("Cannot grow this server (" + server.hostname + ") because user does not have root access"); if (!canHack.res) {
throw makeRuntimeRejectMsg(workerScript, "Cannot grow this server (" + server.hostname + ") because user does not have root access"); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
throw makeRuntimeRejectMsg(workerScript, canHack.msg);
} }
var growTime = calculateGrowTime(server); var growTime = calculateGrowTime(server);
@ -544,9 +604,10 @@ function NetscriptFunctions(workerScript) {
} }
//No root access or skill level too low //No root access or skill level too low
if (server.hasAdminRights == false) { const canHack = netscriptCanWeaken(server);
workerScript.scriptRef.log("Cannot weaken this server (" + server.hostname + ") because user does not have root access"); if (!canHack.res) {
throw makeRuntimeRejectMsg(workerScript, "Cannot weaken this server (" + server.hostname + ") because user does not have root access"); workerScript.scriptRef.log(`ERROR: ${canHack.msg}`);
throw makeRuntimeRejectMsg(workerScript, canHack.msg);
} }
var weakenTime = calculateWeakenTime(server); var weakenTime = calculateWeakenTime(server);
@ -1302,25 +1363,22 @@ function NetscriptFunctions(workerScript) {
let copy = Object.assign({}, BitNodeMultipliers); let copy = Object.assign({}, BitNodeMultipliers);
return copy; return copy;
}, },
getServerMoneyAvailable : function(ip){ getServerMoneyAvailable : function(ip) {
if (workerScript.checkingRam) { if (workerScript.checkingRam) {
return updateStaticRam("getServerMoneyAvailable", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerMoneyAvailable", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerMoneyAvailable", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerMoneyAvailable", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerMoneyAvailable");
if (server == null) { if (failOnHacknetServer(server, "getServerMoneyAvailable")) { return 0; }
workerScript.scriptRef.log("getServerMoneyAvailable() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getServerMoneyAvailable() failed. Invalid IP or hostname passed in: " + ip);
}
if (server.hostname == "home") { if (server.hostname == "home") {
//Return player's money // Return player's money
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerMoneyAvailable == null) { if (workerScript.shouldLog("getServerMoneyAvailable")) {
workerScript.scriptRef.log("getServerMoneyAvailable('home') returned player's money: $" + formatNumber(Player.money.toNumber(), 2)); workerScript.log("getServerMoneyAvailable('home') returned player's money: $" + formatNumber(Player.money.toNumber(), 2));
} }
return Player.money.toNumber(); return Player.money.toNumber();
} }
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerMoneyAvailable == null) { if (workerScript.shouldLog("getServerMoneyAvailable")) {
workerScript.scriptRef.log("getServerMoneyAvailable() returned " + formatNumber(server.moneyAvailable, 2) + " for " + server.hostname); workerScript.log("getServerMoneyAvailable() returned " + formatNumber(server.moneyAvailable, 2) + " for " + server.hostname);
} }
return server.moneyAvailable; return server.moneyAvailable;
}, },
@ -1329,13 +1387,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerSecurityLevel", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerSecurityLevel", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerSecurityLevel");
if (server == null) { if (failOnHacknetServer(server, "getServerSecurityLevel")) { return 1; }
workerScript.scriptRef.log("getServerSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerSecurityLevel")) {
throw makeRuntimeRejectMsg(workerScript, "getServerSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerSecurityLevel() returned " + formatNumber(server.hackDifficulty, 3) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerSecurityLevel == null) {
workerScript.scriptRef.log("getServerSecurityLevel() returned " + formatNumber(server.hackDifficulty, 3) + " for " + server.hostname);
} }
return server.hackDifficulty; return server.hackDifficulty;
}, },
@ -1344,13 +1399,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerBaseSecurityLevel", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerBaseSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerBaseSecurityLevel", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerBaseSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerBaseSecurityLevel");
if (server == null) { if (failOnHacknetServer(server, "getServerBaseSecurityLevel")) { return 1; }
workerScript.scriptRef.log("getServerBaseSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerBaseSecurityLevel")) {
throw makeRuntimeRejectMsg(workerScript, "getServerBaseSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerBaseSecurityLevel() returned " + formatNumber(server.baseDifficulty, 3) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerBaseSecurityLevel == null) {
workerScript.scriptRef.log("getServerBaseSecurityLevel() returned " + formatNumber(server.baseDifficulty, 3) + " for " + server.hostname);
} }
return server.baseDifficulty; return server.baseDifficulty;
}, },
@ -1359,13 +1411,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerMinSecurityLevel", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerMinSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerMinSecurityLevel", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerMinSecurityLevel", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerMinSecurityLevel");
if (server == null) { if (failOnHacknetServer(server, "getServerMinSecurityLevel")) { return 1; }
workerScript.scriptRef.log("getServerMinSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerMinSecurityLevel")) {
throw makeRuntimeRejectMsg(workerScript, "getServerMinSecurityLevel() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerMinSecurityLevel() returned " + formatNumber(server.minDifficulty, 3) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerMinSecurityLevel == null) {
workerScript.scriptRef.log("getServerMinSecurityLevel() returned " + formatNumber(server.minDifficulty, 3) + " for " + server.hostname);
} }
return server.minDifficulty; return server.minDifficulty;
}, },
@ -1374,13 +1423,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerRequiredHackingLevel", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerRequiredHackingLevel", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerRequiredHackingLevel", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerRequiredHackingLevel", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerRequiredHackingLevel");
if (server == null) { if (failOnHacknetServer(server, "getServerRequiredHackingLevel")) { return 1; }
workerScript.scriptRef.log("getServerRequiredHackingLevel() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerRequiredHackingLevel")) {
throw makeRuntimeRejectMsg(workerScript, "getServerRequiredHackingLevel() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerRequiredHackingLevel returned " + formatNumber(server.requiredHackingSkill, 0) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerRequiredHackingLevel == null) {
workerScript.scriptRef.log("getServerRequiredHackingLevel returned " + formatNumber(server.requiredHackingSkill, 0) + " for " + server.hostname);
} }
return server.requiredHackingSkill; return server.requiredHackingSkill;
}, },
@ -1389,13 +1435,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerMaxMoney", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerMaxMoney", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerMaxMoney", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerMaxMoney", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerMaxMoney");
if (server == null) { if (failOnHacknetServer(server, "getServerMaxMoney")) { return 0; }
workerScript.scriptRef.log("getServerMaxMoney() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerMaxMoney")) {
throw makeRuntimeRejectMsg(workerScript, "getServerMaxMoney() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerMaxMoney() returned " + formatNumber(server.moneyMax, 0) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerMaxMoney == null) {
workerScript.scriptRef.log("getServerMaxMoney() returned " + formatNumber(server.moneyMax, 0) + " for " + server.hostname);
} }
return server.moneyMax; return server.moneyMax;
}, },
@ -1404,13 +1447,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerGrowth", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerGrowth", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerGrowth", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerGrowth", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerGrowth");
if (server == null) { if (failOnHacknetServer(server, "getServerGrowth")) { return 1; }
workerScript.scriptRef.log("getServerGrowth() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerGrowth")) {
throw makeRuntimeRejectMsg(workerScript, "getServerGrowth() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerGrowth() returned " + formatNumber(server.serverGrowth, 0) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerGrowth == null) {
workerScript.scriptRef.log("getServerGrowth() returned " + formatNumber(server.serverGrowth, 0) + " for " + server.hostname);
} }
return server.serverGrowth; return server.serverGrowth;
}, },
@ -1419,13 +1459,10 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerNumPortsRequired", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerNumPortsRequired", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerNumPortsRequired", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerNumPortsRequired", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerNumPortsRequired");
if (server == null) { if (failOnHacknetServer(server, "getServerNumPortsRequired")) { return 5; }
workerScript.scriptRef.log("getServerNumPortsRequired() failed. Invalid IP or hostname passed in: " + ip); if (workerScript.shouldLog("getServerNumPortsRequired")) {
throw makeRuntimeRejectMsg(workerScript, "getServerNumPortsRequired() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerNumPortsRequired() returned " + formatNumber(server.numOpenPortsRequired, 0) + " for " + server.hostname);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerNumPortsRequired == null) {
workerScript.scriptRef.log("getServerNumPortsRequired() returned " + formatNumber(server.numOpenPortsRequired, 0) + " for " + server.hostname);
} }
return server.numOpenPortsRequired; return server.numOpenPortsRequired;
}, },
@ -1434,13 +1471,9 @@ function NetscriptFunctions(workerScript) {
return updateStaticRam("getServerRam", CONSTANTS.ScriptGetServerRamCost); return updateStaticRam("getServerRam", CONSTANTS.ScriptGetServerRamCost);
} }
updateDynamicRam("getServerRam", CONSTANTS.ScriptGetServerRamCost); updateDynamicRam("getServerRam", CONSTANTS.ScriptGetServerRamCost);
var server = getServer(ip); const server = safeGetServer(ip, "getServerRam");
if (server == null) { if (workerScript.shouldLog("getServerRam")) {
workerScript.scriptRef.log("getServerRam() failed. Invalid IP or hostname passed in: " + ip); workerScript.log("getServerRam() returned [" + formatNumber(server.maxRam, 2) + "GB, " + formatNumber(server.ramUsed, 2) + "GB]");
throw makeRuntimeRejectMsg(workerScript, "getServerRam() failed. Invalid IP or hostname passed in: " + ip);
}
if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.getServerRam == null) {
workerScript.scriptRef.log("getServerRam() returned [" + formatNumber(server.maxRam, 2) + "GB, " + formatNumber(server.ramUsed, 2) + "GB]");
} }
return [server.maxRam, server.ramUsed]; return [server.maxRam, server.ramUsed];
}, },
@ -4711,7 +4744,7 @@ function NetscriptFunctions(workerScript) {
answer = String(answer); answer = String(answer);
} }
const serv = safeGetServer(ip, "codingcontract.attempt()"); const serv = safeGetServer(ip, "codingcontract.attempt");
if (contract.isSolution(answer)) { if (contract.isSolution(answer)) {
const reward = Player.gainCodingContractReward(contract.reward, contract.getDifficulty()); const reward = Player.gainCodingContractReward(contract.reward, contract.getDifficulty());
workerScript.log(`Successfully completed Coding Contract ${fn}. Reward: ${reward}`); workerScript.log(`Successfully completed Coding Contract ${fn}. Reward: ${reward}`);

@ -435,6 +435,12 @@ export class Sleeve extends Person {
* Called on every sleeve for a Source File prestige * Called on every sleeve for a Source File prestige
*/ */
prestige(p: IPlayer) { prestige(p: IPlayer) {
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.resetTaskStatus(); this.resetTaskStatus();
this.earningsForSleeves = createTaskTracker(); this.earningsForSleeves = createTaskTracker();
this.earningsForPlayer = createTaskTracker(); this.earningsForPlayer = createTaskTracker();

@ -14,6 +14,7 @@ import { Faction } from "./Faction/Faction";
import { Factions, import { Factions,
initFactions } from "./Faction/Factions"; initFactions } from "./Faction/Factions";
import { joinFaction } from "./Faction/FactionHelpers"; import { joinFaction } from "./Faction/FactionHelpers";
import { createHacknetServer } from "./Hacknet/HacknetHelpers";
import {deleteGangDisplayContent} from "./Gang"; import {deleteGangDisplayContent} from "./Gang";
import { Message } from "./Message/Message"; import { Message } from "./Message/Message";
import { initMessages, import { initMessages,
@ -29,7 +30,8 @@ import { AllServers,
prestigeAllServers } from "./Server/AllServers"; prestigeAllServers } from "./Server/AllServers";
import { Server } from "./Server/Server" import { Server } from "./Server/Server"
import { prestigeHomeComputer } from "./Server/ServerHelpers"; import { prestigeHomeComputer } from "./Server/ServerHelpers";
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags"; import { SourceFileFlags,
updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
import { SpecialServerIps, import { SpecialServerIps,
SpecialServerIpsMap, SpecialServerIpsMap,
prestigeSpecialServerIps, prestigeSpecialServerIps,
@ -200,49 +202,45 @@ function prestigeSourceFile() {
//Re-create foreign servers //Re-create foreign servers
initForeignServers(Player.getHomeComputer()); initForeignServers(Player.getHomeComputer());
var srcFile1Owned = false; if (SourceFileFlags[9] >= 2) {
for (var i = 0; i < Player.sourceFiles.length; ++i) { homeComp.setMaxRam(128);
if (Player.sourceFiles[i].n == 1) { } else if (SourceFileFlags[1] > 0) {
srcFile1Owned = true;
}
}
if (srcFile1Owned) {
homeComp.setMaxRam(32); homeComp.setMaxRam(32);
} else { } else {
homeComp.setMaxRam(8); homeComp.setMaxRam(8);
} }
homeComp.cpuCores = 1; homeComp.cpuCores = 1;
//Reset favor for Companies // Reset favor for Companies
for (var member in Companies) { for (var member in Companies) {
if (Companies.hasOwnProperty(member)) { if (Companies.hasOwnProperty(member)) {
Companies[member].favor = 0; Companies[member].favor = 0;
} }
} }
//Reset favor for factions // Reset favor for factions
for (var member in Factions) { for (var member in Factions) {
if (Factions.hasOwnProperty(member)) { if (Factions.hasOwnProperty(member)) {
Factions[member].favor = 0; Factions[member].favor = 0;
} }
} }
//Stop a Terminal action if there is one // Stop a Terminal action if there is one
if (Engine._actionInProgress) { if (Engine._actionInProgress) {
Engine._actionInProgress = false; Engine._actionInProgress = false;
Terminal.finishAction(true); Terminal.finishAction(true);
} }
//Delete all Augmentations // Delete all Augmentations
for (var name in Augmentations) { for (var name in Augmentations) {
if (Augmentations.hasOwnProperty(name)) { if (Augmentations.hasOwnProperty(name)) {
delete Augmentations[name]; delete Augmentations[name];
} }
} }
//Re-initialize things - This will update any changes // Re-initialize things - This will update any changes
initFactions(); //Factions must be initialized before augmentations initFactions(); // Factions must be initialized before augmentations
initAugmentations(); //Calls reapplyAllAugmentations() and resets Player multipliers initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
initCompanies(); initCompanies();
@ -324,7 +322,7 @@ function prestigeSourceFile() {
dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!"); dialogBoxCreate("Visit VitaLife in New Tokyo if you'd like to purchase a new sleeve!");
} }
//Reset Stock market, gang, and corporation // Reset Stock market, gang, and corporation
if (Player.hasWseAccount) { if (Player.hasWseAccount) {
initStockMarket(); initStockMarket();
initSymbolToStockMap(); initSymbolToStockMap();
@ -340,6 +338,16 @@ function prestigeSourceFile() {
Player.corporation = null; resetIndustryResearchTrees(); Player.corporation = null; resetIndustryResearchTrees();
Player.bladeburner = null; Player.bladeburner = null;
// Source-File 9 (level 3) effect
if (SourceFileFlags[9] >= 3) {
const hserver = createHacknetServer();
hserver.level = 100;
hserver.cores = 10;
hserver.cache = 5;
hserver.updateHashRate(Player);
hserver.updateHashCapacity();
Player.hashManager.updateCapacity(Player);
}
// Refresh Main Menu (the 'World' menu, specifically) // Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();

@ -101,8 +101,8 @@ let NetscriptFunctions =
// Hacknet Node API // Hacknet Node API
"hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" + "hacknet|numNodes|purchaseNode|getPurchaseNodeCost|getNodeStats|" +
"upgradeLevel|upgradeRam|upgradeCore|getLevelUpgradeCost|" + "upgradeLevel|upgradeRam|upgradeCore|upgradeCache|getLevelUpgradeCost|" +
"getRamUpgradeCost|getCoreUpgradeCost|" + "getRamUpgradeCost|getCoreUpgradeCost|getCacheUpgradeCost|" +
// Gang API // Gang API
"gang|" + "gang|" +

@ -177,9 +177,11 @@ CodeMirror.defineMode("netscript", function(config, parserConfig) {
"upgradeLevel": atom, "upgradeLevel": atom,
"upgradeRam": atom, "upgradeRam": atom,
"upgradeCore": atom, "upgradeCore": atom,
"upgradeCache": atom,
"getLevelUpgradeCost": atom, "getLevelUpgradeCost": atom,
"getRamUpgradeCost": atom, "getRamUpgradeCost": atom,
"getCoreUpgradeCost": atom, "getCoreUpgradeCost": atom,
"getCacheUpgradeCost": atom,
// Netscript Gang API // Netscript Gang API
"gang": atom, "gang": atom,

@ -62,7 +62,12 @@ function initSourceFiles() {
"Level 3: Ability to use limit/stop orders in other BitNodes<br><br>" + "Level 3: Ability to use limit/stop orders in other BitNodes<br><br>" +
"This Source-File also increases your hacking growth multipliers by: " + "This Source-File also increases your hacking growth multipliers by: " +
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%"); "<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
SourceFiles["SourceFile9"] = new SourceFile(9); SourceFiles["SourceFile9"] = new SourceFile(9, "This Source-File grants the following benefits:<br><br>" +
"Level 1: Permanently unlocks the Hacknet Server in other BitNodes<br>" +
"Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode<br>" +
"Level 3: Grants a highly-upgraded Hacknet Server 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 Augmentations)");
SourceFiles["SourceFile10"] = new SourceFile(10, "This Source-File unlocks Sleeve technology in other BitNodes. Each level of this " + SourceFiles["SourceFile10"] = new SourceFile(10, "This Source-File unlocks Sleeve technology in other BitNodes. Each level of this " +
"Source-File also grants you a Duplicate Sleeve"); "Source-File also grants you a Duplicate Sleeve");
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " + SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
@ -119,7 +124,7 @@ function applySourceFile(srcFile) {
Player.hacknet_node_level_cost_mult *= decMult; Player.hacknet_node_level_cost_mult *= decMult;
Player.work_money_mult *= incMult; Player.work_money_mult *= incMult;
break; break;
case 2: //Rise of the Underworld case 2: // Rise of the Underworld
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (24 / (Math.pow(2, i))); mult += (24 / (Math.pow(2, i)));
@ -129,7 +134,7 @@ function applySourceFile(srcFile) {
Player.crime_success_mult *= incMult; Player.crime_success_mult *= incMult;
Player.charisma_mult *= incMult; Player.charisma_mult *= incMult;
break; break;
case 3: //Corporatocracy case 3: // Corporatocracy
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i))); mult += (8 / (Math.pow(2, i)));
@ -138,10 +143,10 @@ function applySourceFile(srcFile) {
Player.charisma_mult *= incMult; Player.charisma_mult *= incMult;
Player.work_money_mult *= incMult; Player.work_money_mult *= incMult;
break; break;
case 4: //The Singularity case 4: // The Singularity
//No effects, just gives access to Singularity functions // No effects, just gives access to Singularity functions
break; break;
case 5: //Artificial Intelligence case 5: // Artificial Intelligence
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i))); mult += (8 / (Math.pow(2, i)));
@ -154,7 +159,7 @@ function applySourceFile(srcFile) {
Player.hacking_mult *= incMult; Player.hacking_mult *= incMult;
Player.hacking_exp_mult *= incMult; Player.hacking_exp_mult *= incMult;
break; break;
case 6: //Bladeburner case 6: // Bladeburner
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i))); mult += (8 / (Math.pow(2, i)));
@ -169,7 +174,7 @@ function applySourceFile(srcFile) {
Player.dexterity_mult *= incMult; Player.dexterity_mult *= incMult;
Player.agility_mult *= incMult; Player.agility_mult *= incMult;
break; break;
case 7: //Bladeburner 2079 case 7: // Bladeburner 2079
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i))); mult += (8 / (Math.pow(2, i)));
@ -180,7 +185,7 @@ function applySourceFile(srcFile) {
Player.bladeburner_analysis_mult *= incMult; Player.bladeburner_analysis_mult *= incMult;
Player.bladeburner_success_chance_mult *= incMult; Player.bladeburner_success_chance_mult *= incMult;
break; break;
case 8: //Ghost of Wall Street case 8: // Ghost of Wall Street
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (12 / (Math.pow(2, i))); mult += (12 / (Math.pow(2, i)));
@ -188,10 +193,13 @@ function applySourceFile(srcFile) {
var incMult = 1 + (mult / 100); var incMult = 1 + (mult / 100);
Player.hacking_grow_mult *= incMult; Player.hacking_grow_mult *= incMult;
break; break;
case 9: // Hacktocracy
// This has non-multiplier effects
break;
case 10: // Digital Carbon case 10: // Digital Carbon
// No effects, just grants sleeves // No effects, just grants sleeves
break; break;
case 11: //The Big Crash case 11: // The Big Crash
var mult = 0; var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) { for (var i = 0; i < srcFile.lvl; ++i) {
mult += (32 / (Math.pow(2, i))); mult += (32 / (Math.pow(2, i)));
@ -200,7 +208,7 @@ function applySourceFile(srcFile) {
Player.work_money_mult *= incMult; Player.work_money_mult *= incMult;
Player.company_rep_mult *= incMult; Player.company_rep_mult *= incMult;
break; break;
case 12: //The Recursion case 12: // The Recursion
var inc = Math.pow(1.01, srcFile.lvl); var inc = Math.pow(1.01, srcFile.lvl);
var dec = Math.pow(0.99, srcFile.lvl); var dec = Math.pow(0.99, srcFile.lvl);

@ -2,6 +2,7 @@ import {substituteAliases, printAliases,
parseAliasDeclaration, parseAliasDeclaration,
removeAlias, GlobalAliases, removeAlias, GlobalAliases,
Aliases} from "./Alias"; Aliases} from "./Alias";
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import {CodingContract, CodingContractResult, import {CodingContract, CodingContractResult,
CodingContractRewardType} from "./CodingContracts"; CodingContractRewardType} from "./CodingContracts";
import {CONSTANTS} from "./Constants"; import {CONSTANTS} from "./Constants";
@ -1246,23 +1247,26 @@ let Terminal = {
case "free": case "free":
Terminal.executeFreeCommand(commandArray); Terminal.executeFreeCommand(commandArray);
break; break;
case "hack": case "hack": {
if (commandArray.length !== 1) { if (commandArray.length !== 1) {
postError("Incorrect usage of hack command. Usage: hack"); postError("Incorrect usage of hack command. Usage: hack");
return; return;
} }
//Hack the current PC (usually for money) //Hack the current PC (usually for money)
//You can't hack your home pc or servers you purchased //You can't hack your home pc or servers you purchased
if (Player.getCurrentServer().purchasedByPlayer) { if (s.purchasedByPlayer) {
postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers"); postError("Cannot hack your own machines! You are currently connected to your home PC or one of your purchased servers");
} else if (Player.getCurrentServer().hasAdminRights == false ) { } else if (s.hasAdminRights == false ) {
postError("You do not have admin rights for this machine! Cannot hack"); postError("You do not have admin rights for this machine! Cannot hack");
} else if (Player.getCurrentServer().requiredHackingSkill > Player.hacking_skill) { } else if (s.requiredHackingSkill > Player.hacking_skill) {
postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill"); postError("Your hacking skill is not high enough to attempt hacking this machine. Try analyzing the machine to determine the required hacking skill");
} else { } else if (s instanceof HacknetServer) {
postError("Cannot hack this type of Server")
} else {
Terminal.startHack(); Terminal.startHack();
} }
break; break;
}
case "help": case "help":
if (commandArray.length !== 1 && commandArray.length !== 2) { if (commandArray.length !== 1 && commandArray.length !== 2) {
postError("Incorrect usage of help command. Usage: help"); postError("Incorrect usage of help command. Usage: help");
@ -1640,9 +1644,15 @@ let Terminal = {
postError("Incorrect usage of free command. Usage: free"); postError("Incorrect usage of free command. Usage: free");
return; return;
} }
post("Total: " + numeralWrapper.format(Player.getCurrentServer().maxRam, '0.00') + " GB"); const ram = numeralWrapper.format(Player.getCurrentServer().maxRam, '0.00');
post("Used: " + numeralWrapper.format(Player.getCurrentServer().ramUsed, '0.00') + " GB"); const used = numeralWrapper.format(Player.getCurrentServer().ramUsed, '0.00');
post("Available: " + numeralWrapper.format(Player.getCurrentServer().maxRam - Player.getCurrentServer().ramUsed, '0.00') + " GB"); const avail = numeralWrapper.format(Player.getCurrentServer().maxRam - Player.getCurrentServer().ramUsed, '0.00');
const maxLength = Math.max(ram.length, Math.max(used.length, avail.length));
const usedPercent = numeralWrapper.format(Player.getCurrentServer().ramUsed/Player.getCurrentServer().maxRam*100, '0.00');
post(`Total: ${" ".repeat(maxLength-ram.length)}${ram} GB`);
post(`Used: ${" ".repeat(maxLength-used.length)}${used} GB (${usedPercent}%)`);
post(`Available: ${" ".repeat(maxLength-avail.length)}${avail} GB`);
}, },
executeKillCommand: function(commandArray) { executeKillCommand: function(commandArray) {
@ -1894,7 +1904,7 @@ let Terminal = {
//var dashes = Array(d * 2 + 1).join("-"); //var dashes = Array(d * 2 + 1).join("-");
var c = "NO"; var c = "NO";
if (s.hasAdminRights) {c = "YES";} if (s.hasAdminRights) {c = "YES";}
post(`${dashes}Root Access: ${c} ${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`); post(`${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + s.requiredHackingSkill : ""}`);
if (!isHacknet) { post(dashes + "Number of open ports required to NUKE: " + s.numOpenPortsRequired); } if (!isHacknet) { post(dashes + "Number of open ports required to NUKE: " + s.numOpenPortsRequired); }
post(dashes + "RAM: " + s.maxRam); post(dashes + "RAM: " + s.maxRam);
post(" "); post(" ");
@ -2138,7 +2148,8 @@ let Terminal = {
post("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10."); post("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
}; };
programHandlers[Programs.Flight.name] = () => { programHandlers[Programs.Flight.name] = () => {
const fulfilled = Player.augmentations.length >= 30 && const numAugReq = Math.round(BitNodeMultipliers.DaedalusAugsRequirement*30)
const fulfilled = Player.augmentations.length >= numAugReq &&
Player.money.gt(1e11) && Player.money.gt(1e11) &&
((Player.hacking_skill >= 2500)|| ((Player.hacking_skill >= 2500)||
(Player.strength >= 1500 && (Player.strength >= 1500 &&
@ -2146,17 +2157,17 @@ let Terminal = {
Player.dexterity >= 1500 && Player.dexterity >= 1500 &&
Player.agility >= 1500)); Player.agility >= 1500));
if(!fulfilled) { if(!fulfilled) {
post("Augmentations: " + Player.augmentations.length + " / 30"); post(`Augmentations: ${Player.augmentations.length} / ${numAugReq}`);
post("Money: " + numeralWrapper.format(Player.money.toNumber(), '($0.000a)') + " / " + numeralWrapper.format(1e11, '($0.000a)')); post(`Money: ${numeralWrapper.format(Player.money.toNumber(), '($0.000a)')} / ${numeralWrapper.format(1e11, '($0.000a)')}`);
post("One path below must be fulfilled..."); post("One path below must be fulfilled...");
post("----------HACKING PATH----------"); post("----------HACKING PATH----------");
post("Hacking skill: " + Player.hacking_skill + " / 2500"); post(`Hacking skill: ${Player.hacking_skill} / 2500`);
post("----------COMBAT PATH----------"); post("----------COMBAT PATH----------");
post("Strength: " + Player.strength + " / 1500"); post(`Strength: ${Player.strength} / 1500`);
post("Defense: " + Player.defense + " / 1500"); post(`Defense: ${Player.defense} / 1500`);
post("Dexterity: " + Player.dexterity + " / 1500"); post(`Dexterity: ${Player.dexterity} / 1500`);
post("Agility: " + Player.agility + " / 1500"); post(`Agility: ${Player.agility} / 1500`);
return; return;
} }

@ -35,3 +35,12 @@ export interface ISelfLoading {
*/ */
load(saveState: string): void; load(saveState: string): void;
} }
/**
* Status object for functions that return a boolean indicating success/failure
* and an optional message
*/
export interface IReturnStatus {
res: boolean;
msg?: string;
}