bitburner-src/src/Hacknet/HacknetNode.ts

212 lines
7.1 KiB
TypeScript
Raw Normal View History

2019-03-25 04:03:24 +01:00
/**
* 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 { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { dialogBoxCreate } from "../../utils/DialogBox";
import { Generic_fromJSON,
Generic_toJSON,
Reviver } from "../../utils/JSONReviver";
// Constants for Hacknet Node production
export const HacknetNodeMoneyGainPerLevel: number = 1.6; // Base production per level
// Constants for Hacknet Node purchase/upgrade costs
export const BaseCostForHacknetNode: number = 1000;
export const BaseCostFor1GBOfRamHacknetNode: number = 30e3;
export const BaseCostForHacknetNodeCore: number = 500e3;
export const HacknetNodePurchaseNextMult: number = 1.85; // Multiplier when purchasing an additional hacknet node
export const HacknetNodeUpgradeLevelMult: number = 1.04; // Multiplier for cost when upgrading level
export const HacknetNodeUpgradeRamMult: number = 1.28; // Multiplier for cost when upgrading RAM
export const HacknetNodeUpgradeCoreMult: number = 1.48; // Multiplier for cost when buying another core
// Constants for max upgrade levels for Hacknet Nodes
export const HacknetNodeMaxLevel: number = 200;
export const HacknetNodeMaxRam: number = 64;
export const HacknetNodeMaxCores: number = 16;
export class HacknetNode implements IHacknetNode {
/**
* Initiatizes a HacknetNode object from a JSON save state.
*/
static fromJSON(value: any): HacknetNode {
return Generic_fromJSON(HacknetNode, value.data);
}
// Node's number of cores
cores: number = 1;
// Node's Level
level: number = 1;
// Node's production per second
moneyGainRatePerSecond: number = 0;
// Identifier for Node. Includes the full "name" (hacknet-node-N)
name: string;
// How long this Node has existed, in seconds
onlineTimeSeconds: number = 0;
// Node's RAM (GB)
ram: number = 1;
// Total money earned by this Node
totalMoneyGenerated: number = 0;
constructor(name: string="", prodMult: number=1) {
2019-03-25 04:03:24 +01:00
this.name = name;
this.updateMoneyGainRate(prodMult);
2019-03-25 04:03:24 +01:00
}
// Get the cost to upgrade this Node's number of cores
calculateCoreUpgradeCost(levels: number=1, costMult: number): number {
2019-03-25 04:03:24 +01:00
const sanitizedLevels = Math.round(levels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (this.cores >= HacknetNodeMaxCores) {
return Infinity;
}
const coreBaseCost = BaseCostForHacknetNodeCore;
const mult = HacknetNodeUpgradeCoreMult;
let totalCost = 0;
let currentCores = this.cores;
for (let i = 0; i < sanitizedLevels; ++i) {
totalCost += (coreBaseCost * Math.pow(mult, currentCores-1));
++currentCores;
}
totalCost *= costMult;
2019-03-25 04:03:24 +01:00
return totalCost;
}
// Get the cost to upgrade this Node's level
calculateLevelUpgradeCost(levels: number=1, costMult: number): number {
2019-03-25 04:03:24 +01:00
const sanitizedLevels = Math.round(levels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (this.level >= HacknetNodeMaxLevel) {
return Infinity;
}
const mult = HacknetNodeUpgradeLevelMult;
let totalMultiplier = 0;
let currLevel = this.level;
for (let i = 0; i < sanitizedLevels; ++i) {
totalMultiplier += Math.pow(mult, currLevel);
++currLevel;
}
return BaseCostForHacknetNode / 2 * totalMultiplier * costMult;
2019-03-25 04:03:24 +01:00
}
// Get the cost to upgrade this Node's RAM
calculateRamUpgradeCost(levels: number=1, costMult: number): number {
2019-03-25 04:03:24 +01:00
const sanitizedLevels = Math.round(levels);
if (isNaN(sanitizedLevels) || sanitizedLevels < 1) {
return 0;
}
if (this.ram >= HacknetNodeMaxRam) {
return Infinity;
}
let totalCost = 0;
let numUpgrades = Math.round(Math.log2(this.ram));
let currentRam = this.ram;
for (let i = 0; i < sanitizedLevels; ++i) {
let baseCost = currentRam * BaseCostFor1GBOfRamHacknetNode;
let mult = Math.pow(HacknetNodeUpgradeRamMult, numUpgrades);
totalCost += (baseCost * mult);
currentRam *= 2;
++numUpgrades;
}
totalCost *= costMult;
2019-03-25 04:03:24 +01:00
return totalCost;
}
// Process this Hacknet Node in the game loop.
// Returns the amount of money generated
process(numCycles: number=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: number=1, prodMult: number): void {
this.cores = Math.min(HacknetNodeMaxCores, Math.round(this.cores + levels));
this.updateMoneyGainRate(prodMult);
2019-03-25 04:03:24 +01:00
}
// Upgrade this Node's level, if possible
// Returns a boolean indicating whether the level was successfully updated
upgradeLevel(levels: number=1, prodMult: number): void {
this.level = Math.min(HacknetNodeMaxLevel, Math.round(this.level + levels));
this.updateMoneyGainRate(prodMult);
2019-03-25 04:03:24 +01:00
}
// Upgrade this Node's RAM, if possible
// Returns a boolean indicating whether the RAM was successfully upgraded
upgradeRam(levels: number=1, prodMult: number): void {
for (let i = 0; i < levels; ++i) {
2019-03-25 04:03:24 +01:00
this.ram *= 2; // Ram is always doubled
}
this.ram = Math.round(this.ram); // Handle any floating point precision issues
this.updateMoneyGainRate(prodMult);
2019-03-25 04:03:24 +01:00
}
// Re-calculate this Node's production and update the moneyGainRatePerSecond prop
updateMoneyGainRate(prodMult: number): void {
2019-03-25 04:03:24 +01:00
//How much extra $/s is gained per level
var gainPerLevel = HacknetNodeMoneyGainPerLevel;
this.moneyGainRatePerSecond = (this.level * gainPerLevel) *
Math.pow(1.035, this.ram - 1) *
((this.cores + 5) / 6) *
prodMult *
2019-03-25 04:03:24 +01:00
BitNodeMultipliers.HacknetNodeMoney;
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);
}
}
Reviver.constructors.HacknetNode = HacknetNode;