import React, { useState, useEffect } from "react"; import { IPlayer } from "../PersonObjects/IPlayer"; import { IEngine } from "../IEngine"; import { ITerminal } from "../Terminal/ITerminal"; import { installAugmentations } from "../Augmentation/AugmentationHelpers"; import { saveObject } from "../SaveObject"; import { onExport } from "../ExportBonus"; import { LocationName } from "../Locations/data/LocationNames"; import { Location } from "../Locations/Location"; import { Locations } from "../Locations/Locations"; 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 { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling"; import { cancelOrder, eventEmitterForUiReset, initStockMarketFnForReact, placeOrder, StockMarket, } from "../StockMarket/StockMarket"; import { Theme } from "@mui/material/styles"; import makeStyles from "@mui/styles/makeStyles"; 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 { Overview } from "./React/Overview"; import { SidebarRoot } from "../Sidebar/ui/SidebarRoot"; import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot"; import { DevMenuRoot } from "../DevMenu"; import { BladeburnerRoot } from "../Bladeburner/ui/BladeburnerRoot"; import { GangRoot } from "../Gang/ui/GangRoot"; import { CorporationRoot } from "../Corporation/ui/CorporationRoot"; import { InfiltrationRoot } from "../Infiltration/ui/InfiltrationRoot"; import { ResleeveRoot } from "../PersonObjects/Resleeving/ui/ResleeveRoot"; import { WorkInProgressRoot } from "./WorkInProgressRoot"; import { GameOptionsRoot } from "../ui/React/GameOptionsRoot"; import { SleeveRoot } from "../PersonObjects/Sleeve/ui/SleeveRoot"; import { HacknetRoot } from "../Hacknet/ui/HacknetRoot"; import { GenericLocation } from "../Locations/ui/GenericLocation"; import { LocationCity } from "../Locations/ui/City"; import { ProgramsRoot } from "../Programs/ui/ProgramsRoot"; import { Root as ScriptEditorRoot } from "../ScriptEditor/ui/ScriptEditorRoot"; import { MilestonesRoot } from "../Milestones/ui/MilestonesRoot"; import { TerminalRoot } from "../Terminal/ui/TerminalRoot"; import { TutorialRoot } from "../Tutorial/ui/TutorialRoot"; import { ActiveScriptsRoot } from "../ui/ActiveScripts/ActiveScriptsRoot"; import { FactionsRoot } from "../Faction/ui/FactionsRoot"; import { FactionRoot } from "../Faction/ui/FactionRoot"; import { CharacterStats } from "./CharacterStats"; import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot"; import { StockMarketRoot } from "../StockMarket/ui/StockMarketRoot"; import { BitverseRoot } from "../BitNode/ui/BitverseRoot"; import { StaneksGiftRoot } from "../CotMG/ui/StaneksGiftRoot"; import { staneksGift } from "../CotMG/Helper"; import { CharacterOverview } from "./React/CharacterOverview"; import { BladeburnerCinematic } from "../Bladeburner/ui/BladeburnerCinematic"; import { workerScripts } from "../Netscript/WorkerScripts"; import { Unclickable } from "../Exploits/Unclickable"; import { Snackbar, SnackbarProvider } from "./React/Snackbar"; import { LogBoxManager } from "./React/LogBoxManager"; import { AlertManager } from "./React/AlertManager"; import { PromptManager } from "./React/PromptManager"; import { InvitationModal } from "../Faction/ui/InvitationModal"; import { calculateAchievements } from "../Achievements/Achievements"; import { enterBitNode } from "../RedPill"; import { Context } from "./Context"; 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"; import _wrap from "lodash/wrap"; import _functions from "lodash/functions"; const htmlLocation = location; interface IProps { terminal: ITerminal; player: IPlayer; engine: IEngine; } const useStyles = makeStyles((theme: Theme) => createStyles({ root: { "-ms-overflow-style": "none" /* for Internet Explorer, Edge */, "scrollbar-width": "none" /* for Firefox */, margin: theme.spacing(0), flexGrow: 1, display: "block", padding: "8px", minHeight: "100vh", boxSizing: "border-box", }, }), ); export let Router: IRouter = { page: () => { throw new Error("Router called before initialization"); }, allowRouting: () => { throw new Error("Router called before initialization"); }, toActiveScripts: () => { throw new Error("Router called before initialization"); }, toAugmentations: () => { throw new Error("Router called before initialization"); }, toBitVerse: () => { throw new Error("Router called before initialization"); }, toBladeburner: () => { throw new Error("Router called before initialization"); }, toStats: () => { throw new Error("Router called before initialization"); }, toCity: () => { throw new Error("Router called before initialization"); }, toCorporation: () => { throw new Error("Router called before initialization"); }, toCreateProgram: () => { throw new Error("Router called before initialization"); }, toDevMenu: () => { throw new Error("Router called before initialization"); }, toFaction: () => { throw new Error("Router called before initialization"); }, toFactions: () => { throw new Error("Router called before initialization"); }, toGameOptions: () => { throw new Error("Router called before initialization"); }, toGang: () => { throw new Error("Router called before initialization"); }, toHacknetNodes: () => { throw new Error("Router called before initialization"); }, toInfiltration: () => { throw new Error("Router called before initialization"); }, toJob: () => { throw new Error("Router called before initialization"); }, toMilestones: () => { throw new Error("Router called before initialization"); }, toResleeves: () => { throw new Error("Router called before initialization"); }, toScriptEditor: () => { throw new Error("Router called before initialization"); }, toSleeves: () => { throw new Error("Router called before initialization"); }, toStockMarket: () => { throw new Error("Router called before initialization"); }, toTerminal: () => { throw new Error("Router called before initialization"); }, toTravel: () => { throw new Error("Router called before initialization"); }, toTutorial: () => { throw new Error("Router called before initialization"); }, toWork: () => { throw new Error("Router called before initialization"); }, toBladeburnerCinematic: () => { throw new Error("Router called before initialization"); }, toLocation: () => { throw new Error("Router called before initialization"); }, toStaneksGift: () => { throw new Error("Router called before initialization"); }, toAchievements: () => { throw new Error("Router called before initialization"); }, toThemeBrowser: () => { throw new Error("Router called before initialization"); }, toImportSave: () => { throw new Error("Router called before initialization"); }, }; function determineStartPage(player: IPlayer): Page { if (RecoveryMode) return Page.Recovery; if (player.isWorking) return Page.Work; return Page.Terminal; } 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 setRerender = useState(0)[1]; const [faction, setFaction] = useState( player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : (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(false); const [quick, setQuick] = useState(false); const [location, setLocation] = useState(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(0); const [sidebarOpened, setSideBarOpened] = useState(Settings.IsSidebarOpened); const [importString, setImportString] = useState(undefined as unknown as string); const [importAutomatic, setImportAutomatic] = useState(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 { setErrorBoundaryKey(errorBoundaryKey + 1); } function rerender(): void { setRerender((old) => old + 1); } useEffect(() => { return ITutorialEvents.subscribe(rerender); }, []); function killAllScripts(): void { for (const server of GetAllServers()) { server.runningScripts = []; } saveObject.saveGame(); setTimeout(() => htmlLocation.reload(), 2000); } Router = { 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), toFaction: (faction?: Faction) => { 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), toResleeves: () => setPage(Page.Resleeves), toScriptEditor: (files: Record, options?: ScriptEditorRouteOptions) => { setEditorOptions({ files, vim: !!options?.vim, }); setPage(Page.ScriptEditor); }, toSleeves: () => setPage(Page.Sleeves), toStockMarket: () => setPage(Page.StockMarket), toTerminal: () => setPage(Page.Terminal), toTutorial: () => setPage(Page.Tutorial), toJob: () => { setLocation(Locations[player.companyName]); setPage(Page.Job); }, toCity: () => { setPage(Page.City); }, toTravel: () => { player.gotoLocation(LocationName.TravelAgency); setPage(Page.Travel); }, toBitVerse: (flume: boolean, quick: boolean) => { setFlume(flume); setQuick(quick); calculateAchievements(); setPage(Page.BitVerse); }, toInfiltration: (location: Location) => { 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); setPage(Page.ImportSave); }, }; useEffect(() => { // Wrap Router navigate functions to be able to disable the execution _functions(Router). filter((fnName) => fnName.startsWith('to')). forEach((fnName) => { // @ts-ignore - tslint does not like this, couldn't find a way to make it cooperate Router[fnName] = _wrap(Router[fnName], (func, ...args) => { if (!allowRoutingCalls) { // Let's just log to console. console.log(`Routing is currently disabled - Attempted router.${fnName}()`); return; } // Call the function normally return func(...args); }); }); }); useEffect(() => { if (page !== Page.Terminal) window.scrollTo(0, 0); }); function softReset(): void { dialogBoxCreate("Soft Reset!"); prestigeAugmentation(); resetErrorBoundary(); Router.toTerminal(); } let mainPage = Cannot load; let withSidebar = true; let withPopups = true; let bypassGame = false; switch (page) { case Page.Recovery: { mainPage = ; withSidebar = false; withPopups = false; bypassGame = true; break; } case Page.BitVerse: { mainPage = ; withSidebar = false; withPopups = false; break; } case Page.Infiltration: { mainPage = ; withSidebar = false; withPopups = false; break; } case Page.BladeburnerCinematic: { mainPage = ; withSidebar = false; withPopups = false; break; } case Page.Work: { mainPage = ; withSidebar = false; break; } case Page.Terminal: { mainPage = ; break; } case Page.Sleeves: { mainPage = ; break; } case Page.StaneksGift: { mainPage = ; break; } case Page.Stats: { mainPage = ; break; } case Page.ScriptEditor: { mainPage = ( ); break; } case Page.ActiveScripts: { mainPage = ; break; } case Page.Hacknet: { mainPage = ; break; } case Page.CreateProgram: { mainPage = ; break; } case Page.Factions: { mainPage = ; break; } case Page.Faction: { mainPage = ; break; } case Page.Milestones: { mainPage = ; break; } case Page.Tutorial: { mainPage = ( { prestigeAugmentation(); Router.toTerminal(); iTutorialStart(); }} /> ); break; } case Page.DevMenu: { mainPage = ; break; } case Page.Gang: { mainPage = ; break; } case Page.Corporation: { mainPage = ; break; } case Page.Bladeburner: { mainPage = ; break; } case Page.Resleeves: { mainPage = ; break; } case Page.Travel: { mainPage = ; break; } case Page.StockMarket: { mainPage = ( ); break; } case Page.City: { mainPage = ; break; } case Page.Job: case Page.Location: { mainPage = ; break; } case Page.Options: { mainPage = ( saveObject.saveGame()} export={() => { // Apply the export bonus before saving the game onExport(player); saveObject.exportGame(); }} forceKill={killAllScripts} softReset={softReset} /> ); break; } case Page.Augmentations: { mainPage = ( { // Apply the export bonus before saving the game onExport(player); saveObject.exportGame(); }} installAugmentationsFn={() => { installAugmentations(); Router.toTerminal(); }} /> ); break; } case Page.Achievements: { mainPage = ; break; } case Page.ThemeBrowser: { mainPage = ; break; } case Page.ImportSave: { mainPage = ( ); withSidebar = false; withPopups = false; bypassGame = true; } } return ( {!ITutorial.isRunning ? ( saveObject.saveGame()} killScripts={killAllScripts} /> ) : ( )} {withSidebar ? ( { setSideBarOpened(isOpened); Settings.IsSidebarOpened = isOpened; }} /> {mainPage} ) : ( {mainPage} )} {withPopups && ( <> )} ); }