From acd51e832894196bcea8f9b97103d6266b82fd4d Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Fri, 17 Sep 2021 02:04:44 -0400 Subject: [PATCH 1/4] work --- css/activescripts.scss | 1 - css/augmentations.scss | 1 - css/hacknetnodes.scss | 1 - src/Augmentation/AugmentationHelpers.d.ts | 1 + src/Faction/FactionHelpers.d.ts | 1 + src/Faction/FactionHelpers.jsx | 2 +- src/Faction/ui/{Root.tsx => FactionRoot.tsx} | 24 +- .../ui/{FactionList.tsx => FactionsRoot.tsx} | 16 +- src/Gang/IGang.ts | 4 +- src/Locations/ui/GenericLocation.tsx | 6 +- src/Locations/ui/Root.tsx | 7 + ...gencyLocation.tsx => TravelAgencyRoot.tsx} | 44 +- src/PersonObjects/Sleeve/ui/SleeveRoot.tsx | 4 +- src/Prestige.d.ts | 2 + src/ScriptEditor/ui/Root.tsx | 6 +- src/Sidebar/ui/SidebarRoot.tsx | 752 +++++++++--------- src/StockMarket/StockMarket.tsx | 2 +- .../ui/{Root.tsx => StockMarketRoot.tsx} | 0 src/Terminal/ui/TerminalRoot.tsx | 4 +- src/engine.jsx | 40 +- src/ui/GameRoot.tsx | 194 +++++ src/ui/Router.ts | 62 ++ 22 files changed, 724 insertions(+), 450 deletions(-) rename src/Faction/ui/{Root.tsx => FactionRoot.tsx} (92%) rename src/Faction/ui/{FactionList.tsx => FactionsRoot.tsx} (81%) rename src/Locations/ui/{TravelAgencyLocation.tsx => TravelAgencyRoot.tsx} (67%) create mode 100644 src/Prestige.d.ts rename src/StockMarket/ui/{Root.tsx => StockMarketRoot.tsx} (100%) create mode 100644 src/ui/GameRoot.tsx create mode 100644 src/ui/Router.ts diff --git a/css/activescripts.scss b/css/activescripts.scss index 35e959558..f5f7593ba 100644 --- a/css/activescripts.scss +++ b/css/activescripts.scss @@ -6,7 +6,6 @@ .active-scripts-container { > p { - width: 70%; margin: 6px; padding: 4px; } diff --git a/css/augmentations.scss b/css/augmentations.scss index 2615aa4d6..53193ae1e 100644 --- a/css/augmentations.scss +++ b/css/augmentations.scss @@ -8,7 +8,6 @@ .augmentations-content { > p { font-size: $defaultFontSize * 0.875; - width: 70%; } } diff --git a/css/hacknetnodes.scss b/css/hacknetnodes.scss index f06b0b79a..97bf22122 100644 --- a/css/hacknetnodes.scss +++ b/css/hacknetnodes.scss @@ -7,7 +7,6 @@ .hacknet-general-info { margin: 10px; - width: 70vw; } #hacknet-nodes-container li { diff --git a/src/Augmentation/AugmentationHelpers.d.ts b/src/Augmentation/AugmentationHelpers.d.ts index 9e2bb7935..c20c69364 100644 --- a/src/Augmentation/AugmentationHelpers.d.ts +++ b/src/Augmentation/AugmentationHelpers.d.ts @@ -1 +1,2 @@ export declare function isRepeatableAug(aug: Augmentation): boolean; +export declare function installAugmentations(): void; diff --git a/src/Faction/FactionHelpers.d.ts b/src/Faction/FactionHelpers.d.ts index be7642c9a..a4a952b31 100644 --- a/src/Faction/FactionHelpers.d.ts +++ b/src/Faction/FactionHelpers.d.ts @@ -6,3 +6,4 @@ export declare function hasAugmentationPrereqs(aug: Augmentation): boolean; export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void; export declare function displayFactionContent(factionName: string, initiallyOnAugmentationsPage: boolean = false); export declare function joinFaction(faction: Faction): void; +export declare function startHackingMission(faction: Faction): void; diff --git a/src/Faction/FactionHelpers.jsx b/src/Faction/FactionHelpers.jsx index 772444402..1e5f0e166 100644 --- a/src/Faction/FactionHelpers.jsx +++ b/src/Faction/FactionHelpers.jsx @@ -1,7 +1,7 @@ import React from "react"; import ReactDOM from "react-dom"; -import { FactionRoot } from "./ui/Root"; +import { FactionRoot } from "./ui/FactionRoot"; import { Augmentations } from "../Augmentation/Augmentations"; import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; diff --git a/src/Faction/ui/Root.tsx b/src/Faction/ui/FactionRoot.tsx similarity index 92% rename from src/Faction/ui/Root.tsx rename to src/Faction/ui/FactionRoot.tsx index 694fa9059..50655ea62 100644 --- a/src/Faction/ui/Root.tsx +++ b/src/Faction/ui/FactionRoot.tsx @@ -24,8 +24,7 @@ import { CreateGangPopup } from "./CreateGangPopup"; type IProps = { engine: IEngine; - initiallyOnAugmentationsPage?: boolean; - faction: Faction; + faction: Faction | null; p: IPlayer; startHackingMissionFn: (faction: Faction) => void; }; @@ -33,6 +32,7 @@ type IProps = { type IState = { rerenderFlag: boolean; purchasingAugs: boolean; + faction: Faction; }; // Info text for all options on the UI @@ -74,11 +74,13 @@ const GangNames = [ export class FactionRoot extends React.Component { constructor(props: IProps) { + if (props.faction === null) throw new Error("Trying to render the Faction page with null faction"); super(props); this.state = { rerenderFlag: false, - purchasingAugs: props.initiallyOnAugmentationsPage ? props.initiallyOnAugmentationsPage : false, + purchasingAugs: false, + faction: props.faction, }; this.manageGang = this.manageGang.bind(this); @@ -101,7 +103,7 @@ export class FactionRoot extends React.Component { const popupId = "create-gang-popup"; createPopup(popupId, CreateGangPopup, { popupId: popupId, - facName: this.props.faction.name, + facName: this.state.faction.name, p: this.props.p, engine: this.props.engine, }); @@ -130,22 +132,22 @@ export class FactionRoot extends React.Component { } startFieldWork(): void { - this.props.p.startFactionFieldWork(this.props.faction); + this.props.p.startFactionFieldWork(this.state.faction); } startHackingContracts(): void { - this.props.p.startFactionHackWork(this.props.faction); + this.props.p.startFactionHackWork(this.state.faction); } startHackingMission(): void { - const fac = this.props.faction; + const fac = this.state.faction; this.props.p.singularityStopWork(); this.props.engine.loadMissionContent(); this.props.startHackingMissionFn(fac); } startSecurityWork(): void { - this.props.p.startFactionSecurityWork(this.props.faction); + this.props.p.startFactionSecurityWork(this.state.faction); } render(): React.ReactNode { @@ -154,7 +156,7 @@ export class FactionRoot extends React.Component { renderMainPage(): React.ReactNode { const p = this.props.p; - const faction = this.props.faction; + const faction = this.state.faction; const factionInfo = faction.getInfo(); // We have a special flag for whether the player this faction is the player's @@ -200,7 +202,7 @@ export class FactionRoot extends React.Component { )} {!isPlayersGang && factionInfo.offersWork() && ( { renderAugmentationsPage(): React.ReactNode { return ( <> - + ); } diff --git a/src/Faction/ui/FactionList.tsx b/src/Faction/ui/FactionsRoot.tsx similarity index 81% rename from src/Faction/ui/FactionList.tsx rename to src/Faction/ui/FactionsRoot.tsx index 358771ed2..fbed0ae67 100644 --- a/src/Faction/ui/FactionList.tsx +++ b/src/Faction/ui/FactionsRoot.tsx @@ -1,20 +1,20 @@ import React, { useState } from "react"; import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { Factions } from "../Factions"; -import { displayFactionContent, joinFaction } from "../FactionHelpers"; +import { Faction } from "../Faction"; +import { joinFaction } from "../FactionHelpers"; interface IProps { player: IPlayer; - engine: IEngine; + router: IRouter; } -export function FactionList(props: IProps): React.ReactElement { +export function FactionsRoot(props: IProps): React.ReactElement { const setRerender = useState(false)[1]; - function openFaction(faction: string): void { - props.engine.loadFactionContent(); - displayFactionContent(faction); + function openFaction(faction: Faction): void { + props.router.toFaction(faction); } function acceptInvitation(event: React.MouseEvent, faction: string): void { @@ -33,7 +33,7 @@ export function FactionList(props: IProps): React.ReactElement {
  • openFaction(faction)} + onClick={() => openFaction(Factions[faction])} style={{ padding: "4px", margin: "4px", display: "inline-block" }} > {faction} diff --git a/src/Gang/IGang.ts b/src/Gang/IGang.ts index b99f52f1d..00d7911cc 100644 --- a/src/Gang/IGang.ts +++ b/src/Gang/IGang.ts @@ -2,6 +2,7 @@ import { GangMemberUpgrade } from "./GangMemberUpgrade"; import { GangMember } from "./GangMember"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; +import { IAscensionResult } from "./IAscensionResult"; export interface IGang { facName: string; @@ -37,8 +38,9 @@ export interface IGang { getWantedPenalty(): number; calculatePower(): number; killMember(member: GangMember): void; - ascendMember(member: GangMember, workerScript: WorkerScript): void; + ascendMember(member: GangMember, workerScript: WorkerScript): IAscensionResult; getDiscount(): number; getAllTaskNames(): string[]; getUpgradeCost(upg: GangMemberUpgrade): number; + toJSON(): any; } diff --git a/src/Locations/ui/GenericLocation.tsx b/src/Locations/ui/GenericLocation.tsx index 3d6fa9168..f5f345483 100644 --- a/src/Locations/ui/GenericLocation.tsx +++ b/src/Locations/ui/GenericLocation.tsx @@ -12,7 +12,7 @@ import { HospitalLocation } from "./HospitalLocation"; import { SlumsLocation } from "./SlumsLocation"; import { SpecialLocation } from "./SpecialLocation"; import { TechVendorLocation } from "./TechVendorLocation"; -import { TravelAgencyLocation } from "./TravelAgencyLocation"; +import { TravelAgencyRoot } from "./TravelAgencyRoot"; import { UniversityLocation } from "./UniversityLocation"; import { CasinoLocation } from "./CasinoLocation"; @@ -21,6 +21,7 @@ import { LocationType } from "../LocationTypeEnum"; import { CityName } from "../data/CityNames"; import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { Settings } from "../../Settings/Settings"; @@ -32,6 +33,7 @@ import { CorruptableText } from "../../ui/React/CorruptableText"; type IProps = { engine: IEngine; + router: IRouter; loc: Location; p: IPlayer; returnToCity: () => void; @@ -91,7 +93,7 @@ export class GenericLocation extends React.Component { } if (this.props.loc.types.includes(LocationType.TravelAgency)) { - content.push(); + content.push(); } if (this.props.loc.types.includes(LocationType.University)) { diff --git a/src/Locations/ui/Root.tsx b/src/Locations/ui/Root.tsx index f554e7e06..ec7e5c58b 100644 --- a/src/Locations/ui/Root.tsx +++ b/src/Locations/ui/Root.tsx @@ -15,6 +15,7 @@ import { LocationName } from "../data/LocationNames"; import { CONSTANTS } from "../../Constants"; import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { dialogBoxCreate } from "../../../utils/DialogBox"; @@ -22,6 +23,7 @@ import { dialogBoxCreate } from "../../../utils/DialogBox"; type IProps = { initiallyInCity?: boolean; engine: IEngine; + router: IRouter; p: IPlayer; }; @@ -47,6 +49,10 @@ export class LocationRoot extends React.Component { } enterLocation(to: LocationName): void { + if (to == LocationName.TravelAgency) { + this.props.router.toTravel(); + return; + } this.props.p.gotoLocation(to); this.setState({ inCity: false, @@ -98,6 +104,7 @@ export class LocationRoot extends React.Component { return ( void; + router: IRouter; }; -function createTravelPopup(p: IPlayer, city: string, travel: () => void): void { +function travel(p: IPlayer, router: IRouter, to: CityName): void { + const cost = CONSTANTS.TravelCost; + if (!p.canAfford(cost)) { + dialogBoxCreate(`You cannot afford to travel to ${to}`); + return; + } + + p.loseMoney(cost); + p.travel(to); + dialogBoxCreate(You are now in {to}!); + router.toCity(); +} + +function createTravelPopup(p: IPlayer, router: IRouter, city: CityName): void { if (Settings.SuppressTravelConfirmation) { - travel(); + travel(p, router, city); return; } const popupId = `travel-confirmation`; createPopup(popupId, TravelConfirmationPopup, { player: p, city: city, - travel: travel, + travel: () => travel(p, router, city), popupId: popupId, }); } @@ -45,7 +60,7 @@ function ASCIIWorldMap(props: IProps): React.ReactElement {

    createTravelPopup(props.p, city, () => props.travel(city))} + onTravel={(city: CityName) => createTravelPopup(props.p, props.router, city)} /> ); @@ -66,7 +81,7 @@ function ListWorldMap(props: IProps): React.ReactElement { return ( createTravelPopup(props.p, city, () => props.travel(match[1]))} + onClick={() => createTravelPopup(props.p, props.router, city as CityName)} style={{ display: "block" }} text={`Travel to ${city}`} /> @@ -76,10 +91,15 @@ function ListWorldMap(props: IProps): React.ReactElement { ); } -export function TravelAgencyLocation(props: IProps): React.ReactElement { - if (Settings.DisableASCIIArt) { - return ; - } else { - return ; - } +export function TravelAgencyRoot(props: IProps): React.ReactElement { + return ( + <> +

    Travel Agency

    + {Settings.DisableASCIIArt ? ( + + ) : ( + + )} + + ); } diff --git a/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx b/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx index 9df9c22e6..b7e33961d 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveRoot.tsx @@ -20,7 +20,7 @@ export function SleeveRoot(props: IProps): React.ReactElement { }, []); return ( -
    + <>

    Sleeves

    Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness has been copied. In @@ -50,6 +50,6 @@ export function SleeveRoot(props: IProps): React.ReactElement {

  • ))} - + ); } diff --git a/src/Prestige.d.ts b/src/Prestige.d.ts new file mode 100644 index 000000000..61d353ba4 --- /dev/null +++ b/src/Prestige.d.ts @@ -0,0 +1,2 @@ +export declare function prestigeAugmentation(): void; +export declare function prestigeSourceFile(flume: boolean): void; diff --git a/src/ScriptEditor/ui/Root.tsx b/src/ScriptEditor/ui/Root.tsx index 543ebf9d6..b1eb01bef 100644 --- a/src/ScriptEditor/ui/Root.tsx +++ b/src/ScriptEditor/ui/Root.tsx @@ -308,7 +308,7 @@ export function Root(props: IProps): React.ReactElement { } return ( - + ); } diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index b3a27cd94..50086ceab 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -44,7 +44,7 @@ import LiveHelpIcon from "@mui/icons-material/LiveHelp"; import ExpandLessIcon from "@mui/icons-material/ExpandLess"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; -import { IEngine } from "../../IEngine"; +import { IRouter, Page } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { CONSTANTS } from "../../Constants"; import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../../InteractiveTutorial"; @@ -56,7 +56,6 @@ import { inMission } from "../../Missions"; import { cinematicTextFlag } from "../../CinematicText"; import { KEY } from "../../../utils/helpers/keyCodes"; import { FconfSettings } from "../../Fconf/FconfSettings"; -import { Page, routing } from "../../ui/navigationTracking"; const drawerWidth = 240; @@ -83,7 +82,6 @@ const closedMixin = (theme: Theme): CSSObject => ({ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({ width: theme.spacing(31), - flexShrink: 0, whiteSpace: "nowrap", boxSizing: "border-box", ...(open && { @@ -110,7 +108,8 @@ const useStyles = makeStyles((theme: Theme) => interface IProps { player: IPlayer; - engine: IEngine; + router: IRouter; + page: Page; } export function SidebarRoot(props: IProps): React.ReactElement { @@ -124,7 +123,6 @@ export function SidebarRoot(props: IProps): React.ReactElement { return () => clearInterval(id); }, []); - const [activeTab, setActiveTab] = useState("Terminal"); const [hackingOpen, setHackingOpen] = useState(true); const [characterOpen, setCharacterOpen] = useState(true); const [worldOpen, setWorldOpen] = useState(true); @@ -176,108 +174,88 @@ export function SidebarRoot(props: IProps): React.ReactElement { const canBladeburner = !!(props.player.bladeburner as any); function clickTerminal(): void { - setActiveTab("Terminal"); - props.engine.loadTerminalContent(); + props.router.toTerminal(); if (flashTerminal) iTutorialNextStep(); } function clickCreateScripts(): void { - setActiveTab("CreateScripts"); - props.engine.loadScriptEditorContent(); + props.router.toScriptEditor(); } function clickStats(): void { - setActiveTab("Stats"); - props.engine.loadCharacterContent(); + props.router.toCharacterInfo(); if (flashStats) iTutorialNextStep(); } function clickActiveScripts(): void { - setActiveTab("ActiveScripts"); - props.engine.loadActiveScriptsContent(); + props.router.toActiveScripts(); if (flashActiveScripts) iTutorialNextStep(); } function clickCreateProgram(): void { - setActiveTab("CreateProgram"); - props.engine.loadCreateProgramContent(); + props.router.toCreateProgram(); } function clickFactions(): void { - setActiveTab("Factions"); - props.engine.loadFactionsContent(); + props.router.toFactions(); } function clickAugmentations(): void { - setActiveTab("Augmentations"); - props.engine.loadAugmentationsContent(); + props.router.toAugmentations(); } function clickSleeves(): void { - setActiveTab("Sleeves"); - props.engine.loadSleevesContent(); + props.router.toSleeves(); } function clickHacknet(): void { - setActiveTab("Hacknet"); - props.engine.loadHacknetNodesContent(); + props.router.toHacknetNodes(); if (flashHacknet) iTutorialNextStep(); } function clickCity(): void { - setActiveTab("City"); - props.engine.loadLocationContent(); + props.router.toCity(); if (flashCity) iTutorialNextStep(); } function clickTravel(): void { - setActiveTab("Travel"); - props.engine.loadTravelContent(); + props.router.toTravel(); } function clickJob(): void { - setActiveTab("Job"); - props.engine.loadJobContent(); + props.router.toJob(); } function clickStockMarket(): void { - setActiveTab("StockMarket"); - props.engine.loadStockMarketContent(); + props.router.toStockMarket(); } function clickBladeburner(): void { - setActiveTab("Bladeburner"); - props.engine.loadBladeburnerContent(); + props.router.toBladeburner(); } function clickCorp(): void { - setActiveTab("Corp"); - props.engine.loadCorporationContent(); + props.router.toCorporation(); } function clickGang(): void { - setActiveTab("Gang"); - props.engine.loadGangContent(); + props.router.toGang(); } function clickTutorial(): void { - setActiveTab("Tutorial"); - props.engine.loadTutorialContent(); + props.router.toTutorial(); if (flashTutorial) iTutorialNextStep(); } function clickMilestones(): void { - setActiveTab("Milestones"); - props.engine.loadMilestonesContent(); + props.router.toMilestones(); } function clickOptions(): void { - setActiveTab("Options"); - props.engine.loadGameOptionsContent(); + props.router.toGameOptions(); } function clickDev(): void { - setActiveTab("Dev"); - props.engine.loadDevMenuContent(); + props.router.toDevMenu(); } useEffect(() => { @@ -327,7 +305,7 @@ export function SidebarRoot(props: IProps): React.ReactElement { clickCreateProgram(); } else if (event.keyCode === KEY.F && event.altKey) { // Overriden by Fconf - if (routing.isOn(Page.Terminal) && FconfSettings.ENABLE_BASH_HOTKEYS) { + if (props.page == Page.Terminal && FconfSettings.ENABLE_BASH_HOTKEYS) { return; } event.preventDefault(); @@ -359,421 +337,427 @@ export function SidebarRoot(props: IProps): React.ReactElement { const [open, setOpen] = useState(true); const toggleDrawer = (): void => setOpen((old) => !old); return ( - - - + + + + {!open ? : } + + Bitburner v{CONSTANTS.Version}} /> + + + + setHackingOpen((old) => !old)}> - {!open ? : } + - Bitburner v{CONSTANTS.Version}} /> + Hacking} /> + {hackingOpen ? : } - - - setHackingOpen((old) => !old)}> - - - - Hacking} /> - {hackingOpen ? : } - - - - - - - - - - Terminal - - - - - - - - - Create Script - - - - - - - - - Active Scripts - - - - {canCreateProgram && ( - + + + + + + + + Terminal + + + + + + + + + + Create Script + + + + + + + + + - - 0 ? programCount : undefined} color="error"> - - - - - - Create Program - - - - )} - - - - - setCharacterOpen((old) => !old)}> - - - - Character} /> - {characterOpen ? : } - - - - - - - - - Stats + Active Scripts - {canOpenFactions && ( + {canCreateProgram && ( - - + 0 ? programCount : undefined} color="error"> + - Factions + + Create Program + )} - {canOpenAugmentations && ( - - - - - - - - Augmentations - - - )} - - - - - - - Hacknet - - - - {canOpenSleeves && ( - - - - - - Sleeves - - - )} - + + - - setWorldOpen((old) => !old)}> + + setCharacterOpen((old) => !old)}> + + + + Character} /> + {characterOpen ? : } + + + - + - World} /> - {worldOpen ? : } + + + Stats + + - + {canOpenFactions && ( - + + + - - City + + Factions + )} + {canOpenAugmentations && ( - + + + - Travel + + Augmentations + - {canJob && ( - - - - - - Job - - - )} - {canStockMarket && ( - - - - - - Stock Market - - - )} - {canBladeburner && ( - - - - - - Bladeburner - - - )} - {canCorporation && ( - - - - - - Corp - - - )} - {canGang && ( - - - - - - Gang - - - )} - + )} + + + + + + + Hacknet + + + + {canOpenSleeves && ( + + + + + + Sleeves + + + )} + - - setHelpOpen((old) => !old)}> + + setWorldOpen((old) => !old)}> + + + + World} /> + {worldOpen ? : } + + + - + - Help} /> - {helpOpen ? : } + + + City + + - + + + + + + Travel + + + {canJob && ( - + - Milestones + Job + )} + {canStockMarket && ( - + - - Tutorial - + Stock Market + )} + {canBladeburner && ( - + - Options + Bladeburner - {process.env.NODE_ENV === "development" && ( - - - - - - Dev - - - )} - - - - + )} + {canCorporation && ( + + + + + + Corp + + + )} + {canGang && ( + + + + + + Gang + + + )} + + + + setHelpOpen((old) => !old)}> + + + + Help} /> + {helpOpen ? : } + + + + + + + + Milestones + + + + + + + + + Tutorial + + + + + + + + + Options + + + {process.env.NODE_ENV === "development" && ( + + + + + + Dev + + + )} + + + ); } diff --git a/src/StockMarket/StockMarket.tsx b/src/StockMarket/StockMarket.tsx index 3846e1889..dbb62e2e7 100644 --- a/src/StockMarket/StockMarket.tsx +++ b/src/StockMarket/StockMarket.tsx @@ -9,7 +9,7 @@ import { InitStockMetadata } from "./data/InitStockMetadata"; import { OrderTypes } from "./data/OrderTypes"; import { PositionTypes } from "./data/PositionTypes"; import { StockSymbols } from "./data/StockSymbols"; -import { StockMarketRoot } from "./ui/Root"; +import { StockMarketRoot } from "./ui/StockMarketRoot"; import { CONSTANTS } from "../Constants"; import { WorkerScript } from "../Netscript/WorkerScript"; diff --git a/src/StockMarket/ui/Root.tsx b/src/StockMarket/ui/StockMarketRoot.tsx similarity index 100% rename from src/StockMarket/ui/Root.tsx rename to src/StockMarket/ui/StockMarketRoot.tsx diff --git a/src/Terminal/ui/TerminalRoot.tsx b/src/Terminal/ui/TerminalRoot.tsx index 3cc00a346..cc4de1e29 100644 --- a/src/Terminal/ui/TerminalRoot.tsx +++ b/src/Terminal/ui/TerminalRoot.tsx @@ -76,7 +76,7 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE const classes = useStyles(); return ( <> - + {terminal.outputHistory.map((item, i) => { if (item instanceof Output) @@ -105,7 +105,7 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE {terminal.action !== null && }
    - + diff --git a/src/engine.jsx b/src/engine.jsx index 25ab34d64..ec3856841 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -19,13 +19,14 @@ import { CONSTANTS } from "./Constants"; import { DevMenuRoot } from "./DevMenu"; import { Factions, initFactions } from "./Faction/Factions"; import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers"; -import { FactionList } from "./Faction/ui/FactionList"; +import { FactionsRoot } from "./Faction/ui/FactionsRoot"; import { Root as BladeburnerRoot } from "./Bladeburner/ui/Root"; import { Root as GangRoot } from "./Gang/ui/Root"; import { SidebarRoot } from "./Sidebar/ui/SidebarRoot"; import { CorporationRoot } from "./Corporation/ui/CorporationRoot"; import { ResleeveRoot } from "./PersonObjects/Resleeving/ui/ResleeveRoot"; import { GameOptionsRoot } from "./ui/React/GameOptionsRoot"; +import { GameRoot } from "./ui/GameRoot"; import { TTheme as Theme } from "./ui/React/Theme"; import { SleeveRoot } from "./PersonObjects/Sleeve/ui/SleeveRoot"; import { displayInfiltrationContent } from "./Infiltration/Helper"; @@ -106,16 +107,16 @@ const Engine = { _idleSpeed: 200, // Speed (in ms) at which the main loop is updated loadTerminalContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.CharacterInfo); - ReactDOM.render( - - - , - Engine.Display.content, - ); - MainMenuLinks.Stats.classList.add("active"); + // Engine.hideAllContent(); + // Engine.Display.content.style.display = "block"; + // routing.navigateTo(Page.CharacterInfo); + // ReactDOM.render( + // + // + // , + // Engine.Display.content, + // ); + // MainMenuLinks.Stats.classList.add("active"); }, loadCharacterContent: function () { @@ -171,7 +172,7 @@ const Engine = { Engine.Display.content.style.display = "block"; routing.navigateTo(Page.Factions); MainMenuLinks.Factions.classList.add("active"); - ReactDOM.render(, Engine.Display.content); + ReactDOM.render(, Engine.Display.content); }, // TODO reactify @@ -394,9 +395,9 @@ const Engine = { // Helper function that hides all content hideAllContent: function () { - Engine.Display.content.style.display = "none"; - Engine.Display.content.scrollTop = 0; - ReactDOM.unmountComponentAtNode(Engine.Display.content); + // Engine.Display.content.style.display = "none"; + // Engine.Display.content.scrollTop = 0; + // ReactDOM.unmountComponentAtNode(Engine.Display.content); Engine.Display.infiltrationContent.style.display = "none"; ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent); @@ -408,7 +409,6 @@ const Engine = { }, displayCharacterOverviewInfo: function () { - console.log("rendering"); ReactDOM.render( saveObject.saveGame(Engine.indexedDb)} /> @@ -806,15 +806,15 @@ const Engine = { ReactDOM.render( - + , - document.getElementById("sidebar"), + document.getElementById("mainmenu-container"), ); }, setDisplayElements: function () { - Engine.Display.content = document.getElementById("generic-react-container"); - Engine.Display.content.style.display = "none"; + // Engine.Display.content = document.getElementById("generic-react-container"); + // Engine.Display.content.style.display = "none"; Engine.Display.missionContent = document.getElementById("mission-container"); Engine.Display.missionContent.style.display = "none"; diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx new file mode 100644 index 000000000..b8c27ca85 --- /dev/null +++ b/src/ui/GameRoot.tsx @@ -0,0 +1,194 @@ +import React, { useState, useEffect, useRef } 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 { CityName } from "../Locations/data/CityNames"; +import { Faction } from "../Faction/Faction"; +import { prestigeAugmentation } from "../Prestige"; +import { dialogBoxCreate } from "../../utils/DialogBox"; +import { AllServers } from "../Server/AllServers"; + +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 } from "./Router"; +import { SidebarRoot } from "../Sidebar/ui/SidebarRoot"; +import { AugmentationsRoot } from "../Augmentation/ui/Root"; +import { DevMenuRoot } from "../DevMenu"; +import { Root as BladeburnerRoot } from "../Bladeburner/ui/Root"; +import { Root as GangRoot } from "../Gang/ui/Root"; +import { CorporationRoot } from "../Corporation/ui/CorporationRoot"; +import { ResleeveRoot } from "../PersonObjects/Resleeving/ui/ResleeveRoot"; +import { GameOptionsRoot } from "../ui/React/GameOptionsRoot"; +import { SleeveRoot } from "../PersonObjects/Sleeve/ui/SleeveRoot"; +import { HacknetRoot } from "../Hacknet/ui/HacknetRoot"; +import { LocationRoot } from "../Locations/ui/Root"; +import { ProgramsRoot } from "../Programs/ui/ProgramsRoot"; +import { Root as ScriptEditorRoot } from "../ScriptEditor/ui/Root"; +import { MilestonesRoot } from "../Milestones/ui/MilestonesRoot"; +import { TerminalRoot } from "../Terminal/ui/TerminalRoot"; +import { TutorialRoot } from "../Tutorial/ui/TutorialRoot"; +import { ActiveScriptsRoot } from "../ui/ActiveScripts/Root"; +import { FactionsRoot } from "../Faction/ui/FactionsRoot"; +import { FactionRoot } from "../Faction/ui/FactionRoot"; +import { CharacterInfo } from "./CharacterInfo"; +import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot"; +import { StockMarketRoot } from "../Locations/ui/StockMarketRoot"; +import { workerScripts } from "../Netscript/WorkerScripts"; + +import { startHackingMission } from "../Faction/FactionHelpers"; + +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 */, + }, + }), +); + +export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement { + const contentRef = useRef(null); + const [faction, setFaction] = useState(null); + const [page, setPage] = useState(Page.Terminal); + const classes = useStyles(); + + const router = { + toActiveScripts: () => setPage(Page.ActiveScripts), + toAugmentations: () => setPage(Page.Augmentations), + toBladeburner: () => setPage(Page.Bladeburner), + toCharacterInfo: () => setPage(Page.Stats), + toCorporation: () => setPage(Page.Corporation), + toCreateProgram: () => setPage(Page.CreateProgram), + toDevMenu: () => setPage(Page.DevMenu), + toFaction: (faction: Faction) => { + setPage(Page.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: () => setPage(Page.CreateScript), + toSleeves: () => setPage(Page.Sleeves), + toStockMarket: () => setPage(Page.StockMarket), + toTerminal: () => setPage(Page.Terminal), + toTutorial: () => setPage(Page.Tutorial), + toJob: () => setPage(Page.Job), + toCity: () => { + // TODO This is bad. + player.gotoLocation(player.city as unknown as LocationName); + setPage(Page.City); + }, + toTravel: () => { + player.gotoLocation(LocationName.TravelAgency); + setPage(Page.Travel); + }, + }; + + return ( + <> + + + + {page === Page.Terminal ? ( + + ) : page === Page.Sleeves ? ( + + ) : page === Page.Stats ? ( + + ) : page === Page.CreateScript ? ( + + ) : page === Page.ActiveScripts ? ( + + ) : page === Page.Hacknet ? ( + + ) : page === Page.CreateProgram ? ( + + ) : page === Page.Factions ? ( + + ) : page === Page.Faction ? ( + + ) : page === Page.Milestones ? ( + + ) : page === Page.Tutorial ? ( + + ) : page === Page.DevMenu ? ( + + ) : page === Page.Gang ? ( + + ) : page === Page.Corporation ? ( + + ) : page === Page.Bladeburner ? ( + + ) : page === Page.Resleeves ? ( + + ) : page === Page.Travel ? ( + + ) : page === Page.City ? ( + + ) : page === Page.StockMarket ? ( + + ) : page === Page.Options ? ( + saveObject.saveGame(engine.indexedDb)} + delete={() => saveObject.deleteGame(engine.indexedDb)} + export={() => saveObject.exportGame()} + import={() => saveObject.importGame()} + forceKill={() => { + for (const hostname of Object.keys(AllServers)) { + AllServers[hostname].runningScripts = []; + } + dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page."); + }} + softReset={() => { + dialogBoxCreate("Soft Reset!"); + prestigeAugmentation(); + }} + /> + ) : page === Page.Augmentations ? ( + { + saveObject.exportGame(); + onExport(player); + }} + installAugmentationsFn={installAugmentations} + /> + ) : ( + <> + Cannot load + + )} + + + + ); +} diff --git a/src/ui/Router.ts b/src/ui/Router.ts new file mode 100644 index 000000000..58ad8732b --- /dev/null +++ b/src/ui/Router.ts @@ -0,0 +1,62 @@ +import { Faction } from "../Faction/Faction"; +/** + * The full-screen page the player is currently be on. + * These pages are mutually exclusive. + */ +export enum Page { + ActiveScripts, + Augmentations, + Bladeburner, + Stats, + City, + Corporation, + CreateProgram, + DevMenu, + Faction, + Factions, + Options, + Gang, + Hacknet, + Job, + Milestones, + Resleeves, + CreateScript, + Sleeves, + StockMarket, + Terminal, + Travel, + Tutorial, +} + +/** + * This class keeps track of player navigation/routing within the game. + */ +export interface IRouter { + // toCinematicText(): void; + // toInfiltration(): void; + // toMission(): void; + // toRedPill(): void; + // toworkInProgress(): void; + toActiveScripts(): void; + toAugmentations(): void; + toBladeburner(): void; + toCharacterInfo(): void; + toCorporation(): void; + toCreateProgram(): void; + toDevMenu(): void; + toFaction(faction: Faction): void; // faction name + toFactions(): void; + toGameOptions(): void; + toGang(): void; + toHacknetNodes(): void; + toCity(): void; // travel ? city ? + toJob(): void; + toMilestones(): void; + toResleeves(): void; + toScriptEditor(filename?: string, code?: string): void; + toSleeves(): void; + toStockMarket(): void; + toTerminal(): void; + toTravel(): void; + toTutorial(): void; +} From 1883bea906d54009cdf372afe397ef4fa573eb3d Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Fri, 17 Sep 2021 02:31:19 -0400 Subject: [PATCH 2/4] one big container ready --- src/NetscriptFunctions.js | 26 ++-------- src/Programs/ui/ProgramsRoot.tsx | 14 +++--- src/StockMarket/OrderProcessing.tsx | 3 -- src/StockMarket/StockMarket.tsx | 62 ++++++++--------------- src/StockMarket/ui/StockMarketRoot.tsx | 69 ++++++++++---------------- src/engine.jsx | 4 +- src/ui/GameRoot.tsx | 25 +++++++--- test/StockMarket.test.ts | 1 - 8 files changed, 82 insertions(+), 122 deletions(-) diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index add4e2693..1d3447c88 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -119,13 +119,7 @@ import { SpecialServerIps } from "./Server/SpecialServerIps"; import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; import { buyStock, sellStock, shortStock, sellShort } from "./StockMarket/BuyingAndSelling"; import { influenceStockThroughServerHack, influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing"; -import { - StockMarket, - SymbolToStockMap, - placeOrder, - cancelOrder, - displayStockMarketContent, -} from "./StockMarket/StockMarket"; +import { StockMarket, SymbolToStockMap, placeOrder, cancelOrder } from "./StockMarket/StockMarket"; import { getBuyTransactionCost, getSellTransactionGain } from "./StockMarket/StockMarketHelpers"; import { OrderTypes } from "./StockMarket/data/OrderTypes"; import { PositionTypes } from "./StockMarket/data/PositionTypes"; @@ -1964,18 +1958,14 @@ function NetscriptFunctions(workerScript) { updateDynamicRam("buyStock", getRamCost("buyStock")); checkTixApiAccess("buyStock"); const stock = getStockFromSymbol(symbol, "buyStock"); - const res = buyStock(stock, shares, workerScript, { - rerenderFn: displayStockMarketContent, - }); + const res = buyStock(stock, shares, workerScript, {}); return res ? stock.price : 0; }, sellStock: function (symbol, shares) { updateDynamicRam("sellStock", getRamCost("sellStock")); checkTixApiAccess("sellStock"); const stock = getStockFromSymbol(symbol, "sellStock"); - const res = sellStock(stock, shares, workerScript, { - rerenderFn: displayStockMarketContent, - }); + const res = sellStock(stock, shares, workerScript, {}); return res ? stock.price : 0; }, @@ -1991,9 +1981,7 @@ function NetscriptFunctions(workerScript) { } } const stock = getStockFromSymbol(symbol, "shortStock"); - const res = shortStock(stock, shares, workerScript, { - rerenderFn: displayStockMarketContent, - }); + const res = shortStock(stock, shares, workerScript, {}); return res ? stock.price : 0; }, @@ -2009,9 +1997,7 @@ function NetscriptFunctions(workerScript) { } } const stock = getStockFromSymbol(symbol, "sellShort"); - const res = sellShort(stock, shares, workerScript, { - rerenderFn: displayStockMarketContent, - }); + const res = sellShort(stock, shares, workerScript, {}); return res ? stock.price : 0; }, @@ -2168,7 +2154,6 @@ function NetscriptFunctions(workerScript) { Player.has4SData = true; Player.loseMoney(getStockMarket4SDataCost()); workerScript.log("purchase4SMarketData", "Purchased 4S Market Data"); - displayStockMarketContent(); return true; }, purchase4SMarketDataTixApi: function () { @@ -2188,7 +2173,6 @@ function NetscriptFunctions(workerScript) { Player.has4SDataTixApi = true; Player.loseMoney(getStockMarket4STixApiCost()); workerScript.log("purchase4SMarketDataTixApi", "Purchased 4S Market Data TIX API"); - displayStockMarketContent(); return true; }, getPurchasedServerLimit: function () { diff --git a/src/Programs/ui/ProgramsRoot.tsx b/src/Programs/ui/ProgramsRoot.tsx index 3b82d5387..2d274ac86 100644 --- a/src/Programs/ui/ProgramsRoot.tsx +++ b/src/Programs/ui/ProgramsRoot.tsx @@ -25,9 +25,9 @@ export function ProgramsRoot(props: IProps): React.ReactElement {
    - This page displays any programs that you are able to create. Writing the code for a program takes time, which - can vary based on how complex the program is. If you are working on creating a program you can cancel at any - time. Your progress will be saved and you can continue later. + This page displays any programs that you are able to create. Writing the code for a program takes time, + which can vary based on how complex the program is. If you are working on creating a program you can cancel + at any time. Your progress will be saved and you can continue later. @@ -36,15 +36,15 @@ export function ProgramsRoot(props: IProps): React.ReactElement { if (create === null) return <>; return ( - + - ) + ); })}
    - ) + ); } diff --git a/src/StockMarket/OrderProcessing.tsx b/src/StockMarket/OrderProcessing.tsx index d6a6c8cf4..e22024a40 100644 --- a/src/StockMarket/OrderProcessing.tsx +++ b/src/StockMarket/OrderProcessing.tsx @@ -21,7 +21,6 @@ import { dialogBoxCreate } from "../../utils/DialogBox"; import * as React from "react"; export interface IProcessOrderRefs { - rerenderFn: () => void; stockMarket: IStockMarket; symbolToStockMap: IMap; } @@ -116,7 +115,6 @@ function executeOrder(order: Order, refs: IProcessOrderRefs): void { // When orders are executed, the buying and selling functions shouldn't // emit popup dialog boxes. This options object configures the functions for that const opts = { - rerenderFn: refs.rerenderFn, suppressDialog: true, }; @@ -158,7 +156,6 @@ function executeOrder(order: Order, refs: IProcessOrderRefs): void { {numeralWrapper.formatShares(Math.round(order.shares))} shares) , ); - refs.rerenderFn(); return; } } diff --git a/src/StockMarket/StockMarket.tsx b/src/StockMarket/StockMarket.tsx index dbb62e2e7..d33de36f1 100644 --- a/src/StockMarket/StockMarket.tsx +++ b/src/StockMarket/StockMarket.tsx @@ -26,7 +26,12 @@ import { Reviver } from "../../utils/JSONReviver"; import * as React from "react"; import * as ReactDOM from "react-dom"; -export let StockMarket: IStockMarket | IMap = {}; // Maps full stock name -> Stock object +export let StockMarket: IStockMarket = { + lastUpdate: 0, + Orders: {}, + storedCycles: 0, + ticksUntilCycle: 0, +} as IStockMarket; // Maps full stock name -> Stock object export const SymbolToStockMap: IMap = {}; // Maps symbol -> Stock object export function placeOrder( @@ -70,12 +75,10 @@ export function placeOrder( // Process to see if it should be executed immediately const processOrderRefs = { - rerenderFn: displayStockMarketContent, stockMarket: StockMarket as IStockMarket, symbolToStockMap: SymbolToStockMap, }; processOrders(stock, order.type, order.pos, processOrderRefs); - displayStockMarketContent(); return true; } @@ -100,7 +103,6 @@ export function cancelOrder(params: ICancelOrderParams, workerScript: WorkerScri for (let i = 0; i < stockOrders.length; ++i) { if (order == stockOrders[i]) { stockOrders.splice(i, 1); - displayStockMarketContent(); return true; } } @@ -125,7 +127,6 @@ export function cancelOrder(params: ICancelOrderParams, workerScript: WorkerScri params.pos === order.pos ) { stockOrders.splice(i, 1); - displayStockMarketContent(); if (workerScript) { workerScript.scriptRef.log("Successfully cancelled order: " + orderTxt); } @@ -142,14 +143,25 @@ export function cancelOrder(params: ICancelOrderParams, workerScript: WorkerScri export function loadStockMarket(saveString: string): void { if (saveString === "") { - StockMarket = {}; + StockMarket = { + lastUpdate: 0, + Orders: {}, + storedCycles: 0, + ticksUntilCycle: 0, + } as IStockMarket; } else { + console.log(JSON.parse(saveString, Reviver)); StockMarket = JSON.parse(saveString, Reviver); } } export function deleteStockMarket(): void { - StockMarket = {}; + StockMarket = { + lastUpdate: 0, + Orders: {}, + storedCycles: 0, + ticksUntilCycle: 0, + } as IStockMarket; } export function initStockMarket(): void { @@ -269,8 +281,7 @@ export function processStockPrices(numCycles = 1): void { const c = Math.random(); const processOrderRefs = { - rerenderFn: displayStockMarketContent, - stockMarket: StockMarket as IStockMarket, + stockMarket: StockMarket, symbolToStockMap: SymbolToStockMap, }; if (c < chc) { @@ -301,8 +312,6 @@ export function processStockPrices(numCycles = 1): void { // Shares required for price movement gradually approaches max over time stock.shareTxUntilMovement = Math.min(stock.shareTxUntilMovement + 10, stock.shareTxForMovement); } - - displayStockMarketContent(); } let stockMarketContainer: HTMLElement | null = null; @@ -313,36 +322,9 @@ function setStockMarketContainer(): void { document.addEventListener("DOMContentLoaded", setStockMarketContainer); -function initStockMarketFnForReact(): void { +export function initStockMarketFnForReact(): void { initStockMarket(); initSymbolToStockMap(); } -const eventEmitterForUiReset = new EventEmitter(); - -export function displayStockMarketContent(): void { - if (!routing.isOn(Page.StockMarket)) { - return; - } - - eventEmitterForUiReset.emitEvent(); - - if (stockMarketContainer instanceof HTMLElement) { - const castedStockMarket = StockMarket as IStockMarket; - ReactDOM.render( - , - stockMarketContainer, - ); - } -} +export const eventEmitterForUiReset = new EventEmitter(); diff --git a/src/StockMarket/ui/StockMarketRoot.tsx b/src/StockMarket/ui/StockMarketRoot.tsx index 6effdfa11..e7cfecf73 100644 --- a/src/StockMarket/ui/StockMarketRoot.tsx +++ b/src/StockMarket/ui/StockMarketRoot.tsx @@ -1,7 +1,7 @@ /** * Root React component for the Stock Market UI */ -import * as React from "react"; +import React, { useState, useEffect } from "react"; import { InfoAndPurchases } from "./InfoAndPurchases"; import { StockTickers } from "./StockTickers"; @@ -36,47 +36,32 @@ type IProps = { stockMarket: IStockMarket; }; -type IState = { - rerenderFlag: boolean; -}; - -export class StockMarketRoot extends React.Component { - constructor(props: IProps) { - super(props); - - this.state = { - rerenderFlag: false, - }; - - this.rerender = this.rerender.bind(this); +export function StockMarketRoot(props: IProps) { + const setRerender = useState(false)[1]; + function rerender(): void { + setRerender((old) => !old); } - rerender(): void { - this.setState((prevState) => { - return { - rerenderFlag: !prevState.rerenderFlag, - }; - }); - } - - render(): React.ReactNode { - return ( -
    - - {this.props.p.hasWseAccount && ( - - )} -
    - ); - } + useEffect(() => { + const id = setInterval(rerender, 200); + return () => clearInterval(id); + }, []); + return ( +
    + + {props.p.hasWseAccount && ( + + )} +
    + ); } diff --git a/src/engine.jsx b/src/engine.jsx index ec3856841..d68172824 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -53,7 +53,7 @@ import { initForeignServers, AllServers } from "./Server/AllServers"; import { Settings } from "./Settings/Settings"; import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags"; import { initSpecialServerIps } from "./Server/SpecialServerIps"; -import { initSymbolToStockMap, processStockPrices, displayStockMarketContent } from "./StockMarket/StockMarket"; +import { initSymbolToStockMap, processStockPrices } from "./StockMarket/StockMarket"; import { MilestonesRoot } from "./Milestones/ui/MilestonesRoot"; import { TerminalRoot } from "./Terminal/ui/TerminalRoot"; import { Terminal } from "./Terminal"; @@ -308,7 +308,7 @@ const Engine = { Engine.Display.content.style.display = "block"; routing.navigateTo(Page.StockMarket); MainMenuLinks.StockMarket.classList.add("active"); - displayStockMarketContent(); + //displayStockMarketContent(); }, loadGangContent: function () { diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx index b8c27ca85..5fa9cb350 100644 --- a/src/ui/GameRoot.tsx +++ b/src/ui/GameRoot.tsx @@ -12,6 +12,14 @@ import { Faction } from "../Faction/Faction"; import { prestigeAugmentation } from "../Prestige"; import { dialogBoxCreate } from "../../utils/DialogBox"; import { AllServers } from "../Server/AllServers"; +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"; @@ -41,7 +49,7 @@ import { FactionsRoot } from "../Faction/ui/FactionsRoot"; import { FactionRoot } from "../Faction/ui/FactionRoot"; import { CharacterInfo } from "./CharacterInfo"; import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot"; -import { StockMarketRoot } from "../Locations/ui/StockMarketRoot"; +import { StockMarketRoot } from "../StockMarket/ui/StockMarketRoot"; import { workerScripts } from "../Netscript/WorkerScripts"; import { startHackingMission } from "../Faction/FactionHelpers"; @@ -90,7 +98,10 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme toStockMarket: () => setPage(Page.StockMarket), toTerminal: () => setPage(Page.Terminal), toTutorial: () => setPage(Page.Tutorial), - toJob: () => setPage(Page.Job), + toJob: () => { + player.gotoLocation(player.companyName as LocationName); + setPage(Page.Job); + }, toCity: () => { // TODO This is bad. player.gotoLocation(player.city as unknown as LocationName); @@ -141,8 +152,6 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme ) : page === Page.Travel ? ( - ) : page === Page.City ? ( - ) : page === Page.StockMarket ? ( + ) : page === Page.City ? ( + + ) : page === Page.Job ? ( + ) : page === Page.Options ? ( undefined, stockMarket: StockMarket as IStockMarket, symbolToStockMap: SymbolToStockMap, }; From 89ea9aaff5fcf81040c8b3509a44b5808464624b Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Fri, 17 Sep 2021 02:58:02 -0400 Subject: [PATCH 3/4] oops --- src/InteractiveTutorial.js | 30 ---------------------------- src/Script/Script.ts | 24 ++++++++++------------ src/ScriptEditor/ui/Root.tsx | 13 ++++++------ src/Terminal/ITerminal.ts | 6 +++--- src/Terminal/Terminal.ts | 22 ++++++++++---------- src/Terminal/commands/alias.ts | 4 ++-- src/Terminal/commands/analyze.ts | 4 ++-- src/Terminal/commands/backdoor.ts | 4 ++-- src/Terminal/commands/buy.ts | 4 ++-- src/Terminal/commands/cat.ts | 4 ++-- src/Terminal/commands/cd.ts | 4 ++-- src/Terminal/commands/check.ts | 4 ++-- src/Terminal/commands/connect.ts | 4 ++-- src/Terminal/commands/download.ts | 4 ++-- src/Terminal/commands/expr.ts | 4 ++-- src/Terminal/commands/free.ts | 4 ++-- src/Terminal/commands/hack.ts | 4 ++-- src/Terminal/commands/help.ts | 4 ++-- src/Terminal/commands/home.ts | 4 ++-- src/Terminal/commands/hostname.ts | 4 ++-- src/Terminal/commands/ifconfig.ts | 4 ++-- src/Terminal/commands/kill.ts | 4 ++-- src/Terminal/commands/killall.ts | 4 ++-- src/Terminal/commands/ls.tsx | 4 ++-- src/Terminal/commands/lscpu.ts | 4 ++-- src/Terminal/commands/mem.ts | 4 ++-- src/Terminal/commands/mv.ts | 4 ++-- src/Terminal/commands/nano.ts | 14 ++++++------- src/Terminal/commands/ps.ts | 4 ++-- src/Terminal/commands/rm.ts | 4 ++-- src/Terminal/commands/run.ts | 8 ++++---- src/Terminal/commands/runProgram.ts | 4 ++-- src/Terminal/commands/runScript.ts | 4 ++-- src/Terminal/commands/scan.ts | 4 ++-- src/Terminal/commands/scananalyze.ts | 4 ++-- src/Terminal/commands/scp.ts | 4 ++-- src/Terminal/commands/sudov.ts | 4 ++-- src/Terminal/commands/tail.ts | 4 ++-- src/Terminal/commands/theme.ts | 4 ++-- src/Terminal/commands/top.ts | 4 ++-- src/Terminal/commands/unalias.ts | 4 ++-- src/Terminal/commands/wget.ts | 4 ++-- src/Terminal/ui/TerminalInput.tsx | 8 ++++---- src/Terminal/ui/TerminalRoot.tsx | 8 ++++---- src/engine.jsx | 19 ------------------ src/ui/GameRoot.tsx | 18 ++++++++++++++--- 46 files changed, 134 insertions(+), 176 deletions(-) diff --git a/src/InteractiveTutorial.js b/src/InteractiveTutorial.js index 2ecd78882..9925b6e77 100644 --- a/src/InteractiveTutorial.js +++ b/src/InteractiveTutorial.js @@ -63,8 +63,6 @@ function iTutorialStart() { ITutorial.stepIsDone[i] = false; } - Engine.loadTerminalContent(); - // Don't autosave during this interactive tutorial Engine.Counters.autoSaveCounter = Infinity; ITutorial.currStep = 0; @@ -120,7 +118,6 @@ function iTutorialEvaluateStep() { switch (ITutorial.currStep) { case iTutorialSteps.Start: - Engine.loadTerminalContent(); iTutorialSetText( "Welcome to Bitburner, a cyberpunk-themed incremental RPG! " + "The game takes place in a dark, dystopian future... The year is 2077...

    " + @@ -130,7 +127,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "inline-block"; break; case iTutorialSteps.GoToCharacterPage: - Engine.loadTerminalContent(); iTutorialSetText( "Let's start by heading to the Stats page. Click the Stats tab on " + "the main navigation menu (left-hand side of the screen)", @@ -138,7 +134,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.CharacterPage: - Engine.loadCharacterContent(); iTutorialSetText( "The Stats page shows a lot of important information about your progress, " + "such as your skills, money, and bonuses. ", @@ -146,7 +141,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "inline-block"; break; case iTutorialSteps.CharacterGoToTerminalPage: - Engine.loadCharacterContent(); iTutorialSetText( "Let's head to your computer's terminal by clicking the Terminal tab on the " + "main navigation menu.", @@ -154,7 +148,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.TerminalIntro: - Engine.loadTerminalContent(); iTutorialSetText( "The Terminal is used to interface with your home computer as well as " + "all of the other machines around the world.", @@ -162,7 +155,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "inline-block"; break; case iTutorialSteps.TerminalHelp: - Engine.loadTerminalContent(); iTutorialSetText( "Let's try it out. Start by entering the help command into the Terminal " + "(Don't forget to press Enter after typing the command)", @@ -170,7 +162,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalLs: - Engine.loadTerminalContent(); iTutorialSetText( "The help command displays a list of all available Terminal commands, how to use them, " + "and a description of what they do.

    Let's try another command. Enter the ls command.", @@ -178,7 +169,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalScan: - Engine.loadTerminalContent(); iTutorialSetText( " ls is a basic command that shows files " + "on the computer. Right now, it shows that you have a program called NUKE.exe on your computer. " + @@ -189,7 +179,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalScanAnalyze1: - Engine.loadTerminalContent(); iTutorialSetText( "The scan command shows all available network connections. In other words, " + "it displays a list of all servers that can be connected to from your " + @@ -201,7 +190,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalScanAnalyze2: - Engine.loadTerminalContent(); iTutorialSetText( "You just ran scan-analyze with a depth of one. This command shows more detailed " + "information about each server that you can connect to (servers that are a distance of " + @@ -211,7 +199,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalConnect: - Engine.loadTerminalContent(); iTutorialSetText( "Now you can see information about all servers that are up to two nodes away, as well " + "as figure out how to navigate to those servers through the network. You can only connect to " + @@ -222,7 +209,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalAnalyze: - Engine.loadTerminalContent(); iTutorialSetText( "You are now connected to another machine! What can you do now? You can hack it!

    In the year 2077, currency has " + "become digital and decentralized. People and corporations store their money " + @@ -233,7 +219,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalNuke: - Engine.loadTerminalContent(); iTutorialSetText( "When the analyze command finishes running it will show useful information " + "about hacking the server.

    For this server, the required hacking skill is only 1, " + @@ -247,7 +232,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalManualHack: - Engine.loadTerminalContent(); iTutorialSetText( "You now have root access! You can hack the server using the hack command. " + "Try doing that now.", @@ -255,7 +239,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalHackingMechanics: - Engine.loadTerminalContent(); iTutorialSetText( "You are now attempting to hack the server. Performing a hack takes time and " + "only has a certain percentage chance " + @@ -270,7 +253,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "inline-block"; break; case iTutorialSteps.TerminalCreateScript: - Engine.loadTerminalContent(); iTutorialSetText( "Hacking is the core mechanic of the game and is necessary for progressing. However, " + "you don't want to be hacking manually the entire time. You can automate your hacking " + @@ -282,7 +264,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalTypeScript: - Engine.loadScriptEditorContent("n00dles.script", ""); iTutorialSetText( "This is the script editor. You can use it to program your scripts. Scripts are " + "written in a simplified version of javascript. Copy and paste the following code into the script editor:

    " + @@ -297,7 +278,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js) break; case iTutorialSteps.TerminalFree: - Engine.loadTerminalContent(); iTutorialSetText( "Now we'll run the script. Scripts require a certain amount of RAM to run, and can be " + "run on any machine which you have root access to. Different servers have different " + @@ -307,7 +287,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal commmand break; case iTutorialSteps.TerminalRunScript: - Engine.loadTerminalContent(); iTutorialSetText( "We have 4GB of free RAM on this machine, which is enough to run our " + "script. Let's run our script using run n00dles.script.", @@ -315,7 +294,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal commmand break; case iTutorialSteps.TerminalGoToActiveScriptsPage: - Engine.loadTerminalContent(); iTutorialSetText( "Your script is now running! " + "It will continuously run in the background and will automatically stop if " + @@ -329,7 +307,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.ActiveScriptsPage: - Engine.loadActiveScriptsContent(); iTutorialSetText( "This page displays information about all of your scripts that are " + "running across every server. You can use this to gauge how well " + @@ -338,7 +315,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.ActiveScriptsToTerminal: - Engine.loadTerminalContent(); iTutorialSetText( "One last thing about scripts, each active script contains logs that detail " + "what it's doing. We can check these logs using the tail command. Do that " + @@ -347,7 +323,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; // next step triggered by terminal command break; case iTutorialSteps.TerminalTailScript: - Engine.loadTerminalContent(); iTutorialSetText( "The log for this script won't show much right now (it might show nothing at all) because it " + "just started running...but check back again in a few minutes!

    " + @@ -361,7 +336,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "inline-block"; break; case iTutorialSteps.GoToHacknetNodesPage: - Engine.loadTerminalContent(); iTutorialSetText( "Hacking is not the only way to earn money. One other way to passively " + "earn money is by purchasing and upgrading Hacknet Nodes. Let's go to " + @@ -370,14 +344,12 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.HacknetNodesIntroduction: - Engine.loadHacknetNodesContent(); iTutorialSetText( "here you can purchase new Hacknet Nodes and upgrade your " + "existing ones. Let's purchase a new one now.", ); nextBtn.style.display = "none"; // Next step triggered by purchaseHacknet() (HacknetNode.js) break; case iTutorialSteps.HacknetNodesGoToWorldPage: - Engine.loadHacknetNodesContent(); iTutorialSetText( "You just purchased a Hacknet Node! This Hacknet Node will passively " + "earn you money over time, both online and offline. When you get enough " + @@ -388,7 +360,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.WorldDescription: - Engine.loadLocationContent(); iTutorialSetText( "This page lists all of the different locations you can currently " + "travel to. Each location has something that you can do. " + @@ -399,7 +370,6 @@ function iTutorialEvaluateStep() { nextBtn.style.display = "none"; break; case iTutorialSteps.TutorialPageInfo: - Engine.loadTutorialContent(); iTutorialSetText( "This page contains a lot of different documentation about the game's " + "content and mechanics. I know it's a lot, but I highly suggest you read " + diff --git a/src/Script/Script.ts b/src/Script/Script.ts index 233627a32..88295ed12 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -93,22 +93,18 @@ export class Script { * @param {Script[]} otherScripts - Other scripts on the server. Used to process imports */ saveScript(code: string, serverIp: string, otherScripts: Script[]): void { - if (routing.isOn(Page.ScriptEditor)) { - // Update code and filename - this.code = code.replace(/^\s+|\s+$/g, ""); + // Update code and filename + this.code = code.replace(/^\s+|\s+$/g, ""); - const filenameElem: HTMLInputElement | null = document.getElementById( - "script-editor-filename", - ) as HTMLInputElement; - if (filenameElem == null) { - console.error(`Failed to get Script filename DOM element`); - return; - } - this.filename = filenameElem.value; - this.server = serverIp; - this.updateRamUsage(otherScripts); - this.markUpdated(); + const filenameElem: HTMLInputElement | null = document.getElementById("script-editor-filename") as HTMLInputElement; + if (filenameElem == null) { + console.error(`Failed to get Script filename DOM element`); + return; } + this.filename = filenameElem.value; + this.server = serverIp; + this.updateRamUsage(otherScripts); + this.markUpdated(); } /** diff --git a/src/ScriptEditor/ui/Root.tsx b/src/ScriptEditor/ui/Root.tsx index b1eb01bef..6fafaef07 100644 --- a/src/ScriptEditor/ui/Root.tsx +++ b/src/ScriptEditor/ui/Root.tsx @@ -9,7 +9,7 @@ import { Options } from "./Options"; import { js_beautify as beautifyCode } from "js-beautify"; import { isValidFilePath } from "../../Terminal/DirectoryHelpers"; import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { dialogBoxCreate } from "../../../utils/DialogBox"; import { parseFconfSettings } from "../../Fconf/Fconf"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; @@ -53,7 +53,7 @@ interface IProps { filename: string; code: string; player: IPlayer; - engine: IEngine; + router: IRouter; } /* @@ -103,7 +103,6 @@ export function Root(props: IProps): React.ReactElement { } lastPosition = null; - // TODO(hydroflame): re-enable the tutorial. if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) { //Make sure filename + code properly follow tutorial if (filename !== "n00dles.script") { @@ -121,7 +120,7 @@ export function Root(props: IProps): React.ReactElement { for (let i = 0; i < server.scripts.length; i++) { if (filename == server.scripts[i].filename) { server.scripts[i].saveScript(code, props.player.currentServer, server.scripts); - props.engine.loadTerminalContent(); + props.router.toTerminal(); return iTutorialNextStep(); } } @@ -160,7 +159,7 @@ export function Root(props: IProps): React.ReactElement { for (let i = 0; i < server.scripts.length; i++) { if (filename == server.scripts[i].filename) { server.scripts[i].saveScript(code, props.player.currentServer, server.scripts); - props.engine.loadTerminalContent(); + props.router.toTerminal(); return; } } @@ -173,7 +172,7 @@ export function Root(props: IProps): React.ReactElement { for (let i = 0; i < server.textFiles.length; ++i) { if (server.textFiles[i].fn === filename) { server.textFiles[i].write(code); - props.engine.loadTerminalContent(); + props.router.toTerminal(); return; } } @@ -183,7 +182,7 @@ export function Root(props: IProps): React.ReactElement { dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or " + " or text file (.txt)"); return; } - props.engine.loadTerminalContent(); + props.router.toTerminal(); } function beautify(): void { diff --git a/src/Terminal/ITerminal.ts b/src/Terminal/ITerminal.ts index 278f66fb8..0985d10f3 100644 --- a/src/Terminal/ITerminal.ts +++ b/src/Terminal/ITerminal.ts @@ -1,7 +1,7 @@ import { TextFile } from "../TextFile"; import { Script } from "../Script/Script"; import { IPlayer } from "../PersonObjects/IPlayer"; -import { IEngine } from "../IEngine"; +import { IRouter } from "../ui/Router"; export class Output { text: string; @@ -70,8 +70,8 @@ export interface ITerminal { runContract(player: IPlayer, name: string): void; executeScanAnalyzeCommand(player: IPlayer, depth?: number, all?: boolean): void; connectToServer(player: IPlayer, server: string): void; - executeCommand(engine: IEngine, player: IPlayer, command: string): void; - executeCommands(engine: IEngine, player: IPlayer, commands: string): void; + executeCommand(router: IRouter, player: IPlayer, command: string): void; + executeCommands(router: IRouter, player: IPlayer, commands: string): void; // If there was any changes, will return true, once. pollChanges(): boolean; process(player: IPlayer, cycles: number): void; diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index c9f0e022a..5d50d6894 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -1,5 +1,5 @@ import { ITerminal, Output, Link, TTimer } from "./ITerminal"; -import { IEngine } from "../IEngine"; +import { IRouter } from "../ui/Router"; import { IPlayer } from "../PersonObjects/IPlayer"; import { HacknetServer } from "../Hacknet/HacknetServer"; import { BaseServer } from "../Server/BaseServer"; @@ -468,7 +468,7 @@ export class Terminal implements ITerminal { } } - executeCommands(engine: IEngine, player: IPlayer, commands: string): void { + executeCommands(router: IRouter, player: IPlayer, commands: string): void { // Sanitize input commands = commands.trim(); commands = commands.replace(/\s\s+/g, " "); // Replace all extra whitespace in command with a single space @@ -484,7 +484,7 @@ export class Terminal implements ITerminal { const allCommands = ParseCommands(commands); for (let i = 0; i < allCommands.length; i++) { - this.executeCommand(engine, player, allCommands[i]); + this.executeCommand(router, player, allCommands[i]); } } @@ -499,7 +499,7 @@ export class Terminal implements ITerminal { this.clear(); } - executeCommand(engine: IEngine, player: IPlayer, command: string): void { + executeCommand(router: IRouter, player: IPlayer, command: string): void { if (this.action !== null) { this.error(`Cannot execute command (${command}) while an action is in progress`); return; @@ -532,7 +532,7 @@ export class Terminal implements ITerminal { break; case iTutorialSteps.TerminalLs: if (commandArray.length === 1 && commandArray[0] == "ls") { - ls(this, engine, player, s, commandArray.slice(1)); + ls(this, router, player, s, commandArray.slice(1)); iTutorialNextStep(); } else { this.print("Bad command. Please follow the tutorial"); @@ -540,7 +540,7 @@ export class Terminal implements ITerminal { break; case iTutorialSteps.TerminalScan: if (commandArray.length === 1 && commandArray[0] == "scan") { - scan(this, engine, player, s, commandArray.slice(1)); + scan(this, router, player, s, commandArray.slice(1)); iTutorialNextStep(); } else { this.print("Bad command. Please follow the tutorial"); @@ -609,7 +609,7 @@ export class Terminal implements ITerminal { break; case iTutorialSteps.TerminalCreateScript: if (commandArray.length == 2 && commandArray[0] == "nano" && commandArray[1] == "n00dles.script") { - engine.loadScriptEditorContent("n00dles.script", ""); + router.toScriptEditor("n00dles.script", ""); iTutorialNextStep(); } else { this.print("Bad command. Please follow the tutorial"); @@ -617,7 +617,7 @@ export class Terminal implements ITerminal { break; case iTutorialSteps.TerminalFree: if (commandArray.length == 1 && commandArray[0] == "free") { - free(this, engine, player, s, commandArray.slice(1)); + free(this, router, player, s, commandArray.slice(1)); iTutorialNextStep(); } else { this.print("Bad command. Please follow the tutorial"); @@ -625,7 +625,7 @@ export class Terminal implements ITerminal { break; case iTutorialSteps.TerminalRunScript: if (commandArray.length == 2 && commandArray[0] == "run" && commandArray[1] == "n00dles.script") { - run(this, engine, player, s, commandArray.slice(1)); + run(this, router, player, s, commandArray.slice(1)); iTutorialNextStep(); } else { this.print("Bad command. Please follow the tutorial"); @@ -662,7 +662,7 @@ export class Terminal implements ITerminal { const commands: { [key: string]: ( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], @@ -713,7 +713,7 @@ export class Terminal implements ITerminal { return; } - f(this, engine, player, s, commandArray.slice(1)); + f(this, router, player, s, commandArray.slice(1)); } getProgressText(): string { diff --git a/src/Terminal/commands/alias.ts b/src/Terminal/commands/alias.ts index 9fbf59c3e..da06efaab 100644 --- a/src/Terminal/commands/alias.ts +++ b/src/Terminal/commands/alias.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { parseAliasDeclaration, printAliases } from "../../Alias"; export function alias( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/analyze.ts b/src/Terminal/commands/analyze.ts index e3d3b3c88..bd1004a40 100644 --- a/src/Terminal/commands/analyze.ts +++ b/src/Terminal/commands/analyze.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function analyze( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/backdoor.ts b/src/Terminal/commands/backdoor.ts index ea33e2438..72247327f 100644 --- a/src/Terminal/commands/backdoor.ts +++ b/src/Terminal/commands/backdoor.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Server } from "../../Server/Server"; @@ -7,7 +7,7 @@ import { HacknetServer } from "../../Hacknet/HacknetServer"; export function backdoor( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/buy.ts b/src/Terminal/commands/buy.ts index 8f2f3dab4..d81195abe 100644 --- a/src/Terminal/commands/buy.ts +++ b/src/Terminal/commands/buy.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { listAllDarkwebItems, buyDarkwebItem } from "../../DarkWeb/DarkWeb"; @@ -7,7 +7,7 @@ import { SpecialServerIps } from "../../Server/SpecialServerIps"; export function buy( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/cat.ts b/src/Terminal/commands/cat.ts index 98bfa7e8f..c10a025fe 100644 --- a/src/Terminal/commands/cat.ts +++ b/src/Terminal/commands/cat.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { showMessage } from "../../Message/MessageHelpers"; @@ -8,7 +8,7 @@ import { showLiterature } from "../../Literature/LiteratureHelpers"; export function cat( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/cd.ts b/src/Terminal/commands/cd.ts index fe9b66e50..ab5576d7a 100644 --- a/src/Terminal/commands/cd.ts +++ b/src/Terminal/commands/cd.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; @@ -7,7 +7,7 @@ import { evaluateDirectoryPath, removeTrailingSlash } from "../DirectoryHelpers" export function cd( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/check.ts b/src/Terminal/commands/check.ts index c93f8d973..ad4d155a9 100644 --- a/src/Terminal/commands/check.ts +++ b/src/Terminal/commands/check.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { findRunningScript } from "../../Script/ScriptHelpers"; @@ -7,7 +7,7 @@ import { isScriptFilename } from "../../Script/ScriptHelpersTS"; export function check( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/connect.ts b/src/Terminal/commands/connect.ts index 5f868dc8c..f66d6f765 100644 --- a/src/Terminal/commands/connect.ts +++ b/src/Terminal/commands/connect.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { getServerOnNetwork } from "../../Server/ServerHelpers"; export function connect( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/download.ts b/src/Terminal/commands/download.ts index eb58d9e57..cad18d762 100644 --- a/src/Terminal/commands/download.ts +++ b/src/Terminal/commands/download.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; @@ -8,7 +8,7 @@ import JSZip from "jszip"; export function download( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/expr.ts b/src/Terminal/commands/expr.ts index 8a8bab5b4..060971e29 100644 --- a/src/Terminal/commands/expr.ts +++ b/src/Terminal/commands/expr.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function expr( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/free.ts b/src/Terminal/commands/free.ts index b6372bbfa..68a668efc 100644 --- a/src/Terminal/commands/free.ts +++ b/src/Terminal/commands/free.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { numeralWrapper } from "../../ui/numeralFormat"; export function free( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/hack.ts b/src/Terminal/commands/hack.ts index a2f587b4b..4fb0a6c6f 100644 --- a/src/Terminal/commands/hack.ts +++ b/src/Terminal/commands/hack.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Server } from "../../Server/Server"; export function hack( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/help.ts b/src/Terminal/commands/help.ts index 33b11a204..af818ee38 100644 --- a/src/Terminal/commands/help.ts +++ b/src/Terminal/commands/help.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { TerminalHelpText, HelpTexts } from "../HelpText"; export function help( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/home.ts b/src/Terminal/commands/home.ts index 12f120d60..09bd81765 100644 --- a/src/Terminal/commands/home.ts +++ b/src/Terminal/commands/home.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function home( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/hostname.ts b/src/Terminal/commands/hostname.ts index d1dcae62a..13340e9a7 100644 --- a/src/Terminal/commands/hostname.ts +++ b/src/Terminal/commands/hostname.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function hostname( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/ifconfig.ts b/src/Terminal/commands/ifconfig.ts index 68cf00852..d5bfa3ac0 100644 --- a/src/Terminal/commands/ifconfig.ts +++ b/src/Terminal/commands/ifconfig.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function ifconfig( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/kill.ts b/src/Terminal/commands/kill.ts index 61ebcbf1c..08ba7efd2 100644 --- a/src/Terminal/commands/kill.ts +++ b/src/Terminal/commands/kill.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { killWorkerScript } from "../../Netscript/killWorkerScript"; export function kill( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/killall.ts b/src/Terminal/commands/killall.ts index a5a237617..72326c2bb 100644 --- a/src/Terminal/commands/killall.ts +++ b/src/Terminal/commands/killall.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { killWorkerScript } from "../../Netscript/killWorkerScript"; import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter"; -export function killall(terminal: ITerminal, engine: IEngine, player: IPlayer, server: BaseServer): void { +export function killall(terminal: ITerminal, router: IRouter, player: IPlayer, server: BaseServer): void { for (let i = server.runningScripts.length - 1; i >= 0; --i) { killWorkerScript(server.runningScripts[i], server.ip, false); } diff --git a/src/Terminal/commands/ls.tsx b/src/Terminal/commands/ls.tsx index 8d6c346c9..24d3a1420 100644 --- a/src/Terminal/commands/ls.tsx +++ b/src/Terminal/commands/ls.tsx @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Message } from "../../Message/Message"; @@ -7,7 +7,7 @@ import { getFirstParentDirectory, isValidDirectoryPath, evaluateDirectoryPath } export function ls( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/lscpu.ts b/src/Terminal/commands/lscpu.ts index c26d17427..8eba1239e 100644 --- a/src/Terminal/commands/lscpu.ts +++ b/src/Terminal/commands/lscpu.ts @@ -1,7 +1,7 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; -export function lscpu(terminal: ITerminal, engine: IEngine, player: IPlayer): void { +export function lscpu(terminal: ITerminal, router: IRouter, player: IPlayer): void { terminal.print(player.getCurrentServer().cpuCores + " Core(s)"); } diff --git a/src/Terminal/commands/mem.ts b/src/Terminal/commands/mem.ts index 0d0fd12a6..a08b11c75 100644 --- a/src/Terminal/commands/mem.ts +++ b/src/Terminal/commands/mem.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { numeralWrapper } from "../../ui/numeralFormat"; export function mem( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/mv.ts b/src/Terminal/commands/mv.ts index 94014932a..f62f5579f 100644 --- a/src/Terminal/commands/mv.ts +++ b/src/Terminal/commands/mv.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; @@ -8,7 +8,7 @@ import { Script } from "../../Script/Script"; export function mv( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/nano.ts b/src/Terminal/commands/nano.ts index 0195d85fd..ad93cf2f9 100644 --- a/src/Terminal/commands/nano.ts +++ b/src/Terminal/commands/nano.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; @@ -7,7 +7,7 @@ import { createFconf } from "../../Fconf/Fconf"; export function nano( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], @@ -21,7 +21,7 @@ export function nano( const filename = args[0] + ""; if (filename === ".fconf") { const text = createFconf(); - engine.loadScriptEditorContent(filename, text); + router.toScriptEditor(filename, text); return; } else if (isScriptFilename(filename)) { const filepath = terminal.getFilepath(filename); @@ -33,17 +33,17 @@ export function nano( }`; } - engine.loadScriptEditorContent(filepath, code); + router.toScriptEditor(filepath, code); } else { - engine.loadScriptEditorContent(filepath, script.code); + router.toScriptEditor(filepath, script.code); } } else if (filename.endsWith(".txt")) { const filepath = terminal.getFilepath(filename); const txt = terminal.getTextFile(player, filename); if (txt == null) { - engine.loadScriptEditorContent(filepath); + router.toScriptEditor(filepath); } else { - engine.loadScriptEditorContent(filepath, txt.text); + router.toScriptEditor(filepath, txt.text); } } else { terminal.error( diff --git a/src/Terminal/commands/ps.ts b/src/Terminal/commands/ps.ts index 23bf2185d..c18254bbb 100644 --- a/src/Terminal/commands/ps.ts +++ b/src/Terminal/commands/ps.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function ps( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/rm.ts b/src/Terminal/commands/rm.ts index 0244f2d98..0e91bc496 100644 --- a/src/Terminal/commands/rm.ts +++ b/src/Terminal/commands/rm.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { IReturnStatus } from "../../types"; export function rm( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/run.ts b/src/Terminal/commands/run.ts index 1335cc40f..cacc9b864 100644 --- a/src/Terminal/commands/run.ts +++ b/src/Terminal/commands/run.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; @@ -8,7 +8,7 @@ import { runProgram } from "./runProgram"; export function run( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], @@ -30,11 +30,11 @@ export function run( // Check if its a script or just a program/executable if (isScriptFilename(executableName)) { - runScript(terminal, engine, player, server, args); + runScript(terminal, router, player, server, args); } else if (executableName.endsWith(".cct")) { terminal.runContract(player, executableName); } else { - runProgram(terminal, engine, player, server, args); + runProgram(terminal, router, player, server, args); } } } diff --git a/src/Terminal/commands/runProgram.ts b/src/Terminal/commands/runProgram.ts index 65ac4979d..868b95813 100644 --- a/src/Terminal/commands/runProgram.ts +++ b/src/Terminal/commands/runProgram.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Programs } from "../../Programs/Programs"; export function runProgram( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/runScript.ts b/src/Terminal/commands/runScript.ts index b905c8b45..10b5896ed 100644 --- a/src/Terminal/commands/runScript.ts +++ b/src/Terminal/commands/runScript.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { logBoxCreate } from "../../../utils/LogBox"; @@ -10,7 +10,7 @@ import * as libarg from "arg"; export function runScript( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, commandArgs: (string | number)[], diff --git a/src/Terminal/commands/scan.ts b/src/Terminal/commands/scan.ts index 8fd5246fd..d14d0dbdc 100644 --- a/src/Terminal/commands/scan.ts +++ b/src/Terminal/commands/scan.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { getServerOnNetwork } from "../../Server/ServerHelpers"; export function scan( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/scananalyze.ts b/src/Terminal/commands/scananalyze.ts index ec5bcf924..3f997a4ea 100644 --- a/src/Terminal/commands/scananalyze.ts +++ b/src/Terminal/commands/scananalyze.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Programs } from "../../Programs/Programs"; export function scananalyze( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/scp.ts b/src/Terminal/commands/scp.ts index ec2052153..78d5a559b 100644 --- a/src/Terminal/commands/scp.ts +++ b/src/Terminal/commands/scp.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { Message } from "../../Message/Message"; @@ -8,7 +8,7 @@ import { isScriptFilename } from "../../Script/ScriptHelpersTS"; export function scp( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/sudov.ts b/src/Terminal/commands/sudov.ts index 609fb1c2c..4457d1da0 100644 --- a/src/Terminal/commands/sudov.ts +++ b/src/Terminal/commands/sudov.ts @@ -1,11 +1,11 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; export function sudov( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/tail.ts b/src/Terminal/commands/tail.ts index 5d9de3aca..ef17463cf 100644 --- a/src/Terminal/commands/tail.ts +++ b/src/Terminal/commands/tail.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { logBoxCreate } from "../../../utils/LogBox"; @@ -9,7 +9,7 @@ import { isScriptFilename } from "../../Script/ScriptHelpersTS"; export function tail( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, commandArray: (string | number)[], diff --git a/src/Terminal/commands/theme.ts b/src/Terminal/commands/theme.ts index e8e779db2..62e468132 100644 --- a/src/Terminal/commands/theme.ts +++ b/src/Terminal/commands/theme.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { FconfSettings } from "../../Fconf/FconfSettings"; export function theme( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/top.ts b/src/Terminal/commands/top.ts index c542d81e9..e3cf72f97 100644 --- a/src/Terminal/commands/top.ts +++ b/src/Terminal/commands/top.ts @@ -1,5 +1,5 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { getRamUsageFromRunningScript } from "../../Script/RunningScriptHelpers"; @@ -7,7 +7,7 @@ import { numeralWrapper } from "../../ui/numeralFormat"; export function top( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/unalias.ts b/src/Terminal/commands/unalias.ts index 392aad99b..10c274bfb 100644 --- a/src/Terminal/commands/unalias.ts +++ b/src/Terminal/commands/unalias.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { removeAlias } from "../../Alias"; export function unalias( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/commands/wget.ts b/src/Terminal/commands/wget.ts index eaf08b3eb..066416bee 100644 --- a/src/Terminal/commands/wget.ts +++ b/src/Terminal/commands/wget.ts @@ -1,12 +1,12 @@ import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; import { isScriptFilename } from "../../Script/ScriptHelpersTS"; export function wget( terminal: ITerminal, - engine: IEngine, + router: IRouter, player: IPlayer, server: BaseServer, args: (string | number)[], diff --git a/src/Terminal/ui/TerminalInput.tsx b/src/Terminal/ui/TerminalInput.tsx index 3934a08d9..e94f4ea4a 100644 --- a/src/Terminal/ui/TerminalInput.tsx +++ b/src/Terminal/ui/TerminalInput.tsx @@ -6,7 +6,7 @@ import createStyles from "@mui/styles/createStyles"; import TextField from "@mui/material/TextField"; import { KEY } from "../../../utils/helpers/keyCodes"; import { ITerminal } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { determineAllPossibilitiesForTabCompletion } from "../determineAllPossibilitiesForTabCompletion"; import { tabCompletion } from "../tabCompletion"; @@ -37,11 +37,11 @@ const useStyles = makeStyles((theme: Theme) => interface IProps { terminal: ITerminal; - engine: IEngine; + router: IRouter; player: IPlayer; } -export function TerminalInput({ terminal, engine, player }: IProps): React.ReactElement { +export function TerminalInput({ terminal, router, player }: IProps): React.ReactElement { const terminalInput = useRef(null); const [value, setValue] = useState(""); @@ -157,7 +157,7 @@ export function TerminalInput({ terminal, engine, player }: IProps): React.React if (event.keyCode === KEY.ENTER && value !== "") { event.preventDefault(); terminal.print(`[${player.getCurrentServer().hostname} ~${terminal.cwd()}]> ${value}`); - terminal.executeCommands(engine, player, value); + terminal.executeCommands(router, player, value); setValue(""); return; } diff --git a/src/Terminal/ui/TerminalRoot.tsx b/src/Terminal/ui/TerminalRoot.tsx index cc4de1e29..dca127138 100644 --- a/src/Terminal/ui/TerminalRoot.tsx +++ b/src/Terminal/ui/TerminalRoot.tsx @@ -8,7 +8,7 @@ import makeStyles from "@mui/styles/makeStyles"; import createStyles from "@mui/styles/createStyles"; import Box from "@mui/material/Box"; import { ITerminal, Output, Link } from "../ITerminal"; -import { IEngine } from "../../IEngine"; +import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { TerminalInput } from "./TerminalInput"; @@ -42,11 +42,11 @@ const useStyles = makeStyles((theme: Theme) => interface IProps { terminal: ITerminal; - engine: IEngine; + router: IRouter; player: IPlayer; } -export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactElement { +export function TerminalRoot({ terminal, router, player }: IProps): React.ReactElement { const scrollHook = useRef(null); const setRerender = useState(false)[1]; function rerender(): void { @@ -106,7 +106,7 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE
    - + ); diff --git a/src/engine.jsx b/src/engine.jsx index d68172824..8d623c752 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -207,25 +207,6 @@ const Engine = { ReactDOM.render(, Engine.Display.content); }, - loadTutorialContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Tutorial); - MainMenuLinks.Tutorial.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadDevMenuContent: function () { - Engine.hideAllContent(); - if (process.env.NODE_ENV !== "development") { - throw new Error("Cannot create Dev Menu because you are not in a dev build"); - } - Engine.Display.content.style.display = "block"; - ReactDOM.render(, Engine.Display.content); - routing.navigateTo(Page.DevMenu); - MainMenuLinks.DevMenu.classList.add("active"); - }, - loadLocationContent: function (initiallyInCity = true) { Engine.hideAllContent(); Engine.Display.content.style.display = "block"; diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx index 5fa9cb350..906535fda 100644 --- a/src/ui/GameRoot.tsx +++ b/src/ui/GameRoot.tsx @@ -69,6 +69,9 @@ const useStyles = makeStyles((theme: Theme) => }), ); +let filename = ""; +let code = ""; + export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement { const contentRef = useRef(null); const [faction, setFaction] = useState(null); @@ -93,7 +96,11 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme toHacknetNodes: () => setPage(Page.Hacknet), toMilestones: () => setPage(Page.Milestones), toResleeves: () => setPage(Page.Resleeves), - toScriptEditor: () => setPage(Page.CreateScript), + toScriptEditor: (fn: string, c: string) => { + filename = fn; + code = c; + setPage(Page.CreateScript); + }, toSleeves: () => setPage(Page.Sleeves), toStockMarket: () => setPage(Page.StockMarket), toTerminal: () => setPage(Page.Terminal), @@ -113,19 +120,24 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme }, }; + useEffect(() => { + filename = ""; + code = ""; + }); + return ( <> {page === Page.Terminal ? ( - + ) : page === Page.Sleeves ? ( ) : page === Page.Stats ? ( ) : page === Page.CreateScript ? ( - + ) : page === Page.ActiveScripts ? ( ) : page === Page.Hacknet ? ( From 45f2f85a30d75c8bbbb449a73a5ac5fb8dc2f217 Mon Sep 17 00:00:00 2001 From: Olivier Gagnon Date: Fri, 17 Sep 2021 19:43:08 -0400 Subject: [PATCH 4/4] big work --- .../ui/{Root.tsx => AugmentationsRoot.tsx} | 0 src/BitNode/ui/BitFlumePopup.tsx | 5 +- src/BitNode/ui/BitverseRoot.tsx | 28 +- src/BitNode/ui/PortalPopup.tsx | 6 +- src/Bladeburner/Bladeburner.ts | 17 +- src/Bladeburner/IBladeburner.ts | 7 +- src/Bladeburner/ui/BladeburnerCinematic.tsx | 42 ++ .../ui/{Root.tsx => BladeburnerRoot.tsx} | 15 +- src/Bladeburner/ui/Stats.tsx | 9 +- src/DevMenu.tsx | 4 +- src/DevMenu/ui/General.tsx | 11 +- src/DevMenu/ui/TimeSkip.tsx | 2 +- src/Faction/FactionHelpers.d.ts | 1 - src/Faction/FactionHelpers.jsx | 33 +- src/Faction/ui/AugmentationsPage.tsx | 181 +++--- src/Faction/ui/CreateGangPopup.tsx | 96 ++-- src/Faction/ui/FactionRoot.tsx | 138 ++--- src/Faction/ui/PurchaseAugmentationPopup.tsx | 2 + src/Faction/ui/PurchaseableAugmentation.tsx | 232 ++++---- src/Gang/ui/{Root.tsx => GangRoot.tsx} | 20 +- src/Infiltration/Helper.tsx | 51 -- src/Infiltration/ui/Game.tsx | 19 +- src/Infiltration/ui/InfiltrationRoot.tsx | 53 ++ src/Infiltration/ui/Intro.tsx | 4 - src/Infiltration/ui/Root.tsx | 49 -- src/Infiltration/ui/Victory.tsx | 18 +- src/Locations/ui/CompanyLocation.tsx | 533 ++++++++---------- src/Locations/ui/GenericLocation.tsx | 13 +- src/Locations/ui/SlumsLocation.tsx | 296 +++++----- src/Locations/ui/UniversityLocation.tsx | 214 ++++--- src/Missions.jsx | 16 +- src/PersonObjects/IPlayer.ts | 35 +- .../Player/PlayerObjectGeneralMethods.jsx | 381 +------------ src/Prestige.js | 68 --- src/Programs/Program.ts | 5 +- src/Programs/data/ProgramsMetadata.ts | 28 +- src/Programs/ui/ProgramsRoot.tsx | 19 +- src/RedPill.d.ts | 6 +- src/RedPill.jsx | 27 +- src/Script/Script.ts | 1 - src/Sidebar/ui/SidebarRoot.tsx | 8 +- src/StockMarket/StockMarket.tsx | 16 - src/StockMarket/ui/StockMarketRoot.tsx | 2 +- src/Terminal/ITerminal.ts | 8 +- src/Terminal/Terminal.ts | 19 +- src/Terminal/commands/runProgram.ts | 1 + src/Terminal/ui/TerminalInput.tsx | 10 +- src/engine.jsx | 485 +--------------- src/index.html | 20 - .../{Root.tsx => ActiveScriptsRoot.tsx} | 0 src/ui/Context.ts | 19 + src/ui/GameRoot.tsx | 351 ++++++++---- src/ui/React/CharacterOverview.tsx | 42 +- src/ui/React/CinematicText.tsx | 16 +- src/ui/React/GameOptionsRoot.tsx | 5 +- src/ui/React/Theme.tsx | 2 +- src/ui/Router.ts | 20 +- src/ui/WorkInProgressRoot.tsx | 336 +++++++++++ 58 files changed, 1738 insertions(+), 2307 deletions(-) rename src/Augmentation/ui/{Root.tsx => AugmentationsRoot.tsx} (100%) create mode 100644 src/Bladeburner/ui/BladeburnerCinematic.tsx rename src/Bladeburner/ui/{Root.tsx => BladeburnerRoot.tsx} (65%) rename src/Gang/ui/{Root.tsx => GangRoot.tsx} (69%) delete mode 100644 src/Infiltration/Helper.tsx create mode 100644 src/Infiltration/ui/InfiltrationRoot.tsx delete mode 100644 src/Infiltration/ui/Root.tsx rename src/ui/ActiveScripts/{Root.tsx => ActiveScriptsRoot.tsx} (100%) create mode 100644 src/ui/Context.ts create mode 100644 src/ui/WorkInProgressRoot.tsx diff --git a/src/Augmentation/ui/Root.tsx b/src/Augmentation/ui/AugmentationsRoot.tsx similarity index 100% rename from src/Augmentation/ui/Root.tsx rename to src/Augmentation/ui/AugmentationsRoot.tsx diff --git a/src/BitNode/ui/BitFlumePopup.tsx b/src/BitNode/ui/BitFlumePopup.tsx index c8b9ffc4c..a915f356b 100644 --- a/src/BitNode/ui/BitFlumePopup.tsx +++ b/src/BitNode/ui/BitFlumePopup.tsx @@ -1,16 +1,17 @@ import React from "react"; -import { hackWorldDaemon } from "../../RedPill"; import { IPlayer } from "../../PersonObjects/IPlayer"; +import { IRouter } from "../../ui/Router"; import { removePopup } from "../../ui/React/createPopup"; interface IProps { player: IPlayer; + router: IRouter; popupId: string; } export function BitFlumePopup(props: IProps): React.ReactElement { function flume(): void { - hackWorldDaemon(props.player.bitNodeN, true, false); + props.router.toBitVerse(true, false); removePopup(props.popupId); } return ( diff --git a/src/BitNode/ui/BitverseRoot.tsx b/src/BitNode/ui/BitverseRoot.tsx index 1e6c2c1da..ecdd16fb7 100644 --- a/src/BitNode/ui/BitverseRoot.tsx +++ b/src/BitNode/ui/BitverseRoot.tsx @@ -1,18 +1,22 @@ import React, { useState } from "react"; import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; +import { IRouter } from "../../ui/Router"; import { BitNodes } from "../BitNode"; +import { enterBitNode } from "../../RedPill"; import { PortalPopup } from "./PortalPopup"; import { createPopup } from "../../ui/React/createPopup"; import { CinematicText } from "../../ui/React/CinematicText"; +import { use } from "../../ui/Context"; interface IPortalProps { n: number; level: number; destroyedBitNode: number; flume: boolean; - enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void; + enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void; } function BitNodePortal(props: IPortalProps): React.ReactElement { + const router = use.Router(); const bitNode = BitNodes[`BitNode${props.n}`]; if (bitNode == null) { return <>O; @@ -32,6 +36,7 @@ function BitNodePortal(props: IPortalProps): React.ReactElement { n: props.n, level: props.level, enter: props.enter, + router: router, destroyedBitNode: props.destroyedBitNode, flume: props.flume, popupId: popupId, @@ -57,18 +62,20 @@ function BitNodePortal(props: IPortalProps): React.ReactElement { interface IProps { flume: boolean; - destroyedBitNodeNum: number; quick: boolean; - enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void; + enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void; } export function BitverseRoot(props: IProps): React.ReactElement { + const player = use.Player(); + const enter = enterBitNode; + const destroyed = player.bitNodeN; const [destroySequence, setDestroySequence] = useState(true && !props.quick); // Update NextSourceFileFlags const nextSourceFileFlags = SourceFileFlags.slice(); if (!props.flume) { - if (nextSourceFileFlags[props.destroyedBitNodeNum] < 3) ++nextSourceFileFlags[props.destroyedBitNodeNum]; + if (nextSourceFileFlags[destroyed] < 3) ++nextSourceFileFlags[destroyed]; } if (destroySequence) { @@ -84,7 +91,7 @@ export function BitverseRoot(props: IProps): React.ReactElement { "0020 7124696B 0000FF69 74652E6F FFFF1111", "----------------------------------------", "Failsafe initiated...", - `Restarting BitNode-${props.destroyedBitNodeNum}...`, + `Restarting BitNode-${destroyed}...`, "...........", "...........", "[ERROR] FAILED TO AUTOMATICALLY REBOOT BITNODE", @@ -96,6 +103,7 @@ export function BitverseRoot(props: IProps): React.ReactElement { "..............................................", ]} onDone={() => setDestroySequence(false)} + auto={true} /> ); } @@ -116,16 +124,16 @@ export function BitverseRoot(props: IProps): React.ReactElement {
     \| O   |  |_/    |\|   \ O    \__|    \_|  |   O |/ 
      | |   |_/       | |    \|    /  |       \_|   | |  
       \|   /          \|     |   /  /          \   |/   
    -
        |              |     |  /  |              |    
    -
       |  |            |     |     |            |  |   
    +
        |              |     |  /  |              |    
    +
       |  |            |     |     |            |  |   
      | |  |            /    / \    \            |  | |  
    -
       \|  |           /   /   \   \           |  |/   
    +
       \|  |           /   /   \   \           |  |/   
        \  |          /  / |     | \  \          |  /    
    -
         \ \JUMP 3R |  |  |     |  |  | R3 PMUJ/ /     
    +
         \ \JUMP 3R |  |  |     |  |  | R3 PMUJ/ /     
          \||    |   |  |  |     |  |  |   |    ||/      
           \|     \_ |  |  |     |  |  | _/     |/       
            \       \| /    \   /    \ |/       /        
    -
                    |/     | |     \|                
    +
                    |/     | |     \|                
             |       |    |  | |  |    |       |         
              \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/          

    diff --git a/src/BitNode/ui/PortalPopup.tsx b/src/BitNode/ui/PortalPopup.tsx index 600d632ff..dbcbfb3cf 100644 --- a/src/BitNode/ui/PortalPopup.tsx +++ b/src/BitNode/ui/PortalPopup.tsx @@ -1,13 +1,15 @@ import React from "react"; import { BitNodes } from "../BitNode"; +import { IRouter } from "../../ui/Router"; import { removePopup } from "../../ui/React/createPopup"; interface IProps { n: number; level: number; destroyedBitNode: number; flume: boolean; - enter: (flume: boolean, destroyedBitNode: number, newBitNode: number) => void; + router: IRouter; + enter: (router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number) => void; popupId: string; } @@ -33,7 +35,7 @@ export function PortalPopup(props: IProps): React.ReactElement { diff --git a/src/Faction/FactionHelpers.d.ts b/src/Faction/FactionHelpers.d.ts index a4a952b31..8d719b231 100644 --- a/src/Faction/FactionHelpers.d.ts +++ b/src/Faction/FactionHelpers.d.ts @@ -4,6 +4,5 @@ import { Faction } from "../Faction/Faction"; export declare function getNextNeurofluxLevel(): number; export declare function hasAugmentationPrereqs(aug: Augmentation): boolean; export declare function purchaseAugmentation(aug: Augmentation, fac: Faction, sing?: boolean): void; -export declare function displayFactionContent(factionName: string, initiallyOnAugmentationsPage: boolean = false); export declare function joinFaction(faction: Faction): void; export declare function startHackingMission(faction: Faction): void; diff --git a/src/Faction/FactionHelpers.jsx b/src/Faction/FactionHelpers.jsx index 1e5f0e166..5459bff8c 100644 --- a/src/Faction/FactionHelpers.jsx +++ b/src/Faction/FactionHelpers.jsx @@ -1,14 +1,9 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -import { FactionRoot } from "./ui/FactionRoot"; - import { Augmentations } from "../Augmentation/Augmentations"; import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { CONSTANTS } from "../Constants"; -import { Engine } from "../engine"; + import { Faction } from "./Faction"; import { Factions } from "./Factions"; import { HackingMission, setInMission } from "../Missions"; @@ -65,29 +60,6 @@ export function startHackingMission(faction) { mission.init(); } -//Displays the HTML content for a specific faction -export function displayFactionContent(factionName, initiallyOnAugmentationsPage = false) { - const faction = Factions[factionName]; - if (faction == null) { - throw new Error(`Invalid factionName passed into displayFactionContent(): ${factionName}`); - } - - if (!faction.isMember) { - throw new Error(`Not a member of this faction. Cannot display faction information`); - } - - ReactDOM.render( - , - Engine.Display.content, - ); -} - //Returns a boolean indicating whether the player has the prerequisites for the //specified Augmentation export function hasAugmentationPrereqs(aug) { @@ -187,9 +159,6 @@ export function purchaseAugmentation(aug, fac, sing = false) { ); } } - - // Force a rerender of the Augmentations page - displayFactionContent(fac.name, true); } else { dialogBoxCreate( "Hmm, something went wrong when trying to purchase an Augmentation. " + diff --git a/src/Faction/ui/AugmentationsPage.tsx b/src/Faction/ui/AugmentationsPage.tsx index 6a406d51f..063ebfacb 100644 --- a/src/Faction/ui/AugmentationsPage.tsx +++ b/src/Faction/ui/AugmentationsPage.tsx @@ -1,52 +1,37 @@ /** * Root React Component for displaying a faction's "Purchase Augmentations" page */ -import * as React from "react"; +import React, { useState } from "react"; import { PurchaseableAugmentation } from "./PurchaseableAugmentation"; import { Augmentations } from "../../Augmentation/Augmentations"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { Faction } from "../../Faction/Faction"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums"; import { Settings } from "../../Settings/Settings"; import { StdButton } from "../../ui/React/StdButton"; +import { use } from "../../ui/Context"; type IProps = { faction: Faction; - p: IPlayer; routeToMainPage: () => void; }; -type IState = { - rerenderFlag: boolean; - sortOrder: PurchaseAugmentationsOrderSetting; -}; - -const infoStyleMarkup = { - width: "70%", -}; - -export class AugmentationsPage extends React.Component { +export function AugmentationsPage(props: IProps): React.ReactElement { + const player = use.Player(); // Flag for whether the player has a gang with this faction - isPlayersGang: boolean; - constructor(props: IProps) { - super(props); + const isPlayersGang = player.inGang() && player.getGangName() === props.faction.name; - this.isPlayersGang = props.p.inGang() && props.p.getGangName() === props.faction.name; + const setRerender = useState(false)[1]; - this.state = { - rerenderFlag: false, - sortOrder: PurchaseAugmentationsOrderSetting.Default, - }; - - this.rerender = this.rerender.bind(this); + function rerender(): void { + setRerender((old) => !old); } - getAugs(): string[] { - if (this.isPlayersGang) { + function getAugs(): string[] { + if (isPlayersGang) { const augs: string[] = []; for (const augName in Augmentations) { const aug = Augmentations[augName]; @@ -57,25 +42,25 @@ export class AugmentationsPage extends React.Component { return augs; } else { - return this.props.faction.augmentations.slice(); + return props.faction.augmentations.slice(); } } - getAugsSorted(): string[] { + function getAugsSorted(): string[] { switch (Settings.PurchaseAugmentationsOrder) { case PurchaseAugmentationsOrderSetting.Cost: { - return this.getAugsSortedByCost(); + return getAugsSortedByCost(); } case PurchaseAugmentationsOrderSetting.Reputation: { - return this.getAugsSortedByReputation(); + return getAugsSortedByReputation(); } default: - return this.getAugsSortedByDefault(); + return getAugsSortedByDefault(); } } - getAugsSortedByCost(): string[] { - const augs = this.getAugs(); + function getAugsSortedByCost(): string[] { + const augs = getAugs(); augs.sort((augName1, augName2) => { const aug1 = Augmentations[augName1], aug2 = Augmentations[augName2]; @@ -89,8 +74,8 @@ export class AugmentationsPage extends React.Component { return augs; } - getAugsSortedByReputation(): string[] { - const augs = this.getAugs(); + function getAugsSortedByReputation(): string[] { + const augs = getAugs(); augs.sort((augName1, augName2) => { const aug1 = Augmentations[augName1], aug2 = Augmentations[augName2]; @@ -103,88 +88,70 @@ export class AugmentationsPage extends React.Component { return augs; } - getAugsSortedByDefault(): string[] { - return this.getAugs(); + function getAugsSortedByDefault(): string[] { + return getAugs(); } - switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void { + function switchSortOrder(newOrder: PurchaseAugmentationsOrderSetting): void { Settings.PurchaseAugmentationsOrder = newOrder; - this.rerender(); + rerender(); } - rerender(): void { - this.setState((prevState) => { - return { - rerenderFlag: !prevState.rerenderFlag, - }; - }); - } + const augs = getAugsSorted(); + const purchasable = augs.filter( + (aug: string) => + aug === AugmentationNames.NeuroFluxGovernor || + (!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)), + ); - render(): React.ReactNode { - const augs = this.getAugsSorted(); - const purchasable = augs.filter( - (aug: string) => aug === AugmentationNames.NeuroFluxGovernor || - (!this.props.p.augmentations.some((a) => a.name === aug) && - !this.props.p.queuedAugmentations.some((a) => a.name === aug)), - ); + const purchaseableAugmentation = (aug: string): React.ReactNode => { + return ; + }; - const purchaseableAugmentation = (aug: string): React.ReactNode => { - return ( - - ); - }; + const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug)); - const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug)); - - let ownedElem = <>; - const owned = augs.filter((aug: string) => !purchasable.includes(aug)); - if (owned.length !== 0) { - ownedElem = ( - <> -
    -

    Purchased Augmentations

    -

    This factions also offers these augmentations but you already own them.

    - {owned.map((aug) => purchaseableAugmentation(aug))} - - ); - } - - return ( -
    - -

    Faction Augmentations

    -

    - These are all of the Augmentations that are available to purchase from {this.props.faction.name}. - Augmentations are powerful upgrades that will enhance your abilities. -

    - this.switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} /> - this.switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)} - text={"Sort by Reputation"} - /> - this.switchSortOrder(PurchaseAugmentationsOrderSetting.Default)} - text={"Sort by Default Order"} - /> + let ownedElem = <>; + const owned = augs.filter((aug: string) => !purchasable.includes(aug)); + if (owned.length !== 0) { + ownedElem = ( + <>
    - {augListElems} - {ownedElem} -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    +

    Purchased Augmentations

    +

    This factions also offers these augmentations but you already own them.

    + {owned.map((aug) => purchaseableAugmentation(aug))} + ); } + + return ( +
    + +

    Faction Augmentations

    +

    + These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are + powerful upgrades that will enhance your abilities. +

    + switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)} text={"Sort by Cost"} /> + switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)} + text={"Sort by Reputation"} + /> + switchSortOrder(PurchaseAugmentationsOrderSetting.Default)} + text={"Sort by Default Order"} + /> +
    + {augListElems} + {ownedElem} +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + ); } diff --git a/src/Faction/ui/CreateGangPopup.tsx b/src/Faction/ui/CreateGangPopup.tsx index 5423d6348..50e14ad2e 100644 --- a/src/Faction/ui/CreateGangPopup.tsx +++ b/src/Faction/ui/CreateGangPopup.tsx @@ -1,58 +1,66 @@ /** * React Component for the popup used to create a new gang. */ - import React from "react"; - import { removePopup } from "../../ui/React/createPopup"; - import { IPlayer } from "../../PersonObjects/IPlayer"; - import { StdButton } from "../../ui/React/StdButton"; - import { IEngine } from "../../IEngine"; +import React from "react"; +import { removePopup } from "../../ui/React/createPopup"; +import { StdButton } from "../../ui/React/StdButton"; +import { use } from "../../ui/Context"; - interface ICreateGangPopupProps { - popupId: string; - facName: string; - p: IPlayer; - engine: IEngine; - } +interface ICreateGangPopupProps { + popupId: string; + facName: string; +} - export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement { - - const combatGangText = "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " + +export function CreateGangPopup(props: ICreateGangPopupProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); + const combatGangText = + "This is a COMBAT gang. Members in this gang will have different tasks than HACKING gangs. " + "Compared to hacking gangs, progression with combat gangs can be more difficult as territory management " + "is more important. However, well-managed combat gangs can progress faster than hacking ones."; - const hackingGangText = "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " + + const hackingGangText = + "This is a HACKING gang. Members in this gang will have different tasks than COMBAT gangs. " + "Compared to combat gangs, progression with hacking gangs is more straightforward as territory warfare " + "is not as important."; - function isHacking(): boolean { - return ["NiteSec", "The Black Hand"].includes(props.facName); - } + function isHacking(): boolean { + return ["NiteSec", "The Black Hand"].includes(props.facName); + } - function createGang(): void { - props.p.startGang(props.facName, isHacking()); - removePopup(props.popupId); - props.engine.loadGangContent(); - } + function createGang(): void { + player.startGang(props.facName, isHacking()); + removePopup(props.popupId); + router.toGang(); + } - function onKeyUp(event: React.KeyboardEvent): void { - if (event.keyCode === 13) createGang(); - } + function onKeyUp(event: React.KeyboardEvent): void { + if (event.keyCode === 13) createGang(); + } - return ( - <> - Would you like to create a new Gang with {props.facName}? -
    -
    - Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It also resets your reputation with this faction. -
    -
    - { (isHacking()) ? hackingGangText : combatGangText } -
    -
    - Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each of these Factions have all Augmentations available. -
    - -
    - - ); - } \ No newline at end of file + return ( + <> + Would you like to create a new Gang with {props.facName}? +
    +
    + Note that this will prevent you from creating a Gang with any other Faction until this BitNode is destroyed. It + also resets your reputation with this faction. +
    +
    + {isHacking() ? hackingGangText : combatGangText} +
    +
    + Other than hacking vs combat, there are NO differences between the Factions you can create a Gang with, and each + of these Factions have all Augmentations available. +
    + +
    + + ); +} diff --git a/src/Faction/ui/FactionRoot.tsx b/src/Faction/ui/FactionRoot.tsx index 50655ea62..b4cf1b7d9 100644 --- a/src/Faction/ui/FactionRoot.tsx +++ b/src/Faction/ui/FactionRoot.tsx @@ -3,7 +3,7 @@ * This is the component for displaying a single faction's UI, not the list of all * accessible factions */ -import * as React from "react"; +import React, { useState } from "react"; import { AugmentationsPage } from "./AugmentationsPage"; import { DonateOption } from "./DonateOption"; @@ -11,30 +11,21 @@ import { Info } from "./Info"; import { Option } from "./Option"; import { CONSTANTS } from "../../Constants"; -import { IEngine } from "../../IEngine"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; import { Faction } from "../../Faction/Faction"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { createSleevePurchasesFromCovenantPopup } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases"; import { SourceFileFlags } from "../../SourceFile/SourceFileFlags"; import { createPopup } from "../../ui/React/createPopup"; +import { use } from "../../ui/Context"; import { CreateGangPopup } from "./CreateGangPopup"; type IProps = { - engine: IEngine; faction: Faction | null; - p: IPlayer; startHackingMissionFn: (faction: Faction) => void; }; -type IState = { - rerenderFlag: boolean; - purchasingAugs: boolean; - faction: Faction; -}; - // Info text for all options on the UI const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " + "faction reputation"; const hackingMissionInfo = @@ -72,91 +63,68 @@ const GangNames = [ "The Black Hand", ]; -export class FactionRoot extends React.Component { - constructor(props: IProps) { - if (props.faction === null) throw new Error("Trying to render the Faction page with null faction"); - super(props); +export function FactionRoot(props: IProps): React.ReactElement { + const faction = props.faction; + if (faction === null) throw new Error("Trying to render the Faction page with null faction"); - this.state = { - rerenderFlag: false, - purchasingAugs: false, - faction: props.faction, - }; + const player = use.Player(); + const router = use.Router(); + const [, setRerenderFlag] = useState(false); + const [purchasingAugs, setPurchasingAugs] = useState(false); - this.manageGang = this.manageGang.bind(this); - this.rerender = this.rerender.bind(this); - this.routeToMain = this.routeToMain.bind(this); - this.routeToPurchaseAugs = this.routeToPurchaseAugs.bind(this); - this.sleevePurchases = this.sleevePurchases.bind(this); - this.startFieldWork = this.startFieldWork.bind(this); - this.startHackingContracts = this.startHackingContracts.bind(this); - this.startHackingMission = this.startHackingMission.bind(this); - this.startSecurityWork = this.startSecurityWork.bind(this); - } - - manageGang(): void { + function manageGang(faction: Faction): void { // If player already has a gang, just go to the gang UI - if (this.props.p.inGang()) { - return this.props.engine.loadGangContent(); + if (player.inGang()) { + return router.toGang(); } const popupId = "create-gang-popup"; createPopup(popupId, CreateGangPopup, { popupId: popupId, - facName: this.state.faction.name, - p: this.props.p, - engine: this.props.engine, + facName: faction.name, }); } - rerender(): void { - this.setState((prevState) => { - return { - rerenderFlag: !prevState.rerenderFlag, - }; - }); + function rerender(): void { + setRerenderFlag((old) => !old); } // Route to the main faction page - routeToMain(): void { - this.setState({ purchasingAugs: false }); + function routeToMain(): void { + setPurchasingAugs(false); } // Route to the purchase augmentation UI for this faction - routeToPurchaseAugs(): void { - this.setState({ purchasingAugs: true }); + function routeToPurchaseAugs(): void { + setPurchasingAugs(true); } - sleevePurchases(): void { - createSleevePurchasesFromCovenantPopup(this.props.p); + function sleevePurchases(): void { + createSleevePurchasesFromCovenantPopup(player); } - startFieldWork(): void { - this.props.p.startFactionFieldWork(this.state.faction); + function startFieldWork(faction: Faction): void { + player.startFactionFieldWork(faction); + router.toWork(); } - startHackingContracts(): void { - this.props.p.startFactionHackWork(this.state.faction); + function startHackingContracts(faction: Faction): void { + player.startFactionHackWork(faction); + router.toWork(); } - startHackingMission(): void { - const fac = this.state.faction; - this.props.p.singularityStopWork(); - this.props.engine.loadMissionContent(); - this.props.startHackingMissionFn(fac); + function startHackingMission(faction: Faction): void { + player.singularityStopWork(); + props.startHackingMissionFn(faction); } - startSecurityWork(): void { - this.props.p.startFactionSecurityWork(this.state.faction); + function startSecurityWork(faction: Faction): void { + player.startFactionSecurityWork(faction); + router.toWork(); } - render(): React.ReactNode { - return this.state.purchasingAugs ? this.renderAugmentationsPage() : this.renderMainPage(); - } - - renderMainPage(): React.ReactNode { - const p = this.props.p; - const faction = this.state.faction; + function MainPage({ faction }: { faction: Faction }): React.ReactElement { + const p = player; const factionInfo = faction.getInfo(); // We have a special flag for whether the player this faction is the player's @@ -183,49 +151,51 @@ export class FactionRoot extends React.Component {

    {faction.name}

    - {canAccessGang &&
    ); } - renderAugmentationsPage(): React.ReactNode { - return ( - <> - - - ); - } + return purchasingAugs ? ( + + ) : ( + + ); } diff --git a/src/Faction/ui/PurchaseAugmentationPopup.tsx b/src/Faction/ui/PurchaseAugmentationPopup.tsx index a4053b480..8b253a500 100644 --- a/src/Faction/ui/PurchaseAugmentationPopup.tsx +++ b/src/Faction/ui/PurchaseAugmentationPopup.tsx @@ -12,6 +12,7 @@ interface IProps { player: IPlayer; faction: Faction; aug: Augmentation; + rerender: () => void; popupId: string; } @@ -24,6 +25,7 @@ export function PurchaseAugmentationPopup(props: IProps): React.ReactElement { } purchaseAugmentation(props.aug, props.faction); + props.rerender(); removePopup(props.popupId); } diff --git a/src/Faction/ui/PurchaseableAugmentation.tsx b/src/Faction/ui/PurchaseableAugmentation.tsx index 9dfe4bc79..ad38a5b3d 100644 --- a/src/Faction/ui/PurchaseableAugmentation.tsx +++ b/src/Faction/ui/PurchaseableAugmentation.tsx @@ -7,7 +7,6 @@ import * as React from "react"; import { getNextNeurofluxLevel, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers"; import { PurchaseAugmentationPopup } from "./PurchaseAugmentationPopup"; -import { Augmentation } from "../../Augmentation/Augmentation"; import { Augmentations } from "../../Augmentation/Augmentations"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { Faction } from "../../Faction/Faction"; @@ -28,63 +27,56 @@ type IProps = { rerender: () => void; }; -export class PurchaseableAugmentation extends React.Component { - aug: Augmentation; +export function PurchaseableAugmentation(props: IProps): React.ReactElement { + const aug = Augmentations[props.augName]; + if (aug == null) throw new Error(`aug ${props.augName} does not exists`); - constructor(props: IProps) { - super(props); - - const aug = Augmentations[this.props.augName]; - if (aug == null) throw new Error(`aug ${this.props.augName} does not exists`); - this.aug = aug; - - this.handleClick = this.handleClick.bind(this); + function getMoneyCost(): number { + return aug.baseCost * props.faction.getInfo().augmentationPriceMult; } - getMoneyCost(): number { - return this.aug.baseCost * this.props.faction.getInfo().augmentationPriceMult; + function getRepCost(): number { + return aug.baseRepRequirement * props.faction.getInfo().augmentationRepRequirementMult; } - getRepCost(): number { - return this.aug.baseRepRequirement * this.props.faction.getInfo().augmentationRepRequirementMult; - } - - handleClick(): void { + function handleClick(): void { if (!Settings.SuppressBuyAugmentationConfirmation) { const popupId = "purchase-augmentation-popup"; createPopup(popupId, PurchaseAugmentationPopup, { - aug: this.aug, - faction: this.props.faction, - player: this.props.p, + aug: aug, + faction: props.faction, + player: props.p, + rerender: props.rerender, popupId: popupId, }); } else { - purchaseAugmentation(this.aug, this.props.faction); + purchaseAugmentation(aug, props.faction); + props.rerender(); } } // Whether the player has the prerequisite Augmentations - hasPrereqs(): boolean { - return hasAugmentationPrereqs(this.aug); + function hasPrereqs(): boolean { + return hasAugmentationPrereqs(aug); } // Whether the player has enough rep for this Augmentation - hasReputation(): boolean { - return this.props.faction.playerReputation >= this.getRepCost(); + function hasReputation(): boolean { + return props.faction.playerReputation >= getRepCost(); } // Whether the player has this augmentations (purchased OR installed) - owned(): boolean { + function owned(): boolean { let owned = false; - for (const queuedAug of this.props.p.queuedAugmentations) { - if (queuedAug.name === this.props.augName) { + for (const queuedAug of props.p.queuedAugmentations) { + if (queuedAug.name === props.augName) { owned = true; break; } } - for (const installedAug of this.props.p.augmentations) { - if (installedAug.name === this.props.augName) { + for (const installedAug of props.p.augmentations) { + if (installedAug.name === props.augName) { owned = true; break; } @@ -93,96 +85,94 @@ export class PurchaseableAugmentation extends React.Component { return owned; } - render(): React.ReactNode { - if (this.aug == null) { - console.error( - `Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${this.props.augName}`, - ); - return null; - } - - const moneyCost = this.getMoneyCost(); - const repCost = this.getRepCost(); - - // Determine UI properties - let disabled = false; - let status: JSX.Element = <>; - let color = ""; - if (!this.hasPrereqs()) { - disabled = true; - status = <>LOCKED (Requires {this.aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite); - color = "red"; - } else if (this.aug.name !== AugmentationNames.NeuroFluxGovernor && (this.aug.owned || this.owned())) { - disabled = true; - } else if (this.hasReputation()) { - status = ( - <> - UNLOCKED (at {Reputation(repCost)} faction reputation) - - - ); - } else { - disabled = true; - status = ( - <> - LOCKED (Requires {Reputation(repCost)} faction reputation - ) - - ); - color = "red"; - } - - const txtStyle: IMap = { - display: "inline-block", - }; - if (color !== "") { - txtStyle.color = color; - } - - // Determine button txt - let btnTxt = this.aug.name; - if (this.aug.name === AugmentationNames.NeuroFluxGovernor) { - btnTxt += ` - Level ${getNextNeurofluxLevel()}`; - } - - let tooltip = <>; - if (typeof this.aug.info === "string") - tooltip = ( - <> - -
    -
    - {this.aug.stats} - - ); - else - tooltip = ( - <> - {this.aug.info} -
    -
    - {this.aug.stats} - - ); - - return ( -
  • - - -

    {status}

    -
    -
  • + if (aug == null) { + console.error( + `Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${props.augName}`, ); + return <>; } + + const moneyCost = getMoneyCost(); + const repCost = getRepCost(); + + // Determine UI properties + let disabled = false; + let status: JSX.Element = <>; + let color = ""; + if (!hasPrereqs()) { + disabled = true; + status = <>LOCKED (Requires {aug.prereqs.map((aug) => AugFormat(aug))} as prerequisite); + color = "red"; + } else if (aug.name !== AugmentationNames.NeuroFluxGovernor && (aug.owned || owned())) { + disabled = true; + } else if (hasReputation()) { + status = ( + <> + UNLOCKED (at {Reputation(repCost)} faction reputation) - + + ); + } else { + disabled = true; + status = ( + <> + LOCKED (Requires {Reputation(repCost)} faction reputation - ) + + ); + color = "red"; + } + + const txtStyle: IMap = { + display: "inline-block", + }; + if (color !== "") { + txtStyle.color = color; + } + + // Determine button txt + let btnTxt = aug.name; + if (aug.name === AugmentationNames.NeuroFluxGovernor) { + btnTxt += ` - Level ${getNextNeurofluxLevel()}`; + } + + let tooltip = <>; + if (typeof aug.info === "string") + tooltip = ( + <> + +
    +
    + {aug.stats} + + ); + else + tooltip = ( + <> + {aug.info} +
    +
    + {aug.stats} + + ); + + return ( +
  • + + +

    {status}

    +
    +
  • + ); } diff --git a/src/Gang/ui/Root.tsx b/src/Gang/ui/GangRoot.tsx similarity index 69% rename from src/Gang/ui/Root.tsx rename to src/Gang/ui/GangRoot.tsx index 3d53c9277..d746d7626 100644 --- a/src/Gang/ui/Root.tsx +++ b/src/Gang/ui/GangRoot.tsx @@ -2,20 +2,19 @@ * React Component for all the gang stuff. */ import React, { useState, useEffect } from "react"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { ManagementSubpage } from "./ManagementSubpage"; import { TerritorySubpage } from "./TerritorySubpage"; -import { IEngine } from "../../IEngine"; +import { use } from "../../ui/Context"; +import { Factions } from "../../Faction/Factions"; import { Gang } from "../Gang"; -import { displayFactionContent } from "../../Faction/FactionHelpers"; interface IProps { gang: Gang; - player: IPlayer; - engine: IEngine; } -export function Root(props: IProps): React.ReactElement { +export function GangRoot(props: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); const [management, setManagement] = useState(true); const setRerender = useState(false)[1]; @@ -25,8 +24,7 @@ export function Root(props: IProps): React.ReactElement { }, []); function back(): void { - props.engine.loadFactionContent(); - displayFactionContent(props.gang.facName); + router.toFaction(Factions[props.gang.facName]); } return ( @@ -48,11 +46,7 @@ export function Root(props: IProps): React.ReactElement { > Gang Territory - {management ? ( - - ) : ( - - )} + {management ? : } ); } diff --git a/src/Infiltration/Helper.tsx b/src/Infiltration/Helper.tsx deleted file mode 100644 index a15fae91e..000000000 --- a/src/Infiltration/Helper.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Page, routing } from ".././ui/navigationTracking"; -import { Root } from "./ui/Root"; -import { IPlayer } from "../PersonObjects/IPlayer"; -import { IEngine } from "../IEngine"; -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -let container: HTMLElement; - -(function () { - function setContainer(): void { - const c = document.getElementById("infiltration-container"); - if (c === null) throw new Error("huh?"); - container = c; - document.removeEventListener("DOMContentLoaded", setContainer); - } - - document.addEventListener("DOMContentLoaded", setContainer); -})(); - -function calcDifficulty(player: IPlayer, startingDifficulty: number): number { - const totalStats = player.strength + player.defense + player.dexterity + player.agility + player.charisma; - const difficulty = startingDifficulty - Math.pow(totalStats, 0.9) / 250 - player.intelligence / 1600; - if (difficulty < 0) return 0; - if (difficulty > 3) return 3; - return difficulty; -} - -export function displayInfiltrationContent( - engine: IEngine, - player: IPlayer, - location: string, - startingDifficulty: number, - maxLevel: number, -): void { - if (!routing.isOn(Page.Infiltration)) return; - - const difficulty = calcDifficulty(player, startingDifficulty); - - ReactDOM.render( - , - container, - ); -} diff --git a/src/Infiltration/ui/Game.tsx b/src/Infiltration/ui/Game.tsx index 59386f9d1..378d3f9e4 100644 --- a/src/Infiltration/ui/Game.tsx +++ b/src/Infiltration/ui/Game.tsx @@ -1,5 +1,4 @@ -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; +import { use } from "../../ui/Context"; import React, { useState } from "react"; import Grid from "@mui/material/Grid"; import { Countdown } from "./Countdown"; @@ -14,8 +13,6 @@ import { WireCuttingGame } from "./WireCuttingGame"; import { Victory } from "./Victory"; interface IProps { - Player: IPlayer; - Engine: IEngine; StartingDifficulty: number; Difficulty: number; MaxLevel: number; @@ -40,6 +37,8 @@ const minigames = [ ]; export function Game(props: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); const [level, setLevel] = useState(1); const [stage, setStage] = useState(Stage.Countdown); const [results, setResults] = useState(""); @@ -89,12 +88,10 @@ export function Game(props: IProps): React.ReactElement { pushResult(false); // Kill the player immediately if they use automation, so // it's clear they're not meant to - const damage = options?.automated ? props.Player.hp : props.StartingDifficulty * 3; - if (props.Player.takeDamage(damage)) { - const menu = document.getElementById("mainmenu-container"); - if (menu === null) throw new Error("mainmenu-container not found"); - menu.style.visibility = "visible"; - props.Engine.loadLocationContent(); + const damage = options?.automated ? player.hp : props.StartingDifficulty * 3; + if (player.takeDamage(damage)) { + router.toCity(); + return; } setupNextGame(); } @@ -112,8 +109,6 @@ export function Game(props: IProps): React.ReactElement { case Stage.Sell: stageComponent = ( 3) return 3; + return difficulty; +} + +export function InfiltrationRoot(props: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); + const [start, setStart] = useState(false); + + const loc = Locations[props.location]; + if (loc.infiltrationData === undefined) throw new Error("Trying to do infiltration on invalid location."); + const startingDifficulty = loc.infiltrationData.startingSecurityLevel; + const difficulty = calcDifficulty(player, startingDifficulty); + + function cancel(): void { + router.toCity(); + } + + if (!start) { + return ( + setStart(true)} + cancel={cancel} + /> + ); + } + + return ( + + ); +} diff --git a/src/Infiltration/ui/Intro.tsx b/src/Infiltration/ui/Intro.tsx index 6c089a607..a7201c350 100644 --- a/src/Infiltration/ui/Intro.tsx +++ b/src/Infiltration/ui/Intro.tsx @@ -1,12 +1,8 @@ -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; import React from "react"; import { StdButton } from "../../ui/React/StdButton"; import Grid from "@mui/material/Grid"; interface IProps { - Player: IPlayer; - Engine: IEngine; Location: string; Difficulty: number; MaxLevel: number; diff --git a/src/Infiltration/ui/Root.tsx b/src/Infiltration/ui/Root.tsx deleted file mode 100644 index 67631fe0f..000000000 --- a/src/Infiltration/ui/Root.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; -import React, { useState } from "react"; -import { Intro } from "./Intro"; -import { Game } from "./Game"; - -interface IProps { - Player: IPlayer; - Engine: IEngine; - Location: string; - StartingDifficulty: number; - Difficulty: number; - MaxLevel: number; -} - -export function Root(props: IProps): React.ReactElement { - const [start, setStart] = useState(false); - - function cancel(): void { - const menu = document.getElementById("mainmenu-container"); - if (menu === null) throw new Error("mainmenu-container not found"); - menu.style.visibility = "visible"; - props.Engine.loadLocationContent(); - } - - if (!start) { - return ( - setStart(true)} - cancel={cancel} - /> - ); - } - - return ( - - ); -} diff --git a/src/Infiltration/ui/Victory.tsx b/src/Infiltration/ui/Victory.tsx index 9702c63c4..6ee057a57 100644 --- a/src/Infiltration/ui/Victory.tsx +++ b/src/Infiltration/ui/Victory.tsx @@ -1,5 +1,3 @@ -import { IPlayer } from "../../PersonObjects/IPlayer"; -import { IEngine } from "../../IEngine"; import { Factions } from "../../Faction/Factions"; import React, { useState } from "react"; import { StdButton } from "../../ui/React/StdButton"; @@ -7,23 +5,21 @@ import Grid from "@mui/material/Grid"; import { Money } from "../../ui/React/Money"; import { Reputation } from "../../ui/React/Reputation"; import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; +import { use } from "../../ui/Context"; interface IProps { - Player: IPlayer; - Engine: IEngine; StartingDifficulty: number; Difficulty: number; MaxLevel: number; } export function Victory(props: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); const [faction, setFaction] = useState("none"); function quitInfiltration(): void { - const menu = document.getElementById("mainmenu-container"); - if (!menu) throw new Error("mainmenu-container somehow null"); - menu.style.visibility = "visible"; - props.Engine.loadLocationContent(); + router.toCity(); } const levelBonus = props.MaxLevel * Math.pow(1.01, props.MaxLevel); @@ -43,8 +39,8 @@ export function Victory(props: IProps): React.ReactElement { BitNodeMultipliers.InfiltrationMoney; function sell(): void { - props.Player.gainMoney(moneyGain); - props.Player.recordMoneySource(moneyGain, "infiltration"); + player.gainMoney(moneyGain); + player.recordMoneySource(moneyGain, "infiltration"); quitInfiltration(); } @@ -70,7 +66,7 @@ export function Victory(props: IProps): React.ReactElement { - {props.Player.factions + {player.factions .filter((f) => Factions[f].getInfo().offersWork()) .map((f) => (
    - {getAvailableCreatePrograms(props.player).map((program) => { + {getAvailableCreatePrograms(player).map((program) => { const create = program.create; if (create === null) return <>; return ( - diff --git a/src/RedPill.d.ts b/src/RedPill.d.ts index 31523f940..d60d01977 100644 --- a/src/RedPill.d.ts +++ b/src/RedPill.d.ts @@ -1,6 +1,2 @@ export declare let redPillFlag: boolean; -export declare function hackWorldDaemon( - currentNodeNumber: number, - flume: boolean = false, - quick: boolean = false, -): void; +export declare function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number); diff --git a/src/RedPill.jsx b/src/RedPill.jsx index e6f782ea1..2c8a46f7f 100644 --- a/src/RedPill.jsx +++ b/src/RedPill.jsx @@ -1,7 +1,6 @@ /** * Implementation for what happens when you destroy a BitNode */ -import { Engine } from "./engine"; import { Player } from "./Player"; import { prestigeSourceFile } from "./Prestige"; import { PlayerOwnedSourceFile } from "./SourceFile/PlayerOwnedSourceFile"; @@ -9,20 +8,10 @@ import { SourceFileFlags } from "./SourceFile/SourceFileFlags"; import { SourceFiles } from "./SourceFile/SourceFiles"; import { dialogBoxCreate } from "../utils/DialogBox"; -import { BitverseRoot } from "./BitNode/ui/BitverseRoot"; -import React from "react"; -import ReactDOM from "react-dom"; let redPillFlag = false; -function hackWorldDaemon(currentNodeNumber, flume = false, quick = false) { - // Clear the screen - const container = document.getElementById("red-pill-container"); - ReactDOM.unmountComponentAtNode(container); - Engine.loadRedPillContent(); - ReactDOM.render( - , - container, - ); +function hackWorldDaemon(router, flume = false, quick = false) { + router.toBitVerse(flume, quick); redPillFlag = true; } @@ -68,12 +57,12 @@ function giveSourceFile(bitNodeNumber) { Player.intelligence = 1; } dialogBoxCreate( - "You received a Source-File for destroying a Bit Node!

    " + sourceFile.name + "

    " + sourceFile.info, + "You received a Source-File for destroying a BitNode!

    " + sourceFile.name + "

    " + sourceFile.info, ); } } -function enterBitNode(flume, destroyedBitNode, newBitNode) { +export function enterBitNode(router, flume, destroyedBitNode, newBitNode) { if (!flume) { giveSourceFile(destroyedBitNode); } else { @@ -86,12 +75,14 @@ function enterBitNode(flume, destroyedBitNode, newBitNode) { Player.intelligence = 1; } redPillFlag = false; - const container = document.getElementById("red-pill-container"); - ReactDOM.unmountComponentAtNode(container); - // Set new Bit Node Player.bitNodeN = newBitNode; + if (newBitNode === 6) { + router.toBladeburnerCinematic(); + } else { + router.toTerminal(); + } prestigeSourceFile(flume); } diff --git a/src/Script/Script.ts b/src/Script/Script.ts index 88295ed12..521678087 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -6,7 +6,6 @@ */ import { calculateRamUsage } from "./RamCalculations"; import { ScriptUrl } from "./ScriptUrl"; -import { Page, routing } from "../ui/navigationTracking"; import { setTimeoutRef } from "../utils/SetTimeoutRef"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver"; diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 5e906a553..3897405c4 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import clsx from "clsx"; -import { styled, useTheme, Theme, CSSObject } from "@mui/material/styles"; +import { styled, Theme, CSSObject } from "@mui/material/styles"; import createStyles from "@mui/styles/createStyles"; import makeStyles from "@mui/styles/makeStyles"; import MuiDrawer from "@mui/material/Drawer"; @@ -15,8 +15,6 @@ import Typography from "@mui/material/Typography"; import Collapse from "@mui/material/Collapse"; import Badge from "@mui/material/Badge"; -import { TTheme as BBTheme, colors } from "../../ui/React/Theme"; - import ComputerIcon from "@mui/icons-material/Computer"; import LastPageIcon from "@mui/icons-material/LastPage"; // Terminal import CreateIcon from "@mui/icons-material/Create"; // Create Script @@ -57,8 +55,6 @@ import { cinematicTextFlag } from "../../CinematicText"; import { KEY } from "../../../utils/helpers/keyCodes"; import { FconfSettings } from "../../Fconf/FconfSettings"; -const drawerWidth = 240; - const openedMixin = (theme: Theme): CSSObject => ({ width: theme.spacing(31), transition: theme.transitions.create("width", { @@ -97,7 +93,7 @@ const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== "open" const useStyles = makeStyles((theme: Theme) => createStyles({ active: { - borderLeft: "3px solid " + colors.primary, + borderLeft: "3px solid " + theme.palette.primary.main, }, listitem: {}, }), diff --git a/src/StockMarket/StockMarket.tsx b/src/StockMarket/StockMarket.tsx index d33de36f1..e1a5e77ad 100644 --- a/src/StockMarket/StockMarket.tsx +++ b/src/StockMarket/StockMarket.tsx @@ -1,4 +1,3 @@ -import { buyStock, sellStock, shortStock, sellShort } from "./BuyingAndSelling"; import { IOrderBook } from "./IOrderBook"; import { IStockMarket } from "./IStockMarket"; import { Order } from "./Order"; @@ -9,23 +8,17 @@ import { InitStockMetadata } from "./data/InitStockMetadata"; import { OrderTypes } from "./data/OrderTypes"; import { PositionTypes } from "./data/PositionTypes"; import { StockSymbols } from "./data/StockSymbols"; -import { StockMarketRoot } from "./ui/StockMarketRoot"; import { CONSTANTS } from "../Constants"; import { WorkerScript } from "../Netscript/WorkerScript"; -import { Player } from "../Player"; import { IMap } from "../types"; import { EventEmitter } from "../utils/EventEmitter"; -import { Page, routing } from ".././ui/navigationTracking"; import { numeralWrapper } from ".././ui/numeralFormat"; import { dialogBoxCreate } from "../../utils/DialogBox"; import { Reviver } from "../../utils/JSONReviver"; -import * as React from "react"; -import * as ReactDOM from "react-dom"; - export let StockMarket: IStockMarket = { lastUpdate: 0, Orders: {}, @@ -150,7 +143,6 @@ export function loadStockMarket(saveString: string): void { ticksUntilCycle: 0, } as IStockMarket; } else { - console.log(JSON.parse(saveString, Reviver)); StockMarket = JSON.parse(saveString, Reviver); } } @@ -314,14 +306,6 @@ export function processStockPrices(numCycles = 1): void { } } -let stockMarketContainer: HTMLElement | null = null; -function setStockMarketContainer(): void { - stockMarketContainer = document.getElementById("generic-react-container"); - document.removeEventListener("DOMContentLoaded", setStockMarketContainer); -} - -document.addEventListener("DOMContentLoaded", setStockMarketContainer); - export function initStockMarketFnForReact(): void { initStockMarket(); initSymbolToStockMap(); diff --git a/src/StockMarket/ui/StockMarketRoot.tsx b/src/StockMarket/ui/StockMarketRoot.tsx index e7cfecf73..936f553cd 100644 --- a/src/StockMarket/ui/StockMarketRoot.tsx +++ b/src/StockMarket/ui/StockMarketRoot.tsx @@ -36,7 +36,7 @@ type IProps = { stockMarket: IStockMarket; }; -export function StockMarketRoot(props: IProps) { +export function StockMarketRoot(props: IProps): React.ReactElement { const setRerender = useState(false)[1]; function rerender(): void { setRerender((old) => !old); diff --git a/src/Terminal/ITerminal.ts b/src/Terminal/ITerminal.ts index 0985d10f3..a9bc32f87 100644 --- a/src/Terminal/ITerminal.ts +++ b/src/Terminal/ITerminal.ts @@ -56,10 +56,10 @@ export interface ITerminal { startAnalyze(): void; startBackdoor(player: IPlayer): void; startHack(player: IPlayer): void; - finishHack(player: IPlayer, cancelled?: boolean): void; - finishBackdoor(player: IPlayer, cancelled?: boolean): void; + finishHack(router: IRouter, player: IPlayer, cancelled?: boolean): void; + finishBackdoor(router: IRouter, player: IPlayer, cancelled?: boolean): void; finishAnalyze(player: IPlayer, cancelled?: boolean): void; - finishAction(player: IPlayer, cancelled?: boolean): void; + finishAction(router: IRouter, player: IPlayer, cancelled?: boolean): void; getFilepath(filename: string): string; getFile(player: IPlayer, filename: string): Script | TextFile | string | null; getScript(player: IPlayer, filename: string): Script | null; @@ -74,7 +74,7 @@ export interface ITerminal { executeCommands(router: IRouter, player: IPlayer, commands: string): void; // If there was any changes, will return true, once. pollChanges(): boolean; - process(player: IPlayer, cycles: number): void; + process(router: IRouter, player: IPlayer, cycles: number): void; prestige(): void; getProgressText(): string; } diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 5d50d6894..042a73060 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -3,7 +3,6 @@ import { IRouter } from "../ui/Router"; import { IPlayer } from "../PersonObjects/IPlayer"; import { HacknetServer } from "../Hacknet/HacknetServer"; import { BaseServer } from "../Server/BaseServer"; -import { hackWorldDaemon } from "../RedPill"; import { Programs } from "../Programs/Programs"; import { CodingContractResult } from "../CodingContracts"; @@ -86,11 +85,11 @@ export class Terminal implements ITerminal { // Excludes the trailing forward slash currDir = "/"; - process(player: IPlayer, cycles: number): void { + process(router: IRouter, player: IPlayer, cycles: number): void { if (this.action === null) return; this.action.timeLeft -= (CONSTANTS._idleSpeed * cycles) / 1000; this.hasChanges = true; - if (this.action.timeLeft < 0) this.finishAction(player, false); + if (this.action.timeLeft < 0) this.finishAction(router, player, false); } pollChanges(): boolean { @@ -138,7 +137,7 @@ export class Terminal implements ITerminal { } // Complete the hack/analyze command - finishHack(player: IPlayer, cancelled = false): void { + finishHack(router: IRouter, player: IPlayer, cancelled = false): void { if (cancelled) return; const server = player.getCurrentServer(); @@ -156,7 +155,7 @@ export class Terminal implements ITerminal { if (player.bitNodeN == null) { player.bitNodeN = 1; } - hackWorldDaemon(player.bitNodeN); + router.toBitVerse(false, false); return; } server.backdoorInstalled = true; @@ -190,7 +189,7 @@ export class Terminal implements ITerminal { } } - finishBackdoor(player: IPlayer, cancelled = false): void { + finishBackdoor(router: IRouter, player: IPlayer, cancelled = false): void { if (!cancelled) { const server = player.getCurrentServer(); if ( @@ -200,7 +199,7 @@ export class Terminal implements ITerminal { if (player.bitNodeN == null) { player.bitNodeN = 1; } - hackWorldDaemon(player.bitNodeN); + router.toBitVerse(false, false); return; } server.backdoorInstalled = true; @@ -238,16 +237,16 @@ export class Terminal implements ITerminal { } } - finishAction(player: IPlayer, cancelled = false): void { + finishAction(router: IRouter, player: IPlayer, cancelled = false): void { if (this.action === null) { if (!cancelled) throw new Error("Finish action called when there was no action"); return; } this.print(this.getProgressText()); if (this.action.action === "h") { - this.finishHack(player, cancelled); + this.finishHack(router, player, cancelled); } else if (this.action.action === "b") { - this.finishBackdoor(player, cancelled); + this.finishBackdoor(router, player, cancelled); } else if (this.action.action === "a") { this.finishAnalyze(player, cancelled); } diff --git a/src/Terminal/commands/runProgram.ts b/src/Terminal/commands/runProgram.ts index 868b95813..f4c8d83dc 100644 --- a/src/Terminal/commands/runProgram.ts +++ b/src/Terminal/commands/runProgram.ts @@ -31,6 +31,7 @@ export function runProgram( for (const program of Object.values(Programs)) { if (program.name === programName) { program.run( + router, terminal, player, server, diff --git a/src/Terminal/ui/TerminalInput.tsx b/src/Terminal/ui/TerminalInput.tsx index 5993a190f..98cbf62d6 100644 --- a/src/Terminal/ui/TerminalInput.tsx +++ b/src/Terminal/ui/TerminalInput.tsx @@ -17,21 +17,21 @@ import { FconfSettings } from "../../Fconf/FconfSettings"; const useStyles = makeStyles((theme: Theme) => createStyles({ textfield: { - margin: 0, + margin: theme.spacing(0), width: "100%", }, input: { backgroundColor: "#000", }, nopadding: { - padding: 0, + padding: theme.spacing(0), }, preformatted: { whiteSpace: "pre-wrap", - margin: 0, + margin: theme.spacing(0), }, list: { - padding: 0, + padding: theme.spacing(0), height: "100%", }, }), @@ -147,7 +147,7 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React if (ref) ref.focus(); // Cancel action if (event.keyCode === KEY.C && event.ctrlKey) { - terminal.finishAction(player, true); + terminal.finishAction(router, player, true); } } document.addEventListener("keydown", keyDown); diff --git a/src/engine.jsx b/src/engine.jsx index 8d623c752..d6fd12765 100644 --- a/src/engine.jsx +++ b/src/engine.jsx @@ -1,74 +1,44 @@ /** - * Game engine. Handles the main game loop as well as the main UI pages - * - * TODO: Separate UI functionality into its own component + * Game engine. Handles the main game loop. */ import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions"; import { Augmentations } from "./Augmentation/Augmentations"; -import { initAugmentations, installAugmentations } from "./Augmentation/AugmentationHelpers"; -import { onExport } from "./ExportBonus"; -import { AugmentationsRoot } from "./Augmentation/ui/Root"; +import { initAugmentations } from "./Augmentation/AugmentationHelpers"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; import { initBitNodeMultipliers } from "./BitNode/BitNode"; import { Bladeburner } from "./Bladeburner/Bladeburner"; -import { CharacterOverview } from "./ui/React/CharacterOverview"; import { generateRandomContract } from "./CodingContractGenerator"; import { initCompanies } from "./Company/Companies"; import { Corporation } from "./Corporation/Corporation"; import { CONSTANTS } from "./Constants"; -import { DevMenuRoot } from "./DevMenu"; import { Factions, initFactions } from "./Faction/Factions"; import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers"; -import { FactionsRoot } from "./Faction/ui/FactionsRoot"; -import { Root as BladeburnerRoot } from "./Bladeburner/ui/Root"; -import { Root as GangRoot } from "./Gang/ui/Root"; -import { SidebarRoot } from "./Sidebar/ui/SidebarRoot"; -import { CorporationRoot } from "./Corporation/ui/CorporationRoot"; -import { ResleeveRoot } from "./PersonObjects/Resleeving/ui/ResleeveRoot"; -import { GameOptionsRoot } from "./ui/React/GameOptionsRoot"; -import { GameRoot } from "./ui/GameRoot"; +import { GameRoot, Router } from "./ui/GameRoot"; import { TTheme as Theme } from "./ui/React/Theme"; -import { SleeveRoot } from "./PersonObjects/Sleeve/ui/SleeveRoot"; -import { displayInfiltrationContent } from "./Infiltration/Helper"; import { getHackingWorkRepGain, getFactionSecurityWorkRepGain, getFactionFieldWorkRepGain, } from "./PersonObjects/formulas/reputation"; import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers"; -import { HacknetRoot } from "./Hacknet/ui/HacknetRoot"; import { iTutorialStart } from "./InteractiveTutorial"; -import { LocationName } from "./Locations/data/LocationNames"; -import { LocationRoot } from "./Locations/ui/Root"; import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers"; import { inMission, currMission } from "./Missions"; -import { workerScripts } from "./Netscript/WorkerScripts"; import { loadAllRunningScripts, updateOnlineScriptTimes } from "./NetscriptWorker"; import { Player } from "./Player"; -import { prestigeAugmentation } from "./Prestige"; -import { ProgramsRoot } from "./Programs/ui/ProgramsRoot"; import { saveObject, loadGame } from "./SaveObject"; -import { Root as ScriptEditorRoot } from "./ScriptEditor/ui/Root"; -import { initForeignServers, AllServers } from "./Server/AllServers"; +import { initForeignServers } from "./Server/AllServers"; import { Settings } from "./Settings/Settings"; import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags"; import { initSpecialServerIps } from "./Server/SpecialServerIps"; import { initSymbolToStockMap, processStockPrices } from "./StockMarket/StockMarket"; -import { MilestonesRoot } from "./Milestones/ui/MilestonesRoot"; -import { TerminalRoot } from "./Terminal/ui/TerminalRoot"; import { Terminal } from "./Terminal"; -import { TutorialRoot } from "./Tutorial/ui/TutorialRoot"; import { Sleeve } from "./PersonObjects/Sleeve/Sleeve"; -import { CharacterInfo } from "./ui/CharacterInfo"; -import { Page, routing } from "./ui/navigationTracking"; import { Money } from "./ui/React/Money"; import { Hashes } from "./ui/React/Hashes"; import { Reputation } from "./ui/React/Reputation"; -import { ActiveScriptsRoot } from "./ui/ActiveScripts/Root"; -import { MainMenuLinks } from "./ui/MainMenu/Links"; - import { dialogBoxCreate } from "../utils/DialogBox"; import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen"; @@ -79,347 +49,19 @@ import React from "react"; import ReactDOM from "react-dom"; const Engine = { - // Clickable objects - Clickables: { - // Main menu buttons - saveMainMenuButton: null, - deleteMainMenuButton: null, - }, - // Display objects // TODO-Refactor this into its own component Display: { - // Generic page that most react loads into. - content: null, - // Main menu content - infiltrationContent: null, - workInProgressContent: null, - redPillContent: null, - cinematicTextContent: null, missionContent: null, - overview: null, }, indexedDb: undefined, // Time variables (milliseconds unix epoch time) _lastUpdate: new Date().getTime(), - _idleSpeed: 200, // Speed (in ms) at which the main loop is updated - - loadTerminalContent: function () { - // Engine.hideAllContent(); - // Engine.Display.content.style.display = "block"; - // routing.navigateTo(Page.CharacterInfo); - // ReactDOM.render( - // - // - // , - // Engine.Display.content, - // ); - // MainMenuLinks.Stats.classList.add("active"); - }, - - loadCharacterContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.CharacterInfo); - ReactDOM.render(, Engine.Display.content); - MainMenuLinks.Stats.classList.add("active"); - }, - - loadScriptEditorContent: function (filename = "", code = "") { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.ScriptEditor); - MainMenuLinks.ScriptEditor.classList.add("active"); - ReactDOM.render( - , - Engine.Display.content, - ); - }, - - loadActiveScriptsContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.ActiveScripts); - MainMenuLinks.ActiveScripts.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadHacknetNodesContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.HacknetNodes); - MainMenuLinks.HacknetNodes.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadCreateProgramContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.CreateProgram); - MainMenuLinks.CreateProgram.classList.add("active"); - ReactDOM.render( - - - , - Engine.Display.content, - ); - }, - - loadFactionsContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Factions); - MainMenuLinks.Factions.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - // TODO reactify - loadFactionContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Faction); - }, - - loadAugmentationsContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Augmentations); - MainMenuLinks.Augmentations.classList.add("active"); - - function backup() { - saveObject.exportGame(); - onExport(Player); - } - - ReactDOM.render( - , - Engine.Display.content, - ); - }, - - loadMilestonesContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Milestones); - MainMenuLinks.Milestones.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadLocationContent: function (initiallyInCity = true) { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Location); - MainMenuLinks.City.classList.add("active"); - ReactDOM.render( - , - Engine.Display.content, - ); - }, - - loadTravelContent: function () { - // Same as loadLocationContent() except first set the location to the travel agency, - // and make sure that the 'City' main menu link doesnt become 'active' - Engine.hideAllContent(); - Player.gotoLocation(LocationName.TravelAgency); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Location); - MainMenuLinks.Travel.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadJobContent: function () { - // Same as loadLocationContent(), except first set the location to the job. - // Make sure that the 'City' main menu link doesnt become 'active' - if (Player.companyName == "") { - dialogBoxCreate( - "You do not currently have a job! You can visit various companies " + "in the city and try to find a job.", - ); - return; - } - Engine.hideAllContent(); - Player.gotoLocation(Player.companyName); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Location); - MainMenuLinks.Job.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - // TODO reactify - loadWorkInProgressContent: function () { - Engine.hideAllContent(); - const mainMenu = document.getElementById("mainmenu-container"); - console.log("hiding loadWorkInProgressContent"); - mainMenu.style.visibility = "hidden"; - Engine.Display.workInProgressContent.style.display = "block"; - console.log(Engine.Display.workInProgressContent); - routing.navigateTo(Page.WorkInProgress); - }, - - loadRedPillContent: function () { - Engine.hideAllContent(); - const mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "hidden"; - Engine.Display.redPillContent.style.display = "block"; - routing.navigateTo(Page.RedPill); - }, - - // TODO reactify - loadCinematicTextContent: function () { - Engine.hideAllContent(); - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "hidden"; - Engine.Display.cinematicTextContent.style.display = "block"; - routing.navigateTo(Page.CinematicText); - }, - - // TODO reactify - loadInfiltrationContent: function (name, difficulty, maxLevel) { - Engine.hideAllContent(); - const mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "hidden"; - Engine.Display.infiltrationContent.style.display = "block"; - routing.navigateTo(Page.Infiltration); - displayInfiltrationContent(this, Player, name, difficulty, maxLevel); - }, - - loadStockMarketContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.StockMarket); - MainMenuLinks.StockMarket.classList.add("active"); - //displayStockMarketContent(); - }, - - loadGangContent: function () { - if (!Player.inGang()) return; - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Gang); - MainMenuLinks.Gang.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadMissionContent: function () { - Engine.hideAllContent(); - document.getElementById("mainmenu-container").style.visibility = "hidden"; - document.getElementById("character-overview").style.visibility = "hidden"; - Engine.Display.missionContent.style.display = "block"; - routing.navigateTo(Page.Mission); - }, - - loadCorporationContent: function () { - if (!(Player.corporation instanceof Corporation)) return; - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Corporation); - MainMenuLinks.Corporation.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadBladeburnerContent: function () { - if (!(Player.bladeburner instanceof Bladeburner)) return; - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Bladeburner); - MainMenuLinks.Bladeburner.classList.add("active"); - ReactDOM.render( - , - Engine.Display.content, - ); - }, - - loadSleevesContent: function () { - Engine.hideAllContent(); - Engine.Display.content.style.display = "block"; - routing.navigateTo(Page.Sleeves); - ReactDOM.render(, Engine.Display.content); - }, - - loadResleevingContent: function () { - Engine.hideAllContent(); - routing.navigateTo(Page.Resleeves); - Engine.Display.content.style.display = "block"; - MainMenuLinks.City.classList.add("active"); - ReactDOM.render(, Engine.Display.content); - }, - - loadGameOptionsContent: function () { - Engine.hideAllContent(); - routing.navigateTo(Page.GameOptions); - Engine.Display.content.style.display = "block"; - MainMenuLinks.City.classList.add("active"); - ReactDOM.render( - - saveObject.saveGame(Engine.indexedDb)} - delete={() => saveObject.deleteGame(Engine.indexedDb)} - export={() => saveObject.exportGame()} - import={() => saveObject.importGame()} - forceKill={() => { - for (const hostname of Object.keys(AllServers)) { - AllServers[hostname].runningScripts = []; - } - dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page."); - }} - softReset={() => { - dialogBoxCreate("Soft Reset!"); - prestigeAugmentation(); - }} - /> - , - Engine.Display.content, - ); - }, - - // Helper function that hides all content - hideAllContent: function () { - // Engine.Display.content.style.display = "none"; - // Engine.Display.content.scrollTop = 0; - // ReactDOM.unmountComponentAtNode(Engine.Display.content); - - Engine.Display.infiltrationContent.style.display = "none"; - ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent); - - Engine.Display.workInProgressContent.style.display = "none"; - Engine.Display.redPillContent.style.display = "none"; - Engine.Display.cinematicTextContent.style.display = "none"; - Engine.Display.missionContent.style.display = "none"; - }, - - displayCharacterOverviewInfo: function () { - ReactDOM.render( - - saveObject.saveGame(Engine.indexedDb)} /> - , - document.getElementById("character-overview"), - ); - }, - - // Main Game Loop - idleTimer: function () { - // Get time difference - const _thisUpdate = new Date().getTime(); - let diff = _thisUpdate - Engine._lastUpdate; - const offset = diff % Engine._idleSpeed; - - // Divide this by cycle time to determine how many cycles have elapsed since last update - diff = Math.floor(diff / Engine._idleSpeed); - - if (diff > 0) { - // Update the game engine by the calculated number of cycles - Engine._lastUpdate = _thisUpdate - offset; - Player.lastUpdate = _thisUpdate - offset; - Engine.updateGame(diff); - } - - window.requestAnimationFrame(Engine.idleTimer); - }, updateGame: function (numCycles = 1) { - const time = numCycles * Engine._idleSpeed; + const time = numCycles * CONSTANTS._idleSpeed; if (Player.totalPlaytime == null) { Player.totalPlaytime = 0; } @@ -433,7 +75,7 @@ const Engine = { Player.playtimeSinceLastAug += time; Player.playtimeSinceLastBitnode += time; - Terminal.process(Player, numCycles); + Terminal.process(Router, Player, numCycles); // Working if (Player.isWorking) { @@ -581,7 +223,7 @@ const Engine = { } if (Player.bladeburner instanceof Bladeburner) { try { - Player.bladeburner.process(Player); + Player.bladeburner.process(Router, Player); } catch (e) { exceptionAlert("Exception caught in Bladeburner.process(): " + e); } @@ -598,42 +240,11 @@ const Engine = { } }, - /** - * Used in game when clicking on a main menu header (NOT used for initialization) - * @param open {boolean} Whether header is being opened or closed - * @param elems {HTMLElement[]} li Elements under header - * @param links {HTMLElement[]} a elements under header - */ - toggleMainMenuHeader: function (open, elems, links) { - for (var i = 0; i < elems.length; ++i) { - if (open) { - elems[i].style.opacity = 1; - elems[i].style.maxHeight = elems[i].scrollHeight + "px"; - } else { - elems[i].style.opacity = 0; - elems[i].style.maxHeight = null; - } - } - - for (var i = 0; i < links.length; ++i) { - if (open) { - links[i].style.opacity = 1; - links[i].style.maxHeight = links[i].scrollHeight + "px"; - links[i].style.pointerEvents = "auto"; - } else { - links[i].style.opacity = 0; - links[i].style.maxHeight = null; - links[i].style.pointerEvents = "none"; - } - } - }, - load: function (saveString) { // Load game from save or create new game if (loadGame(saveString)) { initBitNodeMultipliers(Player); Engine.setDisplayElements(); // Sets variables for important DOM elements - Engine.init(); // Initialize buttons, work, etc. updateSourceFileFlags(Player); initAugmentations(); // Also calls Player.reapplyAllAugmentations() Player.reapplyAllSourceFiles(); @@ -645,7 +256,7 @@ const Engine = { Engine._lastUpdate = new Date().getTime(); const lastUpdate = Player.lastUpdate; const timeOffline = Engine._lastUpdate - lastUpdate; - const numCyclesOffline = Math.floor(timeOffline / Engine._idleSpeed); + const numCyclesOffline = Math.floor(timeOffline / CONSTANTS._idleSpeed); let offlineReputation = 0; const offlineHackingIncome = (Player.moneySourceA.hacking / Player.playtimeSinceLastAug) * timeOffline * 0.75; @@ -667,6 +278,7 @@ const Engine = { } else { Player.work(numCyclesOffline); } + Player.focus = false; } else { for (let i = 0; i < Player.factions.length; i++) { const facName = Player.factions[i]; @@ -741,7 +353,7 @@ const Engine = { } // Update total playtime - var time = numCyclesOffline * Engine._idleSpeed; + var time = numCyclesOffline * CONSTANTS._idleSpeed; if (Player.totalPlaytime == null) { Player.totalPlaytime = 0; } @@ -794,72 +406,27 @@ const Engine = { }, setDisplayElements: function () { - // Engine.Display.content = document.getElementById("generic-react-container"); - // Engine.Display.content.style.display = "none"; - Engine.Display.missionContent = document.getElementById("mission-container"); Engine.Display.missionContent.style.display = "none"; - - // Work In Progress - Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container"); - Engine.Display.workInProgressContent.style.display = "none"; - - // Red Pill / Hack World Daemon - Engine.Display.redPillContent = document.getElementById("red-pill-container"); - Engine.Display.redPillContent.style.display = "none"; - - Engine.Display.infiltrationContent = document.getElementById("infiltration-container"); - Engine.Display.infiltrationContent.style.display = "none"; - - // Cinematic Text - Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container"); - Engine.Display.cinematicTextContent.style.display = "none"; - - Engine.Display.overview = document.getElementById("character-overview"); - }, - - // Initialization - init: function () { - // Player was working cancel button - - Engine.displayCharacterOverviewInfo(); - if (Player.isWorking) { - var cancelButton = document.getElementById("work-in-progress-cancel-button"); - cancelButton.addEventListener("click", function () { - if (Player.workType == CONSTANTS.WorkTypeFaction) { - Player.finishFactionWork(true); - } else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) { - Player.finishCreateProgramWork(true); - } else if (Player.workType == CONSTANTS.WorkTypeStudyClass) { - Player.finishClass(); - } else if (Player.workType == CONSTANTS.WorkTypeCrime) { - Player.finishCrime(true); - } else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) { - Player.finishWorkPartTime(); - } else { - Player.finishWork(true); - } - }); - - const focusButton = document.getElementById("work-in-progress-something-else-button"); - focusButton.style.visibility = "hidden"; - const focusable = [CONSTANTS.WorkTypeFaction, CONSTANTS.WorkTypeCompanyPartTime, CONSTANTS.WorkTypeCompany]; - if (focusable.includes(Player.workType)) { - focusButton.style.visibility = "visible"; - focusButton.addEventListener("click", function () { - Player.stopFocusing(); - }); - } - - Engine.loadWorkInProgressContent(); - } else { - Engine.loadTerminalContent(); - } }, start: function () { - // Run main loop - Engine.idleTimer(); + // Get time difference + const _thisUpdate = new Date().getTime(); + let diff = _thisUpdate - Engine._lastUpdate; + const offset = diff % CONSTANTS._idleSpeed; + + // Divide this by cycle time to determine how many cycles have elapsed since last update + diff = Math.floor(diff / CONSTANTS._idleSpeed); + + if (diff > 0) { + // Update the game engine by the calculated number of cycles + Engine._lastUpdate = _thisUpdate - offset; + Player.lastUpdate = _thisUpdate - offset; + Engine.updateGame(diff); + } + + window.requestAnimationFrame(Engine.start); }, }; diff --git a/src/index.html b/src/index.html index 00128fd74..dcb03238d 100644 --- a/src/index.html +++ b/src/index.html @@ -45,25 +45,8 @@
    -
    - -
    -

    - - - -
    - - -
    - - -
    -
    @@ -74,9 +57,6 @@
    - -
    -

    diff --git a/src/ui/ActiveScripts/Root.tsx b/src/ui/ActiveScripts/ActiveScriptsRoot.tsx similarity index 100% rename from src/ui/ActiveScripts/Root.tsx rename to src/ui/ActiveScripts/ActiveScriptsRoot.tsx diff --git a/src/ui/Context.ts b/src/ui/Context.ts new file mode 100644 index 000000000..c54b1868a --- /dev/null +++ b/src/ui/Context.ts @@ -0,0 +1,19 @@ +import React, { useContext } from "react"; +import { IPlayer } from "../PersonObjects/IPlayer"; +import { IRouter } from "./Router"; + +export const Context: { + Player: React.Context; + Router: React.Context; +} = { + Player: React.createContext({} as IPlayer), + Router: React.createContext({} as IRouter), +}; + +export const use: { + Player: () => IPlayer; + Router: () => IRouter; +} = { + Player: () => useContext(Context.Player), + Router: () => useContext(Context.Router), +}; diff --git a/src/ui/GameRoot.tsx b/src/ui/GameRoot.tsx index 906535fda..801fa9f57 100644 --- a/src/ui/GameRoot.tsx +++ b/src/ui/GameRoot.tsx @@ -7,11 +7,11 @@ import { installAugmentations } from "../Augmentation/AugmentationHelpers"; import { saveObject } from "../SaveObject"; import { onExport } from "../ExportBonus"; import { LocationName } from "../Locations/data/LocationNames"; -import { CityName } from "../Locations/data/CityNames"; import { Faction } from "../Faction/Faction"; import { prestigeAugmentation } from "../Prestige"; import { dialogBoxCreate } from "../../utils/DialogBox"; import { AllServers } from "../Server/AllServers"; +import { Factions } from "../Faction/Factions"; import { buyStock, sellStock, shortStock, sellShort } from "../StockMarket/BuyingAndSelling"; import { cancelOrder, @@ -29,12 +29,14 @@ import Typography from "@mui/material/Typography"; import { Page, IRouter } from "./Router"; import { SidebarRoot } from "../Sidebar/ui/SidebarRoot"; -import { AugmentationsRoot } from "../Augmentation/ui/Root"; +import { AugmentationsRoot } from "../Augmentation/ui/AugmentationsRoot"; import { DevMenuRoot } from "../DevMenu"; -import { Root as BladeburnerRoot } from "../Bladeburner/ui/Root"; -import { Root as GangRoot } from "../Gang/ui/Root"; +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"; @@ -44,15 +46,20 @@ import { Root as ScriptEditorRoot } from "../ScriptEditor/ui/Root"; import { MilestonesRoot } from "../Milestones/ui/MilestonesRoot"; import { TerminalRoot } from "../Terminal/ui/TerminalRoot"; import { TutorialRoot } from "../Tutorial/ui/TutorialRoot"; -import { ActiveScriptsRoot } from "../ui/ActiveScripts/Root"; +import { ActiveScriptsRoot } from "../ui/ActiveScripts/ActiveScriptsRoot"; import { FactionsRoot } from "../Faction/ui/FactionsRoot"; import { FactionRoot } from "../Faction/ui/FactionRoot"; import { CharacterInfo } from "./CharacterInfo"; import { TravelAgencyRoot } from "../Locations/ui/TravelAgencyRoot"; import { StockMarketRoot } from "../StockMarket/ui/StockMarketRoot"; +import { BitverseRoot } from "../BitNode/ui/BitverseRoot"; +import { CharacterOverview } from "./React/CharacterOverview"; +import { BladeburnerCinematic } from "../Bladeburner/ui/BladeburnerCinematic"; import { workerScripts } from "../Netscript/WorkerScripts"; import { startHackingMission } from "../Faction/FactionHelpers"; +import { enterBitNode } from "../RedPill"; +import { Context } from "./Context"; interface IProps { terminal: ITerminal; @@ -65,6 +72,7 @@ const useStyles = makeStyles((theme: Theme) => root: { "-ms-overflow-style": "none" /* for Internet Explorer, Edge */, "scrollbar-width": "none" /* for Firefox */, + margin: theme.spacing(0), }, }), ); @@ -72,13 +80,111 @@ const useStyles = makeStyles((theme: Theme) => let filename = ""; let code = ""; -export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement { - const contentRef = useRef(null); - const [faction, setFaction] = useState(null); - const [page, setPage] = useState(Page.Terminal); - const classes = useStyles(); +export let Router: IRouter = { + page: () => { + 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"); + }, + toCharacterInfo: () => { + 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"); + }, +}; - const router = { +function determineStartPage(player: IPlayer): Page { + if (player.isWorking) return Page.Work; + return Page.Terminal; +} + +export function GameRoot({ player, engine, terminal }: IProps): React.ReactElement { + const classes = useStyles(); + const contentRef = useRef(null); + const [faction, setFaction] = useState( + player.currentWorkFactionName ? Factions[player.currentWorkFactionName] : null, + ); + const [page, setPage] = useState(determineStartPage(player)); + + const [flume, setFlume] = useState(false); + const [quick, setQuick] = useState(false); + const [location, setLocation] = useState(LocationName.Sector12); + + const [cinematicText, setCinematicText] = useState(""); + + Router = { + page: () => page, toActiveScripts: () => setPage(Page.ActiveScripts), toAugmentations: () => setPage(Page.Augmentations), toBladeburner: () => setPage(Page.Bladeburner), @@ -86,9 +192,9 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme toCorporation: () => setPage(Page.Corporation), toCreateProgram: () => setPage(Page.CreateProgram), toDevMenu: () => setPage(Page.DevMenu), - toFaction: (faction: Faction) => { + toFaction: (faction?: Faction) => { setPage(Page.Faction); - setFaction(faction); + if (faction) setFaction(faction); }, toFactions: () => setPage(Page.Factions), toGameOptions: () => setPage(Page.Options), @@ -110,7 +216,7 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme setPage(Page.Job); }, toCity: () => { - // TODO This is bad. + // TODO This conversion is bad. player.gotoLocation(player.city as unknown as LocationName); setPage(Page.City); }, @@ -118,6 +224,20 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme player.gotoLocation(LocationName.TravelAgency); setPage(Page.Travel); }, + toBitVerse: (flume: boolean, quick: boolean) => { + setFlume(flume); + setQuick(quick); + setPage(Page.BitVerse); + }, + toInfiltration: (location: LocationName) => { + setLocation(location); + setPage(Page.Infiltration); + }, + toWork: () => setPage(Page.Work), + toBladeburnerCinematic: () => { + setPage(Page.BladeburnerCinematic); + setCinematicText(cinematicText); + }, }; useEffect(() => { @@ -126,94 +246,119 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme }); return ( - <> - - - - {page === Page.Terminal ? ( - - ) : page === Page.Sleeves ? ( - - ) : page === Page.Stats ? ( - - ) : page === Page.CreateScript ? ( - - ) : page === Page.ActiveScripts ? ( - - ) : page === Page.Hacknet ? ( - - ) : page === Page.CreateProgram ? ( - - ) : page === Page.Factions ? ( - - ) : page === Page.Faction ? ( - - ) : page === Page.Milestones ? ( - - ) : page === Page.Tutorial ? ( - - ) : page === Page.DevMenu ? ( - - ) : page === Page.Gang ? ( - - ) : page === Page.Corporation ? ( - - ) : page === Page.Bladeburner ? ( - - ) : page === Page.Resleeves ? ( - - ) : page === Page.Travel ? ( - - ) : page === Page.StockMarket ? ( - - ) : page === Page.City ? ( - - ) : page === Page.Job ? ( - - ) : page === Page.Options ? ( - saveObject.saveGame(engine.indexedDb)} - delete={() => saveObject.deleteGame(engine.indexedDb)} - export={() => saveObject.exportGame()} - import={() => saveObject.importGame()} - forceKill={() => { - for (const hostname of Object.keys(AllServers)) { - AllServers[hostname].runningScripts = []; - } - dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page."); - }} - softReset={() => { - dialogBoxCreate("Soft Reset!"); - prestigeAugmentation(); - }} - /> - ) : page === Page.Augmentations ? ( - { - saveObject.exportGame(); - onExport(player); - }} - installAugmentationsFn={installAugmentations} - /> - ) : ( - <> - Cannot load - - )} - - - + + + saveObject.saveGame(engine.indexedDb)} /> + {page === Page.BitVerse ? ( + + ) : page === Page.Infiltration ? ( + + ) : page === Page.BladeburnerCinematic ? ( + + ) : page === Page.Work ? ( + + ) : ( + + + + {page === Page.Terminal ? ( + + ) : page === Page.Sleeves ? ( + + ) : page === Page.Stats ? ( + + ) : page === Page.CreateScript ? ( + + ) : page === Page.ActiveScripts ? ( + + ) : page === Page.Hacknet ? ( + + ) : page === Page.CreateProgram ? ( + + ) : page === Page.Factions ? ( + + ) : page === Page.Faction ? ( + + ) : page === Page.Milestones ? ( + + ) : page === Page.Tutorial ? ( + + ) : page === Page.DevMenu ? ( + + ) : page === Page.Gang ? ( + + ) : page === Page.Corporation ? ( + + ) : page === Page.Bladeburner ? ( + + ) : page === Page.Resleeves ? ( + + ) : page === Page.Travel ? ( + + ) : page === Page.StockMarket ? ( + + ) : page === Page.City ? ( + + ) : page === Page.Job ? ( + + ) : page === Page.Options ? ( + saveObject.saveGame(engine.indexedDb)} + delete={() => saveObject.deleteGame(engine.indexedDb)} + export={() => saveObject.exportGame()} + import={() => saveObject.importGame()} + forceKill={() => { + for (const hostname of Object.keys(AllServers)) { + AllServers[hostname].runningScripts = []; + } + dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page."); + }} + softReset={() => { + dialogBoxCreate("Soft Reset!"); + prestigeAugmentation(); + Router.toTerminal(); + }} + /> + ) : page === Page.Augmentations ? ( + { + saveObject.exportGame(); + onExport(player); + }} + installAugmentationsFn={() => { + installAugmentations(); + Router.toTerminal(); + }} + /> + ) : ( + <> + Cannot load + + )} + + + )} + + ); } diff --git a/src/ui/React/CharacterOverview.tsx b/src/ui/React/CharacterOverview.tsx index db855eb20..1daecd9d8 100644 --- a/src/ui/React/CharacterOverview.tsx +++ b/src/ui/React/CharacterOverview.tsx @@ -2,20 +2,16 @@ import React, { useState, useEffect } from "react"; import makeStyles from "@mui/styles/makeStyles"; -import { IPlayer } from "../../PersonObjects/IPlayer"; import { numeralWrapper } from "../../ui/numeralFormat"; import { Reputation } from "./Reputation"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; -import TableContainer from "@mui/material/TableContainer"; -import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import Paper from "@mui/material/Paper"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; -import Divider from "@mui/material/Divider"; import Button from "@mui/material/Button"; import Collapse from "@mui/material/Collapse"; import Fab from "@mui/material/Fab"; @@ -23,15 +19,17 @@ import VisibilityOffIcon from "@mui/icons-material/VisibilityOff"; import { colors } from "./Theme"; import { Settings } from "../../Settings/Settings"; +import { use } from "../../ui/Context"; +import { Page } from "../../ui/Router"; interface IProps { - player: IPlayer; save: () => void; } -function Intelligence({ player }: { player: IPlayer }): React.ReactElement { - if (player.intelligence === 0) return <>; +function Intelligence(): React.ReactElement { + const player = use.Player(); const classes = useStyles(); + if (player.intelligence === 0) return <>; return ( @@ -44,9 +42,11 @@ function Intelligence({ player }: { player: IPlayer }): React.ReactElement { ); } -function Work({ player }: { player: IPlayer }): React.ReactElement { - if (!player.isWorking || player.focus) return <>; +function Work(): React.ReactElement { + const player = use.Player(); + const router = use.Router(); const classes = useStyles(); + if (!player.isWorking || player.focus) return <>; return ( <> @@ -61,7 +61,14 @@ function Work({ player }: { player: IPlayer }): React.ReactElement { - + @@ -101,7 +108,12 @@ const useStyles = makeStyles({ }, }); -export function CharacterOverview({ player, save }: IProps): React.ReactElement { +export function CharacterOverview({ save }: IProps): React.ReactElement { + const player = use.Player(); + const router = use.Router(); + + if (router.page() === Page.BitVerse) return <>; + const setRerender = useState(false)[1]; const [open, setOpen] = useState(true); @@ -112,7 +124,7 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement const classes = useStyles(); return ( - <> +
    @@ -205,8 +217,8 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement - - + + @@ -226,6 +238,6 @@ export function CharacterOverview({ player, save }: IProps): React.ReactElement - +
    ); } diff --git a/src/ui/React/CinematicText.tsx b/src/ui/React/CinematicText.tsx index b1a343eb0..909972d23 100644 --- a/src/ui/React/CinematicText.tsx +++ b/src/ui/React/CinematicText.tsx @@ -4,24 +4,34 @@ import { CinematicLine } from "./CinematicLine"; interface IProps { lines: string[]; + auto?: boolean; onDone?: () => void; } export function CinematicText(props: IProps): React.ReactElement { const [i, setI] = useState(0); + const [done, setDone] = useState(false); function advance(): void { const newI = i + 1; setI(newI); - if (newI >= props.lines.length && props.onDone) props.onDone(); + if (newI >= props.lines.length) { + if (props.onDone && props.auto) props.onDone(); + setDone(true); + } } return ( - <> +
    {props.lines.slice(0, i).map((line, i) => (
    {line}
    ))} {props.lines.length > i && } - + {!props.auto && props.onDone && done && ( + + )} +
    ); } diff --git a/src/ui/React/GameOptionsRoot.tsx b/src/ui/React/GameOptionsRoot.tsx index 647e1ef9f..d24ccf65e 100644 --- a/src/ui/React/GameOptionsRoot.tsx +++ b/src/ui/React/GameOptionsRoot.tsx @@ -28,12 +28,9 @@ const useStyles = makeStyles((theme: Theme) => createStyles({ root: { width: 50, - padding: 2, + padding: theme.spacing(2), userSelect: "none", }, - pad: { - padding: 2, - }, }), ); diff --git a/src/ui/React/Theme.tsx b/src/ui/React/Theme.tsx index 674da72e8..eb9ded35f 100644 --- a/src/ui/React/Theme.tsx +++ b/src/ui/React/Theme.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { createTheme, ThemeProvider, Theme, StyledEngineProvider, adaptV4Theme } from "@mui/material/styles"; +import { createTheme, ThemeProvider, Theme, StyledEngineProvider } from "@mui/material/styles"; declare module "@mui/styles/defaultTheme" { // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/src/ui/Router.ts b/src/ui/Router.ts index 58ad8732b..9fef28385 100644 --- a/src/ui/Router.ts +++ b/src/ui/Router.ts @@ -1,4 +1,5 @@ import { Faction } from "../Faction/Faction"; +import { LocationName } from "../Locations/data/LocationNames"; /** * The full-screen page the player is currently be on. * These pages are mutually exclusive. @@ -6,26 +7,30 @@ import { Faction } from "../Faction/Faction"; export enum Page { ActiveScripts, Augmentations, + BitVerse, Bladeburner, - Stats, City, Corporation, CreateProgram, + CreateScript, DevMenu, Faction, Factions, - Options, Gang, Hacknet, + Infiltration, Job, Milestones, + Options, Resleeves, - CreateScript, Sleeves, + Stats, StockMarket, Terminal, Travel, Tutorial, + Work, + BladeburnerCinematic, } /** @@ -37,19 +42,22 @@ export interface IRouter { // toMission(): void; // toRedPill(): void; // toworkInProgress(): void; + page(): Page; toActiveScripts(): void; toAugmentations(): void; + toBitVerse(flume: boolean, quick: boolean): void; toBladeburner(): void; toCharacterInfo(): void; + toCity(): void; // travel ? city ? toCorporation(): void; toCreateProgram(): void; toDevMenu(): void; - toFaction(faction: Faction): void; // faction name + toFaction(faction?: Faction): void; // faction name toFactions(): void; toGameOptions(): void; toGang(): void; toHacknetNodes(): void; - toCity(): void; // travel ? city ? + toInfiltration(location: LocationName): void; toJob(): void; toMilestones(): void; toResleeves(): void; @@ -59,4 +67,6 @@ export interface IRouter { toTerminal(): void; toTravel(): void; toTutorial(): void; + toWork(): void; + toBladeburnerCinematic(): void; } diff --git a/src/ui/WorkInProgressRoot.tsx b/src/ui/WorkInProgressRoot.tsx new file mode 100644 index 000000000..54b1e9d4d --- /dev/null +++ b/src/ui/WorkInProgressRoot.tsx @@ -0,0 +1,336 @@ +import React, { useState, useEffect } from "react"; +import { use } from "./Context"; +import { CONSTANTS } from "../Constants"; +import { numeralWrapper } from "./numeralFormat"; +import { Reputation } from "./React/Reputation"; +import { ReputationRate } from "./React/ReputationRate"; +import { MoneyRate } from "./React/MoneyRate"; +import { Money } from "./React/Money"; +import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions"; +import { Factions } from "../Faction/Factions"; +import { Company } from "../Company/Company"; +import { Companies } from "../Company/Companies"; +import { createProgressBarText } from "../../utils/helpers/createProgressBarText"; + +const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; + +export function WorkInProgressRoot(): React.ReactElement { + const setRerender = useState(false)[1]; + function rerender(): void { + setRerender((old) => !old); + } + + useEffect(() => { + const id = setInterval(rerender, CONSTANTS.MilliPerCycle); + return () => clearInterval(id); + }, []); + const player = use.Player(); + const router = use.Router(); + const faction = Factions[player.currentWorkFactionName]; + if (player.workType == CONSTANTS.WorkTypeFaction) { + function cancel(): void { + router.toFaction(); + player.finishFactionWork(true); + } + function unfocus(): void { + router.toFaction(); + player.stopFocusing(); + } + return ( +
    +

    + You are currently {player.currentWorkFactionDescription} for your faction {faction.name} +
    + (Current Faction Reputation: {Reputation(faction.playerReputation)}).
    + You have been doing this for {convertTimeMsToTimeElapsedString(player.timeWorked)} +
    +
    + You have earned:
    +
    + ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)})
    +
    + {Reputation(player.workRepGained)} ({ReputationRate(player.workRepGainRate * CYCLES_PER_SEC)}) reputation for + this faction
    +
    + {numeralWrapper.formatExp(player.workHackExpGained)} ( + {numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp
    +
    + {numeralWrapper.formatExp(player.workStrExpGained)} ( + {numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp
    + {numeralWrapper.formatExp(player.workDefExpGained)} ( + {numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp
    + {numeralWrapper.formatExp(player.workDexExpGained)} ( + {numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp
    + {numeralWrapper.formatExp(player.workAgiExpGained)} ( + {numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp
    +
    + {numeralWrapper.formatExp(player.workChaExpGained)} ( + {numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp
    +
    + You will automatically finish after working for 20 hours. You can cancel earlier if you wish. +
    + There is no penalty for cancelling earlier. +

    + + + +
    + ); + } + + const className = player.className; + if (player.className !== "") { + function cancel(): void { + player.finishClass(true); + router.toCity(); + } + function unfocus(): void { + player.stopFocusing(); + router.toCity(); + } + + let stopText = ""; + if ( + className == CONSTANTS.ClassGymStrength || + className == CONSTANTS.ClassGymDefense || + className == CONSTANTS.ClassGymDexterity || + className == CONSTANTS.ClassGymAgility + ) { + stopText = "Stop training at gym"; + } else { + stopText = "Stop taking course"; + } + + return ( +
    +

    + You have been {className} for {convertTimeMsToTimeElapsedString(player.timeWorked)} +
    +
    + This has cost you:
    + ({MoneyRate(player.workMoneyLossRate * CYCLES_PER_SEC)})
    +
    + You have gained:
    + {numeralWrapper.formatExp(player.workHackExpGained)} ( + {numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec) hacking exp
    + {numeralWrapper.formatExp(player.workStrExpGained)} ( + {numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec) strength exp
    + {numeralWrapper.formatExp(player.workDefExpGained)} ( + {numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec) defense exp
    + {numeralWrapper.formatExp(player.workDexExpGained)} ( + {numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec) dexterity exp
    + {numeralWrapper.formatExp(player.workAgiExpGained)} ( + {numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec) agility exp
    + {numeralWrapper.formatExp(player.workChaExpGained)} ( + {numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec) charisma exp
    + You may cancel at any time +

    + + + +
    + ); + } + + if (player.workType == CONSTANTS.WorkTypeCompany) { + const comp = Companies[player.companyName]; + let companyRep = 0; + if (comp == null || !(comp instanceof Company)) { + throw new Error(`Could not find Company: ${player.companyName}`); + } + companyRep = comp.playerReputation; + + function cancel(): void { + player.finishWork(true); + router.toJob(); + } + function unfocus(): void { + player.stopFocusing(); + router.toJob(); + } + + const position = player.jobs[player.companyName]; + + const penalty = player.cancelationPenalty(); + + const penaltyString = penalty === 0.5 ? "half" : "three-quarters"; + return ( +
    +

    + You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "} + {Reputation(companyRep)})
    +
    + You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)} +
    +
    + You have earned:
    +
    + ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)})
    +
    + {Reputation(player.workRepGained)} ({ReputationRate(player.workRepGainRate * CYCLES_PER_SEC)}) reputation for + this company
    +
    + {numeralWrapper.formatExp(player.workHackExpGained)} ( + {`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`} + ) hacking exp
    +
    + {numeralWrapper.formatExp(player.workStrExpGained)} ( + {`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`} + ) strength exp
    + {numeralWrapper.formatExp(player.workDefExpGained)} ( + {`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`} + ) defense exp
    + {numeralWrapper.formatExp(player.workDexExpGained)} ( + {`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`} + ) dexterity exp
    + {numeralWrapper.formatExp(player.workAgiExpGained)} ( + {`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`} + ) agility exp
    +
    + {numeralWrapper.formatExp(player.workChaExpGained)} ( + {`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`} + ) charisma exp
    +
    + You will automatically finish after working for 8 hours. You can cancel earlier if you wish, but you will only + gain {penaltyString} of the reputation you've earned so far. +

    + + + +
    + ); + } + + if (player.workType == CONSTANTS.WorkTypeCompanyPartTime) { + function cancel(): void { + player.finishWork(true); + router.toJob(); + } + function unfocus(): void { + player.stopFocusing(); + router.toJob(); + } + const comp = Companies[player.companyName]; + let companyRep = 0; + if (comp == null || !(comp instanceof Company)) { + throw new Error(`Could not find Company: ${player.companyName}`); + } + companyRep = comp.playerReputation; + + const position = player.jobs[player.companyName]; + return ( +
    +

    + You are currently working as a {position} at {player.companyName} (Current Company Reputation:{" "} + {Reputation(companyRep)})
    +
    + You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)} +
    +
    + You have earned:
    +
    + ({MoneyRate(player.workMoneyGainRate * CYCLES_PER_SEC)})
    +
    + {Reputation(player.workRepGained)} ( + {Reputation(`${numeralWrapper.formatExp(player.workRepGainRate * CYCLES_PER_SEC)} / sec`)} + ) reputation for this company
    +
    + {numeralWrapper.formatExp(player.workHackExpGained)} ( + {`${numeralWrapper.formatExp(player.workHackExpGainRate * CYCLES_PER_SEC)} / sec`} + ) hacking exp
    +
    + {numeralWrapper.formatExp(player.workStrExpGained)} ( + {`${numeralWrapper.formatExp(player.workStrExpGainRate * CYCLES_PER_SEC)} / sec`} + ) strength exp
    + {numeralWrapper.formatExp(player.workDefExpGained)} ( + {`${numeralWrapper.formatExp(player.workDefExpGainRate * CYCLES_PER_SEC)} / sec`} + ) defense exp
    + {numeralWrapper.formatExp(player.workDexExpGained)} ( + {`${numeralWrapper.formatExp(player.workDexExpGainRate * CYCLES_PER_SEC)} / sec`} + ) dexterity exp
    + {numeralWrapper.formatExp(player.workAgiExpGained)} ( + {`${numeralWrapper.formatExp(player.workAgiExpGainRate * CYCLES_PER_SEC)} / sec`} + ) agility exp
    +
    + {numeralWrapper.formatExp(player.workChaExpGained)} ( + {`${numeralWrapper.formatExp(player.workChaExpGainRate * CYCLES_PER_SEC)} / sec`} + ) charisma exp
    +
    + You will automatically finish after working for 8 hours. You can cancel earlier if you wish, and there will be + no penalty because this is a part-time job. +

    + + + +
    + ); + } + + if (player.crimeType !== "") { + const percent = Math.round((player.timeWorked / player.timeNeededToCompleteWork) * 100); + let numBars = Math.round(percent / 5); + if (numBars < 0) { + numBars = 0; + } + if (numBars > 20) { + numBars = 20; + } + // const progressBar = "[" + Array(numBars + 1).join("|") + Array(20 - numBars + 1).join(" ") + "]"; + const progressBar = createProgressBarText({ progress: (numBars + 1) / 20, totalTicks: 20 }); + + return ( +
    +

    You are attempting to {player.crimeType}.

    +
    + +

    Time remaining: {convertTimeMsToTimeElapsedString(player.timeNeededToCompleteWork - player.timeWorked)}

    + +
    +
    {progressBar}
    + + +
    + ); + } + + if (player.createProgramName !== "") { + return ( +
    +

    + You are currently working on coding {player.createProgramName}.
    +
    + You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)} +
    +
    + The program is {((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)} + % complete.
    + If you cancel, your work will be saved and you can come back to complete the program later. +

    + +
    + ); + } + + setTimeout(() => router.toCity(), 50); + return <>; +}