Add toPreviousPage in router

- Allows the WorkInProgress cancel & unfocus to go back to the previous
page instead of a default one.
- Change layout of overview buttons
- Add a back button in the overview, only visible in pages with a
sidebar
- Clear the history on augmentation install & on prestige
This commit is contained in:
Martin Fournier 2022-01-11 06:51:27 -05:00
parent f742782e4a
commit b0bc3236fd
6 changed files with 165 additions and 57 deletions

@ -13,6 +13,7 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { clearObject } from "../utils/helpers/clearObject";
import { Router } from "../ui/GameRoot";
import { WHRNG } from "../Casino/RNG";
@ -2582,6 +2583,8 @@ function installAugmentations(): boolean {
augmentationList += aug.name + level + "<br>";
}
Player.queuedAugmentations = [];
Router.clearHistory();
dialogBoxCreate(
"You slowly drift to sleep as scientists put you under in order " +
"to install the following Augmentations:<br>" +

@ -306,5 +306,7 @@ export function prestigeSourceFile(flume: boolean): void {
// Gain int exp
if (SourceFileFlags[5] !== 0 && !flume) Player.gainIntelligenceExp(300);
Router.clearHistory();
resetPidCounter();
}

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { cloneDeep } from "lodash";
import { IPlayer } from "../PersonObjects/IPlayer";
import { IEngine } from "../IEngine";
import { ITerminal } from "../Terminal/ITerminal";
@ -86,6 +86,11 @@ interface IProps {
engine: IEngine;
}
interface PageHistoryEntry {
page: Page;
args: any[];
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
@ -104,6 +109,15 @@ export let Router: IRouter = {
page: () => {
throw new Error("Router called before initialization");
},
previousPage: () => {
throw new Error("Router called before initialization");
},
clearHistory: () => {
throw new Error("Router called before initialization");
},
toPreviousPage: (): boolean => {
throw new Error("Router called before initialization");
},
toActiveScripts: () => {
throw new Error("Router called before initialization");
},
@ -202,7 +216,9 @@ function determineStartPage(player: IPlayer): Page {
export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement {
const classes = useStyles();
const [{ files, vim }, setEditorOptions] = useState({ files: {}, vim: false });
const [page, setPage] = useState(determineStartPage(player));
const startPage = determineStartPage(player);
const [page, setPage] = useState(startPage);
const [pageHistory, setPageHistory] = useState<PageHistoryEntry[]>([{ page: startPage, args: [] }]);
const setRerender = useState(0)[1];
const [faction, setFaction] = useState<Faction>(
player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : (undefined as unknown as Faction),
@ -233,70 +249,131 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
setTimeout(() => htmlLocation.reload(), 2000);
}
function setCurrentPage(page: Page, ...args: any): void {
const history = [
{ page, args: cloneDeep(args) },
...pageHistory
].slice(0, 20);
setPageHistory(history)
setPage(page)
}
function goBack(fallback: (...args: any[]) => void): void {
const [ , previousPage ] = pageHistory;
if (previousPage) {
const handler = pageToRouterMap[previousPage?.page];
handler(...previousPage.args);
} else {
if (fallback) fallback();
}
const [ , ...history] = pageHistory;
setPageHistory(cloneDeep(history));
}
const pageToRouterMap: { [key: number] : (...args: any[]) => void } = {
[Page.ActiveScripts]: Router.toActiveScripts,
[Page.Augmentations]: Router.toAugmentations,
[Page.Bladeburner]: Router.toBladeburner,
[Page.Stats]: Router.toStats,
[Page.Corporation]: Router.toCorporation,
[Page.CreateProgram]: Router.toCreateProgram,
[Page.DevMenu]: Router.toDevMenu,
[Page.Faction]: Router.toFaction,
[Page.Factions]: Router.toFactions,
[Page.Options]: Router.toGameOptions,
[Page.Gang]: Router.toGang,
[Page.Hacknet]: Router.toHacknetNodes,
[Page.Milestones]: Router.toMilestones,
[Page.Resleeves]: Router.toResleeves,
[Page.ScriptEditor]: Router.toScriptEditor,
[Page.Sleeves]: Router.toSleeves,
[Page.StockMarket]: Router.toStockMarket,
[Page.Terminal]: Router.toTerminal,
[Page.Tutorial]: Router.toTutorial,
[Page.Job]: Router.toJob,
[Page.City]: Router.toCity,
[Page.Travel]: Router.toTravel,
[Page.BitVerse]: Router.toBitVerse,
[Page.Infiltration]: Router.toInfiltration,
[Page.Work]: Router.toWork,
[Page.BladeburnerCinematic]: Router.toBladeburnerCinematic,
[Page.Location]: Router.toLocation,
[Page.StaneksGift]: Router.toStaneksGift,
[Page.Achievements]: Router.toAchievements,
}
Router = {
page: () => page,
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),
previousPage: () => {
const [ , previousPage] = pageHistory;
return previousPage?.page ?? -1;
},
clearHistory: () => setPageHistory([]),
toPreviousPage: goBack,
toActiveScripts: () => setCurrentPage(Page.ActiveScripts),
toAugmentations: () => setCurrentPage(Page.Augmentations),
toBladeburner: () => setCurrentPage(Page.Bladeburner),
toStats: () => setCurrentPage(Page.Stats),
toCorporation: () => setCurrentPage(Page.Corporation),
toCreateProgram: () => setCurrentPage(Page.CreateProgram),
toDevMenu: () => setCurrentPage(Page.DevMenu),
toFaction: (faction?: Faction) => {
setPage(Page.Faction);
setCurrentPage(Page.Faction, 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),
toResleeves: () => setPage(Page.Resleeves),
toFactions: () => setCurrentPage(Page.Factions),
toGameOptions: () => setCurrentPage(Page.Options),
toGang: () => setCurrentPage(Page.Gang),
toHacknetNodes: () => setCurrentPage(Page.Hacknet),
toMilestones: () => setCurrentPage(Page.Milestones),
toResleeves: () => setCurrentPage(Page.Resleeves),
toScriptEditor: (files: Record<string, string>, options?: ScriptEditorRouteOptions) => {
setEditorOptions({
files,
vim: !!options?.vim,
});
setPage(Page.ScriptEditor);
setCurrentPage(Page.ScriptEditor, files, options);
},
toSleeves: () => setPage(Page.Sleeves),
toStockMarket: () => setPage(Page.StockMarket),
toTerminal: () => setPage(Page.Terminal),
toTutorial: () => setPage(Page.Tutorial),
toSleeves: () => setCurrentPage(Page.Sleeves),
toStockMarket: () => setCurrentPage(Page.StockMarket),
toTerminal: () => setCurrentPage(Page.Terminal),
toTutorial: () => setCurrentPage(Page.Tutorial),
toJob: () => {
setLocation(Locations[player.companyName]);
setPage(Page.Job);
setCurrentPage(Page.Job);
},
toCity: () => {
setPage(Page.City);
setCurrentPage(Page.City);
},
toTravel: () => {
player.gotoLocation(LocationName.TravelAgency);
setPage(Page.Travel);
setCurrentPage(Page.Travel);
},
toBitVerse: (flume: boolean, quick: boolean) => {
setFlume(flume);
setQuick(quick);
setPage(Page.BitVerse);
setCurrentPage(Page.BitVerse, flume, quick);
},
toInfiltration: (location: Location) => {
setLocation(location);
setPage(Page.Infiltration);
setCurrentPage(Page.Infiltration, location);
},
toWork: () => {
setCurrentPage(Page.Work);
},
toWork: () => setPage(Page.Work),
toBladeburnerCinematic: () => {
setPage(Page.BladeburnerCinematic);
setCurrentPage(Page.BladeburnerCinematic);
setCinematicText(cinematicText);
},
toLocation: (location: Location) => {
setLocation(location);
setPage(Page.Location);
setCurrentPage(Page.Location, location);
},
toStaneksGift: () => {
setPage(Page.StaneksGift);
setCurrentPage(Page.StaneksGift);
},
toAchievements: () => {
setPage(Page.Achievements);
setCurrentPage(Page.Achievements);
},
};
@ -499,7 +576,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
<SnackbarProvider>
<Overview mode={ITutorial.isRunning ? "tutorial" : "overview"}>
{!ITutorial.isRunning ? (
<CharacterOverview save={() => saveObject.saveGame()} killScripts={killAllScripts} />
<CharacterOverview
save={() => saveObject.saveGame()}
killScripts={killAllScripts}
router={Router}
allowBackButton={withSidebar} />
) : (
<InteractiveTutorialRoot />
)}

@ -16,16 +16,21 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import IconButton from "@mui/material/IconButton";
import SaveIcon from "@mui/icons-material/Save";
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ClearAllIcon from "@mui/icons-material/ClearAll";
import { Settings } from "../../Settings/Settings";
import { use } from "../Context";
import { StatsProgressOverviewCell } from "./StatsProgressBar";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { IRouter, Page } from "../Router";
import { Box, Tooltip } from "@mui/material";
interface IProps {
save: () => void;
killScripts: () => void;
router: IRouter;
allowBackButton: boolean;
}
function Intelligence(): React.ReactElement {
@ -205,7 +210,7 @@ const useStyles = makeStyles((theme: Theme) =>
export { useStyles as characterOverviewStyles };
export function CharacterOverview({ save, killScripts }: IProps): React.ReactElement {
export function CharacterOverview({ save, killScripts, router, allowBackButton }: IProps): React.ReactElement {
const [killOpen, setKillOpen] = useState(false);
const player = use.Player();
@ -244,6 +249,9 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
);
const previousPageName = router.previousPage() < 0
? '' : Page[router.previousPage() ?? 0].replace(/([a-z])([A-Z])/g, '$1 $2');
return (
<>
<Table sx={{ display: "block", m: 1 }}>
@ -418,21 +426,33 @@ export function CharacterOverview({ save, killScripts }: IProps): React.ReactEle
</TableRow>
<Work />
<Bladeburner />
<TableRow>
<TableCell align="center" classes={{ root: classes.cellNone }}>
<IconButton onClick={save}>
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
</IconButton>
</TableCell>
<TableCell align="center" classes={{ root: classes.cellNone }}>
<IconButton onClick={() => setKillOpen(true)}>
<ClearAllIcon color="error" />
</IconButton>
</TableCell>
</TableRow>
</TableBody>
</Table>
<Box sx={{ display: 'flex', borderTop: `1px solid ${Settings.theme.welllight}` }}>
<Box sx={{ display: 'flex', flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
<IconButton onClick={save}>
<Tooltip title="Save game">
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
</Tooltip>
</IconButton>
{allowBackButton && (
<IconButton
disabled={!previousPageName}
onClick={() => router.toPreviousPage()}>
<Tooltip title={previousPageName ? `Go back to "${previousPageName}"` : ''}>
<ArrowBackIcon />
</Tooltip>
</IconButton>
)}
</Box>
<Box sx={{ display: 'flex', flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
<IconButton onClick={() => setKillOpen(true)}>
<Tooltip title="Kill all running scripts">
<ClearAllIcon color="error" />
</Tooltip>
</IconButton>
</Box>
</Box>
<KillScriptsModal open={killOpen} onClose={() => setKillOpen(false)} killScripts={killScripts} />
</>
);

@ -53,6 +53,9 @@ export interface IRouter {
// toRedPill(): void;
// toworkInProgress(): void;
page(): Page;
previousPage(): Page;
clearHistory(): void;
toPreviousPage(fallback?: (...args: any[]) => void): void;
toActiveScripts(): void;
toAugmentations(): void;
toBitVerse(flume: boolean, quick: boolean): void;

@ -36,12 +36,12 @@ export function WorkInProgressRoot(): React.ReactElement {
const faction = Factions[player.currentWorkFactionName];
if (player.workType == CONSTANTS.WorkTypeFaction) {
function cancel(): void {
router.toFaction(faction);
player.finishFactionWork(true);
router.toPreviousPage(() => router.toFaction(faction));
}
function unfocus(): void {
router.toFaction(faction);
player.stopFocusing();
router.toPreviousPage(() => router.toFaction(faction));
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
@ -120,13 +120,12 @@ export function WorkInProgressRoot(): React.ReactElement {
if (player.className !== "") {
function cancel(): void {
player.finishClass(true);
router.toCity();
router.toPreviousPage(() => router.toCity());
}
function unfocus(): void {
router.toFaction(faction);
router.toCity();
player.stopFocusing();
router.toPreviousPage(() => router.toCity());
}
let stopText = "";
@ -212,11 +211,11 @@ export function WorkInProgressRoot(): React.ReactElement {
function cancel(): void {
player.finishWork(true);
router.toJob();
router.toPreviousPage(() => router.toJob());
}
function unfocus(): void {
player.stopFocusing();
router.toJob();
router.toPreviousPage(() => router.toJob());
}
const position = player.jobs[player.companyName];
@ -304,11 +303,11 @@ export function WorkInProgressRoot(): React.ReactElement {
if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
function cancel(): void {
player.finishWorkPartTime(true);
router.toJob();
router.toPreviousPage(() => router.toJob());
}
function unfocus(): void {
player.stopFocusing();
router.toJob();
router.toPreviousPage(() => router.toJob());
}
const comp = Companies[player.companyName];
let companyRep = 0;
@ -440,11 +439,11 @@ export function WorkInProgressRoot(): React.ReactElement {
if (player.createProgramName !== "") {
function cancel(): void {
player.finishCreateProgramWork(true);
router.toTerminal();
router.toPreviousPage(() => router.toTerminal());
}
function unfocus(): void {
router.toTerminal();
player.stopFocusing();
router.toPreviousPage(() => router.toTerminal());
}
return (
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>