mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-22 17:23:00 +02:00
convert all hacknet to ts
This commit is contained in:
@@ -18,117 +18,109 @@ import { HashUpgrades } from "./HashUpgrades";
|
||||
|
||||
import { generateRandomContract } from "../CodingContractGenerator";
|
||||
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial";
|
||||
import { Player } from "../Player";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { AllServers } from "../Server/AllServers";
|
||||
import { GetServerByHostname } from "../Server/ServerHelpers";
|
||||
import { Server } from "../Server/Server";
|
||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { Page, routing } from "../ui/navigationTracking";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { HacknetRoot } from "./ui/Root";
|
||||
|
||||
let hacknetNodesDiv;
|
||||
function hacknetNodesInit() {
|
||||
hacknetNodesDiv = document.getElementById("hacknet-nodes-container");
|
||||
document.removeEventListener("DOMContentLoaded", hacknetNodesInit);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", hacknetNodesInit);
|
||||
|
||||
// Returns a boolean indicating whether the player has Hacknet Servers
|
||||
// (the upgraded form of Hacknet Nodes)
|
||||
export function hasHacknetServers() {
|
||||
return Player.bitNodeN === 9 || SourceFileFlags[9] > 0;
|
||||
export function hasHacknetServers(player: IPlayer): boolean {
|
||||
return player.bitNodeN === 9 || SourceFileFlags[9] > 0;
|
||||
}
|
||||
|
||||
export function purchaseHacknet() {
|
||||
export function purchaseHacknet(player: IPlayer): number {
|
||||
/* INTERACTIVE TUTORIAL */
|
||||
if (ITutorial.isRunning) {
|
||||
if (ITutorial.currStep === iTutorialSteps.HacknetNodesIntroduction) {
|
||||
iTutorialNextStep();
|
||||
} else {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* END INTERACTIVE TUTORIAL */
|
||||
|
||||
const numOwned = Player.hacknetNodes.length;
|
||||
if (hasHacknetServers()) {
|
||||
const cost = getCostOfNextHacknetServer();
|
||||
const numOwned = player.hacknetNodes.length;
|
||||
if (hasHacknetServers(player)) {
|
||||
const cost = getCostOfNextHacknetServer(player);
|
||||
if (isNaN(cost)) {
|
||||
throw new Error(`Calculated cost of purchasing HacknetServer is NaN`);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return -1;
|
||||
}
|
||||
Player.loseMoney(cost);
|
||||
Player.createHacknetServer();
|
||||
updateHashManagerCapacity();
|
||||
player.loseMoney(cost);
|
||||
player.createHacknetServer();
|
||||
updateHashManagerCapacity(player);
|
||||
|
||||
return numOwned;
|
||||
} else {
|
||||
const cost = getCostOfNextHacknetNode();
|
||||
const cost = getCostOfNextHacknetNode(player);
|
||||
if (isNaN(cost)) {
|
||||
throw new Error(`Calculated cost of purchasing HacknetNode is NaN`);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Auto generate a name for the Node
|
||||
const name = "hacknet-node-" + numOwned;
|
||||
const node = new HacknetNode(name, Player.hacknet_node_money_mult);
|
||||
const node = new HacknetNode(name, player.hacknet_node_money_mult);
|
||||
|
||||
Player.loseMoney(cost);
|
||||
Player.hacknetNodes.push(node);
|
||||
player.loseMoney(cost);
|
||||
player.hacknetNodes.push(node);
|
||||
|
||||
return numOwned;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasMaxNumberHacknetServers() {
|
||||
return hasHacknetServers() && Player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
|
||||
export function hasMaxNumberHacknetServers(player: IPlayer): boolean {
|
||||
return hasHacknetServers(player) && player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
|
||||
}
|
||||
|
||||
export function getCostOfNextHacknetNode() {
|
||||
return calculateNodeCost(Player.hacknetNodes.length + 1, Player.hacknet_node_purchase_cost_mult);
|
||||
export function getCostOfNextHacknetNode(player: IPlayer): number {
|
||||
return calculateNodeCost(player.hacknetNodes.length + 1, player.hacknet_node_purchase_cost_mult);
|
||||
}
|
||||
|
||||
export function getCostOfNextHacknetServer() {
|
||||
return calculateServerCost(Player.hacknetNodes.length + 1, Player.hacknet_node_purchase_cost_mult);
|
||||
export function getCostOfNextHacknetServer(player: IPlayer): number {
|
||||
return calculateServerCost(player.hacknetNodes.length + 1, player.hacknet_node_purchase_cost_mult);
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
|
||||
export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
||||
export function getMaxNumberLevelUpgrades(
|
||||
player: IPlayer,
|
||||
nodeObj: HacknetNode | HacknetServer,
|
||||
maxLevel: number,
|
||||
): number {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1, Player.hacknet_node_level_cost_mult))) {
|
||||
if (player.money.lt(nodeObj.calculateLevelUpgradeCost(1, player.hacknet_node_level_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 1;
|
||||
let max = maxLevel - 1;
|
||||
let levelsToMax = maxLevel - nodeObj.level;
|
||||
if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, Player.hacknet_node_level_cost_mult))) {
|
||||
const levelsToMax = maxLevel - nodeObj.level;
|
||||
if (player.money.gt(nodeObj.calculateLevelUpgradeCost(levelsToMax, player.hacknet_node_level_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
while (min <= max) {
|
||||
var curr = ((min + max) / 2) | 0;
|
||||
const curr = ((min + max) / 2) | 0;
|
||||
if (
|
||||
curr !== maxLevel &&
|
||||
Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult)) &&
|
||||
Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, Player.hacknet_node_level_cost_mult))
|
||||
player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult)) &&
|
||||
player.money.lt(nodeObj.calculateLevelUpgradeCost(curr + 1, player.hacknet_node_level_cost_mult))
|
||||
) {
|
||||
return Math.min(levelsToMax, curr);
|
||||
} else if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
||||
} else if (player.money.lt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) {
|
||||
max = curr - 1;
|
||||
} else if (Player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, Player.hacknet_node_level_cost_mult))) {
|
||||
} else if (player.money.gt(nodeObj.calculateLevelUpgradeCost(curr, player.hacknet_node_level_cost_mult))) {
|
||||
min = curr + 1;
|
||||
} else {
|
||||
return Math.min(levelsToMax, curr);
|
||||
@@ -138,12 +130,16 @@ export function getMaxNumberLevelUpgrades(nodeObj, maxLevel) {
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
|
||||
export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
||||
export function getMaxNumberRamUpgrades(
|
||||
player: IPlayer,
|
||||
nodeObj: HacknetNode | HacknetServer,
|
||||
maxLevel: number,
|
||||
): number {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateRamUpgradeCost(1, Player.hacknet_node_ram_cost_mult))) {
|
||||
if (player.money.lt(nodeObj.calculateRamUpgradeCost(1, player.hacknet_node_ram_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -153,13 +149,13 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
||||
} else {
|
||||
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
|
||||
}
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, Player.hacknet_node_ram_cost_mult))) {
|
||||
if (player.money.gt(nodeObj.calculateRamUpgradeCost(levelsToMax, player.hacknet_node_ram_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
//We'll just loop until we find the max
|
||||
for (let i = levelsToMax - 1; i >= 0; --i) {
|
||||
if (Player.money.gt(nodeObj.calculateRamUpgradeCost(i, Player.hacknet_node_ram_cost_mult))) {
|
||||
if (player.money.gt(nodeObj.calculateRamUpgradeCost(i, player.hacknet_node_ram_cost_mult))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -167,34 +163,38 @@ export function getMaxNumberRamUpgrades(nodeObj, maxLevel) {
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
|
||||
export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
||||
export function getMaxNumberCoreUpgrades(
|
||||
player: IPlayer,
|
||||
nodeObj: HacknetNode | HacknetServer,
|
||||
maxLevel: number,
|
||||
): number {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(1, Player.hacknet_node_core_cost_mult))) {
|
||||
if (player.money.lt(nodeObj.calculateCoreUpgradeCost(1, player.hacknet_node_core_cost_mult))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 1;
|
||||
let max = maxLevel - 1;
|
||||
const levelsToMax = maxLevel - nodeObj.cores;
|
||||
if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, Player.hacknet_node_core_cost_mult))) {
|
||||
if (player.money.gt(nodeObj.calculateCoreUpgradeCost(levelsToMax, player.hacknet_node_core_cost_mult))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
// Use a binary search to find the max possible number of upgrades
|
||||
while (min <= max) {
|
||||
let curr = ((min + max) / 2) | 0;
|
||||
const curr = ((min + max) / 2) | 0;
|
||||
if (
|
||||
curr != maxLevel &&
|
||||
Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult)) &&
|
||||
Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, Player.hacknet_node_core_cost_mult))
|
||||
player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult)) &&
|
||||
player.money.lt(nodeObj.calculateCoreUpgradeCost(curr + 1, player.hacknet_node_core_cost_mult))
|
||||
) {
|
||||
return Math.min(levelsToMax, curr);
|
||||
} else if (Player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
||||
} else if (player.money.lt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) {
|
||||
max = curr - 1;
|
||||
} else if (Player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, Player.hacknet_node_core_cost_mult))) {
|
||||
} else if (player.money.gt(nodeObj.calculateCoreUpgradeCost(curr, player.hacknet_node_core_cost_mult))) {
|
||||
min = curr + 1;
|
||||
} else {
|
||||
return Math.min(levelsToMax, curr);
|
||||
@@ -205,34 +205,34 @@ export function getMaxNumberCoreUpgrades(nodeObj, maxLevel) {
|
||||
}
|
||||
|
||||
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
|
||||
export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
||||
export function getMaxNumberCacheUpgrades(player: IPlayer, nodeObj: HacknetServer, maxLevel: number): number {
|
||||
if (maxLevel == null) {
|
||||
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
|
||||
if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let min = 1;
|
||||
let max = maxLevel - 1;
|
||||
const levelsToMax = maxLevel - nodeObj.cache;
|
||||
if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
|
||||
if (player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
|
||||
return levelsToMax;
|
||||
}
|
||||
|
||||
// Use a binary search to find the max possible number of upgrades
|
||||
while (min <= max) {
|
||||
let curr = ((min + max) / 2) | 0;
|
||||
const curr = ((min + max) / 2) | 0;
|
||||
if (
|
||||
curr != maxLevel &&
|
||||
Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
|
||||
!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
|
||||
player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
|
||||
!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
|
||||
) {
|
||||
return Math.min(levelsToMax, curr);
|
||||
} else if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||
} else if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||
max = curr - 1;
|
||||
} else if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||
} else if (player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
|
||||
min = curr + 1;
|
||||
} else {
|
||||
return Math.min(levelsToMax, curr);
|
||||
@@ -242,9 +242,9 @@ export function getMaxNumberCacheUpgrades(nodeObj, maxLevel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function purchaseLevelUpgrade(node, levels = 1) {
|
||||
export function purchaseLevelUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, Player.hacknet_node_level_cost_mult);
|
||||
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, player.hacknet_node_level_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -260,60 +260,61 @@ export function purchaseLevelUpgrade(node, levels = 1) {
|
||||
// the maximum number of upgrades and use that
|
||||
if (node.level + sanitizedLevels > (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel)) {
|
||||
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel) - node.level);
|
||||
return purchaseLevelUpgrade(node, diff);
|
||||
return purchaseLevelUpgrade(player, node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeLevel(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
player.loseMoney(cost);
|
||||
node.upgradeLevel(sanitizedLevels, player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseRamUpgrade(node, levels = 1) {
|
||||
export function purchaseRamUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateRamUpgradeCost(sanitizedLevels, Player.hacknet_node_ram_cost_mult);
|
||||
const cost = node.calculateRamUpgradeCost(sanitizedLevels, player.hacknet_node_ram_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isServer = node instanceof HacknetServer;
|
||||
if (node instanceof HacknetServer && node.maxRam >= HacknetServerConstants.MaxRam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fail if we're already at max
|
||||
if (node.ram >= (isServer ? HacknetServerConstants.MaxRam : HacknetNodeConstants.MaxRam)) {
|
||||
if (node instanceof HacknetNode && node.ram >= HacknetNodeConstants.MaxRam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the number of specified upgrades would exceed the max RAM, calculate the
|
||||
// max possible number of upgrades and use that
|
||||
if (isServer) {
|
||||
if (node instanceof HacknetServer) {
|
||||
if (node.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerConstants.MaxRam) {
|
||||
const diff = Math.max(0, Math.log2(Math.round(HacknetServerConstants.MaxRam / node.maxRam)));
|
||||
return purchaseRamUpgrade(node, diff);
|
||||
return purchaseRamUpgrade(player, node, diff);
|
||||
}
|
||||
} else {
|
||||
} else if (node instanceof HacknetNode) {
|
||||
if (node.ram * Math.pow(2, sanitizedLevels) > HacknetNodeConstants.MaxRam) {
|
||||
const diff = Math.max(0, Math.log2(Math.round(HacknetNodeConstants.MaxRam / node.ram)));
|
||||
return purchaseRamUpgrade(node, diff);
|
||||
return purchaseRamUpgrade(player, node, diff);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeRam(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
player.loseMoney(cost);
|
||||
node.upgradeRam(sanitizedLevels, player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseCoreUpgrade(node, levels = 1) {
|
||||
export function purchaseCoreUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, Player.hacknet_node_core_cost_mult);
|
||||
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, player.hacknet_node_core_cost_mult);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -329,20 +330,20 @@ export function purchaseCoreUpgrade(node, levels = 1) {
|
||||
// the max possible number of upgrades and use that
|
||||
if (node.cores + sanitizedLevels > (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores)) {
|
||||
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores) - node.cores);
|
||||
return purchaseCoreUpgrade(node, diff);
|
||||
return purchaseCoreUpgrade(player, node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
node.upgradeCore(sanitizedLevels, Player.hacknet_node_money_mult);
|
||||
player.loseMoney(cost);
|
||||
node.upgradeCore(sanitizedLevels, player.hacknet_node_money_mult);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function purchaseCacheUpgrade(node, levels = 1) {
|
||||
export function purchaseCacheUpgrade(player: IPlayer, node: HacknetServer, levels = 1): boolean {
|
||||
const sanitizedLevels = Math.round(levels);
|
||||
const cost = node.calculateCacheUpgradeCost(sanitizedLevels);
|
||||
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
|
||||
@@ -357,143 +358,132 @@ export function purchaseCacheUpgrade(node, levels = 1) {
|
||||
// Fail if we're already at max
|
||||
if (node.cache + sanitizedLevels > HacknetServerConstants.MaxCache) {
|
||||
const diff = Math.max(0, HacknetServerConstants.MaxCache - node.cache);
|
||||
return purchaseCacheUpgrade(node, diff);
|
||||
return purchaseCacheUpgrade(player, node, diff);
|
||||
}
|
||||
|
||||
if (!Player.canAfford(cost)) {
|
||||
if (!player.canAfford(cost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player.loseMoney(cost);
|
||||
player.loseMoney(cost);
|
||||
node.upgradeCache(sanitizedLevels);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create/Refresh Hacknet Nodes UI
|
||||
export function renderHacknetNodesUI() {
|
||||
if (!routing.isOn(Page.HacknetNodes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReactDOM.render(<HacknetRoot />, hacknetNodesDiv);
|
||||
}
|
||||
|
||||
export function clearHacknetNodesUI() {
|
||||
if (hacknetNodesDiv instanceof HTMLElement) {
|
||||
ReactDOM.unmountComponentAtNode(hacknetNodesDiv);
|
||||
}
|
||||
|
||||
hacknetNodesDiv.style.display = "none";
|
||||
}
|
||||
|
||||
export function processHacknetEarnings(numCycles) {
|
||||
export function processHacknetEarnings(player: IPlayer, numCycles: number): number {
|
||||
// Determine if player has Hacknet Nodes or Hacknet Servers, then
|
||||
// call the appropriate function
|
||||
if (Player.hacknetNodes.length === 0) {
|
||||
if (player.hacknetNodes.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (hasHacknetServers()) {
|
||||
return processAllHacknetServerEarnings(numCycles);
|
||||
} else if (Player.hacknetNodes[0] instanceof HacknetNode) {
|
||||
return processAllHacknetNodeEarnings(numCycles);
|
||||
if (hasHacknetServers(player)) {
|
||||
return processAllHacknetServerEarnings(player, numCycles);
|
||||
} else if (player.hacknetNodes[0] instanceof HacknetNode) {
|
||||
return processAllHacknetNodeEarnings(player, numCycles);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function processAllHacknetNodeEarnings(numCycles) {
|
||||
function processAllHacknetNodeEarnings(player: IPlayer, numCycles: number): number {
|
||||
let total = 0;
|
||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||
total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]);
|
||||
for (let i = 0; i < player.hacknetNodes.length; ++i) {
|
||||
const node = player.hacknetNodes[i];
|
||||
if (typeof node === "string") throw new Error("player node should not be ip string");
|
||||
total += processSingleHacknetNodeEarnings(player, numCycles, node);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
function processSingleHacknetNodeEarnings(numCycles, nodeObj) {
|
||||
function processSingleHacknetNodeEarnings(player: IPlayer, numCycles: number, nodeObj: HacknetNode): number {
|
||||
const totalEarnings = nodeObj.process(numCycles);
|
||||
Player.gainMoney(totalEarnings);
|
||||
Player.recordMoneySource(totalEarnings, "hacknetnode");
|
||||
player.gainMoney(totalEarnings);
|
||||
player.recordMoneySource(totalEarnings, "hacknetnode");
|
||||
|
||||
return totalEarnings;
|
||||
}
|
||||
|
||||
function processAllHacknetServerEarnings(numCycles) {
|
||||
if (!(Player.hashManager instanceof HashManager)) {
|
||||
function processAllHacknetServerEarnings(player: IPlayer, numCycles: number): number {
|
||||
if (!(player.hashManager instanceof HashManager)) {
|
||||
throw new Error(`Player does not have a HashManager (should be in 'hashManager' prop)`);
|
||||
}
|
||||
|
||||
let hashes = 0;
|
||||
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
|
||||
for (let i = 0; i < player.hacknetNodes.length; ++i) {
|
||||
// hacknetNodes array only contains the IP addresses of the servers.
|
||||
// Also, update the hash rate before processing
|
||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
||||
const ip = player.hacknetNodes[i];
|
||||
if (ip instanceof HacknetNode) throw new Error(`player nodes should not be HacketNode`);
|
||||
const hserver = AllServers[ip];
|
||||
if (hserver instanceof Server) throw new Error(`player nodes shoud not be Server`);
|
||||
hserver.updateHashRate(player.hacknet_node_money_mult);
|
||||
const h = hserver.process(numCycles);
|
||||
hserver.totalHashesGenerated += h;
|
||||
hashes += h;
|
||||
}
|
||||
|
||||
Player.hashManager.storeHashes(hashes);
|
||||
player.hashManager.storeHashes(hashes);
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
export function updateHashManagerCapacity() {
|
||||
if (!(Player.hashManager instanceof HashManager)) {
|
||||
export function updateHashManagerCapacity(player: IPlayer): void {
|
||||
if (!(player.hashManager instanceof HashManager)) {
|
||||
console.error(`Player does not have a HashManager`);
|
||||
return;
|
||||
}
|
||||
|
||||
const nodes = Player.hacknetNodes;
|
||||
const nodes = player.hacknetNodes;
|
||||
if (nodes.length === 0) {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
if (typeof nodes[i] !== "string") {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = AllServers[nodes[i]];
|
||||
const ip = nodes[i];
|
||||
if (ip instanceof HacknetNode) throw new Error(`player nodes should be string but isn't`);
|
||||
const h = AllServers[ip];
|
||||
if (!(h instanceof HacknetServer)) {
|
||||
Player.hashManager.updateCapacity(0);
|
||||
player.hashManager.updateCapacity(0);
|
||||
return;
|
||||
}
|
||||
|
||||
total += h.hashCapacity;
|
||||
}
|
||||
|
||||
Player.hashManager.updateCapacity(total);
|
||||
player.hashManager.updateCapacity(total);
|
||||
}
|
||||
|
||||
export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
if (!(Player.hashManager instanceof HashManager)) {
|
||||
export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget: string): boolean {
|
||||
if (!(player.hashManager instanceof HashManager)) {
|
||||
console.error(`Player does not have a HashManager`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// HashManager handles the transaction. This just needs to actually implement
|
||||
// the effects of the upgrade
|
||||
if (Player.hashManager.upgrade(upgName)) {
|
||||
if (player.hashManager.upgrade(upgName)) {
|
||||
const upg = HashUpgrades[upgName];
|
||||
|
||||
switch (upgName) {
|
||||
case "Sell for Money": {
|
||||
Player.gainMoney(upg.value);
|
||||
Player.recordMoneySource(upg.value, "hacknetnode");
|
||||
player.gainMoney(upg.value);
|
||||
player.recordMoneySource(upg.value, "hacknetnode");
|
||||
break;
|
||||
}
|
||||
case "Sell for Corporation Funds": {
|
||||
// This will throw if player doesn't have a corporation
|
||||
try {
|
||||
Player.corporation.funds = Player.corporation.funds.plus(upg.value);
|
||||
player.corporation.funds = player.corporation.funds.plus(upg.value);
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -505,10 +495,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||
return false;
|
||||
}
|
||||
if (!(target instanceof Server)) throw new Error(`'${upgTarget}' is not a normal server.`);
|
||||
|
||||
target.changeMinimumSecurity(upg.value, true);
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -520,10 +511,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
console.error(`Invalid target specified in purchaseHashUpgrade(): ${upgTarget}`);
|
||||
return false;
|
||||
}
|
||||
if (!(target instanceof Server)) throw new Error(`'${upgTarget}' is not a normal server.`);
|
||||
|
||||
target.changeMaximumMoney(upg.value, true);
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -539,11 +531,11 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
case "Exchange for Corporation Research": {
|
||||
// This will throw if player doesn't have a corporation
|
||||
try {
|
||||
for (const division of Player.corporation.divisions) {
|
||||
for (const division of player.corporation.divisions) {
|
||||
division.sciResearch.qty += upg.value;
|
||||
}
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -551,9 +543,9 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
case "Exchange for Bladeburner Rank": {
|
||||
// This will throw if player isnt in Bladeburner
|
||||
try {
|
||||
Player.bladeburner.changeRank(Player, upg.value);
|
||||
player.bladeburner.changeRank(player, upg.value);
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -563,9 +555,9 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
try {
|
||||
// As long as we don't change `Bladeburner.totalSkillPoints`, this
|
||||
// shouldn't affect anything else
|
||||
Player.bladeburner.skillPoints += upg.value;
|
||||
player.bladeburner.skillPoints += upg.value;
|
||||
} catch (e) {
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -576,7 +568,7 @@ export function purchaseHashUpgrade(upgName, upgTarget) {
|
||||
}
|
||||
default:
|
||||
console.warn(`Unrecognized upgrade name ${upgName}. Upgrade has no effect`);
|
||||
Player.hashManager.refundUpgrade(upgName);
|
||||
player.hashManager.refundUpgrade(upgName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,19 @@ export const HacknetNodeConstants: {
|
||||
MaxCores: 16,
|
||||
};
|
||||
|
||||
export const PurchaseMultipliers: {
|
||||
[key: string]: number | string | undefined;
|
||||
x1: number;
|
||||
x5: number;
|
||||
x10: number;
|
||||
MAX: string;
|
||||
} = {
|
||||
x1: 1,
|
||||
x5: 5,
|
||||
x10: 10,
|
||||
MAX: "MAX",
|
||||
};
|
||||
|
||||
export const HacknetServerConstants: {
|
||||
// Constants for Hacknet Server stats/production
|
||||
HashesPerLevel: number;
|
||||
|
||||
@@ -54,7 +54,7 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
|
||||
"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}%</>,
|
||||
effectText: (level: number): JSX.Element | null => <>Improves studying by {level * 20}%</>,
|
||||
value: 20, // Improves studying by value%
|
||||
},
|
||||
{
|
||||
@@ -63,7 +63,7 @@ export const HashUpgradesMetadata: IConstructorParams[] = [
|
||||
"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}%</>,
|
||||
effectText: (level: number): JSX.Element | null => <>Improves training by {level * 20}%</>,
|
||||
value: 20, // Improves training by value%
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI
|
||||
*
|
||||
* Displays general information about Hacknet Nodes
|
||||
*/
|
||||
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.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI
|
||||
*
|
||||
* Displays general information about Hacknet Nodes
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
interface IProps {
|
||||
hasHacknetServers: boolean;
|
||||
}
|
||||
|
||||
export function GeneralInfo(props: IProps): React.ReactElement {
|
||||
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>
|
||||
{!props.hasHacknetServers ? (
|
||||
<>
|
||||
<p className={"hacknet-general-info"}>
|
||||
{`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.`}
|
||||
</p>
|
||||
<p className={"hacknet-general-info"}>
|
||||
{`Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node ` +
|
||||
`can be upgraded in order to increase its computing power and thereby increase ` +
|
||||
`the profit you earn from it.`}
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className={"hacknet-general-info"}>
|
||||
{`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.`}
|
||||
</p>
|
||||
<p className={"hacknet-general-info"}>
|
||||
{`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.`}
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI.
|
||||
* This Component displays the panel for a single Hacknet Node
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetNodeConstants } from "../data/Constants";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
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;
|
||||
|
||||
// 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI.
|
||||
* This Component displays the panel for a single Hacknet Node
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetNodeConstants } from "../data/Constants";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { HacknetNode } from "../HacknetNode";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
|
||||
interface IProps {
|
||||
node: HacknetNode;
|
||||
purchaseMultiplier: number | string;
|
||||
rerender: () => void;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function HacknetNodeElem(props: IProps): React.ReactElement {
|
||||
const node = props.node;
|
||||
const purchaseMult = props.purchaseMultiplier;
|
||||
const rerender = props.rerender;
|
||||
|
||||
// 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(props.player, node, HacknetNodeConstants.MaxLevel);
|
||||
} else {
|
||||
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
||||
upgradeLevelContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeLevelCost)) {
|
||||
upgradeLevelClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeLevelClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeLevelOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel);
|
||||
}
|
||||
purchaseLevelUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
let upgradeRamContent, upgradeRamClass;
|
||||
if (node.ram >= HacknetNodeConstants.MaxRam) {
|
||||
upgradeRamContent = <>MAX RAM</>;
|
||||
upgradeRamClass = "std-button-disabled";
|
||||
} else {
|
||||
let multiplier = 0;
|
||||
if (purchaseMult === "MAX") {
|
||||
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
|
||||
} else {
|
||||
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
||||
upgradeRamContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeRamCost)) {
|
||||
upgradeRamClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeRamClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeRamOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
|
||||
}
|
||||
purchaseRamUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
let upgradeCoresContent, upgradeCoresClass;
|
||||
if (node.cores >= HacknetNodeConstants.MaxCores) {
|
||||
upgradeCoresContent = <>MAX CORES</>;
|
||||
upgradeCoresClass = "std-button-disabled";
|
||||
} else {
|
||||
let multiplier = 0;
|
||||
if (purchaseMult === "MAX") {
|
||||
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
|
||||
} else {
|
||||
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
||||
upgradeCoresContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeCoreCost)) {
|
||||
upgradeCoresClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeCoresClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeCoresOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
|
||||
}
|
||||
purchaseCoreUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
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={props.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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Root React Component for the Hacknet Node UI
|
||||
*/
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { GeneralInfo } from "./GeneralInfo";
|
||||
import { HacknetNodeElem } from "./HacknetNodeElem";
|
||||
import { HacknetServerElem } from "./HacknetServerElem";
|
||||
import { HacknetNode } from "../HacknetNode";
|
||||
import { HashUpgradePopup } from "./HashUpgradePopup";
|
||||
import { MultiplierButtons } from "./MultiplierButtons";
|
||||
import { PlayerInfo } from "./PlayerInfo";
|
||||
import { PurchaseButton } from "./PurchaseButton";
|
||||
import { PurchaseMultipliers } from "../data/Constants";
|
||||
|
||||
import {
|
||||
getCostOfNextHacknetNode,
|
||||
getCostOfNextHacknetServer,
|
||||
hasHacknetServers,
|
||||
purchaseHacknet,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function HacknetRoot(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
const [purchaseMultiplier, setPurchaseMultiplier] = useState<number | string>(PurchaseMultipliers.x1);
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(rerender, 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
function createHashUpgradesPopup(): void {
|
||||
const id = "hacknet-server-hash-upgrades-popup";
|
||||
createPopup(id, HashUpgradePopup, {
|
||||
player: props.player,
|
||||
});
|
||||
}
|
||||
|
||||
let totalProduction = 0;
|
||||
for (let i = 0; i < props.player.hacknetNodes.length; ++i) {
|
||||
const node = props.player.hacknetNodes[i];
|
||||
if (hasHacknetServers(props.player)) {
|
||||
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||
const hserver = AllServers[node];
|
||||
if (hserver instanceof Server) throw new Error("node was a normal server"); // should never happen
|
||||
if (hserver) {
|
||||
totalProduction += hserver.hashRate;
|
||||
} else {
|
||||
console.warn(`Could not find Hacknet Server object in AllServers map (i=${i})`);
|
||||
}
|
||||
} else {
|
||||
if (typeof node === "string") throw new Error("node was ip string"); // should never happen
|
||||
totalProduction += node.moneyGainRatePerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
function handlePurchaseButtonClick(): void {
|
||||
purchaseHacknet(props.player);
|
||||
rerender();
|
||||
}
|
||||
|
||||
// Cost to purchase a new Hacknet Node
|
||||
let purchaseCost;
|
||||
if (hasHacknetServers(props.player)) {
|
||||
purchaseCost = getCostOfNextHacknetServer(props.player);
|
||||
} else {
|
||||
purchaseCost = getCostOfNextHacknetNode(props.player);
|
||||
}
|
||||
|
||||
// onClick event handlers for purchase multiplier buttons
|
||||
const purchaseMultiplierOnClicks = [
|
||||
() => setPurchaseMultiplier(PurchaseMultipliers.x1),
|
||||
() => setPurchaseMultiplier(PurchaseMultipliers.x5),
|
||||
() => setPurchaseMultiplier(PurchaseMultipliers.x10),
|
||||
() => setPurchaseMultiplier(PurchaseMultipliers.MAX),
|
||||
];
|
||||
|
||||
// HacknetNode components
|
||||
const nodes = props.player.hacknetNodes.map((node: string | HacknetNode) => {
|
||||
if (hasHacknetServers(props.player)) {
|
||||
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
|
||||
const hserver = AllServers[node];
|
||||
if (hserver == null) {
|
||||
throw new Error(`Could not find Hacknet Server object in AllServers map for IP: ${node}`);
|
||||
}
|
||||
if (hserver instanceof Server) throw new Error("node was normal server"); // should never happen
|
||||
return (
|
||||
<HacknetServerElem
|
||||
player={props.player}
|
||||
key={hserver.hostname}
|
||||
node={hserver}
|
||||
purchaseMultiplier={purchaseMultiplier}
|
||||
rerender={rerender}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
if (typeof node === "string") throw new Error("node was ip string"); // should never happen
|
||||
return (
|
||||
<HacknetNodeElem
|
||||
player={props.player}
|
||||
key={node.name}
|
||||
node={node}
|
||||
purchaseMultiplier={purchaseMultiplier}
|
||||
rerender={rerender}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Hacknet {hasHacknetServers(props.player) ? "Servers" : "Nodes"}</h1>
|
||||
<GeneralInfo hasHacknetServers={hasHacknetServers(props.player)} />
|
||||
|
||||
<PurchaseButton cost={purchaseCost} multiplier={purchaseMultiplier} onClick={handlePurchaseButtonClick} />
|
||||
|
||||
<br />
|
||||
<div id={"hacknet-nodes-money-multipliers-div"}>
|
||||
<PlayerInfo totalProduction={totalProduction} player={props.player} />
|
||||
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={purchaseMultiplier} />
|
||||
</div>
|
||||
|
||||
{hasHacknetServers(props.player) && (
|
||||
<button className={"std-button"} onClick={createHashUpgradesPopup} style={{ display: "block" }}>
|
||||
{"Spend Hashes on Upgrades"}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<ul id={"hacknet-nodes-list"}>{nodes}</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI.
|
||||
* This Component displays the panel for a single Hacknet Node
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetServerConstants } from "../data/Constants";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
getMaxNumberCacheUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
purchaseCacheUpgrade,
|
||||
updateHashManagerCapacity,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
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;
|
||||
|
||||
// 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* React Component for the Hacknet Node UI.
|
||||
* This Component displays the panel for a single Hacknet Node
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { HacknetServerConstants } from "../data/Constants";
|
||||
import {
|
||||
getMaxNumberLevelUpgrades,
|
||||
getMaxNumberRamUpgrades,
|
||||
getMaxNumberCoreUpgrades,
|
||||
getMaxNumberCacheUpgrades,
|
||||
purchaseLevelUpgrade,
|
||||
purchaseRamUpgrade,
|
||||
purchaseCoreUpgrade,
|
||||
purchaseCacheUpgrade,
|
||||
updateHashManagerCapacity,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { HacknetServer } from "../HacknetServer";
|
||||
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Hashes } from "../../ui/React/Hashes";
|
||||
import { HashRate } from "../../ui/React/HashRate";
|
||||
|
||||
interface IProps {
|
||||
node: HacknetServer;
|
||||
purchaseMultiplier: number | string;
|
||||
rerender: () => void;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function HacknetServerElem(props: IProps): React.ReactElement {
|
||||
const node = props.node;
|
||||
const purchaseMult = props.purchaseMultiplier;
|
||||
const rerender = props.rerender;
|
||||
|
||||
// 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(props.player, node, HacknetServerConstants.MaxLevel);
|
||||
} else {
|
||||
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
|
||||
upgradeLevelContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeLevelCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeLevelCost)) {
|
||||
upgradeLevelClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeLevelClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeLevelOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberLevelUpgrades(props.player, node, HacknetServerConstants.MaxLevel);
|
||||
}
|
||||
purchaseLevelUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
// 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(props.player, node, HacknetServerConstants.MaxRam);
|
||||
} else {
|
||||
const levelsToMax = Math.round(Math.log2(HacknetServerConstants.MaxRam / node.maxRam));
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
|
||||
upgradeRamContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeRamCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeRamCost)) {
|
||||
upgradeRamClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeRamClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeRamOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam);
|
||||
}
|
||||
purchaseRamUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
// 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(props.player, node, HacknetServerConstants.MaxCores);
|
||||
} else {
|
||||
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
|
||||
upgradeCoresContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeCoreCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeCoreCost)) {
|
||||
upgradeCoresClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeCoresClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeCoresOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
|
||||
}
|
||||
purchaseCoreUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
}
|
||||
|
||||
// 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(props.player, node, HacknetServerConstants.MaxCache);
|
||||
} else {
|
||||
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
|
||||
multiplier = Math.min(levelsToMax, purchaseMult as number);
|
||||
}
|
||||
|
||||
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
|
||||
upgradeCacheContent = (
|
||||
<>
|
||||
Upgrade x{multiplier} - <Money money={upgradeCacheCost} player={props.player} />
|
||||
</>
|
||||
);
|
||||
if (props.player.money.lt(upgradeCacheCost)) {
|
||||
upgradeCacheClass = "std-button-disabled";
|
||||
} else {
|
||||
upgradeCacheClass = "std-button";
|
||||
}
|
||||
}
|
||||
function upgradeCacheOnClick(): void {
|
||||
let numUpgrades = purchaseMult;
|
||||
if (purchaseMult === "MAX") {
|
||||
numUpgrades = getMaxNumberCacheUpgrades(props.player, node, HacknetServerConstants.MaxCache);
|
||||
}
|
||||
purchaseCacheUpgrade(props.player, node, numUpgrades as number);
|
||||
rerender();
|
||||
updateHashManagerCapacity(props.player);
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { purchaseHashUpgrade } from "../HacknetHelpers";
|
||||
import { HashManager } from "../HashManager";
|
||||
import { HashUpgrade } from "../HashUpgrade";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
|
||||
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
import { CopyableText } from "../../ui/React/CopyableText";
|
||||
import { Hashes } from "../../ui/React/Hashes";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
hashManager: HashManager;
|
||||
upg: HashUpgrade;
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
export function HacknetUpgradeElem(props: IProps): React.ReactElement {
|
||||
const [selectedServer, setSelectedServer] = useState("ecorp");
|
||||
function changeTargetServer(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
setSelectedServer(event.target.value);
|
||||
}
|
||||
|
||||
function purchase(): void {
|
||||
const canPurchase = props.hashManager.hashes >= props.hashManager.getUpgradeCost(props.upg.name);
|
||||
if (canPurchase) {
|
||||
const res = purchaseHashUpgrade(props.player, props.upg.name, selectedServer);
|
||||
if (!res) {
|
||||
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 upgrade affects.",
|
||||
);
|
||||
}
|
||||
props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
const hashManager = props.hashManager;
|
||||
const upg = props.upg;
|
||||
const cost = hashManager.getUpgradeCost(upg.name);
|
||||
const level = hashManager.upgrades[upg.name];
|
||||
const effect = upg.effectText(level);
|
||||
|
||||
// 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={purchase}>
|
||||
Purchase
|
||||
</button>
|
||||
{level > 0 && effect && <p>{effect}</p>}
|
||||
{upg.hasTargetServer && (
|
||||
<ServerDropdown serverType={ServerType.Foreign} onChange={changeTargetServer} style={{ margin: "5px" }} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* Create the pop-up for purchasing upgrades with hashes
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { purchaseHashUpgrade } from "../HacknetHelpers";
|
||||
import { HashManager } from "../HashManager";
|
||||
import { HashUpgrades } from "../HashUpgrades";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
|
||||
|
||||
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);
|
||||
|
||||
this.state = {
|
||||
selectedServer: "ecorp",
|
||||
};
|
||||
|
||||
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.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class HashUpgradePopup extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
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)`);
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Create the pop-up for purchasing upgrades with hashes
|
||||
*/
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { HashManager } from "../HashManager";
|
||||
import { HashUpgrades } from "../HashUpgrades";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
import { Hashes } from "../../ui/React/Hashes";
|
||||
import { HacknetUpgradeElem } from "./HacknetUpgradeElem";
|
||||
|
||||
interface IProps {
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function HashUpgradePopup(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const id = setInterval(() => setRerender((old) => !old), 1000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const hashManager = props.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 (
|
||||
<HacknetUpgradeElem
|
||||
player={props.player}
|
||||
upg={upg}
|
||||
hashManager={hashManager}
|
||||
key={upg.name}
|
||||
rerender={rerender}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Spend your hashes on a variety of different upgrades</p>
|
||||
<p>Hashes: {Hashes(props.player.hashManager.hashes)}</p>
|
||||
{upgradeElems}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,9 +5,16 @@
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { PurchaseMultipliers } from "./Root";
|
||||
import { PurchaseMultipliers } from "../data/Constants";
|
||||
|
||||
function MultiplierButton(props) {
|
||||
interface IMultiplierProps {
|
||||
className: string;
|
||||
key: string;
|
||||
onClick: () => void;
|
||||
text: string;
|
||||
}
|
||||
|
||||
function MultiplierButton(props: IMultiplierProps): React.ReactElement {
|
||||
return (
|
||||
<button className={props.className} onClick={props.onClick}>
|
||||
{props.text}
|
||||
@@ -15,7 +22,12 @@ function MultiplierButton(props) {
|
||||
);
|
||||
}
|
||||
|
||||
export function MultiplierButtons(props) {
|
||||
interface IProps {
|
||||
purchaseMultiplier: number | string;
|
||||
onClicks: (() => void)[];
|
||||
}
|
||||
|
||||
export function MultiplierButtons(props: IProps): React.ReactElement {
|
||||
if (props.purchaseMultiplier == null) {
|
||||
throw new Error(`MultiplierButtons constructed without required props`);
|
||||
}
|
||||
@@ -7,14 +7,19 @@
|
||||
import React from "react";
|
||||
|
||||
import { hasHacknetServers } from "../HacknetHelpers";
|
||||
import { Player } from "../../Player";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { MoneyRate } from "../../ui/React/MoneyRate";
|
||||
import { HashRate } from "../../ui/React/HashRate";
|
||||
import { Hashes } from "../../ui/React/Hashes";
|
||||
|
||||
export function PlayerInfo(props) {
|
||||
const hasServers = hasHacknetServers();
|
||||
interface IProps {
|
||||
totalProduction: number;
|
||||
player: IPlayer;
|
||||
}
|
||||
|
||||
export function PlayerInfo(props: IProps): React.ReactElement {
|
||||
const hasServers = hasHacknetServers(props.player);
|
||||
|
||||
let prod;
|
||||
if (hasServers) {
|
||||
@@ -26,13 +31,13 @@ export function PlayerInfo(props) {
|
||||
return (
|
||||
<p id={"hacknet-nodes-money"}>
|
||||
<span>Money: </span>
|
||||
<Money money={Player.money.toNumber()} />
|
||||
<Money money={props.player.money.toNumber()} />
|
||||
<br />
|
||||
|
||||
{hasServers && (
|
||||
<>
|
||||
<span>
|
||||
Hashes: {Hashes(Player.hashManager.hashes)} / {Hashes(Player.hashManager.capacity)}
|
||||
Hashes: {Hashes(props.player.hashManager.hashes)} / {Hashes(props.player.hashManager.capacity)}
|
||||
</span>
|
||||
<br />
|
||||
</>
|
||||
@@ -7,17 +7,19 @@ 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`);
|
||||
}
|
||||
interface IProps {
|
||||
multiplier: number | string;
|
||||
onClick: () => void;
|
||||
cost: number;
|
||||
}
|
||||
|
||||
export function PurchaseButton(props: IProps): React.ReactElement {
|
||||
const cost = props.cost;
|
||||
let className = Player.canAfford(cost) ? "std-button" : "std-button-disabled";
|
||||
let text;
|
||||
let style = null;
|
||||
if (hasHacknetServers()) {
|
||||
if (hasMaxNumberHacknetServers()) {
|
||||
let style = {};
|
||||
if (hasHacknetServers(Player)) {
|
||||
if (hasMaxNumberHacknetServers(Player)) {
|
||||
className = "std-button-disabled";
|
||||
text = <>Hacknet Server limit reached</>;
|
||||
style = { color: "red" };
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
* Root React Component for the Hacknet Node UI
|
||||
*/
|
||||
import React from "react";
|
||||
|
||||
import { GeneralInfo } from "./GeneralInfo";
|
||||
import { HacknetNode } from "./HacknetNode";
|
||||
import { HacknetServer } from "./HacknetServer";
|
||||
import { HashUpgradePopup } from "./HashUpgradePopup";
|
||||
import { MultiplierButtons } from "./MultiplierButtons";
|
||||
import { PlayerInfo } from "./PlayerInfo";
|
||||
import { PurchaseButton } from "./PurchaseButton";
|
||||
|
||||
import {
|
||||
getCostOfNextHacknetNode,
|
||||
getCostOfNextHacknetServer,
|
||||
hasHacknetServers,
|
||||
purchaseHacknet,
|
||||
} from "../HacknetHelpers";
|
||||
|
||||
import { Player } from "../../Player";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
|
||||
import { createPopup } from "../../ui/React/createPopup";
|
||||
|
||||
export const PurchaseMultipliers = Object.freeze({
|
||||
x1: 1,
|
||||
x5: 5,
|
||||
x10: 10,
|
||||
MAX: "MAX",
|
||||
});
|
||||
|
||||
export class HacknetRoot extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
} 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user