prettify, sorry for the big ass commit

This commit is contained in:
Olivier Gagnon
2021-09-04 19:09:30 -04:00
parent 3d7cdb4ef9
commit a18bdd6afc
554 changed files with 91615 additions and 66138 deletions
File diff suppressed because it is too large Load Diff
+112 -97
View File
@@ -9,125 +9,140 @@ import { IHacknetNode } from "./IHacknetNode";
import { CONSTANTS } from "../Constants";
import {
calculateMoneyGainRate,
calculateLevelUpgradeCost,
calculateCoreUpgradeCost,
calculateRamUpgradeCost,
calculateMoneyGainRate,
calculateLevelUpgradeCost,
calculateCoreUpgradeCost,
calculateRamUpgradeCost,
} from "./formulas/HacknetNodes";
import { HacknetNodeConstants } from "./data/Constants";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { Generic_fromJSON,
Generic_toJSON,
Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export class HacknetNode implements IHacknetNode {
// Node's number of cores
cores = 1;
// Node's number of cores
cores = 1;
// Node's Level
level = 1;
// Node's Level
level = 1;
// Node's production per second
moneyGainRatePerSecond = 0;
// Node's production per second
moneyGainRatePerSecond = 0;
// Identifier for Node. Includes the full "name" (hacknet-node-N)
name: string;
// Identifier for Node. Includes the full "name" (hacknet-node-N)
name: string;
// How long this Node has existed, in seconds
onlineTimeSeconds = 0;
// How long this Node has existed, in seconds
onlineTimeSeconds = 0;
// Node's RAM (GB)
ram = 1;
// Node's RAM (GB)
ram = 1;
// Total money earned by this Node
totalMoneyGenerated = 0;
// Total money earned by this Node
totalMoneyGenerated = 0;
constructor(name = "", prodMult = 1) {
this.name = name;
constructor(name="", prodMult=1) {
this.name = name;
this.updateMoneyGainRate(prodMult);
}
this.updateMoneyGainRate(prodMult);
// Get the cost to upgrade this Node's number of cores
calculateCoreUpgradeCost(levels = 1, costMult: number): number {
return calculateCoreUpgradeCost(this.cores, levels, costMult);
}
// Get the cost to upgrade this Node's level
calculateLevelUpgradeCost(levels = 1, costMult: number): number {
return calculateLevelUpgradeCost(this.level, levels, costMult);
}
// Get the cost to upgrade this Node's RAM
calculateRamUpgradeCost(levels = 1, costMult: number): number {
return calculateRamUpgradeCost(this.ram, levels, costMult);
}
// Process this Hacknet Node in the game loop.
// Returns the amount of money generated
process(numCycles = 1): number {
const seconds = (numCycles * CONSTANTS.MilliPerCycle) / 1000;
let gain = this.moneyGainRatePerSecond * seconds;
if (isNaN(gain)) {
console.error(`Hacknet Node ${this.name} calculated earnings of NaN`);
gain = 0;
}
// Get the cost to upgrade this Node's number of cores
calculateCoreUpgradeCost(levels=1, costMult: number): number {
return calculateCoreUpgradeCost(this.cores, levels, costMult);
this.totalMoneyGenerated += gain;
this.onlineTimeSeconds += seconds;
return gain;
}
// Upgrade this Node's number of cores, if possible
// Returns a boolean indicating whether new cores were successfully bought
upgradeCore(levels = 1, prodMult: number): void {
this.cores = Math.min(
HacknetNodeConstants.MaxCores,
Math.round(this.cores + levels),
);
this.updateMoneyGainRate(prodMult);
}
// Upgrade this Node's level, if possible
// Returns a boolean indicating whether the level was successfully updated
upgradeLevel(levels = 1, prodMult: number): void {
this.level = Math.min(
HacknetNodeConstants.MaxLevel,
Math.round(this.level + levels),
);
this.updateMoneyGainRate(prodMult);
}
// Upgrade this Node's RAM, if possible
// Returns a boolean indicating whether the RAM was successfully upgraded
upgradeRam(levels = 1, prodMult: number): void {
for (let i = 0; i < levels; ++i) {
this.ram *= 2; // Ram is always doubled
}
this.ram = Math.round(this.ram); // Handle any floating point precision issues
this.updateMoneyGainRate(prodMult);
}
// Get the cost to upgrade this Node's level
calculateLevelUpgradeCost(levels=1, costMult: number): number {
return calculateLevelUpgradeCost(this.level, levels, costMult);
// Re-calculate this Node's production and update the moneyGainRatePerSecond prop
updateMoneyGainRate(prodMult: number): void {
this.moneyGainRatePerSecond = calculateMoneyGainRate(
this.level,
this.ram,
this.cores,
prodMult,
);
if (isNaN(this.moneyGainRatePerSecond)) {
this.moneyGainRatePerSecond = 0;
dialogBoxCreate(
"Error in calculating Hacknet Node production. Please report to game developer",
false,
);
}
}
// Get the cost to upgrade this Node's RAM
calculateRamUpgradeCost(levels=1, costMult: number): number {
return calculateRamUpgradeCost(this.ram, levels, costMult);
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("HacknetNode", this);
}
// Process this Hacknet Node in the game loop.
// Returns the amount of money generated
process(numCycles=1): number {
const seconds = numCycles * CONSTANTS.MilliPerCycle / 1000;
let gain = this.moneyGainRatePerSecond * seconds;
if (isNaN(gain)) {
console.error(`Hacknet Node ${this.name} calculated earnings of NaN`);
gain = 0;
}
this.totalMoneyGenerated += gain;
this.onlineTimeSeconds += seconds;
return gain;
}
// Upgrade this Node's number of cores, if possible
// Returns a boolean indicating whether new cores were successfully bought
upgradeCore(levels=1, prodMult: number): void {
this.cores = Math.min(HacknetNodeConstants.MaxCores, Math.round(this.cores + levels));
this.updateMoneyGainRate(prodMult);
}
// Upgrade this Node's level, if possible
// Returns a boolean indicating whether the level was successfully updated
upgradeLevel(levels=1, prodMult: number): void {
this.level = Math.min(HacknetNodeConstants.MaxLevel, Math.round(this.level + levels));
this.updateMoneyGainRate(prodMult);
}
// Upgrade this Node's RAM, if possible
// Returns a boolean indicating whether the RAM was successfully upgraded
upgradeRam(levels=1, prodMult: number): void {
for (let i = 0; i < levels; ++i) {
this.ram *= 2; // Ram is always doubled
}
this.ram = Math.round(this.ram); // Handle any floating point precision issues
this.updateMoneyGainRate(prodMult);
}
// Re-calculate this Node's production and update the moneyGainRatePerSecond prop
updateMoneyGainRate(prodMult: number): void {
this.moneyGainRatePerSecond = calculateMoneyGainRate(this.level, this.ram, this.cores, prodMult);
if (isNaN(this.moneyGainRatePerSecond)) {
this.moneyGainRatePerSecond = 0;
dialogBoxCreate("Error in calculating Hacknet Node production. Please report to game developer", false);
}
}
/**
* Serialize the current object to a JSON save state.
*/
toJSON(): any {
return Generic_toJSON("HacknetNode", this);
}
/**
* Initiatizes a HacknetNode object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HacknetNode {
return Generic_fromJSON(HacknetNode, value.data);
}
/**
* Initiatizes a HacknetNode object from a JSON save state.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HacknetNode {
return Generic_fromJSON(HacknetNode, value.data);
}
}
Reviver.constructors.HacknetNode = HacknetNode;
+129 -107
View File
@@ -8,140 +8,162 @@ import { IHacknetNode } from "./IHacknetNode";
import { BaseServer } from "../Server/BaseServer";
import { RunningScript } from "../Script/RunningScript";
import { HacknetServerConstants } from "./data/Constants";
import {
calculateHashGainRate,
calculateLevelUpgradeCost,
calculateRamUpgradeCost,
calculateCoreUpgradeCost,
calculateCacheUpgradeCost,
import {
calculateHashGainRate,
calculateLevelUpgradeCost,
calculateRamUpgradeCost,
calculateCoreUpgradeCost,
calculateCacheUpgradeCost,
} from "./formulas/HacknetServers";
import { createRandomIp } from "../../utils/IPAddress";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
interface IConstructorParams {
adminRights?: boolean;
hostname: string;
ip?: string;
isConnectedTo?: boolean;
maxRam?: number;
organizationName?: string;
adminRights?: boolean;
hostname: string;
ip?: string;
isConnectedTo?: boolean;
maxRam?: number;
organizationName?: string;
}
export class HacknetServer extends BaseServer implements IHacknetNode {
// Cache level. Affects hash Capacity
cache = 1;
// Cache level. Affects hash Capacity
cache = 1;
// Number of cores. Improves hash production
cores = 1;
// Number of cores. Improves hash production
cores = 1;
// Number of hashes that can be stored by this Hacknet Server
hashCapacity = 0;
// Number of hashes that can be stored by this Hacknet Server
hashCapacity = 0;
// Hashes produced per second
hashRate = 0;
// Hashes produced per second
hashRate = 0;
// Similar to Node level. Improves hash production
level = 1;
// Similar to Node level. Improves hash production
level = 1;
// How long this HacknetServer has existed, in seconds
onlineTimeSeconds = 0;
// How long this HacknetServer has existed, in seconds
onlineTimeSeconds = 0;
// Total number of hashes earned by this server
totalHashesGenerated = 0;
// Total number of hashes earned by this server
totalHashesGenerated = 0;
constructor(
params: IConstructorParams = { hostname: "", ip: createRandomIp() },
) {
super(params);
constructor(params: IConstructorParams={ hostname: "", ip: createRandomIp() }) {
super(params);
this.maxRam = 1;
this.updateHashCapacity();
}
this.maxRam = 1;
this.updateHashCapacity();
calculateCacheUpgradeCost(levels: number): number {
return calculateCacheUpgradeCost(this.cache, levels);
}
calculateCoreUpgradeCost(levels: number, costMult: number): number {
return calculateCoreUpgradeCost(this.cores, levels, costMult);
}
calculateLevelUpgradeCost(levels: number, costMult: number): number {
return calculateLevelUpgradeCost(this.level, levels, costMult);
}
calculateRamUpgradeCost(levels: number, costMult: number): number {
return calculateRamUpgradeCost(this.maxRam, levels, costMult);
}
// Process this Hacknet Server in the game loop. Returns the number of hashes generated
process(numCycles = 1): number {
const seconds = (numCycles * CONSTANTS.MilliPerCycle) / 1000;
return this.hashRate * seconds;
}
upgradeCache(levels: number): void {
this.cache = Math.min(
HacknetServerConstants.MaxCache,
Math.round(this.cache + levels),
);
this.updateHashCapacity();
}
upgradeCore(levels: number, prodMult: number): void {
this.cores = Math.min(
HacknetServerConstants.MaxCores,
Math.round(this.cores + levels),
);
this.updateHashRate(prodMult);
}
upgradeLevel(levels: number, prodMult: number): void {
this.level = Math.min(
HacknetServerConstants.MaxLevel,
Math.round(this.level + levels),
);
this.updateHashRate(prodMult);
}
upgradeRam(levels: number, prodMult: number): boolean {
for (let i = 0; i < levels; ++i) {
this.maxRam *= 2;
}
this.maxRam = Math.min(
HacknetServerConstants.MaxRam,
Math.round(this.maxRam),
);
this.updateHashRate(prodMult);
calculateCacheUpgradeCost(levels: number): number {
return calculateCacheUpgradeCost(this.cache, levels);
return true;
}
// Whenever a script is run, we must update this server's hash rate
runScript(script: RunningScript, prodMult?: number): void {
super.runScript(script);
if (prodMult != null && typeof prodMult === "number") {
this.updateHashRate(prodMult);
}
}
calculateCoreUpgradeCost(levels: number, costMult: number): number {
return calculateCoreUpgradeCost(this.cores, levels, costMult);
updateHashCapacity(): void {
this.hashCapacity = 32 * Math.pow(2, this.cache);
}
updateHashRate(prodMult: number): void {
this.hashRate = calculateHashGainRate(
this.level,
this.ramUsed,
this.maxRam,
this.cores,
prodMult,
);
if (isNaN(this.hashRate)) {
this.hashRate = 0;
console.error(
`Error calculating Hacknet Server hash production. This is a bug. Please report to game dev`,
false,
);
}
}
calculateLevelUpgradeCost(levels: number, costMult: number): number {
return calculateLevelUpgradeCost(this.level, levels, costMult);
}
// Serialize the current object to a JSON save state
toJSON(): any {
return Generic_toJSON("HacknetServer", this);
}
calculateRamUpgradeCost(levels: number, costMult: number): number {
return calculateRamUpgradeCost(this.maxRam, levels, costMult);
}
// Process this Hacknet Server in the game loop. Returns the number of hashes generated
process(numCycles=1): number {
const seconds = numCycles * CONSTANTS.MilliPerCycle / 1000;
return this.hashRate * seconds;
}
upgradeCache(levels: number): void {
this.cache = Math.min(HacknetServerConstants.MaxCache, Math.round(this.cache + levels));
this.updateHashCapacity();
}
upgradeCore(levels: number, prodMult: number): void {
this.cores = Math.min(HacknetServerConstants.MaxCores, Math.round(this.cores + levels));
this.updateHashRate(prodMult);
}
upgradeLevel(levels: number, prodMult: number): void {
this.level = Math.min(HacknetServerConstants.MaxLevel, Math.round(this.level + levels));
this.updateHashRate(prodMult);
}
upgradeRam(levels: number, prodMult: number): boolean {
for (let i = 0; i < levels; ++i) {
this.maxRam *= 2;
}
this.maxRam = Math.min(HacknetServerConstants.MaxRam, Math.round(this.maxRam));
this.updateHashRate(prodMult);
return true;
}
// Whenever a script is run, we must update this server's hash rate
runScript(script: RunningScript, prodMult?: number): void {
super.runScript(script);
if (prodMult != null && typeof prodMult === "number") {
this.updateHashRate(prodMult);
}
}
updateHashCapacity(): void {
this.hashCapacity = 32 * Math.pow(2, this.cache);
}
updateHashRate(prodMult: number): void {
this.hashRate = calculateHashGainRate(this.level, this.ramUsed, this.maxRam, this.cores, prodMult)
if (isNaN(this.hashRate)) {
this.hashRate = 0;
console.error(`Error calculating Hacknet Server hash production. This is a bug. Please report to game dev`, false);
}
}
// Serialize the current object to a JSON save state
toJSON(): any {
return Generic_toJSON("HacknetServer", this);
}
// Initializes a HacknetServer Object from a JSON save state
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HacknetServer {
return Generic_fromJSON(HacknetServer, value.data);
}
// Initializes a HacknetServer Object from a JSON save state
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HacknetServer {
return Generic_fromJSON(HacknetServer, value.data);
}
}
Reviver.constructors.HacknetServer = HacknetServer;
+138 -129
View File
@@ -10,157 +10,166 @@ import { HashUpgrades } from "./HashUpgrades";
import { HashUpgrade } from "./HashUpgrade";
import { IMap } from "../types";
import { Generic_fromJSON,
Generic_toJSON,
Reviver } from "../../utils/JSONReviver";
import {
Generic_fromJSON,
Generic_toJSON,
Reviver,
} from "../../utils/JSONReviver";
export class HashManager {
// Max number of hashes this can hold. Equal to the sum of capacities of
// all Hacknet Servers
capacity = 0;
// Max number of hashes this can hold. Equal to the sum of capacities of
// all Hacknet Servers
capacity = 0;
// Number of hashes currently in storage
hashes = 0;
// Number of hashes currently in storage
hashes = 0;
// Map of Hash Upgrade Name -> levels in that upgrade
upgrades: IMap<number> = {};
// Map of Hash Upgrade Name -> levels in that upgrade
upgrades: IMap<number> = {};
constructor() {
for (const name in HashUpgrades) {
this.upgrades[name] = 0;
}
}
constructor() {
for (const name in HashUpgrades) {
this.upgrades[name] = 0;
}
/**
* Generic helper function for getting a multiplier from a HashUpgrade
*/
getMult(upgName: string): number {
const upg = HashUpgrades[upgName];
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null) {
console.error(`Could not find Hash Study upgrade`);
return 1;
}
/**
* Generic helper function for getting a multiplier from a HashUpgrade
*/
getMult(upgName: string): number {
const upg = HashUpgrades[upgName];
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null) {
console.error(`Could not find Hash Study upgrade`);
return 1;
}
return 1 + (upg.value * currLevel) / 100;
}
return 1 + ((upg.value * currLevel) / 100);
/**
* One of the Hash upgrades improves studying. This returns that multiplier
*/
getStudyMult(): number {
const upgName = "Improve Studying";
return this.getMult(upgName);
}
/**
* One of the Hash upgrades improves gym training. This returns that multiplier
*/
getTrainingMult(): number {
const upgName = "Improve Gym Training";
return this.getMult(upgName);
}
getUpgrade(upgName: string): HashUpgrade | null {
const upg = HashUpgrades[upgName];
if (!upg) {
console.error(
`Invalid Upgrade Name given to HashManager.getUpgrade(): ${upgName}`,
);
return null;
}
return upg;
}
/**
* Get the cost (in hashes) of an upgrade
*/
getUpgradeCost(upgName: string): number {
const upg = this.getUpgrade(upgName);
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null) {
console.error(
`Invalid Upgrade Name given to HashManager.getUpgradeCost(): ${upgName}`,
);
return Infinity;
}
/**
* One of the Hash upgrades improves studying. This returns that multiplier
*/
getStudyMult(): number {
const upgName = "Improve Studying";
return upg.getCost(currLevel);
}
return this.getMult(upgName);
prestige(): void {
for (const name in HashUpgrades) {
this.upgrades[name] = 0;
}
this.hashes = 0;
// When prestiging, player's hacknet nodes are always reset. So capacity = 0
this.updateCapacity(0);
}
/**
* Reverts an upgrade and refunds the hashes used to buy it
*/
refundUpgrade(upgName: string): void {
const upg = HashUpgrades[upgName];
// Reduce the level first, so we get the right cost
--this.upgrades[upgName];
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null || currLevel < 0) {
console.error(
`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`,
);
return;
}
/**
* One of the Hash upgrades improves gym training. This returns that multiplier
*/
getTrainingMult(): number {
const upgName = "Improve Gym Training";
const cost = upg.getCost(currLevel);
this.hashes += cost;
}
return this.getMult(upgName);
storeHashes(numHashes: number): void {
this.hashes += numHashes;
this.hashes = Math.min(this.hashes, this.capacity);
}
updateCapacity(newCap: number): void {
if (newCap < 0) {
this.capacity = 0;
}
this.capacity = Math.max(newCap, 0);
}
/**
* Returns boolean indicating whether or not the upgrade was successfully purchased
* Note that this does NOT actually implement the effect
*/
upgrade(upgName: string): boolean {
const upg = HashUpgrades[upgName];
if (upg == null) {
console.error(
`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`,
);
return false;
}
getUpgrade(upgName: string): HashUpgrade | null {
const upg = HashUpgrades[upgName];
if (!upg) {
console.error(`Invalid Upgrade Name given to HashManager.getUpgrade(): ${upgName}`);
return null;
}
return upg;
const cost = this.getUpgradeCost(upgName);
if (this.hashes < cost) {
return false;
}
/**
* Get the cost (in hashes) of an upgrade
*/
getUpgradeCost(upgName: string): number {
const upg = this.getUpgrade(upgName);
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null) {
console.error(`Invalid Upgrade Name given to HashManager.getUpgradeCost(): ${upgName}`);
return Infinity;
}
this.hashes -= cost;
++this.upgrades[upgName];
return upg.getCost(currLevel);
}
return true;
}
prestige(): void {
for (const name in HashUpgrades) {
this.upgrades[name] = 0;
}
this.hashes = 0;
//Serialize the current object to a JSON save state.
toJSON(): any {
return Generic_toJSON("HashManager", this);
}
// When prestiging, player's hacknet nodes are always reset. So capacity = 0
this.updateCapacity(0);
}
/**
* Reverts an upgrade and refunds the hashes used to buy it
*/
refundUpgrade(upgName: string): void {
const upg = HashUpgrades[upgName];
// Reduce the level first, so we get the right cost
--this.upgrades[upgName];
const currLevel = this.upgrades[upgName];
if (upg == null || currLevel == null || currLevel < 0) {
console.error(`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`);
return;
}
const cost = upg.getCost(currLevel);
this.hashes += cost;
}
storeHashes(numHashes: number): void {
this.hashes += numHashes;
this.hashes = Math.min(this.hashes, this.capacity);
}
updateCapacity(newCap: number): void {
if (newCap < 0) {
this.capacity = 0;
}
this.capacity = Math.max(newCap, 0);
}
/**
* Returns boolean indicating whether or not the upgrade was successfully purchased
* Note that this does NOT actually implement the effect
*/
upgrade(upgName: string): boolean {
const upg = HashUpgrades[upgName];
if (upg == null) {
console.error(`Invalid Upgrade Name given to HashManager.upgrade(): ${upgName}`);
return false;
}
const cost = this.getUpgradeCost(upgName);
if (this.hashes < cost) {
return false;
}
this.hashes -= cost;
++this.upgrades[upgName];
return true;
}
//Serialize the current object to a JSON save state.
toJSON(): any {
return Generic_toJSON("HashManager", this);
}
// Initiatizes a HashManager object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HashManager {
return Generic_fromJSON(HashManager, value.data);
}
// Initiatizes a HashManager object from a JSON save state.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
static fromJSON(value: any): HashManager {
return Generic_fromJSON(HashManager, value.data);
}
}
Reviver.constructors.HashManager = HashManager;
+53 -47
View File
@@ -2,65 +2,71 @@
* Object representing an upgrade that can be purchased with hashes
*/
export interface IConstructorParams {
cost?: number;
costPerLevel: number;
desc: string;
hasTargetServer?: boolean;
name: string;
value: number;
effectText?: (level: number) => JSX.Element | null;
cost?: number;
costPerLevel: number;
desc: string;
hasTargetServer?: boolean;
name: string;
value: number;
effectText?: (level: number) => JSX.Element | null;
}
export class HashUpgrade {
/**
* If the upgrade has a flat cost (never increases), it goes here
* Otherwise, this property should be undefined
*
* This property overrides the 'costPerLevel' property
*/
cost?: number;
/**
* If the upgrade has a flat cost (never increases), it goes here
* Otherwise, this property should be undefined
*
* This property overrides the 'costPerLevel' property
*/
cost?: number;
/**
* Base cost for this upgrade. Every time the upgrade is purchased,
* its cost increases by this same amount (so its 1x, 2x, 3x, 4x, etc.)
*/
costPerLevel = 0;
/**
* Base cost for this upgrade. Every time the upgrade is purchased,
* its cost increases by this same amount (so its 1x, 2x, 3x, 4x, etc.)
*/
costPerLevel = 0;
/**
* Description of what the upgrade does
*/
desc = "";
/**
* Description of what the upgrade does
*/
desc = "";
/**
* Boolean indicating that this upgrade's effect affects a single server,
* the "target" server
*/
hasTargetServer = false;
/**
* Boolean indicating that this upgrade's effect affects a single server,
* the "target" server
*/
hasTargetServer = false;
// Name of upgrade
name = "";
// Name of upgrade
name = "";
// Generic value used to indicate the potency/amount of this upgrade's effect
// The meaning varies between different upgrades
value = 0;
// Generic value used to indicate the potency/amount of this upgrade's effect
// The meaning varies between different upgrades
value = 0;
constructor(p: IConstructorParams) {
if (p.cost != null) { this.cost = p.cost; }
if (p.effectText != null) { this.effectText = p.effectText; }
this.costPerLevel = p.costPerLevel;
this.desc = p.desc;
this.hasTargetServer = p.hasTargetServer ? p.hasTargetServer : false;
this.name = p.name;
this.value = p.value;
constructor(p: IConstructorParams) {
if (p.cost != null) {
this.cost = p.cost;
}
if (p.effectText != null) {
this.effectText = p.effectText;
}
// Functions that returns the UI element to display the effect of this upgrade.
effectText: (level: number) => JSX.Element | null = () => null;
this.costPerLevel = p.costPerLevel;
this.desc = p.desc;
this.hasTargetServer = p.hasTargetServer ? p.hasTargetServer : false;
this.name = p.name;
this.value = p.value;
}
getCost(levels: number): number {
if (typeof this.cost === "number") { return this.cost; }
// Functions that returns the UI element to display the effect of this upgrade.
effectText: (level: number) => JSX.Element | null = () => null;
return Math.round((levels + 1) * this.costPerLevel);
getCost(levels: number): number {
if (typeof this.cost === "number") {
return this.cost;
}
return Math.round((levels + 1) * this.costPerLevel);
}
}
+3 -4
View File
@@ -2,17 +2,16 @@
* Map of all Hash Upgrades
* Key = Hash name, Value = HashUpgrade object
*/
import { HashUpgrade,
IConstructorParams } from "./HashUpgrade";
import { HashUpgrade, IConstructorParams } from "./HashUpgrade";
import { HashUpgradesMetadata } from "./data/HashUpgradesMetadata";
import { IMap } from "../types";
export const HashUpgrades: IMap<HashUpgrade> = {};
function createHashUpgrade(p: IConstructorParams): void {
HashUpgrades[p.name] = new HashUpgrade(p);
HashUpgrades[p.name] = new HashUpgrade(p);
}
for (const metadata of HashUpgradesMetadata) {
createHashUpgrade(metadata);
createHashUpgrade(metadata);
}
+9 -9
View File
@@ -1,14 +1,14 @@
// Interface for a Hacknet Node. Implemented by both a basic Hacknet Node,
// and the upgraded Hacknet Server in BitNode-9
export interface IHacknetNode {
cores: number;
level: number;
onlineTimeSeconds: number;
cores: number;
level: number;
onlineTimeSeconds: number;
calculateCoreUpgradeCost: (levels: number, costMult: number) => number;
calculateLevelUpgradeCost: (levels: number, costMult: number) => number;
calculateRamUpgradeCost: (levels: number, costMult: number) => number;
upgradeCore: (levels: number, prodMult: number) => void;
upgradeLevel: (levels: number, prodMult: number) => void;
upgradeRam: (levels: number, prodMult: number) => void;
calculateCoreUpgradeCost: (levels: number, costMult: number) => number;
calculateLevelUpgradeCost: (levels: number, costMult: number) => number;
calculateRamUpgradeCost: (levels: number, costMult: number) => number;
upgradeCore: (levels: number, prodMult: number) => void;
upgradeLevel: (levels: number, prodMult: number) => void;
upgradeRam: (levels: number, prodMult: number) => void;
}
+65 -65
View File
@@ -1,80 +1,80 @@
export const HacknetNodeConstants: {
// Constants for Hacknet Node production
MoneyGainPerLevel: number;
// Constants for Hacknet Node production
MoneyGainPerLevel: number;
// Constants for Hacknet Node purchase/upgrade costs
BaseCost: number;
LevelBaseCost: number;
RamBaseCost: number;
CoreBaseCost: number;
// Constants for Hacknet Node purchase/upgrade costs
BaseCost: number;
LevelBaseCost: number;
RamBaseCost: number;
CoreBaseCost: number;
PurchaseNextMult: number;
UpgradeLevelMult: number;
UpgradeRamMult: number;
UpgradeCoreMult: number;
PurchaseNextMult: number;
UpgradeLevelMult: number;
UpgradeRamMult: number;
UpgradeCoreMult: number;
// Constants for max upgrade levels for Hacknet Nodes
MaxLevel: number;
MaxRam: number;
MaxCores: number;
// Constants for max upgrade levels for Hacknet Nodes
MaxLevel: number;
MaxRam: number;
MaxCores: number;
} = {
MoneyGainPerLevel: 1.6,
MoneyGainPerLevel: 1.6,
BaseCost: 1000,
LevelBaseCost: 1,
RamBaseCost: 30e3,
CoreBaseCost: 500e3,
PurchaseNextMult: 1.85,
UpgradeLevelMult: 1.04,
UpgradeRamMult: 1.28,
UpgradeCoreMult: 1.48,
BaseCost: 1000,
LevelBaseCost: 1,
RamBaseCost: 30e3,
CoreBaseCost: 500e3,
MaxLevel: 200,
MaxRam: 64,
MaxCores: 16,
}
PurchaseNextMult: 1.85,
UpgradeLevelMult: 1.04,
UpgradeRamMult: 1.28,
UpgradeCoreMult: 1.48,
MaxLevel: 200,
MaxRam: 64,
MaxCores: 16,
};
export const HacknetServerConstants: {
// Constants for Hacknet Server stats/production
HashesPerLevel: number;
// Constants for Hacknet Server stats/production
HashesPerLevel: number;
// Constants for Hacknet Server purchase/upgrade costs
BaseCost: number;
RamBaseCost: number;
CoreBaseCost: number;
CacheBaseCost: number;
// Constants for Hacknet Server purchase/upgrade costs
BaseCost: number;
RamBaseCost: number;
CoreBaseCost: number;
CacheBaseCost: number;
PurchaseMult: number; // Multiplier for puchasing an additional Hacknet Server
UpgradeLevelMult: number; // Multiplier for cost when upgrading level
UpgradeRamMult: number; // Multiplier for cost when upgrading RAM
UpgradeCoreMult: number; // Multiplier for cost when buying another core
UpgradeCacheMult: number; // Multiplier for cost when upgrading cache
MaxServers: number; // Max number of Hacknet Servers you can own
PurchaseMult: number; // Multiplier for puchasing an additional Hacknet Server
UpgradeLevelMult: number; // Multiplier for cost when upgrading level
UpgradeRamMult: number; // Multiplier for cost when upgrading RAM
UpgradeCoreMult: number; // Multiplier for cost when buying another core
UpgradeCacheMult: number; // Multiplier for cost when upgrading cache
MaxServers: number; // Max number of Hacknet Servers you can own
// Constants for max upgrade levels for Hacknet Server
MaxLevel: number;
MaxRam: number;
MaxCores: number;
MaxCache: number;
// Constants for max upgrade levels for Hacknet Server
MaxLevel: number;
MaxRam: number;
MaxCores: number;
MaxCache: number;
} = {
HashesPerLevel: 0.001,
HashesPerLevel: 0.001,
BaseCost: 50e3,
RamBaseCost: 200e3,
CoreBaseCost: 1e6,
CacheBaseCost: 10e6,
PurchaseMult: 3.20,
UpgradeLevelMult: 1.10,
UpgradeRamMult: 1.40,
UpgradeCoreMult: 1.55,
UpgradeCacheMult: 1.85,
MaxServers: 20,
BaseCost: 50e3,
RamBaseCost: 200e3,
CoreBaseCost: 1e6,
CacheBaseCost: 10e6,
MaxLevel: 300,
MaxRam: 8192,
MaxCores: 128,
MaxCache: 15,
}
PurchaseMult: 3.2,
UpgradeLevelMult: 1.1,
UpgradeRamMult: 1.4,
UpgradeCoreMult: 1.55,
UpgradeCacheMult: 1.85,
MaxServers: 20,
MaxLevel: 300,
MaxRam: 8192,
MaxCores: 128,
MaxCache: 15,
};
+106 -78
View File
@@ -5,81 +5,109 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { Money } from "../../ui/React/Money";
export const HashUpgradesMetadata: IConstructorParams[] = [
{
cost: 4,
costPerLevel: 4,
desc: "Sell hashes for $1m",
name: "Sell for Money",
effectText: (level: number): JSX.Element | null => (<>Sold for <Money money={1e6*level} /></>),
value: 1e6,
},
{
costPerLevel: 100,
desc: "Sell hashes for $1b in Corporation funds",
name: "Sell for Corporation Funds",
effectText: (level: number): JSX.Element | null => (<>Sold for <Money money={1e9*level} /> Corporation funds.</>),
value: 1e9,
},
{
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. This effect persists " +
"until you install Augmentations (since servers are reset at that time).",
hasTargetServer: true,
name: "Reduce Minimum Security",
value: 0.98,
},
{
costPerLevel: 50,
desc: "Use hashes to increase the maximum amount of money on a single server by 2%. " +
"This effect persists until you install Augmentations (since servers " +
"are reset at that time).",
hasTargetServer: true,
name: "Increase Maximum Money",
value: 1.02,
},
{
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",
//effectText: (level: number) => JSX.Element | null = <>Improves studying by ${level*20}%</>,
value: 20, // Improves studying by value%
},
{
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",
effectText: (level: number): JSX.Element | null => (<>Improves training by ${level*20}%</>),
value: 20, // Improves training by value%
},
{
costPerLevel: 200,
desc: "Exchange hashes for 1k Scientific Research in all of your Corporation's Industries",
name: "Exchange for Corporation Research",
effectText: (level: number): JSX.Element | null => (<>Acquired a total of {level}k Scientific Research in your industries.</>),
value: 1000,
},
{
costPerLevel: 250,
desc: "Exchange hashes for 100 Bladeburner Rank",
name: "Exchange for Bladeburner Rank",
effectText: (level: number): JSX.Element | null => (<>Acquired a total of {numeralWrapper.format(100*level, '0a')} Bladeburner rank</>),
value: 100,
},
{
costPerLevel: 250,
desc: "Exchanges hashes for 10 Bladeburner Skill Points",
name: "Exchange for Bladeburner SP",
effectText: (level: number): JSX.Element | null => (<>Acquired a total of {numeralWrapper.format(10*level, '0a')} Bladeburner Skill Points</>),
value: 10,
},
{
costPerLevel: 200,
desc: "Generate a random Coding Contract somewhere on the network",
name: "Generate Coding Contract",
effectText: (level: number): JSX.Element | null => (<>Generated {level} contracts.</>),
value: 1,
},
]
{
cost: 4,
costPerLevel: 4,
desc: "Sell hashes for $1m",
name: "Sell for Money",
effectText: (level: number): JSX.Element | null => (
<>
Sold for <Money money={1e6 * level} />
</>
),
value: 1e6,
},
{
costPerLevel: 100,
desc: "Sell hashes for $1b in Corporation funds",
name: "Sell for Corporation Funds",
effectText: (level: number): JSX.Element | null => (
<>
Sold for <Money money={1e9 * level} /> Corporation funds.
</>
),
value: 1e9,
},
{
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. This effect persists " +
"until you install Augmentations (since servers are reset at that time).",
hasTargetServer: true,
name: "Reduce Minimum Security",
value: 0.98,
},
{
costPerLevel: 50,
desc:
"Use hashes to increase the maximum amount of money on a single server by 2%. " +
"This effect persists until you install Augmentations (since servers " +
"are reset at that time).",
hasTargetServer: true,
name: "Increase Maximum Money",
value: 1.02,
},
{
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",
//effectText: (level: number) => JSX.Element | null = <>Improves studying by ${level*20}%</>,
value: 20, // Improves studying by value%
},
{
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",
effectText: (level: number): JSX.Element | null => (
<>Improves training by ${level * 20}%</>
),
value: 20, // Improves training by value%
},
{
costPerLevel: 200,
desc: "Exchange hashes for 1k Scientific Research in all of your Corporation's Industries",
name: "Exchange for Corporation Research",
effectText: (level: number): JSX.Element | null => (
<>Acquired a total of {level}k Scientific Research in your industries.</>
),
value: 1000,
},
{
costPerLevel: 250,
desc: "Exchange hashes for 100 Bladeburner Rank",
name: "Exchange for Bladeburner Rank",
effectText: (level: number): JSX.Element | null => (
<>
Acquired a total of {numeralWrapper.format(100 * level, "0a")}{" "}
Bladeburner rank
</>
),
value: 100,
},
{
costPerLevel: 250,
desc: "Exchanges hashes for 10 Bladeburner Skill Points",
name: "Exchange for Bladeburner SP",
effectText: (level: number): JSX.Element | null => (
<>
Acquired a total of {numeralWrapper.format(10 * level, "0a")}{" "}
Bladeburner Skill Points
</>
),
value: 10,
},
{
costPerLevel: 200,
desc: "Generate a random Coding Contract somewhere on the network",
name: "Generate Coding Contract",
effectText: (level: number): JSX.Element | null => (
<>Generated {level} contracts.</>
),
value: 1,
},
];
+90 -70
View File
@@ -1,96 +1,116 @@
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { HacknetNodeConstants } from "../data/Constants";
export function calculateMoneyGainRate(level: number, ram: number, cores: number, mult: number): number {
const gainPerLevel = HacknetNodeConstants.MoneyGainPerLevel;
export function calculateMoneyGainRate(
level: number,
ram: number,
cores: number,
mult: number,
): number {
const gainPerLevel = HacknetNodeConstants.MoneyGainPerLevel;
const levelMult = (level * gainPerLevel);
const ramMult = Math.pow(1.035, ram - 1);
const coresMult = ((cores + 5) / 6);
return levelMult *
ramMult *
coresMult *
mult *
BitNodeMultipliers.HacknetNodeMoney;
const levelMult = level * gainPerLevel;
const ramMult = Math.pow(1.035, ram - 1);
const coresMult = (cores + 5) / 6;
return (
levelMult * ramMult * coresMult * mult * BitNodeMultipliers.HacknetNodeMoney
);
}
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels=1, costMult=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateLevelUpgradeCost(
startingLevel: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingLevel >= HacknetNodeConstants.MaxLevel) {
return Infinity;
}
if (startingLevel >= HacknetNodeConstants.MaxLevel) {
return Infinity;
}
const mult = HacknetNodeConstants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += (HacknetNodeConstants.LevelBaseCost * Math.pow(mult, currLevel));
++currLevel;
}
const mult = HacknetNodeConstants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier +=
HacknetNodeConstants.LevelBaseCost * Math.pow(mult, currLevel);
++currLevel;
}
return HacknetNodeConstants.BaseCost / 2 * totalMultiplier * costMult;
return (HacknetNodeConstants.BaseCost / 2) * totalMultiplier * costMult;
}
export function calculateRamUpgradeCost(startingRam: number, extraLevels=1, costMult=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateRamUpgradeCost(
startingRam: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingRam >= HacknetNodeConstants.MaxRam) {
return Infinity;
}
if (startingRam >= HacknetNodeConstants.MaxRam) {
return Infinity;
}
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * HacknetNodeConstants.RamBaseCost;
const mult = Math.pow(HacknetNodeConstants.UpgradeRamMult, numUpgrades);
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * HacknetNodeConstants.RamBaseCost;
const mult = Math.pow(HacknetNodeConstants.UpgradeRamMult, numUpgrades);
totalCost += (baseCost * mult);
totalCost += baseCost * mult;
currentRam *= 2;
++numUpgrades;
}
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
totalCost *= costMult;
return totalCost;
return totalCost;
}
export function calculateCoreUpgradeCost(startingCore: number, extraLevels=1, costMult=1): number {
const sanitizedCores = Math.round(extraLevels);
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
return 0;
}
export function calculateCoreUpgradeCost(
startingCore: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedCores = Math.round(extraLevels);
if (isNaN(sanitizedCores) || sanitizedCores < 1) {
return 0;
}
if (startingCore >= HacknetNodeConstants.MaxCores) {
return Infinity;
}
if (startingCore >= HacknetNodeConstants.MaxCores) {
return Infinity;
}
const coreBaseCost = HacknetNodeConstants.CoreBaseCost;
const mult = HacknetNodeConstants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCore;
for (let i = 0; i < sanitizedCores; ++i) {
totalCost += (coreBaseCost * Math.pow(mult, currentCores-1));
++currentCores;
}
const coreBaseCost = HacknetNodeConstants.CoreBaseCost;
const mult = HacknetNodeConstants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCore;
for (let i = 0; i < sanitizedCores; ++i) {
totalCost += coreBaseCost * Math.pow(mult, currentCores - 1);
++currentCores;
}
totalCost *= costMult;
totalCost *= costMult;
return totalCost;
return totalCost;
}
export function calculateNodeCost(n: number, mult=1): number {
if(n <= 0) {
return 0;
}
return HacknetNodeConstants.BaseCost * Math.pow(HacknetNodeConstants.PurchaseNextMult, n-1) * mult;
}
export function calculateNodeCost(n: number, mult = 1): number {
if (n <= 0) {
return 0;
}
return (
HacknetNodeConstants.BaseCost *
Math.pow(HacknetNodeConstants.PurchaseNextMult, n - 1) *
mult
);
}
+115 -86
View File
@@ -1,115 +1,144 @@
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { HacknetServerConstants } from "../data/Constants";
export function calculateHashGainRate(level: number, ramUsed: number, maxRam: number, cores: number, mult: number): number {
const baseGain = HacknetServerConstants.HashesPerLevel * level;
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
const coreMultiplier = 1 + (cores - 1) / 5;
const ramRatio = (1 - ramUsed / maxRam);
export function calculateHashGainRate(
level: number,
ramUsed: number,
maxRam: number,
cores: number,
mult: number,
): number {
const baseGain = HacknetServerConstants.HashesPerLevel * level;
const ramMultiplier = Math.pow(1.07, Math.log2(maxRam));
const coreMultiplier = 1 + (cores - 1) / 5;
const ramRatio = 1 - ramUsed / maxRam;
return baseGain *
ramMultiplier *
coreMultiplier *
ramRatio *
mult *
BitNodeMultipliers.HacknetNodeMoney;
return (
baseGain *
ramMultiplier *
coreMultiplier *
ramRatio *
mult *
BitNodeMultipliers.HacknetNodeMoney
);
}
export function calculateLevelUpgradeCost(startingLevel: number, extraLevels=1, costMult=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateLevelUpgradeCost(
startingLevel: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingLevel >= HacknetServerConstants.MaxLevel) {
return Infinity;
}
if (startingLevel >= HacknetServerConstants.MaxLevel) {
return Infinity;
}
const mult = HacknetServerConstants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += Math.pow(mult, currLevel);
++currLevel;
}
const mult = HacknetServerConstants.UpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = startingLevel;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += Math.pow(mult, currLevel);
++currLevel;
}
return 10 * HacknetServerConstants.BaseCost * totalMultiplier * costMult;
return 10 * HacknetServerConstants.BaseCost * totalMultiplier * costMult;
}
export function calculateRamUpgradeCost(startingRam: number, extraLevels=1, costMult=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateRamUpgradeCost(
startingRam: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingRam >= HacknetServerConstants.MaxRam) {
return Infinity;
}
if (startingRam >= HacknetServerConstants.MaxRam) {
return Infinity;
}
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * HacknetServerConstants.RamBaseCost;
const mult = Math.pow(HacknetServerConstants.UpgradeRamMult, numUpgrades);
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(startingRam));
let currentRam = startingRam;
for (let i = 0; i < sanitizedLevels; ++i) {
const baseCost = currentRam * HacknetServerConstants.RamBaseCost;
const mult = Math.pow(HacknetServerConstants.UpgradeRamMult, numUpgrades);
totalCost += (baseCost * mult);
totalCost += baseCost * mult;
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
return totalCost;
return totalCost;
}
export function calculateCoreUpgradeCost(startingCores: number, extraLevels=1, costMult=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateCoreUpgradeCost(
startingCores: number,
extraLevels = 1,
costMult = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingCores >= HacknetServerConstants.MaxCores) {
return Infinity;
}
if (startingCores >= HacknetServerConstants.MaxCores) {
return Infinity;
}
const mult = HacknetServerConstants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCores;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCores-1);
++currentCores;
}
totalCost *= HacknetServerConstants.CoreBaseCost;
totalCost *= costMult;
const mult = HacknetServerConstants.UpgradeCoreMult;
let totalCost = 0;
let currentCores = startingCores;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCores - 1);
++currentCores;
}
totalCost *= HacknetServerConstants.CoreBaseCost;
totalCost *= costMult;
return totalCost;
return totalCost;
}
export function calculateCacheUpgradeCost(startingCache: number, extraLevels=1): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
export function calculateCacheUpgradeCost(
startingCache: number,
extraLevels = 1,
): number {
const sanitizedLevels = Math.round(extraLevels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (startingCache >= HacknetServerConstants.MaxCache) {
return Infinity;
}
if (startingCache >= HacknetServerConstants.MaxCache) {
return Infinity;
}
const mult = HacknetServerConstants.UpgradeCacheMult;
let totalCost = 0;
let currentCache = startingCache;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCache - 1);
++currentCache;
}
totalCost *= HacknetServerConstants.CacheBaseCost;
const mult = HacknetServerConstants.UpgradeCacheMult;
let totalCost = 0;
let currentCache = startingCache;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += Math.pow(mult, currentCache - 1);
++currentCache;
}
totalCost *= HacknetServerConstants.CacheBaseCost;
return totalCost;
return totalCost;
}
export function calculateServerCost(n: number, mult=1): number {
if (n-1 >= HacknetServerConstants.MaxServers) { return Infinity; }
export function calculateServerCost(n: number, mult = 1): number {
if (n - 1 >= HacknetServerConstants.MaxServers) {
return Infinity;
}
return HacknetServerConstants.BaseCost * Math.pow(HacknetServerConstants.PurchaseMult, n-1) * mult;
}
return (
HacknetServerConstants.BaseCost *
Math.pow(HacknetServerConstants.PurchaseMult, n - 1) *
mult
);
}
+43 -39
View File
@@ -8,47 +8,51 @@ import React from "react";
import { hasHacknetServers } from "../HacknetHelpers";
export class GeneralInfo extends React.Component {
getSecondParagraph() {
if (hasHacknetServers()) {
return `Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` +
`Hacknet Servers will perform computations and operations on the network, earning ` +
`you hashes. Hashes can be spent on a variety of different upgrades.`;
} else {
return `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.`;
}
getSecondParagraph() {
if (hasHacknetServers()) {
return (
`Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` +
`Hacknet Servers will perform computations and operations on the network, earning ` +
`you hashes. Hashes can be spent on a variety of different upgrades.`
);
} else {
return (
`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.`
);
}
}
getThirdParagraph() {
if (hasHacknetServers()) {
return `Hacknet Servers can also be used as servers to run scripts. However, running scripts ` +
`on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` +
`rate will be reduced by the percentage of RAM that is being used by that Server to run ` +
`scripts.`
} else {
return `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.`;
}
getThirdParagraph() {
if (hasHacknetServers()) {
return (
`Hacknet Servers can also be used as servers to run scripts. However, running scripts ` +
`on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` +
`rate will be reduced by the percentage of RAM that is being used by that Server to run ` +
`scripts.`
);
} else {
return (
`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.`
);
}
}
render() {
return (
<div>
<p className={"hacknet-general-info"}>
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.
</p>
<p className={"hacknet-general-info"}>
{this.getSecondParagraph()}
</p>
<p className={"hacknet-general-info"}>
{this.getThirdParagraph()}
</p>
</div>
)
}
render() {
return (
<div>
<p className={"hacknet-general-info"}>
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.
</p>
<p className={"hacknet-general-info"}>{this.getSecondParagraph()}</p>
<p className={"hacknet-general-info"}>{this.getThirdParagraph()}</p>
</div>
);
}
}
+181 -139
View File
@@ -6,12 +6,12 @@ import React from "react";
import { HacknetNodeConstants } from "../data/Constants";
import {
getMaxNumberLevelUpgrades,
getMaxNumberRamUpgrades,
getMaxNumberCoreUpgrades,
purchaseLevelUpgrade,
purchaseRamUpgrade,
purchaseCoreUpgrade,
getMaxNumberLevelUpgrades,
getMaxNumberRamUpgrades,
getMaxNumberCoreUpgrades,
purchaseLevelUpgrade,
purchaseRamUpgrade,
purchaseCoreUpgrade,
} from "../HacknetHelpers";
import { Player } from "../../Player";
@@ -20,140 +20,182 @@ import { Money } from "../../ui/React/Money";
import { MoneyRate } from "../../ui/React/MoneyRate";
export class HacknetNode extends React.Component {
render() {
const node = this.props.node;
const purchaseMult = this.props.purchaseMultiplier;
const recalculate = this.props.recalculate;
render() {
const node = this.props.node;
const purchaseMult = this.props.purchaseMultiplier;
const recalculate = this.props.recalculate;
// Upgrade Level Button
let upgradeLevelContent, upgradeLevelClass;
if (node.level >= HacknetNodeConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>;
upgradeLevelClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel);
} else {
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult);
}
// Upgrade Level Button
let upgradeLevelContent, upgradeLevelClass;
if (node.level >= HacknetNodeConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>;
upgradeLevelClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(
node,
HacknetNodeConstants.MaxLevel,
);
} else {
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
upgradeLevelContent = <>Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={Player} /></>;
if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelClass = "std-button-disabled";
} else {
upgradeLevelClass = "std-button";
}
}
const upgradeLevelOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel);
}
purchaseLevelUpgrade(node, numUpgrades);
recalculate();
return false;
}
let upgradeRamContent, upgradeRamClass;
if (node.ram >= HacknetNodeConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>;
upgradeRamClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
} else {
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
upgradeRamContent = <>Upgrade x{multiplier} - <Money money={upgradeRamCost} player={Player} /></>;
if (Player.money.lt(upgradeRamCost)) {
upgradeRamClass = "std-button-disabled";
} else {
upgradeRamClass = "std-button";
}
}
const upgradeRamOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
}
purchaseRamUpgrade(node, numUpgrades);
recalculate();
return false;
}
let upgradeCoresContent, upgradeCoresClass;
if (node.cores >= HacknetNodeConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>;
upgradeCoresClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores);
} else {
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
upgradeCoresContent = <>Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={Player} /></>;
if (Player.money.lt(upgradeCoreCost)) {
upgradeCoresClass = "std-button-disabled";
} else {
upgradeCoresClass = "std-button";
}
}
const upgradeCoresOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores);
}
purchaseCoreUpgrade(node, numUpgrades);
recalculate();
return false;
}
return (
<li className={"hacknet-node"}>
<div className={"hacknet-node-container"}>
<div className={"row"}>
<h1 style={{"fontSize":"1em"}}>{node.name}</h1>
</div>
<div className={"row"}>
<p>Production:</p>
<span className={"text money-gold"}>
<Money money={node.totalMoneyGenerated} player={Player} /> ({MoneyRate(node.moneyGainRatePerSecond)})
</span>
</div>
<div className={"row"}>
<p>Level:</p>
<span className={"text upgradable-info"}>{node.level}</span>
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
{upgradeLevelContent}
</button>
</div>
<div className={"row"}>
<p>RAM:</p>
<span className={"text upgradable-info"}>{node.ram}GB</span>
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
{upgradeRamContent}
</button>
</div>
<div className={"row"}>
<p>Cores:</p>
<span className={"text upgradable-info"}>{node.cores}</span>
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
{upgradeCoresContent}
</button>
</div>
</div>
</li>
)
const upgradeLevelCost = node.calculateLevelUpgradeCost(
multiplier,
Player.hacknet_node_level_cost_mult,
);
upgradeLevelContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeLevelCost} player={Player} />
</>
);
if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelClass = "std-button-disabled";
} else {
upgradeLevelClass = "std-button";
}
}
const upgradeLevelOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberLevelUpgrades(
node,
HacknetNodeConstants.MaxLevel,
);
}
purchaseLevelUpgrade(node, numUpgrades);
recalculate();
return false;
};
let upgradeRamContent, upgradeRamClass;
if (node.ram >= HacknetNodeConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>;
upgradeRamClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
} else {
const levelsToMax = Math.round(
Math.log2(HacknetNodeConstants.MaxRam / node.ram),
);
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeRamCost = node.calculateRamUpgradeCost(
multiplier,
Player.hacknet_node_ram_cost_mult,
);
upgradeRamContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeRamCost} player={Player} />
</>
);
if (Player.money.lt(upgradeRamCost)) {
upgradeRamClass = "std-button-disabled";
} else {
upgradeRamClass = "std-button";
}
}
const upgradeRamOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(
node,
HacknetNodeConstants.MaxRam,
);
}
purchaseRamUpgrade(node, numUpgrades);
recalculate();
return false;
};
let upgradeCoresContent, upgradeCoresClass;
if (node.cores >= HacknetNodeConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>;
upgradeCoresClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(
node,
HacknetNodeConstants.MaxCores,
);
} else {
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCoreCost = node.calculateCoreUpgradeCost(
multiplier,
Player.hacknet_node_core_cost_mult,
);
upgradeCoresContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeCoreCost} player={Player} />
</>
);
if (Player.money.lt(upgradeCoreCost)) {
upgradeCoresClass = "std-button-disabled";
} else {
upgradeCoresClass = "std-button";
}
}
const upgradeCoresOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCoreUpgrades(
node,
HacknetNodeConstants.MaxCores,
);
}
purchaseCoreUpgrade(node, numUpgrades);
recalculate();
return false;
};
return (
<li className={"hacknet-node"}>
<div className={"hacknet-node-container"}>
<div className={"row"}>
<h1 style={{ fontSize: "1em" }}>{node.name}</h1>
</div>
<div className={"row"}>
<p>Production:</p>
<span className={"text money-gold"}>
<Money money={node.totalMoneyGenerated} player={Player} /> (
{MoneyRate(node.moneyGainRatePerSecond)})
</span>
</div>
<div className={"row"}>
<p>Level:</p>
<span className={"text upgradable-info"}>{node.level}</span>
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
{upgradeLevelContent}
</button>
</div>
<div className={"row"}>
<p>RAM:</p>
<span className={"text upgradable-info"}>{node.ram}GB</span>
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
{upgradeRamContent}
</button>
</div>
<div className={"row"}>
<p>Cores:</p>
<span className={"text upgradable-info"}>{node.cores}</span>
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
{upgradeCoresContent}
</button>
</div>
</div>
</li>
);
}
}
+243 -184
View File
@@ -6,15 +6,15 @@ import React from "react";
import { HacknetServerConstants } from "../data/Constants";
import {
getMaxNumberLevelUpgrades,
getMaxNumberRamUpgrades,
getMaxNumberCoreUpgrades,
getMaxNumberCacheUpgrades,
purchaseLevelUpgrade,
purchaseRamUpgrade,
purchaseCoreUpgrade,
purchaseCacheUpgrade,
updateHashManagerCapacity,
getMaxNumberLevelUpgrades,
getMaxNumberRamUpgrades,
getMaxNumberCoreUpgrades,
getMaxNumberCacheUpgrades,
purchaseLevelUpgrade,
purchaseRamUpgrade,
purchaseCoreUpgrade,
purchaseCacheUpgrade,
updateHashManagerCapacity,
} from "../HacknetHelpers";
import { Player } from "../../Player";
@@ -24,182 +24,241 @@ import { Hashes } from "../../ui/React/Hashes";
import { HashRate } from "../../ui/React/HashRate";
export class HacknetServer extends React.Component {
render() {
const node = this.props.node;
const purchaseMult = this.props.purchaseMultiplier;
const recalculate = this.props.recalculate;
render() {
const node = this.props.node;
const purchaseMult = this.props.purchaseMultiplier;
const recalculate = this.props.recalculate;
// Upgrade Level Button
let upgradeLevelContent, upgradeLevelClass;
if (node.level >= HacknetServerConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>;
upgradeLevelClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
} else {
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult);
}
// Upgrade Level Button
let upgradeLevelContent, upgradeLevelClass;
if (node.level >= HacknetServerConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>;
upgradeLevelClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(
node,
HacknetServerConstants.MaxLevel,
);
} else {
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.hacknet_node_level_cost_mult);
upgradeLevelContent = <>Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={Player} /></>;
if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelClass = "std-button-disabled";
} else {
upgradeLevelClass = "std-button";
}
}
const upgradeLevelOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
}
purchaseLevelUpgrade(node, numUpgrades);
recalculate();
return false;
}
// Upgrade RAM Button
let upgradeRamContent, upgradeRamClass;
if (node.maxRam >= HacknetServerConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>;
upgradeRamClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
} else {
const levelsToMax = Math.round(Math.log2(HacknetServerConstants.MaxRam / node.maxRam));
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.hacknet_node_ram_cost_mult);
upgradeRamContent = <>Upgrade x{multiplier} - <Money money={upgradeRamCost} player={Player} /></>;
if (Player.money.lt(upgradeRamCost)) {
upgradeRamClass = "std-button-disabled";
} else {
upgradeRamClass = "std-button";
}
}
const upgradeRamOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
}
purchaseRamUpgrade(node, numUpgrades);
recalculate();
return false;
}
// Upgrade Cores Button
let upgradeCoresContent, upgradeCoresClass;
if (node.cores >= HacknetServerConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>;
upgradeCoresClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
} else {
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.hacknet_node_core_cost_mult);
upgradeCoresContent = <>Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={Player} /></>;
if (Player.money.lt(upgradeCoreCost)) {
upgradeCoresClass = "std-button-disabled";
} else {
upgradeCoresClass = "std-button";
}
}
const upgradeCoresOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
}
purchaseCoreUpgrade(node, numUpgrades);
recalculate();
return false;
}
// Upgrade Cache button
let upgradeCacheContent, upgradeCacheClass;
if (node.cache >= HacknetServerConstants.MaxCache) {
upgradeCacheContent = <>MAX CACHE</>;
upgradeCacheClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
} else {
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
upgradeCacheContent = <>Upgrade x{multiplier} - <Money money={upgradeCacheCost} player={Player} /></>;
if (Player.money.lt(upgradeCacheCost)) {
upgradeCacheClass = "std-button-disabled";
} else {
upgradeCacheClass = "std-button";
}
}
const upgradeCacheOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
}
purchaseCacheUpgrade(node, numUpgrades);
recalculate();
updateHashManagerCapacity();
return false;
}
return (
<li className={"hacknet-node"}>
<div className={"hacknet-node-container"}>
<div className={"row"}>
<h1 style={{"fontSize":"1em"}}>{node.hostname}</h1>
</div>
<div className={"row"}>
<p>Production:</p>
<span className={"text money-gold"}>
{Hashes(node.totalHashesGenerated)} ({HashRate(node.hashRate)})
</span>
</div>
<div className={"row"}>
<p>Hash Capacity:</p>
<span className={"text"}>{Hashes(node.hashCapacity)}</span>
</div>
<div className={"row"}>
<p>Level:</p><span className={"text upgradable-info"}>{node.level}</span>
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
{upgradeLevelContent}
</button>
</div>
<div className={"row"}>
<p>RAM:</p><span className={"text upgradable-info"}>{node.maxRam}GB</span>
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
{upgradeRamContent}
</button>
</div>
<div className={"row"}>
<p>Cores:</p><span className={"text upgradable-info"}>{node.cores}</span>
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
{upgradeCoresContent}
</button>
</div>
<div className={"row"}>
<p>Cache Level:</p><span className={"text upgradable-info"}>{node.cache}</span>
<button className={upgradeCacheClass} onClick={upgradeCacheOnClick}>
{upgradeCacheContent}
</button>
</div>
</div>
</li>
)
const upgradeLevelCost = node.calculateLevelUpgradeCost(
multiplier,
Player.hacknet_node_level_cost_mult,
);
upgradeLevelContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeLevelCost} player={Player} />
</>
);
if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelClass = "std-button-disabled";
} else {
upgradeLevelClass = "std-button";
}
}
const upgradeLevelOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberLevelUpgrades(
node,
HacknetServerConstants.MaxLevel,
);
}
purchaseLevelUpgrade(node, numUpgrades);
recalculate();
return false;
};
// Upgrade RAM Button
let upgradeRamContent, upgradeRamClass;
if (node.maxRam >= HacknetServerConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>;
upgradeRamClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(
node,
HacknetServerConstants.MaxRam,
);
} else {
const levelsToMax = Math.round(
Math.log2(HacknetServerConstants.MaxRam / node.maxRam),
);
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeRamCost = node.calculateRamUpgradeCost(
multiplier,
Player.hacknet_node_ram_cost_mult,
);
upgradeRamContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeRamCost} player={Player} />
</>
);
if (Player.money.lt(upgradeRamCost)) {
upgradeRamClass = "std-button-disabled";
} else {
upgradeRamClass = "std-button";
}
}
const upgradeRamOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(
node,
HacknetServerConstants.MaxRam,
);
}
purchaseRamUpgrade(node, numUpgrades);
recalculate();
return false;
};
// Upgrade Cores Button
let upgradeCoresContent, upgradeCoresClass;
if (node.cores >= HacknetServerConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>;
upgradeCoresClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(
node,
HacknetServerConstants.MaxCores,
);
} else {
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCoreCost = node.calculateCoreUpgradeCost(
multiplier,
Player.hacknet_node_core_cost_mult,
);
upgradeCoresContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeCoreCost} player={Player} />
</>
);
if (Player.money.lt(upgradeCoreCost)) {
upgradeCoresClass = "std-button-disabled";
} else {
upgradeCoresClass = "std-button";
}
}
const upgradeCoresOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCoreUpgrades(
node,
HacknetServerConstants.MaxCores,
);
}
purchaseCoreUpgrade(node, numUpgrades);
recalculate();
return false;
};
// Upgrade Cache button
let upgradeCacheContent, upgradeCacheClass;
if (node.cache >= HacknetServerConstants.MaxCache) {
upgradeCacheContent = <>MAX CACHE</>;
upgradeCacheClass = "std-button-disabled";
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCacheUpgrades(
node,
HacknetServerConstants.MaxCache,
);
} else {
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
upgradeCacheContent = (
<>
Upgrade x{multiplier} -{" "}
<Money money={upgradeCacheCost} player={Player} />
</>
);
if (Player.money.lt(upgradeCacheCost)) {
upgradeCacheClass = "std-button-disabled";
} else {
upgradeCacheClass = "std-button";
}
}
const upgradeCacheOnClick = () => {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCacheUpgrades(
node,
HacknetServerConstants.MaxCache,
);
}
purchaseCacheUpgrade(node, numUpgrades);
recalculate();
updateHashManagerCapacity();
return false;
};
return (
<li className={"hacknet-node"}>
<div className={"hacknet-node-container"}>
<div className={"row"}>
<h1 style={{ fontSize: "1em" }}>{node.hostname}</h1>
</div>
<div className={"row"}>
<p>Production:</p>
<span className={"text money-gold"}>
{Hashes(node.totalHashesGenerated)} ({HashRate(node.hashRate)})
</span>
</div>
<div className={"row"}>
<p>Hash Capacity:</p>
<span className={"text"}>{Hashes(node.hashCapacity)}</span>
</div>
<div className={"row"}>
<p>Level:</p>
<span className={"text upgradable-info"}>{node.level}</span>
<button className={upgradeLevelClass} onClick={upgradeLevelOnClick}>
{upgradeLevelContent}
</button>
</div>
<div className={"row"}>
<p>RAM:</p>
<span className={"text upgradable-info"}>{node.maxRam}GB</span>
<button className={upgradeRamClass} onClick={upgradeRamOnClick}>
{upgradeRamContent}
</button>
</div>
<div className={"row"}>
<p>Cores:</p>
<span className={"text upgradable-info"}>{node.cores}</span>
<button className={upgradeCoresClass} onClick={upgradeCoresOnClick}>
{upgradeCoresContent}
</button>
</div>
<div className={"row"}>
<p>Cache Level:</p>
<span className={"text upgradable-info"}>{node.cache}</span>
<button className={upgradeCacheClass} onClick={upgradeCacheOnClick}>
{upgradeCacheContent}
</button>
</div>
</div>
</li>
);
}
}
+117 -103
View File
@@ -3,129 +3,143 @@
*/
import React from "react";
import { purchaseHashUpgrade } from "../HacknetHelpers";
import { HashManager } from "../HashManager";
import { HashUpgrades } from "../HashUpgrades";
import { purchaseHashUpgrade } from "../HacknetHelpers";
import { HashManager } from "../HashManager";
import { HashUpgrades } from "../HashUpgrades";
import { Player } from "../../Player";
import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { numeralWrapper } from "../../ui/numeralFormat";
import { ServerDropdown,
ServerType } from "../../ui/React/ServerDropdown"
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { dialogBoxCreate } from "../../../utils/DialogBox";
import { CopyableText } from "../../ui/React/CopyableText";
import { Hashes } from "../../ui/React/Hashes";
class HashUpgrade extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
selectedServer: "ecorp",
}
this.state = {
selectedServer: "ecorp",
};
this.changeTargetServer = this.changeTargetServer.bind(this);
this.purchase = this.purchase.bind(this, this.props.hashManager, this.props.upg);
this.changeTargetServer = this.changeTargetServer.bind(this);
this.purchase = this.purchase.bind(
this,
this.props.hashManager,
this.props.upg,
);
}
changeTargetServer(e) {
this.setState({
selectedServer: e.target.value,
});
}
purchase(hashManager, upg) {
const canPurchase =
hashManager.hashes >= hashManager.getUpgradeCost(upg.name);
if (canPurchase) {
const res = purchaseHashUpgrade(upg.name, this.state.selectedServer);
if (res) {
this.props.rerender();
} else {
dialogBoxCreate(
"Failed to purchase upgrade. This may be because you do not have enough hashes, " +
"or because you do not have access to the feature this upgrade affects.",
);
}
}
}
changeTargetServer(e) {
this.setState({
selectedServer: e.target.value,
});
}
render() {
const hashManager = this.props.hashManager;
const upg = this.props.upg;
const cost = hashManager.getUpgradeCost(upg.name);
const level = hashManager.upgrades[upg.name];
const effect = upg.effectText(level);
purchase(hashManager, upg) {
const canPurchase = hashManager.hashes >= hashManager.getUpgradeCost(upg.name);
if (canPurchase) {
const res = purchaseHashUpgrade(upg.name, this.state.selectedServer);
if (res) {
this.props.rerender();
} else {
dialogBoxCreate("Failed to purchase upgrade. This may be because you do not have enough hashes, " +
"or because you do not have access to the feature this upgrade affects.");
}
}
}
// Purchase button
const canPurchase = hashManager.hashes >= cost;
const btnClass = canPurchase ? "std-button" : "std-button-disabled";
render() {
const hashManager = this.props.hashManager;
const upg = this.props.upg;
const cost = hashManager.getUpgradeCost(upg.name);
const level = hashManager.upgrades[upg.name];
const effect = upg.effectText(level);
// We'll reuse a Bladeburner css class
return (
<div className={"bladeburner-action"}>
<CopyableText value={upg.name} />
<p>
Cost: {Hashes(cost)}, Bought: {level} times
</p>
// Purchase button
const canPurchase = hashManager.hashes >= cost;
const btnClass = canPurchase ? "std-button" : "std-button-disabled";
// We'll reuse a Bladeburner css class
return (
<div className={"bladeburner-action"}>
<CopyableText value={upg.name} />
<p>Cost: {Hashes(cost)}, Bought: {level} times</p>
<p>{upg.desc}</p>
<button className={btnClass} onClick={this.purchase}>
Purchase
</button>
{level > 0 && effect && <p>{effect}</p>}
{
upg.hasTargetServer &&
<ServerDropdown
serverType={ServerType.Foreign}
onChange={this.changeTargetServer}
style={{margin: "5px"}}
/>
}
</div>
)
}
<p>{upg.desc}</p>
<button className={btnClass} onClick={this.purchase}>
Purchase
</button>
{level > 0 && effect && <p>{effect}</p>}
{upg.hasTargetServer && (
<ServerDropdown
serverType={ServerType.Foreign}
onChange={this.changeTargetServer}
style={{ margin: "5px" }}
/>
)}
</div>
);
}
}
export class HashUpgradePopup extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
totalHashes: Player.hashManager.hashes,
}
this.state = {
totalHashes: Player.hashManager.hashes,
};
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1e3);
}
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
this.setState({
totalHashes: Player.hashManager.hashes,
});
}
render() {
const rerender = this.props.rerender;
const hashManager = Player.hashManager;
if (!(hashManager instanceof HashManager)) {
throw new Error(`Player does not have a HashManager)`);
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1e3);
}
const upgradeElems = Object.keys(HashUpgrades).map((upgName) => {
const upg = HashUpgrades[upgName];
return (
<HashUpgrade
upg={upg}
hashManager={hashManager}
key={upg.name}
rerender={rerender}
/>
);
});
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
this.setState({
totalHashes: Player.hashManager.hashes,
})
}
render() {
const rerender = this.props.rerender;
const hashManager = Player.hashManager;
if (!(hashManager instanceof HashManager)) {
throw new Error(`Player does not have a HashManager)`);
}
const upgradeElems = Object.keys(HashUpgrades).map((upgName) => {
const upg = HashUpgrades[upgName];
return <HashUpgrade upg={upg} hashManager={hashManager} key={upg.name} rerender={rerender} />
});
return (
<div>
<p>Spend your hashes on a variety of different upgrades</p>
<p>Hashes: {numeralWrapper.formatHashes(this.state.totalHashes)}</p>
{upgradeElems}
</div>
)
}
return (
<div>
<p>Spend your hashes on a variety of different upgrades</p>
<p>Hashes: {numeralWrapper.formatHashes(this.state.totalHashes)}</p>
{upgradeElems}
</div>
);
}
}
+25 -24
View File
@@ -8,34 +8,35 @@ import React from "react";
import { PurchaseMultipliers } from "./Root";
function MultiplierButton(props) {
return (
<button className={props.className} onClick={props.onClick}>{props.text}</button>
)
return (
<button className={props.className} onClick={props.onClick}>
{props.text}
</button>
);
}
export function MultiplierButtons(props) {
if (props.purchaseMultiplier == null) {
throw new Error(`MultiplierButtons constructed without required props`);
}
if (props.purchaseMultiplier == null) {
throw new Error(`MultiplierButtons constructed without required props`);
}
const mults = ["x1", "x5", "x10", "MAX"];
const onClicks = props.onClicks;
const buttons = [];
for (let i = 0; i < mults.length; ++i) {
const mult = mults[i];
const btnProps = {
className: props.purchaseMultiplier === PurchaseMultipliers[mult] ? "std-button-disabled" : "std-button",
key: mult,
onClick: onClicks[i],
text: mult,
}
const mults = ["x1", "x5", "x10", "MAX"];
const onClicks = props.onClicks;
const buttons = [];
for (let i = 0; i < mults.length; ++i) {
const mult = mults[i];
const btnProps = {
className:
props.purchaseMultiplier === PurchaseMultipliers[mult]
? "std-button-disabled"
: "std-button",
key: mult,
onClick: onClicks[i],
text: mult,
};
buttons.push(<MultiplierButton {...btnProps} />)
}
buttons.push(<MultiplierButton {...btnProps} />);
}
return (
<span id={"hacknet-nodes-multipliers"}>
{buttons}
</span>
)
return <span id={"hacknet-nodes-multipliers"}>{buttons}</span>;
}
+25 -18
View File
@@ -14,26 +14,33 @@ import { HashRate } from "../../ui/React/HashRate";
import { Hashes } from "../../ui/React/Hashes";
export function PlayerInfo(props) {
const hasServers = hasHacknetServers();
const hasServers = hasHacknetServers();
let prod;
if (hasServers) {
prod = HashRate(props.totalProduction);
} else {
prod = MoneyRate(props.totalProduction);
}
let prod;
if (hasServers) {
prod = HashRate(props.totalProduction);
} else {
prod = MoneyRate(props.totalProduction);
}
return (
<p id={"hacknet-nodes-money"}>
<span>Money: </span>
<Money money={Player.money.toNumber()} /><br />
return (
<p id={"hacknet-nodes-money"}>
<span>Money: </span>
<Money money={Player.money.toNumber()} />
<br />
{
hasServers && <><span>Hashes: {Hashes(Player.hashManager.hashes)} / {Hashes(Player.hashManager.capacity)}</span><br /></>
}
{hasServers && (
<>
<span>
Hashes: {Hashes(Player.hashManager.hashes)} /{" "}
{Hashes(Player.hashManager.capacity)}
</span>
<br />
</>
)}
<span>Total Hacknet {hasServers ? 'Server' : 'Node'} Production: </span>
{prod}
</p>
)
<span>Total Hacknet {hasServers ? "Server" : "Node"} Production: </span>
{prod}
</p>
);
}
+33 -26
View File
@@ -3,38 +3,45 @@
*/
import React from "react";
import { hasHacknetServers,
hasMaxNumberHacknetServers } from "../HacknetHelpers";
import {
hasHacknetServers,
hasMaxNumberHacknetServers,
} from "../HacknetHelpers";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
export function PurchaseButton(props) {
if (props.multiplier == null || props.onClick == null) {
throw new Error(`PurchaseButton constructed without required props`);
}
if (props.multiplier == null || props.onClick == null) {
throw new Error(`PurchaseButton constructed without required props`);
}
const cost = props.cost;
let className = Player.canAfford(cost) ? "std-button" : "std-button-disabled";
let text;
let style = null;
if (hasHacknetServers()) {
if (hasMaxNumberHacknetServers()) {
className = "std-button-disabled";
text = <>Hacknet Server limit reached</>;
style = {color: "red"};
} else {
text = <>Purchase Hacknet Server - <Money money={cost} player={Player} /></>;
}
const cost = props.cost;
let className = Player.canAfford(cost) ? "std-button" : "std-button-disabled";
let text;
let style = null;
if (hasHacknetServers()) {
if (hasMaxNumberHacknetServers()) {
className = "std-button-disabled";
text = <>Hacknet Server limit reached</>;
style = { color: "red" };
} else {
text = <>Purchase Hacknet Node - <Money money={cost} player={Player} /></>;
text = (
<>
Purchase Hacknet Server - <Money money={cost} player={Player} />
</>
);
}
} else {
text = (
<>
Purchase Hacknet Node - <Money money={cost} player={Player} />
</>
);
}
return (
<button className={className}
onClick={props.onClick}
style={style}>
{text}
</button>
)
return (
<button className={className} onClick={props.onClick} style={style}>
{text}
</button>
);
}
+143 -123
View File
@@ -11,10 +11,12 @@ import { MultiplierButtons } from "./MultiplierButtons";
import { PlayerInfo } from "./PlayerInfo";
import { PurchaseButton } from "./PurchaseButton";
import { getCostOfNextHacknetNode,
getCostOfNextHacknetServer,
hasHacknetServers,
purchaseHacknet } from "../HacknetHelpers";
import {
getCostOfNextHacknetNode,
getCostOfNextHacknetServer,
hasHacknetServers,
purchaseHacknet,
} from "../HacknetHelpers";
import { Player } from "../../Player";
import { AllServers } from "../../Server/AllServers";
@@ -22,133 +24,151 @@ import { AllServers } from "../../Server/AllServers";
import { createPopup } from "../../ui/React/createPopup";
export const PurchaseMultipliers = Object.freeze({
"x1": 1,
"x5": 5,
"x10": 10,
"MAX": "MAX",
x1: 1,
x5: 5,
x10: 10,
MAX: "MAX",
});
export class HacknetRoot extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
purchaseMultiplier: PurchaseMultipliers.x1,
totalProduction: 0, // Total production ($ / s) of Hacknet Nodes
}
this.state = {
purchaseMultiplier: PurchaseMultipliers.x1,
totalProduction: 0, // Total production ($ / s) of Hacknet Nodes
};
this.createHashUpgradesPopup = this.createHashUpgradesPopup.bind(this);
this.handlePurchaseButtonClick = this.handlePurchaseButtonClick.bind(this);
this.recalculateTotalProduction = this.recalculateTotalProduction.bind(this);
this.createHashUpgradesPopup = this.createHashUpgradesPopup.bind(this);
this.handlePurchaseButtonClick = this.handlePurchaseButtonClick.bind(this);
this.recalculateTotalProduction =
this.recalculateTotalProduction.bind(this);
}
componentDidMount() {
this.recalculateTotalProduction();
}
createHashUpgradesPopup() {
const id = "hacknet-server-hash-upgrades-popup";
createPopup(id, HashUpgradePopup, {
popupId: id,
rerender: this.createHashUpgradesPopup,
});
}
handlePurchaseButtonClick() {
if (purchaseHacknet() >= 0) {
this.recalculateTotalProduction();
}
}
componentDidMount() {
this.recalculateTotalProduction();
}
createHashUpgradesPopup() {
const id = "hacknet-server-hash-upgrades-popup";
createPopup(id, HashUpgradePopup, { popupId: id, rerender: this.createHashUpgradesPopup });
}
handlePurchaseButtonClick() {
if (purchaseHacknet() >= 0) {
this.recalculateTotalProduction();
}
}
recalculateTotalProduction() {
let total = 0;
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
if (hasHacknetServers()) {
const hserver = AllServers[Player.hacknetNodes[i]];
if (hserver) {
total += hserver.hashRate;
} else {
console.warn(`Could not find Hacknet Server object in AllServers map (i=${i})`)
}
} else {
total += Player.hacknetNodes[i].moneyGainRatePerSecond;
}
}
this.setState({
totalProduction: total,
});
}
setPurchaseMultiplier(mult) {
this.setState({
purchaseMultiplier: mult,
});
}
render() {
// Cost to purchase a new Hacknet Node
let purchaseCost;
if (hasHacknetServers()) {
purchaseCost = getCostOfNextHacknetServer();
recalculateTotalProduction() {
let total = 0;
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
if (hasHacknetServers()) {
const hserver = AllServers[Player.hacknetNodes[i]];
if (hserver) {
total += hserver.hashRate;
} else {
purchaseCost = getCostOfNextHacknetNode();
console.warn(
`Could not find Hacknet Server object in AllServers map (i=${i})`,
);
}
// onClick event handlers for purchase multiplier buttons
const purchaseMultiplierOnClicks = [
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x1),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x5),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x10),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.MAX),
];
// HacknetNode components
const nodes = Player.hacknetNodes.map((node) => {
if (hasHacknetServers()) {
const hserver = AllServers[node];
if (hserver == null) {
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
}
return (
<HacknetServer
key={hserver.hostname}
node={hserver}
purchaseMultiplier={this.state.purchaseMultiplier}
recalculate={this.recalculateTotalProduction}
/>
)
} else {
return (
<HacknetNode
key={node.name}
node={node}
purchaseMultiplier={this.state.purchaseMultiplier}
recalculate={this.recalculateTotalProduction}
/>
)
}
});
return (
<div>
<h1>Hacknet {hasHacknetServers() ? "Servers" : "Nodes"}</h1>
<GeneralInfo />
<PurchaseButton cost={purchaseCost} multiplier={this.state.purchaseMultiplier} onClick={this.handlePurchaseButtonClick} />
<br />
<div id={"hacknet-nodes-money-multipliers-div"}>
<PlayerInfo totalProduction={this.state.totalProduction} />
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={this.state.purchaseMultiplier} />
</div>
{
hasHacknetServers() &&
<button className={"std-button"} onClick={this.createHashUpgradesPopup} style={{display: "block"}}>
{"Spend Hashes on Upgrades"}
</button>
}
<ul id={"hacknet-nodes-list"}>{nodes}</ul>
</div>
)
} else {
total += Player.hacknetNodes[i].moneyGainRatePerSecond;
}
}
this.setState({
totalProduction: total,
});
}
setPurchaseMultiplier(mult) {
this.setState({
purchaseMultiplier: mult,
});
}
render() {
// Cost to purchase a new Hacknet Node
let purchaseCost;
if (hasHacknetServers()) {
purchaseCost = getCostOfNextHacknetServer();
} else {
purchaseCost = getCostOfNextHacknetNode();
}
// onClick event handlers for purchase multiplier buttons
const purchaseMultiplierOnClicks = [
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x1),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x5),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.x10),
this.setPurchaseMultiplier.bind(this, PurchaseMultipliers.MAX),
];
// HacknetNode components
const nodes = Player.hacknetNodes.map((node) => {
if (hasHacknetServers()) {
const hserver = AllServers[node];
if (hserver == null) {
throw new Error(
`Could not find Hacknet Server object in AllServers map for IP: ${node}`,
);
}
return (
<HacknetServer
key={hserver.hostname}
node={hserver}
purchaseMultiplier={this.state.purchaseMultiplier}
recalculate={this.recalculateTotalProduction}
/>
);
} else {
return (
<HacknetNode
key={node.name}
node={node}
purchaseMultiplier={this.state.purchaseMultiplier}
recalculate={this.recalculateTotalProduction}
/>
);
}
});
return (
<div>
<h1>Hacknet {hasHacknetServers() ? "Servers" : "Nodes"}</h1>
<GeneralInfo />
<PurchaseButton
cost={purchaseCost}
multiplier={this.state.purchaseMultiplier}
onClick={this.handlePurchaseButtonClick}
/>
<br />
<div id={"hacknet-nodes-money-multipliers-div"}>
<PlayerInfo totalProduction={this.state.totalProduction} />
<MultiplierButtons
onClicks={purchaseMultiplierOnClicks}
purchaseMultiplier={this.state.purchaseMultiplier}
/>
</div>
{hasHacknetServers() && (
<button
className={"std-button"}
onClick={this.createHashUpgradesPopup}
style={{ display: "block" }}
>
{"Spend Hashes on Upgrades"}
</button>
)}
<ul id={"hacknet-nodes-list"}>{nodes}</ul>
</div>
);
}
}