This commit is contained in:
Olivier Gagnon 2021-09-17 02:04:44 -04:00
parent ff726afcd6
commit acd51e8328
22 changed files with 724 additions and 450 deletions

@ -6,7 +6,6 @@
.active-scripts-container {
> p {
width: 70%;
margin: 6px;
padding: 4px;
}

@ -8,7 +8,6 @@
.augmentations-content {
> p {
font-size: $defaultFontSize * 0.875;
width: 70%;
}
}

@ -7,7 +7,6 @@
.hacknet-general-info {
margin: 10px;
width: 70vw;
}
#hacknet-nodes-container li {

@ -1 +1,2 @@
export declare function isRepeatableAug(aug: Augmentation): boolean;
export declare function installAugmentations(): void;

@ -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;

@ -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";

@ -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<IProps, IState> {
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<IProps, IState> {
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<IProps, IState> {
}
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<IProps, IState> {
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<IProps, IState> {
)}
{!isPlayersGang && factionInfo.offersWork() && (
<DonateOption
faction={this.props.faction}
faction={this.state.faction}
p={this.props.p}
rerender={this.rerender}
favorToDonate={favorToDonate}
@ -222,7 +224,7 @@ export class FactionRoot extends React.Component<IProps, IState> {
renderAugmentationsPage(): React.ReactNode {
return (
<>
<AugmentationsPage faction={this.props.faction} p={this.props.p} routeToMainPage={this.routeToMain} />
<AugmentationsPage faction={this.state.faction} p={this.props.p} routeToMainPage={this.routeToMain} />
</>
);
}

@ -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<HTMLElement>, faction: string): void {
@ -33,7 +33,7 @@ export function FactionList(props: IProps): React.ReactElement {
<li key={faction}>
<a
className="a-link-button"
onClick={() => openFaction(faction)}
onClick={() => openFaction(Factions[faction])}
style={{ padding: "4px", margin: "4px", display: "inline-block" }}
>
{faction}

@ -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;
}

@ -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<IProps, any> {
}
if (this.props.loc.types.includes(LocationType.TravelAgency)) {
content.push(<TravelAgencyLocation key={"travelagencylocation"} p={this.props.p} travel={this.props.travel} />);
content.push(<TravelAgencyRoot key={"travelagencylocation"} p={this.props.p} router={this.props.router} />);
}
if (this.props.loc.types.includes(LocationType.University)) {

@ -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<IProps, IState> {
}
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<IProps, IState> {
return (
<GenericLocation
engine={this.props.engine}
router={this.props.router}
loc={loc}
p={this.props.p}
returnToCity={this.returnToCity}

@ -10,28 +10,43 @@ import { TravelConfirmationPopup } from "./TravelConfirmationPopup";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IRouter } from "../../ui/Router";
import { Settings } from "../../Settings/Settings";
import { StdButton } from "../../ui/React/StdButton";
import { createPopup } from "../../ui/React/createPopup";
import { Money } from "../../ui/React/Money";
import { WorldMap } from "../../ui/React/WorldMap";
import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
p: IPlayer;
travel: (to: CityName) => 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(<span className="noselect">You are now in {to}!</span>);
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 {
</p>
<WorldMap
currentCity={props.p.city}
onTravel={(city: CityName) => createTravelPopup(props.p, city, () => props.travel(city))}
onTravel={(city: CityName) => createTravelPopup(props.p, props.router, city)}
/>
</div>
);
@ -66,7 +81,7 @@ function ListWorldMap(props: IProps): React.ReactElement {
return (
<StdButton
key={city}
onClick={() => 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 <ListWorldMap p={props.p} travel={props.travel} />;
} else {
return <ASCIIWorldMap p={props.p} travel={props.travel} />;
}
export function TravelAgencyRoot(props: IProps): React.ReactElement {
return (
<>
<h1>Travel Agency</h1>
{Settings.DisableASCIIArt ? (
<ListWorldMap p={props.p} router={props.router} />
) : (
<ASCIIWorldMap p={props.p} router={props.router} />
)}
</>
);
}

@ -20,7 +20,7 @@ export function SleeveRoot(props: IProps): React.ReactElement {
}, []);
return (
<div style={{ width: "70%" }}>
<>
<h1>Sleeves</h1>
<p>
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 {
</li>
))}
</ul>
</div>
</>
);
}

2
src/Prestige.d.ts vendored Normal file

@ -0,0 +1,2 @@
export declare function prestigeAugmentation(): void;
export declare function prestigeSourceFile(flume: boolean): void;

@ -308,7 +308,7 @@ export function Root(props: IProps): React.ReactElement {
}
return (
<div className="script-editor-wrapper">
<>
<div id="script-editor-filename-wrapper">
<p id="script-editor-filename-tag" className="noselect">
{" "}
@ -328,7 +328,7 @@ export function Root(props: IProps): React.ReactElement {
beforeMount={beforeMount}
onMount={onMount}
loading={<p>Loading script editor!</p>}
height="80%"
height="90%"
defaultLanguage="javascript"
defaultValue={code}
onChange={updateCode}
@ -352,6 +352,6 @@ export function Root(props: IProps): React.ReactElement {
Netscript Documentation
</a>
</div>
</div>
</>
);
}

@ -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 (
<BBTheme>
<Drawer open={open} anchor="left" variant="permanent">
<ListItem classes={{ root: classes.listitem }} button onClick={toggleDrawer}>
<Drawer open={open} anchor="left" variant="permanent">
<ListItem classes={{ root: classes.listitem }} button onClick={toggleDrawer}>
<ListItemIcon>
{!open ? <ChevronRightIcon color={"primary"} /> : <ChevronLeftIcon color={"primary"} />}
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Bitburner v{CONSTANTS.Version}</Typography>} />
</ListItem>
<Divider />
<List>
<ListItem classes={{ root: classes.listitem }} button onClick={() => setHackingOpen((old) => !old)}>
<ListItemIcon>
{!open ? <ChevronRightIcon color={"primary"} /> : <ChevronLeftIcon color={"primary"} />}
<ComputerIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Bitburner v{CONSTANTS.Version}</Typography>} />
<ListItemText primary={<Typography color="primary">Hacking</Typography>} />
{hackingOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Divider />
<List>
<ListItem classes={{ root: classes.listitem }} button onClick={() => setHackingOpen((old) => !old)}>
<ListItemIcon>
<ComputerIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Hacking</Typography>} />
{hackingOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Collapse in={hackingOpen} timeout="auto" unmountOnExit>
<List>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Terminal"}
className={clsx({
[classes.active]: activeTab === "Terminal",
})}
onClick={clickTerminal}
>
<ListItemIcon>
<LastPageIcon color={flashTerminal ? "error" : activeTab !== "Terminal" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashTerminal ? "error" : activeTab !== "Terminal" ? "secondary" : "primary"}>
Terminal
</Typography>
</ListItemText>
</ListItem>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Create Scripts"}
className={clsx({
[classes.active]: activeTab === "CreateScripts",
})}
onClick={clickCreateScripts}
>
<ListItemIcon>
<CreateIcon color={activeTab !== "CreateScripts" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "CreateScripts" ? "secondary" : "primary"}>Create Script</Typography>
</ListItemText>
</ListItem>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Active Scripts"}
className={clsx({
[classes.active]: activeTab === "ActiveScripts",
})}
onClick={clickActiveScripts}
>
<ListItemIcon>
<StorageIcon
color={flashActiveScripts ? "error" : activeTab !== "ActiveScripts" ? "secondary" : "primary"}
/>
</ListItemIcon>
<ListItemText>
<Typography
color={flashActiveScripts ? "error" : activeTab !== "ActiveScripts" ? "secondary" : "primary"}
>
Active Scripts
</Typography>
</ListItemText>
</ListItem>
{canCreateProgram && (
<ListItem
button
key={"Create Program"}
className={clsx({
[classes.active]: activeTab === "CreateProgram",
})}
onClick={clickCreateProgram}
<Collapse in={hackingOpen} timeout="auto" unmountOnExit>
<List>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Terminal"}
className={clsx({
[classes.active]: props.page === Page.Terminal,
})}
onClick={clickTerminal}
>
<ListItemIcon>
<LastPageIcon
color={flashTerminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}
/>
</ListItemIcon>
<ListItemText>
<Typography color={flashTerminal ? "error" : props.page !== Page.Terminal ? "secondary" : "primary"}>
Terminal
</Typography>
</ListItemText>
</ListItem>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Create Scripts"}
className={clsx({
[classes.active]: props.page === Page.CreateScript,
})}
onClick={clickCreateScripts}
>
<ListItemIcon>
<CreateIcon color={props.page !== Page.CreateScript ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.CreateScript ? "secondary" : "primary"}>
Create Script
</Typography>
</ListItemText>
</ListItem>
<ListItem
classes={{ root: classes.listitem }}
button
key={"Active Scripts"}
className={clsx({
[classes.active]: props.page === Page.ActiveScripts,
})}
onClick={clickActiveScripts}
>
<ListItemIcon>
<StorageIcon
color={flashActiveScripts ? "error" : props.page !== Page.ActiveScripts ? "secondary" : "primary"}
/>
</ListItemIcon>
<ListItemText>
<Typography
color={flashActiveScripts ? "error" : props.page !== Page.ActiveScripts ? "secondary" : "primary"}
>
<ListItemIcon>
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
<BugReportIcon color={activeTab !== "CreateProgram" ? "secondary" : "primary"} />
</Badge>
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "CreateProgram" ? "secondary" : "primary"}>
Create Program
</Typography>
</ListItemText>
</ListItem>
)}
</List>
</Collapse>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setCharacterOpen((old) => !old)}>
<ListItemIcon>
<AccountBoxIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Character</Typography>} />
{characterOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Collapse in={characterOpen} timeout="auto" unmountOnExit>
<ListItem
button
key={"Stats"}
className={clsx({
[classes.active]: activeTab === "Stats",
})}
onClick={clickStats}
>
<ListItemIcon>
<EqualizerIcon color={flashStats ? "error" : activeTab !== "Stats" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashStats ? "error" : activeTab !== "Stats" ? "secondary" : "primary"}>
Stats
Active Scripts
</Typography>
</ListItemText>
</ListItem>
{canOpenFactions && (
{canCreateProgram && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Factions"}
key={"Create Program"}
className={clsx({
[classes.active]: activeTab === "Factions",
[classes.active]: props.page === Page.CreateProgram,
})}
onClick={clickFactions}
onClick={clickCreateProgram}
>
<ListItemIcon>
<Badge badgeContent={invitationsCount !== 0 ? invitationsCount : undefined} color="error">
<ContactsIcon color={activeTab !== "Factions" ? "secondary" : "primary"} />
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
</Badge>
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Factions" ? "secondary" : "primary"}>Factions</Typography>
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
Create Program
</Typography>
</ListItemText>
</ListItem>
)}
{canOpenAugmentations && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Augmentations"}
className={clsx({
[classes.active]: activeTab === "Augmentations",
})}
onClick={clickAugmentations}
>
<ListItemIcon>
<Badge badgeContent={augmentationCount !== 0 ? augmentationCount : undefined} color="error">
<DoubleArrowIcon
style={{ transform: "rotate(-90deg)" }}
color={activeTab !== "Augmentations" ? "secondary" : "primary"}
/>
</Badge>
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Augmentations" ? "secondary" : "primary"}>Augmentations</Typography>
</ListItemText>
</ListItem>
)}
<ListItem
button
key={"Hacknet"}
className={clsx({
[classes.active]: activeTab === "Hacknet",
})}
onClick={clickHacknet}
>
<ListItemIcon>
<AccountTreeIcon color={flashHacknet ? "error" : activeTab !== "Hacknet" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashHacknet ? "error" : activeTab !== "Hacknet" ? "secondary" : "primary"}>
Hacknet
</Typography>
</ListItemText>
</ListItem>
{canOpenSleeves && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Sleeves"}
className={clsx({
[classes.active]: activeTab === "Sleeves",
})}
onClick={clickSleeves}
>
<ListItemIcon>
<PeopleAltIcon color={activeTab !== "Sleeves" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Sleeves" ? "secondary" : "primary"}>Sleeves</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
</List>
</Collapse>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setWorldOpen((old) => !old)}>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setCharacterOpen((old) => !old)}>
<ListItemIcon>
<AccountBoxIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Character</Typography>} />
{characterOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Collapse in={characterOpen} timeout="auto" unmountOnExit>
<ListItem
button
key={"Stats"}
className={clsx({
[classes.active]: props.page === Page.Stats,
})}
onClick={clickStats}
>
<ListItemIcon>
<PublicIcon color={"primary"} />
<EqualizerIcon color={flashStats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">World</Typography>} />
{worldOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
<ListItemText>
<Typography color={flashStats ? "error" : props.page !== Page.Stats ? "secondary" : "primary"}>
Stats
</Typography>
</ListItemText>
</ListItem>
<Collapse in={worldOpen} timeout="auto" unmountOnExit>
{canOpenFactions && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"City"}
key={"Factions"}
className={clsx({
[classes.active]: activeTab === "City",
[classes.active]: [Page.Factions, Page.Faction].includes(props.page),
})}
onClick={clickCity}
onClick={clickFactions}
>
<ListItemIcon>
<LocationCityIcon color={flashCity ? "error" : activeTab !== "City" ? "secondary" : "primary"} />
<Badge badgeContent={invitationsCount !== 0 ? invitationsCount : undefined} color="error">
<ContactsIcon color={![Page.Factions, Page.Faction].includes(props.page) ? "secondary" : "primary"} />
</Badge>
</ListItemIcon>
<ListItemText>
<Typography color={flashCity ? "error" : activeTab !== "City" ? "secondary" : "primary"}>
City
<Typography color={![Page.Factions, Page.Faction].includes(props.page) ? "secondary" : "primary"}>
Factions
</Typography>
</ListItemText>
</ListItem>
)}
{canOpenAugmentations && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Travel"}
key={"Augmentations"}
className={clsx({
[classes.active]: activeTab === "Travel",
[classes.active]: props.page === Page.Augmentations,
})}
onClick={clickTravel}
onClick={clickAugmentations}
>
<ListItemIcon>
<AirplanemodeActiveIcon color={activeTab !== "Travel" ? "secondary" : "primary"} />
<Badge badgeContent={augmentationCount !== 0 ? augmentationCount : undefined} color="error">
<DoubleArrowIcon
style={{ transform: "rotate(-90deg)" }}
color={props.page !== Page.Augmentations ? "secondary" : "primary"}
/>
</Badge>
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Travel" ? "secondary" : "primary"}>Travel</Typography>
<Typography color={props.page !== Page.Augmentations ? "secondary" : "primary"}>
Augmentations
</Typography>
</ListItemText>
</ListItem>
{canJob && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Job"}
className={clsx({
[classes.active]: activeTab === "Job",
})}
onClick={clickJob}
>
<ListItemIcon>
<WorkIcon color={activeTab !== "Job" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Job" ? "secondary" : "primary"}>Job</Typography>
</ListItemText>
</ListItem>
)}
{canStockMarket && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Stock Market"}
className={clsx({
[classes.active]: activeTab === "StockMarket",
})}
onClick={clickStockMarket}
>
<ListItemIcon>
<TrendingUpIcon color={activeTab !== "StockMarket" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "StockMarket" ? "secondary" : "primary"}>Stock Market</Typography>
</ListItemText>
</ListItem>
)}
{canBladeburner && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Bladeburner"}
className={clsx({
[classes.active]: activeTab === "Bladeburner",
})}
onClick={clickBladeburner}
>
<ListItemIcon>
<FormatBoldIcon color={activeTab !== "Bladeburner" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Bladeburner" ? "secondary" : "primary"}>Bladeburner</Typography>
</ListItemText>
</ListItem>
)}
{canCorporation && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Corp"}
className={clsx({
[classes.active]: activeTab === "Corp",
})}
onClick={clickCorp}
>
<ListItemIcon>
<BusinessIcon color={activeTab !== "Corp" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Corp" ? "secondary" : "primary"}>Corp</Typography>
</ListItemText>
</ListItem>
)}
{canGang && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Gang"}
className={clsx({
[classes.active]: activeTab === "Gang",
})}
onClick={clickGang}
>
<ListItemIcon>
<SportsMmaIcon color={activeTab !== "Gang" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Gang" ? "secondary" : "primary"}>Gang</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
)}
<ListItem
button
key={"Hacknet"}
className={clsx({
[classes.active]: props.page === Page.Hacknet,
})}
onClick={clickHacknet}
>
<ListItemIcon>
<AccountTreeIcon color={flashHacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashHacknet ? "error" : props.page !== Page.Hacknet ? "secondary" : "primary"}>
Hacknet
</Typography>
</ListItemText>
</ListItem>
{canOpenSleeves && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Sleeves"}
className={clsx({
[classes.active]: props.page === Page.Sleeves,
})}
onClick={clickSleeves}
>
<ListItemIcon>
<PeopleAltIcon color={props.page !== Page.Sleeves ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Sleeves ? "secondary" : "primary"}>Sleeves</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setHelpOpen((old) => !old)}>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setWorldOpen((old) => !old)}>
<ListItemIcon>
<PublicIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">World</Typography>} />
{worldOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Collapse in={worldOpen} timeout="auto" unmountOnExit>
<ListItem
button
key={"City"}
className={clsx({
[classes.active]: props.page === Page.City,
})}
onClick={clickCity}
>
<ListItemIcon>
<LiveHelpIcon color={"primary"} />
<LocationCityIcon color={flashCity ? "error" : props.page !== Page.City ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Help</Typography>} />
{helpOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
<ListItemText>
<Typography color={flashCity ? "error" : props.page !== Page.City ? "secondary" : "primary"}>
City
</Typography>
</ListItemText>
</ListItem>
<Collapse in={helpOpen} timeout="auto" unmountOnExit>
<ListItem
button
key={"Travel"}
className={clsx({
[classes.active]: props.page === Page.Travel,
})}
onClick={clickTravel}
>
<ListItemIcon>
<AirplanemodeActiveIcon color={props.page !== Page.Travel ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Travel ? "secondary" : "primary"}>Travel</Typography>
</ListItemText>
</ListItem>
{canJob && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Milestones"}
key={"Job"}
className={clsx({
[classes.active]: activeTab === "Milestones",
[classes.active]: props.page === Page.Job,
})}
onClick={clickMilestones}
onClick={clickJob}
>
<ListItemIcon>
<CheckIcon color={activeTab !== "Milestones" ? "secondary" : "primary"} />
<WorkIcon color={props.page !== Page.Job ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Milestones" ? "secondary" : "primary"}>Milestones</Typography>
<Typography color={props.page !== Page.Job ? "secondary" : "primary"}>Job</Typography>
</ListItemText>
</ListItem>
)}
{canStockMarket && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Tutorial"}
key={"Stock Market"}
className={clsx({
[classes.active]: activeTab === "Tutorial",
[classes.active]: props.page === Page.StockMarket,
})}
onClick={clickTutorial}
onClick={clickStockMarket}
>
<ListItemIcon>
<HelpIcon color={flashTutorial ? "error" : activeTab !== "Tutorial" ? "secondary" : "primary"} />
<TrendingUpIcon color={props.page !== Page.StockMarket ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashTutorial ? "error" : activeTab !== "Tutorial" ? "secondary" : "primary"}>
Tutorial
</Typography>
<Typography color={props.page !== Page.StockMarket ? "secondary" : "primary"}>Stock Market</Typography>
</ListItemText>
</ListItem>
)}
{canBladeburner && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Options"}
key={"Bladeburner"}
className={clsx({
[classes.active]: activeTab === "Options",
[classes.active]: props.page === Page.Bladeburner,
})}
onClick={clickOptions}
onClick={clickBladeburner}
>
<ListItemIcon>
<SettingsIcon color={activeTab !== "Options" ? "secondary" : "primary"} />
<FormatBoldIcon color={props.page !== Page.Bladeburner ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Options" ? "secondary" : "primary"}>Options</Typography>
<Typography color={props.page !== Page.Bladeburner ? "secondary" : "primary"}>Bladeburner</Typography>
</ListItemText>
</ListItem>
{process.env.NODE_ENV === "development" && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Dev"}
className={clsx({
[classes.active]: activeTab === "Dev",
})}
onClick={clickDev}
>
<ListItemIcon>
<DeveloperBoardIcon color={activeTab !== "Dev" ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={activeTab !== "Dev" ? "secondary" : "primary"}>Dev</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
</List>
</Drawer>
</BBTheme>
)}
{canCorporation && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Corp"}
className={clsx({
[classes.active]: props.page === Page.Corporation,
})}
onClick={clickCorp}
>
<ListItemIcon>
<BusinessIcon color={props.page !== Page.Corporation ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Corporation ? "secondary" : "primary"}>Corp</Typography>
</ListItemText>
</ListItem>
)}
{canGang && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Gang"}
className={clsx({
[classes.active]: props.page === Page.Gang,
})}
onClick={clickGang}
>
<ListItemIcon>
<SportsMmaIcon color={props.page !== Page.Gang ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Gang ? "secondary" : "primary"}>Gang</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
<Divider />
<ListItem classes={{ root: classes.listitem }} button onClick={() => setHelpOpen((old) => !old)}>
<ListItemIcon>
<LiveHelpIcon color={"primary"} />
</ListItemIcon>
<ListItemText primary={<Typography color="primary">Help</Typography>} />
{helpOpen ? <ExpandLessIcon color={"primary"} /> : <ExpandMoreIcon color={"primary"} />}
</ListItem>
<Collapse in={helpOpen} timeout="auto" unmountOnExit>
<ListItem
button
key={"Milestones"}
className={clsx({
[classes.active]: props.page === Page.Milestones,
})}
onClick={clickMilestones}
>
<ListItemIcon>
<CheckIcon color={props.page !== Page.Milestones ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Milestones ? "secondary" : "primary"}>Milestones</Typography>
</ListItemText>
</ListItem>
<ListItem
button
key={"Tutorial"}
className={clsx({
[classes.active]: props.page === Page.Tutorial,
})}
onClick={clickTutorial}
>
<ListItemIcon>
<HelpIcon color={flashTutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={flashTutorial ? "error" : props.page !== Page.Tutorial ? "secondary" : "primary"}>
Tutorial
</Typography>
</ListItemText>
</ListItem>
<ListItem
button
key={"Options"}
className={clsx({
[classes.active]: props.page === Page.Options,
})}
onClick={clickOptions}
>
<ListItemIcon>
<SettingsIcon color={props.page !== Page.Options ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.Options ? "secondary" : "primary"}>Options</Typography>
</ListItemText>
</ListItem>
{process.env.NODE_ENV === "development" && (
<ListItem
classes={{ root: classes.listitem }}
button
key={"Dev"}
className={clsx({
[classes.active]: props.page === Page.DevMenu,
})}
onClick={clickDev}
>
<ListItemIcon>
<DeveloperBoardIcon color={props.page !== Page.DevMenu ? "secondary" : "primary"} />
</ListItemIcon>
<ListItemText>
<Typography color={props.page !== Page.DevMenu ? "secondary" : "primary"}>Dev</Typography>
</ListItemText>
</ListItem>
)}
</Collapse>
</List>
</Drawer>
);
}

@ -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";

@ -76,7 +76,7 @@ export function TerminalRoot({ terminal, engine, player }: IProps): React.ReactE
const classes = useStyles();
return (
<>
<Box width="100%" minHeight="100vh" px={1} display={"flex"} alignItems={"flex-end"}>
<Box width="100%" minHeight="100vh" display={"flex"} alignItems={"flex-end"}>
<List classes={{ root: classes.list }}>
{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 && <ActionTimer terminal={terminal} />}
<div ref={scrollHook}></div>
</Box>
<Box position="sticky" bottom={0} width="100%" px={1}>
<Box position="sticky" bottom={0} width="100%" px={0}>
<TerminalInput player={player} engine={engine} terminal={terminal} />
</Box>
</>

@ -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(
<Theme>
<TerminalRoot terminal={Terminal} engine={this} player={Player} />
</Theme>,
Engine.Display.content,
);
MainMenuLinks.Stats.classList.add("active");
// Engine.hideAllContent();
// Engine.Display.content.style.display = "block";
// routing.navigateTo(Page.CharacterInfo);
// ReactDOM.render(
// <Theme>
// <TerminalRoot terminal={Terminal} engine={this} player={Player} />
// </Theme>,
// 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(<FactionList player={Player} engine={this} />, Engine.Display.content);
ReactDOM.render(<FactionsRoot player={Player} engine={this} />, 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(
<Theme>
<CharacterOverview player={Player} save={() => saveObject.saveGame(Engine.indexedDb)} />
@ -806,15 +806,15 @@ const Engine = {
ReactDOM.render(
<Theme>
<SidebarRoot engine={this} player={Player} />
<GameRoot terminal={Terminal} engine={this} player={Player} />
</Theme>,
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";

194
src/ui/GameRoot.tsx Normal file

@ -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<HTMLDivElement>(null);
const [faction, setFaction] = useState<Faction | null>(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 (
<>
<Box display="flex" flexDirection="row" width="100%">
<SidebarRoot player={player} router={router} page={page} />
<Box ref={contentRef} className={classes.root} flexGrow={1} display="block" width="100%" px={1} height="100vh">
{page === Page.Terminal ? (
<TerminalRoot terminal={terminal} engine={engine} player={player} />
) : page === Page.Sleeves ? (
<SleeveRoot player={player} />
) : page === Page.Stats ? (
<CharacterInfo player={player} />
) : page === Page.CreateScript ? (
<ScriptEditorRoot filename={""} code={""} player={player} engine={engine} />
) : page === Page.ActiveScripts ? (
<ActiveScriptsRoot p={player} workerScripts={workerScripts} />
) : page === Page.Hacknet ? (
<HacknetRoot player={player} />
) : page === Page.CreateProgram ? (
<ProgramsRoot player={player} />
) : page === Page.Factions ? (
<FactionsRoot player={player} router={router} />
) : page === Page.Faction ? (
<FactionRoot engine={engine} faction={faction} p={player} startHackingMissionFn={startHackingMission} />
) : page === Page.Milestones ? (
<MilestonesRoot player={player} />
) : page === Page.Tutorial ? (
<TutorialRoot />
) : page === Page.DevMenu ? (
<DevMenuRoot player={player} engine={engine} />
) : page === Page.Gang ? (
<GangRoot engine={engine} gang={player.gang} player={player} />
) : page === Page.Corporation ? (
<CorporationRoot corp={player.corporation} player={player} />
) : page === Page.Bladeburner ? (
<BladeburnerRoot bladeburner={player.bladeburner} player={player} engine={engine} />
) : page === Page.Resleeves ? (
<ResleeveRoot player={player} />
) : page === Page.Travel ? (
<TravelAgencyRoot p={player} router={router} />
) : page === Page.City ? (
<LocationRoot initiallyInCity={true} engine={engine} p={player} router={router} />
) : page === Page.StockMarket ? (
<StockMarketRoot
buyStockLong={buyStock}
buyStockShort={shortStock}
cancelOrder={cancelOrder}
eventEmitterForReset={eventEmitterForUiReset}
initStockMarket={initStockMarketFnForReact}
p={Player}
placeOrder={placeOrder}
sellStockLong={sellStock}
sellStockShort={sellShort}
stockMarket={castedStockMarket}
/>
) : page === Page.Options ? (
<GameOptionsRoot
player={player}
save={() => 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 ? (
<AugmentationsRoot
exportGameFn={() => {
saveObject.exportGame();
onExport(player);
}}
installAugmentationsFn={installAugmentations}
/>
) : (
<>
<Typography>Cannot load</Typography>
</>
)}
</Box>
</Box>
</>
);
}

62
src/ui/Router.ts Normal file

@ -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;
}