mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-09 17:23:53 +01:00
UI: Correct behavior of "back" button on faction augs page
Plus router refactoring
This commit is contained in:
parent
9a0a843ffc
commit
1af01401d9
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { EventEmitter } from "../../utils/EventEmitter";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -10,7 +11,7 @@ export const BitFlumeEvent = new EventEmitter<[]>();
|
||||
export function BitFlumeModal(): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
function flume(): void {
|
||||
Router.toBitVerse(true, false);
|
||||
Router.toPage(Page.BitVerse, { flume: true, quick: false });
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { BlackOperationName, FactionName } from "@enums";
|
||||
import { BlackOpList } from "./BlackOpList";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
|
||||
interface IProps {
|
||||
@ -28,7 +29,7 @@ export function BlackOpPage(props: IProps): React.ReactElement {
|
||||
losses.
|
||||
</Typography>
|
||||
{props.bladeburner.blackops[BlackOperationName.OperationDaedalus] ? (
|
||||
<Button sx={{ my: 1, p: 1 }} onClick={() => Router.toBitVerse(false, false)}>
|
||||
<Button sx={{ my: 1, p: 1 }} onClick={() => Router.toPage(Page.BitVerse, { flume: false, quick: false })}>
|
||||
<CorruptableText content="Destroy w0rld_d34mon"></CorruptableText>
|
||||
</Button>
|
||||
) : (
|
||||
|
@ -8,6 +8,7 @@ import { Money } from "../../ui/React/Money";
|
||||
import { formatNumberNoSuffix, formatPopulation, formatBigNumber } from "../../ui/formatNumber";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { joinFaction } from "../../Faction/FactionHelpers";
|
||||
import { Bladeburner } from "../Bladeburner";
|
||||
|
||||
@ -34,7 +35,7 @@ export function Stats(props: IProps): React.ReactElement {
|
||||
joinFaction(faction);
|
||||
}
|
||||
|
||||
Router.toFaction(faction);
|
||||
Router.toPage(Page.Faction, { faction });
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -16,6 +16,7 @@ import { Player } from "@player";
|
||||
import { FactionName } from "@enums";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { Bladeburner } from "../../Bladeburner/Bladeburner";
|
||||
import { GangConstants } from "../../Gang/data/Constants";
|
||||
import { checkForMessagesToSend } from "../../Message/MessageHelpers";
|
||||
@ -37,10 +38,10 @@ export function General(): React.ReactElement {
|
||||
const upgradeRam = () => (Player.getHomeComputer().maxRam *= 2);
|
||||
|
||||
// Node-clearing functions
|
||||
const quickB1tFlum3 = () => Router.toBitVerse(true, true);
|
||||
const b1tflum3 = () => Router.toBitVerse(true, false);
|
||||
const quickHackW0r1dD43m0n = () => Router.toBitVerse(false, true);
|
||||
const hackW0r1dD43m0n = () => Router.toBitVerse(false, false);
|
||||
const quickB1tFlum3 = () => Router.toPage(Page.BitVerse, { flume: true, quick: true });
|
||||
const b1tflum3 = () => Router.toPage(Page.BitVerse, { flume: true, quick: false });
|
||||
const quickHackW0r1dD43m0n = () => Router.toPage(Page.BitVerse, { flume: false, quick: true });
|
||||
const hackW0r1dD43m0n = () => Router.toPage(Page.BitVerse, { flume: false, quick: false });
|
||||
|
||||
// Corp functions
|
||||
const createCorporation = () => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Player } from "@player";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
import { Page } from "./ui/Router";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { SnackbarEvents } from "./ui/React/Snackbar";
|
||||
import { ToastVariant } from "@enums";
|
||||
@ -28,8 +29,8 @@ declare global {
|
||||
triggerGameExport: () => void;
|
||||
triggerScriptsExport: () => void;
|
||||
getSaveData: () => { save: string; fileName: string };
|
||||
getSaveInfo: (base64save: string) => Promise<ImportPlayerData | undefined>;
|
||||
pushSaveData: (base64save: string, automatic?: boolean) => void;
|
||||
getSaveInfo: (base64Save: string) => Promise<ImportPlayerData | undefined>;
|
||||
pushSaveData: (base64Save: string, automatic?: boolean) => void;
|
||||
};
|
||||
electronBridge: {
|
||||
send: (channel: string, data?: unknown) => void;
|
||||
@ -137,16 +138,17 @@ function initSaveFunctions(): void {
|
||||
fileName: saveObject.getSaveFileName(),
|
||||
};
|
||||
},
|
||||
getSaveInfo: async (base64save: string): Promise<ImportPlayerData | undefined> => {
|
||||
getSaveInfo: async (base64Save: string): Promise<ImportPlayerData | undefined> => {
|
||||
try {
|
||||
const data = await saveObject.getImportDataFromString(base64save);
|
||||
const data = await saveObject.getImportDataFromString(base64Save);
|
||||
return data.playerData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
},
|
||||
pushSaveData: (base64save: string, automatic = false): void => Router.toImportSave(base64save, automatic),
|
||||
pushSaveData: (base64Save: string, automatic = false): void =>
|
||||
Router.toPage(Page.ImportSave, { base64Save, automatic }),
|
||||
};
|
||||
|
||||
// Will be consumed by the electron wrapper.
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
|
||||
import React from "react";
|
||||
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { getAugCost, getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
||||
@ -11,22 +11,18 @@ import { Player } from "@player";
|
||||
import { formatBigNumber } from "../../ui/formatNumber";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Faction } from "../Faction";
|
||||
import { getFactionAugmentationsFiltered, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
|
||||
interface IProps {
|
||||
faction: Faction;
|
||||
routeToMainPage: () => void;
|
||||
}
|
||||
|
||||
/** Root React Component for displaying a faction's "Purchase Augmentations" page */
|
||||
export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
export function AugmentationsPage({ faction }: { faction: Faction }): React.ReactElement {
|
||||
const rerender = useRerender();
|
||||
|
||||
function getAugs(): AugmentationName[] {
|
||||
return getFactionAugmentationsFiltered(props.faction);
|
||||
return getFactionAugmentationsFiltered(faction);
|
||||
}
|
||||
|
||||
function getAugsSorted(): AugmentationName[] {
|
||||
@ -66,7 +62,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
const aug = Augmentations[augName];
|
||||
const augCosts = getAugCost(aug);
|
||||
const repCost = augCosts.repCost;
|
||||
const hasReq = props.faction.playerReputation >= repCost;
|
||||
const hasReq = faction.playerReputation >= repCost;
|
||||
const hasRep = hasAugmentationPrereqs(aug);
|
||||
const hasCost = augCosts.moneyCost !== 0 && Player.money > augCosts.moneyCost;
|
||||
return hasCost && hasReq && hasRep;
|
||||
@ -126,7 +122,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
const owned = augs.filter((aug) => !purchasable.includes(aug));
|
||||
|
||||
const multiplierComponent =
|
||||
props.faction.name !== FactionName.ShadowsOfAnarchy ? (
|
||||
faction.name !== FactionName.ShadowsOfAnarchy ? (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
@ -171,27 +167,27 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<>
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||
<Typography variant="h4">Faction Augmentations - {props.faction.name}</Typography>
|
||||
<Button onClick={() => Router.back()}>Back</Button>
|
||||
<Typography variant="h4">Faction Augmentations - {faction.name}</Typography>
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography>
|
||||
These are all of the Augmentations that are available to purchase from <b>{props.faction.name}</b>.
|
||||
Augmentations are powerful upgrades that will enhance your abilities.
|
||||
These are all of the Augmentations that are available to purchase from <b>{faction.name}</b>. Augmentations
|
||||
are powerful upgrades that will enhance your abilities.
|
||||
<br />
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${props.faction.name === FactionName.ShadowsOfAnarchy ? "2" : "3"}, 1fr)`,
|
||||
gridTemplateColumns: `repeat(${faction.name === FactionName.ShadowsOfAnarchy ? "2" : "3"}, 1fr)`,
|
||||
justifyItems: "center",
|
||||
my: 1,
|
||||
}}
|
||||
>
|
||||
<>{multiplierComponent}</>
|
||||
<Typography>
|
||||
<b>Reputation:</b> <Reputation reputation={props.faction.playerReputation} />
|
||||
<b>Reputation:</b> <Reputation reputation={faction.playerReputation} />
|
||||
<br />
|
||||
<b>Favor:</b> <Favor favor={Math.floor(props.faction.favor)} />
|
||||
<b>Favor:</b> <Favor favor={Math.floor(faction.favor)} />
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)" }}>
|
||||
@ -216,7 +212,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
const costs = getAugCost(aug);
|
||||
return (
|
||||
hasAugmentationPrereqs(aug) &&
|
||||
props.faction.playerReputation >= costs.repCost &&
|
||||
faction.playerReputation >= costs.repCost &&
|
||||
(costs.moneyCost === 0 || Player.money > costs.moneyCost)
|
||||
);
|
||||
}}
|
||||
@ -224,12 +220,12 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
showModal(true);
|
||||
} else {
|
||||
purchaseAugmentation(aug, props.faction);
|
||||
purchaseAugmentation(aug, faction);
|
||||
rerender();
|
||||
}
|
||||
}}
|
||||
rep={props.faction.playerReputation}
|
||||
faction={props.faction}
|
||||
rep={faction.playerReputation}
|
||||
faction={faction}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { AugmentationsPage } from "./AugmentationsPage";
|
||||
import { DonateOption } from "./DonateOption";
|
||||
import { Info } from "./Info";
|
||||
import { Option } from "./Option";
|
||||
@ -24,10 +23,9 @@ import { FactionWork } from "../../Work/FactionWork";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { repNeededToDonate } from "../formulas/donation";
|
||||
|
||||
interface IProps {
|
||||
type FactionRootProps = {
|
||||
faction: Faction;
|
||||
augPage: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
// Info text for all options on the UI
|
||||
const hackingContractsInfo =
|
||||
@ -148,11 +146,8 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
);
|
||||
}
|
||||
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
export function FactionRoot({ faction }: FactionRootProps): React.ReactElement {
|
||||
const rerender = useRerender(200);
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(props.augPage);
|
||||
|
||||
const faction = props.faction;
|
||||
|
||||
if (!Player.factions.includes(faction.name)) {
|
||||
return (
|
||||
@ -165,9 +160,11 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={() => setPurchasingAugs(false)} />
|
||||
) : (
|
||||
<MainPage rerender={rerender} faction={faction} onAugmentations={() => setPurchasingAugs(true)} />
|
||||
return (
|
||||
<MainPage
|
||||
rerender={rerender}
|
||||
faction={faction}
|
||||
onAugmentations={() => Router.toPage(Page.FactionAugmentations, { faction })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,16 +1,18 @@
|
||||
import type { Faction } from "../Faction";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma } from "@mui/icons-material";
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { FactionName } from "@enums";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { formatFavor, formatReputation } from "../../ui/formatNumber";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { FactionName } from "@enums";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { Faction } from "../Faction";
|
||||
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
|
||||
import { Factions } from "../Factions";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
|
||||
export const InvitationsSeen: string[] = [];
|
||||
|
||||
@ -53,11 +55,11 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
const augsLeft = getFactionAugmentationsFiltered(props.faction).filter((aug) => !Player.hasAugmentation(aug)).length;
|
||||
|
||||
function openFaction(faction: Faction): void {
|
||||
Router.toFaction(faction);
|
||||
Router.toPage(Page.Faction, { faction });
|
||||
}
|
||||
|
||||
function openFactionAugPage(faction: Faction): void {
|
||||
Router.toFaction(faction, true);
|
||||
Router.toPage(Page.FactionAugmentations, { faction });
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement>, faction: FactionName): void {
|
||||
|
@ -95,7 +95,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
||||
|
||||
function compareSaveGame(): void {
|
||||
if (!importData) return;
|
||||
Router.toImportSave(importData.base64);
|
||||
Router.toPage(Page.ImportSave, { base64Save: importData.base64 });
|
||||
setImportSaveOpen(false);
|
||||
setImportData(null);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ function toLocation(location: Location): void {
|
||||
} else if (location.name === LocationName.WorldStockExchange) {
|
||||
Router.toPage(Page.StockMarket);
|
||||
} else {
|
||||
Router.toLocation(location);
|
||||
Router.toPage(Page.Location, { location });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,11 +151,10 @@ export function CompanyLocation(props: IProps): React.ReactElement {
|
||||
if (!e.isTrusted) {
|
||||
return;
|
||||
}
|
||||
const loc = location;
|
||||
if (!loc.infiltrationData)
|
||||
if (!location.infiltrationData)
|
||||
throw new Error(`trying to start infiltration at ${props.locName} but the infiltrationData is null`);
|
||||
|
||||
Router.toInfiltration(loc);
|
||||
Router.toPage(Page.Infiltration, { location });
|
||||
}
|
||||
|
||||
function work(e: React.MouseEvent<HTMLElement>): void {
|
||||
|
@ -23,8 +23,8 @@ import { findCrime } from "../Crime/CrimeHelpers";
|
||||
import { CompanyPositions } from "../Company/CompanyPositions";
|
||||
import { DarkWebItems } from "../DarkWeb/DarkWebItems";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { Page } from "../ui/Router";
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { Locations } from "../Locations/Locations";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
import { Programs } from "../Programs/Programs";
|
||||
@ -231,7 +231,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
} else if (location.name === LocationName.WorldStockExchange) {
|
||||
Router.toPage(Page.StockMarket);
|
||||
} else {
|
||||
Router.toLocation(location);
|
||||
Router.toPage(Page.Location, { location });
|
||||
}
|
||||
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50000);
|
||||
return true;
|
||||
@ -559,7 +559,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
server.backdoorInstalled = true;
|
||||
|
||||
if (SpecialServers.WorldDaemon === server.hostname) {
|
||||
return Router.toBitVerse(false, false);
|
||||
return Router.toPage(Page.BitVerse, { flume: false, quick: false });
|
||||
}
|
||||
// Manunally check for faction invites
|
||||
Engine.Counters.checkFactionInvitations = 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { Augmentation } from "../../../Augmentation/Augmentation";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { AugmentationName, LocationName } from "@enums";
|
||||
import { AugmentationName } from "@enums";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { CheckBox, CheckBoxOutlineBlank, Construction } from "@mui/icons-material";
|
||||
@ -11,7 +11,6 @@ import { GraftingWork } from "../../../Work/GraftingWork";
|
||||
import { Augmentations } from "../../../Augmentation/Augmentations";
|
||||
import { CONSTANTS } from "../../../Constants";
|
||||
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
|
||||
import { Locations } from "../../../Locations/Locations";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../../Settings/SettingEnums";
|
||||
import { Settings } from "../../../Settings/Settings";
|
||||
import { Router } from "../../../ui/GameRoot";
|
||||
@ -87,7 +86,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
|
||||
return (
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||
<Button onClick={() => Router.toLocation(Locations[LocationName.NewTokyoVitaLife])}>Back</Button>
|
||||
<Button onClick={() => Router.back()}>Back</Button>
|
||||
<Typography variant="h4">Grafting Laboratory</Typography>
|
||||
<Typography>
|
||||
You find yourself in a secret laboratory, owned by a mysterious researcher.
|
||||
|
@ -41,7 +41,7 @@ import PublicIcon from "@mui/icons-material/Public";
|
||||
import LiveHelpIcon from "@mui/icons-material/LiveHelp";
|
||||
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page, SimplePage } from "../../ui/Router";
|
||||
import { Page, isSimplePage } from "../../ui/Router";
|
||||
import { SidebarAccordion } from "./SidebarAccordion";
|
||||
import { Player } from "@player";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
@ -104,11 +104,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
}),
|
||||
);
|
||||
|
||||
interface IProps {
|
||||
page: Page;
|
||||
}
|
||||
|
||||
export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
export function SidebarRoot(props: { page: Page }): React.ReactElement {
|
||||
useRerender(200);
|
||||
|
||||
let flash: Page | null = null;
|
||||
@ -239,11 +235,11 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
const clickPage = useCallback(
|
||||
(page: Page) => {
|
||||
if (page === Page.Job) {
|
||||
Router.toJob(Locations[Object.keys(Player.jobs)[0]]);
|
||||
Router.toPage(page, { location: 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);
|
||||
Router.toPage(page, {});
|
||||
} else if (isSimplePage(page)) {
|
||||
Router.toPage(page);
|
||||
} else {
|
||||
throw new Error("Can't handle click on Page " + page);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Output, Link, RawOutput, TTimer } from "./OutputTypes";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { Page } from "../ui/Router";
|
||||
import { Player } from "@player";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { BaseServer } from "../Server/BaseServer";
|
||||
@ -206,7 +207,7 @@ export class Terminal {
|
||||
// Success!
|
||||
server.backdoorInstalled = true;
|
||||
if (SpecialServers.WorldDaemon === server.hostname) {
|
||||
Router.toBitVerse(false, false);
|
||||
Router.toPage(Page.BitVerse, { flume: false, quick: false });
|
||||
return;
|
||||
}
|
||||
// Manunally check for faction invites
|
||||
@ -301,7 +302,7 @@ export class Terminal {
|
||||
if (Player.bitNodeN == null) {
|
||||
Player.bitNodeN = 1;
|
||||
}
|
||||
Router.toBitVerse(false, false);
|
||||
Router.toPage(Page.BitVerse, { flume: false, quick: false });
|
||||
return;
|
||||
}
|
||||
// Manunally check for faction invites
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Terminal } from "../../../Terminal";
|
||||
import { ScriptEditorRouteOptions } from "../../../ui/Router";
|
||||
import { ScriptEditorRouteOptions, Page } from "../../../ui/Router";
|
||||
import { Router } from "../../../ui/GameRoot";
|
||||
import { BaseServer } from "../../../Server/BaseServer";
|
||||
import { CursorPositions } from "../../../ScriptEditor/CursorPositions";
|
||||
@ -26,17 +26,17 @@ export async function main(ns) {
|
||||
export function commonEditor(
|
||||
command: string,
|
||||
{ args, server }: EditorParameters,
|
||||
scriptEditorRouteOptions?: ScriptEditorRouteOptions,
|
||||
options?: ScriptEditorRouteOptions,
|
||||
): void {
|
||||
if (args.length < 1) return Terminal.error(`Incorrect usage of ${command} command. Usage: ${command} [scriptname]`);
|
||||
const filesToOpen = new Map<ScriptFilePath | TextFilePath, string>();
|
||||
const files = new Map<ScriptFilePath | TextFilePath, string>();
|
||||
for (const arg of args) {
|
||||
const pattern = String(arg);
|
||||
|
||||
// Glob of existing files
|
||||
if (pattern.includes("*") || pattern.includes("?")) {
|
||||
for (const [path, file] of getGlobbedFileMap(pattern, server, Terminal.currDir)) {
|
||||
filesToOpen.set(path, file.content);
|
||||
files.set(path, file.content);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -49,8 +49,8 @@ export function commonEditor(
|
||||
}
|
||||
const file = server.getContentFile(path);
|
||||
const content = file ? file.content : isNs2(path) ? newNs2Template : "";
|
||||
filesToOpen.set(path, content);
|
||||
files.set(path, content);
|
||||
if (content === newNs2Template) CursorPositions.saveCursor(path, { row: 3, column: 5 });
|
||||
}
|
||||
Router.toScriptEditor(filesToOpen, scriptEditorRouteOptions);
|
||||
Router.toPage(Page.ScriptEditor, { files, options });
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
import React from "react";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
|
||||
import type { TextFilePath } from "../../Paths/TextFilePath";
|
||||
import type { ContractFilePath } from "../../Paths/ContractFilePath";
|
||||
import type { ProgramFilePath } from "../../Paths/ProgramFilePath";
|
||||
import type { ContentFilePath } from "../../Paths/ContentFile";
|
||||
import type { ScriptFilePath } from "../../Paths/ScriptFilePath";
|
||||
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import React from "react";
|
||||
import { BaseServer } from "../../Server/BaseServer";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { Terminal } from "../../Terminal";
|
||||
import libarg from "arg";
|
||||
import { showLiterature } from "../../Literature/LiteratureHelpers";
|
||||
@ -133,9 +135,9 @@ export function ls(args: (string | number | boolean)[], server: BaseServer): voi
|
||||
const fullPath = combinePath(baseDirectory, props.path);
|
||||
function onClick() {
|
||||
const code = server.scripts.get(fullPath)?.content ?? "";
|
||||
const map = new Map<ContentFilePath, string>();
|
||||
map.set(fullPath, code);
|
||||
Router.toScriptEditor(map);
|
||||
const files = new Map<ContentFilePath, string>();
|
||||
files.set(fullPath, code);
|
||||
Router.toPage(Page.ScriptEditor, { files });
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
|
@ -1,6 +1,3 @@
|
||||
import type { ScriptFilePath } from "../Paths/ScriptFilePath";
|
||||
import type { TextFilePath } from "../Paths/TextFilePath";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { createStyles, makeStyles } from "@mui/styles";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
@ -11,19 +8,16 @@ import { installAugmentations } from "../Augmentation/AugmentationHelpers";
|
||||
import { saveObject } from "../SaveObject";
|
||||
import { onExport } from "../ExportBonus";
|
||||
import { LocationName } from "@enums";
|
||||
import { Location } from "../Locations/Location";
|
||||
import { ITutorial, iTutorialStart } from "../InteractiveTutorial";
|
||||
import { InteractiveTutorialRoot } from "./InteractiveTutorial/InteractiveTutorialRoot";
|
||||
import { ITutorialEvents } from "./InteractiveTutorial/ITutorialEvents";
|
||||
|
||||
import { Faction } from "../Faction/Faction";
|
||||
import { prestigeAugmentation } from "../Prestige";
|
||||
import { dialogBoxCreate } from "./React/DialogBox";
|
||||
import { GetAllServers } from "../Server/AllServers";
|
||||
import { Factions } from "../Faction/Factions";
|
||||
import { StockMarket } from "../StockMarket/StockMarket";
|
||||
|
||||
import { Page, SimplePage, IRouter } from "./Router";
|
||||
import { Page, PageWithContext, IRouter, ComplexPage, PageContext } from "./Router";
|
||||
import { Overview } from "./React/Overview";
|
||||
import { SidebarRoot } from "../Sidebar/ui/SidebarRoot";
|
||||
import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot";
|
||||
@ -47,6 +41,7 @@ import { TutorialRoot } from "../Tutorial/ui/TutorialRoot";
|
||||
import { ActiveScriptsRoot } from "./ActiveScripts/ActiveScriptsRoot";
|
||||
import { FactionsRoot } from "../Faction/ui/FactionsRoot";
|
||||
import { FactionRoot } from "../Faction/ui/FactionRoot";
|
||||
import { AugmentationsPage as FactionAugmentations } from "../Faction/ui/AugmentationsPage";
|
||||
import { CharacterStats } from "./CharacterStats";
|
||||
import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot";
|
||||
import { StockMarketRoot } from "../StockMarket/ui/StockMarketRoot";
|
||||
@ -72,7 +67,6 @@ import { ImportSave } from "./React/ImportSave";
|
||||
import { BypassWrapper } from "./React/BypassWrapper";
|
||||
|
||||
import { Apr1 } from "./Apr1";
|
||||
import { isFactionWork } from "../Work/FactionWork";
|
||||
import { V2Modal } from "../utils/V2Modal";
|
||||
import { MathJaxContext } from "better-react-mathjax";
|
||||
import { useRerender } from "./React/hooks";
|
||||
@ -100,6 +94,8 @@ const uninitialized = (): void => {
|
||||
throw new Error("Router called before initialization");
|
||||
};
|
||||
|
||||
const MAX_PAGES_IN_HISTORY = 10;
|
||||
|
||||
export let Router: IRouter = {
|
||||
isInitialized: false,
|
||||
page: () => {
|
||||
@ -109,16 +105,12 @@ export let Router: IRouter = {
|
||||
toPage: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
toBitVerse: uninitialized,
|
||||
toFaction: uninitialized,
|
||||
toInfiltration: uninitialized,
|
||||
toJob: uninitialized,
|
||||
toScriptEditor: uninitialized,
|
||||
toLocation: uninitialized,
|
||||
toImportSave: uninitialized,
|
||||
back: () => {
|
||||
throw new Error("Router called before initialization");
|
||||
},
|
||||
};
|
||||
|
||||
function determineStartPage(): Page {
|
||||
function determineStartPage() {
|
||||
if (RecoveryMode) return Page.Recovery;
|
||||
if (Player.currentWork !== null) return Page.Work;
|
||||
return Page.Terminal;
|
||||
@ -126,36 +118,21 @@ function determineStartPage(): Page {
|
||||
|
||||
export function GameRoot(): React.ReactElement {
|
||||
const classes = useStyles();
|
||||
const [{ files, vim }, setEditorOptions] = useState<{
|
||||
files: Map<ScriptFilePath | TextFilePath, string>;
|
||||
vim: boolean;
|
||||
}>({
|
||||
files: new Map(),
|
||||
vim: false,
|
||||
|
||||
const [pages, setPages] = useState<PageWithContext[]>(() => [{ page: determineStartPage() }]);
|
||||
const pageWithContext = pages[0];
|
||||
|
||||
const setNextPage = (pageWithContext: PageWithContext) =>
|
||||
setPages((prev) => {
|
||||
const next = [pageWithContext, ...prev];
|
||||
next.length = Math.min(next.length, MAX_PAGES_IN_HISTORY);
|
||||
return next;
|
||||
});
|
||||
const [page, setPage] = useState(determineStartPage());
|
||||
|
||||
const rerender = useRerender();
|
||||
const [augPage, setAugPage] = useState<boolean>(false);
|
||||
const [faction, setFaction] = useState<Faction>(
|
||||
isFactionWork(Player.currentWork) ? Factions[Player.currentWork.factionName] : (undefined as unknown as Faction),
|
||||
);
|
||||
if (faction === undefined && page === Page.Faction)
|
||||
throw new Error("Trying to go to a page without the proper setup");
|
||||
|
||||
const [flume, setFlume] = useState<boolean>(false);
|
||||
const [quick, setQuick] = useState<boolean>(false);
|
||||
const [location, setLocation] = useState<Location>(undefined as unknown as Location);
|
||||
if (location === undefined && (page === Page.Infiltration || page === Page.Location || page === Page.Job))
|
||||
throw new Error("Trying to go to a page without the proper setup");
|
||||
|
||||
const [cinematicText, setCinematicText] = useState("");
|
||||
const [errorBoundaryKey, setErrorBoundaryKey] = useState<number>(0);
|
||||
|
||||
const [importString, setImportString] = useState<string>(undefined as unknown as string);
|
||||
const [importAutomatic, setImportAutomatic] = useState<boolean>(false);
|
||||
if (importString === undefined && page === Page.ImportSave)
|
||||
throw new Error("Trying to go to a page without the proper setup");
|
||||
|
||||
const [allowRoutingCalls, setAllowRoutingCalls] = useState(true);
|
||||
|
||||
function resetErrorBoundary(): void {
|
||||
@ -180,67 +157,28 @@ export function GameRoot(): React.ReactElement {
|
||||
|
||||
Router = {
|
||||
isInitialized: true,
|
||||
page: () => page,
|
||||
page: () => pageWithContext.page,
|
||||
allowRouting: (value: boolean) => setAllowRoutingCalls(value),
|
||||
toPage: (page: SimplePage) => {
|
||||
toPage: (page: Page, context?: PageContext<ComplexPage>) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toPage");
|
||||
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) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toFaction");
|
||||
setAugPage(augPage);
|
||||
setPage(Page.Faction);
|
||||
if (faction) setFaction(faction);
|
||||
},
|
||||
toScriptEditor: (files = new Map(), options) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toScriptEditor");
|
||||
setEditorOptions({
|
||||
files,
|
||||
vim: !!options?.vim,
|
||||
});
|
||||
setPage(Page.ScriptEditor);
|
||||
},
|
||||
toJob: (location: Location) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toJob");
|
||||
setLocation(location);
|
||||
setPage(Page.Job);
|
||||
},
|
||||
toBitVerse: (flume: boolean, quick: boolean) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toBitVerse");
|
||||
setFlume(flume);
|
||||
setQuick(quick);
|
||||
case Page.BitVerse:
|
||||
calculateAchievements();
|
||||
setPage(Page.BitVerse);
|
||||
break;
|
||||
}
|
||||
setNextPage({ page, ...context } as PageWithContext);
|
||||
},
|
||||
toInfiltration: (location: Location) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toInfiltration");
|
||||
setLocation(location);
|
||||
setPage(Page.Infiltration);
|
||||
},
|
||||
toLocation: (location: Location) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toLocation");
|
||||
setLocation(location);
|
||||
setPage(Page.Location);
|
||||
},
|
||||
toImportSave: (base64save: string, automatic = false) => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("toImportSave");
|
||||
setImportString(base64save);
|
||||
setImportAutomatic(automatic);
|
||||
setPage(Page.ImportSave);
|
||||
back: () => {
|
||||
if (!allowRoutingCalls) return attemptedForbiddenRouting("back");
|
||||
setPages((pages) => pages.slice(1));
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (page !== Page.Terminal) window.scrollTo(0, 0);
|
||||
if (pageWithContext.page !== Page.Terminal) window.scrollTo(0, 0);
|
||||
});
|
||||
|
||||
function softReset(): void {
|
||||
@ -254,7 +192,7 @@ export function GameRoot(): React.ReactElement {
|
||||
let withSidebar = true;
|
||||
let withPopups = true;
|
||||
let bypassGame = false;
|
||||
switch (page) {
|
||||
switch (pageWithContext.page) {
|
||||
case Page.Recovery: {
|
||||
mainPage = <RecoveryRoot softReset={softReset} />;
|
||||
withSidebar = false;
|
||||
@ -263,13 +201,13 @@ export function GameRoot(): React.ReactElement {
|
||||
break;
|
||||
}
|
||||
case Page.BitVerse: {
|
||||
mainPage = <BitverseRoot flume={flume} quick={quick} />;
|
||||
mainPage = <BitverseRoot flume={pageWithContext.flume} quick={pageWithContext.quick} />;
|
||||
withSidebar = false;
|
||||
withPopups = false;
|
||||
break;
|
||||
}
|
||||
case Page.Infiltration: {
|
||||
mainPage = <InfiltrationRoot location={location} />;
|
||||
mainPage = <InfiltrationRoot location={pageWithContext.location} />;
|
||||
withSidebar = false;
|
||||
withPopups = false;
|
||||
break;
|
||||
@ -302,7 +240,13 @@ export function GameRoot(): React.ReactElement {
|
||||
break;
|
||||
}
|
||||
case Page.ScriptEditor: {
|
||||
mainPage = <ScriptEditorRoot files={files} hostname={Player.getCurrentServer().hostname} vim={vim} />;
|
||||
mainPage = (
|
||||
<ScriptEditorRoot
|
||||
files={pageWithContext.files ?? new Map()}
|
||||
hostname={Player.getCurrentServer().hostname}
|
||||
vim={!!pageWithContext.options?.vim}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case Page.ActiveScripts: {
|
||||
@ -322,7 +266,11 @@ export function GameRoot(): React.ReactElement {
|
||||
break;
|
||||
}
|
||||
case Page.Faction: {
|
||||
mainPage = <FactionRoot faction={faction} augPage={augPage} />;
|
||||
mainPage = <FactionRoot faction={pageWithContext.faction} />;
|
||||
break;
|
||||
}
|
||||
case Page.FactionAugmentations: {
|
||||
mainPage = <FactionAugmentations faction={pageWithContext.faction} />;
|
||||
break;
|
||||
}
|
||||
case Page.Milestones: {
|
||||
@ -375,7 +323,7 @@ export function GameRoot(): React.ReactElement {
|
||||
}
|
||||
case Page.Job:
|
||||
case Page.Location: {
|
||||
mainPage = <GenericLocation loc={location} />;
|
||||
mainPage = <GenericLocation loc={pageWithContext.location} />;
|
||||
break;
|
||||
}
|
||||
case Page.Options: {
|
||||
@ -417,7 +365,7 @@ export function GameRoot(): React.ReactElement {
|
||||
break;
|
||||
}
|
||||
case Page.ImportSave: {
|
||||
mainPage = <ImportSave importString={importString} automatic={importAutomatic} />;
|
||||
mainPage = <ImportSave importString={pageWithContext.base64Save} automatic={!!pageWithContext.automatic} />;
|
||||
withSidebar = false;
|
||||
withPopups = false;
|
||||
bypassGame = true;
|
||||
@ -444,7 +392,7 @@ export function GameRoot(): React.ReactElement {
|
||||
</Overview>
|
||||
{withSidebar ? (
|
||||
<Box display="flex" flexDirection="row" width="100%">
|
||||
<SidebarRoot page={page} />
|
||||
<SidebarRoot page={pageWithContext.page} />
|
||||
<Box className={classes.root}>{mainPage}</Box>
|
||||
</Box>
|
||||
) : (
|
||||
|
@ -3,7 +3,7 @@ import type { TextFilePath } from "../Paths/TextFilePath";
|
||||
import type { Faction } from "../Faction/Faction";
|
||||
import type { Location } from "../Locations/Location";
|
||||
|
||||
// These enums don't need enum helper support for now
|
||||
// This enum doesn't need enum helper support for now
|
||||
/**
|
||||
* The full-screen page the player is currently be on.
|
||||
* These are "simple" pages that don't require any extra parameters to
|
||||
@ -38,14 +38,12 @@ export enum SimplePage {
|
||||
ThemeBrowser = "Theme Browser",
|
||||
}
|
||||
|
||||
/**
|
||||
* "Complex" pages that need a custom transition function.
|
||||
*/
|
||||
export enum ComplexPage {
|
||||
BitVerse = "BitVerse",
|
||||
Faction = "Faction",
|
||||
Infiltration = "Infiltration",
|
||||
Job = "Job",
|
||||
Faction = "Faction",
|
||||
FactionAugmentations = "Faction Augmentations",
|
||||
ScriptEditor = "Script Editor",
|
||||
Location = "Location",
|
||||
ImportSave = "Import Save",
|
||||
@ -56,6 +54,35 @@ export enum ComplexPage {
|
||||
export type Page = SimplePage | ComplexPage;
|
||||
export const Page = { ...SimplePage, ...ComplexPage };
|
||||
|
||||
export type PageContext<T extends Page> = T extends ComplexPage.BitVerse
|
||||
? { flume: boolean; quick: boolean }
|
||||
: T extends ComplexPage.Infiltration
|
||||
? { location: Location }
|
||||
: T extends ComplexPage.Job
|
||||
? { location: Location }
|
||||
: T extends ComplexPage.Faction
|
||||
? { faction: Faction }
|
||||
: T extends ComplexPage.FactionAugmentations
|
||||
? { faction: Faction }
|
||||
: T extends ComplexPage.ScriptEditor
|
||||
? { files?: Map<ScriptFilePath | TextFilePath, string>; options?: ScriptEditorRouteOptions }
|
||||
: T extends ComplexPage.Location
|
||||
? { location: Location }
|
||||
: T extends ComplexPage.ImportSave
|
||||
? { base64Save: string; automatic?: boolean }
|
||||
: never;
|
||||
|
||||
export type PageWithContext =
|
||||
| ({ page: ComplexPage.BitVerse } & PageContext<ComplexPage.BitVerse>)
|
||||
| ({ page: ComplexPage.Infiltration } & PageContext<ComplexPage.Infiltration>)
|
||||
| ({ page: ComplexPage.Job } & PageContext<ComplexPage.Job>)
|
||||
| ({ page: ComplexPage.Faction } & PageContext<ComplexPage.Faction>)
|
||||
| ({ page: ComplexPage.FactionAugmentations } & PageContext<ComplexPage.FactionAugmentations>)
|
||||
| ({ page: ComplexPage.ScriptEditor } & PageContext<ComplexPage.ScriptEditor>)
|
||||
| ({ page: ComplexPage.Location } & PageContext<ComplexPage.Location>)
|
||||
| ({ page: ComplexPage.ImportSave } & PageContext<ComplexPage.ImportSave>)
|
||||
| { page: SimplePage };
|
||||
|
||||
export interface ScriptEditorRouteOptions {
|
||||
vim: boolean;
|
||||
}
|
||||
@ -66,11 +93,10 @@ export interface IRouter {
|
||||
page(): Page;
|
||||
allowRouting(value: boolean): void;
|
||||
toPage(page: SimplePage): void;
|
||||
toBitVerse(flume: boolean, quick: boolean): void;
|
||||
toFaction(faction: Faction, augPage?: boolean): void; // faction name
|
||||
toInfiltration(location: Location): void;
|
||||
toJob(location: Location): void;
|
||||
toScriptEditor(files?: Map<ScriptFilePath | TextFilePath, string>, options?: ScriptEditorRouteOptions): void;
|
||||
toLocation(location: Location): void;
|
||||
toImportSave(base64Save: string, automatic?: boolean): void;
|
||||
toPage<T extends ComplexPage>(page: T, context: PageContext<T>): void;
|
||||
/** go to a preveious page (if any) */
|
||||
back(): void;
|
||||
}
|
||||
|
||||
const simplePages = Object.values(SimplePage);
|
||||
export const isSimplePage = (page: Page): page is SimplePage => simplePages.includes(page as SimplePage);
|
||||
|
@ -206,7 +206,7 @@ export function WorkInProgressRoot(): React.ReactElement {
|
||||
workInfo = {
|
||||
buttons: {
|
||||
cancel: () => {
|
||||
Router.toLocation(Locations[LocationName.Slums]);
|
||||
Router.toPage(Page.Location, { location: Locations[LocationName.Slums] });
|
||||
Player.finishWork(true);
|
||||
},
|
||||
unfocus: () => {
|
||||
@ -374,11 +374,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
||||
workInfo = {
|
||||
buttons: {
|
||||
cancel: () => {
|
||||
Router.toFaction(faction);
|
||||
Router.toPage(Page.Faction, { faction });
|
||||
Player.finishWork(true);
|
||||
},
|
||||
unfocus: () => {
|
||||
Router.toFaction(faction);
|
||||
Router.toPage(Page.Faction, { faction });
|
||||
Player.stopFocusing();
|
||||
},
|
||||
},
|
||||
@ -426,11 +426,11 @@ export function WorkInProgressRoot(): React.ReactElement {
|
||||
buttons: {
|
||||
cancel: () => {
|
||||
Player.finishWork(true);
|
||||
Router.toJob(Locations[comp.name]);
|
||||
Router.toPage(Page.Job, { location: Locations[comp.name] });
|
||||
},
|
||||
unfocus: () => {
|
||||
Player.stopFocusing();
|
||||
Router.toJob(Locations[comp.name]);
|
||||
Router.toPage(Page.Job, { location: Locations[comp.name] });
|
||||
},
|
||||
},
|
||||
title: (
|
||||
|
Loading…
Reference in New Issue
Block a user