This commit is contained in:
Olivier Gagnon 2021-11-18 11:32:22 -05:00
commit fc4c0fd8fd
26 changed files with 281 additions and 157 deletions

8
dist/bitburner.d.ts vendored

@ -3093,13 +3093,13 @@ export declare interface NS extends Singularity {
* @remarks * @remarks
* RAM cost: 0.05 GB * RAM cost: 0.05 GB
* *
* Returns the amount of time in seconds it takes to execute the grow Netscript function on the target server. * Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server.
* The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels. * The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.
* *
* @param host - Host of target server. * @param host - Host of target server.
* @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level. * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.
* @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5). * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).
* @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
*/ */
getGrowTime(host: string): number; getGrowTime(host: string): number;
@ -3108,13 +3108,13 @@ export declare interface NS extends Singularity {
* @remarks * @remarks
* RAM cost: 0.05 GB * RAM cost: 0.05 GB
* *
* Returns the amount of time in seconds it takes to execute the weaken() Netscript function on the target server. * Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server.
* The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels. * The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.
* *
* @param host - Host of target server. * @param host - Host of target server.
* @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level. * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.
* @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5). * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).
* @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
*/ */
getWeakenTime(host: string): number; getWeakenTime(host: string): number;

26
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.58' version = '1.0'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.58.0' release = '1.0.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

@ -12476,7 +12476,7 @@
{ {
"kind": "MethodSignature", "kind": "MethodSignature",
"canonicalReference": "bitburner!NS#getGrowTime:member(1)", "canonicalReference": "bitburner!NS#getGrowTime:member(1)",
"docComment": "/**\n * Get the execution time of a grow() call.\n *\n * @remarks\n *\n * RAM cost: 0.05 GB\n *\n * Returns the amount of time in seconds it takes to execute the grow Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.\n *\n * @param host - Host of target server.\n *\n * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.\n *\n * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).\n *\n * @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.\n */\n", "docComment": "/**\n * Get the execution time of a grow() call.\n *\n * @remarks\n *\n * RAM cost: 0.05 GB\n *\n * Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.\n *\n * @param host - Host of target server.\n *\n * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.\n *\n * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).\n *\n * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",
@ -13836,7 +13836,7 @@
{ {
"kind": "MethodSignature", "kind": "MethodSignature",
"canonicalReference": "bitburner!NS#getWeakenTime:member(1)", "canonicalReference": "bitburner!NS#getWeakenTime:member(1)",
"docComment": "/**\n * Get the execution time of a weaken() call.\n *\n * @remarks\n *\n * RAM cost: 0.05 GB\n *\n * Returns the amount of time in seconds it takes to execute the weaken() Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.\n *\n * @param host - Host of target server.\n *\n * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.\n *\n * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).\n *\n * @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.\n */\n", "docComment": "/**\n * Get the execution time of a weaken() call.\n *\n * @remarks\n *\n * RAM cost: 0.05 GB\n *\n * Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.\n *\n * @param host - Host of target server.\n *\n * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.\n *\n * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).\n *\n * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.\n */\n",
"excerptTokens": [ "excerptTokens": [
{ {
"kind": "Content", "kind": "Content",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -22,11 +22,11 @@ getGrowTime(host: string): number;
number number
Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
## Remarks ## Remarks
RAM cost: 0.05 GB RAM cost: 0.05 GB
Returns the amount of time in seconds it takes to execute the grow Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels. Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.

@ -22,11 +22,11 @@ getWeakenTime(host: string): number;
number number
Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
## Remarks ## Remarks
RAM cost: 0.05 GB RAM cost: 0.05 GB
Returns the amount of time in seconds it takes to execute the weaken() Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels. Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.

@ -1,7 +1,7 @@
{ {
"name": "bitburner", "name": "bitburner",
"license": "SEE LICENSE IN license.txt", "license": "SEE LICENSE IN license.txt",
"version": "1.0.0", "version": "1.0.1",
"main": "electron-main.js", "main": "electron-main.js",
"author": { "author": {
"name": "Daniel Xie" "name": "Daniel Xie"

@ -86,7 +86,7 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
if (price === "") price = "0"; if (price === "") price = "0";
if (amt === "") amt = "0"; if (amt === "") amt = "0";
let cost = price.replace(/\s+/g, ""); let cost = price.replace(/\s+/g, "");
cost = cost.replace(/[^-()\d/*+.MP]/g, ""); //Sanitize cost cost = cost.replace(/[^-()\d/*+.MPe]/g, ""); //Sanitize cost
let temp = cost.replace(/MP/g, mat.bCost + ""); let temp = cost.replace(/MP/g, mat.bCost + "");
try { try {
temp = eval(temp); temp = eval(temp);

@ -16,10 +16,13 @@ import { use } from "../../ui/Context";
import { Reputation } from "../../ui/React/Reputation"; import { Reputation } from "../../ui/React/Reputation";
import { Favor } from "../../ui/React/Favor"; import { Favor } from "../../ui/React/Favor";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import TableBody from "@mui/material/TableBody"; import TableBody from "@mui/material/TableBody";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import { CONSTANTS } from "../../Constants";
type IProps = { type IProps = {
faction: Faction; faction: Faction;
@ -176,7 +179,10 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
</> </>
); );
} }
const mult = Math.pow(
CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][player.sourceFileLvl(11)],
player.queuedAugmentations.length,
);
return ( return (
<> <>
<Button onClick={props.routeToMainPage}>Back</Button> <Button onClick={props.routeToMainPage}>Back</Button>
@ -188,6 +194,18 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
Reputation: <Reputation reputation={props.faction.playerReputation} /> Favor:{" "} Reputation: <Reputation reputation={props.faction.playerReputation} /> Favor:{" "}
<Favor favor={props.faction.favor} /> <Favor favor={props.faction.favor} />
</Typography> </Typography>
<Box display="flex">
<Tooltip
title={
<Typography>
The price of every Augmentation increases for every queued Augmentation and it is reset when you install
them.
</Typography>
}
>
<Typography>Price multiplier: x {mult.toFixed(3)}</Typography>
</Tooltip>
</Box>
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button> <Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>Sort by Reputation</Button> <Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>Sort by Reputation</Button>
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>Sort by Default Order</Button> <Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>Sort by Default Order</Button>

@ -19,6 +19,7 @@ import {
import { createRandomIp } from "../utils/IPAddress"; import { createRandomIp } from "../utils/IPAddress";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { IPlayer } from "../PersonObjects/IPlayer";
interface IConstructorParams { interface IConstructorParams {
adminRights?: boolean; adminRights?: boolean;
@ -122,6 +123,11 @@ export class HacknetServer extends BaseServer implements IHacknetNode {
} }
} }
updateRamUsed(ram: number, player: IPlayer): void {
super.updateRamUsed(ram, player);
this.updateHashRate(player.hacknet_node_money_mult);
}
updateHashCapacity(): void { updateHashCapacity(): void {
this.hashCapacity = 32 * Math.pow(2, this.cache); this.hashCapacity = 32 * Math.pow(2, this.cache);
} }

@ -28,7 +28,9 @@ import { TableCell } from "../../ui/React/Table";
import TableBody from "@mui/material/TableBody"; import TableBody from "@mui/material/TableBody";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import TableRow from "@mui/material/TableRow"; import TableRow from "@mui/material/TableRow";
import Tooltip from "@mui/material/Tooltip";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { calculateMoneyGainRate } from "../formulas/HacknetNodes";
interface IProps { interface IProps {
node: HacknetNode; node: HacknetNode;
@ -43,9 +45,9 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
const rerender = props.rerender; const rerender = props.rerender;
// Upgrade Level Button // Upgrade Level Button
let upgradeLevelContent; let upgradeLevelButton;
if (node.level >= HacknetNodeConstants.MaxLevel) { if (node.level >= HacknetNodeConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>; upgradeLevelButton = <Button disabled>MAX LEVEL</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -55,12 +57,23 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateMoneyGainRate(node.level + multiplier, node.ram, node.cores, props.player.hacknet_node_money_mult) -
node.moneyGainRatePerSecond;
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult); const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
upgradeLevelContent = ( upgradeLevelButton = (
<> <Tooltip
title={
<Typography>
+<MoneyRate money={increase} />
</Typography>
}
>
<Button onClick={upgradeLevelOnClick}>
+{multiplier} -&nbsp; +{multiplier} -&nbsp;
<Money money={upgradeLevelCost} player={props.player} /> <Money money={upgradeLevelCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
function upgradeLevelOnClick(): void { function upgradeLevelOnClick(): void {
@ -72,9 +85,9 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
rerender(); rerender();
} }
let upgradeRamContent; let upgradeRAMButton;
if (node.ram >= HacknetNodeConstants.MaxRam) { if (node.ram >= HacknetNodeConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>; upgradeRAMButton = <Button disabled>MAX RAM</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -84,12 +97,27 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateMoneyGainRate(
node.level,
node.ram * Math.pow(2, multiplier),
node.cores,
props.player.hacknet_node_money_mult,
) - node.moneyGainRatePerSecond;
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult); const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
upgradeRamContent = ( upgradeRAMButton = (
<> <Tooltip
title={
<Typography>
+<MoneyRate money={increase} />
</Typography>
}
>
<Button onClick={upgradeRamOnClick}>
+{multiplier} -&nbsp; +{multiplier} -&nbsp;
<Money money={upgradeRamCost} player={props.player} /> <Money money={upgradeRamCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
function upgradeRamOnClick(): void { function upgradeRamOnClick(): void {
@ -99,9 +127,17 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
rerender(); rerender();
} }
let upgradeCoresContent; function upgradeCoresOnClick(): void {
const numUpgrades =
purchaseMult === "MAX"
? getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores)
: purchaseMult;
purchaseCoreUpgrade(props.player, node, numUpgrades);
rerender();
}
let upgradeCoresButton;
if (node.cores >= HacknetNodeConstants.MaxCores) { if (node.cores >= HacknetNodeConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>; upgradeCoresButton = <Button disabled>MAX CORES</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -111,22 +147,25 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateMoneyGainRate(node.level, node.ram, node.cores + multiplier, props.player.hacknet_node_money_mult) -
node.moneyGainRatePerSecond;
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult); const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
upgradeCoresContent = ( upgradeCoresButton = (
<> <Tooltip
title={
<Typography>
+<MoneyRate money={increase} />
</Typography>
}
>
<Button onClick={upgradeCoresOnClick}>
+{multiplier} -&nbsp; +{multiplier} -&nbsp;
<Money money={upgradeCoreCost} player={props.player} /> <Money money={upgradeCoreCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
function upgradeCoresOnClick(): void {
const numUpgrades =
purchaseMult === "MAX"
? getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores)
: purchaseMult;
purchaseCoreUpgrade(props.player, node, numUpgrades);
rerender();
}
return ( return (
<Grid item component={Paper} p={1}> <Grid item component={Paper} p={1}>
@ -155,9 +194,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{node.level}</Typography> <Typography>{node.level}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeLevelButton}</TableCell>
<Button onClick={upgradeLevelOnClick}>{upgradeLevelContent}</Button>
</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell> <TableCell>
@ -166,9 +203,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{numeralWrapper.formatRAM(node.ram)}</Typography> <Typography>{numeralWrapper.formatRAM(node.ram)}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeRAMButton}</TableCell>
<Button onClick={upgradeRamOnClick}>{upgradeRamContent}</Button>
</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell> <TableCell>
@ -177,9 +212,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{node.cores}</Typography> <Typography>{node.cores}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeCoresButton}</TableCell>
<Button onClick={upgradeCoresOnClick}>{upgradeCoresContent}</Button>
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>

@ -32,6 +32,8 @@ import TableBody from "@mui/material/TableBody";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import TableRow from "@mui/material/TableRow"; import TableRow from "@mui/material/TableRow";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { calculateHashGainRate } from "../formulas/HacknetServers";
import Tooltip from "@mui/material/Tooltip";
interface IProps { interface IProps {
node: HacknetServer; node: HacknetServer;
@ -46,9 +48,9 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
const rerender = props.rerender; const rerender = props.rerender;
// Upgrade Level Button // Upgrade Level Button
let upgradeLevelContent; let upgradeLevelButton;
if (node.level >= HacknetServerConstants.MaxLevel) { if (node.level >= HacknetServerConstants.MaxLevel) {
upgradeLevelContent = <>MAX LEVEL</>; upgradeLevelButton = <Button disabled>MAX LEVEL</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -58,12 +60,23 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateHashGainRate(node.level + multiplier, 0, node.maxRam, node.cores, props.player.hacknet_node_money_mult) -
node.hashRate;
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult); const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.hacknet_node_level_cost_mult);
upgradeLevelContent = ( upgradeLevelButton = (
<> <Tooltip
title={
<Typography>
+<HashRate hashes={increase} />
</Typography>
}
>
<Button onClick={upgradeLevelOnClick}>
+{multiplier}&nbsp;-&nbsp; +{multiplier}&nbsp;-&nbsp;
<Money money={upgradeLevelCost} player={props.player} /> <Money money={upgradeLevelCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
function upgradeLevelOnClick(): void { function upgradeLevelOnClick(): void {
@ -75,10 +88,18 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
rerender(); rerender();
} }
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 RAM Button // Upgrade RAM Button
let upgradeRamContent; let upgradeRamButton;
if (node.maxRam >= HacknetServerConstants.MaxRam) { if (node.maxRam >= HacknetServerConstants.MaxRam) {
upgradeRamContent = <>MAX RAM</>; upgradeRamButton = <Button disabled>MAX RAM</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -88,27 +109,43 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateHashGainRate(
node.level,
0,
node.maxRam * Math.pow(2, multiplier),
node.cores,
props.player.hacknet_node_money_mult,
) - node.hashRate;
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult); const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.hacknet_node_ram_cost_mult);
upgradeRamContent = ( upgradeRamButton = (
<> <Tooltip
title={
<Typography>
+<HashRate hashes={increase} />
</Typography>
}
>
<Button onClick={upgradeRamOnClick}>
+{multiplier}&nbsp;-&nbsp; +{multiplier}&nbsp;-&nbsp;
<Money money={upgradeRamCost} player={props.player} /> <Money money={upgradeRamCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
function upgradeRamOnClick(): void {
function upgradeCoresOnClick(): void {
let numUpgrades = purchaseMult; let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam); numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
} }
purchaseRamUpgrade(props.player, node, numUpgrades as number); purchaseCoreUpgrade(props.player, node, numUpgrades as number);
rerender(); rerender();
} }
// Upgrade Cores Button // Upgrade Cores Button
let upgradeCoresContent; let upgradeCoresButton;
if (node.cores >= HacknetServerConstants.MaxCores) { if (node.cores >= HacknetServerConstants.MaxCores) {
upgradeCoresContent = <>MAX CORES</>; upgradeCoresButton = <Button disabled>MAX CORES</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -118,27 +155,30 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
multiplier = Math.min(levelsToMax, purchaseMult as number); multiplier = Math.min(levelsToMax, purchaseMult as number);
} }
const increase =
calculateHashGainRate(node.level, 0, node.maxRam, node.cores + multiplier, props.player.hacknet_node_money_mult) -
node.hashRate;
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult); const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.hacknet_node_core_cost_mult);
upgradeCoresContent = ( upgradeCoresButton = (
<> <Tooltip
title={
<Typography>
+<HashRate hashes={increase} />
</Typography>
}
>
<Button onClick={upgradeCoresOnClick}>
+{multiplier}&nbsp;-&nbsp; +{multiplier}&nbsp;-&nbsp;
<Money money={upgradeCoreCost} player={props.player} /> <Money money={upgradeCoreCost} player={props.player} />
</> </Button>
</Tooltip>
); );
} }
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 // Upgrade Cache button
let upgradeCacheContent; let upgradeCacheButton;
if (node.cache >= HacknetServerConstants.MaxCache) { if (node.cache >= HacknetServerConstants.MaxCache) {
upgradeCacheContent = <>MAX CACHE</>; upgradeCacheButton = <Button disabled>MAX CACHE</Button>;
} else { } else {
let multiplier = 0; let multiplier = 0;
if (purchaseMult === "MAX") { if (purchaseMult === "MAX") {
@ -149,11 +189,19 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
} }
const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier); const upgradeCacheCost = node.calculateCacheUpgradeCost(multiplier);
upgradeCacheContent = ( upgradeCacheButton = (
<> <Tooltip
title={
<Typography>
+<Hashes hashes={32 * Math.pow(2, node.cache)} /> hashes
</Typography>
}
>
<Button onClick={upgradeCacheOnClick}>
+{multiplier}&nbsp;-&nbsp; +{multiplier}&nbsp;-&nbsp;
<Money money={upgradeCacheCost} player={props.player} /> <Money money={upgradeCacheCost} player={props.player} />
</> </Button>
</Tooltip>
); );
if (props.player.money < upgradeCacheCost) { if (props.player.money < upgradeCacheCost) {
} else { } else {
@ -205,9 +253,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{node.level}</Typography> <Typography>{node.level}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeLevelButton}</TableCell>
<Button onClick={upgradeLevelOnClick}>{upgradeLevelContent}</Button>
</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell> <TableCell>
@ -216,9 +262,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{numeralWrapper.formatRAM(node.maxRam)}</Typography> <Typography>{numeralWrapper.formatRAM(node.maxRam)}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeRamButton}</TableCell>
<Button onClick={upgradeRamOnClick}>{upgradeRamContent}</Button>
</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell> <TableCell>
@ -227,9 +271,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{node.cores}</Typography> <Typography>{node.cores}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeCoresButton}</TableCell>
<Button onClick={upgradeCoresOnClick}>{upgradeCoresContent}</Button>
</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell> <TableCell>
@ -238,9 +280,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
<TableCell> <TableCell>
<Typography>{node.cache}</Typography> <Typography>{node.cache}</Typography>
</TableCell> </TableCell>
<TableCell> <TableCell>{upgradeCacheButton}</TableCell>
<Button onClick={upgradeCacheOnClick}>{upgradeCacheContent}</Button>
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>

@ -12,6 +12,7 @@ import { GetServer } from "../Server/AllServers";
import { compareArrays } from "../utils/helpers/compareArrays"; import { compareArrays } from "../utils/helpers/compareArrays";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { AddRecentScript } from "./RecentScripts"; import { AddRecentScript } from "./RecentScripts";
import { Player } from "../Player";
export function killWorkerScript(runningScriptObj: RunningScript, hostname: string, rerenderUi?: boolean): boolean; export function killWorkerScript(runningScriptObj: RunningScript, hostname: string, rerenderUi?: boolean): boolean;
export function killWorkerScript(workerScript: WorkerScript): boolean; export function killWorkerScript(workerScript: WorkerScript): boolean;
@ -110,8 +111,9 @@ function removeWorkerScript(workerScript: WorkerScript, rerenderUi = true): void
} }
// Recalculate ram used on that server // Recalculate ram used on that server
server.ramUsed = 0;
for (const rs of server.runningScripts) server.ramUsed += rs.ramUsage * rs.threads; server.updateRamUsed(0, Player);
for (const rs of server.runningScripts) server.updateRamUsed(server.ramUsed + rs.ramUsage * rs.threads, Player);
// Delete script from global pool (workerScripts) // Delete script from global pool (workerScripts)
const res = workerScripts.delete(workerScript.pid); const res = workerScripts.delete(workerScript.pid);

@ -530,7 +530,6 @@ export function NetscriptSingularity(
if (player.hasProgram(item.program)) { if (player.hasProgram(item.program)) {
workerScript.log("purchaseProgram", `You already have the '${item.program}' program`); workerScript.log("purchaseProgram", `You already have the '${item.program}' program`);
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50);
return true; return true;
} }
@ -540,6 +539,7 @@ export function NetscriptSingularity(
"purchaseProgram", "purchaseProgram",
`You have purchased the '${item.program}' program. The new program can be found on your home computer.`, `You have purchased the '${item.program}' program. The new program can be found on your home computer.`,
); );
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50);
return true; return true;
}, },
getCurrentServer: function (): any { getCurrentServer: function (): any {

@ -33,6 +33,7 @@ import { sprintf } from "sprintf-js";
import { parse } from "acorn"; import { parse } from "acorn";
import { simple as walksimple } from "acorn-walk"; import { simple as walksimple } from "acorn-walk";
import { areFilesEqual } from "./Terminal/DirectoryHelpers"; import { areFilesEqual } from "./Terminal/DirectoryHelpers";
import { Player } from "./Player";
// Netscript Ports are instantiated here // Netscript Ports are instantiated here
export const NetscriptPorts: IPort[] = []; export const NetscriptPorts: IPort[] = [];
@ -167,14 +168,7 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<WorkerScript
const entry = ns[name]; const entry = ns[name];
if (typeof entry === "function") { if (typeof entry === "function") {
//Async functions need to be wrapped. See JS-Interpreter documentation //Async functions need to be wrapped. See JS-Interpreter documentation
if ( if (["hack", "grow", "weaken", "sleep", "prompt", "manualHack", "scp", "write"].includes(name)) {
name === "hack" ||
name === "grow" ||
name === "weaken" ||
name === "sleep" ||
name === "prompt" ||
name === "manualHack"
) {
const tempWrapper = function (...args: any[]): void { const tempWrapper = function (...args: any[]): void {
const fnArgs = []; const fnArgs = [];
@ -497,7 +491,8 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
); );
return false; return false;
} }
server.ramUsed = roundToTwo(server.ramUsed + ramUsage);
server.updateRamUsed(roundToTwo(server.ramUsed + ramUsage), Player);
// Get the pid // Get the pid
const pid = generateNextPid(); const pid = generateNextPid();

@ -854,7 +854,7 @@ export function startFactionHackWork(this: IPlayer, router: IRouter, faction: Fa
this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking); this.resetWorkStatus(CONSTANTS.WorkTypeFaction, faction.name, CONSTANTS.FactionWorkHacking);
this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workHackExpGainRate = 0.15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction); this.workRepGainRate = getHackingWorkRepGain(this, faction);
this.factionWorkType = CONSTANTS.FactionWorkHacking; this.factionWorkType = CONSTANTS.FactionWorkHacking;
this.currentWorkFactionDescription = "carrying out hacking contracts"; this.currentWorkFactionDescription = "carrying out hacking contracts";
@ -872,6 +872,7 @@ export function startFactionFieldWork(this: IPlayer, router: IRouter, faction: F
this.workAgiExpGainRate = 0.1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workAgiExpGainRate = 0.1 * this.agility_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain; this.workChaExpGainRate = 0.1 * this.charisma_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction); this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
console.log(this.workRepGainRate);
this.factionWorkType = CONSTANTS.FactionWorkField; this.factionWorkType = CONSTANTS.FactionWorkField;
this.currentWorkFactionDescription = "carrying out field missions"; this.currentWorkFactionDescription = "carrying out field missions";
@ -906,6 +907,7 @@ export function workForFaction(this: IPlayer, numCycles: number): boolean {
break; break;
case CONSTANTS.FactionWorkField: case CONSTANTS.FactionWorkField:
this.workRepGainRate = getFactionFieldWorkRepGain(this, faction); this.workRepGainRate = getFactionFieldWorkRepGain(this, faction);
console.log(this.workRepGainRate);
break; break;
case CONSTANTS.FactionWorkSecurity: case CONSTANTS.FactionWorkSecurity:
this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction); this.workRepGainRate = getFactionSecurityWorkRepGain(this, faction);
@ -913,6 +915,12 @@ export function workForFaction(this: IPlayer, numCycles: number): boolean {
default: default:
break; break;
} }
let favorMult = 1 + faction.favor / 100;
if (isNaN(favorMult)) {
favorMult = 1;
}
this.workRepGainRate *= favorMult;
this.workRepGainRate *= BitNodeMultipliers.FactionWorkRepGain;
//Cap the number of cycles being processed to whatever would put you at limit (20 hours) //Cap the number of cycles being processed to whatever would put you at limit (20 hours)
let overMax = false; let overMax = false;

@ -1992,7 +1992,7 @@ export interface Singularity {
* *
* @returns True if the installation was successful. * @returns True if the installation was successful.
*/ */
installBackdoor(): Promise<boolean>; installBackdoor(): Promise<void>;
} }
/** /**
@ -3607,7 +3607,7 @@ export interface NS extends Singularity {
* @param growthAmount - Multiplicative factor by which the server is grown. Decimal form.. * @param growthAmount - Multiplicative factor by which the server is grown. Decimal form..
* @returns The amount of grow calls needed to grow the specified server by the specified amount * @returns The amount of grow calls needed to grow the specified server by the specified amount
*/ */
growthAnalyze(host: string, growthAmount: number): number; growthAnalyze(host: string, growthAmount: number, cores?: number): number;
/** /**
* Calculate the security increase for a number of thread. * Calculate the security increase for a number of thread.
@ -4738,13 +4738,13 @@ export interface NS extends Singularity {
* @remarks * @remarks
* RAM cost: 0.05 GB * RAM cost: 0.05 GB
* *
* Returns the amount of time in seconds it takes to execute the grow Netscript function on the target server. * Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server.
* The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels. * The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.
* *
* @param host - Host of target server. * @param host - Host of target server.
* @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level. * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.
* @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5). * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).
* @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
*/ */
getGrowTime(host: string): number; getGrowTime(host: string): number;
@ -4753,13 +4753,13 @@ export interface NS extends Singularity {
* @remarks * @remarks
* RAM cost: 0.05 GB * RAM cost: 0.05 GB
* *
* Returns the amount of time in seconds it takes to execute the weaken() Netscript function on the target server. * Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server.
* The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels. * The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.
* *
* @param host - Host of target server. * @param host - Host of target server.
* @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level. * @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.
* @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5). * @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).
* @returns Returns the amount of time in seconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server. * @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
*/ */
getWeakenTime(host: string): number; getWeakenTime(host: string): number;

@ -12,6 +12,7 @@ import { isScriptFilename } from "../Script/isScriptFilename";
import { createRandomIp } from "../utils/IPAddress"; import { createRandomIp } from "../utils/IPAddress";
import { compareArrays } from "../utils/helpers/compareArrays"; import { compareArrays } from "../utils/helpers/compareArrays";
import { IPlayer } from "../PersonObjects/IPlayer";
interface IConstructorParams { interface IConstructorParams {
adminRights?: boolean; adminRights?: boolean;
@ -245,6 +246,10 @@ export class BaseServer {
this.maxRam = ram; this.maxRam = ram;
} }
updateRamUsed(ram: number, player: IPlayer): void {
this.ramUsed = ram;
}
/** /**
* Write to a script file * Write to a script file
* Overwrites existing files. Creates new files if the script does not eixst * Overwrites existing files. Creates new files if the script does not eixst

@ -225,7 +225,7 @@ export class Terminal implements ITerminal {
} }
if (!(server instanceof Server)) throw new Error("server should be normal server"); if (!(server instanceof Server)) throw new Error("server should be normal server");
const expGain = calculateHackingExpGain(server, player); const expGain = calculateHackingExpGain(server, player);
const growth = processSingleServerGrowth(server, 1, player, server.cpuCores) - 1; const growth = processSingleServerGrowth(server, 25, player, server.cpuCores) - 1;
this.print( this.print(
`Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage( `Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage(
growth, growth,

@ -1,7 +1,7 @@
import { evaluateDirectoryPath, getAllParentDirectories } from "./DirectoryHelpers"; import { evaluateDirectoryPath, getAllParentDirectories } from "./DirectoryHelpers";
import { getSubdirectories } from "./DirectoryServerHelpers"; import { getSubdirectories } from "./DirectoryServerHelpers";
import { Aliases, GlobalAliases } from "../Alias"; import { Aliases, GlobalAliases, substituteAliases } from "../Alias";
import { DarkWebItems } from "../DarkWeb/DarkWebItems"; import { DarkWebItems } from "../DarkWeb/DarkWebItems";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { GetServer, GetAllServers } from "../Server/AllServers"; import { GetServer, GetAllServers } from "../Server/AllServers";
@ -58,6 +58,7 @@ export async function determineAllPossibilitiesForTabCompletion(
index: number, index: number,
currPath = "", currPath = "",
): Promise<string[]> { ): Promise<string[]> {
input = substituteAliases(input);
let allPos: string[] = []; let allPos: string[] = [];
allPos = allPos.concat(Object.keys(GlobalAliases)); allPos = allPos.concat(Object.keys(GlobalAliases));
const currServ = p.getCurrentServer(); const currServ = p.getCurrentServer();
@ -302,7 +303,7 @@ export async function determineAllPossibilitiesForTabCompletion(
const script = currServ.scripts.find((script) => script.filename === filename); const script = currServ.scripts.find((script) => script.filename === filename);
if (!script) return; // Doesn't exist. if (!script) return; // Doesn't exist.
if (!script.module) { if (!script.module) {
compile(script, currServ.scripts); await compile(script, currServ.scripts);
} }
const loadedModule = await script.module; const loadedModule = await script.module;
if (!loadedModule.autocomplete) return; // Doesn't have an autocomplete function. if (!loadedModule.autocomplete) return; // Doesn't have an autocomplete function.

@ -345,6 +345,10 @@ export function InteractiveTutorialRoot(): React.ReactElement {
continuously hack the n00dles server. continuously hack the n00dles server.
<br /> <br />
<br /> <br />
If you're an intermediate programmer you should use ns2 instead. It is much faster and offers more
possibilities.
<br />
<br />
To save and close the script editor, press the button in the bottom left, or press ctrl + b. To save and close the script editor, press the button in the bottom left, or press ctrl + b.
</Typography> </Typography>
</> </>

@ -3,5 +3,5 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { Hashes } from "../../ui/React/Hashes"; import { Hashes } from "../../ui/React/Hashes";
export function HashRate({ hashes }: { hashes: number }): React.ReactElement { export function HashRate({ hashes }: { hashes: number }): React.ReactElement {
return <Hashes hashes={`${numeralWrapper.formatHashes(hashes)} / sec`} />; return <Hashes hashes={`${numeralWrapper.formatHashes(hashes)} h / s`} />;
} }

@ -11,6 +11,9 @@ import { ResizableBox } from "react-resizable";
import makeStyles from "@mui/styles/makeStyles"; import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos"; import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
import { workerScripts } from "../../Netscript/WorkerScripts";
import { startWorkerScript } from "../../NetscriptWorker";
import { GetServer } from "../../Server/AllServers";
let layerCounter = 0; let layerCounter = 0;
@ -21,28 +24,30 @@ interface Log {
script: RunningScript; script: RunningScript;
} }
let logs: Log[] = [];
export function LogBoxManager(): React.ReactElement { export function LogBoxManager(): React.ReactElement {
const [logs, setLogs] = useState<Log[]>([]); const setRerender = useState(true)[1];
function rerender(): void {
setRerender((o) => !o);
}
useEffect( useEffect(
() => () =>
LogBoxEvents.subscribe((script: RunningScript) => { LogBoxEvents.subscribe((script: RunningScript) => {
const id = script.server + "-" + script.filename + script.args.map((x: any): string => `${x}`).join("-"); const id = script.server + "-" + script.filename + script.args.map((x: any): string => `${x}`).join("-");
if (logs.find((l) => l.id === id)) return; if (logs.find((l) => l.id === id)) return;
setLogs((old) => { logs.push({
return [
...old,
{
id: id, id: id,
script: script, script: script,
},
];
}); });
rerender();
}), }),
[], [],
); );
function close(id: string): void { function close(id: string): void {
setLogs((old) => old.filter((l) => l.id !== id)); logs = logs.filter((l) => l.id !== id);
rerender();
} }
return ( return (
@ -87,7 +92,12 @@ function LogWindow(props: IProps): React.ReactElement {
function kill(): void { function kill(): void {
killWorkerScript(props.script, props.script.server, true); killWorkerScript(props.script, props.script.server, true);
props.onClose(); }
function run(): void {
const server = GetServer(props.script.server);
if (server === null) return;
startWorkerScript(props.script, server);
} }
function updateLayer(): void { function updateLayer(): void {
@ -132,12 +142,13 @@ function LogWindow(props: IProps): React.ReactElement {
</Typography> </Typography>
<Box position="absolute" right={0}> <Box position="absolute" right={0}>
<Button onClick={kill}>Kill Script</Button> {!workerScripts.has(props.script.pid) && <Button onClick={run}>Run</Button>}
{workerScripts.has(props.script.pid) && <Button onClick={kill}>Kill</Button>}
<Button onClick={props.onClose}>Close</Button> <Button onClick={props.onClose}>Close</Button>
</Box> </Box>
</Box> </Box>
</Paper> </Paper>
<Paper sx={{ overflow: "scroll", overflowWrap: "break-word", whiteSpace: "pre-line" }}> <Paper sx={{ overflow: "scroll", overflowWrap: "break-word", whiteSpace: "pre-wrap" }}>
<ResizableBox <ResizableBox
className={classes.logs} className={classes.logs}
height={500} height={500}

@ -43,6 +43,7 @@ export function WorkInProgressRoot(): React.ReactElement {
router.toFaction(faction); router.toFaction(faction);
player.stopFocusing(); player.stopFocusing();
} }
console.log(`${player.currentWorkFactionName} ${player.workRepGainRate}`);
return ( return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}> <Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item> <Grid item>