mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-22 23:53:48 +01:00
convert all hacknet to ts
This commit is contained in:
parent
c97fece747
commit
b7e07bc7f2
@ -2,25 +2,25 @@ const numSpaces = 4;
|
||||
const maxLineLength = 160;
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
extends: "eslint:recommended",
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
ecmaVersion: 8,
|
||||
sourceType: "module",
|
||||
"ecmaVersion": 8,
|
||||
"sourceType": "module"
|
||||
},
|
||||
rules: {
|
||||
"rules": {
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{
|
||||
getWithoutSet: false,
|
||||
setWithoutGet: true,
|
||||
},
|
||||
"getWithoutSet": false,
|
||||
"setWithoutGet": true
|
||||
}
|
||||
],
|
||||
"array-bracket-newline": ["error"],
|
||||
"array-bracket-spacing": ["error"],
|
||||
@ -33,35 +33,50 @@ module.exports = {
|
||||
"block-spacing": ["error"],
|
||||
"brace-style": ["error"],
|
||||
"callback-return": ["error"],
|
||||
camelcase: ["error"],
|
||||
"camelcase": ["error"],
|
||||
"capitalized-comments": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"comma-dangle": ["error"],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": ["error", "last"],
|
||||
complexity: ["error"],
|
||||
"computed-property-spacing": ["error", "never"],
|
||||
"comma-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"complexity": ["error"],
|
||||
"computed-property-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"consistent-return": ["error"],
|
||||
"consistent-this": ["error"],
|
||||
"constructor-super": ["error"],
|
||||
curly: ["error"],
|
||||
"curly": ["error"],
|
||||
"default-case": ["error"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-location": [
|
||||
"error",
|
||||
"property"
|
||||
],
|
||||
"dot-notation": ["error"],
|
||||
"eol-last": ["error"],
|
||||
eqeqeq: ["error"],
|
||||
"eqeqeq": ["error"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": ["error", "never"],
|
||||
"func-names": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"func-style": ["error"],
|
||||
"function-paren-newline": ["error"],
|
||||
"generator-star-spacing": ["error", "before"],
|
||||
"generator-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
allowImplicit: false,
|
||||
},
|
||||
"allowImplicit": false
|
||||
}
|
||||
],
|
||||
"global-require": ["error"],
|
||||
"guard-for-in": ["error"],
|
||||
@ -69,37 +84,52 @@ module.exports = {
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["error"],
|
||||
"id-match": ["error"],
|
||||
"implicit-arrow-linebreak": ["error", "beside"],
|
||||
indent: [
|
||||
"implicit-arrow-linebreak": [
|
||||
"error",
|
||||
"beside"
|
||||
],
|
||||
"indent": [
|
||||
"error",
|
||||
numSpaces,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
},
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"init-declarations": ["error"],
|
||||
"jsx-quotes": ["error"],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"line-comment-position": ["error"],
|
||||
"linebreak-style": ["error", "windows"],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"windows"
|
||||
],
|
||||
"lines-around-comment": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["error"],
|
||||
"max-len": ["error", maxLineLength],
|
||||
"max-len": [
|
||||
"error",
|
||||
maxLineLength
|
||||
],
|
||||
"max-lines": [
|
||||
"error",
|
||||
{
|
||||
skipBlankLines: true,
|
||||
skipComments: true,
|
||||
},
|
||||
"skipBlankLines": true,
|
||||
"skipComments": true
|
||||
}
|
||||
],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["error"],
|
||||
"max-statements": ["error"],
|
||||
"max-statements-per-line": ["error"],
|
||||
"multiline-comment-style": ["off", "starred-block"],
|
||||
"multiline-ternary": ["error", "never"],
|
||||
"multiline-comment-style": [
|
||||
"off",
|
||||
"starred-block"
|
||||
],
|
||||
"multiline-ternary": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"new-cap": ["error"],
|
||||
"new-parens": ["error"],
|
||||
// TODO: configure this...
|
||||
@ -115,15 +145,18 @@ module.exports = {
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-cond-assign": ["error", "except-parens"],
|
||||
"no-cond-assign": [
|
||||
"error",
|
||||
"except-parens"
|
||||
],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["error"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
checkLoops: false,
|
||||
},
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
@ -137,15 +170,15 @@ module.exports = {
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
includeExports: true,
|
||||
},
|
||||
"includeExports": true
|
||||
}
|
||||
],
|
||||
"no-else-return": ["error"],
|
||||
"no-empty": [
|
||||
"error",
|
||||
{
|
||||
allowEmptyCatch: false,
|
||||
},
|
||||
"allowEmptyCatch": false
|
||||
}
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["error"],
|
||||
@ -161,8 +194,8 @@ module.exports = {
|
||||
"error",
|
||||
"all",
|
||||
{
|
||||
conditionalAssign: false,
|
||||
},
|
||||
"conditionalAssign": false
|
||||
}
|
||||
],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-fallthrough": ["error"],
|
||||
@ -173,17 +206,20 @@ module.exports = {
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["error"],
|
||||
"no-inner-declarations": ["error", "both"],
|
||||
"no-inner-declarations": [
|
||||
"error",
|
||||
"both"
|
||||
],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
skipComments: false,
|
||||
skipRegExps: false,
|
||||
skipStrings: false,
|
||||
skipTemplates: false,
|
||||
},
|
||||
"skipComments": false,
|
||||
"skipRegExps": false,
|
||||
"skipStrings": false,
|
||||
"skipTemplates": false
|
||||
}
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
@ -194,9 +230,13 @@ module.exports = {
|
||||
"no-magic-numbers": [
|
||||
"error",
|
||||
{
|
||||
ignore: [-1, 0, 1],
|
||||
ignoreArrayIndexes: true,
|
||||
},
|
||||
"ignore": [
|
||||
-1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"ignoreArrayIndexes": true
|
||||
}
|
||||
],
|
||||
"no-mixed-operators": ["error"],
|
||||
"no-mixed-requires": ["error"],
|
||||
@ -207,8 +247,8 @@ module.exports = {
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{
|
||||
max: 1,
|
||||
},
|
||||
"max": 1
|
||||
}
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["error"],
|
||||
@ -228,8 +268,8 @@ module.exports = {
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
allowForLoopAfterthoughts: true,
|
||||
},
|
||||
"allowForLoopAfterthoughts": true
|
||||
}
|
||||
],
|
||||
"no-process-env": ["error"],
|
||||
"no-process-exit": ["error"],
|
||||
@ -243,10 +283,10 @@ module.exports = {
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
{
|
||||
message: "'log' is too general, use an appropriate level when logging.",
|
||||
object: "console",
|
||||
property: "log",
|
||||
},
|
||||
"message": "'log' is too general, use an appropriate level when logging.",
|
||||
"object": "console",
|
||||
"property": "log"
|
||||
}
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["error"],
|
||||
@ -255,8 +295,8 @@ module.exports = {
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
props: false,
|
||||
},
|
||||
"props": false
|
||||
}
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
@ -293,10 +333,10 @@ module.exports = {
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
ignoreDestructuring: false,
|
||||
ignoreExport: false,
|
||||
ignoreImport: false,
|
||||
},
|
||||
"ignoreDestructuring": false,
|
||||
"ignoreExport": false,
|
||||
"ignoreImport": false
|
||||
}
|
||||
],
|
||||
"no-useless-return": ["error"],
|
||||
"no-var": ["error"],
|
||||
@ -304,7 +344,10 @@ module.exports = {
|
||||
"no-warning-comments": ["error"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": ["error", "below"],
|
||||
"nonblock-statement-body-position": [
|
||||
"error",
|
||||
"below"
|
||||
],
|
||||
"object-curly-newline": ["error"],
|
||||
"object-curly-spacing": ["error"],
|
||||
"object-property-newline": ["error"],
|
||||
@ -312,7 +355,10 @@ module.exports = {
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["error"],
|
||||
"operator-assignment": ["error"],
|
||||
"operator-linebreak": ["error", "none"],
|
||||
"operator-linebreak": [
|
||||
"error",
|
||||
"none"
|
||||
],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["error"],
|
||||
@ -325,15 +371,24 @@ module.exports = {
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["error"],
|
||||
"quote-props": ["error"],
|
||||
quotes: ["error"],
|
||||
radix: ["error", "as-needed"],
|
||||
"quotes": ["error"],
|
||||
"radix": [
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"require-await": ["error"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
semi: ["error"],
|
||||
"rest-spread-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"semi": ["error"],
|
||||
"semi-spacing": ["error"],
|
||||
"semi-style": ["error", "last"],
|
||||
"semi-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"sort-imports": ["error"],
|
||||
"sort-keys": ["error"],
|
||||
"sort-vars": ["error"],
|
||||
@ -343,25 +398,37 @@ module.exports = {
|
||||
"space-infix-ops": ["error"],
|
||||
"space-unary-ops": ["error"],
|
||||
"spaced-comment": ["error"],
|
||||
strict: ["error"],
|
||||
"strict": ["error"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
after: true,
|
||||
before: false,
|
||||
},
|
||||
"after": true,
|
||||
"before": false
|
||||
}
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": ["error", "never"],
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["error"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["error"],
|
||||
"wrap-iife": ["error", "any"],
|
||||
"wrap-iife": [
|
||||
"error",
|
||||
"any"
|
||||
],
|
||||
"wrap-regex": ["error"],
|
||||
"yield-star-spacing": ["error", "before"],
|
||||
yoda: ["error", "never"],
|
||||
},
|
||||
"yield-star-spacing": [
|
||||
"error",
|
||||
"before"
|
||||
],
|
||||
"yoda": [
|
||||
"error",
|
||||
"never"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
@ -8,8 +8,7 @@ const path = require("path");
|
||||
const exec = require("child_process").exec;
|
||||
const semver = require("./semver");
|
||||
|
||||
const getPackageJson = () =>
|
||||
new Promise((resolve, reject) => {
|
||||
const getPackageJson = () => new Promise((resolve, reject) => {
|
||||
try {
|
||||
/* eslint-disable-next-line global-require */
|
||||
resolve(require(path.resolve(process.cwd(), "package.json")));
|
||||
@ -18,8 +17,7 @@ const getPackageJson = () =>
|
||||
}
|
||||
});
|
||||
|
||||
const getEngines = (data) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const getEngines = (data) => new Promise((resolve, reject) => {
|
||||
let versions = null;
|
||||
|
||||
if (data.engines) {
|
||||
@ -33,8 +31,7 @@ const getEngines = (data) =>
|
||||
}
|
||||
});
|
||||
|
||||
const checkNpmVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const checkNpmVersion = (engines) => new Promise((resolve, reject) => {
|
||||
exec("npm -v", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(`Unable to find NPM version\n${stderr}`);
|
||||
@ -46,23 +43,18 @@ const checkNpmVersion = (engines) =>
|
||||
if (semver.satisfies(npmVersion, engineVersion)) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(
|
||||
`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`,
|
||||
);
|
||||
reject(`Incorrect npm version\n'package.json' specifies "${engineVersion}", you are currently running "${npmVersion}".`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const checkNodeVersion = (engines) =>
|
||||
new Promise((resolve, reject) => {
|
||||
const checkNodeVersion = (engines) => new Promise((resolve, reject) => {
|
||||
const nodeVersion = process.version.substring(1);
|
||||
|
||||
if (semver.satisfies(nodeVersion, engines.node)) {
|
||||
resolve(engines);
|
||||
} else {
|
||||
reject(
|
||||
`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`,
|
||||
);
|
||||
reject(`Incorrect node version\n'package.json' specifies "${engines.node}", you are currently running "${process.version}".`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -77,5 +69,5 @@ getPackageJson()
|
||||
/* eslint-disable no-console, no-process-exit */
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -444,6 +444,7 @@ function parseComparator(comp, loose) {
|
||||
}
|
||||
|
||||
class SemVer {
|
||||
|
||||
/**
|
||||
* A semantic version.
|
||||
* @param {string} version The version.
|
||||
@ -487,7 +488,7 @@ class SemVer {
|
||||
// Numberify any prerelease numeric ids
|
||||
if (matches[4]) {
|
||||
this.prerelease = matches[4].split(".").map((id) => {
|
||||
if (/^[0-9]+$/.test(id)) {
|
||||
if ((/^[0-9]+$/).test(id)) {
|
||||
const num = Number(id);
|
||||
if (num >= 0 && num < MAX_SAFE_INTEGER) {
|
||||
return num;
|
||||
@ -531,9 +532,7 @@ class SemVer {
|
||||
}
|
||||
|
||||
return (
|
||||
compareIdentifiers(this.major, other.major) ||
|
||||
compareIdentifiers(this.minor, other.minor) ||
|
||||
compareIdentifiers(this.patch, other.patch)
|
||||
compareIdentifiers(this.major, other.major) || compareIdentifiers(this.minor, other.minor) || compareIdentifiers(this.patch, other.patch)
|
||||
);
|
||||
}
|
||||
|
||||
@ -573,8 +572,7 @@ class SemVer {
|
||||
}
|
||||
}
|
||||
|
||||
const compare = (leftVersion, rightVersion, loose) =>
|
||||
new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose));
|
||||
const compare = (leftVersion, rightVersion, loose) => new SemVer(leftVersion, loose).compare(new SemVer(rightVersion, loose));
|
||||
const gt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) > 0;
|
||||
const lt = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) < 0;
|
||||
const eq = (leftVersion, rightVersion, loose) => compare(leftVersion, rightVersion, loose) === 0;
|
||||
|
@ -1928,7 +1928,7 @@ export class Bladeburner implements IBladeburner {
|
||||
|
||||
// Count increase for contracts/operations
|
||||
for (const contract of Object.values(this.contracts) as Contract[]) {
|
||||
let growthF = Growths[contract.name];
|
||||
const growthF = Growths[contract.name];
|
||||
if (growthF === undefined) throw new Error(`growth formula for action '${contract.name}' is undefined`);
|
||||
contract.count += (seconds * growthF()) / BladeburnerConstants.ActionCountGrowthPeriod;
|
||||
}
|
||||
|
@ -22,8 +22,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
|
||||
});
|
||||
|
||||
blackops = blackops.filter(
|
||||
(blackop: BlackOperation, i: number) =>
|
||||
!(
|
||||
(blackop: BlackOperation, i: number) => !(
|
||||
props.bladeburner.blackops[blackops[i].name] == null &&
|
||||
i !== 0 &&
|
||||
props.bladeburner.blackops[blackops[i - 1].name] == null
|
||||
|
@ -61,8 +61,7 @@ export function CityTabs(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
{Object.values(props.division.offices).map(
|
||||
(office: OfficeSpace | 0) =>
|
||||
office !== 0 && (
|
||||
(office: OfficeSpace | 0) => office !== 0 && (
|
||||
<CityTab
|
||||
current={city === office.loc}
|
||||
key={office.loc}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { useRef } from "react";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { removePopup } from "../../ui/React/createPopup";
|
||||
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||
|
@ -20,8 +20,7 @@ function ExpandButton(props: IExpandButtonProps): React.ReactElement {
|
||||
const allIndustries = Object.keys(Industries).sort();
|
||||
const possibleIndustries = allIndustries
|
||||
.filter(
|
||||
(industryType: string) =>
|
||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
(industryType: string) => props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
)
|
||||
.sort();
|
||||
if (possibleIndustries.length === 0) return <></>;
|
||||
|
@ -424,7 +424,6 @@ function MaterialComponent(props: IMaterialProps): React.ReactElement {
|
||||
)}
|
||||
<br />
|
||||
|
||||
{/* TODO: add flashing here */}
|
||||
<button className={`std-button${shouldFlash() ? " flashing-button" : ""}`} onClick={openSellMaterialPopup}>
|
||||
{sellButtonText}
|
||||
</button>
|
||||
@ -481,17 +480,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
});
|
||||
}
|
||||
|
||||
// Industry material Requirements
|
||||
let generalReqsText = "This Industry uses [" + Object.keys(props.division.reqMats).join(", ") + "] in order to ";
|
||||
if (props.division.prodMats.length > 0) {
|
||||
generalReqsText += "produce [" + props.division.prodMats.join(", ") + "] ";
|
||||
if (props.division.makesProducts) {
|
||||
generalReqsText += " and " + props.division.getProductDescriptionText();
|
||||
}
|
||||
} else if (props.division.makesProducts) {
|
||||
generalReqsText += props.division.getProductDescriptionText() + ".";
|
||||
}
|
||||
|
||||
const ratioLines = [];
|
||||
for (const matName in props.division.reqMats) {
|
||||
if (props.division.reqMats.hasOwnProperty(matName)) {
|
||||
@ -504,16 +492,6 @@ export function IndustryWarehouse(props: IProps): React.ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
let createdItemsText = "in order to create ";
|
||||
if (props.division.prodMats.length > 0) {
|
||||
createdItemsText += "one of each produced Material (" + props.division.prodMats.join(", ") + ") ";
|
||||
if (props.division.makesProducts) {
|
||||
createdItemsText += "or to create one of its Products";
|
||||
}
|
||||
} else if (props.division.makesProducts) {
|
||||
createdItemsText += "one of its Products";
|
||||
}
|
||||
|
||||
// Current State:
|
||||
let stateText;
|
||||
switch (props.division.state) {
|
||||
|
@ -17,8 +17,7 @@ export function NewIndustryPopup(props: IProps): React.ReactElement {
|
||||
const allIndustries = Object.keys(Industries).sort();
|
||||
const possibleIndustries = allIndustries
|
||||
.filter(
|
||||
(industryType: string) =>
|
||||
props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
(industryType: string) => props.corp.divisions.find((division: IIndustry) => division.type === industryType) === undefined,
|
||||
)
|
||||
.sort();
|
||||
const [industry, setIndustry] = useState(possibleIndustries.length > 0 ? possibleIndustries[0] : "");
|
||||
|
@ -5,7 +5,6 @@ import { ICorporation } from "../ICorporation";
|
||||
import { IIndustry } from "../IIndustry";
|
||||
import { SetSmartSupply } from "../Actions";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { isRelevantMaterial } from "./Helpers";
|
||||
import { Material } from "../Material";
|
||||
|
||||
interface ILeftoverProps {
|
||||
@ -43,7 +42,7 @@ interface IProps {
|
||||
|
||||
export function SmartSupplyPopup(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender() {
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
// Smart Supply Checkbox
|
||||
|
@ -737,8 +737,7 @@ class DevMenuComponent extends Component {
|
||||
}
|
||||
|
||||
let sourceFiles = [];
|
||||
validSFN.forEach((i) =>
|
||||
sourceFiles.push(
|
||||
validSFN.forEach((i) => sourceFiles.push(
|
||||
<tr key={"sf-" + i}>
|
||||
<td>
|
||||
<span className="text">SF-{i}:</span>
|
||||
|
@ -123,8 +123,7 @@ export class AugmentationsPage extends React.Component<IProps, IState> {
|
||||
render(): React.ReactNode {
|
||||
const augs = this.getAugsSorted();
|
||||
const purchasable = augs.filter(
|
||||
(aug: string) =>
|
||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(aug: string) => aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!this.props.p.augmentations.some((a) => a.name === aug) &&
|
||||
!this.props.p.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
50
src/Hacknet/ui/GeneralInfo.tsx
Normal file
50
src/Hacknet/ui/GeneralInfo.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
174
src/Hacknet/ui/HacknetNodeElem.tsx
Normal file
174
src/Hacknet/ui/HacknetNodeElem.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
145
src/Hacknet/ui/HacknetRoot.tsx
Normal file
145
src/Hacknet/ui/HacknetRoot.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
227
src/Hacknet/ui/HacknetServerElem.tsx
Normal file
227
src/Hacknet/ui/HacknetServerElem.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
70
src/Hacknet/ui/HacknetUpgradeElem.tsx
Normal file
70
src/Hacknet/ui/HacknetUpgradeElem.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
54
src/Hacknet/ui/HashUpgradePopup.tsx
Normal file
54
src/Hacknet/ui/HashUpgradePopup.tsx
Normal file
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
|
@ -24,7 +24,7 @@ type IProps = {
|
||||
|
||||
export function TechVendorLocation(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender() {
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
const btnStyle = { display: "block" };
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { purchaseTorRouter } from "../LocationsHelpers";
|
||||
|
||||
|
@ -351,7 +351,7 @@ function NetscriptFunctions(workerScript) {
|
||||
throw makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
|
||||
if (hasHacknetServers()) {
|
||||
if (hasHacknetServers(Player)) {
|
||||
const hserver = AllServers[Player.hacknetNodes[i]];
|
||||
if (hserver == null) {
|
||||
throw makeRuntimeErrorMsg(
|
||||
@ -719,24 +719,24 @@ function NetscriptFunctions(workerScript) {
|
||||
return Player.hacknetNodes.length;
|
||||
},
|
||||
maxNumNodes: function () {
|
||||
if (hasHacknetServers()) {
|
||||
if (hasHacknetServers(Player)) {
|
||||
return HacknetServerConstants.MaxServers;
|
||||
}
|
||||
return Infinity;
|
||||
},
|
||||
purchaseNode: function () {
|
||||
return purchaseHacknet();
|
||||
return purchaseHacknet(Player);
|
||||
},
|
||||
getPurchaseNodeCost: function () {
|
||||
if (hasHacknetServers()) {
|
||||
return getCostOfNextHacknetServer();
|
||||
if (hasHacknetServers(Player)) {
|
||||
return getCostOfNextHacknetServer(Player);
|
||||
} else {
|
||||
return getCostOfNextHacknetNode();
|
||||
return getCostOfNextHacknetNode(Player);
|
||||
}
|
||||
},
|
||||
getNodeStats: function (i) {
|
||||
const node = getHacknetNode(i, "getNodeStats");
|
||||
const hasUpgraded = hasHacknetServers();
|
||||
const hasUpgraded = hasHacknetServers(Player);
|
||||
const res = {
|
||||
name: hasUpgraded ? node.hostname : node.name,
|
||||
level: node.level,
|
||||
@ -756,24 +756,24 @@ function NetscriptFunctions(workerScript) {
|
||||
},
|
||||
upgradeLevel: function (i, n) {
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return purchaseLevelUpgrade(node, n);
|
||||
return purchaseLevelUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeRam: function (i, n) {
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return purchaseRamUpgrade(node, n);
|
||||
return purchaseRamUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeCore: function (i, n) {
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return purchaseCoreUpgrade(node, n);
|
||||
return purchaseCoreUpgrade(Player, node, n);
|
||||
},
|
||||
upgradeCache: function (i, n) {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
const res = purchaseCacheUpgrade(node, n);
|
||||
const res = purchaseCacheUpgrade(Player, node, n);
|
||||
if (res) {
|
||||
updateHashManagerCapacity();
|
||||
updateHashManagerCapacity(Player);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
@ -790,36 +790,36 @@ function NetscriptFunctions(workerScript) {
|
||||
return node.calculateCoreUpgradeCost(n, Player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost: function (i, n) {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return Infinity;
|
||||
}
|
||||
const node = getHacknetNode(i, "upgradeCache");
|
||||
return node.calculateCacheUpgradeCost(n);
|
||||
},
|
||||
numHashes: function () {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return 0;
|
||||
}
|
||||
return Player.hashManager.hashes;
|
||||
},
|
||||
hashCapacity: function () {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return 0;
|
||||
}
|
||||
return Player.hashManager.capacity;
|
||||
},
|
||||
hashCost: function (upgName) {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return Player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes: function (upgName, upgTarget) {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(upgName, upgTarget);
|
||||
return purchaseHashUpgrade(Player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgradeLevel: function (upgName) {
|
||||
const level = Player.hashManager.upgrades[upgName];
|
||||
@ -829,13 +829,13 @@ function NetscriptFunctions(workerScript) {
|
||||
return level;
|
||||
},
|
||||
getStudyMult: function () {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return Player.hashManager.getStudyMult();
|
||||
},
|
||||
getTrainingMult: function () {
|
||||
if (!hasHacknetServers()) {
|
||||
if (!hasHacknetServers(Player)) {
|
||||
return false;
|
||||
}
|
||||
return Player.hashManager.getTrainingMult();
|
||||
|
@ -191,4 +191,5 @@ export interface IPlayer {
|
||||
getIntelligenceBonus(weight: number): number;
|
||||
getCasinoWinnings(): number;
|
||||
quitJob(company: string): void;
|
||||
createHacknetServer(): void;
|
||||
}
|
||||
|
@ -2518,7 +2518,6 @@ export function checkForFactionInvitations() {
|
||||
|
||||
//BitRunners
|
||||
var bitrunnersFac = Factions["BitRunners"];
|
||||
var homeComp = this.getHomeComputer();
|
||||
var bitrunnersServer = AllServers[SpecialServerIps[SpecialServerNames.BitRunnersServer]];
|
||||
if (bitrunnersServer == null) {
|
||||
console.error("Could not find BitRunners Server");
|
||||
@ -2743,7 +2742,7 @@ export function checkForFactionInvitations() {
|
||||
var totalHacknetCores = 0;
|
||||
var totalHacknetLevels = 0;
|
||||
for (let i = 0; i < this.hacknetNodes.length; ++i) {
|
||||
if (hasHacknetServers()) {
|
||||
if (hasHacknetServers(this)) {
|
||||
const hserver = AllServers[this.hacknetNodes[i]];
|
||||
if (hserver) {
|
||||
totalHacknetLevels += hserver.level;
|
||||
|
@ -339,7 +339,7 @@ function prestigeSourceFile(flume) {
|
||||
hserver.cache = 5;
|
||||
hserver.updateHashRate(Player.hacknet_node_money_mult);
|
||||
hserver.updateHashCapacity();
|
||||
updateHashManagerCapacity();
|
||||
updateHashManagerCapacity(Player);
|
||||
}
|
||||
|
||||
// Refresh Main Menu (the 'World' menu, specifically)
|
||||
|
@ -157,8 +157,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
d += " [\n";
|
||||
d += n
|
||||
.map(
|
||||
(line: number[]) =>
|
||||
" [" +
|
||||
(line: number[]) => " [" +
|
||||
line.map((x: number) => `${x}`.padStart(2, " ")).join(",") +
|
||||
"]",
|
||||
)
|
||||
|
@ -28,12 +28,8 @@ import {
|
||||
getFactionFieldWorkRepGain,
|
||||
} from "./PersonObjects/formulas/reputation";
|
||||
import { FconfSettings } from "./Fconf/FconfSettings";
|
||||
import {
|
||||
hasHacknetServers,
|
||||
renderHacknetNodesUI,
|
||||
clearHacknetNodesUI,
|
||||
processHacknetEarnings,
|
||||
} from "./Hacknet/HacknetHelpers";
|
||||
import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
||||
import { HacknetRoot } from "./Hacknet/ui/HacknetRoot";
|
||||
import { iTutorialStart } from "./InteractiveTutorial";
|
||||
import { LocationName } from "./Locations/data/LocationNames";
|
||||
import { LocationRoot } from "./Locations/ui/Root";
|
||||
@ -251,7 +247,7 @@ const Engine = {
|
||||
Engine.hideAllContent();
|
||||
Engine.Display.hacknetNodesContent.style.display = "block";
|
||||
routing.navigateTo(Page.HacknetNodes);
|
||||
renderHacknetNodesUI();
|
||||
ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.hacknetNodesContent);
|
||||
MainMenuLinks.HacknetNodes.classList.add("active");
|
||||
},
|
||||
|
||||
@ -462,7 +458,9 @@ const Engine = {
|
||||
Engine.Display.infiltrationContent.style.display = "none";
|
||||
ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent);
|
||||
|
||||
clearHacknetNodesUI();
|
||||
Engine.Display.hacknetNodesContent.style.display = "none";
|
||||
ReactDOM.unmountComponentAtNode(Engine.Display.hacknetNodesContent);
|
||||
|
||||
Engine.Display.createProgramContent.style.display = "none";
|
||||
|
||||
Engine.Display.factionsContent.style.display = "none";
|
||||
@ -670,7 +668,7 @@ const Engine = {
|
||||
updateOnlineScriptTimes(numCycles);
|
||||
|
||||
// Hacknet Nodes
|
||||
processHacknetEarnings(numCycles);
|
||||
processHacknetEarnings(Player, numCycles);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -737,9 +735,7 @@ const Engine = {
|
||||
|
||||
if (Engine.Counters.updateDisplays <= 0) {
|
||||
Engine.displayCharacterOverviewInfo();
|
||||
if (routing.isOn(Page.HacknetNodes)) {
|
||||
renderHacknetNodesUI();
|
||||
} else if (routing.isOn(Page.CreateProgram)) {
|
||||
if (routing.isOn(Page.CreateProgram)) {
|
||||
displayCreateProgramContent();
|
||||
} else if (routing.isOn(Page.Sleeves)) {
|
||||
updateSleevesPage();
|
||||
@ -1020,8 +1016,8 @@ const Engine = {
|
||||
}
|
||||
|
||||
// Hacknet Nodes offline progress
|
||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
||||
const hacknetProdInfo = hasHacknetServers() ? (
|
||||
var offlineProductionFromHacknetNodes = processHacknetEarnings(Player, numCyclesOffline);
|
||||
const hacknetProdInfo = hasHacknetServers(Player) ? (
|
||||
<>{Hashes(offlineProductionFromHacknetNodes)} hashes</>
|
||||
) : (
|
||||
<Money money={offlineProductionFromHacknetNodes} />
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
import React from "react";
|
||||
import { AllServers } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
|
||||
@ -16,52 +17,50 @@ export const ServerType = {
|
||||
Purchased: 3, // Everything from Owned except home computer
|
||||
};
|
||||
|
||||
export class ServerDropdown extends React.Component {
|
||||
interface IProps {
|
||||
serverType: number;
|
||||
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
|
||||
style: any;
|
||||
}
|
||||
|
||||
export function ServerDropdown(props: IProps): React.ReactElement {
|
||||
/**
|
||||
* Checks if the server should be shown in the dropdown menu, based on the
|
||||
* 'serverType' property
|
||||
*/
|
||||
isValidServer(s) {
|
||||
const type = this.props.serverType;
|
||||
function isValidServer(s: Server | HacknetServer): boolean {
|
||||
const purchased = s instanceof Server && s.purchasedByPlayer;
|
||||
const type = props.serverType;
|
||||
switch (type) {
|
||||
case ServerType.All:
|
||||
return true;
|
||||
case ServerType.Foreign:
|
||||
return s.hostname !== "home" && !s.purchasedByPlayer;
|
||||
return s.hostname !== "home" && !purchased;
|
||||
case ServerType.Owned:
|
||||
return s.purchasedByPlayer || s instanceof HacknetServer || s.hostname === "home";
|
||||
return purchased || s instanceof HacknetServer || s.hostname === "home";
|
||||
case ServerType.Purchased:
|
||||
return s.purchasedByPlayer || s instanceof HacknetServer;
|
||||
return purchased || s instanceof HacknetServer;
|
||||
default:
|
||||
console.warn(`Invalid ServerType specified for ServerDropdown component: ${type}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a Server object, creates a Option element
|
||||
*/
|
||||
renderOption(s) {
|
||||
return (
|
||||
<option key={s.hostname} value={s.hostname}>
|
||||
{s.hostname}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const servers = [];
|
||||
for (const serverName in AllServers) {
|
||||
const server = AllServers[serverName];
|
||||
if (this.isValidServer(server)) {
|
||||
servers.push(this.renderOption(server));
|
||||
if (isValidServer(server)) {
|
||||
servers.push(
|
||||
<option key={server.hostname} value={server.hostname}>
|
||||
{server.hostname}
|
||||
</option>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<select className={"dropdown"} onChange={this.props.onChange} style={this.props.style}>
|
||||
<select className={"dropdown"} onChange={props.onChange} style={props.style}>
|
||||
{servers}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user