import React, { useState, useEffect } from "react"; import clsx from "clsx"; 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"; import List from "@mui/material/List"; import Divider from "@mui/material/Divider"; import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import ListItem from "@mui/material/ListItem"; import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import Typography from "@mui/material/Typography"; import Collapse from "@mui/material/Collapse"; import Badge from "@mui/material/Badge"; import ComputerIcon from "@mui/icons-material/Computer"; import LastPageIcon from "@mui/icons-material/LastPage"; // Terminal import CreateIcon from "@mui/icons-material/Create"; // Create Script import StorageIcon from "@mui/icons-material/Storage"; // Active Scripts import BugReportIcon from "@mui/icons-material/BugReport"; // Create Program import EqualizerIcon from "@mui/icons-material/Equalizer"; // Stats import ContactsIcon from "@mui/icons-material/Contacts"; // Factions import DoubleArrowIcon from "@mui/icons-material/DoubleArrow"; // Augmentations import AccountTreeIcon from "@mui/icons-material/AccountTree"; // Hacknet import PeopleAltIcon from "@mui/icons-material/PeopleAlt"; // Sleeves import LocationCityIcon from "@mui/icons-material/LocationCity"; // City import AirplanemodeActiveIcon from "@mui/icons-material/AirplanemodeActive"; // Travel import WorkIcon from "@mui/icons-material/Work"; // Job import TrendingUpIcon from "@mui/icons-material/TrendingUp"; // Stock Market import FormatBoldIcon from "@mui/icons-material/FormatBold"; // Bladeburner import BusinessIcon from "@mui/icons-material/Business"; // Corp import SportsMmaIcon from "@mui/icons-material/SportsMma"; // Gang import CheckIcon from "@mui/icons-material/Check"; // Milestones import HelpIcon from "@mui/icons-material/Help"; // Tutorial import SettingsIcon from "@mui/icons-material/Settings"; // options import DeveloperBoardIcon from "@mui/icons-material/DeveloperBoard"; // Dev import AccountBoxIcon from "@mui/icons-material/AccountBox"; import PublicIcon from "@mui/icons-material/Public"; import LiveHelpIcon from "@mui/icons-material/LiveHelp"; import ExpandLessIcon from "@mui/icons-material/ExpandLess"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { IRouter, Page } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { CONSTANTS } from "../../Constants"; import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../../InteractiveTutorial"; import { getAvailableCreatePrograms } from "../../Programs/ProgramHelpers"; import { Settings } from "../../Settings/Settings"; import { redPillFlag } from "../../RedPill"; import { AugmentationNames } from "../../Augmentation/data/AugmentationNames"; import { KEY } from "../../utils/helpers/keyCodes"; const openedMixin = (theme: Theme): CSSObject => ({ width: theme.spacing(31), transition: theme.transitions.create("width", { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.enteringScreen, }), overflowX: "hidden", }); const closedMixin = (theme: Theme): CSSObject => ({ transition: theme.transitions.create("width", { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, }), overflowX: "hidden", width: `calc(${theme.spacing(2)} + 1px)`, [theme.breakpoints.up("sm")]: { width: `calc(${theme.spacing(7)} + 1px)`, }, }); const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({ width: theme.spacing(31), whiteSpace: "nowrap", boxSizing: "border-box", ...(open && { ...openedMixin(theme), "& .MuiDrawer-paper": openedMixin(theme), }), ...(!open && { ...closedMixin(theme), "& .MuiDrawer-paper": closedMixin(theme), }), })); const useStyles = makeStyles((theme: Theme) => createStyles({ active: { borderLeft: "3px solid " + theme.palette.primary.main, }, listitem: {}, }), ); interface IProps { player: IPlayer; router: IRouter; page: Page; } export function SidebarRoot(props: IProps): React.ReactElement { const setRerender = useState(false)[1]; function rerender(): void { setRerender((old) => !old); } useEffect(() => { const id = setInterval(rerender, 200); return () => clearInterval(id); }, []); const [hackingOpen, setHackingOpen] = useState(true); const [characterOpen, setCharacterOpen] = useState(true); const [worldOpen, setWorldOpen] = useState(true); const [helpOpen, setHelpOpen] = useState(true); const flashTerminal = ITutorial.currStep === iTutorialSteps.CharacterGoToTerminalPage || ITutorial.currStep === iTutorialSteps.ActiveScriptsPage; const flashStats = ITutorial.currStep === iTutorialSteps.GoToCharacterPage; const flashActiveScripts = ITutorial.currStep === iTutorialSteps.TerminalGoToActiveScriptsPage; const flashHacknet = ITutorial.currStep === iTutorialSteps.GoToHacknetNodesPage; const flashCity = ITutorial.currStep === iTutorialSteps.HacknetNodesGoToWorldPage; const flashTutorial = ITutorial.currStep === iTutorialSteps.WorldDescription; const augmentationCount = props.player.queuedAugmentations.length; const invitationsCount = props.player.factionInvitations.length; const programCount = getAvailableCreatePrograms(props.player).length; const canCreateProgram = programCount > 0 || props.player.augmentations.length > 0 || props.player.queuedAugmentations.length > 0 || props.player.sourceFiles.length > 0; const canOpenFactions = props.player.factionInvitations.length > 0 || props.player.factions.length > 0 || props.player.augmentations.length > 0 || props.player.queuedAugmentations.length > 0 || props.player.sourceFiles.length > 0; const canOpenAugmentations = props.player.augmentations.length > 0 || props.player.queuedAugmentations.length > 0 || props.player.sourceFiles.length > 0; const canOpenSleeves = props.player.sleeves.length > 0; const canCorporation = !!(props.player.corporation as any); const canGang = !!(props.player.gang as any); const canJob = props.player.companyName !== ""; const canStockMarket = props.player.hasWseAccount; const canBladeburner = !!(props.player.bladeburner as any); const canStaneksGift = props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1); function clickTerminal(): void { props.router.toTerminal(); if (flashTerminal) iTutorialNextStep(); } function clickScriptEditor(): void { props.router.toScriptEditor(); } function clickStats(): void { props.router.toStats(); if (flashStats) iTutorialNextStep(); } function clickActiveScripts(): void { props.router.toActiveScripts(); if (flashActiveScripts) iTutorialNextStep(); } function clickCreateProgram(): void { props.router.toCreateProgram(); } function clickStaneksGift(): void { props.router.toStaneksGift(); } function clickFactions(): void { props.router.toFactions(); } function clickAugmentations(): void { props.router.toAugmentations(); } function clickSleeves(): void { props.router.toSleeves(); } function clickHacknet(): void { props.router.toHacknetNodes(); if (flashHacknet) iTutorialNextStep(); } function clickCity(): void { props.router.toCity(); if (flashCity) iTutorialNextStep(); } function clickTravel(): void { props.router.toTravel(); } function clickJob(): void { props.router.toJob(); } function clickStockMarket(): void { props.router.toStockMarket(); } function clickBladeburner(): void { props.router.toBladeburner(); } function clickCorp(): void { props.router.toCorporation(); } function clickGang(): void { props.router.toGang(); } function clickTutorial(): void { props.router.toTutorial(); if (flashTutorial) iTutorialNextStep(); } function clickMilestones(): void { props.router.toMilestones(); } function clickOptions(): void { props.router.toGameOptions(); } function clickDev(): void { props.router.toDevMenu(); } useEffect(() => { // Shortcuts to navigate through the game // Alt-t - Terminal // Alt-c - Character // Alt-e - Script editor // Alt-s - Active scripts // Alt-h - Hacknet Nodes // Alt-w - City // Alt-j - Job // Alt-r - Travel Agency of current city // Alt-p - Create program // Alt-f - Factions // Alt-a - Augmentations // Alt-u - Tutorial // Alt-o - Options function handleShortcuts(this: Document, event: KeyboardEvent): any { if (Settings.DisableHotkeys) return; if (props.player.isWorking || redPillFlag) return; if (event.keyCode == KEY.T && event.altKey) { event.preventDefault(); clickTerminal(); } else if (event.keyCode === KEY.C && event.altKey) { event.preventDefault(); clickStats(); } else if (event.keyCode === KEY.E && event.altKey) { event.preventDefault(); clickScriptEditor(); } else if (event.keyCode === KEY.S && event.altKey) { event.preventDefault(); clickActiveScripts(); } else if (event.keyCode === KEY.H && event.altKey) { event.preventDefault(); clickHacknet(); } else if (event.keyCode === KEY.W && event.altKey) { event.preventDefault(); clickCity(); } else if (event.keyCode === KEY.J && event.altKey) { event.preventDefault(); clickJob(); } else if (event.keyCode === KEY.R && event.altKey) { event.preventDefault(); clickTravel(); } else if (event.keyCode === KEY.P && event.altKey) { event.preventDefault(); clickCreateProgram(); } else if (event.keyCode === KEY.F && event.altKey) { if (props.page == Page.Terminal && Settings.EnableBashHotkeys) { return; } event.preventDefault(); clickFactions(); } else if (event.keyCode === KEY.A && event.altKey) { event.preventDefault(); clickAugmentations(); } else if (event.keyCode === KEY.U && event.altKey) { event.preventDefault(); clickTutorial(); } else if (event.keyCode === KEY.B && event.altKey) { event.preventDefault(); clickBladeburner(); } else if (event.keyCode === KEY.G && event.altKey) { event.preventDefault(); clickGang(); } // if (event.keyCode === KEY.O && event.altKey) { // event.preventDefault(); // gameOptionsBoxOpen(); // } } document.addEventListener("keypress", handleShortcuts); return () => document.removeEventListener("keypress", handleShortcuts); }, []); const classes = useStyles(); const [open, setOpen] = useState(true); const toggleDrawer = (): void => setOpen((old) => !old); return ( {!open ? : } Bitburner v{CONSTANTS.Version}} /> setHackingOpen((old) => !old)}> Hacking} /> {hackingOpen ? : } Terminal Script Editor Active Scripts {canCreateProgram && ( 0 ? programCount : undefined} color="error"> Create Program )} {canStaneksGift && ( Stanek's Gift )} setCharacterOpen((old) => !old)}> Character} /> {characterOpen ? : } Stats {canOpenFactions && ( Factions )} {canOpenAugmentations && ( Augmentations )} Hacknet {canOpenSleeves && ( Sleeves )} setWorldOpen((old) => !old)}> World} /> {worldOpen ? : } City Travel {canJob && ( Job )} {canStockMarket && ( Stock Market )} {canBladeburner && ( Bladeburner )} {canCorporation && ( Corp )} {canGang && ( Gang )} setHelpOpen((old) => !old)}> Help} /> {helpOpen ? : } Milestones Tutorial Options {true && ( Dev )} ); }