From 5c6c472b64d02607ec135a4d3db001b19679b174 Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Sat, 25 Sep 2021 01:06:17 -0400 Subject: [PATCH] Augmentations in mui --- src/Augmentation/Augmentation.tsx | 9 +- src/Augmentation/AugmentationHelpers.tsx | 4 +- src/Augmentation/ui/AugmentationsRoot.tsx | 142 +++++----- .../ui/InstalledAugmentations.tsx | 76 +++-- .../InstalledAugmentationsAndSourceFiles.tsx | 115 -------- src/Augmentation/ui/ListConfiguration.tsx | 33 --- src/Augmentation/ui/OwnedSourceFiles.tsx | 28 +- src/Augmentation/ui/PlayerMultipliers.tsx | 265 ++++++++++-------- .../ui/PurchasedAugmentations.tsx | 9 +- src/Augmentation/ui/SourceFileMinus1.tsx | 68 +++-- src/Augmentation/ui/SourceFiles.tsx | 20 ++ .../Sleeve/ui/SleeveAugmentationsPopup.tsx | 4 +- src/Script/Script.ts | 9 +- src/ScriptEditor/ui/Root.tsx | 8 +- src/SourceFile/SourceFile.ts | 4 +- src/SourceFile/SourceFiles.ts | 104 ------- src/SourceFile/SourceFiles.tsx | 197 +++++++++++++ src/ui/React/AugmentationAccordion.tsx | 73 +++-- src/ui/React/SourceFileAccordion.tsx | 43 ++- 19 files changed, 637 insertions(+), 574 deletions(-) delete mode 100644 src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx delete mode 100644 src/Augmentation/ui/ListConfiguration.tsx create mode 100644 src/Augmentation/ui/SourceFiles.tsx delete mode 100644 src/SourceFile/SourceFiles.ts create mode 100644 src/SourceFile/SourceFiles.tsx diff --git a/src/Augmentation/Augmentation.tsx b/src/Augmentation/Augmentation.tsx index 3da10649b..466e17279 100644 --- a/src/Augmentation/Augmentation.tsx +++ b/src/Augmentation/Augmentation.tsx @@ -12,7 +12,7 @@ import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviv export interface IConstructorParams { info: string | JSX.Element; - stats?: JSX.Element; + stats?: JSX.Element | null; isSpecial?: boolean; moneyCost: number; name: string; @@ -369,7 +369,7 @@ export class Augmentation { info: string | JSX.Element; // Description of the stats, often autogenerated, sometimes manually written. - stats: JSX.Element; + stats: JSX.Element | null; // Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs) isSpecial = false; @@ -507,8 +507,9 @@ export class Augmentation { this.mults.bladeburner_success_chance_mult = params.bladeburner_success_chance_mult; } - if (params.stats) this.stats = params.stats; - else this.stats = generateStatsDescription(this.mults, params.programs, params.startingMoney); + if (params.stats === undefined) + this.stats = generateStatsDescription(this.mults, params.programs, params.startingMoney); + else this.stats = params.stats; } // Adds this Augmentation to the specified Factions diff --git a/src/Augmentation/AugmentationHelpers.tsx b/src/Augmentation/AugmentationHelpers.tsx index d4783fa6a..703b2806f 100644 --- a/src/Augmentation/AugmentationHelpers.tsx +++ b/src/Augmentation/AugmentationHelpers.tsx @@ -1555,7 +1555,7 @@ function initAugmentations() { repCost: 2.5e6, moneyCost: 0, info: "It's time to leave the cave.", - stats: <>, + stats: null, }); RedPill.addToFactions(["Daedalus"]); if (augmentationExists(AugmentationNames.TheRedPill)) { @@ -1595,7 +1595,7 @@ function initAugmentations() { "exactly the implant does, but they promise that it will greatly " + "enhance your abilities.", hacking_grow_mult: 3, - stats: <>, + stats: null, }); HiveMind.addToFactions(["ECorp"]); if (augmentationExists(AugmentationNames.HiveMind)) { diff --git a/src/Augmentation/ui/AugmentationsRoot.tsx b/src/Augmentation/ui/AugmentationsRoot.tsx index 7f47a3377..d8dca07db 100644 --- a/src/Augmentation/ui/AugmentationsRoot.tsx +++ b/src/Augmentation/ui/AugmentationsRoot.tsx @@ -2,92 +2,78 @@ * Root React component for the Augmentations UI page that display all of your * owned and purchased Augmentations and Source-Files. */ -import * as React from "react"; +import React, { useState } from "react"; -import { InstalledAugmentationsAndSourceFiles } from "./InstalledAugmentationsAndSourceFiles"; +import { InstalledAugmentations } from "./InstalledAugmentations"; import { PlayerMultipliers } from "./PlayerMultipliers"; import { PurchasedAugmentations } from "./PurchasedAugmentations"; +import { SourceFiles } from "./SourceFiles"; import { Player } from "../../Player"; import { StdButton } from "../../ui/React/StdButton"; import { canGetBonus } from "../../ExportBonus"; -type IProps = { +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import Tooltip from "@mui/material/Tooltip"; + +interface IProps { exportGameFn: () => void; installAugmentationsFn: () => void; -}; - -type IState = { - rerender: boolean; -}; - -export class AugmentationsRoot extends React.Component { - constructor(props: IProps) { - super(props); - this.state = { - rerender: false, - }; - this.export = this.export.bind(this); - } - - export(): void { - this.props.exportGameFn(); - this.setState({ - rerender: !this.state.rerender, - }); - } - - render(): React.ReactNode { - function exportBonusStr(): string { - if (canGetBonus()) return "(+1 favor to all factions)"; - return ""; - } - - return ( - <> -
-

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) -

- - - -

Installed Augmentations

-

- {`List of all Augmentations ${Player.sourceFiles.length > 0 ? "and Source Files " : ""} ` + - `that have been installed. You have gained the effects of these.`} -

- -

- -
- - ); - } +} + +export function AugmentationsRoot(props: IProps): React.ReactElement { + const setRerender = useState(false)[1]; + + function doExport(): void { + props.exportGameFn(); + setRerender((o) => !o); + } + + function exportBonusStr(): string { + if (canGetBonus()) return "(+1 favor to all factions)"; + return ""; + } + + 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) + + + + + + + + + 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 58be31f73..b4cced0b5 100644 --- a/src/Augmentation/ui/InstalledAugmentations.tsx +++ b/src/Augmentation/ui/InstalledAugmentations.tsx @@ -1,19 +1,31 @@ /** - * React Component for displaying a list of the player's installed Augmentations - * on the Augmentations UI + * React Component for displaying all of the player's installed Augmentations and + * Source-Files. + * + * It also contains 'configuration' buttons that allow you to change how the + * Augs/SF's are displayed */ -import * as React from "react"; +import React, { useState } from "react"; -import { Player } from "../../Player"; +import { OwnedSourceFiles } from "./OwnedSourceFiles"; +import { SourceFileMinus1 } from "./SourceFileMinus1"; +import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion"; import { Augmentations } from "../../Augmentation/Augmentations"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; -import { Settings } from "../../Settings/Settings"; -import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; -import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion"; +import { Settings } from "../../Settings/Settings"; +import { use } from "../../ui/Context"; +import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import Tooltip from "@mui/material/Tooltip"; +import List from "@mui/material/List"; export function InstalledAugmentations(): React.ReactElement { - const sourceAugs = Player.augmentations.slice(); + const setRerender = useState(true)[1]; + const player = use.Player(); + + const sourceAugs = player.augmentations.slice(); if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) { sourceAugs.sort((aug1, aug2) => { @@ -21,20 +33,42 @@ export function InstalledAugmentations(): React.ReactElement { }); } - const augs = sourceAugs.map((e) => { - const aug = Augmentations[e.name]; + function rerender(): void { + setRerender((old) => !old); + } - let level = null; - if (e.name === AugmentationNames.NeuroFluxGovernor) { - level = e.level; - } + function sortByAcquirementTime(): void { + Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime; + rerender(); + } - return ( -
  • - -
  • - ); - }); + function sortInOrder(): void { + Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically; + rerender(); + } - return <>{augs}; + return ( + <> + + + + + + + + {sourceAugs.map((e) => { + const aug = Augmentations[e.name]; + + let level = null; + if (e.name === AugmentationNames.NeuroFluxGovernor) { + level = e.level; + } + + return ; + })} + + + ); } diff --git a/src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx b/src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx deleted file mode 100644 index f275e71ba..000000000 --- a/src/Augmentation/ui/InstalledAugmentationsAndSourceFiles.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/** - * React Component for displaying all of the player's installed Augmentations and - * Source-Files. - * - * It also contains 'configuration' buttons that allow you to change how the - * Augs/SF's are displayed - */ -import * as React from "react"; - -import { InstalledAugmentations } from "./InstalledAugmentations"; -import { ListConfiguration } from "./ListConfiguration"; -import { OwnedSourceFiles } from "./OwnedSourceFiles"; -import { SourceFileMinus1 } from "./SourceFileMinus1"; - -import { Settings } from "../../Settings/Settings"; -import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; - -type IProps = { - // nothing special. -}; - -type IState = { - rerenderFlag: boolean; -}; - -export class InstalledAugmentationsAndSourceFiles extends React.Component { - listRef: React.RefObject; - - constructor(props: IProps) { - super(props); - - this.state = { - rerenderFlag: false, - }; - - this.collapseAllHeaders = this.collapseAllHeaders.bind(this); - this.expandAllHeaders = this.expandAllHeaders.bind(this); - this.sortByAcquirementTime = this.sortByAcquirementTime.bind(this); - this.sortInOrder = this.sortInOrder.bind(this); - - this.listRef = React.createRef(); - } - - collapseAllHeaders(): void { - const ul = this.listRef.current; - if (ul == null) { - return; - } - const tickers = ul.getElementsByClassName("accordion-header"); - for (let i = 0; i < tickers.length; ++i) { - const ticker = tickers[i]; - if (!(ticker instanceof HTMLButtonElement)) { - continue; - } - - if (ticker.classList.contains("active")) { - ticker.click(); - } - } - } - - expandAllHeaders(): void { - const ul = this.listRef.current; - if (ul == null) { - return; - } - const tickers = ul.getElementsByClassName("accordion-header"); - for (let i = 0; i < tickers.length; ++i) { - const ticker = tickers[i]; - if (!(ticker instanceof HTMLButtonElement)) { - continue; - } - - if (!ticker.classList.contains("active")) { - ticker.click(); - } - } - } - - rerender(): void { - this.setState((prevState) => { - return { - rerenderFlag: !prevState.rerenderFlag, - }; - }); - } - - sortByAcquirementTime(): void { - Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.AcquirementTime; - this.rerender(); - } - - sortInOrder(): void { - Settings.OwnedAugmentationsOrder = OwnedAugmentationsOrderSetting.Alphabetically; - this.rerender(); - } - - render(): React.ReactNode { - return ( - <> - -
      - - - -
    - - ); - } -} diff --git a/src/Augmentation/ui/ListConfiguration.tsx b/src/Augmentation/ui/ListConfiguration.tsx deleted file mode 100644 index 5deb770a3..000000000 --- a/src/Augmentation/ui/ListConfiguration.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * React Component for configuring the way installed augmentations and - * Source-Files are displayed in the Augmentations UI - */ -import * as React from "react"; - -import { StdButton } from "../../ui/React/StdButton"; - -type IProps = { - collapseAllButtonsFn: () => void; - expandAllButtonsFn: () => void; - sortByAcquirementTimeFn: () => void; - sortInOrderFn: () => void; -}; - -export function ListConfiguration(props: IProps): React.ReactElement { - return ( - <> - - - - - - ); -} diff --git a/src/Augmentation/ui/OwnedSourceFiles.tsx b/src/Augmentation/ui/OwnedSourceFiles.tsx index db777bdce..b2b652d91 100644 --- a/src/Augmentation/ui/OwnedSourceFiles.tsx +++ b/src/Augmentation/ui/OwnedSourceFiles.tsx @@ -20,20 +20,18 @@ export function OwnedSourceFiles(): React.ReactElement { }); } - const sfs = sourceSfs.map((e) => { - const srcFileKey = "SourceFile" + e.n; - const sfObj = SourceFiles[srcFileKey]; - if (sfObj == null) { - console.error(`Invalid source file number: ${e.n}`); - return null; - } + return ( + <> + {sourceSfs.map((e) => { + const srcFileKey = "SourceFile" + e.n; + const sfObj = SourceFiles[srcFileKey]; + if (sfObj == null) { + console.error(`Invalid source file number: ${e.n}`); + return null; + } - return ( -
  • - -
  • - ); - }); - - return <>{sfs}; + return ; + })} + + ); } diff --git a/src/Augmentation/ui/PlayerMultipliers.tsx b/src/Augmentation/ui/PlayerMultipliers.tsx index f5572710c..1590a76e8 100644 --- a/src/Augmentation/ui/PlayerMultipliers.tsx +++ b/src/Augmentation/ui/PlayerMultipliers.tsx @@ -6,6 +6,11 @@ import * as React from "react"; 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 { Table as MuiTable } from "@mui/material"; +import TableRow from "@mui/material/TableRow"; +import Typography from "@mui/material/Typography"; function calculateAugmentedStats(): any { const augP: any = {}; @@ -19,62 +24,74 @@ function calculateAugmentedStats(): any { return augP; } -export function PlayerMultipliers(): React.ReactElement { - const mults = calculateAugmentedStats(); - function MultiplierTable(rows: any[]): React.ReactElement { - function improvements(r: number): JSX.Element[] { - let elems: JSX.Element[] = []; - if (r) { - elems = [ {"=>"} , {numeralWrapper.formatPercentage(r)}]; - } - return elems; - } - +function Improvements({ r }: { r: number }): React.ReactElement { + if (r) { + console.log(r); return ( - - - {rows.map((r: any) => ( - - - - {improvements(r[2])} - - ))} - -
    - {r[0]} multiplier:  - - {numeralWrapper.formatPercentage(r[1])} -
    + <> + +  {"=>"}  + + + {numeralWrapper.formatPercentage(r)} + + ); } + return <>; +} + +function MultiplierTable({ rows }: { rows: [string, number, number][] }): React.ReactElement { + return ( + + + {rows.map((r: any) => ( + + + {r[0]} multiplier:  + + + {numeralWrapper.formatPercentage(r[1])} + + + + ))} + +
    + ); +} + +export function PlayerMultipliers(): React.ReactElement { + const mults = calculateAugmentedStats(); function BladeburnerMults(): React.ReactElement { if (!Player.canAccessBladeburner()) return <>; return ( <> - {MultiplierTable([ - [ - "Bladeburner Success Chance", - Player.bladeburner_success_chance_mult, - Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult, - ], - [ - "Bladeburner Max Stamina", - Player.bladeburner_max_stamina_mult, - Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult, - ], - [ - "Bladeburner Stamina Gain", - Player.bladeburner_stamina_gain_mult, - Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult, - ], - [ - "Bladeburner Field Analysis", - Player.bladeburner_analysis_mult, - Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult, - ], - ])} +
    ); @@ -88,90 +105,110 @@ export function PlayerMultipliers(): React.ReactElement {


    - {MultiplierTable([ - ["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult], - ["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult], - ["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult], - ["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult], - ])} +
    - {MultiplierTable([ - ["Hacking Level ", Player.hacking_mult, Player.hacking_mult * mults.hacking_mult], - ["Hacking Experience ", Player.hacking_exp_mult, Player.hacking_exp_mult * mults.hacking_exp_mult], - ])} +
    - {MultiplierTable([ - ["Strength Level ", Player.strength_mult, Player.strength_mult * mults.strength_mult], - ["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult], - ])} +
    - {MultiplierTable([ - ["Defense Level ", Player.defense_mult, Player.defense_mult * mults.defense_mult], - ["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult], - ])} +
    - {MultiplierTable([ - ["Dexterity Level ", Player.dexterity_mult, Player.dexterity_mult * mults.dexterity_mult], - ["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult], - ])} +
    - {MultiplierTable([ - ["Agility Level ", Player.agility_mult, Player.agility_mult * mults.agility_mult], - ["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult], - ])} +
    - {MultiplierTable([ - ["Charisma Level ", Player.charisma_mult, Player.charisma_mult * mults.charisma_mult], - ["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult], - ])} +
    - {MultiplierTable([ - [ - "Hacknet Node production ", - Player.hacknet_node_money_mult, - Player.hacknet_node_money_mult * mults.hacknet_node_money_mult, - ], - [ - "Hacknet Node purchase cost ", - Player.hacknet_node_purchase_cost_mult, - Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult, - ], - [ - "Hacknet Node RAM upgrade cost ", - Player.hacknet_node_ram_cost_mult, - Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult, - ], - [ - "Hacknet Node Core purchase cost ", - Player.hacknet_node_core_cost_mult, - Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult, - ], - [ - "Hacknet Node level upgrade cost ", - Player.hacknet_node_level_cost_mult, - Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult, - ], - ])} +
    - {MultiplierTable([ - ["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult], - ["Faction reputation gain ", Player.faction_rep_mult, Player.faction_rep_mult * mults.faction_rep_mult], - ["Salary ", Player.work_money_mult, Player.work_money_mult * mults.work_money_mult], - ])} +
    - {MultiplierTable([ - ["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult], - ["Crime money ", Player.crime_money_mult, Player.crime_money_mult * mults.crime_money_mult], - ])} +
    diff --git a/src/Augmentation/ui/PurchasedAugmentations.tsx b/src/Augmentation/ui/PurchasedAugmentations.tsx index 7ffc8ff4e..032f2dcad 100644 --- a/src/Augmentation/ui/PurchasedAugmentations.tsx +++ b/src/Augmentation/ui/PurchasedAugmentations.tsx @@ -9,6 +9,7 @@ import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { Player } from "../../Player"; import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion"; +import List from "@mui/material/List"; export function PurchasedAugmentations(): React.ReactElement { const augs: React.ReactElement[] = []; @@ -29,12 +30,8 @@ export function PurchasedAugmentations(): React.ReactElement { level = ownedAug.level; } - augs.push( -
  • - -
  • , - ); + augs.push(); } - return
      {augs}
    ; + return {augs}; } diff --git a/src/Augmentation/ui/SourceFileMinus1.tsx b/src/Augmentation/ui/SourceFileMinus1.tsx index 631209c71..897ab4421 100644 --- a/src/Augmentation/ui/SourceFileMinus1.tsx +++ b/src/Augmentation/ui/SourceFileMinus1.tsx @@ -2,14 +2,22 @@ * React Component for displaying a list of the player's Source-Files * on the Augmentations UI */ -import * as React from "react"; +import React, { useState } from "react"; import { Player } from "../../Player"; import { Exploit, ExploitName } from "../../Exploits/Exploit"; -import { BBAccordion } from "../../ui/React/BBAccordion"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemText from "@mui/material/ListItemText"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Paper from "@mui/material/Paper"; +import Collapse from "@mui/material/Collapse"; +import ExpandMore from "@mui/icons-material/ExpandMore"; +import ExpandLess from "@mui/icons-material/ExpandLess"; export function SourceFileMinus1(): React.ReactElement { + const [open, setOpen] = useState(false); const exploits = Player.exploits; if (exploits.length === 0) { @@ -17,33 +25,35 @@ export function SourceFileMinus1(): React.ReactElement { } return ( -
  • - - Source-File -1: Exploits in the BitNodes -
    - Level {exploits.length} / ? - - } - panelContent={ - <> -

    - 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%

    -
    + + setOpen((old) => !old)}> + + Source-File -1: Exploits in the BitNodes +
    + Level {exploits.length} / ? + + } + /> + {open ? : } +
    + + + + 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:

    -
      - {exploits.map((c: Exploit) => ( -
    • * {ExploitName(c)}
    • - ))} -
    - - } - /> -
  • + You have found the following exploits: + + {exploits.map((c: Exploit) => ( + * {ExploitName(c)} + ))} + + + + ); } diff --git a/src/Augmentation/ui/SourceFiles.tsx b/src/Augmentation/ui/SourceFiles.tsx new file mode 100644 index 000000000..e895c26ec --- /dev/null +++ b/src/Augmentation/ui/SourceFiles.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { use } from "../../ui/Context"; +import { SourceFileMinus1 } from "./SourceFileMinus1"; +import { OwnedSourceFiles } from "./OwnedSourceFiles"; +import List from "@mui/material/List"; + +import Typography from "@mui/material/Typography"; + +export function SourceFiles(): React.ReactElement { + const player = use.Player(); + return ( + <> + Source Files + + + + + + ); +} diff --git a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx index c5e6cd4e9..d70a115e3 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsPopup.tsx @@ -47,7 +47,7 @@ export function SleeveAugmentationsPopup(props: IProps): React.ReactElement { tooltip = renderToStaticMarkup(tooltip); } tooltip += "

    "; - tooltip += renderToStaticMarkup(aug.stats); + tooltip += renderToStaticMarkup(aug.stats || <>); return (
    {augName} @@ -70,7 +70,7 @@ export function SleeveAugmentationsPopup(props: IProps): React.ReactElement { info = renderToStaticMarkup(info); } info += "

    "; - info += renderToStaticMarkup(aug.stats); + info += renderToStaticMarkup(aug.stats || <>); return (
    purchaseAugmentation(aug)}> diff --git a/src/Script/Script.ts b/src/Script/Script.ts index 521678087..fa92abf33 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -91,16 +91,11 @@ export class Script { * @param {string} code - The new contents of the script * @param {Script[]} otherScripts - Other scripts on the server. Used to process imports */ - saveScript(code: string, serverIp: string, otherScripts: Script[]): void { + saveScript(filename: string, code: string, serverIp: string, otherScripts: Script[]): void { // Update code and filename this.code = code.replace(/^\s+|\s+$/g, ""); - const filenameElem: HTMLInputElement | null = document.getElementById("script-editor-filename") as HTMLInputElement; - if (filenameElem == null) { - console.error(`Failed to get Script filename DOM element`); - return; - } - this.filename = filenameElem.value; + this.filename = filename; this.server = serverIp; this.updateRamUsage(otherScripts); this.markUpdated(); diff --git a/src/ScriptEditor/ui/Root.tsx b/src/ScriptEditor/ui/Root.tsx index de1318a1e..4750e815e 100644 --- a/src/ScriptEditor/ui/Root.tsx +++ b/src/ScriptEditor/ui/Root.tsx @@ -130,14 +130,14 @@ export function Root(props: IProps): React.ReactElement { let found = false; for (let i = 0; i < server.scripts.length; i++) { if (filename == server.scripts[i].filename) { - server.scripts[i].saveScript(code, props.player.currentServer, server.scripts); + server.scripts[i].saveScript(filename, code, props.player.currentServer, server.scripts); found = true; } } if (!found) { const script = new Script(); - script.saveScript(code, props.player.currentServer, server.scripts); + script.saveScript(filename, code, props.player.currentServer, server.scripts); server.scripts.push(script); } @@ -165,7 +165,7 @@ export function Root(props: IProps): React.ReactElement { //If the current script already exists on the server, overwrite it for (let i = 0; i < server.scripts.length; i++) { if (filename == server.scripts[i].filename) { - server.scripts[i].saveScript(code, props.player.currentServer, server.scripts); + server.scripts[i].saveScript(filename, code, props.player.currentServer, server.scripts); props.router.toTerminal(); return; } @@ -173,7 +173,7 @@ export function Root(props: IProps): React.ReactElement { //If the current script does NOT exist, create a new one const script = new Script(); - script.saveScript(code, props.player.currentServer, server.scripts); + script.saveScript(filename, code, props.player.currentServer, server.scripts); server.scripts.push(script); } else if (filename.endsWith(".txt")) { for (let i = 0; i < server.textFiles.length; ++i) { diff --git a/src/SourceFile/SourceFile.ts b/src/SourceFile/SourceFile.ts index 64ed0484d..35956677b 100644 --- a/src/SourceFile/SourceFile.ts +++ b/src/SourceFile/SourceFile.ts @@ -1,13 +1,13 @@ import { BitNodes } from "../BitNode/BitNode"; export class SourceFile { - info: string; + info: JSX.Element; lvl = 1; n: number; name: string; owned = false; - constructor(number: number, info = "") { + constructor(number: number, info: JSX.Element) { const bitnodeKey = "BitNode" + number; const bitnode = BitNodes[bitnodeKey]; if (bitnode == null) { diff --git a/src/SourceFile/SourceFiles.ts b/src/SourceFile/SourceFiles.ts deleted file mode 100644 index 18588d573..000000000 --- a/src/SourceFile/SourceFiles.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { SourceFile } from "./SourceFile"; -import { IMap } from "../types"; - -export const SourceFiles: IMap = {}; - -SourceFiles["SourceFile1"] = new SourceFile( - 1, - "This Source-File lets the player start with 32GB of RAM on his/her " + - "home computer. It also increases all of the player's multipliers by:

    " + - "Level 1: 16%
    " + - "Level 2: 24%
    " + - "Level 3: 28%", -); -SourceFiles["SourceFile2"] = new SourceFile( - 2, - "This Source-File allows you to form gangs in other BitNodes " + - "once your karma decreases to a certain value. It also increases the player's " + - "crime success rate, crime money, and charisma multipliers by:

    " + - "Level 1: 24%
    " + - "Level 2: 36%
    " + - "Level 3: 42%", -); -SourceFiles["SourceFile3"] = new SourceFile( - 3, - "This Source-File lets you create corporations on other BitNodes (although " + - "some BitNodes will disable this mechanic). This Source-File also increases your charisma and company salary multipliers by:
    " + - "Level 1: 8%
    " + - "Level 2: 12%
    " + - "Level 3: 14%", -); -SourceFiles["SourceFile4"] = new SourceFile( - 4, - "This Source-File lets you access and use the Singularity Functions in every BitNode. Every " + - "level of this Source-File opens up more of the Singularity Functions you can use.", -); -SourceFiles["SourceFile5"] = new SourceFile( - 5, - "This Source-File grants a special new stat called Intelligence. Intelligence " + - "is unique because it is permanent and persistent (it never gets reset back to 1). However, " + - "gaining Intelligence experience is much slower than other stats, and it is also hidden (you won't " + - "know when you gain experience and how much). Higher Intelligence levels will boost your production " + - "for many actions in the game. In addition, this Source-File will unlock the getBitNodeMultipliers() " + - "and getServer() Netscript functions, as well as the formulas API, and will raise all of your " + - "hacking-related multipliers by:

    " + - "Level 1: 8%
    " + - "Level 2: 12%
    " + - "Level 3: 14%", -); -SourceFiles["SourceFile6"] = new SourceFile( - 6, - "This Source-File allows you to access the NSA's Bladeburner Division in other " + - "BitNodes. In addition, this Source-File will raise both the level and experience gain rate of all your combat stats by:

    " + - "Level 1: 8%
    " + - "Level 2: 12%
    " + - "Level 3: 14%", -); -SourceFiles["SourceFile7"] = new SourceFile( - 7, - "This Source-File allows you to access the Bladeburner Netscript API in other " + - "BitNodes. In addition, this Source-File will increase all of your Bladeburner multipliers by:

    " + - "Level 1: 8%
    " + - "Level 2: 12%
    " + - "Level 3: 14%", -); -SourceFiles["SourceFile8"] = new SourceFile( - 8, - "This Source-File grants the following benefits:

    " + - "Level 1: Permanent access to WSE and TIX API
    " + - "Level 2: Ability to short stocks in other BitNodes
    " + - "Level 3: Ability to use limit/stop orders in other BitNodes

    " + - "This Source-File also increases your hacking growth multipliers by: " + - "
    Level 1: 12%
    Level 2: 18%
    Level 3: 21%", -); -SourceFiles["SourceFile9"] = new SourceFile( - 9, - "This Source-File grants the following benefits:

    " + - "Level 1: Permanently unlocks the Hacknet Server in other BitNodes
    " + - "Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode
    " + - "Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode

    " + - "(Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT " + - "when installing Augmentations)", -); -SourceFiles["SourceFile10"] = new SourceFile( - 10, - "This Source-File unlocks Sleeve technology in other BitNodes. Each level of this " + - "Source-File also grants you a Duplicate Sleeve", -); -SourceFiles["SourceFile11"] = new SourceFile( - 11, - "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " + - "at that company by 1% per favor (rather than just the reputation gain). This Source-File also " + - " increases the player's company salary and reputation gain multipliers by:

    " + - "Level 1: 32%
    " + - "Level 2: 48%
    " + - "Level 3: 56%

    " + - "It also reduces the price increase for every aug bought by:

    " + - "Level 1: 4%
    " + - "Level 2: 6%
    " + - "Level 3: 7%", -); -SourceFiles["SourceFile12"] = new SourceFile( - 12, - "This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.", -); diff --git a/src/SourceFile/SourceFiles.tsx b/src/SourceFile/SourceFiles.tsx new file mode 100644 index 000000000..4c0814731 --- /dev/null +++ b/src/SourceFile/SourceFiles.tsx @@ -0,0 +1,197 @@ +import React from "react"; +import { SourceFile } from "./SourceFile"; +import { IMap } from "../types"; + +export const SourceFiles: IMap = {}; + +SourceFiles["SourceFile1"] = new SourceFile( + 1, + ( + <> + This Source-File lets the player start with 32GB of RAM on his/her home computer. It also increases all of the + player's multipliers by: +
    +
    + Level 1: 16% +
    + Level 2: 24% +
    + Level 3: 28% + + ), +); +SourceFiles["SourceFile2"] = new SourceFile( + 2, + ( + <> + This Source-File allows you to form gangs in other BitNodes once your karma decreases to a certain value. It also + increases the player's crime success rate, crime money, and charisma multipliers by: +
    +
    + Level 1: 24% +
    + Level 2: 36% +
    + Level 3: 42% + + ), +); +SourceFiles["SourceFile3"] = new SourceFile( + 3, + ( + <> + This Source-File lets you create corporations on other BitNodes (although some BitNodes will disable this + mechanic). This Source-File also increases your charisma and company salary multipliers by: +
    + Level 1: 8% +
    + Level 2: 12% +
    + Level 3: 14% + + ), +); +SourceFiles["SourceFile4"] = new SourceFile( + 4, + ( + <> + This Source-File lets you access and use the Singularity Functions in every BitNode. Every level of this + Source-File opens up more of the Singularity Functions you can use. + + ), +); +SourceFiles["SourceFile5"] = new SourceFile( + 5, + ( + <> + This Source-File grants a special new stat called Intelligence. Intelligence is unique because it is permanent and + persistent (it never gets reset back to 1). However, gaining Intelligence experience is much slower than other + stats, and it is also hidden (you won't know when you gain experience and how much). Higher Intelligence levels + will boost your production for many actions in the game. In addition, this Source-File will unlock the + getBitNodeMultipliers() and getServer() Netscript functions, as well as the formulas API, and will raise all of + your hacking-related multipliers by: +
    +
    + Level 1: 8% +
    + Level 2: 12% +
    + Level 3: 14% + + ), +); +SourceFiles["SourceFile6"] = new SourceFile( + 6, + ( + <> + This Source-File allows you to access the NSA's Bladeburner Division in other BitNodes. In addition, this + Source-File will raise both the level and experience gain rate of all your combat stats by: +
    +
    + Level 1: 8% +
    + Level 2: 12% +
    + Level 3: 14% + + ), +); +SourceFiles["SourceFile7"] = new SourceFile( + 7, + ( + <> + This Source-File allows you to access the Bladeburner Netscript API in other BitNodes. In addition, this + Source-File will increase all of your Bladeburner multipliers by: +
    +
    + Level 1: 8% +
    + Level 2: 12% +
    + Level 3: 14% + + ), +); +SourceFiles["SourceFile8"] = new SourceFile( + 8, + ( + <> + This Source-File grants the following benefits: +
    +
    + Level 1: Permanent access to WSE and TIX API +
    + Level 2: Ability to short stocks in other BitNodes +
    + Level 3: Ability to use limit/stop orders in other BitNodes +
    +
    + This Source-File also increases your hacking growth multipliers by: +
    + Level 1: 12% +
    + Level 2: 18% +
    + Level 3: 21% + + ), +); +SourceFiles["SourceFile9"] = new SourceFile( + 9, + ( + <> + This Source-File grants the following benefits: +
    +
    + Level 1: Permanently unlocks the Hacknet Server in other BitNodes +
    + Level 2: You start with 128GB of RAM on your home computer when entering a new BitNode +
    + Level 3: Grants a highly-upgraded Hacknet Server when entering a new BitNode +
    +
    + (Note that the Level 3 effect of this Source-File only applies when entering a new BitNode, NOT when installing + Augmentations) + + ), +); +SourceFiles["SourceFile10"] = new SourceFile( + 10, + ( + <> + This Source-File unlocks Sleeve technology in other BitNodes. Each level of this Source-File also grants you a + Duplicate Sleeve + + ), +); +SourceFiles["SourceFile11"] = new SourceFile( + 11, + ( + <> + This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate at + that company by 1% per favor (rather than just the reputation gain). This Source-File also increases the player's + company salary and reputation gain multipliers by: +
    +
    + Level 1: 32% +
    + Level 2: 48% +
    + Level 3: 56% +
    +
    + It also reduces the price increase for every aug bought by: +
    +
    + Level 1: 4% +
    + Level 2: 6% +
    + Level 3: 7% + + ), +); +SourceFiles["SourceFile12"] = new SourceFile( + 12, + <>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File., +); diff --git a/src/ui/React/AugmentationAccordion.tsx b/src/ui/React/AugmentationAccordion.tsx index b657a9e1a..484782d9d 100644 --- a/src/ui/React/AugmentationAccordion.tsx +++ b/src/ui/React/AugmentationAccordion.tsx @@ -4,12 +4,18 @@ * The header of the accordion contains the Augmentation's name (and level, if * applicable), and the accordion's panel contains the Augmentation's description. */ -import * as React from "react"; - -import { BBAccordion } from "./BBAccordion"; +import React, { useState } from "react"; import { Augmentation } from "../../Augmentation/Augmentation"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemText from "@mui/material/ListItemText"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Paper from "@mui/material/Paper"; +import Collapse from "@mui/material/Collapse"; +import ExpandMore from "@mui/icons-material/ExpandMore"; +import ExpandLess from "@mui/icons-material/ExpandLess"; type IProps = { aug: Augmentation; @@ -17,6 +23,7 @@ type IProps = { }; export function AugmentationAccordion(props: IProps): React.ReactElement { + const [open, setOpen] = useState(false); let displayName = props.aug.name; if (props.level != null) { if (props.aug.name === AugmentationNames.NeuroFluxGovernor) { @@ -26,31 +33,47 @@ export function AugmentationAccordion(props: IProps): React.ReactElement { if (typeof props.aug.info === "string") { return ( - {displayName}} - panelContent={ -

    - -
    -
    - {props.aug.stats} -

    - } - /> + + setOpen((old) => !old)}> + {displayName}} /> + {open ? : } + + + + + {props.aug.stats && ( + <> +
    +
    + {props.aug.stats} + + )} +
    +
    +
    ); } return ( - {displayName}} - panelContent={ -

    - {props.aug.info} -
    -
    - {props.aug.stats} -

    - } - /> + + setOpen((old) => !old)}> + {displayName}} /> + {open ? : } + + + + + {props.aug.info} + {props.aug.stats && ( + <> +
    +
    + {props.aug.stats} + + )} +
    +
    +
    +
    ); } diff --git a/src/ui/React/SourceFileAccordion.tsx b/src/ui/React/SourceFileAccordion.tsx index 72e9541b4..eedf0ee36 100644 --- a/src/ui/React/SourceFileAccordion.tsx +++ b/src/ui/React/SourceFileAccordion.tsx @@ -4,30 +4,47 @@ * The header of the accordion contains the Source-Files's name and level, * and the accordion's panel contains the Source-File's description. */ -import * as React from "react"; - -import { BBAccordion } from "./BBAccordion"; +import React, { useState } from "react"; import { SourceFile } from "../../SourceFile/SourceFile"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemText from "@mui/material/ListItemText"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import Paper from "@mui/material/Paper"; +import Collapse from "@mui/material/Collapse"; +import ExpandMore from "@mui/icons-material/ExpandMore"; +import ExpandLess from "@mui/icons-material/ExpandLess"; + type IProps = { level: number; sf: SourceFile; }; export function SourceFileAccordion(props: IProps): React.ReactElement { + const [open, setOpen] = useState(false); const maxLevel = props.sf.n === 12 ? "∞" : "3"; return ( - - {props.sf.name} -
    - {`Level ${props.level} / ${maxLevel}`} - - } - panelContent={

    } - /> + + setOpen((old) => !old)}> + + {props.sf.name} +
    + {`Level ${props.level} / ${maxLevel}`} + + } + /> + {open ? : } +
    + + + {props.sf.info} + + +
    ); }