/** * Hacknet Node Class * * Hacknet Nodes are specialized machines that passively earn the player money over time. * They can be upgraded to increase their production */ import { IHacknetNode } from "./IHacknetNode"; import { CONSTANTS } from "../Constants"; import { calculateMoneyGainRate, calculateLevelUpgradeCost, calculateCoreUpgradeCost, calculateRamUpgradeCost, } from "./formulas/HacknetNodes"; import { HacknetNodeConstants } from "./data/Constants"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { ObjectValidator, minMax } from "../utils/Validator"; export class HacknetNode implements IHacknetNode { static validationData: ObjectValidator = { cores: minMax(1, 1, HacknetNodeConstants.MaxCores), level: minMax(1, 1, HacknetNodeConstants.MaxLevel), ram: minMax(1, 1, HacknetNodeConstants.MaxRam), onlineTimeSeconds: minMax(0, 0, Infinity), totalMoneyGenerated: minMax(0, 0, Infinity), }; // Node's number of cores cores = 1; // Node's Level level = 1; // Node's production per second moneyGainRatePerSecond = 0; // Identifier for Node. Includes the full "name" (hacknet-node-N) name: string; // How long this Node has existed, in seconds onlineTimeSeconds = 0; // Node's RAM (GB) ram = 1; // Total money earned by this Node totalMoneyGenerated = 0; constructor(name = "", prodMult = 1) { this.name = name; 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; } 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"); } } /** * 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); } } Reviver.constructors.HacknetNode = HacknetNode;