Internal refactoring of Router (#241)

This commit is contained in:
David Walker 2022-12-04 00:14:06 -08:00 committed by GitHub
parent 897a1fbc8e
commit 8d793ea271
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 292 additions and 383 deletions

@ -21,6 +21,7 @@ import {
initUnstableCircadianModulator,
} from "./data/AugmentationCreator";
import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router";
import { mergeMultipliers } from "../PersonObjects/Multipliers";
export function AddToStaticAugmentations(aug: Augmentation): void {
@ -138,7 +139,7 @@ function installAugmentations(force?: boolean): boolean {
);
}
prestigeAugmentation();
Router.toTerminal();
Router.toPage(Page.Terminal);
return true;
}

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

@ -3,6 +3,7 @@ import React, { useState } from "react";
import { Money } from "../../../ui/React/Money";
import { Modal } from "../../../ui/React/Modal";
import { Router } from "../../../ui/GameRoot";
import { Page } from "../../../ui/Router";
import { Player } from "@player";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@ -33,7 +34,7 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
Player.loseMoney(150e9, "corporation");
props.onClose();
Router.toCorporation();
Router.toPage(Page.Corporation);
}
function seed(): void {
@ -44,7 +45,7 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
Player.startCorporation(name, 500e6);
props.onClose();
Router.toCorporation();
Router.toPage(Page.Corporation);
}
return (

@ -1,6 +1,7 @@
import React from "react";
import { FactionNames } from "./data/FactionNames";
import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router";
import { Option } from "./ui/Option";
import { Typography } from "@mui/material";
@ -432,7 +433,7 @@ export const FactionInfos: Record<string, FactionInfo> = {
<Option
buttonText={"Open Bladeburner headquarters"}
infoText={"You can gain reputation with bladeburner by completing contracts and operations."}
onClick={() => Router.toBladeburner()}
onClick={() => Router.toPage(Page.Bladeburner)}
/>
);
},
@ -484,7 +485,7 @@ export const FactionInfos: Record<string, FactionInfo> = {
"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."
}
onClick={() => Router.toStaneksGift()}
onClick={() => Router.toPage(Page.StaneksGift)}
/>
);
},

@ -1,6 +1,7 @@
import React from "react";
import { Modal } from "../../ui/React/Modal";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@ -32,7 +33,7 @@ export function CreateGangModal(props: IProps): React.ReactElement {
function createGang(): void {
Player.startGang(props.facName, isHacking());
props.onClose();
Router.toGang();
Router.toPage(Page.Gang);
}
function onKeyUp(event: React.KeyboardEvent): void {

@ -16,6 +16,7 @@ import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Faction } from "../Faction";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Typography, Button } from "@mui/material";
@ -64,7 +65,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
function startWork(): void {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}
function startFieldWork(faction: Faction): void {
@ -113,7 +114,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
return (
<>
<Button onClick={() => Router.toFactions()}>Back</Button>
<Button onClick={() => Router.toPage(Page.Factions)}>Back</Button>
<Typography variant="h4" color="primary">
{faction.name}
</Typography>
@ -171,7 +172,7 @@ export function FactionRoot(props: IProps): React.ReactElement {
<Typography variant="h4" color="primary">
You have not joined {faction.name} yet!
</Typography>
<Button onClick={() => Router.toFactions()}>Back to Factions</Button>
<Button onClick={() => Router.toPage(Page.Factions)}>Back to Factions</Button>
</>
);
}

@ -2,6 +2,7 @@ import { Button, Typography, Box, Paper, Tooltip } from "@mui/material";
import React, { useState } from "react";
import { GangConstants } from "../../Gang/data/Constants";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Faction } from "../Faction";
import { CreateGangModal } from "./CreateGangModal";
@ -51,7 +52,7 @@ export function GangButton({ faction }: IProps): React.ReactElement {
const manageGang = (): void => {
// If player already has a gang, just go to the gang UI
if (Player.inGang()) {
return Router.toGang();
return Router.toPage(Page.Gang);
}
setGangOpen(true);

@ -22,6 +22,7 @@ import { DeleteGameButton } from "../../ui/React/DeleteGameButton";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
import { SoftResetButton } from "../../ui/React/SoftResetButton";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { GameOptionsTab } from "../GameOptionsTab";
@ -216,7 +217,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
</Button>
</Tooltip>
<Tooltip title="Head to the theme browser to see a collection of prebuilt themes.">
<Button startIcon={<Palette />} onClick={() => Router.toThemeBrowser()} sx={{ gridArea: "browse" }}>
<Button startIcon={<Palette />} onClick={() => Router.toPage(Page.ThemeBrowser)} sx={{ gridArea: "browse" }}>
Theme Browser
</Button>
</Tooltip>

@ -2,6 +2,7 @@ import { Button, Container, Paper, Typography } from "@mui/material";
import React, { useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { BackwardGame } from "./BackwardGame";
import { BracketGame } from "./BracketGame";
@ -93,14 +94,14 @@ export function Game(props: IProps): React.ReactElement {
? Player.hp.current
: props.StartingDifficulty * 3 * (Player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 0.5 : 1);
if (Player.takeDamage(damage)) {
Router.toCity();
Router.toPage(Page.City);
return;
}
setupNextGame();
}
function cancel(): void {
Router.toCity();
Router.toPage(Page.City);
return;
}

@ -1,6 +1,7 @@
import React, { useState } from "react";
import { Location } from "../../Locations/Location";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { calculateDifficulty, calculateReward } from "../formulas/game";
import { Game } from "./Game";
import { Intro } from "./Intro";
@ -17,7 +18,7 @@ export function InfiltrationRoot(props: IProps): React.ReactElement {
const reward = calculateReward(startingSecurityLevel);
function cancel(): void {
Router.toCity();
Router.toPage(Page.City);
}
return (

@ -4,6 +4,7 @@ import { FactionNames } from "../../Faction/data/FactionNames";
import { inviteToFaction } from "../../Faction/FactionHelpers";
import { Factions } from "../../Faction/Factions";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Money } from "../../ui/React/Money";
import { Reputation } from "../../ui/React/Reputation";
@ -26,7 +27,7 @@ export function Victory(props: IProps): React.ReactElement {
function quitInfiltration(): void {
handleInfiltrators();
Router.toCity();
Router.toPage(Page.City);
}
const soa = Factions[FactionNames.ShadowsOfAnarchy];

@ -14,6 +14,7 @@ import { Settings } from "../../Settings/Settings";
import { Player } from "@player";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { LocationType } from "../LocationTypeEnum";
@ -39,9 +40,9 @@ const useStyles = makeStyles((theme: Theme) =>
function toLocation(location: Location): void {
if (location.name === LocationName.TravelAgency) {
Router.toTravel();
Router.toPage(Page.Travel);
} else if (location.name === LocationName.WorldStockExchange) {
Router.toStockMarket();
Router.toPage(Page.StockMarket);
} else {
Router.toLocation(location);
}

@ -21,6 +21,7 @@ import * as posNames from "../../Company/data/companypositionnames";
import { Reputation } from "../../ui/React/Reputation";
import { Favor } from "../../ui/React/Favor";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { QuitJobModal } from "../../Company/ui/QuitJobModal";
import { CompanyWork } from "../../Work/CompanyWork";
@ -177,7 +178,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
}),
);
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}
}

@ -28,6 +28,7 @@ import { GetServer } from "../../Server/AllServers";
import { CorruptableText } from "../../ui/React/CorruptableText";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { serverMetadata } from "../../Server/data/servers";
import { Tooltip } from "@mui/material";
@ -90,7 +91,7 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
return (
<>
<Button onClick={() => Router.toCity()}>Return to World</Button>
<Button onClick={() => Router.toPage(Page.City)}>Return to World</Button>
<Typography variant="h4" sx={{ mt: 1 }}>
{backdoorInstalled && !Settings.DisableTextEffects ? (
<Tooltip title={`Backdoor installed on ${loc.name}.`}>

@ -12,6 +12,7 @@ import { Player } from "@player";
import { Money } from "../../ui/React/Money";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Box } from "@mui/material";
import { ClassWork, Classes } from "../../Work/ClassWork";
import { calculateCost } from "../../Work/Formulas";
@ -31,7 +32,7 @@ export function GymLocation(props: IProps): React.ReactElement {
}),
);
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}
const cost = calculateCost(Classes[GymType.strength], props.loc);

@ -11,6 +11,7 @@ import { Crimes } from "../../Crime/Crimes";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Box } from "@mui/material";
import { Crime } from "../../Crime/Crime";
@ -27,7 +28,7 @@ export function SlumsLocation(): React.ReactElement {
function doCrime(e: React.MouseEvent<HTMLElement>, crime: Crime) {
if (!e.isTrusted) return;
crime.commit();
Router.toWork();
Router.toPage(Page.Work);
Player.focus = true;
}

@ -22,6 +22,7 @@ import { Factions } from "../../Faction/Factions";
import { joinFaction } from "../../Faction/FactionHelpers";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
@ -48,7 +49,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function handleBladeburner(): void {
if (Player.bladeburner) {
// Enter Bladeburner division
Router.toBladeburner();
Router.toPage(Page.Bladeburner);
} else if (
Player.skills.strength >= 100 &&
Player.skills.defense >= 100 &&
@ -72,7 +73,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
/** Click handler for Resleeving button at New Tokyo VitaLife */
function handleGrafting(): void {
Router.toGrafting();
Router.toPage(Page.Grafting);
}
function renderBladeburner(): React.ReactElement {
@ -173,11 +174,11 @@ export function SpecialLocation(props: IProps): React.ReactElement {
applyAugmentation({ name: AugmentationNames.StaneksGift1, level: 1 });
}
Router.toStaneksGift();
Router.toPage(Page.StaneksGift);
}
function renderCotMG(): React.ReactElement {
const toStanek = <Button onClick={() => Router.toStaneksGift()}>Open Stanek's Gift</Button>;
const toStanek = <Button onClick={() => Router.toPage(Page.StaneksGift)}>Open Stanek's Gift</Button>;
// prettier-ignore
const symbol = <Typography sx={{ lineHeight: '1em', whiteSpace: 'pre' }}>
{" `` "}<br />

@ -11,6 +11,7 @@ import { TravelConfirmationModal } from "./TravelConfirmationModal";
import { CONSTANTS } from "../../Constants";
import { Player } from "@player";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Settings } from "../../Settings/Settings";
import { Money } from "../../ui/React/Money";
@ -30,7 +31,7 @@ function travel(to: CityName): void {
Player.loseMoney(cost, "other");
Player.travel(to);
dialogBoxCreate(`You are now in ${to}!`);
Router.toCity();
Router.toPage(Page.City);
}
export function TravelAgencyRoot(): React.ReactElement {

@ -11,6 +11,7 @@ import { Location } from "../Location";
import { Money } from "../../ui/React/Money";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Box } from "@mui/material";
@ -32,7 +33,7 @@ export function UniversityLocation(props: IProps): React.ReactElement {
}),
);
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}
const dataStructuresCost = calculateCost(Classes[UniversityClassType.dataStructures], props.loc);

@ -7,6 +7,7 @@ import { getGraftingAvailableAugs, calculateGraftingTimeWithBonus } from "../Per
import { Player as player } from "../Player";
import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions";
import { Router } from "../ui/GameRoot";
import { Page } from "../ui/Router";
import { GraftingWork } from "../Work/GraftingWork";
import { helpers } from "../Netscript/NetscriptHelpers";
@ -83,10 +84,10 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
if (focus) {
player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Began grafting Augmentation ${augName}.`);

@ -240,9 +240,9 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
return false;
}
if (location.name === LocationName.TravelAgency) {
Router.toTravel();
Router.toPage(Page.Travel);
} else if (location.name === LocationName.WorldStockExchange) {
Router.toStockMarket();
Router.toPage(Page.StockMarket);
} else {
Router.toLocation(location);
}
@ -307,10 +307,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Started ${classType} at ${universityName}`);
return true;
@ -393,10 +393,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.startWork(new ClassWork({ classType, location: Player.location, singularity: true }));
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Started training ${classType} at ${gymName}`);
return true;
@ -594,11 +594,11 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
if (!Player.focus && focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
return true;
} else if (Player.focus && !focus) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
return true;
}
return false;
@ -723,10 +723,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocused) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Began working at '${companyName}' with position '${companyPositionName}'`);
return true;
@ -889,10 +889,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Started carrying out hacking contracts for '${faction.name}'`);
return true;
@ -912,10 +912,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Started carrying out field missions for '${faction.name}'`);
return true;
@ -935,10 +935,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Started carrying out security work for '${faction.name}'`);
return true;
@ -1054,10 +1054,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
helpers.log(ctx, () => `Began creating program: '${programName}'`);
return true;
@ -1079,10 +1079,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
const crimeTime = crime.commit(1, ctx.workerScript);
if (focus) {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
} else if (wasFocusing) {
Player.stopFocusing();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
return crimeTime;
},

@ -12,6 +12,7 @@ import { Locations } from "../../../Locations/Locations";
import { PurchaseAugmentationsOrderSetting } from "../../../Settings/SettingEnums";
import { Settings } from "../../../Settings/Settings";
import { Router } from "../../../ui/GameRoot";
import { Page } from "../../../ui/Router";
import { ConfirmationModal } from "../../../ui/React/ConfirmationModal";
import { Money } from "../../../ui/React/Money";
import { convertTimeMsToTimeElapsedString, formatNumber } from "../../../utils/StringHelperFunctions";
@ -158,7 +159,7 @@ export const GraftingRoot = (): React.ReactElement => {
}),
);
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}}
confirmationText={
<>

@ -5,6 +5,7 @@ import { Box, Typography, Button, Container, Paper } from "@mui/material";
import { Check, Lock, Create } from "@mui/icons-material";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Settings } from "../../Settings/Settings";
@ -99,7 +100,7 @@ export function ProgramsRoot(): React.ReactElement {
if (!event.isTrusted) return;
Player.startWork(new CreateProgramWork({ singularity: false, programName: program.name }));
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
}}
>
Create program

@ -7,6 +7,7 @@ import { SourceFiles } from "./SourceFile/SourceFiles";
import { dialogBoxCreate } from "./ui/React/DialogBox";
import { Router } from "./ui/GameRoot";
import { Page } from "./ui/Router";
function giveSourceFile(bitNodeNumber: number): void {
const sourceFileKey = "SourceFile" + bitNodeNumber.toString();
@ -68,9 +69,9 @@ export function enterBitNode(flume: boolean, destroyedBitNode: number, newBitNod
Player.bitNodeN = newBitNode;
if (newBitNode === 6) {
Router.toBladeburnerCinematic();
Router.toPage(Page.BladeburnerCinematic);
} else {
Router.toTerminal();
Router.toPage(Page.Terminal);
}
prestigeSourceFile(flume);
}

@ -9,6 +9,7 @@ import { Options } from "./Options";
import { isValidFilePath } from "../../Terminal/DirectoryHelpers";
import { Player } from "@player";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { isScriptFilename } from "../../Script/isScriptFilename";
import { Script } from "../../Script/Script";
@ -154,7 +155,7 @@ export function Root(props: IProps): React.ReactElement {
//Ctrl + b
if (event.code == "KeyB" && (event.ctrlKey || event.metaKey)) {
event.preventDefault();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
// CTRL/CMD + S
@ -181,12 +182,12 @@ export function Root(props: IProps): React.ReactElement {
save();
});
MonacoVim.VimMode.Vim.defineEx("quit", "q", function () {
Router.toTerminal();
Router.toPage(Page.Terminal);
});
const saveNQuit = (): void => {
save();
Router.toTerminal();
Router.toPage(Page.Terminal);
};
// "wqriteandquit" & "xriteandquit" are not typos, prefix must be found in full string
MonacoVim.VimMode.Vim.defineEx("wqriteandquit", "wq", saveNQuit);
@ -465,7 +466,7 @@ export function Root(props: IProps): React.ReactElement {
if (scriptToSave.fileName == server.scripts[i].filename) {
server.scripts[i].saveScript(scriptToSave.fileName, scriptToSave.code, Player.currentServer, server.scripts);
if (Settings.SaveGameOnFileSave) saveObject.saveGame();
Router.toTerminal();
Router.toPage(Page.Terminal);
return;
}
}
@ -479,7 +480,7 @@ export function Root(props: IProps): React.ReactElement {
if (server.textFiles[i].fn === scriptToSave.fileName) {
server.textFiles[i].write(scriptToSave.code);
if (Settings.SaveGameOnFileSave) saveObject.saveGame();
Router.toTerminal();
Router.toPage(Page.Terminal);
return;
}
}
@ -491,7 +492,7 @@ export function Root(props: IProps): React.ReactElement {
}
if (Settings.SaveGameOnFileSave) saveObject.saveGame();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
function save(): void {
@ -646,7 +647,7 @@ export function Root(props: IProps): React.ReactElement {
openScripts.splice(index, 1);
if (openScripts.length === 0) {
currentScript = null;
Router.toTerminal();
Router.toPage(Page.Terminal);
return;
}
@ -900,7 +901,7 @@ export function Root(props: IProps): React.ReactElement {
{ram}
</Button>
<Button onClick={save}>Save (Ctrl/Cmd + s)</Button>
<Button sx={{ mx: 1 }} onClick={Router.toTerminal}>
<Button sx={{ mx: 1 }} onClick={() => Router.toPage(Page.Terminal)}>
Terminal (Ctrl/Cmd + b)
</Button>
<Typography>

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useCallback, useState, useEffect } from "react";
import { KEYCODE } from "../../utils/helpers/keyCodes";
import clsx from "clsx";
import { styled, Theme, CSSObject } from "@mui/material/styles";
@ -46,7 +46,7 @@ import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Page, SimplePage } from "../../ui/Router";
import { Player } from "@player";
import { CONSTANTS } from "../../Constants";
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../../InteractiveTutorial";
@ -105,8 +105,6 @@ const useStyles = makeStyles((theme: Theme) =>
interface IProps {
page: Page;
opened: boolean;
onToggled: (newValue: boolean) => void;
}
export function SidebarRoot(props: IProps): React.ReactElement {
@ -125,19 +123,28 @@ export function SidebarRoot(props: IProps): React.ReactElement {
const [worldOpen, setWorldOpen] = useState(true);
const [helpOpen, setHelpOpen] = useState(true);
const flashTerminal =
ITutorial.currStep === iTutorialSteps.CharacterGoToTerminalPage ||
ITutorial.currStep === iTutorialSteps.ActiveScriptsPage;
const flashStats = ITutorial.currStep === iTutorialSteps.GoToCharacterPage;
const flashActiveScripts = ITutorial.currStep === iTutorialSteps.TerminalGoToActiveScriptsPage;
const flashHacknet = ITutorial.currStep === iTutorialSteps.GoToHacknetNodesPage;
const flashCity = ITutorial.currStep === iTutorialSteps.HacknetNodesGoToWorldPage;
const flashTutorial = ITutorial.currStep === iTutorialSteps.WorldDescription;
let flash: Page | null = null;
switch (ITutorial.currStep) {
case iTutorialSteps.CharacterGoToTerminalPage:
case iTutorialSteps.ActiveScriptsPage:
flash = Page.Terminal;
break;
case iTutorialSteps.GoToCharacterPage:
flash = Page.Stats;
break;
case iTutorialSteps.TerminalGoToActiveScriptsPage:
flash = Page.ActiveScripts;
break;
case iTutorialSteps.GoToHacknetNodesPage:
flash = Page.Hacknet;
break;
case iTutorialSteps.HacknetNodesGoToWorldPage:
flash = Page.City;
break;
case iTutorialSteps.WorldDescription:
flash = Page.Tutorial;
break;
}
const augmentationCount = Player.queuedAugmentations.length;
const invitationsCount = Player.factionInvitations.filter((f) => !InvitationsSeen.includes(f)).length;
@ -162,99 +169,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
const canBladeburner = !!Player.bladeburner;
const canStaneksGift = Player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1);
function clickTerminal(): void {
Router.toTerminal();
if (flashTerminal) iTutorialNextStep();
}
function clickScriptEditor(): void {
Router.toScriptEditor();
}
function clickStats(): void {
Router.toStats();
if (flashStats) iTutorialNextStep();
}
function clickActiveScripts(): void {
Router.toActiveScripts();
if (flashActiveScripts) iTutorialNextStep();
}
function clickCreateProgram(): void {
Router.toCreateProgram();
}
function clickStaneksGift(): void {
Router.toStaneksGift();
}
function clickFactions(): void {
Router.toFactions();
}
function clickAugmentations(): void {
Router.toAugmentations();
}
function clickSleeves(): void {
Router.toSleeves();
}
function clickHacknet(): void {
Router.toHacknetNodes();
if (flashHacknet) iTutorialNextStep();
}
function clickCity(): void {
Router.toCity();
if (flashCity) iTutorialNextStep();
}
function clickTravel(): void {
Router.toTravel();
}
function clickJob(): void {
Router.toJob(Locations[Object.keys(Player.jobs)[0]]);
}
function clickStockMarket(): void {
Router.toStockMarket();
}
function clickBladeburner(): void {
Router.toBladeburner();
}
function clickCorp(): void {
Router.toCorporation();
}
function clickGang(): void {
Router.toGang();
}
function clickTutorial(): void {
Router.toTutorial();
if (flashTutorial) iTutorialNextStep();
}
function clickMilestones(): void {
Router.toMilestones();
}
function clickOptions(): void {
Router.toGameOptions();
}
function clickDev(): void {
Router.toDevMenu();
}
function clickAchievements(): void {
Router.toAchievements();
}
useEffect(() => {
// Shortcuts to navigate through the game
// Alt-t - Terminal
@ -277,53 +191,53 @@ export function SidebarRoot(props: IProps): React.ReactElement {
if ((Player.currentWork && Player.focus) || Router.page() === Page.BitVerse) return;
if (event.code === KEYCODE.T && event.altKey) {
event.preventDefault();
clickTerminal();
clickPage(Page.Terminal);
} else if (event.code === KEYCODE.C && event.altKey) {
event.preventDefault();
clickStats();
clickPage(Page.Stats);
} else if (event.code === KEYCODE.E && event.altKey) {
event.preventDefault();
clickScriptEditor();
clickPage(Page.ScriptEditor);
} else if (event.code === KEYCODE.S && event.altKey) {
event.preventDefault();
clickActiveScripts();
clickPage(Page.ActiveScripts);
} else if (event.code === KEYCODE.H && event.altKey) {
event.preventDefault();
clickHacknet();
clickPage(Page.Hacknet);
} else if (event.code === KEYCODE.W && event.altKey) {
event.preventDefault();
clickCity();
clickPage(Page.City);
} else if (event.code === KEYCODE.J && event.altKey && !event.ctrlKey && !event.metaKey && canJob) {
// ctrl/cmd + alt + j is shortcut to open Chrome dev tools
event.preventDefault();
clickJob();
clickPage(Page.Job);
} else if (event.code === KEYCODE.R && event.altKey) {
event.preventDefault();
clickTravel();
clickPage(Page.Travel);
} else if (event.code === KEYCODE.P && event.altKey) {
event.preventDefault();
clickCreateProgram();
clickPage(Page.CreateProgram);
} else if (event.code === KEYCODE.F && event.altKey) {
if (props.page == Page.Terminal && Settings.EnableBashHotkeys) {
return;
}
event.preventDefault();
clickFactions();
clickPage(Page.Factions);
} else if (event.code === KEYCODE.A && event.altKey) {
event.preventDefault();
clickAugmentations();
clickPage(Page.Augmentations);
} else if (event.code === KEYCODE.U && event.altKey) {
event.preventDefault();
clickTutorial();
clickPage(Page.Tutorial);
} else if (event.code === KEYCODE.O && event.altKey) {
event.preventDefault();
clickOptions();
clickPage(Page.Options);
} else if (event.code === KEYCODE.B && event.altKey && Player.bladeburner) {
event.preventDefault();
clickBladeburner();
clickPage(Page.Bladeburner);
} else if (event.code === KEYCODE.G && event.altKey && Player.gang) {
event.preventDefault();
clickGang();
clickPage(Page.Gang);
}
}
@ -331,13 +245,31 @@ export function SidebarRoot(props: IProps): React.ReactElement {
return () => document.removeEventListener("keydown", handleShortcuts);
}, []);
const classes = useStyles();
const [open, setOpen] = useState(props.opened);
const toggleDrawer = (): void => setOpen((old) => !old);
const clickPage = useCallback(
(page: Page) => {
if (page === Page.Job) {
Router.toJob(Locations[Object.keys(Player.jobs)[0]]);
} else if (page == Page.ScriptEditor) {
Router.toScriptEditor();
} else if ((Object.values(SimplePage) as Page[]).includes(page)) {
Router.toPage(page as SimplePage);
} else {
throw new Error("Can't handle click on Page " + page);
}
if (flash === page) {
iTutorialNextStep();
}
},
[flash],
);
useEffect(() => {
props.onToggled(open);
}, [open]);
const classes = useStyles();
const [open, setOpen] = useState(Settings.IsSidebarOpened);
const toggleDrawer = (): void =>
setOpen((old) => {
Settings.IsSidebarOpened = !old;
return !old;
});
return (
<Drawer open={open} anchor="left" variant="permanent">
@ -373,17 +305,19 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Terminal,
})}
onClick={clickTerminal}
onClick={() => clickPage(Page.Terminal)}
>
<ListItemIcon>
<Tooltip title={!open ? "Terminal" : ""}>
<LastPageIcon
color={flashTerminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}
color={flash === Page.Terminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography color={flashTerminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}>
<Typography
color={flash === Page.Terminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}
>
Terminal
</Typography>
</ListItemText>
@ -395,7 +329,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.ScriptEditor,
})}
onClick={clickScriptEditor}
onClick={() => clickPage(Page.ScriptEditor)}
>
<ListItemIcon>
<Tooltip title={!open ? "Script Editor" : ""}>
@ -415,18 +349,26 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.ActiveScripts,
})}
onClick={clickActiveScripts}
onClick={() => clickPage(Page.ActiveScripts)}
>
<ListItemIcon>
<Tooltip title={!open ? "Active Scripts" : ""}>
<StorageIcon
color={flashActiveScripts ? "error" : props.page !== Page.ActiveScripts ? "secondary" : "primary"}
color={
flash === Page.ActiveScripts
? "error"
: props.page !== Page.ActiveScripts
? "secondary"
: "primary"
}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography
color={flashActiveScripts ? "error" : props.page !== Page.ActiveScripts ? "secondary" : "primary"}
color={
flash === Page.ActiveScripts ? "error" : props.page !== Page.ActiveScripts ? "secondary" : "primary"
}
>
Active Scripts
</Typography>
@ -438,7 +380,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.CreateProgram,
})}
onClick={clickCreateProgram}
onClick={() => clickPage(Page.CreateProgram)}
>
<ListItemIcon>
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
@ -460,7 +402,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.StaneksGift,
})}
onClick={clickStaneksGift}
onClick={() => clickPage(Page.StaneksGift)}
>
<ListItemIcon>
<Tooltip title={!open ? "Stanek's Gift" : ""}>
@ -494,15 +436,17 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Stats,
})}
onClick={clickStats}
onClick={() => clickPage(Page.Stats)}
>
<ListItemIcon>
<Tooltip title={!open ? "Stats" : ""}>
<EqualizerIcon color={flashStats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"} />
<EqualizerIcon
color={flash === Page.Stats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography color={flashStats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"}>
<Typography color={flash === Page.Stats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"}>
Stats
</Typography>
</ListItemText>
@ -515,7 +459,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: [Page.Factions, Page.Faction].includes(props.page),
})}
onClick={clickFactions}
onClick={() => clickPage(Page.Factions)}
>
<ListItemIcon>
<Badge badgeContent={invitationsCount !== 0 ? invitationsCount : undefined} color="error">
@ -541,7 +485,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Augmentations,
})}
onClick={clickAugmentations}
onClick={() => clickPage(Page.Augmentations)}
>
<ListItemIcon>
<Badge badgeContent={augmentationCount !== 0 ? augmentationCount : undefined} color="error">
@ -566,17 +510,19 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Hacknet,
})}
onClick={clickHacknet}
onClick={() => clickPage(Page.Hacknet)}
>
<ListItemIcon>
<Tooltip title={!open ? "Hacknet" : ""}>
<AccountTreeIcon
color={flashHacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"}
color={flash === Page.Hacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography color={flashHacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"}>
<Typography
color={flash === Page.Hacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"}
>
Hacknet
</Typography>
</ListItemText>
@ -589,7 +535,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Sleeves,
})}
onClick={clickSleeves}
onClick={() => clickPage(Page.Sleeves)}
>
<ListItemIcon>
<Tooltip title={!open ? "Sleeves" : ""}>
@ -621,15 +567,17 @@ export function SidebarRoot(props: IProps): React.ReactElement {
[classes.active]:
props.page === Page.City || props.page === Page.Grafting || props.page === Page.Location,
})}
onClick={clickCity}
onClick={() => clickPage(Page.City)}
>
<ListItemIcon>
<Tooltip title={!open ? "City" : ""}>
<LocationCityIcon color={flashCity ? "error" : props.page !== Page.City ? "secondary" : "primary"} />
<LocationCityIcon
color={flash === Page.City ? "error" : props.page !== Page.City ? "secondary" : "primary"}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography color={flashCity ? "error" : props.page !== Page.City ? "secondary" : "primary"}>
<Typography color={flash === Page.City ? "error" : props.page !== Page.City ? "secondary" : "primary"}>
City
</Typography>
</ListItemText>
@ -640,7 +588,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Travel,
})}
onClick={clickTravel}
onClick={() => clickPage(Page.Travel)}
>
<ListItemIcon>
<Tooltip title={!open ? "Travel" : ""}>
@ -659,7 +607,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Job,
})}
onClick={clickJob}
onClick={() => clickPage(Page.Job)}
>
<ListItemIcon>
<Tooltip title={!open ? "Job" : ""}>
@ -679,7 +627,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.StockMarket,
})}
onClick={clickStockMarket}
onClick={() => clickPage(Page.StockMarket)}
>
<ListItemIcon>
<Tooltip title={!open ? "Stock Market" : ""}>
@ -699,7 +647,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Bladeburner,
})}
onClick={clickBladeburner}
onClick={() => clickPage(Page.Bladeburner)}
>
<ListItemIcon>
<Tooltip title={!open ? "Bladeburner" : ""}>
@ -719,7 +667,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Corporation,
})}
onClick={clickCorp}
onClick={() => clickPage(Page.Corporation)}
>
<ListItemIcon>
<Tooltip title={!open ? "Corp" : ""}>
@ -739,7 +687,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Gang,
})}
onClick={clickGang}
onClick={() => clickPage(Page.Gang)}
>
<ListItemIcon>
<Tooltip title={!open ? "Gang" : ""}>
@ -770,7 +718,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Milestones,
})}
onClick={clickMilestones}
onClick={() => clickPage(Page.Milestones)}
>
<ListItemIcon>
<Tooltip title={!open ? "Milestones" : ""}>
@ -787,15 +735,19 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Tutorial,
})}
onClick={clickTutorial}
onClick={() => clickPage(Page.Tutorial)}
>
<ListItemIcon>
<Tooltip title={!open ? "Tutorial" : ""}>
<HelpIcon color={flashTutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"} />
<HelpIcon
color={flash === Page.Tutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"}
/>
</Tooltip>
</ListItemIcon>
<ListItemText>
<Typography color={flashTutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"}>
<Typography
color={flash === Page.Tutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"}
>
Tutorial
</Typography>
</ListItemText>
@ -806,7 +758,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Achievements,
})}
onClick={clickAchievements}
onClick={() => clickPage(Page.Achievements)}
>
<ListItemIcon>
<Tooltip title={!open ? "Achievements" : ""}>
@ -823,7 +775,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.Options,
})}
onClick={clickOptions}
onClick={() => clickPage(Page.Options)}
>
<ListItemIcon>
<Tooltip title={!open ? "Options" : ""}>
@ -842,7 +794,7 @@ export function SidebarRoot(props: IProps): React.ReactElement {
className={clsx({
[classes.active]: props.page === Page.DevMenu,
})}
onClick={clickDev}
onClick={() => clickPage(Page.DevMenu)}
>
<ListItemIcon>
<Tooltip title={!open ? "Dev" : ""}>

@ -16,6 +16,7 @@ import { Settings } from "../../Settings/Settings";
import { defaultTheme } from "../Themes";
import { UserInterfaceTheme } from "../../ScriptEditor/NetscriptDefinitions";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { ThemeCollaborate } from "./ThemeCollaborate";
interface IProps {
@ -380,7 +381,7 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
</Button>
</Tooltip>
<Tooltip title="Move over to the theme browser's page to use one of our predefined themes.">
<Button startIcon={<PaletteSharpIcon />} onClick={() => Router.toThemeBrowser()}>
<Button startIcon={<PaletteSharpIcon />} onClick={() => Router.toPage(Page.ThemeBrowser)}>
See more themes
</Button>
</Tooltip>

@ -411,7 +411,7 @@ function warnAutosaveDisabled(): void {
// We don't want this warning to show up on certain pages.
// When in recovery or importing we want to keep autosave disabled.
const ignoredPages = [Page.Recovery, Page.ImportSave];
const ignoredPages = [Page.Recovery as Page, Page.ImportSave];
if (ignoredPages.includes(Router.page())) return;
const warningToast = (

@ -23,7 +23,7 @@ import createStyles from "@mui/styles/createStyles";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { Page, IRouter, ScriptEditorRouteOptions } from "./Router";
import { Page, SimplePage, IRouter, ScriptEditorRouteOptions } from "./Router";
import { Overview } from "./React/Overview";
import { SidebarRoot } from "../Sidebar/ui/SidebarRoot";
import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot";
@ -67,7 +67,6 @@ import { calculateAchievements } from "../Achievements/Achievements";
import { RecoveryMode, RecoveryRoot } from "./React/RecoveryRoot";
import { AchievementsRoot } from "../Achievements/AchievementsRoot";
import { ErrorBoundary } from "./ErrorBoundary";
import { Settings } from "../Settings/Settings";
import { ThemeBrowser } from "../Themes/ui/ThemeBrowser";
import { ImportSaveRoot } from "./React/ImportSaveRoot";
import { BypassWrapper } from "./React/BypassWrapper";
@ -105,36 +104,15 @@ export let Router: IRouter = {
throw new Error("Router called before initialization");
},
allowRouting: uninitialized,
toActiveScripts: uninitialized,
toAugmentations: uninitialized,
toPage: () => {
throw new Error("Router called before initialization");
},
toBitVerse: uninitialized,
toBladeburner: uninitialized,
toStats: uninitialized,
toCity: uninitialized,
toCorporation: uninitialized,
toCreateProgram: uninitialized,
toDevMenu: uninitialized,
toFaction: uninitialized,
toFactions: uninitialized,
toGameOptions: uninitialized,
toGang: uninitialized,
toHacknetNodes: uninitialized,
toInfiltration: uninitialized,
toJob: uninitialized,
toMilestones: uninitialized,
toGrafting: uninitialized,
toScriptEditor: uninitialized,
toSleeves: uninitialized,
toStockMarket: uninitialized,
toTerminal: uninitialized,
toTravel: uninitialized,
toTutorial: uninitialized,
toWork: uninitialized,
toBladeburnerCinematic: uninitialized,
toLocation: uninitialized,
toStaneksGift: uninitialized,
toAchievements: uninitialized,
toThemeBrowser: uninitialized,
toImportSave: uninitialized,
};
@ -164,7 +142,6 @@ export function GameRoot(): React.ReactElement {
const [cinematicText, setCinematicText] = useState("");
const [errorBoundaryKey, setErrorBoundaryKey] = useState<number>(0);
const [sidebarOpened, setSideBarOpened] = useState(Settings.IsSidebarOpened);
const [importString, setImportString] = useState<string>(undefined as unknown as string);
const [importAutomatic, setImportAutomatic] = useState<boolean>(false);
@ -196,24 +173,23 @@ export function GameRoot(): React.ReactElement {
isInitialized: true,
page: () => page,
allowRouting: (value: boolean) => setAllowRoutingCalls(value),
toActiveScripts: () => setPage(Page.ActiveScripts),
toAugmentations: () => setPage(Page.Augmentations),
toBladeburner: () => setPage(Page.Bladeburner),
toStats: () => setPage(Page.Stats),
toCorporation: () => setPage(Page.Corporation),
toCreateProgram: () => setPage(Page.CreateProgram),
toDevMenu: () => setPage(Page.DevMenu),
toPage: (page: SimplePage) => {
switch (page) {
case Page.Travel:
Player.gotoLocation(LocationName.TravelAgency);
break;
case Page.BladeburnerCinematic:
setPage(page);
setCinematicText(cinematicText);
return;
}
setPage(page);
},
toFaction: (faction: Faction, augPage = false) => {
setAugPage(augPage);
setPage(Page.Faction);
if (faction) setFaction(faction);
},
toFactions: () => setPage(Page.Factions),
toGameOptions: () => setPage(Page.Options),
toGang: () => setPage(Page.Gang),
toHacknetNodes: () => setPage(Page.Hacknet),
toMilestones: () => setPage(Page.Milestones),
toGrafting: () => setPage(Page.Grafting),
toScriptEditor: (files: Record<string, string>, options?: ScriptEditorRouteOptions) => {
setEditorOptions({
files,
@ -221,21 +197,10 @@ export function GameRoot(): React.ReactElement {
});
setPage(Page.ScriptEditor);
},
toSleeves: () => setPage(Page.Sleeves),
toStockMarket: () => setPage(Page.StockMarket),
toTerminal: () => setPage(Page.Terminal),
toTutorial: () => setPage(Page.Tutorial),
toJob: (location: Location) => {
setLocation(location);
setPage(Page.Job);
},
toCity: () => {
setPage(Page.City);
},
toTravel: () => {
Player.gotoLocation(LocationName.TravelAgency);
setPage(Page.Travel);
},
toBitVerse: (flume: boolean, quick: boolean) => {
setFlume(flume);
setQuick(quick);
@ -246,24 +211,10 @@ export function GameRoot(): React.ReactElement {
setLocation(location);
setPage(Page.Infiltration);
},
toWork: () => setPage(Page.Work),
toBladeburnerCinematic: () => {
setPage(Page.BladeburnerCinematic);
setCinematicText(cinematicText);
},
toLocation: (location: Location) => {
setLocation(location);
setPage(Page.Location);
},
toStaneksGift: () => {
setPage(Page.StaneksGift);
},
toAchievements: () => {
setPage(Page.Achievements);
},
toThemeBrowser: () => {
setPage(Page.ThemeBrowser);
},
toImportSave: (base64save: string, automatic = false) => {
setImportString(base64save);
setImportAutomatic(automatic);
@ -298,7 +249,7 @@ export function GameRoot(): React.ReactElement {
dialogBoxCreate("Soft Reset!");
installAugmentations(true);
resetErrorBoundary();
Router.toTerminal();
Router.toPage(Page.Terminal);
}
let mainPage = <Typography>Cannot load</Typography>;
@ -385,7 +336,7 @@ export function GameRoot(): React.ReactElement {
<TutorialRoot
reactivateTutorial={() => {
prestigeAugmentation();
Router.toTerminal();
Router.toPage(Page.Terminal);
iTutorialStart();
}}
/>
@ -489,14 +440,7 @@ export function GameRoot(): React.ReactElement {
</Overview>
{withSidebar ? (
<Box display="flex" flexDirection="row" width="100%">
<SidebarRoot
page={page}
opened={sidebarOpened}
onToggled={(isOpened) => {
setSideBarOpened(isOpened);
Settings.IsSidebarOpened = isOpened;
}}
/>
<SidebarRoot page={page} />
<Box className={classes.root}>{mainPage}</Box>
</Box>
) : (

@ -21,6 +21,7 @@ import ClearAllIcon from "@mui/icons-material/ClearAll";
import { Settings } from "../../Settings/Settings";
import { Router } from "../GameRoot";
import { Page } from "../Router";
import { Player } from "@player";
import { StatsProgressOverviewCell } from "./StatsProgressBar";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
@ -140,7 +141,7 @@ function WorkInProgressOverview({
function Work(): React.ReactElement {
const onClickFocus = (): void => {
Player.startFocusing();
Router.toWork();
Router.toPage(Page.Work);
};
if (Player.currentWork === null || Player.focus) return <></>;

@ -32,6 +32,7 @@ import { numeralWrapper } from "../numeralFormat";
import { ConfirmationModal } from "./ConfirmationModal";
import { pushImportResult } from "../../Electron";
import { Router } from "../GameRoot";
import { Page } from "../Router";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -136,7 +137,7 @@ export function ImportSaveRoot(props: IProps): JSX.Element {
}, []);
useEffect(() => {
if (headback) Router.toTerminal();
if (headback) Router.toPage(Page.Terminal);
}, [headback]);
useEffect(() => {

@ -4,6 +4,7 @@ import { Typography, Link, Button, ButtonGroup, Tooltip, Box, Paper, TextField }
import { Settings } from "../../Settings/Settings";
import { load } from "../../db";
import { Router } from "../GameRoot";
import { Page } from "../Router";
import { download } from "../../SaveObject";
import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper";
import { DeleteGameButton } from "./DeleteGameButton";
@ -28,7 +29,7 @@ export function RecoveryRoot({ softReset, errorData, resetError }: IProps): Reac
function recover(): void {
if (resetError) resetError();
RecoveryMode = false;
Router.toTerminal();
Router.toPage(Page.Terminal);
}
Settings.AutosaveInterval = 0;

@ -3,87 +3,71 @@ import { Location } from "../Locations/Location";
/**
* The full-screen page the player is currently be on.
* These pages are mutually exclusive.
* These are "simple" pages that don't require any extra parameters to
* transition to. You can use setPage() with these.
*/
export enum Page {
ActiveScripts,
Augmentations,
BitVerse,
Bladeburner,
City,
Corporation,
CreateProgram,
ScriptEditor,
DevMenu,
Faction,
Factions,
Gang,
Hacknet,
Infiltration,
Job,
Milestones,
Options,
Grafting,
Sleeves,
Stats,
StockMarket,
Terminal,
Travel,
Tutorial,
Work,
BladeburnerCinematic,
Location,
Loading,
StaneksGift,
Recovery,
Achievements,
ThemeBrowser,
ImportSave,
export enum SimplePage {
ActiveScripts = "Active Scripts",
Augmentations = "Augmentations",
Bladeburner = "Bladeburner",
City = "City",
Corporation = "Corporation",
CreateProgram = "Create Program",
DevMenu = "Dev",
Factions = "Factions",
Gang = "Gang",
Hacknet = "Hacknet",
Milestones = "Milestones",
Options = "Options",
Grafting = "Grafting",
Sleeves = "Sleeves",
Stats = "Stats",
StockMarket = "Stock Market",
Terminal = "Terminal",
Travel = "Travel",
Tutorial = "Tutorial",
Work = "Work",
BladeburnerCinematic = "Bladeburner Cinematic",
Loading = "Loading",
StaneksGift = "Staneks Gift",
Recovery = "Recovery",
Achievements = "Achievements",
ThemeBrowser = "Theme Browser",
}
/**
* "Complex" pages that need a custom transition function.
*/
export enum ComplexPage {
BitVerse = "BitVerse",
Faction = "Faction",
Infiltration = "Infiltration",
Job = "Job",
ScriptEditor = "Script Editor",
Location = "Location",
ImportSave = "Import Save",
}
// Using the same name as both type and object to mimic enum-like behavior.
// See https://stackoverflow.com/a/71255520/202091
export type Page = SimplePage | ComplexPage;
export const Page = { ...SimplePage, ...ComplexPage };
export interface ScriptEditorRouteOptions {
vim: boolean;
}
/** The router keeps track of player navigation/routing within the game. */
export interface IRouter {
// toCinematicText(): void;
// toInfiltration(): void;
// toMission(): void;
// toRedPill(): void;
// toworkInProgress(): void;
isInitialized: boolean;
page(): Page;
allowRouting(value: boolean): void;
toActiveScripts(): void;
toAugmentations(): void;
toPage(page: SimplePage): void;
toBitVerse(flume: boolean, quick: boolean): void;
toBladeburner(): void;
toStats(): void;
toCity(): void; // travel ? city ?
toCorporation(): void;
toCreateProgram(): void;
toDevMenu(): void;
toFaction(faction: Faction, augPage?: boolean): void; // faction name
toFactions(): void;
toGameOptions(): void;
toGang(): void;
toHacknetNodes(): void;
toInfiltration(location: Location): void;
toJob(location: Location): void;
toMilestones(): void;
toGrafting(): void;
toScriptEditor(files?: Record<string, string>, options?: ScriptEditorRouteOptions): void;
toSleeves(): void;
toStockMarket(): void;
toTerminal(): void;
toTravel(): void;
toTutorial(): void;
toWork(): void;
toBladeburnerCinematic(): void;
toLocation(location: Location): void;
toStaneksGift(): void;
toAchievements(): void;
toThemeBrowser(): void;
toImportSave(base64Save: string, automatic?: boolean): void;
}

@ -11,6 +11,7 @@ import { Settings } from "../Settings/Settings";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { Player } from "@player";
import { Router } from "./GameRoot";
import { Page } from "./Router";
import { numeralWrapper } from "./numeralFormat";
import { Money } from "./React/Money";
import { MoneyRate } from "./React/MoneyRate";
@ -211,7 +212,7 @@ export function WorkInProgressRoot(): React.ReactElement {
};
if (Player.currentWork === null) {
setTimeout(() => Router.toTerminal());
setTimeout(() => Router.toPage(Page.Terminal));
return <></>;
}
@ -227,7 +228,7 @@ export function WorkInProgressRoot(): React.ReactElement {
Player.finishWork(true);
},
unfocus: () => {
Router.toCity();
Router.toPage(Page.City);
Player.stopFocusing();
},
},
@ -256,11 +257,11 @@ export function WorkInProgressRoot(): React.ReactElement {
const classWork = Player.currentWork;
function cancel(): void {
Player.finishWork(true);
Router.toCity();
Router.toPage(Page.City);
}
function unfocus(): void {
Router.toCity();
Router.toPage(Page.City);
Player.stopFocusing();
}
@ -303,10 +304,10 @@ export function WorkInProgressRoot(): React.ReactElement {
const create = Player.currentWork;
function cancel(): void {
Player.finishWork(true);
Router.toTerminal();
Router.toPage(Page.Terminal);
}
function unfocus(): void {
Router.toTerminal();
Router.toPage(Page.Terminal);
Player.stopFocusing();
}
@ -337,10 +338,10 @@ export function WorkInProgressRoot(): React.ReactElement {
const graft = Player.currentWork;
function cancel(): void {
Player.finishWork(true);
Router.toTerminal();
Router.toPage(Page.Terminal);
}
function unfocus(): void {
Router.toTerminal();
Router.toPage(Page.Terminal);
Player.stopFocusing();
}
@ -374,7 +375,7 @@ export function WorkInProgressRoot(): React.ReactElement {
if (!faction) {
workInfo = {
buttons: {
cancel: () => Router.toFactions(),
cancel: () => Router.toPage(Page.Factions),
},
title:
`You have not joined ${Player.currentWork.factionName || "(Faction not found)"} at this time,` +
@ -432,7 +433,7 @@ export function WorkInProgressRoot(): React.ReactElement {
if (comp) {
workInfo = {
buttons: {
cancel: () => Router.toTerminal(),
cancel: () => Router.toPage(Page.Terminal),
},
title:
`You cannot work for ${Player.currentWork.companyName || "(Company not found)"} at this time,` +

@ -89,7 +89,7 @@ export function getErrorForDisplay(error: Error, errorInfo?: React.ErrorInfo, pa
`lang=${metadata.features.language} cookiesEnabled=${metadata.features.cookiesEnabled.toString()}` +
` doNotTrack=${metadata.features.doNotTrack ?? "null"} indexedDb=${metadata.features.indexedDb.toString()}`;
const title = `${metadata.error.name}: ${metadata.error.message}${metadata.page && ` (at "${Page[metadata.page]}")`}`;
const title = `${metadata.error.name}: ${metadata.error.message} (at "${metadata.page}")`;
const body = `
## ${title}
@ -104,7 +104,7 @@ Please fill this information with details if relevant.
### Environment
* Error: ${metadata.error?.toString() ?? "n/a"}
* Page: ${metadata.page ? Page[metadata.page] : "n/a"}
* Page: ${metadata.page ?? "n/a"}
* Version: ${metadata.version.toDisplay()}
* Environment: ${GameEnv[metadata.environment]}
* Platform: ${Platform[metadata.platform]}