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); }
.a-link-button-inactive,
.std-button-disabled,
.std-button:disabled {
text-decoration: none;
background-color: #333;
@ -501,11 +502,15 @@ button {
.a-link-button-inactive:hover .tooltiptext,
.a-link-button-inactive:hover .tooltiptexthigh,
.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 .tooltiptexthigh,
.std-button:disabled:hover .tooltiptextleft {
visibility: visible; }
.a-link-button-inactive:active,
.std-button-disabled:active,
.std-button:disabled:active {
pointer-events: none; }
@ -671,7 +676,7 @@ button {
/* COLORS */
/* Attributes */
/**
* Styling for the Character Overview Panel (top-right)
* Styling for the Character Overview Panel (top-right panel)
*/
#character-overview-wrapper {
position: relative; }
@ -927,6 +932,64 @@ button {
/* 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 */
/* Attributes */
/* CSS for different main menu pages, such as character info, script editor, etc (but excluding
@ -1044,64 +1107,6 @@ button {
color: #fff;
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-container {
position: fixed;
@ -1402,7 +1407,7 @@ button {
/* Pop-up boxes */
.popup-box-container {
display: none;
/* Hidden by default */
/* Initially hidden */
position: fixed;
/* Stay in place */
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
=========
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
-------------------
* Added two new Corporation Researches

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents.
#
# The short X.Y version.
version = '0.45'
version = '0.46'
# 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
# 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
=================================
.. warning:: This page contains spoilers for the game
.. js:function:: getNodeStats(i)
: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,
ram: Node's RAM,
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,
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>
upgradeRam() <hacknetnodeapi/upgradeRam>
upgradeCore() <hacknetnodeapi/upgradeCore>
upgradeCache() <hacknetnodeapi/upgradeCache>
getLevelUpgradeCost() <hacknetnodeapi/getLevelUpgradeCost>
getRamUpgradeCost() <hacknetnodeapi/getRamUpgradeCost>
getCoreUpgradeCost() <hacknetnodeapi/getCoreUpgradeCost>
getCacheUpgradeCost() <hacknetnodeapi/getCacheUpgradeCost>
.. _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.
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() {
return getServerMoneyAvailable("home");() <hacknetnodeapi/ return getServerMoneyAvailable("home");>
return getServerMoneyAvailable("home");
}
}() <hacknetnodeapi/>
disableLog("getServerMoneyAvailable");
disableLog("sleep");
cnt = 8;
var cnt = 8;
while(hacknet.numNodes() < cnt) {
res = hacknet.purchaseNode();
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) {
var cost = hacknet.getLevelUpgradeCost(i, 10);
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) {
var cost = hacknet.getRamUpgradeCost(i, 2);
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");
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");
print("All nodes upgraded to 16GB RAM");

@ -201,35 +201,7 @@
<!-- Hacknet Nodes -->
<div id="hacknet-nodes-container" class="generic-menupage-container">
<h1 id="hacknet-nodes-title"> Hacknet Nodes </h1>
<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>
<!-- React Component -->
</div>
<!-- World -->

@ -176,7 +176,21 @@ export function initBitNodes() {
BitNodes["BitNode9"] = new BitNode(9, "Hacktocracy", "Hacknet Unleashed",
"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 " +
"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",
"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 " +
@ -186,7 +200,7 @@ export function initBitNodes() {
"1. Re-sleeve: Purchase and transfer your consciousness into a new body<br>" +
"2. Duplicate Sleeves: Duplicate your consciousness into Synthoids, allowing you to perform different tasks synchronously<br><br>" +
"In this BitNode:<br><br>" +
"Your stats are significantly decreased.<br>" +
"Your stats are significantly decreased<br>" +
"All methods of gaining money are half as profitable (except Stock Market)<br>" +
"Purchased servers are more expensive, have less max RAM, and a lower maximum limit<br>" +
"Augmentations are 5x as expensive and require twice as much reputation<br><br>" +
@ -360,11 +374,15 @@ export function initBitNodeMultipliers(p: IPlayer) {
BitNodeMultipliers.HomeComputerRamCost = 5;
BitNodeMultipliers.CrimeMoney = 0.5;
BitNodeMultipliers.ScriptHackMoney = 0.1;
BitNodeMultipliers.HackExpGain = 0.1;
BitNodeMultipliers.HackExpGain = 0.05;
BitNodeMultipliers.ServerStartingMoney = 0.1;
BitNodeMultipliers.ServerMaxMoney = 0.1;
BitNodeMultipliers.ServerStartingSecurity = 2.5;
BitNodeMultipliers.CorporationValuation = 0.5;
BitNodeMultipliers.FourSigmaMarketDataCost = 5;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 4;
BitNodeMultipliers.BladeburnerRank = 0.9;
BitNodeMultipliers.BladeburnerSkillCost = 1.2;
break;
case 10: // Digital Carbon
BitNodeMultipliers.HackingLevelMultiplier = 0.2;

@ -6,7 +6,7 @@
import {IMap} from "./types";
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
//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:
** '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

@ -31,6 +31,7 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { getRandomInt } from "../../../utils/helpers/getRandomInt";
import { KEY } from "../../../utils/helpers/keyCodes";
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);
}
export function createHacknetServer() {
const numOwned = Player.hacknetNodes.length;
const name = `hacknet-node-${numOwned}`;
const server = new HacknetServer({
adminRights: true,
hostname: name,
player: Player,
});
Player.hacknetNodes.push(server.ip);
// Configure the HacknetServer to actually act as a Server
AddToAllServers(server);
const homeComputer = Player.getHomeComputer();
homeComputer.serversOnNetwork.push(server.ip);
server.serversOnNetwork.push(homeComputer.ip);
return server;
}
export function purchaseHacknet() {
/* INTERACTIVE TUTORIAL */
if (ITutorial.isRunning) {
@ -54,9 +73,9 @@ export function purchaseHacknet() {
return;
}
}
/* END INTERACTIVE TUTORIAL */
const numOwned = Player.hacknetNodes.length;
if (hasHacknetServers()) {
const cost = getCostOfNextHacknetServer();
if (isNaN(cost)) {
@ -64,24 +83,9 @@ export function purchaseHacknet() {
}
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.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);
const server = createHacknetServer();
Player.hashManager.updateCapacity(Player);
return numOwned;
} else {
@ -93,7 +97,6 @@ export function purchaseHacknet() {
if (!Player.canAfford(cost)) { return -1; }
// Auto generate a name for the Node
const numOwned = Player.hacknetNodes.length;
const name = "hacknet-node-" + numOwned;
const node = new HacknetNode(name);
node.updateMoneyGainRate(Player);
@ -396,11 +399,21 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
break;
}
case "Exchange for Bladeburner Rank": {
// This will throw if player doesn't have a corporation
// This will throw if player isnt in Bladeburner
try {
for (const division of Player.corporation.divisions) {
division.sciResearch.qty += upg.value;
Player.bladeburner.changeRank(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) {
Player.hashManager.refundUpgrade(upgName);
return false;
@ -413,6 +426,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
}
default:
console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`)
Player.hashManager.refundUpgrade(upgName);
return false;
}

@ -327,16 +327,17 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
updateHashRate(p: IPlayer): void {
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 hashRate = baseGain * coreMultiplier * ramRatio;
const hashRate = baseGain * ramMultiplier * coreMultiplier * ramRatio;
this.hashRate = hashRate * p.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney;
if (isNaN(this.hashRate)) {
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);
}
storeHashes(numHashes: number): void {
this.hashes += numHashes;
this.hashes = Math.min(this.hashes, this.capacity);
prestige(p: IPlayer): void {
for (const name in HashUpgrades) {
this.upgrades[name] = 0;
}
this.hashes = 0;
if (p != null) {
this.updateCapacity(p);
}
}
/**
@ -106,6 +111,11 @@ export class HashManager {
this.hashes += cost;
}
storeHashes(numHashes: number): void {
this.hashes += numHashes;
this.hashes = Math.min(this.hashes, this.capacity);
}
updateCapacity(p: IPlayer): void {
if (p.hacknetNodes.length <= 0) {
this.capacity = 0;

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

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

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

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

@ -14,6 +14,7 @@ import { Faction } from "./Faction/Faction";
import { Factions,
initFactions } from "./Faction/Factions";
import { joinFaction } from "./Faction/FactionHelpers";
import { createHacknetServer } from "./Hacknet/HacknetHelpers";
import {deleteGangDisplayContent} from "./Gang";
import { Message } from "./Message/Message";
import { initMessages,
@ -29,7 +30,8 @@ import { AllServers,
prestigeAllServers } from "./Server/AllServers";
import { Server } from "./Server/Server"
import { prestigeHomeComputer } from "./Server/ServerHelpers";
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
import { SourceFileFlags,
updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
import { SpecialServerIps,
SpecialServerIpsMap,
prestigeSpecialServerIps,
@ -200,49 +202,45 @@ function prestigeSourceFile() {
//Re-create foreign servers
initForeignServers(Player.getHomeComputer());
var srcFile1Owned = false;
for (var i = 0; i < Player.sourceFiles.length; ++i) {
if (Player.sourceFiles[i].n == 1) {
srcFile1Owned = true;
}
}
if (srcFile1Owned) {
if (SourceFileFlags[9] >= 2) {
homeComp.setMaxRam(128);
} else if (SourceFileFlags[1] > 0) {
homeComp.setMaxRam(32);
} else {
homeComp.setMaxRam(8);
}
homeComp.cpuCores = 1;
//Reset favor for Companies
// Reset favor for Companies
for (var member in Companies) {
if (Companies.hasOwnProperty(member)) {
Companies[member].favor = 0;
}
}
//Reset favor for factions
// Reset favor for factions
for (var member in Factions) {
if (Factions.hasOwnProperty(member)) {
Factions[member].favor = 0;
}
}
//Stop a Terminal action if there is one
// Stop a Terminal action if there is one
if (Engine._actionInProgress) {
Engine._actionInProgress = false;
Terminal.finishAction(true);
}
//Delete all Augmentations
// Delete all Augmentations
for (var name in Augmentations) {
if (Augmentations.hasOwnProperty(name)) {
delete Augmentations[name];
}
}
//Re-initialize things - This will update any changes
initFactions(); //Factions must be initialized before augmentations
initAugmentations(); //Calls reapplyAllAugmentations() and resets Player multipliers
// Re-initialize things - This will update any changes
initFactions(); // Factions must be initialized before augmentations
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
Player.reapplyAllSourceFiles();
initCompanies();
@ -324,7 +322,7 @@ function prestigeSourceFile() {
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) {
initStockMarket();
initSymbolToStockMap();
@ -340,6 +338,16 @@ function prestigeSourceFile() {
Player.corporation = null; resetIndustryResearchTrees();
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)
document.getElementById("world-menu-header").click();

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

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

@ -62,7 +62,12 @@ function initSourceFiles() {
"Level 3: Ability to use limit/stop orders in other BitNodes<br><br>" +
"This Source-File also increases your hacking growth multipliers by: " +
"<br>Level 1: 12%<br>Level 2: 18%<br>Level 3: 21%");
SourceFiles["SourceFile9"] = new SourceFile(9);
SourceFiles["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 " +
"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 " +
@ -119,7 +124,7 @@ function applySourceFile(srcFile) {
Player.hacknet_node_level_cost_mult *= decMult;
Player.work_money_mult *= incMult;
break;
case 2: //Rise of the Underworld
case 2: // Rise of the Underworld
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (24 / (Math.pow(2, i)));
@ -129,7 +134,7 @@ function applySourceFile(srcFile) {
Player.crime_success_mult *= incMult;
Player.charisma_mult *= incMult;
break;
case 3: //Corporatocracy
case 3: // Corporatocracy
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i)));
@ -138,10 +143,10 @@ function applySourceFile(srcFile) {
Player.charisma_mult *= incMult;
Player.work_money_mult *= incMult;
break;
case 4: //The Singularity
//No effects, just gives access to Singularity functions
case 4: // The Singularity
// No effects, just gives access to Singularity functions
break;
case 5: //Artificial Intelligence
case 5: // Artificial Intelligence
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i)));
@ -154,7 +159,7 @@ function applySourceFile(srcFile) {
Player.hacking_mult *= incMult;
Player.hacking_exp_mult *= incMult;
break;
case 6: //Bladeburner
case 6: // Bladeburner
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i)));
@ -169,7 +174,7 @@ function applySourceFile(srcFile) {
Player.dexterity_mult *= incMult;
Player.agility_mult *= incMult;
break;
case 7: //Bladeburner 2079
case 7: // Bladeburner 2079
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (8 / (Math.pow(2, i)));
@ -180,7 +185,7 @@ function applySourceFile(srcFile) {
Player.bladeburner_analysis_mult *= incMult;
Player.bladeburner_success_chance_mult *= incMult;
break;
case 8: //Ghost of Wall Street
case 8: // Ghost of Wall Street
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (12 / (Math.pow(2, i)));
@ -188,10 +193,13 @@ function applySourceFile(srcFile) {
var incMult = 1 + (mult / 100);
Player.hacking_grow_mult *= incMult;
break;
case 9: // Hacktocracy
// This has non-multiplier effects
break;
case 10: // Digital Carbon
// No effects, just grants sleeves
break;
case 11: //The Big Crash
case 11: // The Big Crash
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (32 / (Math.pow(2, i)));
@ -200,7 +208,7 @@ function applySourceFile(srcFile) {
Player.work_money_mult *= incMult;
Player.company_rep_mult *= incMult;
break;
case 12: //The Recursion
case 12: // The Recursion
var inc = Math.pow(1.01, srcFile.lvl);
var dec = Math.pow(0.99, srcFile.lvl);

@ -2,6 +2,7 @@ import {substituteAliases, printAliases,
parseAliasDeclaration,
removeAlias, GlobalAliases,
Aliases} from "./Alias";
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import {CodingContract, CodingContractResult,
CodingContractRewardType} from "./CodingContracts";
import {CONSTANTS} from "./Constants";
@ -1246,23 +1247,26 @@ let Terminal = {
case "free":
Terminal.executeFreeCommand(commandArray);
break;
case "hack":
case "hack": {
if (commandArray.length !== 1) {
postError("Incorrect usage of hack command. Usage: hack");
return;
}
//Hack the current PC (usually for money)
//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");
} else if (Player.getCurrentServer().hasAdminRights == false ) {
} else if (s.hasAdminRights == false ) {
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");
} else if (s instanceof HacknetServer) {
postError("Cannot hack this type of Server")
} else {
Terminal.startHack();
}
break;
}
case "help":
if (commandArray.length !== 1 && commandArray.length !== 2) {
postError("Incorrect usage of help command. Usage: help");
@ -1640,9 +1644,15 @@ let Terminal = {
postError("Incorrect usage of free command. Usage: free");
return;
}
post("Total: " + numeralWrapper.format(Player.getCurrentServer().maxRam, '0.00') + " GB");
post("Used: " + numeralWrapper.format(Player.getCurrentServer().ramUsed, '0.00') + " GB");
post("Available: " + numeralWrapper.format(Player.getCurrentServer().maxRam - Player.getCurrentServer().ramUsed, '0.00') + " GB");
const ram = numeralWrapper.format(Player.getCurrentServer().maxRam, '0.00');
const used = numeralWrapper.format(Player.getCurrentServer().ramUsed, '0.00');
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) {
@ -1894,7 +1904,7 @@ let Terminal = {
//var dashes = Array(d * 2 + 1).join("-");
var c = "NO";
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); }
post(dashes + "RAM: " + s.maxRam);
post(" ");
@ -2138,7 +2148,8 @@ let Terminal = {
post("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10.");
};
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.hacking_skill >= 2500)||
(Player.strength >= 1500 &&
@ -2146,17 +2157,17 @@ let Terminal = {
Player.dexterity >= 1500 &&
Player.agility >= 1500));
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("----------HACKING PATH----------");
post("Hacking skill: " + Player.hacking_skill + " / 2500");
post(`Hacking skill: ${Player.hacking_skill} / 2500`);
post("----------COMBAT PATH----------");
post("Strength: " + Player.strength + " / 1500");
post("Defense: " + Player.defense + " / 1500");
post("Dexterity: " + Player.dexterity + " / 1500");
post("Agility: " + Player.agility + " / 1500");
post(`Strength: ${Player.strength} / 1500`);
post(`Defense: ${Player.defense} / 1500`);
post(`Dexterity: ${Player.dexterity} / 1500`);
post(`Agility: ${Player.agility} / 1500`);
return;
}

@ -35,3 +35,12 @@ export interface ISelfLoading {
*/
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;
}