mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-01-01 19:07:36 +01:00
Merge pull request #3390 from nickofolas/improvement/stats-augs-ui
[Improvement] Overhaul Stats and Augmentations UI
This commit is contained in:
commit
243cdceb8c
@ -7,7 +7,7 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { InstalledAugmentations } from "./InstalledAugmentations";
|
import { InstalledAugmentations } from "./InstalledAugmentations";
|
||||||
import { PlayerMultipliers } from "./PlayerMultipliers";
|
import { PlayerMultipliers } from "./PlayerMultipliers";
|
||||||
import { PurchasedAugmentations } from "./PurchasedAugmentations";
|
import { PurchasedAugmentations } from "./PurchasedAugmentations";
|
||||||
import { SourceFiles } from "./SourceFiles";
|
import { SourceFilesElement } from "./SourceFiles";
|
||||||
|
|
||||||
import { canGetBonus } from "../../ExportBonus";
|
import { canGetBonus } from "../../ExportBonus";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
@ -16,8 +16,55 @@ import Typography from "@mui/material/Typography";
|
|||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Tooltip from "@mui/material/Tooltip";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
import Paper from "@mui/material/Paper";
|
||||||
|
import Container from "@mui/material/Container";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
|
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
|
||||||
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
|
import { Augmentations } from "../Augmentations";
|
||||||
|
import { CONSTANTS } from "../../Constants";
|
||||||
|
import { formatNumber } from "../../utils/StringHelperFunctions";
|
||||||
|
import { Info } from "@mui/icons-material";
|
||||||
|
|
||||||
|
interface NFGDisplayProps {
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
|
||||||
|
const level = player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
|
||||||
|
|
||||||
|
return level > 0 ? (
|
||||||
|
<Paper sx={{ p: 1 }}>
|
||||||
|
<Typography variant="h5" color={Settings.theme.info}>
|
||||||
|
NeuroFlux Governor - Level {level}
|
||||||
|
</Typography>
|
||||||
|
<Typography color={Settings.theme.info}>{Augmentations[AugmentationNames.NeuroFluxGovernor].stats}</Typography>
|
||||||
|
</Paper>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface EntropyDisplayProps {
|
||||||
|
player: IPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EntropyDisplay = ({ player }: EntropyDisplayProps): React.ReactElement => {
|
||||||
|
return player.entropy > 0 ? (
|
||||||
|
<Paper sx={{ p: 1 }}>
|
||||||
|
<Typography variant="h5" color={Settings.theme.error}>
|
||||||
|
Entropy Virus - Level {player.entropy}
|
||||||
|
</Typography>
|
||||||
|
<Typography color={Settings.theme.error}>
|
||||||
|
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}%
|
||||||
|
(multiplicative)
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
exportGameFn: () => void;
|
exportGameFn: () => void;
|
||||||
@ -55,81 +102,113 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||||
<Typography variant="h4">Augmentations</Typography>
|
<Typography variant="h4">Augmentations</Typography>
|
||||||
<Box mx={2}>
|
<Box sx={{ mb: 1 }}>
|
||||||
<Typography>
|
<Paper sx={{ p: 1 }}>
|
||||||
Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to
|
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||||
install them.
|
Purchased Augmentations
|
||||||
</Typography>
|
<Tooltip
|
||||||
<Typography>WARNING: Installing your Augmentations resets most of your progress, including:</Typography>
|
title={
|
||||||
<br />
|
<>
|
||||||
<Typography>- Stats/Skill levels and Experience</Typography>
|
<Typography>
|
||||||
<Typography>- Money</Typography>
|
Below is a list of all Augmentations you have purchased but not yet installed. Click the button
|
||||||
<Typography>- Scripts on every computer but your home computer</Typography>
|
below to install them.
|
||||||
<Typography>- Purchased servers</Typography>
|
</Typography>
|
||||||
<Typography>- Hacknet Nodes</Typography>
|
<Typography>
|
||||||
<Typography>- Faction/Company reputation</Typography>
|
WARNING: Installing your Augmentations resets most of your progress, including:
|
||||||
<Typography>- Stocks</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
<Typography>
|
<Typography>- Stats/Skill levels and Experience</Typography>
|
||||||
Installing Augmentations lets you start over with the perks and benefits granted by all of the Augmentations
|
<Typography>- Money</Typography>
|
||||||
you have ever installed. Also, you will keep any scripts and RAM/Core upgrades on your home computer (but you
|
<Typography>- Scripts on every computer but your home computer</Typography>
|
||||||
will lose all programs besides NUKE.exe)
|
<Typography>- Purchased servers</Typography>
|
||||||
</Typography>
|
<Typography>- Hacknet Nodes</Typography>
|
||||||
|
<Typography>- Faction/Company reputation</Typography>
|
||||||
|
<Typography>- Stocks</Typography>
|
||||||
|
<br />
|
||||||
|
<Typography>
|
||||||
|
Installing Augmentations lets you start over with the perks and benefits granted by all of the
|
||||||
|
Augmentations you have ever installed. Also, you will keep any scripts and RAM/Core upgrades on your
|
||||||
|
home computer (but you will lose all programs besides NUKE.exe)
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||||
|
</Tooltip>
|
||||||
|
</Typography>
|
||||||
|
<ConfirmationModal
|
||||||
|
open={installOpen}
|
||||||
|
onClose={() => setInstallOpen(false)}
|
||||||
|
onConfirm={props.installAugmentationsFn}
|
||||||
|
confirmationText={
|
||||||
|
<>
|
||||||
|
Installing will reset
|
||||||
|
<br />
|
||||||
|
<br />- money
|
||||||
|
<br />- skill / experience
|
||||||
|
<br />- every server except home
|
||||||
|
<br />- factions and reputation
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
You will keep:
|
||||||
|
<br />
|
||||||
|
<br />- All scripts on home
|
||||||
|
<br />- home ram and cores
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
It is recommended to install several Augmentations at once. Preferably everything from any faction of
|
||||||
|
your choosing.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Box sx={{ display: "grid", width: "100%", gridTemplateColumns: "1fr 1fr" }}>
|
||||||
|
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
|
||||||
|
<span>
|
||||||
|
<Button sx={{ width: "100%" }} disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
|
||||||
|
Install Augmentations
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={<Typography>It's always a good idea to backup/export your save!</Typography>}>
|
||||||
|
<Button sx={{ width: "100%" }} onClick={doExport} color="error">
|
||||||
|
Backup Save {exportBonusStr()}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
{player.queuedAugmentations.length > 0 ? (
|
||||||
|
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||||
|
<PurchasedAugmentations />
|
||||||
|
<PlayerMultipliers />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Paper sx={{ p: 1 }}>
|
||||||
|
<Typography>No Augmentations have been purchased yet</Typography>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="h4" color="primary">
|
|
||||||
Purchased Augmentations
|
<Box
|
||||||
</Typography>
|
sx={{
|
||||||
<Box mx={2}>
|
my: 1,
|
||||||
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
|
display: "grid",
|
||||||
<span>
|
gridTemplateColumns: `repeat(${
|
||||||
<Button disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
|
+!!((player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) +
|
||||||
Install Augmentations
|
+!!(player.entropy > 0)
|
||||||
</Button>
|
}, 1fr)`,
|
||||||
</span>
|
gap: 1,
|
||||||
</Tooltip>
|
}}
|
||||||
<ConfirmationModal
|
>
|
||||||
open={installOpen}
|
<NeuroFluxDisplay player={player} />
|
||||||
onClose={() => setInstallOpen(false)}
|
<EntropyDisplay player={player} />
|
||||||
onConfirm={props.installAugmentationsFn}
|
|
||||||
confirmationText={
|
|
||||||
<>
|
|
||||||
Installing will reset
|
|
||||||
<br />
|
|
||||||
<br />- money
|
|
||||||
<br />- skill / experience
|
|
||||||
<br />- every server except home
|
|
||||||
<br />- factions and reputation
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
You will keep:
|
|
||||||
<br />
|
|
||||||
<br />- All scripts on home
|
|
||||||
<br />- home ram and cores
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
It is recommended to install several Augmentations at once. Preferably everything from any faction of your
|
|
||||||
choosing.
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Tooltip title={<Typography>It's always a good idea to backup/export your save!</Typography>}>
|
|
||||||
<Button sx={{ mx: 2 }} onClick={doExport} color="error">
|
|
||||||
Backup Save {exportBonusStr()}
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
<PurchasedAugmentations />
|
|
||||||
</Box>
|
</Box>
|
||||||
<Typography variant="h4">Installed Augmentations</Typography>
|
|
||||||
<Box mx={2}>
|
<Box>
|
||||||
<Typography>
|
|
||||||
List of all Augmentations that have been installed. You have gained the effects of these.
|
|
||||||
</Typography>
|
|
||||||
<InstalledAugmentations />
|
<InstalledAugmentations />
|
||||||
</Box>
|
</Box>
|
||||||
<PlayerMultipliers />
|
<SourceFilesElement />
|
||||||
<SourceFiles />
|
</Container>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,28 +5,23 @@
|
|||||||
* It also contains 'configuration' buttons that allow you to change how the
|
* It also contains 'configuration' buttons that allow you to change how the
|
||||||
* Augs/SF's are displayed
|
* Augs/SF's are displayed
|
||||||
*/
|
*/
|
||||||
|
import { Box, ListItemButton, Paper, Typography } from "@mui/material";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import List from "@mui/material/List";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
|
||||||
import { Augmentations } from "../Augmentations";
|
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
|
||||||
|
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
import { Augmentations } from "../Augmentations";
|
||||||
import Button from "@mui/material/Button";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
import Tooltip from "@mui/material/Tooltip";
|
|
||||||
import List from "@mui/material/List";
|
|
||||||
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
|
||||||
import { Box, Paper, ListItemButton, ListItemText, Typography, Collapse } from "@mui/material";
|
|
||||||
import { CONSTANTS } from "../../Constants";
|
|
||||||
import { formatNumber } from "../../utils/StringHelperFunctions";
|
|
||||||
|
|
||||||
export function InstalledAugmentations(): React.ReactElement {
|
export function InstalledAugmentations(): React.ReactElement {
|
||||||
const setRerender = useState(true)[1];
|
const setRerender = useState(true)[1];
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
|
const sourceAugs = player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
|
||||||
|
|
||||||
const sourceAugs = player.augmentations.slice();
|
const [selectedAug, setSelectedAug] = useState(sourceAugs[0]);
|
||||||
|
|
||||||
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
|
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
|
||||||
sourceAugs.sort((aug1, aug2) => {
|
sourceAugs.sort((aug1, aug2) => {
|
||||||
@ -49,59 +44,60 @@ export function InstalledAugmentations(): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box sx={{ width: "100%" }}>
|
||||||
<Tooltip title={"Sorts the Augmentations alphabetically in numeral order"}>
|
<Paper sx={{ p: 1 }}>
|
||||||
<Button onClick={sortInOrder}>Sort in Order</Button>
|
<Typography variant="h5">Installed Augmentations</Typography>
|
||||||
</Tooltip>
|
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
||||||
<Tooltip title={"Sorts the Augmentations based on when you acquired them (same as default)"}>
|
<Tooltip title={"Sorts the Augmentations alphabetically in numeral order"}>
|
||||||
<Button sx={{ mx: 2 }} onClick={sortByAcquirementTime}>
|
<Button sx={{ width: "100%" }} onClick={sortInOrder}>
|
||||||
Sort by Acquirement Time
|
Sort in Order
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<List dense>
|
<Tooltip title={"Sorts the Augmentations based on when you acquired them (same as default)"}>
|
||||||
{player.entropy > 0 &&
|
<Button sx={{ width: "100%" }} onClick={sortByAcquirementTime}>
|
||||||
(() => {
|
Sort by Time of Acquirement
|
||||||
const [open, setOpen] = useState(false);
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
return (
|
</Box>
|
||||||
<Box component={Paper}>
|
</Paper>
|
||||||
<ListItemButton onClick={() => setOpen((old) => !old)}>
|
{sourceAugs.length > 0 ? (
|
||||||
<ListItemText
|
<Paper sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||||
primary={
|
<Box>
|
||||||
<Typography color={Settings.theme.hp} style={{ whiteSpace: "pre-wrap" }}>
|
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
||||||
Entropy Virus - Level {player.entropy}
|
{sourceAugs.map((k, i) => (
|
||||||
</Typography>
|
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
||||||
}
|
<Typography>{k.name}</Typography>
|
||||||
/>
|
|
||||||
{open ? (
|
|
||||||
<ExpandLess sx={{ color: Settings.theme.hp }} />
|
|
||||||
) : (
|
|
||||||
<ExpandMore sx={{ color: Settings.theme.hp }} />
|
|
||||||
)}
|
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Collapse in={open} unmountOnExit>
|
))}
|
||||||
<Box m={4}>
|
</List>
|
||||||
<Typography color={Settings.theme.hp}>
|
</Box>
|
||||||
<b>All multipliers decreased by:</b>{" "}
|
<Box sx={{ m: 1 }}>
|
||||||
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative)
|
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||||
</Typography>
|
{selectedAug.name}
|
||||||
</Box>
|
</Typography>
|
||||||
</Collapse>
|
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
|
||||||
</Box>
|
{(() => {
|
||||||
);
|
const aug = Augmentations[selectedAug.name];
|
||||||
})()}
|
|
||||||
|
|
||||||
{sourceAugs.map((e) => {
|
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||||
const aug = Augmentations[e.name];
|
const tooltip = (
|
||||||
|
<>
|
||||||
let level = null;
|
{info}
|
||||||
if (e.name === AugmentationNames.NeuroFluxGovernor) {
|
<br />
|
||||||
level = e.level;
|
<br />
|
||||||
}
|
{aug.stats}
|
||||||
|
</>
|
||||||
return <AugmentationAccordion key={aug.name} aug={aug} level={level} />;
|
);
|
||||||
})}
|
return tooltip;
|
||||||
</List>
|
})()}
|
||||||
</>
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
) : (
|
||||||
|
<Paper sx={{ p: 1 }}>
|
||||||
|
<Typography>No Augmentations have been installed yet</Typography>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
/**
|
/**
|
||||||
* React component for displaying the player's multipliers on the Augmentation UI page
|
* React component for displaying the player's multipliers on the Augmentation UI page
|
||||||
*/
|
*/
|
||||||
|
import { DoubleArrow } from "@mui/icons-material";
|
||||||
|
import { List, ListItem, ListItemText, Paper, Typography } from "@mui/material";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||||
import { Player } from "../../Player";
|
import { Player } from "../../Player";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { Augmentations } from "../Augmentations";
|
||||||
import { Table, TableCell } from "../../ui/React/Table";
|
|
||||||
import TableBody from "@mui/material/TableBody";
|
|
||||||
import TableRow from "@mui/material/TableRow";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
|
||||||
|
|
||||||
function calculateAugmentedStats(): any {
|
interface IAugmentedStats {
|
||||||
const augP: any = {};
|
[index: string]: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateAugmentedStats(): IAugmentedStats {
|
||||||
|
const augP: IAugmentedStats = {};
|
||||||
for (const aug of Player.queuedAugmentations) {
|
for (const aug of Player.queuedAugmentations) {
|
||||||
const augObj = Augmentations[aug.name];
|
const augObj = Augmentations[aug.name];
|
||||||
for (const mult of Object.keys(augObj.mults)) {
|
for (const mult of Object.keys(augObj.mults)) {
|
||||||
@ -25,268 +27,249 @@ function calculateAugmentedStats(): any {
|
|||||||
return augP;
|
return augP;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Improvements({ r, m }: { r: number; m: number }): React.ReactElement {
|
interface IBitNodeModifiedStatsProps {
|
||||||
if (r) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TableCell key="2">
|
|
||||||
<Typography> {"=>"} </Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell key="3">
|
|
||||||
<Typography>
|
|
||||||
{numeralWrapper.formatPercentage(r)} <BN5Stat base={r} mult={m} />
|
|
||||||
</Typography>
|
|
||||||
</TableCell>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IBN5StatsProps {
|
|
||||||
base: number;
|
base: number;
|
||||||
mult: number;
|
mult: number;
|
||||||
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BN5Stat(props: IBN5StatsProps): React.ReactElement {
|
function BitNodeModifiedStats(props: IBitNodeModifiedStatsProps): React.ReactElement {
|
||||||
if (props.mult === 1) return <></>;
|
// If player doesn't have SF5 or if the property isn't affected by BitNode mults
|
||||||
return <>({numeralWrapper.formatPercentage(props.base * props.mult)})</>;
|
if (props.mult === 1 || SourceFileFlags[5] === 0)
|
||||||
}
|
return <Typography color={props.color}>{numeralWrapper.formatPercentage(props.base)}</Typography>;
|
||||||
|
|
||||||
function MultiplierTable({ rows }: { rows: [string, number, number, number][] }): React.ReactElement {
|
|
||||||
return (
|
return (
|
||||||
<Table size="small" padding="none">
|
<Typography color={props.color}>
|
||||||
<TableBody>
|
<span style={{ opacity: 0.5 }}>{numeralWrapper.formatPercentage(props.base)}</span>{" "}
|
||||||
{rows.map((r: any) => (
|
{numeralWrapper.formatPercentage(props.base * props.mult)}
|
||||||
<TableRow key={r[0]}>
|
</Typography>
|
||||||
<TableCell key="0">
|
|
||||||
<Typography noWrap>{r[0]} multiplier: </Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell key="1" style={{ textAlign: "right" }}>
|
|
||||||
<Typography noWrap>
|
|
||||||
{numeralWrapper.formatPercentage(r[1])} <BN5Stat base={r[1]} mult={r[3]} />
|
|
||||||
</Typography>
|
|
||||||
</TableCell>
|
|
||||||
<Improvements r={r[2]} m={r[3]} />
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MultiplierListItemData = [
|
||||||
|
multiplier: string,
|
||||||
|
currentValue: number,
|
||||||
|
augmentedValue: number,
|
||||||
|
bitNodeMultiplier: number,
|
||||||
|
color: string,
|
||||||
|
];
|
||||||
|
|
||||||
|
interface IMultiplierListProps {
|
||||||
|
rows: MultiplierListItemData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function MultiplierList(props: IMultiplierListProps): React.ReactElement {
|
||||||
|
const listItems = props.rows
|
||||||
|
.map((data) => {
|
||||||
|
const [multiplier, currentValue, augmentedValue, bitNodeMultiplier, color] = data;
|
||||||
|
|
||||||
|
if (!isNaN(augmentedValue)) {
|
||||||
|
return (
|
||||||
|
<ListItem key={multiplier} disableGutters sx={{ py: 0 }}>
|
||||||
|
<ListItemText
|
||||||
|
sx={{ my: 0.1 }}
|
||||||
|
primary={
|
||||||
|
<Typography color={color}>
|
||||||
|
<b>{multiplier}</b>
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
secondary={
|
||||||
|
<span style={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||||
|
<BitNodeModifiedStats base={currentValue} mult={bitNodeMultiplier} color={color} />
|
||||||
|
<DoubleArrow fontSize="small" color="success" sx={{ mb: 0.5, mx: 1 }} />
|
||||||
|
<BitNodeModifiedStats base={augmentedValue} mult={bitNodeMultiplier} color={Settings.theme.success} />
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
disableTypography
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.filter((i) => i !== undefined);
|
||||||
|
|
||||||
|
return listItems.length > 0 ? <List disablePadding>{listItems}</List> : <></>;
|
||||||
|
}
|
||||||
|
|
||||||
export function PlayerMultipliers(): React.ReactElement {
|
export function PlayerMultipliers(): React.ReactElement {
|
||||||
const mults = calculateAugmentedStats();
|
const mults = calculateAugmentedStats();
|
||||||
|
|
||||||
function BladeburnerMults(): React.ReactElement {
|
// Column data is a bit janky, so it's set up here to allow for
|
||||||
if (!Player.canAccessBladeburner()) return <></>;
|
// easier logic in setting up the layout
|
||||||
return (
|
const leftColData: MultiplierListItemData[] = [
|
||||||
<>
|
...[
|
||||||
<MultiplierTable
|
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
|
||||||
rows={[
|
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
|
||||||
[
|
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
|
||||||
"Bladeburner Success Chance",
|
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
|
||||||
Player.bladeburner_success_chance_mult,
|
[
|
||||||
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
"Hacking Level ",
|
||||||
1,
|
Player.hacking_mult,
|
||||||
],
|
Player.hacking_mult * mults.hacking_mult,
|
||||||
[
|
BitNodeMultipliers.HackingLevelMultiplier,
|
||||||
"Bladeburner Max Stamina",
|
],
|
||||||
Player.bladeburner_max_stamina_mult,
|
[
|
||||||
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
"Hacking Experience ",
|
||||||
1,
|
Player.hacking_exp_mult,
|
||||||
],
|
Player.hacking_exp_mult * mults.hacking_exp_mult,
|
||||||
[
|
BitNodeMultipliers.HackExpGain,
|
||||||
"Bladeburner Stamina Gain",
|
],
|
||||||
Player.bladeburner_stamina_gain_mult,
|
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.hack])),
|
||||||
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
...[
|
||||||
1,
|
[
|
||||||
],
|
"Strength Level ",
|
||||||
[
|
Player.strength_mult,
|
||||||
"Bladeburner Field Analysis",
|
Player.strength_mult * mults.strength_mult,
|
||||||
Player.bladeburner_analysis_mult,
|
BitNodeMultipliers.StrengthLevelMultiplier,
|
||||||
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
],
|
||||||
1,
|
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
|
||||||
],
|
[
|
||||||
]}
|
"Defense Level ",
|
||||||
/>
|
Player.defense_mult,
|
||||||
<br />
|
Player.defense_mult * mults.defense_mult,
|
||||||
</>
|
BitNodeMultipliers.DefenseLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
|
||||||
|
[
|
||||||
|
"Dexterity Level ",
|
||||||
|
Player.dexterity_mult,
|
||||||
|
Player.dexterity_mult * mults.dexterity_mult,
|
||||||
|
BitNodeMultipliers.DexterityLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult, 1],
|
||||||
|
[
|
||||||
|
"Agility Level ",
|
||||||
|
Player.agility_mult,
|
||||||
|
Player.agility_mult * mults.agility_mult,
|
||||||
|
BitNodeMultipliers.AgilityLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
|
||||||
|
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.combat])),
|
||||||
|
[
|
||||||
|
"Charisma Level ",
|
||||||
|
Player.charisma_mult,
|
||||||
|
Player.charisma_mult * mults.charisma_mult,
|
||||||
|
BitNodeMultipliers.CharismaLevelMultiplier,
|
||||||
|
Settings.theme.cha,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Charisma Experience ",
|
||||||
|
Player.charisma_exp_mult,
|
||||||
|
Player.charisma_exp_mult * mults.charisma_exp_mult,
|
||||||
|
1,
|
||||||
|
Settings.theme.cha,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const rightColData: MultiplierListItemData[] = [
|
||||||
|
...[
|
||||||
|
[
|
||||||
|
"Hacknet Node production ",
|
||||||
|
Player.hacknet_node_money_mult,
|
||||||
|
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
||||||
|
BitNodeMultipliers.HacknetNodeMoney,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacknet Node purchase cost ",
|
||||||
|
Player.hacknet_node_purchase_cost_mult,
|
||||||
|
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacknet Node RAM upgrade cost ",
|
||||||
|
Player.hacknet_node_ram_cost_mult,
|
||||||
|
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacknet Node Core purchase cost ",
|
||||||
|
Player.hacknet_node_core_cost_mult,
|
||||||
|
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacknet Node level upgrade cost ",
|
||||||
|
Player.hacknet_node_level_cost_mult,
|
||||||
|
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
|
||||||
|
[
|
||||||
|
"Faction reputation gain ",
|
||||||
|
Player.faction_rep_mult,
|
||||||
|
Player.faction_rep_mult * mults.faction_rep_mult,
|
||||||
|
BitNodeMultipliers.FactionWorkRepGain,
|
||||||
|
],
|
||||||
|
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||||
|
[
|
||||||
|
"Salary ",
|
||||||
|
Player.work_money_mult,
|
||||||
|
Player.work_money_mult * mults.work_money_mult,
|
||||||
|
BitNodeMultipliers.CompanyWorkMoney,
|
||||||
|
Settings.theme.money,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Crime success ",
|
||||||
|
Player.crime_success_mult,
|
||||||
|
Player.crime_success_mult * mults.crime_success_mult,
|
||||||
|
1,
|
||||||
|
Settings.theme.combat,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Crime money ",
|
||||||
|
Player.crime_money_mult,
|
||||||
|
Player.crime_money_mult * mults.crime_money_mult,
|
||||||
|
BitNodeMultipliers.CrimeMoney,
|
||||||
|
Settings.theme.money,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (Player.canAccessBladeburner()) {
|
||||||
|
rightColData.push(
|
||||||
|
...[
|
||||||
|
[
|
||||||
|
"Bladeburner Success Chance",
|
||||||
|
Player.bladeburner_success_chance_mult,
|
||||||
|
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Bladeburner Max Stamina",
|
||||||
|
Player.bladeburner_max_stamina_mult,
|
||||||
|
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Bladeburner Stamina Gain",
|
||||||
|
Player.bladeburner_stamina_gain_mult,
|
||||||
|
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Bladeburner Field Analysis",
|
||||||
|
Player.bladeburner_analysis_mult,
|
||||||
|
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasLeftImprovements = +!!(leftColData.filter((item) => item[2] !== 0).length > 0),
|
||||||
|
hasRightImprovements = +!!(rightColData.filter((item) => item[2] !== 0).length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Paper
|
||||||
<Typography variant="h4">Multipliers</Typography>
|
sx={{
|
||||||
<Box mx={2}>
|
p: 1,
|
||||||
<MultiplierTable
|
maxHeight: 400,
|
||||||
rows={[
|
overflowY: "scroll",
|
||||||
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
|
display: "grid",
|
||||||
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
|
gridTemplateColumns: `repeat(${hasLeftImprovements + hasRightImprovements}, 1fr)`,
|
||||||
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
|
}}
|
||||||
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
|
>
|
||||||
]}
|
<MultiplierList rows={leftColData} />
|
||||||
/>
|
<MultiplierList rows={rightColData} />
|
||||||
<br />
|
</Paper>
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Hacking Level ",
|
|
||||||
Player.hacking_mult,
|
|
||||||
Player.hacking_mult * mults.hacking_mult,
|
|
||||||
BitNodeMultipliers.HackingLevelMultiplier,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Hacking Experience ",
|
|
||||||
Player.hacking_exp_mult,
|
|
||||||
Player.hacking_exp_mult * mults.hacking_exp_mult,
|
|
||||||
BitNodeMultipliers.HackExpGain,
|
|
||||||
],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Strength Level ",
|
|
||||||
Player.strength_mult,
|
|
||||||
Player.strength_mult * mults.strength_mult,
|
|
||||||
BitNodeMultipliers.StrengthLevelMultiplier,
|
|
||||||
],
|
|
||||||
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Defense Level ",
|
|
||||||
Player.defense_mult,
|
|
||||||
Player.defense_mult * mults.defense_mult,
|
|
||||||
BitNodeMultipliers.DefenseLevelMultiplier,
|
|
||||||
],
|
|
||||||
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Dexterity Level ",
|
|
||||||
Player.dexterity_mult,
|
|
||||||
Player.dexterity_mult * mults.dexterity_mult,
|
|
||||||
BitNodeMultipliers.DexterityLevelMultiplier,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Dexterity Experience ",
|
|
||||||
Player.dexterity_exp_mult,
|
|
||||||
Player.dexterity_exp_mult * mults.dexterity_exp_mult,
|
|
||||||
1,
|
|
||||||
],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Agility Level ",
|
|
||||||
Player.agility_mult,
|
|
||||||
Player.agility_mult * mults.agility_mult,
|
|
||||||
BitNodeMultipliers.AgilityLevelMultiplier,
|
|
||||||
],
|
|
||||||
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Charisma Level ",
|
|
||||||
Player.charisma_mult,
|
|
||||||
Player.charisma_mult * mults.charisma_mult,
|
|
||||||
BitNodeMultipliers.CharismaLevelMultiplier,
|
|
||||||
],
|
|
||||||
["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult, 1],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
[
|
|
||||||
"Hacknet Node production ",
|
|
||||||
Player.hacknet_node_money_mult,
|
|
||||||
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
|
|
||||||
BitNodeMultipliers.HacknetNodeMoney,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Hacknet Node purchase cost ",
|
|
||||||
Player.hacknet_node_purchase_cost_mult,
|
|
||||||
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
|
|
||||||
1,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Hacknet Node RAM upgrade cost ",
|
|
||||||
Player.hacknet_node_ram_cost_mult,
|
|
||||||
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
|
|
||||||
1,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Hacknet Node Core purchase cost ",
|
|
||||||
Player.hacknet_node_core_cost_mult,
|
|
||||||
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
|
|
||||||
1,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Hacknet Node level upgrade cost ",
|
|
||||||
Player.hacknet_node_level_cost_mult,
|
|
||||||
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
|
|
||||||
1,
|
|
||||||
],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
|
|
||||||
[
|
|
||||||
"Faction reputation gain ",
|
|
||||||
Player.faction_rep_mult,
|
|
||||||
Player.faction_rep_mult * mults.faction_rep_mult,
|
|
||||||
BitNodeMultipliers.FactionWorkRepGain,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"Salary ",
|
|
||||||
Player.work_money_mult,
|
|
||||||
Player.work_money_mult * mults.work_money_mult,
|
|
||||||
BitNodeMultipliers.CompanyWorkMoney,
|
|
||||||
],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult, 1],
|
|
||||||
[
|
|
||||||
"Crime money ",
|
|
||||||
Player.crime_money_mult,
|
|
||||||
Player.crime_money_mult * mults.crime_money_mult,
|
|
||||||
BitNodeMultipliers.CrimeMoney,
|
|
||||||
],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<BladeburnerMults />
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,11 @@
|
|||||||
* React component for displaying all of the player's purchased (but not installed)
|
* React component for displaying all of the player's purchased (but not installed)
|
||||||
* Augmentations on the Augmentations UI.
|
* Augmentations on the Augmentations UI.
|
||||||
*/
|
*/
|
||||||
|
import { List, ListItemText, Paper, Tooltip, Typography } from "@mui/material";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { Player } from "../../Player";
|
||||||
import { Augmentations } from "../Augmentations";
|
import { Augmentations } from "../Augmentations";
|
||||||
import { AugmentationNames } from "../data/AugmentationNames";
|
import { AugmentationNames } from "../data/AugmentationNames";
|
||||||
import { Player } from "../../Player";
|
|
||||||
|
|
||||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
|
||||||
import List from "@mui/material/List";
|
|
||||||
|
|
||||||
export function PurchasedAugmentations(): React.ReactElement {
|
export function PurchasedAugmentations(): React.ReactElement {
|
||||||
const augs: React.ReactElement[] = [];
|
const augs: React.ReactElement[] = [];
|
||||||
@ -23,14 +20,48 @@ export function PurchasedAugmentations(): React.ReactElement {
|
|||||||
}
|
}
|
||||||
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
|
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
|
||||||
const ownedAug = Player.queuedAugmentations[i];
|
const ownedAug = Player.queuedAugmentations[i];
|
||||||
|
let displayName = ownedAug.name;
|
||||||
|
|
||||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
|
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
|
||||||
const aug = Augmentations[ownedAug.name];
|
const aug = Augmentations[ownedAug.name];
|
||||||
|
|
||||||
let level = null;
|
let level = null;
|
||||||
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||||
level = ownedAug.level;
|
level = ownedAug.level;
|
||||||
|
displayName += ` - Level ${level}`;
|
||||||
}
|
}
|
||||||
augs.push(<AugmentationAccordion key={aug.name} aug={aug} level={level} />);
|
|
||||||
|
augs.push(
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<Typography>
|
||||||
|
{(() => {
|
||||||
|
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||||
|
const tooltip = (
|
||||||
|
<>
|
||||||
|
{info}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{aug.stats}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
return tooltip;
|
||||||
|
})()}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
enterNextDelay={500}
|
||||||
|
key={displayName}
|
||||||
|
>
|
||||||
|
<ListItemText sx={{ px: 2, py: 1 }} primary={displayName} />
|
||||||
|
</Tooltip>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <List dense>{augs}</List>;
|
return (
|
||||||
|
<Paper sx={{ py: 1, maxHeight: 400, overflowY: "scroll" }}>
|
||||||
|
<List sx={{ height: 400, overflowY: "scroll" }} disablePadding>
|
||||||
|
{augs}
|
||||||
|
</List>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,159 @@
|
|||||||
import React from "react";
|
import { ListItemButton, ListItemText, Paper } from "@mui/material";
|
||||||
import { SourceFileMinus1 } from "./SourceFileMinus1";
|
|
||||||
import { OwnedSourceFiles } from "./OwnedSourceFiles";
|
|
||||||
import List from "@mui/material/List";
|
|
||||||
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
|
import List from "@mui/material/List";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Exploit, ExploitName } from "../../Exploits/Exploit";
|
||||||
|
import { Player } from "../../Player";
|
||||||
|
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { SourceFile } from "../../SourceFile/SourceFile";
|
||||||
|
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
||||||
|
|
||||||
|
interface SfMinus1 {
|
||||||
|
info: React.ReactElement;
|
||||||
|
n: number;
|
||||||
|
name: string;
|
||||||
|
lvl: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const safeGetSf = (sfNum: number): SourceFile | SfMinus1 | null => {
|
||||||
|
if (sfNum === -1) {
|
||||||
|
const sfMinus1: SfMinus1 = {
|
||||||
|
info: (
|
||||||
|
<>
|
||||||
|
This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web ecosystem.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
It increases all of the player's multipliers by 0.1%
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
You have found the following exploits:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{Player.exploits.map((c: Exploit) => (
|
||||||
|
<React.Fragment key={c}>
|
||||||
|
* {ExploitName(c)}
|
||||||
|
<br />
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
lvl: Player.exploits.length,
|
||||||
|
n: -1,
|
||||||
|
name: "Source-File -1: Exploits in the BitNodes",
|
||||||
|
};
|
||||||
|
return sfMinus1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const srcFileKey = "SourceFile" + sfNum;
|
||||||
|
const sfObj = SourceFiles[srcFileKey];
|
||||||
|
if (sfObj == null) {
|
||||||
|
console.error(`Invalid source file number: ${sfNum}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sfObj;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMaxLevel = (sfObj: SourceFile | SfMinus1): string | number => {
|
||||||
|
let maxLevel;
|
||||||
|
switch (sfObj.n) {
|
||||||
|
case 12:
|
||||||
|
maxLevel = "∞";
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
maxLevel = Object.keys(Exploit).length;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
maxLevel = "3";
|
||||||
|
}
|
||||||
|
return maxLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SourceFilesElement(): React.ReactElement {
|
||||||
|
const sourceSfs = Player.sourceFiles.slice();
|
||||||
|
const exploits = Player.exploits;
|
||||||
|
// Create a fake SF for -1, if "owned"
|
||||||
|
if (exploits.length > 0) {
|
||||||
|
sourceSfs.unshift({
|
||||||
|
n: -1,
|
||||||
|
lvl: exploits.length,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
|
||||||
|
sourceSfs.sort((sf1, sf2) => {
|
||||||
|
return sf1.n - sf2.n;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceSfs.length === 0) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [selectedSf, setSelectedSf] = useState(sourceSfs[0]);
|
||||||
|
|
||||||
export function SourceFiles(): React.ReactElement {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box sx={{ width: "100%", mt: 1 }}>
|
||||||
<Typography variant="h4">Source Files</Typography>
|
<Paper sx={{ p: 1 }}>
|
||||||
<Box mx={2}>
|
<Typography variant="h5">Source Files</Typography>
|
||||||
<List dense>
|
</Paper>
|
||||||
<SourceFileMinus1 />
|
<Paper sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||||
<OwnedSourceFiles />
|
<Box>
|
||||||
</List>
|
<List
|
||||||
</Box>
|
sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}
|
||||||
</>
|
disablePadding
|
||||||
|
>
|
||||||
|
{sourceSfs.map((e, i) => {
|
||||||
|
const sfObj = safeGetSf(e.n);
|
||||||
|
if (!sfObj) return;
|
||||||
|
|
||||||
|
const maxLevel = getMaxLevel(sfObj);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItemButton
|
||||||
|
key={i + 1}
|
||||||
|
onClick={() => setSelectedSf(e)}
|
||||||
|
selected={selectedSf.n === e.n}
|
||||||
|
sx={{ py: 0 }}
|
||||||
|
>
|
||||||
|
<ListItemText
|
||||||
|
disableTypography
|
||||||
|
primary={<Typography>{sfObj.name}</Typography>}
|
||||||
|
secondary={
|
||||||
|
<Typography>
|
||||||
|
Level {e.lvl} / {maxLevel}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ m: 1 }}>
|
||||||
|
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||||
|
{safeGetSf(selectedSf.n)?.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
|
||||||
|
{(() => {
|
||||||
|
const sfObj = safeGetSf(selectedSf.n);
|
||||||
|
if (!sfObj) return;
|
||||||
|
|
||||||
|
const maxLevel = getMaxLevel(sfObj);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
Level {selectedSf.lvl} / {maxLevel}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
{sfObj.info}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
|
import { Clear, ExpandMore, Reply, ReplyAll } from "@mui/icons-material";
|
||||||
|
import {
|
||||||
|
Accordion,
|
||||||
|
AccordionDetails,
|
||||||
|
AccordionSummary,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
SelectChangeEvent,
|
||||||
|
Typography,
|
||||||
|
} from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
|
||||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
||||||
|
|
||||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
|
||||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import Typography from "@mui/material/Typography";
|
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
|
||||||
import IconButton from "@mui/material/IconButton";
|
|
||||||
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
|
||||||
import ReplyIcon from "@mui/icons-material/Reply";
|
|
||||||
import ClearIcon from "@mui/icons-material/Clear";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
player: IPlayer;
|
player: IPlayer;
|
||||||
@ -39,50 +38,46 @@ export function Augmentations(props: IProps): React.ReactElement {
|
|||||||
props.player.augmentations = [];
|
props.player.augmentations = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearQueuedAugs(): void {
|
||||||
|
props.player.queuedAugmentations = [];
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
<AccordionSummary expandIcon={<ExpandMore />}>
|
||||||
<Typography>Augmentations</Typography>
|
<Typography>Augmentations</Typography>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<table>
|
<Select
|
||||||
<tbody>
|
onChange={setAugmentationDropdown}
|
||||||
<tr>
|
value={augmentation}
|
||||||
<td>
|
startAdornment={
|
||||||
<Typography>Aug:</Typography>
|
<>
|
||||||
</td>
|
<IconButton onClick={queueAllAugs} size="large">
|
||||||
<td>
|
<ReplyAll />
|
||||||
<Select
|
</IconButton>
|
||||||
onChange={setAugmentationDropdown}
|
<IconButton onClick={queueAug} size="large">
|
||||||
value={augmentation}
|
<Reply />
|
||||||
startAdornment={
|
</IconButton>
|
||||||
<>
|
</>
|
||||||
<IconButton onClick={queueAllAugs} size="large">
|
}
|
||||||
<ReplyAllIcon />
|
endAdornment={
|
||||||
</IconButton>
|
<>
|
||||||
<IconButton onClick={queueAug} size="large">
|
<IconButton onClick={clearAugs} size="large">
|
||||||
<ReplyIcon />
|
<Clear />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
endAdornment={
|
>
|
||||||
<>
|
{Object.values(AugmentationNames).map((aug) => (
|
||||||
<IconButton onClick={clearAugs} size="large">
|
<MenuItem key={aug} value={aug}>
|
||||||
<ClearIcon />
|
{aug}
|
||||||
</IconButton>
|
</MenuItem>
|
||||||
</>
|
))}
|
||||||
}
|
</Select>
|
||||||
>
|
<Button sx={{ display: "block" }} onClick={clearQueuedAugs}>
|
||||||
{Object.values(AugmentationNames).map((aug) => (
|
Clear Queued Augmentations
|
||||||
<MenuItem key={aug} value={aug}>
|
</Button>
|
||||||
{aug}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
);
|
);
|
||||||
|
@ -94,7 +94,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
<Typography variant="h5">Graft Augmentations</Typography>
|
<Typography variant="h5">Graft Augmentations</Typography>
|
||||||
{getAvailableAugs(player).length > 0 ? (
|
{getAvailableAugs(player).length > 0 ? (
|
||||||
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
|
||||||
<List sx={{ maxHeight: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
|
||||||
{getAvailableAugs(player).map((k, i) => (
|
{getAvailableAugs(player).map((k, i) => (
|
||||||
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
|
||||||
<Typography>{k}</Typography>
|
<Typography>{k}</Typography>
|
||||||
|
@ -1,144 +1,80 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { Paper, Table, TableBody, Box, IconButton, Typography, Container, Tooltip } from "@mui/material";
|
||||||
|
import { MoreHoriz, Info } from "@mui/icons-material";
|
||||||
import { numeralWrapper } from "./numeralFormat";
|
import React, { useEffect, useState } from "react";
|
||||||
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
|
||||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
|
||||||
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
|
||||||
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
|
|
||||||
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
|
||||||
import { StatsTable } from "./React/StatsTable";
|
|
||||||
import { Money } from "./React/Money";
|
|
||||||
import { use } from "./Context";
|
|
||||||
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
|
|
||||||
import { BitNodes } from "../BitNode/BitNode";
|
import { BitNodes } from "../BitNode/BitNode";
|
||||||
|
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||||
import Typography from "@mui/material/Typography";
|
import { HacknetServerConstants } from "../Hacknet/data/Constants";
|
||||||
import Box from "@mui/material/Box";
|
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import { Settings } from "../Settings/Settings";
|
||||||
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||||
|
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
|
||||||
|
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||||
|
import { use } from "./Context";
|
||||||
|
import { numeralWrapper } from "./numeralFormat";
|
||||||
import { Modal } from "./React/Modal";
|
import { Modal } from "./React/Modal";
|
||||||
|
import { Money } from "./React/Money";
|
||||||
|
import { StatsRow } from "./React/StatsRow";
|
||||||
|
import { StatsTable } from "./React/StatsTable";
|
||||||
|
|
||||||
import TableBody from "@mui/material/TableBody";
|
interface EmployersModalProps {
|
||||||
import { Table, TableCell } from "./React/Table";
|
open: boolean;
|
||||||
import TableRow from "@mui/material/TableRow";
|
onClose: () => void;
|
||||||
|
|
||||||
function LastEmployer(): React.ReactElement {
|
|
||||||
const player = use.Player();
|
|
||||||
if (player.companyName) {
|
|
||||||
return <Typography>Employer at which you last worked: {player.companyName}</Typography>;
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function LastJob(): React.ReactElement {
|
const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElement => {
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
if (player.companyName !== "") {
|
return (
|
||||||
return <Typography>Job you last worked: {player.jobs[player.companyName]}</Typography>;
|
<Modal open={open} onClose={onClose}>
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Employers(): React.ReactElement {
|
|
||||||
const player = use.Player();
|
|
||||||
if (player.jobs && Object.keys(player.jobs).length !== 0)
|
|
||||||
return (
|
|
||||||
<>
|
<>
|
||||||
<Typography>All Employers:</Typography>
|
<Typography variant="h5">All Employers</Typography>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{Object.keys(player.jobs).map((j) => (
|
{Object.keys(player.jobs).map((j) => (
|
||||||
<Typography key={j}> * {j}</Typography>
|
<Typography key={j}>* {j}</Typography>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
);
|
</Modal>
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Hacknet(): React.ReactElement {
|
|
||||||
const player = use.Player();
|
|
||||||
// Can't import HacknetHelpers for some reason.
|
|
||||||
if (!(player.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Typography>{`Hacknet Nodes owned: ${player.hacknetNodes.length}`}</Typography>
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Typography>{`Hacknet Servers owned: ${player.hacknetNodes.length} / ${HacknetServerConstants.MaxServers}`}</Typography>
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Intelligence(): React.ReactElement {
|
|
||||||
const player = use.Player();
|
|
||||||
if (player.intelligence > 0 && (player.bitNodeN === 5 || SourceFileFlags[5] > 0)) {
|
|
||||||
return (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>
|
|
||||||
<Typography>Intelligence: </Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="right">
|
|
||||||
<Typography>{numeralWrapper.formatSkill(player.intelligence)} </Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell align="right">
|
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.intelligence_exp)} exp)</Typography>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function MultiplierTable(props: any): React.ReactElement {
|
|
||||||
function bn5Stat(r: any): JSX.Element {
|
|
||||||
if (SourceFileFlags[5] > 0 && r.length > 2 && r[1] != r[2]) {
|
|
||||||
return (
|
|
||||||
<TableCell key="2" align="right">
|
|
||||||
<Typography noWrap>({numeralWrapper.formatPercentage(r[2])})</Typography>
|
|
||||||
</TableCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Table size="small" padding="none">
|
|
||||||
<TableBody>
|
|
||||||
{props.rows.map((r: any) => (
|
|
||||||
<TableRow key={r[0]}>
|
|
||||||
<TableCell key="0">
|
|
||||||
<Typography noWrap>{`${r[0]} multiplier:`} </Typography>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell key="1" align="right">
|
|
||||||
<Typography noWrap>{numeralWrapper.formatPercentage(r[1])}</Typography>
|
|
||||||
</TableCell>
|
|
||||||
{bn5Stat(r)}
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface MultTableProps {
|
||||||
|
rows: (string | number)[][];
|
||||||
|
color: string;
|
||||||
|
noMargin?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BladeburnerMults(): React.ReactElement {
|
function MultiplierTable(props: MultTableProps): React.ReactElement {
|
||||||
const player = use.Player();
|
|
||||||
if (!player.canAccessBladeburner()) return <></>;
|
|
||||||
return (
|
return (
|
||||||
<MultiplierTable
|
<Table sx={{ display: "table", width: "100%", mb: (props.noMargin ?? false) === true ? 0 : 2 }}>
|
||||||
rows={[
|
<TableBody>
|
||||||
["Bladeburner Success Chance", player.bladeburner_success_chance_mult],
|
{props.rows.map((data) => {
|
||||||
["Bladeburner Max Stamina", player.bladeburner_max_stamina_mult],
|
const mult = data[0] as string,
|
||||||
["Bladeburner Stamina Gain", player.bladeburner_stamina_gain_mult],
|
value = data[1] as number,
|
||||||
["Bladeburner Field Analysis", player.bladeburner_analysis_mult],
|
modded = data[2] as number | null;
|
||||||
]}
|
|
||||||
/>
|
if (modded && modded !== value && SourceFileFlags[5] > 0) {
|
||||||
|
return (
|
||||||
|
<StatsRow key={mult} name={mult} color={props.color} data={{}}>
|
||||||
|
<>
|
||||||
|
<Typography color={props.color}>
|
||||||
|
<span style={{ opacity: 0.5 }}>{numeralWrapper.formatPercentage(value)}</span>{" "}
|
||||||
|
{numeralWrapper.formatPercentage(modded)}
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
</StatsRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<StatsRow
|
||||||
|
key={mult}
|
||||||
|
name={mult}
|
||||||
|
color={props.color}
|
||||||
|
data={{ content: numeralWrapper.formatPercentage(value) }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,15 +82,17 @@ function CurrentBitNode(): React.ReactElement {
|
|||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
if (player.sourceFiles.length > 0) {
|
if (player.sourceFiles.length > 0) {
|
||||||
const index = "BitNode" + player.bitNodeN;
|
const index = "BitNode" + player.bitNodeN;
|
||||||
|
const currentSourceFile = player.sourceFiles.find((sourceFile) => sourceFile.n == player.bitNodeN);
|
||||||
|
const lvl = currentSourceFile ? currentSourceFile.lvl : 0;
|
||||||
return (
|
return (
|
||||||
<>
|
<Box>
|
||||||
<Typography variant="h4">
|
<Paper sx={{ p: 1 }}>
|
||||||
BitNode {player.bitNodeN}: {BitNodes[index].name}
|
<Typography variant="h5">
|
||||||
</Typography>
|
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
|
||||||
<Typography sx={{ mx: 2 }} style={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>
|
</Typography>
|
||||||
{BitNodes[index].info}
|
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
|
||||||
</Typography>
|
</Paper>
|
||||||
</>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,6 +200,7 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
|
|||||||
export function CharacterStats(): React.ReactElement {
|
export function CharacterStats(): React.ReactElement {
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
const [moneyOpen, setMoneyOpen] = useState(false);
|
const [moneyOpen, setMoneyOpen] = useState(false);
|
||||||
|
const [employersOpen, setEmployersOpen] = useState(false);
|
||||||
const setRerender = useState(false)[1];
|
const setRerender = useState(false)[1];
|
||||||
function rerender(): void {
|
function rerender(): void {
|
||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
@ -273,229 +212,307 @@ export function CharacterStats(): React.ReactElement {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const timeRows = [
|
const timeRows = [
|
||||||
["Time played since last Augmentation:", convertTimeMsToTimeElapsedString(player.playtimeSinceLastAug)],
|
["Since last Augmentation installation", convertTimeMsToTimeElapsedString(player.playtimeSinceLastAug)],
|
||||||
];
|
];
|
||||||
if (player.sourceFiles.length > 0) {
|
if (player.sourceFiles.length > 0) {
|
||||||
timeRows.push([
|
timeRows.push(["Since last Bitnode destroyed", convertTimeMsToTimeElapsedString(player.playtimeSinceLastBitnode)]);
|
||||||
"Time played since last Bitnode destroyed:",
|
|
||||||
convertTimeMsToTimeElapsedString(player.playtimeSinceLastBitnode),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
timeRows.push(["Total Time played:", convertTimeMsToTimeElapsedString(player.totalPlaytime)]);
|
timeRows.push(["Total", convertTimeMsToTimeElapsedString(player.totalPlaytime)]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container maxWidth="lg" disableGutters sx={{ mx: 0 }}>
|
||||||
<Typography variant="h4">General</Typography>
|
|
||||||
<Box sx={{ mx: 2 }}>
|
|
||||||
<Typography>Current City: {player.city}</Typography>
|
|
||||||
<LastEmployer />
|
|
||||||
<LastJob />
|
|
||||||
<Employers />
|
|
||||||
|
|
||||||
<Typography>
|
|
||||||
Money: <Money money={player.money} />
|
|
||||||
<IconButton onClick={() => setMoneyOpen(true)}>
|
|
||||||
<MoreHorizIcon color="info" />
|
|
||||||
</IconButton>
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<br />
|
|
||||||
<Typography variant="h4">Stats</Typography>
|
<Typography variant="h4">Stats</Typography>
|
||||||
<Box sx={{ mx: 2 }}>
|
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", minWidth: "fit-content", mb: 1, gap: 1 }}>
|
||||||
<Table size="small" padding="none">
|
<Paper sx={{ p: 1 }}>
|
||||||
<TableBody>
|
<Typography variant="h5">General</Typography>
|
||||||
<TableRow>
|
<Table>
|
||||||
<TableCell>
|
<TableBody>
|
||||||
<Typography noWrap>Hacking: </Typography>
|
<StatsRow name="Current City" color={Settings.theme.primary} data={{ content: player.city }} />
|
||||||
</TableCell>
|
<StatsRow name="Money" color={Settings.theme.money} data={{}}>
|
||||||
<TableCell align="right">
|
<>
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.hacking)} </Typography>
|
<Money money={player.money} />
|
||||||
</TableCell>
|
<IconButton onClick={() => setMoneyOpen(true)} sx={{ p: 0 }}>
|
||||||
<TableCell align="right">
|
<MoreHoriz color="info" />
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.hacking_exp)} exp)</Typography>
|
</IconButton>
|
||||||
</TableCell>
|
</>
|
||||||
</TableRow>
|
</StatsRow>
|
||||||
<TableRow>
|
{player.companyName ? (
|
||||||
<TableCell>
|
<>
|
||||||
<Typography noWrap>Strength: </Typography>
|
<StatsRow
|
||||||
</TableCell>
|
name="Last Employer"
|
||||||
<TableCell align="right">
|
color={Settings.theme.primary}
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.strength)} </Typography>
|
data={{ content: player.companyName }}
|
||||||
</TableCell>
|
/>
|
||||||
<TableCell align="right">
|
<StatsRow
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.strength_exp)} exp)</Typography>
|
name="Last Job"
|
||||||
</TableCell>
|
color={Settings.theme.primary}
|
||||||
</TableRow>
|
data={{ content: player.jobs[player.companyName] }}
|
||||||
<TableRow>
|
/>
|
||||||
<TableCell>
|
</>
|
||||||
<Typography noWrap>Defense: </Typography>
|
) : (
|
||||||
</TableCell>
|
<></>
|
||||||
<TableCell align="right">
|
)}
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.defense)} </Typography>
|
{player.jobs && Object.keys(player.jobs).length !== 0 ? (
|
||||||
</TableCell>
|
<StatsRow name="All Employers" color={Settings.theme.primary} data={{}}>
|
||||||
<TableCell align="right">
|
<>
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.defense_exp)} exp)</Typography>
|
<span style={{ color: Settings.theme.primary }}>{Object.keys(player.jobs).length} total</span>
|
||||||
</TableCell>
|
<IconButton onClick={() => setEmployersOpen(true)} sx={{ p: 0 }}>
|
||||||
</TableRow>
|
<MoreHoriz color="info" />
|
||||||
<TableRow>
|
</IconButton>
|
||||||
<TableCell>
|
</>
|
||||||
<Typography noWrap>Dexterity: </Typography>
|
</StatsRow>
|
||||||
</TableCell>
|
) : (
|
||||||
<TableCell align="right">
|
<></>
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.dexterity)} </Typography>
|
)}
|
||||||
</TableCell>
|
<StatsRow
|
||||||
<TableCell align="right">
|
name="Servers Owned"
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.dexterity_exp)} exp)</Typography>
|
color={Settings.theme.primary}
|
||||||
</TableCell>
|
data={{ content: `${player.purchasedServers.length} / ${getPurchaseServerLimit()}` }}
|
||||||
</TableRow>
|
/>
|
||||||
<TableRow>
|
<StatsRow
|
||||||
<TableCell>
|
name={`Hacknet ${player.bitNodeN === 9 || SourceFileFlags[9] > 0 ? "Servers" : "Nodes"} owned`}
|
||||||
<Typography noWrap>Agility: </Typography>
|
color={Settings.theme.primary}
|
||||||
</TableCell>
|
data={{
|
||||||
<TableCell align="right">
|
content: `${player.hacknetNodes.length}${
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.agility)} </Typography>
|
player.bitNodeN === 9 || SourceFileFlags[9] > 0 ? ` / ${HacknetServerConstants.MaxServers}` : ""
|
||||||
</TableCell>
|
}`,
|
||||||
<TableCell align="right">
|
}}
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.agility_exp)} exp)</Typography>
|
/>
|
||||||
</TableCell>
|
<StatsRow
|
||||||
</TableRow>
|
name="Augmentations Installed"
|
||||||
<TableRow>
|
color={Settings.theme.primary}
|
||||||
<TableCell>
|
data={{ content: String(player.augmentations.length) }}
|
||||||
<Typography noWrap>Charisma: </Typography>
|
/>
|
||||||
</TableCell>
|
</TableBody>
|
||||||
<TableCell align="right">
|
</Table>
|
||||||
<Typography noWrap>{numeralWrapper.formatSkill(player.charisma)} </Typography>
|
</Paper>
|
||||||
</TableCell>
|
<Paper sx={{ p: 1 }}>
|
||||||
<TableCell align="right">
|
<Typography variant="h5">Skills</Typography>
|
||||||
<Typography noWrap>({numeralWrapper.formatExp(player.charisma_exp)} exp)</Typography>
|
<Table>
|
||||||
</TableCell>
|
<TableBody>
|
||||||
</TableRow>
|
<StatsRow
|
||||||
<Intelligence />
|
name="Hacking"
|
||||||
</TableBody>
|
color={Settings.theme.hack}
|
||||||
</Table>
|
data={{ level: player.hacking, exp: player.hacking_exp }}
|
||||||
<br />
|
/>
|
||||||
|
<StatsRow
|
||||||
|
name="Strength"
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
data={{ level: player.strength, exp: player.strength_exp }}
|
||||||
|
/>
|
||||||
|
<StatsRow
|
||||||
|
name="Defense"
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
data={{ level: player.defense, exp: player.defense_exp }}
|
||||||
|
/>
|
||||||
|
<StatsRow
|
||||||
|
name="Dexterity"
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
data={{ level: player.dexterity, exp: player.dexterity_exp }}
|
||||||
|
/>
|
||||||
|
<StatsRow
|
||||||
|
name="Agility"
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
data={{ level: player.agility, exp: player.agility_exp }}
|
||||||
|
/>
|
||||||
|
<StatsRow
|
||||||
|
name="Charisma"
|
||||||
|
color={Settings.theme.cha}
|
||||||
|
data={{ level: player.charisma, exp: player.charisma_exp }}
|
||||||
|
/>
|
||||||
|
{player.intelligence > 0 && (player.bitNodeN === 5 || SourceFileFlags[5] > 0) && (
|
||||||
|
<StatsRow
|
||||||
|
name="Intelligence"
|
||||||
|
color={Settings.theme.int}
|
||||||
|
data={{ level: player.intelligence, exp: player.intelligence_exp }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
<br />
|
<Box sx={{ mb: 1 }}>
|
||||||
<Typography variant="h4">Multipliers</Typography>
|
<Paper sx={{ p: 1 }}>
|
||||||
<Box sx={{ mx: 2 }}>
|
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
|
||||||
<MultiplierTable
|
Multipliers
|
||||||
rows={[
|
{SourceFileFlags[5] > 0 && (
|
||||||
["Hacking Chance", player.hacking_chance_mult],
|
<Tooltip
|
||||||
["Hacking Speed", player.hacking_speed_mult],
|
title={
|
||||||
[
|
<Typography>
|
||||||
"Hacking Money",
|
Displays your current multipliers.
|
||||||
player.hacking_money_mult,
|
<br />
|
||||||
player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
<br />
|
||||||
],
|
When there is a dim number next to a multiplier, that means that the multiplier in question is being
|
||||||
[
|
affected by BitNode multipliers.
|
||||||
"Hacking Growth",
|
<br />
|
||||||
player.hacking_grow_mult,
|
<br />
|
||||||
player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as
|
||||||
],
|
dictated by the BitNode.
|
||||||
]}
|
</Typography>
|
||||||
/>
|
}
|
||||||
<br />
|
>
|
||||||
<MultiplierTable
|
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
|
||||||
rows={[
|
</Tooltip>
|
||||||
["Hacking Level", player.hacking_mult, player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier],
|
)}
|
||||||
["Hacking Experience", player.hacking_exp_mult, player.hacking_exp_mult * BitNodeMultipliers.HackExpGain],
|
</Typography>
|
||||||
]}
|
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
|
||||||
/>
|
<Box>
|
||||||
<br />
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
["Hacking Chance", player.hacking_chance_mult],
|
||||||
|
["Hacking Speed", player.hacking_speed_mult],
|
||||||
|
[
|
||||||
|
"Hacking Money",
|
||||||
|
player.hacking_money_mult,
|
||||||
|
player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacking Growth",
|
||||||
|
player.hacking_grow_mult,
|
||||||
|
player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
|
||||||
|
],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.hack}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Hacking Level",
|
||||||
|
player.hacking_mult,
|
||||||
|
player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Hacking Experience",
|
||||||
|
player.hacking_exp_mult,
|
||||||
|
player.hacking_exp_mult * BitNodeMultipliers.HackExpGain,
|
||||||
|
],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.hack}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Strength Level",
|
||||||
|
player.strength_mult,
|
||||||
|
player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Strength Experience", player.strength_exp_mult],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Defense Level",
|
||||||
|
player.defense_mult,
|
||||||
|
player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Defense Experience", player.defense_exp_mult],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Dexterity Level",
|
||||||
|
player.dexterity_mult,
|
||||||
|
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Dexterity Experience", player.dexterity_exp_mult],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Agility Level",
|
||||||
|
player.agility_mult,
|
||||||
|
player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Agility Experience", player.agility_exp_mult],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.combat}
|
||||||
|
/>
|
||||||
|
<MultiplierTable
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
"Charisma Level",
|
||||||
|
player.charisma_mult,
|
||||||
|
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
|
||||||
|
],
|
||||||
|
["Charisma Experience", player.charisma_exp_mult],
|
||||||
|
]}
|
||||||
|
color={Settings.theme.cha}
|
||||||
|
noMargin
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<MultiplierTable
|
<Box>
|
||||||
rows={[
|
<MultiplierTable
|
||||||
["Strength Level", player.strength_mult, player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier],
|
rows={[
|
||||||
["Strength Experience", player.strength_exp_mult],
|
[
|
||||||
]}
|
"Hacknet Node production",
|
||||||
/>
|
player.hacknet_node_money_mult,
|
||||||
<br />
|
player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
||||||
|
],
|
||||||
<MultiplierTable
|
["Hacknet Node purchase cost", player.hacknet_node_purchase_cost_mult],
|
||||||
rows={[
|
["Hacknet Node RAM upgrade cost", player.hacknet_node_ram_cost_mult],
|
||||||
["Defense Level", player.defense_mult, player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier],
|
["Hacknet Node Core purchase cost", player.hacknet_node_core_cost_mult],
|
||||||
["Defense Experience", player.defense_exp_mult],
|
["Hacknet Node level upgrade cost", player.hacknet_node_level_cost_mult],
|
||||||
]}
|
]}
|
||||||
/>
|
color={Settings.theme.primary}
|
||||||
<br />
|
/>
|
||||||
|
<MultiplierTable
|
||||||
<MultiplierTable
|
rows={[
|
||||||
rows={[
|
["Company reputation gain", player.company_rep_mult],
|
||||||
[
|
[
|
||||||
"Dexterity Level",
|
"Faction reputation gain",
|
||||||
player.dexterity_mult,
|
player.faction_rep_mult,
|
||||||
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
|
player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
||||||
],
|
],
|
||||||
["Dexterity Experience", player.dexterity_exp_mult],
|
["Salary", player.work_money_mult, player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney],
|
||||||
]}
|
]}
|
||||||
/>
|
color={Settings.theme.money}
|
||||||
<br />
|
/>
|
||||||
|
<MultiplierTable
|
||||||
<MultiplierTable
|
rows={[
|
||||||
rows={[
|
["Crime success", player.crime_success_mult],
|
||||||
["Agility Level", player.agility_mult, player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier],
|
["Crime money", player.crime_money_mult, player.crime_money_mult * BitNodeMultipliers.CrimeMoney],
|
||||||
["Agility Experience", player.agility_exp_mult],
|
]}
|
||||||
]}
|
color={Settings.theme.combat}
|
||||||
/>
|
/>
|
||||||
<br />
|
{player.canAccessBladeburner() && (
|
||||||
|
<MultiplierTable
|
||||||
<MultiplierTable
|
rows={[
|
||||||
rows={[
|
["Bladeburner Success Chance", player.bladeburner_success_chance_mult],
|
||||||
["Charisma Level", player.charisma_mult, player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier],
|
["Bladeburner Max Stamina", player.bladeburner_max_stamina_mult],
|
||||||
["Charisma Experience", player.charisma_exp_mult],
|
["Bladeburner Stamina Gain", player.bladeburner_stamina_gain_mult],
|
||||||
]}
|
["Bladeburner Field Analysis", player.bladeburner_analysis_mult],
|
||||||
/>
|
]}
|
||||||
<br />
|
color={Settings.theme.primary}
|
||||||
|
noMargin
|
||||||
<MultiplierTable
|
/>
|
||||||
rows={[
|
)}
|
||||||
[
|
</Box>
|
||||||
"Hacknet Node production",
|
</Box>
|
||||||
player.hacknet_node_money_mult,
|
</Paper>
|
||||||
player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
|
|
||||||
],
|
|
||||||
["Hacknet Node purchase cost", player.hacknet_node_purchase_cost_mult],
|
|
||||||
["Hacknet Node RAM upgrade cost", player.hacknet_node_ram_cost_mult],
|
|
||||||
["Hacknet Node Core purchase cost", player.hacknet_node_core_cost_mult],
|
|
||||||
["Hacknet Node level upgrade cost", player.hacknet_node_level_cost_mult],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
["Company reputation gain", player.company_rep_mult],
|
|
||||||
[
|
|
||||||
"Faction reputation gain",
|
|
||||||
player.faction_rep_mult,
|
|
||||||
player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
|
|
||||||
],
|
|
||||||
["Salary", player.work_money_mult, player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<MultiplierTable
|
|
||||||
rows={[
|
|
||||||
["Crime success", player.crime_success_mult],
|
|
||||||
["Crime money", player.crime_money_mult, player.crime_money_mult * BitNodeMultipliers.CrimeMoney],
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<BladeburnerMults />
|
|
||||||
</Box>
|
</Box>
|
||||||
<br />
|
|
||||||
|
|
||||||
<Typography variant="h4">Misc</Typography>
|
<Box sx={{ mb: 1 }}>
|
||||||
<Box sx={{ mx: 2 }}>
|
<Paper sx={{ p: 1 }}>
|
||||||
<Typography>{`Servers owned: ${player.purchasedServers.length} / ${getPurchaseServerLimit()}`}</Typography>
|
<Typography variant="h5">Time Played</Typography>
|
||||||
<Hacknet />
|
<Table>
|
||||||
<Typography>{`Augmentations installed: ${player.augmentations.length}`}</Typography>
|
<TableBody>
|
||||||
<StatsTable rows={timeRows} />
|
{timeRows.map(([name, content]) => (
|
||||||
|
<StatsRow key={name} name={name} color={Settings.theme.primary} data={{ content: content }} />
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
<br />
|
|
||||||
<CurrentBitNode />
|
<CurrentBitNode />
|
||||||
<MoneyModal open={moneyOpen} onClose={() => setMoneyOpen(false)} />
|
<MoneyModal open={moneyOpen} onClose={() => setMoneyOpen(false)} />
|
||||||
</>
|
<EmployersModal open={employersOpen} onClose={() => setEmployersOpen(false)} />
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,10 @@ interface IProps {
|
|||||||
color: string;
|
color: string;
|
||||||
classes?: any;
|
classes?: any;
|
||||||
data: ITableRowData;
|
data: ITableRowData;
|
||||||
|
children?: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StatsRow = ({ name, color, classes = useStyles(), data }: IProps): React.ReactElement => {
|
export const StatsRow = ({ name, color, classes = useStyles(), children, data }: IProps): React.ReactElement => {
|
||||||
let content;
|
let content;
|
||||||
|
|
||||||
if (data.content !== undefined) {
|
if (data.content !== undefined) {
|
||||||
@ -36,7 +37,8 @@ export const StatsRow = ({ name, color, classes = useStyles(), data }: IProps):
|
|||||||
<Typography style={{ color: color }}>{name}</Typography>
|
<Typography style={{ color: color }}>{name}</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align="right" classes={{ root: classes.cellNone }}>
|
<TableCell align="right" classes={{ root: classes.cellNone }}>
|
||||||
<Typography style={{ color: color }}>{content}</Typography>
|
{content ? <Typography style={{ color: color }}>{content}</Typography> : <></>}
|
||||||
|
{children}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user