diff --git a/src/Augmentation/ui/AugmentationsRoot.tsx b/src/Augmentation/ui/AugmentationsRoot.tsx index 9f7ad401d..f3a64e6e3 100644 --- a/src/Augmentation/ui/AugmentationsRoot.tsx +++ b/src/Augmentation/ui/AugmentationsRoot.tsx @@ -7,7 +7,7 @@ import React, { useState, useEffect } from "react"; import { InstalledAugmentations } from "./InstalledAugmentations"; import { PlayerMultipliers } from "./PlayerMultipliers"; import { PurchasedAugmentations } from "./PurchasedAugmentations"; -import { SourceFiles } from "./SourceFiles"; +import { SourceFilesElement } from "./SourceFiles"; import { canGetBonus } from "../../ExportBonus"; import { use } from "../../ui/Context"; @@ -16,8 +16,53 @@ import Typography from "@mui/material/Typography"; import Button from "@mui/material/Button"; import Tooltip from "@mui/material/Tooltip"; import Box from "@mui/material/Box"; +import Paper from "@mui/material/Paper"; +import Container from "@mui/material/Container"; import { Settings } from "../../Settings/Settings"; 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 ? ( + + NeuroFlux Governor - Level {level} + {Augmentations[AugmentationNames.NeuroFluxGovernor].stats} + + ) : ( + <> + ); +}; + +interface EntropyDisplayProps { + player: IPlayer; +} + +const EntropyDisplay = ({ player }: EntropyDisplayProps): React.ReactElement => { + return player.entropy > 0 ? ( + + + Entropy Virus - Level {player.entropy} + + + All multipliers decreased by: {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% + (multiplicative) + + + ) : ( + <> + ); +}; interface IProps { exportGameFn: () => void; @@ -55,81 +100,112 @@ export function AugmentationsRoot(props: IProps): React.ReactElement { } return ( - <> + Augmentations - - - Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to - install them. - - WARNING: Installing your Augmentations resets most of your progress, including: -
- - Stats/Skill levels and Experience - - Money - - Scripts on every computer but your home computer - - Purchased servers - - Hacknet Nodes - - Faction/Company reputation - - Stocks -
- - 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) - + + + + Purchased Augmentations + + + Below is a list of all Augmentations you have purchased but not yet installed. Click the button + below to install them. + + + WARNING: Installing your Augmentations resets most of your progress, including: + +
+ - Stats/Skill levels and Experience + - Money + - Scripts on every computer but your home computer + - Purchased servers + - Hacknet Nodes + - Faction/Company reputation + - Stocks +
+ + 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) + + + } + > + +
+
+ setInstallOpen(false)} + onConfirm={props.installAugmentationsFn} + confirmationText={ + <> + Installing will reset +
+
- money +
- skill / experience +
- every server except home +
- factions and reputation +
+
+ You will keep: +
+
- All scripts on home +
- home ram and cores +
+
+ It is recommended to install several Augmentations at once. Preferably everything from any faction of + your choosing. + + } + /> + + 'I never asked for this'}> + + + + + It's always a good idea to backup/export your save!}> + + + +
+ {player.queuedAugmentations.length > 0 ? ( + + + + + ) : ( + + No Augmentations have been purchased yet + + )}
- - Purchased Augmentations - - - 'I never asked for this'}> - - - - - setInstallOpen(false)} - onConfirm={props.installAugmentationsFn} - confirmationText={ - <> - Installing will reset -
-
- money -
- skill / experience -
- every server except home -
- factions and reputation -
-
- You will keep: -
-
- All scripts on home -
- home ram and cores -
-
- It is recommended to install several Augmentations at once. Preferably everything from any faction of your - choosing. - - } - /> - It's always a good idea to backup/export your save!}> - - - + + e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) + + +!!(player.entropy > 0) + }, 1fr)`, + }} + > + + - Installed Augmentations - - - List of all Augmentations that have been installed. You have gained the effects of these. - + + - - - + +
); } diff --git a/src/Augmentation/ui/InstalledAugmentations.tsx b/src/Augmentation/ui/InstalledAugmentations.tsx index eccfd94ec..6f208789f 100644 --- a/src/Augmentation/ui/InstalledAugmentations.tsx +++ b/src/Augmentation/ui/InstalledAugmentations.tsx @@ -5,29 +5,24 @@ * It also contains 'configuration' buttons that allow you to change how the * 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 { AugmentationAccordion } from "../../ui/React/AugmentationAccordion"; -import { Augmentations } from "../Augmentations"; -import { AugmentationNames } from "../data/AugmentationNames"; - +import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; import { Settings } from "../../Settings/Settings"; import { use } from "../../ui/Context"; -import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; -import Button from "@mui/material/Button"; -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"; +import { Augmentations } from "../Augmentations"; +import { AugmentationNames } from "../data/AugmentationNames"; export function InstalledAugmentations(): React.ReactElement { const setRerender = useState(true)[1]; const player = use.Player(); - const sourceAugs = player.augmentations.slice(); + const [selectedAug, setSelectedAug] = useState(sourceAugs[0]); + if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) { sourceAugs.sort((aug1, aug2) => { return aug1.name.localeCompare(aug2.name); @@ -49,59 +44,62 @@ export function InstalledAugmentations(): React.ReactElement { } return ( - <> - - - - - - - - {player.entropy > 0 && - (() => { - const [open, setOpen] = useState(false); + + + Installed Augmentations + + + + + + + + + + {sourceAugs.length > 0 ? ( + + + + {sourceAugs + .filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor) + .map((k, i) => ( + setSelectedAug(k)} selected={selectedAug === k}> + {k.name} + + ))} + + + + + {selectedAug.name} + + + {(() => { + const aug = Augmentations[selectedAug.name]; - return ( - - setOpen((old) => !old)}> - - Entropy Virus - Level {player.entropy} - - } - /> - {open ? ( - - ) : ( - - )} - - - - - All multipliers decreased by:{" "} - {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative) - - - - - ); - })()} - - {sourceAugs.map((e) => { - const aug = Augmentations[e.name]; - - let level = null; - if (e.name === AugmentationNames.NeuroFluxGovernor) { - level = e.level; - } - - return ; - })} - - + const info = typeof aug.info === "string" ? {aug.info} : aug.info; + const tooltip = ( + <> + {info} +
+
+ {aug.stats} + + ); + return tooltip; + })()} + + + + ) : ( + + No Augmentations have been installed yet + + )} + ); } diff --git a/src/Augmentation/ui/PlayerMultipliers.tsx b/src/Augmentation/ui/PlayerMultipliers.tsx index be2c1bf47..d866bb340 100644 --- a/src/Augmentation/ui/PlayerMultipliers.tsx +++ b/src/Augmentation/ui/PlayerMultipliers.tsx @@ -1,17 +1,14 @@ /** * React component for displaying the player's multipliers on the Augmentation UI page */ +import { Box, Typography, List, ListItemText, ListItem, Paper } from "@mui/material"; import * as React from "react"; - +import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { Player } from "../../Player"; import { numeralWrapper } from "../../ui/numeralFormat"; 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"; +import { DoubleArrow } from "@mui/icons-material"; +import { Settings } from "../../Settings/Settings"; function calculateAugmentedStats(): any { const augP: any = {}; @@ -25,53 +22,63 @@ function calculateAugmentedStats(): any { return augP; } -function Improvements({ r, m }: { r: number; m: number }): React.ReactElement { - if (r) { - return ( - <> - -  {"=>"}  - - - - {numeralWrapper.formatPercentage(r)} - - - - ); - } - return <>; -} - -interface IBN5StatsProps { +interface BitNodeModifiedStatsProps { base: number; mult: number; + color: string; } -function BN5Stat(props: IBN5StatsProps): React.ReactElement { - if (props.mult === 1) return <>; - return <>({numeralWrapper.formatPercentage(props.base * props.mult)}); -} +function BitNodeModifiedStats(props: BitNodeModifiedStatsProps): React.ReactElement { + if (props.mult === 1) + return {numeralWrapper.formatPercentage(props.base)}; -function MultiplierTable({ rows }: { rows: [string, number, number, number][] }): React.ReactElement { return ( - - - {rows.map((r: any) => ( - - - {r[0]} multiplier:  - - - - {numeralWrapper.formatPercentage(r[1])} - - - - - ))} - -
+ + {numeralWrapper.formatPercentage(props.base)}{" "} + {numeralWrapper.formatPercentage(props.base * props.mult)} + + ); +} + +interface MultListProps { + rows: (string | number)[][]; + color: string; +} + +function MultiplierList(props: MultListProps): React.ReactElement { + return ( + + {props.rows.map((data) => { + const mult = data[0] as string, + value = data[1] as number, + improved = data[2] as number | null, + bnMult = data[3] as number; + + if (improved) { + return ( + + + {mult} + + } + secondary={ + + + + + + } + disableTypography + /> + + ); + } + return <>; + })} + ); } @@ -82,7 +89,7 @@ export function PlayerMultipliers(): React.ReactElement { if (!Player.canAccessBladeburner()) return <>; return ( <> -
@@ -116,20 +124,21 @@ export function PlayerMultipliers(): React.ReactElement { } return ( - <> - Multipliers - - + Multipliers + +
-
-
-
-
-
-
-
-
-
- + ); } diff --git a/src/Augmentation/ui/PurchasedAugmentations.tsx b/src/Augmentation/ui/PurchasedAugmentations.tsx index a8aa13b55..6b0402b5e 100644 --- a/src/Augmentation/ui/PurchasedAugmentations.tsx +++ b/src/Augmentation/ui/PurchasedAugmentations.tsx @@ -9,7 +9,7 @@ import { AugmentationNames } from "../data/AugmentationNames"; import { Player } from "../../Player"; import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion"; -import List from "@mui/material/List"; +import { List, Paper } from "@mui/material"; export function PurchasedAugmentations(): React.ReactElement { const augs: React.ReactElement[] = []; @@ -32,5 +32,9 @@ export function PurchasedAugmentations(): React.ReactElement { augs.push(); } - return {augs}; + return ( + + {augs} + + ); } diff --git a/src/Augmentation/ui/SourceFiles.tsx b/src/Augmentation/ui/SourceFiles.tsx index 1293f2298..ec9da77dd 100644 --- a/src/Augmentation/ui/SourceFiles.tsx +++ b/src/Augmentation/ui/SourceFiles.tsx @@ -1,21 +1,161 @@ -import React from "react"; -import { SourceFileMinus1 } from "./SourceFileMinus1"; -import { OwnedSourceFiles } from "./OwnedSourceFiles"; -import List from "@mui/material/List"; - -import Typography from "@mui/material/Typography"; +import { ListItemButton, ListItemText, Paper } from "@mui/material"; 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; +} + +const safeGetSf = (sfNum: number): SourceFile | SfMinus1 | null => { + if (sfNum === -1) { + return { + info: ( + <> + This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web ecosystem. +
+
+ It increases all of the player's multipliers by 0.1% +
+
+ You have found the following exploits: +
+
+ {Player.exploits.map((c: Exploit) => ( + + * {ExploitName(c)} +
+
+ ))} + + ), + lvl: Player.exploits.length, + n: -1, + name: "Source-File -1: Exploits in the BitNodes", + }; + } + + const srcFileKey = "SourceFile" + sfNum; + const sfObj = SourceFiles[srcFileKey]; + if (sfObj == null) { + console.error(`Invalid source file number: ${sfNum}`); + return null; + } + return sfObj; +}; + +export function SourceFilesElement(): React.ReactElement { + const sourceSfs = Player.sourceFiles.slice(); + const exploits = Player.exploits; + + if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) { + sourceSfs.sort((sf1, sf2) => { + return sf1.n - sf2.n; + }); + } + + const [selectedSf, setSelectedSf] = useState(sourceSfs[0]); -export function SourceFiles(): React.ReactElement { return ( - <> - Source Files - - - - - - - + + + Source Files + + {sourceSfs.length > 0 ? ( + + + + {exploits.length > 0 && ( + setSelectedSf({ n: -1, lvl: exploits.length })} + selected={selectedSf.n === -1} + sx={{ py: 0 }} + > + Source-File -1: Exploits in the BitNodes} + secondary={ + + Level {exploits.length} / {Object.keys(Exploit).length} + + } + /> + + )} + + {sourceSfs.map((e, i) => { + const sfObj = safeGetSf(e.n); + const maxLevel = sfObj?.n === 12 ? "∞" : "3"; + + return ( + setSelectedSf(e)} + selected={selectedSf === e} + sx={{ py: 0 }} + > + {sfObj?.name}} + secondary={ + + Level {selectedSf.lvl} / {maxLevel} + + } + /> + + ); + })} + + + + + {safeGetSf(selectedSf.n)?.name} + + + {(() => { + const sfObj = safeGetSf(selectedSf.n); + + let maxLevel; + switch (sfObj?.n) { + case 12: + maxLevel = "∞"; + break; + case -1: + maxLevel = Object.keys(Exploit).length; + break; + default: + maxLevel = "3"; + } + + return ( + <> + Level {selectedSf.lvl} / {maxLevel} +
+
+ {sfObj?.info} + + ); + })()} +
+
+
+ ) : ( + <> + )} +
); }