From 0ae8b7218820f55630480fd61f04656b55f2319e Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Fri, 1 Oct 2021 15:19:37 -0400 Subject: [PATCH] 100% mui I think --- src/Bladeburner/ui/AllPages.tsx | 1 - src/Gang/IGang.ts | 2 +- ...{AscensionPopup.tsx => AscensionModal.tsx} | 38 ++- src/Gang/ui/BonusTime.tsx | 25 +- src/Gang/ui/Context.ts | 10 + src/Gang/ui/EquipmentsSubpage.tsx | 220 +++++++++++++++++ src/Gang/ui/GangMemberAccordion.tsx | 31 ++- src/Gang/ui/GangMemberAccordionContent.tsx | 23 +- src/Gang/ui/GangMemberList.tsx | 50 +--- src/Gang/ui/GangMemberStats.tsx | 149 ++++++------ src/Gang/ui/GangMemberUpgradePopup.tsx | 224 ------------------ src/Gang/ui/GangRoot.tsx | 55 ++--- src/Gang/ui/GangStats.tsx | 107 +++++---- src/Gang/ui/ManagementSubpage.tsx | 26 +- src/Gang/ui/RecruitButton.tsx | 45 ++-- .../ui/{RecruitPopup.tsx => RecruitModal.tsx} | 48 ++-- src/Gang/ui/TaskDescription.tsx | 3 +- src/Gang/ui/TaskSelector.tsx | 35 +-- src/Gang/ui/TerritorySubpage.tsx | 198 +++++++++------- src/Locations/ui/PurchaseServerModal.tsx | 1 - src/ui/React/BBAccordion.tsx | 84 ------- src/ui/React/MuiButton.tsx | 46 ---- src/ui/React/MuiPaper.tsx | 32 --- src/ui/React/Reputation.tsx | 2 +- src/ui/React/StdButton.tsx | 60 ----- 25 files changed, 652 insertions(+), 863 deletions(-) rename src/Gang/ui/{AscensionPopup.tsx => AscensionModal.tsx} (83%) create mode 100644 src/Gang/ui/Context.ts create mode 100644 src/Gang/ui/EquipmentsSubpage.tsx delete mode 100644 src/Gang/ui/GangMemberUpgradePopup.tsx rename src/Gang/ui/{RecruitPopup.tsx => RecruitModal.tsx} (53%) delete mode 100644 src/ui/React/BBAccordion.tsx delete mode 100644 src/ui/React/MuiButton.tsx delete mode 100644 src/ui/React/MuiPaper.tsx delete mode 100644 src/ui/React/StdButton.tsx diff --git a/src/Bladeburner/ui/AllPages.tsx b/src/Bladeburner/ui/AllPages.tsx index 383e89900..36f354ee6 100644 --- a/src/Bladeburner/ui/AllPages.tsx +++ b/src/Bladeburner/ui/AllPages.tsx @@ -10,7 +10,6 @@ import { IPlayer } from "../../PersonObjects/IPlayer"; import Tabs from "@mui/material/Tabs"; import Tab from "@mui/material/Tab"; import Box from "@mui/material/Box"; -import Paper from "@mui/material/Paper"; interface IProps { bladeburner: IBladeburner; diff --git a/src/Gang/IGang.ts b/src/Gang/IGang.ts index 00d7911cc..827be1914 100644 --- a/src/Gang/IGang.ts +++ b/src/Gang/IGang.ts @@ -38,7 +38,7 @@ export interface IGang { getWantedPenalty(): number; calculatePower(): number; killMember(member: GangMember): void; - ascendMember(member: GangMember, workerScript: WorkerScript): IAscensionResult; + ascendMember(member: GangMember, workerScript?: WorkerScript): IAscensionResult; getDiscount(): number; getAllTaskNames(): string[]; getUpgradeCost(upg: GangMemberUpgrade): number; diff --git a/src/Gang/ui/AscensionPopup.tsx b/src/Gang/ui/AscensionModal.tsx similarity index 83% rename from src/Gang/ui/AscensionPopup.tsx rename to src/Gang/ui/AscensionModal.tsx index 09476dd6e..1c22fc329 100644 --- a/src/Gang/ui/AscensionPopup.tsx +++ b/src/Gang/ui/AscensionModal.tsx @@ -3,20 +3,23 @@ * ascension of a gang member. */ import React, { useState, useEffect } from "react"; -import { Gang } from "../Gang"; import { GangMember } from "../GangMember"; import { numeralWrapper } from "../../ui/numeralFormat"; -import { removePopup } from "../../ui/React/createPopup"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import { Modal } from "../../ui/React/Modal"; +import { useGang } from "./Context"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; interface IProps { + open: boolean; + onClose: () => void; member: GangMember; - gang: Gang; - popupId: string; onAscend: () => void; } -export function AscensionPopup(props: IProps): React.ReactElement { +export function AscensionModal(props: IProps): React.ReactElement { + const gang = useGang(); const setRerender = useState(false)[1]; useEffect(() => { @@ -26,9 +29,9 @@ export function AscensionPopup(props: IProps): React.ReactElement { function confirm(): void { props.onAscend(); - const res = props.gang.ascendMember(props.member); + const res = gang.ascendMember(props.member); dialogBoxCreate( -

+ You ascended {props.member.name}!

Your gang lost {numeralWrapper.formatRespect(res.respect)} respect. @@ -48,13 +51,13 @@ export function AscensionPopup(props: IProps): React.ReactElement {
Charisma: x{numeralWrapper.format(res.cha, "0.000")}
-

, + , ); - removePopup(props.popupId); + props.onClose(); } function cancel(): void { - removePopup(props.popupId); + props.onClose(); } // const ascendBenefits = props.member.getAscensionResults(); @@ -62,8 +65,8 @@ export function AscensionPopup(props: IProps): React.ReactElement { const postAscend = props.member.getAscensionMultsAfterAscend(); return ( - <> -
+    
+      
         Are you sure you want to ascend this member? They will lose all of
         
their non-Augmentation upgrades and their stats will reset back to 1. @@ -92,13 +95,8 @@ export function AscensionPopup(props: IProps): React.ReactElement { Charisma: x{numeralWrapper.format(preAscend.cha, "0.000")} => x {numeralWrapper.format(postAscend.cha, "0.000")}
-
- - - + + + ); } diff --git a/src/Gang/ui/BonusTime.tsx b/src/Gang/ui/BonusTime.tsx index ec309ab4f..69364ed1e 100644 --- a/src/Gang/ui/BonusTime.tsx +++ b/src/Gang/ui/BonusTime.tsx @@ -5,6 +5,9 @@ import * as React from "react"; import { Gang } from "../Gang"; import { CONSTANTS } from "../../Constants"; import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions"; +import Typography from "@mui/material/Typography"; +import Tooltip from "@mui/material/Tooltip"; +import Box from "@mui/material/Box"; interface IProps { gang: Gang; @@ -15,15 +18,17 @@ export function BonusTime(props: IProps): React.ReactElement { if ((props.gang.storedCycles / CyclerPerSecond) * 1000 <= 5000) return <>; const bonusMillis = (props.gang.storedCycles / CyclerPerSecond) * 1000; return ( - <> -

- Bonus time: {convertTimeMsToTimeElapsedString(bonusMillis)} - - You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by the - browser). Bonus time makes the Gang mechanic progress faster, up to 5x the normal speed. - -

-
- + + + You gain bonus time while offline or when the game is inactive (e.g. when the tab is throttled by the + browser). Bonus time makes the Gang mechanic progress faster, up to 5x the normal speed. + + } + > + Bonus time: {convertTimeMsToTimeElapsedString(bonusMillis)} + + ); } diff --git a/src/Gang/ui/Context.ts b/src/Gang/ui/Context.ts new file mode 100644 index 000000000..9a5346777 --- /dev/null +++ b/src/Gang/ui/Context.ts @@ -0,0 +1,10 @@ +import React, { useContext } from "react"; +import { IGang } from "../IGang"; + +export const Context: { + Gang: React.Context; +} = { + Gang: React.createContext({} as IGang), +}; + +export const useGang = () => useContext(Context.Gang); diff --git a/src/Gang/ui/EquipmentsSubpage.tsx b/src/Gang/ui/EquipmentsSubpage.tsx new file mode 100644 index 000000000..b9a226e11 --- /dev/null +++ b/src/Gang/ui/EquipmentsSubpage.tsx @@ -0,0 +1,220 @@ +/** + * React Component for the popup that manages gang members upgrades + */ +import React, { useState } from "react"; +import { formatNumber } from "../../utils/StringHelperFunctions"; +import { numeralWrapper } from "../../ui/numeralFormat"; +import { GangMemberUpgrades } from "../GangMemberUpgrades"; +import { GangMemberUpgrade } from "../GangMemberUpgrade"; +import { Money } from "../../ui/React/Money"; +import { useGang } from "./Context"; +import { GangMember } from "../GangMember"; +import { UpgradeType } from "../data/upgrades"; +import { use } from "../../ui/Context"; +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 Grid from "@mui/material/Grid"; + +interface INextRevealProps { + upgrades: string[]; + type: UpgradeType; +} + +function NextReveal(props: INextRevealProps): React.ReactElement { + const gang = useGang(); + const player = use.Player(); + const upgrades = Object.keys(GangMemberUpgrades) + .filter((upgName: string) => { + const upg = GangMemberUpgrades[upgName]; + if (player.money.gt(gang.getUpgradeCost(upg))) return false; + if (upg.type !== props.type) return false; + if (props.upgrades.includes(upgName)) return false; + return true; + }) + .map((upgName: string) => GangMemberUpgrades[upgName]); + + if (upgrades.length === 0) return <>; + return ( + + Next at + + ); +} + +function PurchasedUpgrade({ upgName }: { upgName: string }): React.ReactElement { + const upg = GangMemberUpgrades[upgName]; + return ( + + + }> + {upg.name} + + + + ); +} + +interface IUpgradeButtonProps { + upg: GangMemberUpgrade; + rerender: () => void; + member: GangMember; +} + +function UpgradeButton(props: IUpgradeButtonProps): React.ReactElement { + const gang = useGang(); + const player = use.Player(); + function onClick(): void { + props.member.buyUpgrade(props.upg, player, gang); + props.rerender(); + } + return ( + }> + + {props.upg.name} + + + + ); +} + +interface IPanelProps { + member: GangMember; +} + +function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { + const gang = useGang(); + const player = use.Player(); + const setRerender = useState(false)[1]; + function rerender(): void { + setRerender((old) => !old); + } + function filterUpgrades(list: string[], type: UpgradeType): GangMemberUpgrade[] { + return Object.keys(GangMemberUpgrades) + .filter((upgName: string) => { + const upg = GangMemberUpgrades[upgName]; + if (player.money.lt(gang.getUpgradeCost(upg))) return false; + if (upg.type !== type) return false; + if (list.includes(upgName)) return false; + return true; + }) + .map((upgName: string) => GangMemberUpgrades[upgName]); + } + const weaponUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Weapon); + const armorUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Armor); + const vehicleUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Vehicle); + const rootkitUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Rootkit); + const augUpgrades = filterUpgrades(props.member.augmentations, UpgradeType.Augmentation); + + const asc = { + hack: props.member.calculateAscensionMult(props.member.hack_asc_points), + str: props.member.calculateAscensionMult(props.member.str_asc_points), + def: props.member.calculateAscensionMult(props.member.def_asc_points), + dex: props.member.calculateAscensionMult(props.member.dex_asc_points), + agi: props.member.calculateAscensionMult(props.member.agi_asc_points), + cha: props.member.calculateAscensionMult(props.member.cha_asc_points), + }; + return ( + + + {props.member.name} ({props.member.task}) + + + Hack: {props.member.hack} (x + {formatNumber(props.member.hack_mult * asc.hack, 2)})
+ Str: {props.member.str} (x + {formatNumber(props.member.str_mult * asc.str, 2)})
+ Def: {props.member.def} (x + {formatNumber(props.member.def_mult * asc.def, 2)})
+ Dex: {props.member.dex} (x + {formatNumber(props.member.dex_mult * asc.dex, 2)})
+ Agi: {props.member.agi} (x + {formatNumber(props.member.agi_mult * asc.agi, 2)})
+ Cha: {props.member.cha} (x + {formatNumber(props.member.cha_mult * asc.cha, 2)}) +
+ + Purchased Upgrades: +
+ {props.member.upgrades.map((upg: string) => ( + + ))} + {props.member.augmentations.map((upg: string) => ( + + ))} +
+ + + + Weapons + + {weaponUpgrades.map((upg) => ( + + ))} + + + + + Armor + + {armorUpgrades.map((upg) => ( + + ))} + + + + + Vehicles + + {vehicleUpgrades.map((upg) => ( + + ))} + + + + + Rootkits + + {rootkitUpgrades.map((upg) => ( + + ))} + + + + + Augmentations + + {augUpgrades.map((upg) => ( + + ))} + + + +
+ ); +} + +export function EquipmentsSubpage(): React.ReactElement { + const gang = useGang(); + return ( + <> + + You get a discount on equipment and upgrades based on your gang's respect and power. More respect and power + leads to more discounts. + + } + > + Discount: -{numeralWrapper.formatPercentage(1 - 1 / gang.getDiscount())} + + {gang.members.map((member: GangMember) => ( + + ))} + + ); +} diff --git a/src/Gang/ui/GangMemberAccordion.tsx b/src/Gang/ui/GangMemberAccordion.tsx index 4c415fe81..0f9cefcef 100644 --- a/src/Gang/ui/GangMemberAccordion.tsx +++ b/src/Gang/ui/GangMemberAccordion.tsx @@ -1,23 +1,36 @@ /** * React Component for a gang member on the management subpage. */ -import React from "react"; -import { Gang } from "../Gang"; +import React, { useState } from "react"; import { GangMember } from "../GangMember"; -import { BBAccordion } from "../../ui/React/BBAccordion"; import { GangMemberAccordionContent } from "./GangMemberAccordionContent"; +import Box from "@mui/material/Box"; + +import Typography from "@mui/material/Typography"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemText from "@mui/material/ListItemText"; +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"; interface IProps { - gang: Gang; member: GangMember; } export function GangMemberAccordion(props: IProps): React.ReactElement { + const [open, setOpen] = useState(true); return ( - {props.member.name}} - panelContent={} - /> + + setOpen((old) => !old)}> + {props.member.name}} /> + {open ? : } + + + + + + + ); } diff --git a/src/Gang/ui/GangMemberAccordionContent.tsx b/src/Gang/ui/GangMemberAccordionContent.tsx index 55a996bb1..a79592b36 100644 --- a/src/Gang/ui/GangMemberAccordionContent.tsx +++ b/src/Gang/ui/GangMemberAccordionContent.tsx @@ -6,27 +6,26 @@ import React, { useState } from "react"; import { GangMemberStats } from "./GangMemberStats"; import { TaskSelector } from "./TaskSelector"; import { TaskDescription } from "./TaskDescription"; -import { Gang } from "../Gang"; import { GangMember } from "../GangMember"; +import Grid from "@mui/material/Grid"; interface IProps { - gang: Gang; member: GangMember; } export function GangMemberAccordionContent(props: IProps): React.ReactElement { const setRerender = useState(false)[1]; return ( - <> -
- setRerender((old) => !old)} gang={props.gang} member={props.member} /> -
-
- setRerender((old) => !old)} gang={props.gang} member={props.member} /> -
-
+ + + setRerender((old) => !old)} member={props.member} /> + + + setRerender((old) => !old)} member={props.member} /> + + -
- + + ); } diff --git a/src/Gang/ui/GangMemberList.tsx b/src/Gang/ui/GangMemberList.tsx index 57ef554f7..104e218b8 100644 --- a/src/Gang/ui/GangMemberList.tsx +++ b/src/Gang/ui/GangMemberList.tsx @@ -2,59 +2,21 @@ * React Component for the list of gang members on the management subpage. */ import React, { useState } from "react"; -import { GangMemberUpgradePopup } from "./GangMemberUpgradePopup"; import { GangMemberAccordion } from "./GangMemberAccordion"; -import { createPopup } from "../../ui/React/createPopup"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { Gang } from "../Gang"; import { GangMember } from "../GangMember"; import { RecruitButton } from "./RecruitButton"; +import { useGang } from "./Context"; -interface IProps { - gang: Gang; - player: IPlayer; -} - -export function GangMemberList(props: IProps): React.ReactElement { - const [filter, setFilter] = useState(""); +export function GangMemberList(): React.ReactElement { + const gang = useGang(); const setRerender = useState(false)[1]; - function openUpgradePopup(): void { - const popupId = `gang-upgrade-popup`; - createPopup(popupId, GangMemberUpgradePopup, { - gang: props.gang, - player: props.player, - popupId: popupId, - }); - } - - function onFilterChange(event: React.ChangeEvent): void { - setFilter(event.target.value); - } - - const members = props.gang.members.filter( - (member: GangMember) => member.name.indexOf(filter) > -1 || member.task.indexOf(filter) > -1, - ); - return ( <> - setRerender((old) => !old)} gang={props.gang} /> -
- - - Manage Equipment - + setRerender((old) => !old)} />
    - {members.map((member: GangMember) => ( -
  • - -
  • + {gang.members.map((member: GangMember) => ( + ))}
diff --git a/src/Gang/ui/GangMemberStats.tsx b/src/Gang/ui/GangMemberStats.tsx index 167b7dff8..c81161a7e 100644 --- a/src/Gang/ui/GangMemberStats.tsx +++ b/src/Gang/ui/GangMemberStats.tsx @@ -2,48 +2,26 @@ * React Component for the first part of a gang member details. * Contains skills and exp. */ -import React from "react"; -import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import React, { useState } from "react"; import { formatNumber } from "../../utils/StringHelperFunctions"; import { numeralWrapper } from "../../ui/numeralFormat"; -import { createPopup } from "../../ui/React/createPopup"; -import { Gang } from "../Gang"; import { GangMember } from "../GangMember"; -import { AscensionPopup } from "./AscensionPopup"; +import { AscensionModal } from "./AscensionModal"; +import Typography from "@mui/material/Typography"; +import Tooltip from "@mui/material/Tooltip"; +import Button from "@mui/material/Button"; +import { StaticModal } from "../../ui/React/StaticModal"; +import IconButton from "@mui/material/IconButton"; +import HelpIcon from "@mui/icons-material/Help"; interface IProps { member: GangMember; - gang: Gang; onAscend: () => void; } export function GangMemberStats(props: IProps): React.ReactElement { - function ascend(): void { - const popupId = `gang-management-ascend-member ${props.member.name}`; - createPopup(popupId, AscensionPopup, { - member: props.member, - gang: props.gang, - popupId: popupId, - onAscend: props.onAscend, - }); - } - - function openAscensionHelp(): void { - dialogBoxCreate( - <> - Ascending a Gang Member resets the member's progress and stats in exchange for a permanent boost to their stat - multipliers. -
-
- The additional stat multiplier that the Gang Member gains upon ascension is based on the amount of exp they - have. -
-
- Upon ascension, the member will lose all of its non-Augmentation Equipment and your gang will lose respect equal - to the total respect earned by the member. - , - ); - } + const [helpOpen, setHelpOpen] = useState(false); + const [ascendOpen, setAscendOpen] = useState(false); const asc = { hack: props.member.calculateAscensionMult(props.member.hack_asc_points), @@ -56,48 +34,77 @@ export function GangMemberStats(props: IProps): React.ReactElement { return ( <> - - Hk: x{numeralWrapper.formatMultiplier(props.member.hack_mult * asc.hack)}(x - {numeralWrapper.formatMultiplier(props.member.hack_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.hack)} Asc) -
- St: x{numeralWrapper.formatMultiplier(props.member.str_mult * asc.str)} - (x{numeralWrapper.formatMultiplier(props.member.str_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.str)} Asc) -
- Df: x{numeralWrapper.formatMultiplier(props.member.def_mult * asc.def)} - (x{numeralWrapper.formatMultiplier(props.member.def_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.def)} Asc) -
- Dx: x{numeralWrapper.formatMultiplier(props.member.dex_mult * asc.dex)} - (x{numeralWrapper.formatMultiplier(props.member.dex_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.dex)} Asc) -
- Ag: x{numeralWrapper.formatMultiplier(props.member.agi_mult * asc.agi)} - (x{numeralWrapper.formatMultiplier(props.member.agi_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.agi)} Asc) -
- Ch: x{numeralWrapper.formatMultiplier(props.member.cha_mult * asc.cha)} - (x{numeralWrapper.formatMultiplier(props.member.cha_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.cha)} Asc) -
-
-        Hacking: {formatNumber(props.member.hack, 0)} ({numeralWrapper.formatExp(props.member.hack_exp)} exp)
-        
- Strength: {formatNumber(props.member.str, 0)} ({numeralWrapper.formatExp(props.member.str_exp)} exp) -
- Defense: {formatNumber(props.member.def, 0)} ({numeralWrapper.formatExp(props.member.def_exp)} exp) -
- Dexterity: {formatNumber(props.member.dex, 0)} ({numeralWrapper.formatExp(props.member.dex_exp)} exp) -
- Agility: {formatNumber(props.member.agi, 0)} ({numeralWrapper.formatExp(props.member.agi_exp)} exp) -
- Charisma: {formatNumber(props.member.cha, 0)} ({numeralWrapper.formatExp(props.member.cha_exp)} exp) -
-
+ + Hk: x{numeralWrapper.formatMultiplier(props.member.hack_mult * asc.hack)}(x + {numeralWrapper.formatMultiplier(props.member.hack_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.hack)}{" "} + Asc) +
+ St: x{numeralWrapper.formatMultiplier(props.member.str_mult * asc.str)} + (x{numeralWrapper.formatMultiplier(props.member.str_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.str)}{" "} + Asc) +
+ Df: x{numeralWrapper.formatMultiplier(props.member.def_mult * asc.def)} + (x{numeralWrapper.formatMultiplier(props.member.def_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.def)}{" "} + Asc) +
+ Dx: x{numeralWrapper.formatMultiplier(props.member.dex_mult * asc.dex)} + (x{numeralWrapper.formatMultiplier(props.member.dex_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.dex)}{" "} + Asc) +
+ Ag: x{numeralWrapper.formatMultiplier(props.member.agi_mult * asc.agi)} + (x{numeralWrapper.formatMultiplier(props.member.agi_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.agi)}{" "} + Asc) +
+ Ch: x{numeralWrapper.formatMultiplier(props.member.cha_mult * asc.cha)} + (x{numeralWrapper.formatMultiplier(props.member.cha_mult)} Eq, x{numeralWrapper.formatMultiplier(asc.cha)}{" "} + Asc) + + } + > + + Hacking: {formatNumber(props.member.hack, 0)} ({numeralWrapper.formatExp(props.member.hack_exp)} exp) +
+ Strength: {formatNumber(props.member.str, 0)} ({numeralWrapper.formatExp(props.member.str_exp)} exp) +
+ Defense: {formatNumber(props.member.def, 0)} ({numeralWrapper.formatExp(props.member.def_exp)} exp) +
+ Dexterity: {formatNumber(props.member.dex, 0)} ({numeralWrapper.formatExp(props.member.dex_exp)} exp) +
+ Agility: {formatNumber(props.member.agi, 0)} ({numeralWrapper.formatExp(props.member.agi_exp)} exp) +
+ Charisma: {formatNumber(props.member.cha, 0)} ({numeralWrapper.formatExp(props.member.cha_exp)} exp) +
+
+

{props.member.canAscend() && ( <> - -
- ? -
+ + setAscendOpen(false)} + member={props.member} + onAscend={props.onAscend} + /> + setHelpOpen(true)}> + + + setHelpOpen(false)}> + + Ascending a Gang Member resets the member's progress and stats in exchange for a permanent boost to their + stat multipliers. +
+
+ The additional stat multiplier that the Gang Member gains upon ascension is based on the amount of exp + they have. +
+
+ Upon ascension, the member will lose all of its non-Augmentation Equipment and your gang will lose respect + equal to the total respect earned by the member. +
+
)} diff --git a/src/Gang/ui/GangMemberUpgradePopup.tsx b/src/Gang/ui/GangMemberUpgradePopup.tsx deleted file mode 100644 index 0b615bac4..000000000 --- a/src/Gang/ui/GangMemberUpgradePopup.tsx +++ /dev/null @@ -1,224 +0,0 @@ -/** - * React Component for the popup that manages gang members upgrades - */ -import React, { useState, useEffect } from "react"; -import { formatNumber } from "../../utils/StringHelperFunctions"; -import { numeralWrapper } from "../../ui/numeralFormat"; -import { GangMemberUpgrades } from "../GangMemberUpgrades"; -import { GangMemberUpgrade } from "../GangMemberUpgrade"; -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { Money } from "../../ui/React/Money"; -import { removePopup } from "../../ui/React/createPopup"; -import { GangMember } from "../GangMember"; -import { Gang } from "../Gang"; -import { UpgradeType } from "../data/upgrades"; - -interface INextRevealProps { - gang: Gang; - upgrades: string[]; - type: UpgradeType; - player: IPlayer; -} - -function NextReveal(props: INextRevealProps): React.ReactElement { - const upgrades = Object.keys(GangMemberUpgrades) - .filter((upgName: string) => { - const upg = GangMemberUpgrades[upgName]; - if (props.player.money.gt(props.gang.getUpgradeCost(upg))) return false; - if (upg.type !== props.type) return false; - if (props.upgrades.includes(upgName)) return false; - return true; - }) - .map((upgName: string) => GangMemberUpgrades[upgName]); - - if (upgrades.length === 0) return <>; - return ( -

- Next at -

- ); -} - -interface IPanelProps { - member: GangMember; - gang: Gang; - player: IPlayer; -} - -function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { - const setRerender = useState(false)[1]; - function filterUpgrades(list: string[], type: UpgradeType): GangMemberUpgrade[] { - return Object.keys(GangMemberUpgrades) - .filter((upgName: string) => { - const upg = GangMemberUpgrades[upgName]; - if (props.player.money.lt(props.gang.getUpgradeCost(upg))) return false; - if (upg.type !== type) return false; - if (list.includes(upgName)) return false; - return true; - }) - .map((upgName: string) => GangMemberUpgrades[upgName]); - } - const weaponUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Weapon); - const armorUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Armor); - const vehicleUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Vehicle); - const rootkitUpgrades = filterUpgrades(props.member.upgrades, UpgradeType.Rootkit); - const augUpgrades = filterUpgrades(props.member.augmentations, UpgradeType.Augmentation); - - function purchasedUpgrade(upgName: string): React.ReactElement { - const upg = GangMemberUpgrades[upgName]; - return ( -
- {upg.name} - -
- ); - } - - function upgradeButton(upg: GangMemberUpgrade, left = false): React.ReactElement { - function onClick(): void { - props.member.buyUpgrade(upg, props.player, props.gang); - setRerender((old) => !old); - } - return ( - - {upg.name} - - - - ); - } - - const asc = { - hack: props.member.calculateAscensionMult(props.member.hack_asc_points), - str: props.member.calculateAscensionMult(props.member.str_asc_points), - def: props.member.calculateAscensionMult(props.member.def_asc_points), - dex: props.member.calculateAscensionMult(props.member.dex_asc_points), - agi: props.member.calculateAscensionMult(props.member.agi_asc_points), - cha: props.member.calculateAscensionMult(props.member.cha_asc_points), - }; - return ( -
-

- {props.member.name}({props.member.task}) -

-
-        Hack: {props.member.hack} (x
-        {formatNumber(props.member.hack_mult * asc.hack, 2)})
- Str: {props.member.str} (x - {formatNumber(props.member.str_mult * asc.str, 2)})
- Def: {props.member.def} (x - {formatNumber(props.member.def_mult * asc.def, 2)})
- Dex: {props.member.dex} (x - {formatNumber(props.member.dex_mult * asc.dex, 2)})
- Agi: {props.member.agi} (x - {formatNumber(props.member.agi_mult * asc.agi, 2)})
- Cha: {props.member.cha} (x - {formatNumber(props.member.cha_mult * asc.cha, 2)}) -
-
- Purchased Upgrades: {props.member.upgrades.map((upg: string) => purchasedUpgrade(upg))} - {props.member.augmentations.map((upg: string) => purchasedUpgrade(upg))} -
-
-

Weapons

- {weaponUpgrades.map((upg) => upgradeButton(upg))} - -
-
-

Armor

- {armorUpgrades.map((upg) => upgradeButton(upg))} - -
-
-

Vehicles

- {vehicleUpgrades.map((upg) => upgradeButton(upg))} - -
-
-

Rootkits

- {rootkitUpgrades.map((upg) => upgradeButton(upg, true))} - -
-
-

Augmentations

- {augUpgrades.map((upg) => upgradeButton(upg, true))} - -
-
- ); -} - -interface IProps { - gang: Gang; - player: IPlayer; - popupId: string; -} - -export function GangMemberUpgradePopup(props: IProps): React.ReactElement { - const setRerender = useState(false)[1]; - const [filter, setFilter] = useState(""); - - function closePopup(this: Window, ev: KeyboardEvent): void { - if (ev.keyCode !== 27) return; - removePopup(props.popupId); - } - - useEffect(() => { - window.addEventListener<"keydown">("keydown", closePopup); - const id = setInterval(() => setRerender((old) => !old), 1000); - return () => { - clearInterval(id); - window.removeEventListener<"keydown">("keydown", closePopup); - }; - }, []); - - return ( - <> - setFilter(event.target.value)} - /> -

- Discount: -{numeralWrapper.formatPercentage(1 - 1 / props.gang.getDiscount())} - - You get a discount on equipment and upgrades based on your gang's respect and power. More respect and power - leads to more discounts. - -

- {props.gang.members.map((member: GangMember) => ( - - ))} - - ); -} diff --git a/src/Gang/ui/GangRoot.tsx b/src/Gang/ui/GangRoot.tsx index fe2d4ade0..87b1a642e 100644 --- a/src/Gang/ui/GangRoot.tsx +++ b/src/Gang/ui/GangRoot.tsx @@ -4,48 +4,49 @@ import React, { useState, useEffect } from "react"; import { ManagementSubpage } from "./ManagementSubpage"; import { TerritorySubpage } from "./TerritorySubpage"; +import { EquipmentsSubpage } from "./EquipmentsSubpage"; import { use } from "../../ui/Context"; import { Factions } from "../../Faction/Factions"; +import { Context } from "./Context"; + +import Tabs from "@mui/material/Tabs"; +import Tab from "@mui/material/Tab"; + +enum Page { + Management, + Equipment, + Territory, +} export function GangRoot(): React.ReactElement { const player = use.Player(); - const router = use.Router(); const gang = (function () { if (player.gang === null) throw new Error("Gang should not be null"); return player.gang; })(); - const [management, setManagement] = useState(true); + const [value, setValue] = React.useState(0); + + function handleChange(event: React.SyntheticEvent, tab: number): void { + setValue(tab); + } + const setRerender = useState(false)[1]; useEffect(() => { - const id = setInterval(() => setRerender((old) => !old), 1000); + const id = setInterval(() => setRerender((old) => !old), 200); return () => clearInterval(id); }, []); - function back(): void { - router.toFaction(Factions[gang.facName]); - } - return ( - + + + + + + + {value === 0 && } + {value === 1 && } + {value === 2 && } + ); } diff --git a/src/Gang/ui/GangStats.tsx b/src/Gang/ui/GangStats.tsx index f8f91e9d1..ec07fd858 100644 --- a/src/Gang/ui/GangStats.tsx +++ b/src/Gang/ui/GangStats.tsx @@ -4,7 +4,6 @@ */ import React from "react"; import { Factions } from "../../Faction/Factions"; -import { Gang } from "../Gang"; import { formatNumber } from "../../utils/StringHelperFunctions"; import { numeralWrapper } from "../../ui/numeralFormat"; @@ -12,13 +11,14 @@ import { MoneyRate } from "../../ui/React/MoneyRate"; import { Reputation } from "../../ui/React/Reputation"; import { AllGangs } from "../AllGangs"; import { BonusTime } from "./BonusTime"; +import { useGang } from "./Context"; +import Typography from "@mui/material/Typography"; +import Tooltip from "@mui/material/Tooltip"; +import Box from "@mui/material/Box"; -interface IProps { - gang: Gang; -} - -export function GangStats(props: IProps): React.ReactElement { - const territoryMult = AllGangs[props.gang.facName].territory * 100; +export function GangStats(): React.ReactElement { + const gang = useGang(); + const territoryMult = AllGangs[gang.facName].territory * 100; let territoryStr; if (territoryMult <= 0) { territoryStr = formatNumber(0, 2); @@ -30,46 +30,59 @@ export function GangStats(props: IProps): React.ReactElement { return ( <> -

- Respect: {numeralWrapper.formatRespect(props.gang.respect)} ( - {numeralWrapper.formatRespect(5 * props.gang.respectGainRate)} / sec) - - Represents the amount of respect your gang has from other gangs and criminal organizations. Your respect - affects the amount of money your gang members will earn, and also determines how much reputation you are - earning with your gang's corresponding Faction. - -

-
-

- Wanted Level: {numeralWrapper.formatWanted(props.gang.wanted)} ( - {numeralWrapper.formatWanted(5 * props.gang.wantedGainRate)} / sec) - - Represents how much the gang is wanted by law enforcement. The higher your gang's wanted level, the harder it - will be for your gang members to make money and earn respect. Note that the minimum wanted level is 1. - -

-
-

- Wanted Level Penalty: -{formatNumber((1 - props.gang.getWantedPenalty()) * 100, 2)}% - Penalty for respect and money gain rates due to Wanted Level -

-
-
-

- Money gain rate: -

-
-
-

- Territory: {territoryStr}% - The percentage of total territory your Gang controls -

-
-

- Faction reputation: -

-
- + + + Represents the amount of respect your gang has from other gangs and criminal organizations. Your respect + affects the amount of money your gang members will earn, and also determines how much reputation you are + earning with your gang's corresponding Faction. + + } + > + + Respect: {numeralWrapper.formatRespect(gang.respect)} ( + {numeralWrapper.formatRespect(5 * gang.respectGainRate)} / sec) + + + + + + + Represents how much the gang is wanted by law enforcement. The higher your gang's wanted level, the harder + it will be for your gang members to make money and earn respect. Note that the minimum wanted level is 1. + + } + > + + Wanted Level: {numeralWrapper.formatWanted(gang.wanted)} ( + {numeralWrapper.formatWanted(5 * gang.wantedGainRate)} / sec) + + + + + + Penalty for respect and money gain rates due to Wanted Level}> + Wanted Level Penalty: -{formatNumber((1 - gang.getWantedPenalty()) * 100, 2)}% + + + + + Money gain rate: + + + + The percentage of total territory your Gang controls}> + Territory: {territoryStr}% + + + + Faction reputation: + + + ); } diff --git a/src/Gang/ui/ManagementSubpage.tsx b/src/Gang/ui/ManagementSubpage.tsx index 0455dd561..6f42a1aa8 100644 --- a/src/Gang/ui/ManagementSubpage.tsx +++ b/src/Gang/ui/ManagementSubpage.tsx @@ -2,20 +2,16 @@ * React Component for the subpage that manages gang members, the main page. */ import React from "react"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { GangStats } from "./GangStats"; -import { Gang } from "../Gang"; import { GangMemberList } from "./GangMemberList"; +import { useGang } from "./Context"; +import Typography from "@mui/material/Typography"; -interface IProps { - gang: Gang; - player: IPlayer; -} - -export function ManagementSubpage(props: IProps): React.ReactElement { +export function ManagementSubpage(): React.ReactElement { + const gang = useGang(); return ( -
-

+ <> + This page is used to manage your gang members and get an overview of your gang's stats.

@@ -23,7 +19,7 @@ export function ManagementSubpage(props: IProps): React.ReactElement { too difficult. Consider training that member's stats or choosing an easier task. The tasks closer to the top of the dropdown list are generally easier. Alternatively, the gang member's low production might be due to the fact that your wanted level is too high. Consider assigning a few members to the ' - {props.gang.isHackingGang ? "Ethical Hacking" : "Vigilante Justice"}' task to lower your wanted level. + {gang.isHackingGang ? "Ethical Hacking" : "Vigilante Justice"}' task to lower your wanted level.

Installing Augmentations does NOT reset your progress with your Gang. Furthermore, after installing @@ -31,11 +27,11 @@ export function ManagementSubpage(props: IProps): React.ReactElement {

You can also manage your gang programmatically through Netscript using the Gang API -

+
- +
- -
+ + ); } diff --git a/src/Gang/ui/RecruitButton.tsx b/src/Gang/ui/RecruitButton.tsx index 95a032f16..c1a89d3f2 100644 --- a/src/Gang/ui/RecruitButton.tsx +++ b/src/Gang/ui/RecruitButton.tsx @@ -1,51 +1,42 @@ /** * React Component for the recruitment button and text on the gang main page. */ -import React from "react"; -import { Gang } from "../Gang"; -import { RecruitPopup } from "./RecruitPopup"; +import React, { useState } from "react"; +import { RecruitModal } from "./RecruitModal"; import { GangConstants } from "../data/Constants"; import { formatNumber } from "../../utils/StringHelperFunctions"; -import { createPopup } from "../../ui/React/createPopup"; +import { useGang } from "./Context"; +import Typography from "@mui/material/Typography"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; interface IProps { - gang: Gang; onRecruit: () => void; } export function RecruitButton(props: IProps): React.ReactElement { - if (props.gang.members.length >= GangConstants.MaximumGangMembers) { + const gang = useGang(); + const [open, setOpen] = useState(false); + if (gang.members.length >= GangConstants.MaximumGangMembers) { return <>; } - if (!props.gang.canRecruitMember()) { - const respect = props.gang.getRespectNeededToRecruitMember(); + if (!gang.canRecruitMember()) { + const respect = gang.getRespectNeededToRecruitMember(); return ( - <> - + + + {formatNumber(respect, 2)} respect needed to recruit next member + ); } - function onClick(): void { - const popupId = "recruit-gang-member-popup"; - createPopup(popupId, RecruitPopup, { - gang: props.gang, - popupId: popupId, - onRecruit: props.onRecruit, - }); - } - return ( <> - - Recruit Gang Member - + + setOpen(false)} onRecruit={props.onRecruit} /> ); } diff --git a/src/Gang/ui/RecruitPopup.tsx b/src/Gang/ui/RecruitModal.tsx similarity index 53% rename from src/Gang/ui/RecruitPopup.tsx rename to src/Gang/ui/RecruitModal.tsx index 0fa295577..c5096ba74 100644 --- a/src/Gang/ui/RecruitPopup.tsx +++ b/src/Gang/ui/RecruitModal.tsx @@ -2,38 +2,35 @@ * React Component for the popup used to recruit new gang members. */ import React, { useState } from "react"; -import { Gang } from "../Gang"; -import { removePopup } from "../../ui/React/createPopup"; +import { Modal } from "../../ui/React/Modal"; import { dialogBoxCreate } from "../../ui/React/DialogBox"; +import { useGang } from "./Context"; +import Typography from "@mui/material/Typography"; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; interface IRecruitPopupProps { - gang: Gang; - popupId: string; + open: boolean; + onClose: () => void; onRecruit: () => void; } -export function RecruitPopup(props: IRecruitPopupProps): React.ReactElement { +export function RecruitModal(props: IRecruitPopupProps): React.ReactElement { + const gang = useGang(); const [name, setName] = useState(""); + const disabled = name === "" || !gang.canRecruitMember(); function recruit(): void { - if (name === "") { - dialogBoxCreate("You must enter a name for your Gang member!"); - return; - } - if (!props.gang.canRecruitMember()) { - dialogBoxCreate("You cannot recruit another Gang member!"); - return; - } - + if (disabled) return; // At this point, the only way this can fail is if you already // have a gang member with the same name - if (!props.gang.recruitMember(name)) { + if (!gang.recruitMember(name)) { dialogBoxCreate("You already have a gang member with this name!"); return; } props.onRecruit(); - removePopup(props.popupId); + props.onClose(); } function onKeyUp(event: React.KeyboardEvent): void { @@ -45,20 +42,23 @@ export function RecruitPopup(props: IRecruitPopupProps): React.ReactElement { } return ( - <> -

Enter a name for your new Gang member:

+ + Enter a name for your new Gang member:
- + Recruit + + ), + }} /> - - Recruit Gang Member - - +
); } diff --git a/src/Gang/ui/TaskDescription.tsx b/src/Gang/ui/TaskDescription.tsx index 83c934836..1946bf23e 100644 --- a/src/Gang/ui/TaskDescription.tsx +++ b/src/Gang/ui/TaskDescription.tsx @@ -5,6 +5,7 @@ import React from "react"; import { GangMemberTasks } from "../GangMemberTasks"; import { GangMember } from "../GangMember"; +import Typography from "@mui/material/Typography"; interface IProps { member: GangMember; @@ -14,5 +15,5 @@ export function TaskDescription(props: IProps): React.ReactElement { const task = GangMemberTasks[props.member.task]; const desc = task ? task.desc : GangMemberTasks["Unassigned"].desc; - return

; + return ; } diff --git a/src/Gang/ui/TaskSelector.tsx b/src/Gang/ui/TaskSelector.tsx index 49d263c56..02e3e2013 100644 --- a/src/Gang/ui/TaskSelector.tsx +++ b/src/Gang/ui/TaskSelector.tsx @@ -6,49 +6,50 @@ import React, { useState } from "react"; import { numeralWrapper } from "../../ui/numeralFormat"; import { StatsTable } from "../../ui/React/StatsTable"; import { MoneyRate } from "../../ui/React/MoneyRate"; -import { Gang } from "../Gang"; +import { useGang } from "./Context"; import { GangMember } from "../GangMember"; +import MenuItem from "@mui/material/MenuItem"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; interface IProps { member: GangMember; - gang: Gang; onTaskChange: () => void; } export function TaskSelector(props: IProps): React.ReactElement { + const gang = useGang(); const [currentTask, setCurrentTask] = useState(props.member.task); - function onChange(event: React.ChangeEvent): void { + function onChange(event: SelectChangeEvent): void { const task = event.target.value; props.member.assignToTask(task); setCurrentTask(task); props.onTaskChange(); } - const tasks = props.gang.getAllTaskNames(); + const tasks = gang.getAllTaskNames(); const data = [ - [`Money:`, ], - [`Respect:`, `${numeralWrapper.formatRespect(5 * props.member.calculateRespectGain(props.gang))} / sec`], - [`Wanted Level:`, `${numeralWrapper.formatWanted(5 * props.member.calculateWantedLevelGain(props.gang))} / sec`], + [`Money:`, ], + [`Respect:`, `${numeralWrapper.formatRespect(5 * props.member.calculateRespectGain(gang))} / sec`], + [`Wanted Level:`, `${numeralWrapper.formatWanted(5 * props.member.calculateWantedLevelGain(gang))} / sec`], [`Total Respect:`, `${numeralWrapper.formatRespect(props.member.earnedRespect)}`], ]; return ( <> - + + Unassigned + {tasks.map((task: string, i: number) => ( - + ))} - -

- -
+ + + ); } diff --git a/src/Gang/ui/TerritorySubpage.tsx b/src/Gang/ui/TerritorySubpage.tsx index 14b2159ec..3651899ab 100644 --- a/src/Gang/ui/TerritorySubpage.tsx +++ b/src/Gang/ui/TerritorySubpage.tsx @@ -3,59 +3,25 @@ */ import React from "react"; import { numeralWrapper } from "../../ui/numeralFormat"; -import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { formatNumber } from "../../utils/StringHelperFunctions"; import { AllGangs } from "../AllGangs"; import { Gang } from "../Gang"; +import { useGang } from "./Context"; -interface IProps { - gang: Gang; -} +import Typography from "@mui/material/Typography"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Switch from "@mui/material/Switch"; +import Tooltip from "@mui/material/Tooltip"; +import Box from "@mui/material/Box"; +import Paper from "@mui/material/Paper"; -export function TerritorySubpage(props: IProps): React.ReactElement { - function openWarfareHelp(): void { - dialogBoxCreate( - "This percentage represents the chance you have of " + - "'clashing' with with another gang. If you do not " + - "wish to gain/lose territory, then keep this " + - "percentage at 0% by not engaging in territory warfare.", - ); - } - - function formatTerritory(n: number): string { - const v = n * 100; - if (v <= 0) { - return formatNumber(0, 2); - } else if (v >= 100) { - return formatNumber(100, 2); - } else { - return formatNumber(v, 2); - } - } - - const playerPower = AllGangs[props.gang.facName].power; - function otherGangTerritory(name: string): React.ReactElement { - const power = AllGangs[name].power; - const clashVictoryChance = playerPower / (power + playerPower); - return ( - - {name} -
- Power: {formatNumber(power, 6)} -
- Territory: {formatTerritory(AllGangs[name].territory)}%
- Chance to win clash with this gang: {numeralWrapper.formatPercentage(clashVictoryChance, 3)} -
-
-
- ); - } - - const gangNames = Object.keys(AllGangs).filter((g) => g != props.gang.facName); +export function TerritorySubpage(): React.ReactElement { + const gang = useGang(); + const gangNames = Object.keys(AllGangs).filter((g) => g != gang.facName); return ( -
-

+ <> + This page shows how much territory your Gang controls. This statistic is listed as a percentage, which represents how much of the total territory you control.
@@ -76,59 +42,113 @@ export function TerritorySubpage(props: IProps): React.ReactElement { and wanted level. It is very beneficial to have high territory control.

-

- (props.gang.territoryWarfareEngaged = event.target.checked)} + + (gang.territoryWarfareEngaged = event.target.checked)} + /> + } + label={ + + Engaging in Territory Warfare sets your clash chance to 100%. Disengaging will cause your clash chance + to gradually decrease until it reaches 0%. + + } + > + Engage in Territory Warfare + + } /> -
-

- Territory Clash Chance: {numeralWrapper.formatPercentage(props.gang.territoryClashChance, 3)} -

-
- ? -
+ + + This percentage represents the chance you have of 'clashing' with with another gang. If you do not wish to + gain/lose territory, then keep this percentage at 0% by not engaging in territory warfare. + + } + > + + Territory Clash Chance: {numeralWrapper.formatPercentage(gang.territoryClashChance, 3)} + + +
- - (props.gang.notifyMemberDeath = event.target.checked)} + (gang.notifyMemberDeath = event.target.checked)} + /> + } + label={ + + If this is enabled, then you will receive a pop-up notifying you whenever one of your Gang Members dies + in a territory clash. + + } + > + Notify about Gang Member Deaths + + } /> -
-
-

+ + - {props.gang.facName} + {gang.facName}
- Power: {formatNumber(AllGangs[props.gang.facName].power, 6)} + Power: {formatNumber(AllGangs[gang.facName].power, 6)}
- Territory: {formatTerritory(AllGangs[props.gang.facName].territory)}% + Territory: {formatTerritory(AllGangs[gang.facName].territory)}%

- {gangNames.map((name) => otherGangTerritory(name))} -

-
-
+ + {gangNames.map((name) => ( + + ))} + + + ); +} +function formatTerritory(n: number): string { + const v = n * 100; + if (v <= 0) { + return formatNumber(0, 2); + } else if (v >= 100) { + return formatNumber(100, 2); + } else { + return formatNumber(v, 2); + } +} + +interface ITerritoryProps { + name: string; +} + +function OtherGangTerritory(props: ITerritoryProps): React.ReactElement { + const gang = useGang(); + const playerPower = AllGangs[gang.facName].power; + const power = AllGangs[props.name].power; + const clashVictoryChance = playerPower / (power + playerPower); + return ( + + {props.name} +
+ Power: {formatNumber(power, 6)} +
+ Territory: {formatTerritory(AllGangs[props.name].territory)}%
+ Chance to win clash with this gang: {numeralWrapper.formatPercentage(clashVictoryChance, 3)} +
+
+
); } diff --git a/src/Locations/ui/PurchaseServerModal.tsx b/src/Locations/ui/PurchaseServerModal.tsx index a8e8a94c2..d0f8ccf44 100644 --- a/src/Locations/ui/PurchaseServerModal.tsx +++ b/src/Locations/ui/PurchaseServerModal.tsx @@ -6,7 +6,6 @@ import { purchaseServer } from "../../Server/ServerPurchases"; import { numeralWrapper } from "../../ui/numeralFormat"; import { Money } from "../../ui/React/Money"; import { Modal } from "../../ui/React/Modal"; -import { StdButton } from "../../ui/React/StdButton"; import { use } from "../../ui/Context"; import Typography from "@mui/material/Typography"; import TextField from "@mui/material/TextField"; diff --git a/src/ui/React/BBAccordion.tsx b/src/ui/React/BBAccordion.tsx deleted file mode 100644 index 15d614171..000000000 --- a/src/ui/React/BBAccordion.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/** - * React component to create an accordion element - */ -import * as React from "react"; - -type IProps = { - headerClass?: string; // Override default class - headerContent: React.ReactElement; - panelClass?: string; // Override default class - panelContent: React.ReactElement; - panelInitiallyOpened?: boolean; - style?: string; -}; - -type IState = { - panelOpened: boolean; -}; - -export class BBAccordion extends React.Component { - constructor(props: IProps) { - super(props); - - this.handleHeaderClick = this.handleHeaderClick.bind(this); - - this.state = { - panelOpened: props.panelInitiallyOpened ? props.panelInitiallyOpened : false, - }; - } - - handleHeaderClick(): void { - this.setState({ - panelOpened: !this.state.panelOpened, - }); - } - - render(): React.ReactNode { - let className = "accordion-header"; - if (typeof this.props.headerClass === "string") { - className = this.props.headerClass; - } - - if (this.state.panelOpened) className += " active"; - - return ( - <> - - - - ); - } -} - -type IPanelProps = { - opened: boolean; - panelClass?: string; // Override default class - panelContent: React.ReactElement; -}; - -class AccordionPanel extends React.Component { - shouldComponentUpdate(nextProps: IPanelProps): boolean { - return this.props.opened || nextProps.opened; - } - - render(): React.ReactNode { - let className = "accordion-panel"; - if (typeof this.props.panelClass === "string") { - className = this.props.panelClass; - } - - if (!this.props.opened) return <>; - - return ( -
- {this.props.panelContent} -
- ); - } -} diff --git a/src/ui/React/MuiButton.tsx b/src/ui/React/MuiButton.tsx deleted file mode 100644 index 95357541a..000000000 --- a/src/ui/React/MuiButton.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Wrapper around material-ui's Button component that styles it with - * Bitburner's UI theme - */ - -import React from "react"; -import { Button, ButtonProps } from "@mui/material"; -import makeStyles from "@mui/styles/makeStyles"; -const useStyles = makeStyles({ - // Tries to emulate StdButton in buttons.scss - root: { - backgroundColor: "#555", - border: "1px solid #333", - color: "white", - margin: "5px", - padding: "3px 5px", - "&:hover": { - backgroundColor: "#666", - }, - - borderRadius: 0, - }, - textPrimary: { - color: "rgb( 144, 202, 249)", - }, - textSecondary: { - color: "rgb(244, 143, 177)", - }, - disabled: { - backgroundColor: "#333", - color: "#fff", - cursor: "default", - }, -}); - -export const MuiButton: React.FC = (props: ButtonProps) => { - return ( - - ); -}