No more player/router context

This commit is contained in:
Snarling 2022-09-12 18:00:09 -04:00
parent 83d357e758
commit a21b1029d7
56 changed files with 418 additions and 527 deletions

@ -2,7 +2,7 @@ import React, { useState } from "react";
import { BBCabinetRoot } from "./BBCabinet"; import { BBCabinetRoot } from "./BBCabinet";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { AlertEvents } from "../../ui/React/AlertManager"; import { AlertEvents } from "../../ui/React/AlertManager";
enum Page { enum Page {
@ -11,11 +11,10 @@ enum Page {
} }
export function ArcadeRoot(): React.ReactElement { export function ArcadeRoot(): React.ReactElement {
const player = use.Player();
const [page, setPage] = useState(Page.None); const [page, setPage] = useState(Page.None);
function mbBurner2000(): void { function mbBurner2000(): void {
if (player.sourceFileLvl(1) === 0) { if (Player.sourceFileLvl(1) === 0) {
AlertEvents.emit("This machine is broken."); AlertEvents.emit("This machine is broken.");
} else { } else {
setPage(Page.Megabyteburner2000); setPage(Page.Megabyteburner2000);

@ -1,6 +1,6 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
const metaBB = "https://bitburner-official.github.io/bitburner-legacy/"; const metaBB = "https://bitburner-official.github.io/bitburner-legacy/";
@ -12,11 +12,10 @@ const style = {
}; };
export function BBCabinetRoot(): React.ReactElement { export function BBCabinetRoot(): React.ReactElement {
const player = use.Player();
useEffect(() => { useEffect(() => {
window.addEventListener("message", function (this: Window, ev: MessageEvent<boolean>) { window.addEventListener("message", function (this: Window, ev: MessageEvent<boolean>) {
if (ev.isTrusted && ev.origin == "https://bitburner-official.github.io" && ev.data) { if (ev.isTrusted && ev.origin == "https://bitburner-official.github.io" && ev.data) {
player.giveExploit(Exploit.TrueRecursion); Player.giveExploit(Exploit.TrueRecursion);
} }
}); });
}); });

@ -10,8 +10,6 @@ import { PurchasedAugmentations } from "./PurchasedAugmentations";
import { SourceFilesElement } from "./SourceFiles"; import { SourceFilesElement } from "./SourceFiles";
import { canGetBonus } from "../../ExportBonus"; import { canGetBonus } from "../../ExportBonus";
import { use } from "../../ui/Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@ -86,7 +84,6 @@ interface IProps {
export function AugmentationsRoot(props: IProps): React.ReactElement { export function AugmentationsRoot(props: IProps): React.ReactElement {
const [installOpen, setInstallOpen] = useState(false); const [installOpen, setInstallOpen] = useState(false);
const player = use.Player();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {
setRerender((o) => !o); setRerender((o) => !o);
@ -179,7 +176,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
<Box sx={{ display: "grid", width: "100%", gridTemplateColumns: "1fr 1fr" }}> <Box sx={{ display: "grid", width: "100%", gridTemplateColumns: "1fr 1fr" }}>
<Tooltip title={<Typography>'I never asked for this'</Typography>}> <Tooltip title={<Typography>'I never asked for this'</Typography>}>
<span> <span>
<Button sx={{ width: "100%" }} disabled={player.queuedAugmentations.length === 0} onClick={doInstall}> <Button sx={{ width: "100%" }} disabled={Player.queuedAugmentations.length === 0} onClick={doInstall}>
Install Augmentations Install Augmentations
</Button> </Button>
</span> </span>
@ -191,7 +188,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
</Tooltip> </Tooltip>
</Box> </Box>
</Paper> </Paper>
{player.queuedAugmentations.length > 0 ? ( {Player.queuedAugmentations.length > 0 ? (
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}> <Box sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<PurchasedAugmentations /> <PurchasedAugmentations />
<PlayerMultipliers /> <PlayerMultipliers />
@ -208,8 +205,8 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
my: 1, my: 1,
display: "grid", display: "grid",
gridTemplateColumns: `repeat(${ gridTemplateColumns: `repeat(${
+!!((player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) + +!!((Player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) +
+!!(player.entropy > 0) +!!(Player.entropy > 0)
}, 1fr)`, }, 1fr)`,
gap: 1, gap: 1,
}} }}

@ -12,14 +12,13 @@ import Tooltip from "@mui/material/Tooltip";
import React, { useState } from "react"; import React, { useState } from "react";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums"; import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { StaticAugmentations } from "../StaticAugmentations"; import { StaticAugmentations } from "../StaticAugmentations";
import { AugmentationNames } from "../data/AugmentationNames"; import { AugmentationNames } from "../data/AugmentationNames";
export function InstalledAugmentations(): React.ReactElement { export function InstalledAugmentations(): React.ReactElement {
const setRerender = useState(true)[1]; const setRerender = useState(true)[1];
const player = use.Player(); const sourceAugs = Player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
const sourceAugs = player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
const [selectedAug, setSelectedAug] = useState(sourceAugs[0]); const [selectedAug, setSelectedAug] = useState(sourceAugs[0]);

@ -6,7 +6,7 @@ import { purchaseAugmentation } from "../../Faction/FactionHelpers";
import { isRepeatableAug } from "../AugmentationHelpers"; import { isRepeatableAug } from "../AugmentationHelpers";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -22,10 +22,8 @@ export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
return <></>; return <></>;
} }
const player = use.Player();
function buy(): void { function buy(): void {
if (!isRepeatableAug(props.aug as Augmentation) && player.hasAugmentation(props.aug as Augmentation)) { if (!isRepeatableAug(props.aug as Augmentation) && Player.hasAugmentation(props.aug as Augmentation)) {
return; return;
} }

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { EventEmitter } from "../../utils/EventEmitter"; import { EventEmitter } from "../../utils/EventEmitter";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -8,10 +8,9 @@ import Button from "@mui/material/Button";
export const BitFlumeEvent = new EventEmitter<[]>(); export const BitFlumeEvent = new EventEmitter<[]>();
export function BitFlumeModal(): React.ReactElement { export function BitFlumeModal(): React.ReactElement {
const router = use.Router();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
function flume(): void { function flume(): void {
router.toBitVerse(true, false); Router.toBitVerse(true, false);
setOpen(false); setOpen(false);
} }

@ -5,7 +5,7 @@ import { uniqueId } from "lodash";
import React from "react"; import React from "react";
import { SpecialServers } from "../../Server/data/SpecialServers"; import { SpecialServers } from "../../Server/data/SpecialServers";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context"; import { Player } from "../../ui/Player";
import { StatsRow } from "../../ui/React/StatsRow"; import { StatsRow } from "../../ui/React/StatsRow";
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode"; import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
import { IBitNodeMultipliers } from "../BitNodeMultipliers"; import { IBitNodeMultipliers } from "../BitNodeMultipliers";
@ -33,13 +33,12 @@ export function BitnodeMultiplierDescription({ n, level }: IProps): React.ReactE
} }
export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => { export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => {
const player = use.Player();
// If a level argument has been provided, use that as the multiplier level // If a level argument has been provided, use that as the multiplier level
// If not, then we have to assume that we want the next level up from the // If not, then we have to assume that we want the next level up from the
// current node's source file, so we get the min of that, the SF's max level, // current node's source file, so we get the min of that, the SF's max level,
// or if it's BN12, ∞ // or if it's BN12, ∞
const maxSfLevel = n === 12 ? Infinity : 3; const maxSfLevel = n === 12 ? Infinity : 3;
const mults = getBitNodeMultipliers(n, level ?? Math.min(player.sourceFileLvl(n) + 1, maxSfLevel)); const mults = getBitNodeMultipliers(n, level ?? Math.min(Player.sourceFileLvl(n) + 1, maxSfLevel));
return ( return (
<Box sx={{ columnCount: 2, columnGap: 1, mb: -2 }}> <Box sx={{ columnCount: 2, columnGap: 1, mb: -2 }}>
@ -277,8 +276,7 @@ function InfiltrationMults({ mults }: IMultsProps): React.ReactElement {
} }
function BladeburnerMults({ mults }: IMultsProps): React.ReactElement { function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
const player = use.Player(); if (!Player.canAccessBladeburner()) return <></>;
if (!player.canAccessBladeburner()) return <></>;
if (mults.BladeburnerRank === 0) { if (mults.BladeburnerRank === 0) {
const rows: IBNMultRows = { const rows: IBNMultRows = {
@ -297,8 +295,7 @@ function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
} }
function StanekMults({ mults }: IMultsProps): React.ReactElement { function StanekMults({ mults }: IMultsProps): React.ReactElement {
const player = use.Player(); if (!Player.canAccessCotMG()) return <></>;
if (!player.canAccessCotMG()) return <></>;
const extraSize = mults.StaneksGiftExtraSize.toFixed(3); const extraSize = mults.StaneksGiftExtraSize.toFixed(3);
const rows: IBNMultRows = { const rows: IBNMultRows = {
@ -313,8 +310,7 @@ function StanekMults({ mults }: IMultsProps): React.ReactElement {
} }
function GangMults({ mults }: IMultsProps): React.ReactElement { function GangMults({ mults }: IMultsProps): React.ReactElement {
const player = use.Player(); if (Player.bitNodeN !== 2 && Player.sourceFileLvl(2) <= 0) return <></>;
if (player.bitNodeN !== 2 && player.sourceFileLvl(2) <= 0) return <></>;
const rows: IBNMultRows = { const rows: IBNMultRows = {
GangSoftcap: { GangSoftcap: {
@ -328,8 +324,7 @@ function GangMults({ mults }: IMultsProps): React.ReactElement {
} }
function CorporationMults({ mults }: IMultsProps): React.ReactElement { function CorporationMults({ mults }: IMultsProps): React.ReactElement {
const player = use.Player(); if (!Player.canAccessCorporation()) return <></>;
if (!player.canAccessCorporation()) return <></>;
if (mults.CorporationSoftcap < 0.15) { if (mults.CorporationSoftcap < 0.15) {
const rows: IBNMultRows = { const rows: IBNMultRows = {

@ -1,10 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { IRouter } from "../../ui/Router";
import { BitNodes } from "../BitNode"; import { BitNodes } from "../BitNode";
import { enterBitNode } from "../../RedPill";
import { PortalModal } from "./PortalModal"; import { PortalModal } from "./PortalModal";
import { CinematicText } from "../../ui/React/CinematicText"; import { CinematicText } from "../../ui/React/CinematicText";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import makeStyles from "@mui/styles/makeStyles"; import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles"; import createStyles from "@mui/styles/createStyles";
import IconButton from "@mui/material/IconButton"; import IconButton from "@mui/material/IconButton";
@ -46,7 +44,6 @@ interface IPortalProps {
level: number; level: number;
destroyedBitNode: number; destroyedBitNode: number;
flume: boolean; flume: boolean;
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
} }
function BitNodePortal(props: IPortalProps): React.ReactElement { function BitNodePortal(props: IPortalProps): React.ReactElement {
const [portalOpen, setPortalOpen] = useState(false); const [portalOpen, setPortalOpen] = useState(false);
@ -105,7 +102,6 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
onClose={() => setPortalOpen(false)} onClose={() => setPortalOpen(false)}
n={props.n} n={props.n}
level={props.level} level={props.level}
enter={props.enter}
destroyedBitNode={props.destroyedBitNode} destroyedBitNode={props.destroyedBitNode}
flume={props.flume} flume={props.flume}
/> />
@ -118,13 +114,10 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
interface IProps { interface IProps {
flume: boolean; flume: boolean;
quick: boolean; quick: boolean;
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
} }
export function BitverseRoot(props: IProps): React.ReactElement { export function BitverseRoot(props: IProps): React.ReactElement {
const player = use.Player(); const destroyed = Player.bitNodeN;
const enter = enterBitNode;
const destroyed = player.bitNodeN;
const [destroySequence, setDestroySequence] = useState(!props.quick); const [destroySequence, setDestroySequence] = useState(!props.quick);
if (destroySequence) { if (destroySequence) {
@ -158,7 +151,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
} }
const nextSourceFileLvl = (n: number): number => { const nextSourceFileLvl = (n: number): number => {
const lvl = player.sourceFileLvl(n); const lvl = Player.sourceFileLvl(n);
if (n !== destroyed) { if (n !== destroyed) {
return lvl; return lvl;
} }
@ -181,7 +174,6 @@ export function BitverseRoot(props: IProps): React.ReactElement {
key={node.number} key={node.number}
n={node.number} n={node.number}
level={nextSourceFileLvl(node.number)} level={nextSourceFileLvl(node.number)}
enter={enter}
flume={props.flume} flume={props.flume}
destroyedBitNode={destroyed} destroyedBitNode={destroyed}
/> />
@ -234,19 +226,19 @@ export function BitverseRoot(props: IProps): React.ReactElement {
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={n(13)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={n(13)} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={n(10)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={n(11)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={n(10)} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={n(11)} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={n(9)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={n(12)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={n(9)} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={n(12)} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={n(7)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={n(8)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={n(7)} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={n(8)} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={n(5)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={n(6)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={n(5)} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={n(6)} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={n(1)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={n(2)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={n(3)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={n(4)} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={n(1)} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={n(2)} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={n(3)} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={n(4)} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography> <Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
<br /> <br />

@ -1,8 +1,7 @@
import React from "react"; import React from "react";
import { enterBitNode } from "../../RedPill";
import { BitNodes } from "../BitNode"; import { BitNodes } from "../BitNode";
import { IRouter } from "../../ui/Router";
import { use } from "../../ui/Context";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -15,11 +14,9 @@ interface IProps {
level: number; level: number;
destroyedBitNode: number; destroyedBitNode: number;
flume: boolean; flume: boolean;
enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void;
} }
export function PortalModal(props: IProps): React.ReactElement { export function PortalModal(props: IProps): React.ReactElement {
const router = use.Router();
const bitNodeKey = "BitNode" + props.n; const bitNodeKey = "BitNode" + props.n;
const bitNode = BitNodes[bitNodeKey]; const bitNode = BitNodes[bitNodeKey];
if (bitNode == null) throw new Error(`Could not find BitNode object for number: ${props.n}`); if (bitNode == null) throw new Error(`Could not find BitNode object for number: ${props.n}`);
@ -48,7 +45,7 @@ export function PortalModal(props: IProps): React.ReactElement {
aria-label={`enter-bitnode-${bitNode.number.toString()}`} aria-label={`enter-bitnode-${bitNode.number.toString()}`}
autoFocus={true} autoFocus={true}
onClick={() => { onClick={() => {
props.enter(router, props.flume, props.destroyedBitNode, props.n); enterBitNode(props.flume, props.destroyedBitNode, props.n);
props.onClose(); props.onClose();
}} }}
> >

@ -2,7 +2,6 @@ import React from "react";
import { IAction } from "../IAction"; import { IAction } from "../IAction";
import { IBladeburner } from "../IBladeburner"; import { IBladeburner } from "../IBladeburner";
import { BladeburnerConstants } from "../data/Constants"; import { BladeburnerConstants } from "../data/Constants";
import { use } from "../../ui/Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@ -19,8 +18,6 @@ interface IProps {
} }
export function ActionLevel({ action, isActive, bladeburner, rerender }: IProps): React.ReactElement { export function ActionLevel({ action, isActive, bladeburner, rerender }: IProps): React.ReactElement {
const player = use.Player();
const canIncrease = action.level < action.maxLevel; const canIncrease = action.level < action.maxLevel;
const canDecrease = action.level > 1; const canDecrease = action.level > 1;

@ -3,7 +3,7 @@ import { BlackOpList } from "./BlackOpList";
import { IBladeburner } from "../IBladeburner"; import { IBladeburner } from "../IBladeburner";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { BlackOperationNames } from "../data/BlackOperationNames"; import { BlackOperationNames } from "../data/BlackOperationNames";
import { Button } from "@mui/material"; import { Button } from "@mui/material";
import { CorruptableText } from "../../ui/React/CorruptableText"; import { CorruptableText } from "../../ui/React/CorruptableText";
@ -13,7 +13,6 @@ interface IProps {
} }
export function BlackOpPage(props: IProps): React.ReactElement { export function BlackOpPage(props: IProps): React.ReactElement {
const router = use.Router();
return ( return (
<> <>
<Typography> <Typography>
@ -31,7 +30,7 @@ export function BlackOpPage(props: IProps): React.ReactElement {
losses. losses.
</Typography> </Typography>
{props.bladeburner.blackops[BlackOperationNames.OperationDaedalus] ? ( {props.bladeburner.blackops[BlackOperationNames.OperationDaedalus] ? (
<Button sx={{ my: 1, p: 1 }} onClick={() => router.toBitVerse(false, false)}> <Button sx={{ my: 1, p: 1 }} onClick={() => Router.toBitVerse(false, false)}>
<CorruptableText content="Destroy w0rld_d34mon"></CorruptableText> <CorruptableText content="Destroy w0rld_d34mon"></CorruptableText>
</Button> </Button>
) : ( ) : (

@ -1,11 +1,10 @@
import React from "react"; import React from "react";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { CinematicText } from "../../ui/React/CinematicText"; import { CinematicText } from "../../ui/React/CinematicText";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
export function BladeburnerCinematic(): React.ReactElement { export function BladeburnerCinematic(): React.ReactElement {
const router = use.Router();
return ( return (
<CinematicText <CinematicText
lines={[ lines={[
@ -32,7 +31,7 @@ export function BladeburnerCinematic(): React.ReactElement {
"investigating and dealing with Synthoid threats.", "investigating and dealing with Synthoid threats.",
]} ]}
onDone={() => { onDone={() => {
router.toTerminal(); Router.toTerminal();
dialogBoxCreate( dialogBoxCreate(
`Visit the National Security Agency (NSA) to apply for their ${FactionNames.Bladeburners} ` + `Visit the National Security Agency (NSA) to apply for their ${FactionNames.Bladeburners} ` +
"division! You will need 100 of each combat stat before doing this.", "division! You will need 100 of each combat stat before doing this.",

@ -3,12 +3,10 @@ import { Stats } from "./Stats";
import { Console } from "./Console"; import { Console } from "./Console";
import { AllPages } from "./AllPages"; import { AllPages } from "./AllPages";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
export function BladeburnerRoot(): React.ReactElement { export function BladeburnerRoot(): React.ReactElement {
const player = use.Player();
const router = use.Router();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {
setRerender((old) => !old); setRerender((old) => !old);
@ -19,8 +17,8 @@ export function BladeburnerRoot(): React.ReactElement {
return () => clearInterval(id); return () => clearInterval(id);
}, []); }, []);
const bladeburner = player.bladeburner; const bladeburner = Player.bladeburner;
if (bladeburner === null) return <></>; if (!bladeburner) return <></>;
return ( return (
<Box display="flex" flexDirection="column"> <Box display="flex" flexDirection="column">
<Box sx={{ display: "grid", gridTemplateColumns: "4fr 8fr", p: 1 }}> <Box sx={{ display: "grid", gridTemplateColumns: "4fr 8fr", p: 1 }}>

@ -2,7 +2,7 @@ import React from "react";
import { IBladeburner } from "../IBladeburner"; import { IBladeburner } from "../IBladeburner";
import { BlackOperation } from "../BlackOperation"; import { BlackOperation } from "../BlackOperation";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
@ -13,7 +13,6 @@ interface IProps {
rerender: () => void; rerender: () => void;
} }
export function StartButton(props: IProps): React.ReactElement { export function StartButton(props: IProps): React.ReactElement {
const player = use.Player();
const action = props.bladeburner.getActionObject({ name: props.name, type: props.type }); const action = props.bladeburner.getActionObject({ name: props.name, type: props.type });
if (action == null) { if (action == null) {
throw new Error("Failed to get Operation Object for: " + props.name); throw new Error("Failed to get Operation Object for: " + props.name);
@ -33,7 +32,7 @@ export function StartButton(props: IProps): React.ReactElement {
if (disabled) return; if (disabled) return;
props.bladeburner.action.type = props.type; props.bladeburner.action.type = props.type;
props.bladeburner.action.name = props.name; props.bladeburner.action.name = props.name;
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true)) player.finishWork(true); if (!Player.hasAugmentation(AugmentationNames.BladesSimulacrum, true)) Player.finishWork(true);
props.bladeburner.startAction(props.bladeburner.action); props.bladeburner.startAction(props.bladeburner.action);
props.rerender(); props.rerender();
} }

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import { Company } from "../Company"; import { Company } from "../Company";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -14,9 +14,8 @@ interface IProps {
} }
export function QuitJobModal(props: IProps): React.ReactElement { export function QuitJobModal(props: IProps): React.ReactElement {
const player = use.Player();
function quit(): void { function quit(): void {
player.quitJob(props.locName); Player.quitJob(props.locName);
props.onQuit(); props.onQuit();
props.onClose(); props.onClose();
} }

@ -1,5 +1,4 @@
import { Industry } from "./Industry"; import { Industry } from "./Industry";
import { IPlayer } from "../PersonObjects/IPlayer";
import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades"; import { CorporationUnlockUpgrade } from "./data/CorporationUnlockUpgrades";
import { CorporationUpgrade } from "./data/CorporationUpgrades"; import { CorporationUpgrade } from "./data/CorporationUpgrades";
import { CorporationState } from "./CorporationState"; import { CorporationState } from "./CorporationState";
@ -36,7 +35,7 @@ export interface ICorporation {
addFunds(amt: number): void; addFunds(amt: number): void;
getState(): string; getState(): string;
storeCycles(numCycles: number): void; storeCycles(numCycles: number): void;
process(player: IPlayer): void; process(): void;
determineValuation(): void; determineValuation(): void;
determineCycleValuation(): number; determineCycleValuation(): number;
getTargetSharePrice(): number; getTargetSharePrice(): number;
@ -56,7 +55,7 @@ export interface ICorporation {
getEmployeeEffMultiplier(): number; getEmployeeEffMultiplier(): number;
getSalesMultiplier(): number; getSalesMultiplier(): number;
getScientificResearchMultiplier(): number; getScientificResearchMultiplier(): number;
getStarterGuide(player: IPlayer): void; getStarterGuide(): void;
updateDividendTax(): void; updateDividendTax(): void;
getCycleDividends(): number; getCycleDividends(): number;
toJSON(): IReviverValue; toJSON(): IReviverValue;

@ -6,7 +6,7 @@ import { IIndustry } from "../IIndustry";
import { MainPanel } from "./MainPanel"; import { MainPanel } from "./MainPanel";
import { Industries } from "../IndustryData"; import { Industries } from "../IndustryData";
import { ExpandIndustryTab } from "./ExpandIndustryTab"; import { ExpandIndustryTab } from "./ExpandIndustryTab";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { Context } from "./Context"; import { Context } from "./Context";
import { Overview } from "./Overview"; import { Overview } from "./Overview";
@ -14,8 +14,7 @@ import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab"; import Tab from "@mui/material/Tab";
export function CorporationRoot(): React.ReactElement { export function CorporationRoot(): React.ReactElement {
const player = use.Player(); const corporation = Player.corporation;
const corporation = player.corporation;
if (corporation === null) return <></>; if (corporation === null) return <></>;
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {

@ -7,7 +7,6 @@ import { IndustryOverview } from "./IndustryOverview";
import { IndustryWarehouse } from "./IndustryWarehouse"; import { IndustryWarehouse } from "./IndustryWarehouse";
import { Warehouse } from "../Warehouse"; import { Warehouse } from "../Warehouse";
import { OfficeSpace } from "../OfficeSpace"; import { OfficeSpace } from "../OfficeSpace";
import { use } from "../../ui/Context";
import { useCorporation, useDivision } from "./Context"; import { useCorporation, useDivision } from "./Context";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
@ -19,7 +18,6 @@ interface IProps {
} }
export function Industry(props: IProps): React.ReactElement { export function Industry(props: IProps): React.ReactElement {
const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const division = useDivision(); const division = useDivision();
return ( return (

@ -21,7 +21,7 @@ import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFuncti
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { MoneyRate } from "../../ui/React/MoneyRate"; import { MoneyRate } from "../../ui/React/MoneyRate";
import { StatsTable } from "../../ui/React/StatsTable"; import { StatsTable } from "../../ui/React/StatsTable";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { useCorporation } from "./Context"; import { useCorporation } from "./Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@ -34,7 +34,6 @@ interface IProps {
rerender: () => void; rerender: () => void;
} }
export function Overview({ rerender }: IProps): React.ReactElement { export function Overview({ rerender }: IProps): React.ReactElement {
const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const profit: number = corp.revenue - corp.expenses; const profit: number = corp.revenue - corp.expenses;
@ -100,7 +99,7 @@ export function Overview({ rerender }: IProps): React.ReactElement {
</Typography> </Typography>
} }
> >
<Button onClick={() => corp.getStarterGuide(player)}>Getting Started Guide</Button> <Button onClick={() => corp.getStarterGuide()}>Getting Started Guide</Button>
</Tooltip> </Tooltip>
{corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />} {corp.public ? <PublicButtons rerender={rerender} /> : <PrivateButtons rerender={rerender} />}
<BribeButton /> <BribeButton />
@ -240,12 +239,11 @@ function PublicButtons({ rerender }: IPublicButtonsProps): React.ReactElement {
} }
function BribeButton(): React.ReactElement { function BribeButton(): React.ReactElement {
const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const canBribe = const canBribe =
corp.valuation >= CorporationConstants.BribeThreshold && corp.valuation >= CorporationConstants.BribeThreshold &&
player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0; Player.factions.filter((f) => Factions[f].getInfo().offersWork()).length > 0;
function openBribe(): void { function openBribe(): void {
if (!canBribe) return; if (!canBribe) return;

@ -4,7 +4,7 @@ import { CorporationConstants } from "../../data/Constants";
import { numeralWrapper } from "../../../ui/numeralFormat"; import { numeralWrapper } from "../../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { use } from "../../../ui/Context"; import { Player } from "../../../Player";
import { useCorporation } from "../Context"; import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -19,11 +19,10 @@ interface IProps {
} }
export function BribeFactionModal(props: IProps): React.ReactElement { export function BribeFactionModal(props: IProps): React.ReactElement {
const player = use.Player(); const factions = Player.factions.filter((name: string) => {
const factions = player.factions.filter((name: string) => {
const info = Factions[name].getInfo(); const info = Factions[name].getInfo();
if (!info.offersWork()) return false; if (!info.offersWork()) return false;
if (player.hasGangWith(name)) return false; if (Player.hasGangWith(name)) return false;
return true; return true;
}); });
const corp = useCorporation(); const corp = useCorporation();
@ -77,7 +76,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
{factions.map((name: string) => { {factions.map((name: string) => {
const info = Factions[name].getInfo(); const info = Factions[name].getInfo();
if (!info.offersWork()) return; if (!info.offersWork()) return;
if (player.hasGangWith(name)) return; if (Player.hasGangWith(name)) return;
return ( return (
<MenuItem key={name} value={name}> <MenuItem key={name} value={name}>
{name} {name}

@ -1,7 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { numeralWrapper } from "../../../ui/numeralFormat"; import { numeralWrapper } from "../../../ui/numeralFormat";
import { use } from "../../../ui/Context"; import { Player } from "../../../Player";
import { useCorporation } from "../Context"; import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -19,7 +19,6 @@ interface IProps {
// Create a popup that lets the player buyback shares // Create a popup that lets the player buyback shares
// This is created when the player clicks the "Buyback Shares" button in the overview panel // This is created when the player clicks the "Buyback Shares" button in the overview panel
export function BuybackSharesModal(props: IProps): React.ReactElement { export function BuybackSharesModal(props: IProps): React.ReactElement {
const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const [shares, setShares] = useState<number>(NaN); const [shares, setShares] = useState<number>(NaN);
@ -30,7 +29,7 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
isNaN(shares) || isNaN(shares) ||
shares <= 0 || shares <= 0 ||
shares > corp.issuedShares || shares > corp.issuedShares ||
shares * buybackPrice > player.money; shares * buybackPrice > Player.money;
function buy(): void { function buy(): void {
if (disabled) return; if (disabled) return;

@ -2,7 +2,8 @@ import React, { useState } from "react";
import { Money } from "../../../ui/React/Money"; import { Money } from "../../../ui/React/Money";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { use } from "../../../ui/Context"; import { Router } from "../../../ui/GameRoot";
import { Player } from "../../../Player";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
@ -13,10 +14,8 @@ interface IProps {
} }
export function CreateCorporationModal(props: IProps): React.ReactElement { export function CreateCorporationModal(props: IProps): React.ReactElement {
const player = use.Player(); const canSelfFund = Player.canAfford(150e9);
const router = use.Router(); if (!Player.canAccessCorporation() || Player.hasCorporation()) {
const canSelfFund = player.canAfford(150e9);
if (!player.canAccessCorporation() || player.hasCorporation()) {
props.onClose(); props.onClose();
return <></>; return <></>;
} }
@ -35,11 +34,11 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
return; return;
} }
player.startCorporation(name); Player.startCorporation(name);
player.loseMoney(150e9, "corporation"); Player.loseMoney(150e9, "corporation");
props.onClose(); props.onClose();
router.toCorporation(); Router.toCorporation();
} }
function seed(): void { function seed(): void {
@ -47,17 +46,17 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
return; return;
} }
player.startCorporation(name, 500e6); Player.startCorporation(name, 500e6);
props.onClose(); props.onClose();
router.toCorporation(); Router.toCorporation();
} }
return ( return (
<Modal open={props.open} onClose={props.onClose}> <Modal open={props.open} onClose={props.onClose}>
<Typography> <Typography>
Would you like to start a corporation? This will require $150b for registration and initial funding.{" "} Would you like to start a corporation? This will require $150b for registration and initial funding.{" "}
{player.bitNodeN === 3 && {Player.bitNodeN === 3 &&
`This $150b `This $150b
can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million can either be self-funded, or you can obtain the seed money from the government in exchange for 500 million
shares`} shares`}
@ -66,7 +65,7 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
If you would like to start one, please enter a name for your corporation below: If you would like to start one, please enter a name for your corporation below:
</Typography> </Typography>
<TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} /> <TextField autoFocus={true} placeholder="Corporation Name" onChange={onChange} value={name} />
{player.bitNodeN === 3 && ( {Player.bitNodeN === 3 && (
<Button onClick={seed} disabled={name == ""}> <Button onClick={seed} disabled={name == ""}>
Use seed money Use seed money
</Button> </Button>

@ -2,7 +2,6 @@ import React, { useState } from "react";
import { numeralWrapper } from "../../../ui/numeralFormat"; import { numeralWrapper } from "../../../ui/numeralFormat";
import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { use } from "../../../ui/Context";
import { useCorporation } from "../Context"; import { useCorporation } from "../Context";
import { ICorporation } from "../../ICorporation"; import { ICorporation } from "../../ICorporation";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -20,7 +19,6 @@ interface IProps {
// Create a popup that lets the player sell Corporation shares // Create a popup that lets the player sell Corporation shares
// This is created when the player clicks the "Sell Shares" button in the overview panel // This is created when the player clicks the "Sell Shares" button in the overview panel
export function SellSharesModal(props: IProps): React.ReactElement { export function SellSharesModal(props: IProps): React.ReactElement {
const player = use.Player();
const corp = useCorporation(); const corp = useCorporation();
const [shares, setShares] = useState<number>(NaN); const [shares, setShares] = useState<number>(NaN);

@ -1,5 +1,5 @@
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player } from "../Player";
import { IPerson } from "../PersonObjects/IPerson"; import { IPerson } from "../PersonObjects/IPerson";
import { WorkerScript } from "../Netscript/WorkerScript"; import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/WorkType";
@ -101,11 +101,11 @@ export class Crime {
this.kills = params.kills ? params.kills : 0; this.kills = params.kills ? params.kills : 0;
} }
commit(p: IPlayer, div = 1, workerScript: WorkerScript | null = null): number { commit(div = 1, workerScript: WorkerScript | null = null): number {
if (div <= 0) { if (div <= 0) {
div = 1; div = 1;
} }
p.startWork( Player.startWork(
new CrimeWork({ new CrimeWork({
crimeType: this.type, crimeType: this.type,
singularity: workerScript !== null, singularity: workerScript !== null,

@ -1,16 +1,15 @@
import React from "react"; import React from "react";
import { use } from "../ui/Context"; import { Player } from "../Player";
import { Exploit } from "./Exploit"; import { Exploit } from "./Exploit";
const getComputedStyle = window.getComputedStyle; const getComputedStyle = window.getComputedStyle;
export function Unclickable(): React.ReactElement { export function Unclickable(): React.ReactElement {
const player = use.Player();
function unclickable(event: React.MouseEvent<HTMLDivElement>): void { function unclickable(event: React.MouseEvent<HTMLDivElement>): void {
if (!event.target || !(event.target instanceof Element)) return; if (!event.target || !(event.target instanceof Element)) return;
const display = getComputedStyle(event.target).display; const display = getComputedStyle(event.target).display;
const visibility = getComputedStyle(event.target).visibility; const visibility = getComputedStyle(event.target).visibility;
if (display === "none" && visibility === "hidden" && event.isTrusted) player.giveExploit(Exploit.Unclickable); if (display === "none" && visibility === "hidden" && event.isTrusted) Player.giveExploit(Exploit.Unclickable);
} }
return ( return (

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { IMap } from "../types"; import { IMap } from "../types";
import { FactionNames } from "./data/FactionNames"; import { FactionNames } from "./data/FactionNames";
import { use } from "../ui/Context"; import { Router } from "../ui/GameRoot";
import { Option } from "./ui/Option"; import { Option } from "./ui/Option";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
@ -449,12 +449,11 @@ export const FactionInfos: IMap<FactionInfo> = {
special: true, special: true,
assignment: (): React.ReactElement => { assignment: (): React.ReactElement => {
const router = use.Router();
return ( return (
<Option <Option
buttonText={"Open Bladeburner headquarters"} buttonText={"Open Bladeburner headquarters"}
infoText={"You can gain reputation with bladeburner by completing contracts and operations."} infoText={"You can gain reputation with bladeburner by completing contracts and operations."}
onClick={() => router.toBladeburner()} onClick={() => Router.toBladeburner()}
/> />
); );
}, },
@ -499,7 +498,6 @@ export const FactionInfos: IMap<FactionInfo> = {
special: true, special: true,
keepOnInstall: true, keepOnInstall: true,
assignment: (): React.ReactElement => { assignment: (): React.ReactElement => {
const router = use.Router();
return ( return (
<Option <Option
buttonText={"Open Staneks Gift"} buttonText={"Open Staneks Gift"}
@ -507,7 +505,7 @@ export const FactionInfos: IMap<FactionInfo> = {
"Stanek's Gift is a powerful augmentation that powers up the stat you chose to boost." + "Stanek's Gift is a powerful augmentation that powers up the stat you chose to boost." +
"Gaining reputation with the Church of the Machine God can only be done by charging the gift." "Gaining reputation with the Church of the Machine God can only be done by charging the gift."
} }
onClick={() => router.toStaneksGift()} onClick={() => Router.toStaneksGift()}
/> />
); );
}, },

@ -3,7 +3,8 @@
*/ */
import React from "react"; import React from "react";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { KEY } from "../../utils/helpers/keyCodes"; import { KEY } from "../../utils/helpers/keyCodes";
@ -16,8 +17,6 @@ interface IProps {
} }
export function CreateGangModal(props: IProps): React.ReactElement { export function CreateGangModal(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const combatGangText = const combatGangText =
"This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " + "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " +
"Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " + "Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " +
@ -33,9 +32,9 @@ export function CreateGangModal(props: IProps): React.ReactElement {
} }
function createGang(): void { function createGang(): void {
player.startGang(props.facName, isHacking()); Player.startGang(props.facName, isHacking());
props.onClose(); props.onClose();
router.toGang(); Router.toGang();
} }
function onKeyUp(event: React.KeyboardEvent): void { function onKeyUp(event: React.KeyboardEvent): void {

@ -1,7 +1,8 @@
import { Button, Typography, Box, Paper, Tooltip } from "@mui/material"; import { Button, Typography, Box, Paper, Tooltip } from "@mui/material";
import React, { useState } from "react"; import React, { useState } from "react";
import { GangConstants } from "../../Gang/data/Constants"; import { GangConstants } from "../../Gang/data/Constants";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { Faction } from "../Faction"; import { Faction } from "../Faction";
import { CreateGangModal } from "./CreateGangModal"; import { CreateGangModal } from "./CreateGangModal";
@ -10,14 +11,12 @@ type IProps = {
}; };
export function GangButton({ faction }: IProps): React.ReactElement { export function GangButton({ faction }: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const [gangOpen, setGangOpen] = useState(false); const [gangOpen, setGangOpen] = useState(false);
if ( if (
!GangConstants.Names.includes(faction.name) || // not even a gang !GangConstants.Names.includes(faction.name) || // not even a gang
!player.isAwareOfGang() || // doesn't know about gang !Player.isAwareOfGang() || // doesn't know about gang
(player.inGang() && player.getGangName() !== faction.name) // already in another gang (Player.inGang() && Player.getGangName() !== faction.name) // already in another gang
) { ) {
return <></>; return <></>;
} }
@ -29,7 +28,7 @@ export function GangButton({ faction }: IProps): React.ReactElement {
description: "", description: "",
}; };
if (player.inGang()) { if (Player.inGang()) {
data = { data = {
enabled: true, enabled: true,
title: "Manage Gang", title: "Manage Gang",
@ -38,9 +37,9 @@ export function GangButton({ faction }: IProps): React.ReactElement {
}; };
} else { } else {
data = { data = {
enabled: player.canAccessGang(), enabled: Player.canAccessGang(),
title: "Create Gang", title: "Create Gang",
tooltip: !player.canAccessGang() ? ( tooltip: !Player.canAccessGang() ? (
<Typography>Unlocked when reaching {GangConstants.GangKarmaRequirement} karma</Typography> <Typography>Unlocked when reaching {GangConstants.GangKarmaRequirement} karma</Typography>
) : ( ) : (
"" ""
@ -51,8 +50,8 @@ export function GangButton({ faction }: IProps): React.ReactElement {
const manageGang = (): void => { const manageGang = (): void => {
// If player already has a gang, just go to the gang UI // If player already has a gang, just go to the gang UI
if (player.inGang()) { if (Player.inGang()) {
return router.toGang(); return Router.toGang();
} }
setGangOpen(true); setGangOpen(true);

@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import { joinFaction } from "../FactionHelpers"; import { joinFaction } from "../FactionHelpers";
import { Faction } from "../Faction"; import { Faction } from "../Faction";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { EventEmitter } from "../../utils/EventEmitter"; import { EventEmitter } from "../../utils/EventEmitter";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -11,11 +11,10 @@ export const InvitationEvent = new EventEmitter<[Faction]>();
export function InvitationModal(): React.ReactElement { export function InvitationModal(): React.ReactElement {
const [faction, setFaction] = useState<Faction | null>(null); const [faction, setFaction] = useState<Faction | null>(null);
const player = use.Player();
function join(): void { function join(): void {
if (faction === null) return; if (faction === null) return;
//Remove from invited factions //Remove from invited factions
const i = player.factionInvitations.findIndex((facName) => facName === faction.name); const i = Player.factionInvitations.findIndex((facName) => facName === faction.name);
if (i === -1) { if (i === -1) {
console.error("Could not find faction in Player.factionInvitations"); console.error("Could not find faction in Player.factionInvitations");
} }

@ -2,10 +2,9 @@ import React from "react";
import { OptionSwitch } from "../../ui/React/OptionSwitch"; import { OptionSwitch } from "../../ui/React/OptionSwitch";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { GameOptionsPage } from "./GameOptionsPage"; import { GameOptionsPage } from "./GameOptionsPage";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
export const GameplayPage = (): React.ReactElement => { export const GameplayPage = (): React.ReactElement => {
const player = use.Player();
return ( return (
<GameOptionsPage title="Gameplay"> <GameOptionsPage title="Gameplay">
<OptionSwitch <OptionSwitch
@ -53,7 +52,7 @@ export const GameplayPage = (): React.ReactElement => {
text="Suppress TIX messages" text="Suppress TIX messages"
tooltip={<>If this is set, the stock market will never create any popup.</>} tooltip={<>If this is set, the stock market will never create any popup.</>}
/> />
{player.bladeburner && ( {Player.bladeburner && (
<OptionSwitch <OptionSwitch
checked={Settings.SuppressBladeburnerPopup} checked={Settings.SuppressBladeburnerPopup}
onChange={(newValue) => (Settings.SuppressBladeburnerPopup = newValue)} onChange={(newValue) => (Settings.SuppressBladeburnerPopup = newValue)}

@ -3,7 +3,7 @@ import { GangMemberTasks } from "./GangMemberTasks";
import { GangMemberUpgrade } from "./GangMemberUpgrade"; import { GangMemberUpgrade } from "./GangMemberUpgrade";
import { GangMemberUpgrades } from "./GangMemberUpgrades"; import { GangMemberUpgrades } from "./GangMemberUpgrades";
import { IAscensionResult } from "./IAscensionResult"; import { IAscensionResult } from "./IAscensionResult";
import { IPlayer } from "../PersonObjects/IPlayer"; import { Player } from "../Player";
import { IGang } from "./IGang"; import { IGang } from "./IGang";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { import {
@ -302,12 +302,14 @@ export class GangMember {
if (upg.mults.hack != null) this.hack_mult *= upg.mults.hack; if (upg.mults.hack != null) this.hack_mult *= upg.mults.hack;
} }
buyUpgrade(upg: GangMemberUpgrade, player: IPlayer, gang: IGang): boolean { buyUpgrade(upg: GangMemberUpgrade): boolean {
if (!Player.gang) throw new Error("Tried to buy a gang member upgrade when no gang was present");
// Prevent purchasing of already-owned upgrades // Prevent purchasing of already-owned upgrades
if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) return false; if (this.augmentations.includes(upg.name) || this.upgrades.includes(upg.name)) return false;
if (player.money < gang.getUpgradeCost(upg)) return false; if (Player.money < Player.gang.getUpgradeCost(upg)) return false;
player.loseMoney(gang.getUpgradeCost(upg), "gang"); Player.loseMoney(Player.gang.getUpgradeCost(upg), "gang");
if (upg.type === "g") { if (upg.type === "g") {
this.augmentations.push(upg.name); this.augmentations.push(upg.name);
} else { } else {

@ -19,7 +19,7 @@ import { GangMemberUpgrade } from "../GangMemberUpgrade";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { GangMember } from "../GangMember"; import { GangMember } from "../GangMember";
import { UpgradeType } from "../data/upgrades"; import { UpgradeType } from "../data/upgrades";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { StatsRow } from "../../ui/React/StatsRow"; import { StatsRow } from "../../ui/React/StatsRow";
@ -30,11 +30,10 @@ interface INextRevealProps {
function NextReveal(props: INextRevealProps): React.ReactElement { function NextReveal(props: INextRevealProps): React.ReactElement {
const gang = useGang(); const gang = useGang();
const player = use.Player();
const upgrades = Object.keys(GangMemberUpgrades) const upgrades = Object.keys(GangMemberUpgrades)
.filter((upgName: string) => { .filter((upgName: string) => {
const upg = GangMemberUpgrades[upgName]; const upg = GangMemberUpgrades[upgName];
if (player.money > gang.getUpgradeCost(upg)) return false; if (Player.money > gang.getUpgradeCost(upg)) return false;
if (upg.type !== props.type) return false; if (upg.type !== props.type) return false;
if (props.upgrades.includes(upgName)) return false; if (props.upgrades.includes(upgName)) return false;
return true; return true;
@ -68,9 +67,8 @@ interface IUpgradeButtonProps {
function UpgradeButton(props: IUpgradeButtonProps): React.ReactElement { function UpgradeButton(props: IUpgradeButtonProps): React.ReactElement {
const gang = useGang(); const gang = useGang();
const player = use.Player();
function onClick(): void { function onClick(): void {
props.member.buyUpgrade(props.upg, player, gang); props.member.buyUpgrade(props.upg);
props.rerender(); props.rerender();
} }
return ( return (
@ -91,7 +89,6 @@ interface IPanelProps {
function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement { function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement {
const gang = useGang(); const gang = useGang();
const player = use.Player();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
const [currentCategory, setCurrentCategory] = useState("Weapons"); const [currentCategory, setCurrentCategory] = useState("Weapons");
@ -103,7 +100,7 @@ function GangMemberUpgradePanel(props: IPanelProps): React.ReactElement {
return Object.keys(GangMemberUpgrades) return Object.keys(GangMemberUpgrades)
.filter((upgName: string) => { .filter((upgName: string) => {
const upg = GangMemberUpgrades[upgName]; const upg = GangMemberUpgrades[upgName];
if (player.money < gang.getUpgradeCost(upg)) return false; if (Player.money < gang.getUpgradeCost(upg)) return false;
if (upg.type !== type) return false; if (upg.type !== type) return false;
if (list.includes(upgName)) return false; if (list.includes(upgName)) return false;
return true; return true;

@ -5,17 +5,16 @@ import React, { useState, useEffect } from "react";
import { ManagementSubpage } from "./ManagementSubpage"; import { ManagementSubpage } from "./ManagementSubpage";
import { TerritorySubpage } from "./TerritorySubpage"; import { TerritorySubpage } from "./TerritorySubpage";
import { EquipmentsSubpage } from "./EquipmentsSubpage"; import { EquipmentsSubpage } from "./EquipmentsSubpage";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { Context } from "./Context"; import { Context } from "./Context";
import Tabs from "@mui/material/Tabs"; import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab"; import Tab from "@mui/material/Tab";
export function GangRoot(): React.ReactElement { export function GangRoot(): React.ReactElement {
const player = use.Player();
const gang = (function () { const gang = (function () {
if (player.gang === null) throw new Error("Gang should not be null"); if (Player.gang === null) throw new Error("Gang should not be null");
return player.gang; return Player.gang;
})(); })();
const [value, setValue] = React.useState(0); const [value, setValue] = React.useState(0);

@ -1,7 +1,8 @@
import { Button, Container, Paper, Typography } from "@mui/material"; import { Button, Container, Paper, Typography } from "@mui/material";
import React, { useState } from "react"; import React, { useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { BackwardGame } from "./BackwardGame"; import { BackwardGame } from "./BackwardGame";
import { BracketGame } from "./BracketGame"; import { BracketGame } from "./BracketGame";
import { BribeGame } from "./BribeGame"; import { BribeGame } from "./BribeGame";
@ -39,8 +40,6 @@ const minigames = [
]; ];
export function Game(props: IProps): React.ReactElement { export function Game(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const [level, setLevel] = useState(1); const [level, setLevel] = useState(1);
const [stage, setStage] = useState(Stage.Countdown); const [stage, setStage] = useState(Stage.Countdown);
const [results, setResults] = useState(""); const [results, setResults] = useState("");
@ -91,17 +90,17 @@ export function Game(props: IProps): React.ReactElement {
// Kill the player immediately if they use automation, so // Kill the player immediately if they use automation, so
// it's clear they're not meant to // it's clear they're not meant to
const damage = options?.automated const damage = options?.automated
? player.hp.current ? Player.hp.current
: props.StartingDifficulty * 3 * (player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 0.5 : 1); : props.StartingDifficulty * 3 * (Player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 0.5 : 1);
if (player.takeDamage(damage)) { if (Player.takeDamage(damage)) {
router.toCity(); Router.toCity();
return; return;
} }
setupNextGame(); setupNextGame();
} }
function cancel(): void { function cancel(): void {
router.toCity(); Router.toCity();
return; return;
} }

@ -1,7 +1,7 @@
import { Paper } from "@mui/material"; import { Paper } from "@mui/material";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { ProgressBar } from "../../ui/React/Progress"; import { ProgressBar } from "../../ui/React/Progress";
interface IProps { interface IProps {
@ -11,9 +11,8 @@ interface IProps {
} }
export function GameTimer(props: IProps): React.ReactElement { export function GameTimer(props: IProps): React.ReactElement {
const player = use.Player();
const [v, setV] = useState(100); const [v, setV] = useState(100);
const totalMillis = (player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.3 : 1) * props.millis; const totalMillis = (Player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.3 : 1) * props.millis;
const tick = 200; const tick = 200;
useEffect(() => { useEffect(() => {

@ -1,6 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Location } from "../../Locations/Location"; import { Location } from "../../Locations/Location";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { calculateDifficulty, calculateReward } from "../formulas/game"; import { calculateDifficulty, calculateReward } from "../formulas/game";
import { Game } from "./Game"; import { Game } from "./Game";
import { Intro } from "./Intro"; import { Intro } from "./Intro";
@ -9,17 +10,15 @@ interface IProps {
} }
export function InfiltrationRoot(props: IProps): React.ReactElement { export function InfiltrationRoot(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const [start, setStart] = useState(false); const [start, setStart] = useState(false);
if (props.location.infiltrationData === undefined) throw new Error("Trying to do infiltration on invalid location."); if (props.location.infiltrationData === undefined) throw new Error("Trying to do infiltration on invalid location.");
const startingSecurityLevel = props.location.infiltrationData.startingSecurityLevel; const startingSecurityLevel = props.location.infiltrationData.startingSecurityLevel;
const difficulty = calculateDifficulty(player, startingSecurityLevel); const difficulty = calculateDifficulty(Player, startingSecurityLevel);
const reward = calculateReward(player, startingSecurityLevel); const reward = calculateReward(Player, startingSecurityLevel);
function cancel(): void { function cancel(): void {
router.toCity(); Router.toCity();
} }
return ( return (

@ -3,7 +3,8 @@ import React, { useState } from "react";
import { FactionNames } from "../../Faction/data/FactionNames"; import { FactionNames } from "../../Faction/data/FactionNames";
import { inviteToFaction } from "../../Faction/FactionHelpers"; import { inviteToFaction } from "../../Faction/FactionHelpers";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Reputation } from "../../ui/React/Reputation"; import { Reputation } from "../../ui/React/Reputation";
import { formatNumber } from "../../utils/StringHelperFunctions"; import { formatNumber } from "../../utils/StringHelperFunctions";
@ -21,25 +22,23 @@ interface IProps {
} }
export function Victory(props: IProps): React.ReactElement { export function Victory(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const [faction, setFaction] = useState("none"); const [faction, setFaction] = useState("none");
function quitInfiltration(): void { function quitInfiltration(): void {
handleInfiltrators(); handleInfiltrators();
router.toCity(); Router.toCity();
} }
const soa = Factions[FactionNames.ShadowsOfAnarchy]; const soa = Factions[FactionNames.ShadowsOfAnarchy];
const repGain = calculateTradeInformationRepReward(player, props.Reward, props.MaxLevel, props.StartingDifficulty); const repGain = calculateTradeInformationRepReward(Player, props.Reward, props.MaxLevel, props.StartingDifficulty);
const moneyGain = calculateSellInformationCashReward(player, props.Reward, props.MaxLevel, props.StartingDifficulty); const moneyGain = calculateSellInformationCashReward(Player, props.Reward, props.MaxLevel, props.StartingDifficulty);
const infiltrationRepGain = calculateInfiltratorsRepReward(player, soa, props.StartingDifficulty); const infiltrationRepGain = calculateInfiltratorsRepReward(Player, soa, props.StartingDifficulty);
const isMemberOfInfiltrators = player.factions.includes(FactionNames.ShadowsOfAnarchy); const isMemberOfInfiltrators = Player.factions.includes(FactionNames.ShadowsOfAnarchy);
function sell(): void { function sell(): void {
handleInfiltrators(); handleInfiltrators();
player.gainMoney(moneyGain, "infiltration"); Player.gainMoney(moneyGain, "infiltration");
quitInfiltration(); quitInfiltration();
} }
@ -81,7 +80,7 @@ export function Victory(props: IProps): React.ReactElement {
<MenuItem key={"none"} value={"none"}> <MenuItem key={"none"} value={"none"}>
{"none"} {"none"}
</MenuItem> </MenuItem>
{player.factions {Player.factions
.filter((f) => Factions[f].getInfo().offersWork()) .filter((f) => Factions[f].getInfo().offersWork())
.map((f) => ( .map((f) => (
<MenuItem key={f} value={f}> <MenuItem key={f} value={f}>

@ -7,7 +7,7 @@ import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition"; import { CompanyPosition } from "../../Company/CompanyPosition";
import { getJobRequirementText } from "../../Company/GetJobRequirementText"; import { getJobRequirementText } from "../../Company/GetJobRequirementText";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@ -19,10 +19,8 @@ type IProps = {
}; };
export function ApplyToJobButton(props: IProps): React.ReactElement { export function ApplyToJobButton(props: IProps): React.ReactElement {
const player = use.Player();
function getJobRequirementTooltip(): string { function getJobRequirementTooltip(): string {
const pos = player.getNextCompanyPosition(props.company, props.entryPosType); const pos = Player.getNextCompanyPosition(props.company, props.entryPosType);
if (pos == null) { if (pos == null) {
return ""; return "";
} }

@ -12,8 +12,8 @@ import { Locations } from "../Locations";
import { Location } from "../Location"; import { Location } from "../Location";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import { IRouter } from "../../ui/Router"; import { Router } from "../../ui/GameRoot";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import { LocationType } from "../LocationTypeEnum"; import { LocationType } from "../LocationTypeEnum";
@ -37,19 +37,18 @@ const useStyles = makeStyles((theme: Theme) =>
}), }),
); );
function toLocation(router: IRouter, location: Location): void { function toLocation(location: Location): void {
if (location.name === LocationName.TravelAgency) { if (location.name === LocationName.TravelAgency) {
router.toTravel(); Router.toTravel();
} else if (location.name === LocationName.WorldStockExchange) { } else if (location.name === LocationName.WorldStockExchange) {
router.toStockMarket(); Router.toStockMarket();
} else { } else {
router.toLocation(location); Router.toLocation(location);
} }
} }
function LocationLetter(location: Location): React.ReactElement { function LocationLetter(location: Location): React.ReactElement {
location.types; location.types;
const router = use.Router();
const classes = useStyles(); const classes = useStyles();
let L = "X"; let L = "X";
if (location.types.includes(LocationType.Company)) L = "C"; if (location.types.includes(LocationType.Company)) L = "C";
@ -68,7 +67,7 @@ function LocationLetter(location: Location): React.ReactElement {
aria-label={location.name} aria-label={location.name}
key={location.name} key={location.name}
className={classes.location} className={classes.location}
onClick={() => toLocation(router, location)} onClick={() => toLocation(location)}
> >
<b>{L}</b> <b>{L}</b>
</span> </span>
@ -147,11 +146,10 @@ function ASCIICity(props: IProps): React.ReactElement {
} }
function ListCity(props: IProps): React.ReactElement { function ListCity(props: IProps): React.ReactElement {
const router = use.Router();
const locationButtons = props.city.locations.map((locName) => { const locationButtons = props.city.locations.map((locName) => {
return ( return (
<React.Fragment key={locName}> <React.Fragment key={locName}>
<Button onClick={() => toLocation(router, Locations[locName])}>{locName}</Button> <Button onClick={() => toLocation(Locations[locName])}>{locName}</Button>
<br /> <br />
</React.Fragment> </React.Fragment>
); );
@ -161,8 +159,7 @@ function ListCity(props: IProps): React.ReactElement {
} }
export function LocationCity(): React.ReactElement { export function LocationCity(): React.ReactElement {
const player = use.Player(); const city = Cities[Player.city];
const city = Cities[player.city];
return ( return (
<> <>
<Typography>{city.name}</Typography> <Typography>{city.name}</Typography>

@ -21,7 +21,8 @@ import * as posNames from "../../Company/data/companypositionnames";
import { Reputation } from "../../ui/React/Reputation"; import { Reputation } from "../../ui/React/Reputation";
import { Favor } from "../../ui/React/Favor"; import { Favor } from "../../ui/React/Favor";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { QuitJobModal } from "../../Company/ui/QuitJobModal"; import { QuitJobModal } from "../../Company/ui/QuitJobModal";
import { CompanyWork } from "../../Work/CompanyWork"; import { CompanyWork } from "../../Work/CompanyWork";
@ -30,8 +31,6 @@ type IProps = {
}; };
export function CompanyLocation(props: IProps): React.ReactElement { export function CompanyLocation(props: IProps): React.ReactElement {
const p = use.Player();
const router = use.Router();
const [quitOpen, setQuitOpen] = useState(false); const [quitOpen, setQuitOpen] = useState(false);
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {
@ -60,7 +59,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
/** /**
* Name of company position that player holds, if applicable * Name of company position that player holds, if applicable
*/ */
const jobTitle = p.jobs[props.locName] ? p.jobs[props.locName] : null; const jobTitle = Player.jobs[props.locName] ? Player.jobs[props.locName] : null;
/** /**
* CompanyPosition object for the job that the player holds at this company * CompanyPosition object for the job that the player holds at this company
@ -68,13 +67,13 @@ export function CompanyLocation(props: IProps): React.ReactElement {
*/ */
const companyPosition = jobTitle ? CompanyPositions[jobTitle] : null; const companyPosition = jobTitle ? CompanyPositions[jobTitle] : null;
p.location = props.locName; Player.location = props.locName;
function applyForAgentJob(e: React.MouseEvent<HTMLElement>): void { function applyForAgentJob(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForAgentJob(); Player.applyForAgentJob();
rerender(); rerender();
} }
@ -82,7 +81,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForBusinessConsultantJob(); Player.applyForBusinessConsultantJob();
rerender(); rerender();
} }
@ -90,7 +89,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForBusinessJob(); Player.applyForBusinessJob();
rerender(); rerender();
} }
@ -98,7 +97,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForEmployeeJob(); Player.applyForEmployeeJob();
rerender(); rerender();
} }
@ -106,7 +105,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForItJob(); Player.applyForItJob();
rerender(); rerender();
} }
@ -114,7 +113,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForPartTimeEmployeeJob(); Player.applyForPartTimeEmployeeJob();
rerender(); rerender();
} }
@ -122,7 +121,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForPartTimeWaiterJob(); Player.applyForPartTimeWaiterJob();
rerender(); rerender();
} }
@ -130,7 +129,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForSecurityJob(); Player.applyForSecurityJob();
rerender(); rerender();
} }
@ -138,7 +137,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForSoftwareConsultantJob(); Player.applyForSoftwareConsultantJob();
rerender(); rerender();
} }
@ -146,7 +145,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForSoftwareJob(); Player.applyForSoftwareJob();
rerender(); rerender();
} }
@ -154,7 +153,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
p.applyForWaiterJob(); Player.applyForWaiterJob();
rerender(); rerender();
} }
@ -166,7 +165,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
if (!loc.infiltrationData) if (!loc.infiltrationData)
throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`); throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`);
router.toInfiltration(loc); Router.toInfiltration(loc);
} }
function work(e: React.MouseEvent<HTMLElement>): void { function work(e: React.MouseEvent<HTMLElement>): void {
@ -176,14 +175,14 @@ export function CompanyLocation(props: IProps): React.ReactElement {
const pos = companyPosition; const pos = companyPosition;
if (pos instanceof CompanyPosition) { if (pos instanceof CompanyPosition) {
p.startWork( Player.startWork(
new CompanyWork({ new CompanyWork({
singularity: false, singularity: false,
companyName: props.locName, companyName: props.locName,
}), }),
); );
p.startFocusing(); Player.startFocusing();
router.toWork(); Router.toWork();
} }
} }

@ -6,7 +6,7 @@ import { purchaseServer } from "../../Server/ServerPurchases";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context"; import { Player } from "../../Player";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -21,7 +21,6 @@ interface IProps {
} }
export function PurchaseServerModal(props: IProps): React.ReactElement { export function PurchaseServerModal(props: IProps): React.ReactElement {
const player = use.Player();
const [hostname, setHostname] = useState(""); const [hostname, setHostname] = useState("");
function tryToPurchaseServer(): void { function tryToPurchaseServer(): void {
@ -56,7 +55,7 @@ export function PurchaseServerModal(props: IProps): React.ReactElement {
placeholder="Unique Hostname" placeholder="Unique Hostname"
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (
<Button onClick={tryToPurchaseServer} disabled={!player.canAfford(props.cost) || hostname === ""}> <Button onClick={tryToPurchaseServer} disabled={!Player.canAfford(props.cost) || hostname === ""}>
Buy Buy
</Button> </Button>
), ),

@ -10,132 +10,131 @@ import Tooltip from "@mui/material/Tooltip";
import { Crimes } from "../../Crime/Crimes"; import { Crimes } from "../../Crime/Crimes";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
export function SlumsLocation(): React.ReactElement { export function SlumsLocation(): React.ReactElement {
const player = use.Player();
const router = use.Router();
function shoplift(e: React.MouseEvent<HTMLElement>): void { function shoplift(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Shoplift.commit(player); Crimes.Shoplift.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function robStore(e: React.MouseEvent<HTMLElement>): void { function robStore(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.RobStore.commit(player); Crimes.RobStore.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function mug(e: React.MouseEvent<HTMLElement>): void { function mug(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Mug.commit(player); Crimes.Mug.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function larceny(e: React.MouseEvent<HTMLElement>): void { function larceny(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Larceny.commit(player); Crimes.Larceny.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function dealDrugs(e: React.MouseEvent<HTMLElement>): void { function dealDrugs(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.DealDrugs.commit(player); Crimes.DealDrugs.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function bondForgery(e: React.MouseEvent<HTMLElement>): void { function bondForgery(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.BondForgery.commit(player); Crimes.BondForgery.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function traffickArms(e: React.MouseEvent<HTMLElement>): void { function traffickArms(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.TraffickArms.commit(player); Crimes.TraffickArms.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function homicide(e: React.MouseEvent<HTMLElement>): void { function homicide(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Homicide.commit(player); Crimes.Homicide.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function grandTheftAuto(e: React.MouseEvent<HTMLElement>): void { function grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.GrandTheftAuto.commit(player); Crimes.GrandTheftAuto.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function kidnap(e: React.MouseEvent<HTMLElement>): void { function kidnap(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Kidnap.commit(player); Crimes.Kidnap.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function assassinate(e: React.MouseEvent<HTMLElement>): void { function assassinate(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Assassination.commit(player); Crimes.Assassination.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
function heist(e: React.MouseEvent<HTMLElement>): void { function heist(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) { if (!e.isTrusted) {
return; return;
} }
Crimes.Heist.commit(player); Crimes.Heist.commit();
router.toWork(); Router.toWork();
player.focus = true; Player.focus = true;
} }
const shopliftChance = Crimes.Shoplift.successRate(player); const shopliftChance = Crimes.Shoplift.successRate(Player);
const robStoreChance = Crimes.RobStore.successRate(player); const robStoreChance = Crimes.RobStore.successRate(Player);
const mugChance = Crimes.Mug.successRate(player); const mugChance = Crimes.Mug.successRate(Player);
const larcenyChance = Crimes.Larceny.successRate(player); const larcenyChance = Crimes.Larceny.successRate(Player);
const drugsChance = Crimes.DealDrugs.successRate(player); const drugsChance = Crimes.DealDrugs.successRate(Player);
const bondChance = Crimes.BondForgery.successRate(player); const bondChance = Crimes.BondForgery.successRate(Player);
const armsChance = Crimes.TraffickArms.successRate(player); const armsChance = Crimes.TraffickArms.successRate(Player);
const homicideChance = Crimes.Homicide.successRate(player); const homicideChance = Crimes.Homicide.successRate(Player);
const gtaChance = Crimes.GrandTheftAuto.successRate(player); const gtaChance = Crimes.GrandTheftAuto.successRate(Player);
const kidnapChance = Crimes.Kidnap.successRate(player); const kidnapChance = Crimes.Kidnap.successRate(Player);
const assassinateChance = Crimes.Assassination.successRate(player); const assassinateChance = Crimes.Assassination.successRate(Player);
const heistChance = Crimes.Heist.successRate(player); const heistChance = Crimes.Heist.successRate(Player);
return ( return (
<Box sx={{ display: "grid", width: "fit-content" }}> <Box sx={{ display: "grid", width: "fit-content" }}>

@ -21,7 +21,8 @@ import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { joinFaction } from "../../Faction/FactionHelpers"; import { joinFaction } from "../../Faction/FactionHelpers";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
@ -41,27 +42,24 @@ type IProps = {
}; };
export function SpecialLocation(props: IProps): React.ReactElement { export function SpecialLocation(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
const inBladeburner = player.inBladeburner(); const inBladeburner = Player.inBladeburner();
/** /**
* Click handler for Bladeburner button at Sector-12 NSA * Click handler for Bladeburner button at Sector-12 NSA
*/ */
function handleBladeburner(): void { function handleBladeburner(): void {
const p = player; if (Player.inBladeburner()) {
if (p.inBladeburner()) {
// Enter Bladeburner division // Enter Bladeburner division
router.toBladeburner(); Router.toBladeburner();
} else if ( } else if (
p.skills.strength >= 100 && Player.skills.strength >= 100 &&
p.skills.defense >= 100 && Player.skills.defense >= 100 &&
p.skills.dexterity >= 100 && Player.skills.dexterity >= 100 &&
p.skills.agility >= 100 Player.skills.agility >= 100
) { ) {
// Apply for Bladeburner division // Apply for Bladeburner division
p.startBladeburner(); Player.startBladeburner();
dialogBoxCreate("You have been accepted into the Bladeburner division!"); dialogBoxCreate("You have been accepted into the Bladeburner division!");
setRerender((old) => !old); setRerender((old) => !old);
@ -79,11 +77,11 @@ export function SpecialLocation(props: IProps): React.ReactElement {
* Click handler for Resleeving button at New Tokyo VitaLife * Click handler for Resleeving button at New Tokyo VitaLife
*/ */
function handleGrafting(): void { function handleGrafting(): void {
router.toGrafting(); Router.toGrafting();
} }
function renderBladeburner(): React.ReactElement { function renderBladeburner(): React.ReactElement {
if (!player.canAccessBladeburner() || BitNodeMultipliers.BladeburnerRank === 0) { if (!Player.canAccessBladeburner() || BitNodeMultipliers.BladeburnerRank === 0) {
return <></>; return <></>;
} }
const text = inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division"; const text = inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
@ -99,32 +97,32 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function EatNoodles(): void { function EatNoodles(): void {
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", ToastVariant.SUCCESS, 2000); SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", ToastVariant.SUCCESS, 2000);
N00dles(); // This is the true power of the noodles. N00dles(); // This is the true power of the noodles.
if (player.sourceFiles.length > 0) player.giveExploit(Exploit.N00dles); if (Player.sourceFiles.length > 0) Player.giveExploit(Exploit.N00dles);
if (player.sourceFileLvl(5) > 0 || player.bitNodeN === 5) { if (Player.sourceFileLvl(5) > 0 || Player.bitNodeN === 5) {
player.exp.intelligence *= 1.0000000000000002; Player.exp.intelligence *= 1.0000000000000002;
} }
player.exp.hacking *= 1.0000000000000002; Player.exp.hacking *= 1.0000000000000002;
player.exp.strength *= 1.0000000000000002; Player.exp.strength *= 1.0000000000000002;
player.exp.defense *= 1.0000000000000002; Player.exp.defense *= 1.0000000000000002;
player.exp.agility *= 1.0000000000000002; Player.exp.agility *= 1.0000000000000002;
player.exp.dexterity *= 1.0000000000000002; Player.exp.dexterity *= 1.0000000000000002;
player.exp.charisma *= 1.0000000000000002; Player.exp.charisma *= 1.0000000000000002;
for (const node of player.hacknetNodes) { for (const node of Player.hacknetNodes) {
if (node instanceof HacknetNode) { if (node instanceof HacknetNode) {
player.gainMoney(node.moneyGainRatePerSecond * 0.001, "other"); Player.gainMoney(node.moneyGainRatePerSecond * 0.001, "other");
} else { } else {
const server = GetServer(node); const server = GetServer(node);
if (!(server instanceof HacknetServer)) throw new Error(`Server ${node} is not a hacknet server.`); if (!(server instanceof HacknetServer)) throw new Error(`Server ${node} is not a hacknet server.`);
player.hashManager.storeHashes(server.hashRate * 0.001); Player.hashManager.storeHashes(server.hashRate * 0.001);
} }
} }
if (player.bladeburner) { if (Player.bladeburner) {
player.bladeburner.rank += 0.00001; Player.bladeburner.rank += 0.00001;
} }
if (player.corporation) { if (Player.corporation) {
player.corporation.funds += player.corporation.revenue * 0.01; Player.corporation.funds += Player.corporation.revenue * 0.01;
} }
} }
@ -138,7 +136,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function CreateCorporation(): React.ReactElement { function CreateCorporation(): React.ReactElement {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
if (!player.canAccessCorporation()) { if (!Player.canAccessCorporation()) {
return ( return (
<> <>
<Typography> <Typography>
@ -149,7 +147,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
} }
return ( return (
<> <>
<Button disabled={!player.canAccessCorporation() || player.hasCorporation()} onClick={() => setOpen(true)}> <Button disabled={!Player.canAccessCorporation() || Player.hasCorporation()} onClick={() => setOpen(true)}>
Create a Corporation Create a Corporation
</Button> </Button>
<CreateCorporationModal open={open} onClose={() => setOpen(false)} /> <CreateCorporationModal open={open} onClose={() => setOpen(false)} />
@ -158,7 +156,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
} }
function renderGrafting(): React.ReactElement { function renderGrafting(): React.ReactElement {
if (!player.canAccessGrafting()) { if (!Player.canAccessGrafting()) {
return <></>; return <></>;
} }
return ( return (
@ -170,21 +168,21 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function handleCotMG(): void { function handleCotMG(): void {
const faction = Factions[FactionNames.ChurchOfTheMachineGod]; const faction = Factions[FactionNames.ChurchOfTheMachineGod];
if (!player.factions.includes(FactionNames.ChurchOfTheMachineGod)) { if (!Player.factions.includes(FactionNames.ChurchOfTheMachineGod)) {
joinFaction(faction); joinFaction(faction);
} }
if ( if (
!player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1) && !Player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1) &&
!player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1) !Player.queuedAugmentations.some((a) => a.name === AugmentationNames.StaneksGift1)
) { ) {
applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 }); applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 });
} }
router.toStaneksGift(); Router.toStaneksGift();
} }
function renderCotMG(): React.ReactElement { function renderCotMG(): React.ReactElement {
const toStanek = <Button onClick={() => router.toStaneksGift()}>Open Stanek's Gift</Button>; const toStanek = <Button onClick={() => Router.toStaneksGift()}>Open Stanek's Gift</Button>;
// prettier-ignore // prettier-ignore
const symbol = <Typography sx={{ lineHeight: '1em', whiteSpace: 'pre' }}> const symbol = <Typography sx={{ lineHeight: '1em', whiteSpace: 'pre' }}>
{" `` "}<br /> {" `` "}<br />
@ -215,7 +213,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
{" sNNo-.`.-omNy` "}<br /> {" sNNo-.`.-omNy` "}<br />
{" -smNNNNmdo- "}<br /> {" -smNNNNmdo- "}<br />
{" `..` "}</Typography> {" `..` "}</Typography>
if (player.hasAugmentation(AugmentationNames.StaneksGift3, true)) { if (Player.hasAugmentation(AugmentationNames.StaneksGift3, true)) {
return ( return (
<> <>
<Typography> <Typography>
@ -232,7 +230,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
</> </>
); );
} }
if (player.hasAugmentation(AugmentationNames.StaneksGift2, true)) { if (Player.hasAugmentation(AugmentationNames.StaneksGift2, true)) {
return ( return (
<> <>
<Typography> <Typography>
@ -249,7 +247,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
</> </>
); );
} }
if (player.factions.includes(FactionNames.ChurchOfTheMachineGod)) { if (Player.factions.includes(FactionNames.ChurchOfTheMachineGod)) {
return ( return (
<> <>
<Typography> <Typography>
@ -263,7 +261,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
); );
} }
if (!player.canAccessCotMG()) { if (!Player.canAccessCotMG()) {
return ( return (
<> <>
<Typography> <Typography>
@ -278,8 +276,8 @@ export function SpecialLocation(props: IProps): React.ReactElement {
} }
if ( if (
player.augmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0 || Player.augmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0 ||
player.queuedAugmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0 Player.queuedAugmentations.filter((a) => a.name !== AugmentationNames.NeuroFluxGovernor).length > 0
) { ) {
return ( return (
<> <>

@ -2,7 +2,6 @@ import React from "react";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
@ -15,7 +14,6 @@ interface IProps {
} }
export function TravelConfirmationModal(props: IProps): React.ReactElement { export function TravelConfirmationModal(props: IProps): React.ReactElement {
const player = use.Player();
const cost = CONSTANTS.TravelCost; const cost = CONSTANTS.TravelCost;
function travel(): void { function travel(): void {
props.travel(); props.travel();

@ -10,7 +10,8 @@ import Button from "@mui/material/Button";
import { Location } from "../Location"; import { Location } from "../Location";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { use } from "../../ui/Context"; import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { ClassWork, ClassType, Classes } from "../../Work/ClassWork"; import { ClassWork, ClassType, Classes } from "../../Work/ClassWork";
@ -21,19 +22,16 @@ type IProps = {
}; };
export function UniversityLocation(props: IProps): React.ReactElement { export function UniversityLocation(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
function take(classType: ClassType): void { function take(classType: ClassType): void {
player.startWork( Player.startWork(
new ClassWork({ new ClassWork({
classType: classType, classType: classType,
location: props.loc.name, location: props.loc.name,
singularity: false, singularity: false,
}), }),
); );
player.startFocusing(); Player.startFocusing();
router.toWork(); Router.toWork();
} }
const dataStructuresCost = calculateCost(Classes[ClassType.DataStructures], props.loc); const dataStructuresCost = calculateCost(Classes[ClassType.DataStructures], props.loc);

@ -274,7 +274,7 @@ export function NetscriptGang(): InternalAPI<IGang> {
const member = getGangMember(ctx, memberName); const member = getGangMember(ctx, memberName);
const equipment = GangMemberUpgrades[equipName]; const equipment = GangMemberUpgrades[equipName];
if (!equipment) return false; if (!equipment) return false;
const res = member.buyUpgrade(equipment, player, gang); const res = member.buyUpgrade(equipment);
if (res) { if (res) {
ctx.workerScript.log( ctx.workerScript.log(
"gang.purchaseEquipment", "gang.purchaseEquipment",

@ -1178,7 +1178,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeRoughName}'`); throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeRoughName}'`);
} }
helpers.log(ctx, () => `Attempting to commit ${crime.name}...`); helpers.log(ctx, () => `Attempting to commit ${crime.name}...`);
const crimeTime = crime.commit(Player, 1, ctx.workerScript); const crimeTime = crime.commit(1, ctx.workerScript);
if (focus) { if (focus) {
Player.startFocusing(); Player.startFocusing();
Router.toWork(); Router.toWork();
@ -1275,7 +1275,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
const nextBN = helpers.number(ctx, "nextBN", _nextBN); const nextBN = helpers.number(ctx, "nextBN", _nextBN);
const callbackScript = helpers.string(ctx, "callbackScript", _callbackScript); const callbackScript = helpers.string(ctx, "callbackScript", _callbackScript);
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
enterBitNode(Router, true, Player.bitNodeN, nextBN); enterBitNode(true, Player.bitNodeN, nextBN);
if (callbackScript) if (callbackScript)
setTimeout(() => { setTimeout(() => {
runAfterReset(callbackScript); runAfterReset(callbackScript);
@ -1308,7 +1308,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
wd.backdoorInstalled = true; wd.backdoorInstalled = true;
calculateAchievements(); calculateAchievements();
enterBitNode(Router, false, Player.bitNodeN, nextBN); enterBitNode(false, Player.bitNodeN, nextBN);
if (callbackScript) if (callbackScript)
setTimeout(() => { setTimeout(() => {
runAfterReset(callbackScript); runAfterReset(callbackScript);

@ -11,7 +11,7 @@ import { BaseCostPerSleeve, MaxSleevesFromCovenant } from "../SleeveCovenantPurc
import { Money } from "../../../ui/React/Money"; import { Money } from "../../../ui/React/Money";
import { Modal } from "../../../ui/React/Modal"; import { Modal } from "../../../ui/React/Modal";
import { use } from "../../../ui/Context"; import { Player } from "../../../Player";
import { dialogBoxCreate } from "../../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -24,14 +24,13 @@ interface IProps {
} }
export function CovenantPurchasesRoot(props: IProps): React.ReactElement { export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
const player = use.Player();
const [update, setUpdate] = useState(0); const [update, setUpdate] = useState(0);
/** /**
* Get the cost to purchase a new Duplicate Sleeve * Get the cost to purchase a new Duplicate Sleeve
*/ */
function purchaseCost(): number { function purchaseCost(): number {
return Math.pow(10, player.sleevesFromCovenant) * BaseCostPerSleeve; return Math.pow(10, Player.sleevesFromCovenant) * BaseCostPerSleeve;
} }
/** /**
@ -43,20 +42,20 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
// Purchasing a new Duplicate Sleeve // Purchasing a new Duplicate Sleeve
let purchaseDisabled = false; let purchaseDisabled = false;
if (!player.canAfford(purchaseCost())) { if (!Player.canAfford(purchaseCost())) {
purchaseDisabled = true; purchaseDisabled = true;
} }
if (player.sleevesFromCovenant >= MaxSleevesFromCovenant) { if (Player.sleevesFromCovenant >= MaxSleevesFromCovenant) {
purchaseDisabled = true; purchaseDisabled = true;
} }
function purchaseOnClick(): void { function purchaseOnClick(): void {
if (player.sleevesFromCovenant >= MaxSleevesFromCovenant) return; if (Player.sleevesFromCovenant >= MaxSleevesFromCovenant) return;
if (player.canAfford(purchaseCost())) { if (Player.canAfford(purchaseCost())) {
player.loseMoney(purchaseCost(), "sleeves"); Player.loseMoney(purchaseCost(), "sleeves");
player.sleevesFromCovenant += 1; Player.sleevesFromCovenant += 1;
player.sleeves.push(new Sleeve()); Player.sleeves.push(new Sleeve());
rerender(); rerender();
} else { } else {
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`); dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`);
@ -65,15 +64,15 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
// Purchasing Upgrades for Sleeves // Purchasing Upgrades for Sleeves
const upgradePanels = []; const upgradePanels = [];
for (let i = 0; i < player.sleeves.length; ++i) { for (let i = 0; i < Player.sleeves.length; ++i) {
const sleeve = player.sleeves[i]; const sleeve = Player.sleeves[i];
upgradePanels.push(<CovenantSleeveMemoryUpgrade index={i} rerender={rerender} sleeve={sleeve} />); upgradePanels.push(<CovenantSleeveMemoryUpgrade index={i} rerender={rerender} sleeve={sleeve} />);
} }
return ( return (
<Modal open={props.open} onClose={props.onClose}> <Modal open={props.open} onClose={props.onClose}>
<> <>
{player.sleevesFromCovenant < MaxSleevesFromCovenant && ( {Player.sleevesFromCovenant < MaxSleevesFromCovenant && (
<> <>
<Typography> <Typography>
Purchase an additional Sleeves. These Duplicate Sleeves are permanent (they persist through BitNodes). You Purchase an additional Sleeves. These Duplicate Sleeves are permanent (they persist through BitNodes). You

@ -2,13 +2,12 @@ import React, { useState, useEffect } from "react";
import { Box, Typography, Button, Container } from "@mui/material"; import { Box, Typography, Button, Container } from "@mui/material";
import { use } from "../../../ui/Context"; import { Player } from "../../../Player";
import { SleeveElem } from "./SleeveElem"; import { SleeveElem } from "./SleeveElem";
import { FAQModal } from "./FAQModal"; import { FAQModal } from "./FAQModal";
export function SleeveRoot(): React.ReactElement { export function SleeveRoot(): React.ReactElement {
const player = use.Player();
const [FAQOpen, setFAQOpen] = useState(false); const [FAQOpen, setFAQOpen] = useState(false);
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
function rerender(): void { function rerender(): void {
@ -43,7 +42,7 @@ export function SleeveRoot(): React.ReactElement {
Wiki Documentation Wiki Documentation
</Button> </Button>
<Box display="grid" sx={{ gridTemplateColumns: "repeat(2, 1fr)", mt: 1 }}> <Box display="grid" sx={{ gridTemplateColumns: "repeat(2, 1fr)", mt: 1 }}>
{player.sleeves.map((sleeve, i) => ( {Player.sleeves.map((sleeve, i) => (
<SleeveElem key={i} rerender={rerender} sleeve={sleeve} /> <SleeveElem key={i} rerender={rerender} sleeve={sleeve} />
))} ))}
</Box> </Box>

@ -8,7 +8,7 @@ import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile";
import { SourceFiles } from "./SourceFile/SourceFiles"; import { SourceFiles } from "./SourceFile/SourceFiles";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
import { IRouter } from "./ui/Router"; import { Router } from "./ui/GameRoot";
function giveSourceFile(bitNodeNumber: number): void { function giveSourceFile(bitNodeNumber: number): void {
const sourceFileKey = "SourceFile" + bitNodeNumber.toString(); const sourceFileKey = "SourceFile" + bitNodeNumber.toString();
@ -65,7 +65,7 @@ function giveSourceFile(bitNodeNumber: number): void {
} }
} }
export function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number): void { export function enterBitNode(flume: boolean, destroyedBitNode: number, newBitNode: number): void {
if (!flume) { if (!flume) {
giveSourceFile(destroyedBitNode); giveSourceFile(destroyedBitNode);
} else if (Player.sourceFileLvl(5) === 0 && newBitNode !== 5) { } else if (Player.sourceFileLvl(5) === 0 && newBitNode !== 5) {
@ -79,9 +79,9 @@ export function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode:
Player.bitNodeN = newBitNode; Player.bitNodeN = newBitNode;
if (newBitNode === 6) { if (newBitNode === 6) {
router.toBladeburnerCinematic(); Router.toBladeburnerCinematic();
} else { } else {
router.toTerminal(); Router.toTerminal();
} }
prestigeSourceFile(flume); prestigeSourceFile(flume);
} }

@ -6,7 +6,7 @@ import * as React from "react";
import { Money } from "../React/Money"; import { Money } from "../React/Money";
import { MoneyRate } from "../React/MoneyRate"; import { MoneyRate } from "../React/MoneyRate";
import { use } from "../Context"; import { Player } from "../../Player";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -32,9 +32,8 @@ const useStyles = makeStyles((theme: Theme) =>
}), }),
); );
export function ScriptProduction(): React.ReactElement { export function ScriptProduction(): React.ReactElement {
const player = use.Player();
const classes = useStyles(); const classes = useStyles();
const prodRateSinceLastAug = player.scriptProdSinceLastAug / (player.playtimeSinceLastAug / 1000); const prodRateSinceLastAug = Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug / 1000);
return ( return (
<Table size="small" classes={{ root: classes.size }}> <Table size="small" classes={{ root: classes.size }}>
@ -45,7 +44,7 @@ export function ScriptProduction(): React.ReactElement {
</TableCell> </TableCell>
<TableCell align="left" classes={{ root: classes.cell }}> <TableCell align="left" classes={{ root: classes.cell }}>
<Typography variant="body2"> <Typography variant="body2">
<Money money={player.scriptProdSinceLastAug} /> <Money money={Player.scriptProdSinceLastAug} />
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="left" classes={{ root: classes.cell }}> <TableCell align="left" classes={{ root: classes.cell }}>

@ -9,7 +9,7 @@ import { getPurchaseServerLimit } from "../Server/ServerPurchases";
import { Settings } from "../Settings/Settings"; import { Settings } from "../Settings/Settings";
import { MoneySourceTracker } from "../utils/MoneySourceTracker"; import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions"; import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { use } from "./Context"; import { Player } from "../Player";
import { numeralWrapper } from "./numeralFormat"; import { numeralWrapper } from "./numeralFormat";
import { Modal } from "./React/Modal"; import { Modal } from "./React/Modal";
import { Money } from "./React/Money"; import { Money } from "./React/Money";
@ -23,13 +23,12 @@ interface EmployersModalProps {
} }
const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElement => { const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElement => {
const player = use.Player();
return ( return (
<Modal open={open} onClose={onClose}> <Modal open={open} onClose={onClose}>
<> <>
<Typography variant="h5">All Employers</Typography> <Typography variant="h5">All Employers</Typography>
<ul> <ul>
{Object.keys(player.jobs).map((j) => ( {Object.keys(Player.jobs).map((j) => (
<Typography key={j}>* {j}</Typography> <Typography key={j}>* {j}</Typography>
))} ))}
</ul> </ul>
@ -59,14 +58,13 @@ interface MultTableProps {
} }
function MultiplierTable(props: MultTableProps): React.ReactElement { function MultiplierTable(props: MultTableProps): React.ReactElement {
const player = use.Player();
return ( return (
<Table sx={{ display: "table", width: "100%", mb: (props.noMargin ?? false) === true ? 0 : 2 }}> <Table sx={{ display: "table", width: "100%", mb: (props.noMargin ?? false) === true ? 0 : 2 }}>
<TableBody> <TableBody>
{props.rows.map((data) => { {props.rows.map((data) => {
const { mult, value, effValue = null, color = props.color } = data; const { mult, value, effValue = null, color = props.color } = data;
if (effValue !== null && effValue !== value && player.sourceFileLvl(5) > 0) { if (effValue !== null && effValue !== value && Player.sourceFileLvl(5) > 0) {
return ( return (
<StatsRow key={mult} name={mult} color={color} data={{}}> <StatsRow key={mult} name={mult} color={color} data={{}}>
<> <>
@ -88,14 +86,13 @@ function MultiplierTable(props: MultTableProps): React.ReactElement {
} }
function CurrentBitNode(): React.ReactElement { function CurrentBitNode(): React.ReactElement {
const player = use.Player(); if (Player.sourceFiles.length > 0) {
if (player.sourceFiles.length > 0) { const index = "BitNode" + Player.bitNodeN;
const index = "BitNode" + player.bitNodeN; const lvl = Math.min(Player.sourceFileLvl(Player.bitNodeN) + 1, Player.bitNodeN === 12 ? Infinity : 3);
const lvl = Math.min(player.sourceFileLvl(player.bitNodeN) + 1, player.bitNodeN === 12 ? Infinity : 3);
return ( return (
<Paper sx={{ mb: 1, p: 1 }}> <Paper sx={{ mb: 1, p: 1 }}>
<Typography variant="h5"> <Typography variant="h5">
BitNode {player.bitNodeN}: {BitNodes[index].name} (Level {lvl}) BitNode {Player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
</Typography> </Typography>
<Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography> <Typography sx={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>{BitNodes[index].info}</Typography>
</Paper> </Paper>
@ -111,7 +108,6 @@ interface IMoneyModalProps {
} }
function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement { function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
const player = use.Player();
function convertMoneySourceTrackerToString(src: MoneySourceTracker): React.ReactElement { function convertMoneySourceTrackerToString(src: MoneySourceTracker): React.ReactElement {
const parts: [string, JSX.Element][] = [[`Total:`, <Money money={src.total} />]]; const parts: [string, JSX.Element][] = [[`Total:`, <Money money={src.total} />]];
if (src.augmentations) { if (src.augmentations) {
@ -178,10 +174,10 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
Money earned since you last installed Augmentations Money earned since you last installed Augmentations
</Typography> </Typography>
<br /> <br />
{convertMoneySourceTrackerToString(player.moneySourceA)} {convertMoneySourceTrackerToString(Player.moneySourceA)}
</> </>
); );
if (player.sourceFiles.length !== 0) { if (Player.sourceFiles.length !== 0) {
content = ( content = (
<> <>
{content} {content}
@ -191,7 +187,7 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
Money earned in this BitNode Money earned in this BitNode
</Typography> </Typography>
<br /> <br />
{convertMoneySourceTrackerToString(player.moneySourceB)} {convertMoneySourceTrackerToString(Player.moneySourceB)}
</> </>
); );
} }
@ -204,7 +200,6 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
} }
export function CharacterStats(): React.ReactElement { export function CharacterStats(): React.ReactElement {
const player = use.Player();
const [moneyOpen, setMoneyOpen] = useState(false); const [moneyOpen, setMoneyOpen] = useState(false);
const [employersOpen, setEmployersOpen] = useState(false); const [employersOpen, setEmployersOpen] = useState(false);
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
@ -218,18 +213,18 @@ export function CharacterStats(): React.ReactElement {
}, []); }, []);
const timeRows = [ const timeRows = [
["Since last Augmentation installation", convertTimeMsToTimeElapsedString(player.playtimeSinceLastAug)], ["Since last Augmentation installation", convertTimeMsToTimeElapsedString(Player.playtimeSinceLastAug)],
]; ];
if (player.sourceFiles.length > 0) { if (Player.sourceFiles.length > 0) {
timeRows.push(["Since last Bitnode destroyed", convertTimeMsToTimeElapsedString(player.playtimeSinceLastBitnode)]); timeRows.push(["Since last Bitnode destroyed", convertTimeMsToTimeElapsedString(Player.playtimeSinceLastBitnode)]);
} }
timeRows.push(["Total", convertTimeMsToTimeElapsedString(player.totalPlaytime)]); timeRows.push(["Total", convertTimeMsToTimeElapsedString(Player.totalPlaytime)]);
let showBitNodeMults = false; let showBitNodeMults = false;
if (player.sourceFileLvl(5) > 0) { if (Player.sourceFileLvl(5) > 0) {
const n = player.bitNodeN; const n = Player.bitNodeN;
const maxSfLevel = n === 12 ? Infinity : 3; const maxSfLevel = n === 12 ? Infinity : 3;
const mults = getBitNodeMultipliers(n, Math.min(player.sourceFileLvl(n) + 1, maxSfLevel)); const mults = getBitNodeMultipliers(n, Math.min(Player.sourceFileLvl(n) + 1, maxSfLevel));
showBitNodeMults = !isEqual(mults, defaultMultipliers); showBitNodeMults = !isEqual(mults, defaultMultipliers);
} }
return ( return (
@ -240,20 +235,20 @@ export function CharacterStats(): React.ReactElement {
<Typography variant="h5">General</Typography> <Typography variant="h5">General</Typography>
<Table> <Table>
<TableBody> <TableBody>
<StatsRow name="Current City" color={Settings.theme.primary} data={{ content: player.city }} /> <StatsRow name="Current City" color={Settings.theme.primary} data={{ content: Player.city }} />
<StatsRow name="Money" color={Settings.theme.money} data={{}}> <StatsRow name="Money" color={Settings.theme.money} data={{}}>
<> <>
<Money money={player.money} /> <Money money={Player.money} />
<IconButton onClick={() => setMoneyOpen(true)} sx={{ p: 0 }}> <IconButton onClick={() => setMoneyOpen(true)} sx={{ p: 0 }}>
<MoreHoriz color="info" /> <MoreHoriz color="info" />
</IconButton> </IconButton>
</> </>
</StatsRow> </StatsRow>
{player.jobs && Object.keys(player.jobs).length !== 0 ? ( {Player.jobs && Object.keys(Player.jobs).length !== 0 ? (
<StatsRow name="All Employers" color={Settings.theme.primary} data={{}}> <StatsRow name="All Employers" color={Settings.theme.primary} data={{}}>
<> <>
<span style={{ color: Settings.theme.primary }}>{Object.keys(player.jobs).length} total</span> <span style={{ color: Settings.theme.primary }}>{Object.keys(Player.jobs).length} total</span>
<IconButton onClick={() => setEmployersOpen(true)} sx={{ p: 0 }}> <IconButton onClick={() => setEmployersOpen(true)} sx={{ p: 0 }}>
<MoreHoriz color="info" /> <MoreHoriz color="info" />
</IconButton> </IconButton>
@ -265,14 +260,14 @@ export function CharacterStats(): React.ReactElement {
<StatsRow <StatsRow
name="Servers Owned" name="Servers Owned"
color={Settings.theme.primary} color={Settings.theme.primary}
data={{ content: `${player.purchasedServers.length} / ${getPurchaseServerLimit()}` }} data={{ content: `${Player.purchasedServers.length} / ${getPurchaseServerLimit()}` }}
/> />
<StatsRow <StatsRow
name={`Hacknet ${player.bitNodeN === 9 || player.sourceFileLvl(9) > 0 ? "Servers" : "Nodes"} owned`} name={`Hacknet ${Player.bitNodeN === 9 || Player.sourceFileLvl(9) > 0 ? "Servers" : "Nodes"} owned`}
color={Settings.theme.primary} color={Settings.theme.primary}
data={{ data={{
content: `${player.hacknetNodes.length}${ content: `${Player.hacknetNodes.length}${
player.bitNodeN === 9 || player.sourceFileLvl(9) > 0 Player.bitNodeN === 9 || Player.sourceFileLvl(9) > 0
? ` / ${HacknetServerConstants.MaxServers}` ? ` / ${HacknetServerConstants.MaxServers}`
: "" : ""
}`, }`,
@ -281,7 +276,7 @@ export function CharacterStats(): React.ReactElement {
<StatsRow <StatsRow
name="Augmentations Installed" name="Augmentations Installed"
color={Settings.theme.primary} color={Settings.theme.primary}
data={{ content: String(player.augmentations.length) }} data={{ content: String(Player.augmentations.length) }}
/> />
</TableBody> </TableBody>
</Table> </Table>
@ -293,38 +288,38 @@ export function CharacterStats(): React.ReactElement {
<StatsRow <StatsRow
name="Hacking" name="Hacking"
color={Settings.theme.hack} color={Settings.theme.hack}
data={{ level: player.skills.hacking, exp: player.exp.hacking }} data={{ level: Player.skills.hacking, exp: Player.exp.hacking }}
/> />
<StatsRow <StatsRow
name="Strength" name="Strength"
color={Settings.theme.combat} color={Settings.theme.combat}
data={{ level: player.skills.strength, exp: player.exp.strength }} data={{ level: Player.skills.strength, exp: Player.exp.strength }}
/> />
<StatsRow <StatsRow
name="Defense" name="Defense"
color={Settings.theme.combat} color={Settings.theme.combat}
data={{ level: player.skills.defense, exp: player.exp.defense }} data={{ level: Player.skills.defense, exp: Player.exp.defense }}
/> />
<StatsRow <StatsRow
name="Dexterity" name="Dexterity"
color={Settings.theme.combat} color={Settings.theme.combat}
data={{ level: player.skills.dexterity, exp: player.exp.dexterity }} data={{ level: Player.skills.dexterity, exp: Player.exp.dexterity }}
/> />
<StatsRow <StatsRow
name="Agility" name="Agility"
color={Settings.theme.combat} color={Settings.theme.combat}
data={{ level: player.skills.agility, exp: player.exp.agility }} data={{ level: Player.skills.agility, exp: Player.exp.agility }}
/> />
<StatsRow <StatsRow
name="Charisma" name="Charisma"
color={Settings.theme.cha} color={Settings.theme.cha}
data={{ level: player.skills.charisma, exp: player.exp.charisma }} data={{ level: Player.skills.charisma, exp: Player.exp.charisma }}
/> />
{player.skills.intelligence > 0 && (player.bitNodeN === 5 || player.sourceFileLvl(5) > 0) && ( {Player.skills.intelligence > 0 && (Player.bitNodeN === 5 || Player.sourceFileLvl(5) > 0) && (
<StatsRow <StatsRow
name="Intelligence" name="Intelligence"
color={Settings.theme.int} color={Settings.theme.int}
data={{ level: player.skills.intelligence, exp: player.exp.intelligence }} data={{ level: Player.skills.intelligence, exp: Player.exp.intelligence }}
/> />
)} )}
</TableBody> </TableBody>
@ -335,7 +330,7 @@ export function CharacterStats(): React.ReactElement {
<Paper sx={{ p: 1, mb: 1 }}> <Paper sx={{ p: 1, mb: 1 }}>
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}> <Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
Multipliers Multipliers
{player.sourceFileLvl(5) > 0 && ( {Player.sourceFileLvl(5) > 0 && (
<Tooltip <Tooltip
title={ title={
<Typography> <Typography>
@ -361,21 +356,21 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Hacking Chance", mult: "Hacking Chance",
value: player.mults.hacking_chance, value: Player.mults.hacking_chance,
}, },
{ {
mult: "Hacking Speed", mult: "Hacking Speed",
value: player.mults.hacking_speed, value: Player.mults.hacking_speed,
}, },
{ {
mult: "Hacking Money", mult: "Hacking Money",
value: player.mults.hacking_money, value: Player.mults.hacking_money,
effValue: player.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney, effValue: Player.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney,
}, },
{ {
mult: "Hacking Growth", mult: "Hacking Growth",
value: player.mults.hacking_grow, value: Player.mults.hacking_grow,
effValue: player.mults.hacking_grow * BitNodeMultipliers.ServerGrowthRate, effValue: Player.mults.hacking_grow * BitNodeMultipliers.ServerGrowthRate,
}, },
]} ]}
color={Settings.theme.hack} color={Settings.theme.hack}
@ -384,13 +379,13 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Hacking Level", mult: "Hacking Level",
value: player.mults.hacking, value: Player.mults.hacking,
effValue: player.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier, effValue: Player.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier,
}, },
{ {
mult: "Hacking Experience", mult: "Hacking Experience",
value: player.mults.hacking_exp, value: Player.mults.hacking_exp,
effValue: player.mults.hacking_exp * BitNodeMultipliers.HackExpGain, effValue: Player.mults.hacking_exp * BitNodeMultipliers.HackExpGain,
}, },
]} ]}
color={Settings.theme.hack} color={Settings.theme.hack}
@ -399,12 +394,12 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Strength Level", mult: "Strength Level",
value: player.mults.strength, value: Player.mults.strength,
effValue: player.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier, effValue: Player.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier,
}, },
{ {
mult: "Strength Experience", mult: "Strength Experience",
value: player.mults.strength_exp, value: Player.mults.strength_exp,
}, },
]} ]}
color={Settings.theme.combat} color={Settings.theme.combat}
@ -413,12 +408,12 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Defense Level", mult: "Defense Level",
value: player.mults.defense, value: Player.mults.defense,
effValue: player.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier, effValue: Player.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier,
}, },
{ {
mult: "Defense Experience", mult: "Defense Experience",
value: player.mults.defense_exp, value: Player.mults.defense_exp,
}, },
]} ]}
color={Settings.theme.combat} color={Settings.theme.combat}
@ -427,12 +422,12 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Dexterity Level", mult: "Dexterity Level",
value: player.mults.dexterity, value: Player.mults.dexterity,
effValue: player.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier, effValue: Player.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier,
}, },
{ {
mult: "Dexterity Experience", mult: "Dexterity Experience",
value: player.mults.dexterity_exp, value: Player.mults.dexterity_exp,
}, },
]} ]}
color={Settings.theme.combat} color={Settings.theme.combat}
@ -441,12 +436,12 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Agility Level", mult: "Agility Level",
value: player.mults.agility, value: Player.mults.agility,
effValue: player.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier, effValue: Player.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier,
}, },
{ {
mult: "Agility Experience", mult: "Agility Experience",
value: player.mults.agility_exp, value: Player.mults.agility_exp,
}, },
]} ]}
color={Settings.theme.combat} color={Settings.theme.combat}
@ -455,12 +450,12 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Charisma Level", mult: "Charisma Level",
value: player.mults.charisma, value: Player.mults.charisma,
effValue: player.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier, effValue: Player.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier,
}, },
{ {
mult: "Charisma Experience", mult: "Charisma Experience",
value: player.mults.charisma_exp, value: Player.mults.charisma_exp,
}, },
]} ]}
color={Settings.theme.cha} color={Settings.theme.cha}
@ -473,24 +468,24 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Hacknet Node Production", mult: "Hacknet Node Production",
value: player.mults.hacknet_node_money, value: Player.mults.hacknet_node_money,
effValue: player.mults.hacknet_node_money * BitNodeMultipliers.HacknetNodeMoney, effValue: Player.mults.hacknet_node_money * BitNodeMultipliers.HacknetNodeMoney,
}, },
{ {
mult: "Hacknet Node Purchase Cost", mult: "Hacknet Node Purchase Cost",
value: player.mults.hacknet_node_purchase_cost, value: Player.mults.hacknet_node_purchase_cost,
}, },
{ {
mult: "Hacknet Node RAM Upgrade Cost", mult: "Hacknet Node RAM Upgrade Cost",
value: player.mults.hacknet_node_ram_cost, value: Player.mults.hacknet_node_ram_cost,
}, },
{ {
mult: "Hacknet Node Core Purchase Cost", mult: "Hacknet Node Core Purchase Cost",
value: player.mults.hacknet_node_core_cost, value: Player.mults.hacknet_node_core_cost,
}, },
{ {
mult: "Hacknet Node Level Upgrade Cost", mult: "Hacknet Node Level Upgrade Cost",
value: player.mults.hacknet_node_level_cost, value: Player.mults.hacknet_node_level_cost,
}, },
]} ]}
color={Settings.theme.primary} color={Settings.theme.primary}
@ -499,19 +494,19 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Company Reputation Gain", mult: "Company Reputation Gain",
value: player.mults.company_rep, value: Player.mults.company_rep,
color: Settings.theme.rep, color: Settings.theme.rep,
}, },
{ {
mult: "Faction Reputation Gain", mult: "Faction Reputation Gain",
value: player.mults.faction_rep, value: Player.mults.faction_rep,
effValue: player.mults.faction_rep * BitNodeMultipliers.FactionWorkRepGain, effValue: Player.mults.faction_rep * BitNodeMultipliers.FactionWorkRepGain,
color: Settings.theme.rep, color: Settings.theme.rep,
}, },
{ {
mult: "Salary", mult: "Salary",
value: player.mults.work_money, value: Player.mults.work_money,
effValue: player.mults.work_money * BitNodeMultipliers.CompanyWorkMoney, effValue: Player.mults.work_money * BitNodeMultipliers.CompanyWorkMoney,
color: Settings.theme.money, color: Settings.theme.money,
}, },
]} ]}
@ -521,35 +516,35 @@ export function CharacterStats(): React.ReactElement {
rows={[ rows={[
{ {
mult: "Crime Success Chance", mult: "Crime Success Chance",
value: player.mults.crime_success, value: Player.mults.crime_success,
}, },
{ {
mult: "Crime Money", mult: "Crime Money",
value: player.mults.crime_money, value: Player.mults.crime_money,
effValue: player.mults.crime_money * BitNodeMultipliers.CrimeMoney, effValue: Player.mults.crime_money * BitNodeMultipliers.CrimeMoney,
color: Settings.theme.money, color: Settings.theme.money,
}, },
]} ]}
color={Settings.theme.combat} color={Settings.theme.combat}
/> />
{player.canAccessBladeburner() && BitNodeMultipliers.BladeburnerRank > 0 && ( {Player.canAccessBladeburner() && BitNodeMultipliers.BladeburnerRank > 0 && (
<MultiplierTable <MultiplierTable
rows={[ rows={[
{ {
mult: "Bladeburner Success Chance", mult: "Bladeburner Success Chance",
value: player.mults.bladeburner_success_chance, value: Player.mults.bladeburner_success_chance,
}, },
{ {
mult: "Bladeburner Max Stamina", mult: "Bladeburner Max Stamina",
value: player.mults.bladeburner_max_stamina, value: Player.mults.bladeburner_max_stamina,
}, },
{ {
mult: "Bladeburner Stamina Gain", mult: "Bladeburner Stamina Gain",
value: player.mults.bladeburner_stamina_gain, value: Player.mults.bladeburner_stamina_gain,
}, },
{ {
mult: "Bladeburner Field Analysis", mult: "Bladeburner Field Analysis",
value: player.mults.bladeburner_analysis, value: Player.mults.bladeburner_analysis,
}, },
]} ]}
color={Settings.theme.primary} color={Settings.theme.primary}
@ -576,7 +571,7 @@ export function CharacterStats(): React.ReactElement {
{showBitNodeMults && ( {showBitNodeMults && (
<Paper sx={{ p: 1, mb: 1 }}> <Paper sx={{ p: 1, mb: 1 }}>
<Typography variant="h5">BitNode Multipliers</Typography> <Typography variant="h5">BitNode Multipliers</Typography>
<BitNodeMultipliersDisplay n={player.bitNodeN} /> <BitNodeMultipliersDisplay n={Player.bitNodeN} />
</Paper> </Paper>
)} )}

@ -1,19 +0,0 @@
import React, { useContext } from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { IRouter } from "./Router";
export const Context: {
Player: React.Context<IPlayer>;
Router: React.Context<IRouter>;
} = {
Player: React.createContext<IPlayer>({} as IPlayer),
Router: React.createContext<IRouter>({} as IRouter),
};
export const use: {
Player: () => IPlayer;
Router: () => IRouter;
} = {
Player: () => useContext(Context.Player),
Router: () => useContext(Context.Router),
};

@ -64,8 +64,6 @@ import { PromptManager } from "./React/PromptManager";
import { InvitationModal } from "../Faction/ui/InvitationModal"; import { InvitationModal } from "../Faction/ui/InvitationModal";
import { calculateAchievements } from "../Achievements/Achievements"; import { calculateAchievements } from "../Achievements/Achievements";
import { enterBitNode } from "../RedPill";
import { Context } from "./Context";
import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot"; import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot";
import { AchievementsRoot } from "../Achievements/AchievementsRoot"; import { AchievementsRoot } from "../Achievements/AchievementsRoot";
import { ErrorBoundary } from "./ErrorBoundary"; import { ErrorBoundary } from "./ErrorBoundary";
@ -316,7 +314,7 @@ export function GameRoot(): React.ReactElement {
break; break;
} }
case Page.BitVerse: { case Page.BitVerse: {
mainPage = <BitverseRoot flume={flume} enter={enterBitNode} quick={quick} />; mainPage = <BitverseRoot flume={flume} quick={quick} />;
withSidebar = false; withSidebar = false;
withPopups = false; withPopups = false;
break; break;

@ -20,7 +20,8 @@ import SaveIcon from "@mui/icons-material/Save";
import ClearAllIcon from "@mui/icons-material/ClearAll"; import ClearAllIcon from "@mui/icons-material/ClearAll";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { use } from "../Context"; import { Router } from "../GameRoot";
import { Player } from "../../Player";
import { StatsProgressOverviewCell } from "./StatsProgressBar"; import { StatsProgressOverviewCell } from "./StatsProgressBar";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
@ -42,10 +43,9 @@ interface IProps {
function Intelligence(): React.ReactElement { function Intelligence(): React.ReactElement {
const theme = useTheme(); const theme = useTheme();
const player = use.Player();
const classes = useStyles(); const classes = useStyles();
if (player.skills.intelligence === 0) return <></>; if (Player.skills.intelligence === 0) return <></>;
const progress = player.calculateSkillProgress(player.exp.intelligence); const progress = Player.calculateSkillProgress(Player.exp.intelligence);
return ( return (
<> <>
@ -55,7 +55,7 @@ function Intelligence(): React.ReactElement {
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cell }}> <TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}> <Typography classes={{ root: classes.int }}>
{numeralWrapper.formatSkill(player.skills.intelligence)} {numeralWrapper.formatSkill(Player.skills.intelligence)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cell }}> <TableCell align="right" classes={{ root: classes.cell }}>
@ -75,9 +75,8 @@ function Intelligence(): React.ReactElement {
} }
function Bladeburner(): React.ReactElement { function Bladeburner(): React.ReactElement {
const player = use.Player();
const classes = useStyles(); const classes = useStyles();
const bladeburner = player.bladeburner; const bladeburner = Player.bladeburner;
if (bladeburner === null) return <></>; if (bladeburner === null) return <></>;
const action = bladeburner.getTypeAndNameFromActionId(bladeburner.action); const action = bladeburner.getTypeAndNameFromActionId(bladeburner.action);
if (action.type === "Idle") return <></>; if (action.type === "Idle") return <></>;
@ -141,32 +140,30 @@ function WorkInProgressOverview({
} }
function Work(): React.ReactElement { function Work(): React.ReactElement {
const player = use.Player();
const router = use.Router();
const onClickFocus = (): void => { const onClickFocus = (): void => {
player.startFocusing(); Player.startFocusing();
router.toWork(); Router.toWork();
}; };
if (player.currentWork === null || player.focus) return <></>; if (Player.currentWork === null || Player.focus) return <></>;
let details = <></>; let details = <></>;
let header = <></>; let header = <></>;
let innerText = <></>; let innerText = <></>;
if (isCrimeWork(player.currentWork)) { if (isCrimeWork(Player.currentWork)) {
const crime = player.currentWork.getCrime(); const crime = Player.currentWork.getCrime();
const perc = (player.currentWork.unitCompleted / crime.time) * 100; const perc = (Player.currentWork.unitCompleted / crime.time) * 100;
details = <>{player.currentWork.crimeType}</>; details = <>{Player.currentWork.crimeType}</>;
header = <>You are attempting to {player.currentWork.crimeType}</>; header = <>You are attempting to {Player.currentWork.crimeType}</>;
innerText = <>{perc.toFixed(2)}%</>; innerText = <>{perc.toFixed(2)}%</>;
} }
if (isClassWork(player.currentWork)) { if (isClassWork(Player.currentWork)) {
details = <>{player.currentWork.getClass().youAreCurrently}</>; details = <>{Player.currentWork.getClass().youAreCurrently}</>;
header = <>You are {player.currentWork.getClass().youAreCurrently}</>; header = <>You are {Player.currentWork.getClass().youAreCurrently}</>;
innerText = <>{convertTimeMsToTimeElapsedString(player.currentWork.cyclesWorked * CONSTANTS._idleSpeed)}</>; innerText = <>{convertTimeMsToTimeElapsedString(Player.currentWork.cyclesWorked * CONSTANTS._idleSpeed)}</>;
} }
if (isCreateProgramWork(player.currentWork)) { if (isCreateProgramWork(Player.currentWork)) {
const create = player.currentWork; const create = Player.currentWork;
details = <>Coding {create.programName}</>; details = <>Coding {create.programName}</>;
header = <>Creating a program</>; header = <>Creating a program</>;
innerText = ( innerText = (
@ -175,8 +172,8 @@ function Work(): React.ReactElement {
</> </>
); );
} }
if (isGraftingWork(player.currentWork)) { if (isGraftingWork(Player.currentWork)) {
const graft = player.currentWork; const graft = Player.currentWork;
details = <>Grafting {graft.augmentation}</>; details = <>Grafting {graft.augmentation}</>;
header = <>Grafting an Augmentation</>; header = <>Grafting an Augmentation</>;
innerText = ( innerText = (
@ -186,8 +183,8 @@ function Work(): React.ReactElement {
); );
} }
if (isFactionWork(player.currentWork)) { if (isFactionWork(Player.currentWork)) {
const factionWork = player.currentWork; const factionWork = Player.currentWork;
header = ( header = (
<> <>
Working for <strong>{factionWork.factionName}</strong> Working for <strong>{factionWork.factionName}</strong>
@ -201,11 +198,11 @@ function Work(): React.ReactElement {
</> </>
); );
} }
if (isCompanyWork(player.currentWork)) { if (isCompanyWork(Player.currentWork)) {
const companyWork = player.currentWork; const companyWork = Player.currentWork;
details = ( details = (
<> <>
{player.jobs[companyWork.companyName]} at <strong>{companyWork.companyName}</strong> {Player.jobs[companyWork.companyName]} at <strong>{companyWork.companyName}</strong>
</> </>
); );
header = ( header = (
@ -215,7 +212,7 @@ function Work(): React.ReactElement {
); );
innerText = ( innerText = (
<> <>
<Reputation reputation={companyWork.getCompany().playerReputation} /> rep <Reputation reputation={companyWork.getCompany().PlayerReputation} /> rep
<br />( <br />(
<ReputationRate reputation={companyWork.getGainRates().reputation * (1000 / CONSTANTS._idleSpeed)} />) <ReputationRate reputation={companyWork.getGainRates().reputation * (1000 / CONSTANTS._idleSpeed)} />)
</> </>
@ -281,41 +278,37 @@ export { useStyles as characterOverviewStyles };
export function CharacterOverview({ save, killScripts }: IProps): React.ReactElement { export function CharacterOverview({ save, killScripts }: IProps): React.ReactElement {
const [killOpen, setKillOpen] = useState(false); const [killOpen, setKillOpen] = useState(false);
const player = use.Player();
const setRerender = useState(false)[1]; const setRerender = useState(false)[1];
useEffect(() => { useEffect(() => {
const id = setInterval(() => setRerender((old) => !old), 600); const id = setInterval(() => setRerender((old) => !old), 600);
return () => clearInterval(id); return () => clearInterval(id);
}, []); }, []);
const classes = useStyles(); const classes = useStyles();
const theme = useTheme(); const theme = useTheme();
const hackingProgress = player.calculateSkillProgress( const hackingProgress = Player.calculateSkillProgress(
player.exp.hacking, Player.exp.hacking,
player.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier, Player.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier,
); );
const strengthProgress = player.calculateSkillProgress( const strengthProgress = Player.calculateSkillProgress(
player.exp.strength, Player.exp.strength,
player.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier, Player.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier,
); );
const defenseProgress = player.calculateSkillProgress( const defenseProgress = Player.calculateSkillProgress(
player.exp.defense, Player.exp.defense,
player.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier, Player.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier,
); );
const dexterityProgress = player.calculateSkillProgress( const dexterityProgress = Player.calculateSkillProgress(
player.exp.dexterity, Player.exp.dexterity,
player.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier, Player.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier,
); );
const agilityProgress = player.calculateSkillProgress( const agilityProgress = Player.calculateSkillProgress(
player.exp.agility, Player.exp.agility,
player.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier, Player.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier,
); );
const charismaProgress = player.calculateSkillProgress( const charismaProgress = Player.calculateSkillProgress(
player.exp.charisma, Player.exp.charisma,
player.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier, Player.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier,
); );
return ( return (
@ -328,7 +321,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.hp }}> <Typography classes={{ root: classes.hp }}>
{numeralWrapper.formatHp(player.hp.current)}&nbsp;/&nbsp;{numeralWrapper.formatHp(player.hp.max)} {numeralWrapper.formatHp(Player.hp.current)}&nbsp;/&nbsp;{numeralWrapper.formatHp(Player.hp.max)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
@ -343,7 +336,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
<Typography classes={{ root: classes.money }}>Money&nbsp;</Typography> <Typography classes={{ root: classes.money }}>Money&nbsp;</Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.money }}>{numeralWrapper.formatMoney(player.money)}</Typography> <Typography classes={{ root: classes.money }}>{numeralWrapper.formatMoney(Player.money)}</Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-money-hook" classes={{ root: classes.money }}> <Typography id="overview-money-hook" classes={{ root: classes.money }}>
@ -358,7 +351,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.hack }}> <Typography classes={{ root: classes.hack }}>
{numeralWrapper.formatSkill(player.skills.hacking)} {numeralWrapper.formatSkill(Player.skills.hacking)}
</Typography> </Typography>
</TableCell> </TableCell>
</TableRow> </TableRow>
@ -384,7 +377,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}> <Typography classes={{ root: classes.combat }}>
{numeralWrapper.formatSkill(player.skills.strength)} {numeralWrapper.formatSkill(Player.skills.strength)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
@ -405,7 +398,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}> <Typography classes={{ root: classes.combat }}>
{numeralWrapper.formatSkill(player.skills.defense)} {numeralWrapper.formatSkill(Player.skills.defense)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
@ -426,7 +419,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}> <Typography classes={{ root: classes.combat }}>
{numeralWrapper.formatSkill(player.skills.dexterity)} {numeralWrapper.formatSkill(Player.skills.dexterity)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
@ -447,7 +440,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cell }}> <TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.combat }}> <Typography classes={{ root: classes.combat }}>
{numeralWrapper.formatSkill(player.skills.agility)} {numeralWrapper.formatSkill(Player.skills.agility)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cell }}> <TableCell align="right" classes={{ root: classes.cell }}>
@ -468,7 +461,7 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.cha }}> <Typography classes={{ root: classes.cha }}>
{numeralWrapper.formatSkill(player.skills.charisma)} {numeralWrapper.formatSkill(Player.skills.charisma)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}> <TableCell align="right" classes={{ root: classes.cellNone }}>

@ -7,7 +7,7 @@ import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
import EqualizerIcon from "@mui/icons-material/Equalizer"; import EqualizerIcon from "@mui/icons-material/Equalizer";
import SchoolIcon from "@mui/icons-material/School"; import SchoolIcon from "@mui/icons-material/School";
import { use } from "../Context"; import { Router } from "../GameRoot";
import { Page } from "../Router"; import { Page } from "../Router";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { Box, Button, Typography } from "@mui/material"; import { Box, Button, Typography } from "@mui/material";
@ -69,7 +69,6 @@ export function Overview({ children, mode }: IProps): React.ReactElement {
const [x, setX] = useState(Settings.overview.x); const [x, setX] = useState(Settings.overview.x);
const [y, setY] = useState(Settings.overview.y); const [y, setY] = useState(Settings.overview.y);
const classes = useStyles(); const classes = useStyles();
const router = use.Router();
const CurrentIcon = open ? KeyboardArrowUpIcon : KeyboardArrowDownIcon; const CurrentIcon = open ? KeyboardArrowUpIcon : KeyboardArrowDownIcon;
const LeftIcon = mode === "tutorial" ? SchoolIcon : EqualizerIcon; const LeftIcon = mode === "tutorial" ? SchoolIcon : EqualizerIcon;
@ -113,7 +112,7 @@ export function Overview({ children, mode }: IProps): React.ReactElement {
node.dispatchEvent(clickEvent); node.dispatchEvent(clickEvent);
}; };
if (router.page() === Page.BitVerse || router.page() === Page.Loading || router.page() === Page.Recovery) if (Router.page() === Page.BitVerse || Router.page() === Page.Loading || Router.page() === Page.Recovery)
return <></>; return <></>;
return ( return (
<Draggable handle=".drag" bounds="body" onStop={handleStop} defaultPosition={{ x, y }}> <Draggable handle=".drag" bounds="body" onStop={handleStop} defaultPosition={{ x, y }}>