bitburner-src/src/ui/React/CharacterOverview.tsx

460 lines
17 KiB
TypeScript
Raw Normal View History

2021-09-13 00:03:07 +02:00
// Root React Component for the Corporation UI
2021-09-16 23:30:47 +02:00
import React, { useState, useEffect } from "react";
2021-09-13 00:03:07 +02:00
import { Theme, useTheme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
2021-09-21 02:42:13 +02:00
import createStyles from "@mui/styles/createStyles";
2021-09-13 00:03:07 +02:00
import { numeralWrapper } from "../../ui/numeralFormat";
import { Reputation } from "./Reputation";
2021-10-26 21:50:55 +02:00
import { KillScriptsModal } from "./KillScriptsModal";
2021-09-13 00:03:07 +02:00
2021-09-17 01:23:03 +02:00
import Table from "@mui/material/Table";
2021-10-18 20:15:43 +02:00
import TableBody from "@mui/material/TableBody";
2021-09-17 01:23:03 +02:00
import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
2021-09-18 18:13:20 +02:00
import IconButton from "@mui/material/IconButton";
2021-09-19 22:19:24 +02:00
import SaveIcon from "@mui/icons-material/Save";
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
2021-10-26 21:50:55 +02:00
import ClearAllIcon from "@mui/icons-material/ClearAll";
2021-09-16 23:30:47 +02:00
import { Settings } from "../../Settings/Settings";
2021-09-19 06:46:39 +02:00
import { use } from "../Context";
import { StatsProgressOverviewCell } from "./StatsProgressBar";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { IRouter, Page } from "../Router";
import { Box, Tooltip } from "@mui/material";
2021-09-16 23:30:47 +02:00
2021-09-13 00:03:07 +02:00
interface IProps {
2021-09-16 23:30:47 +02:00
save: () => void;
2021-10-26 21:50:55 +02:00
killScripts: () => void;
router: IRouter;
allowBackButton: boolean;
2021-09-13 00:03:07 +02:00
}
2021-09-18 01:43:08 +02:00
function Intelligence(): React.ReactElement {
const player = use.Player();
2021-09-16 23:30:47 +02:00
const classes = useStyles();
2021-09-18 01:43:08 +02:00
if (player.intelligence === 0) return <></>;
2021-09-16 23:30:47 +02:00
return (
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>Int&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.int }}>{numeralWrapper.formatSkill(player.intelligence)}</Typography>
</TableCell>
2021-09-19 20:39:34 +02:00
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography id="overview-int-hook" classes={{ root: classes.int }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
2021-09-16 23:30:47 +02:00
</TableRow>
2021-09-13 00:03:07 +02:00
);
2021-09-16 23:30:47 +02:00
}
2021-09-13 00:03:07 +02:00
2021-10-12 22:06:32 +02:00
function Bladeburner(): React.ReactElement {
const player = use.Player();
const classes = useStyles();
const bladeburner = player.bladeburner;
if (bladeburner === null) return <></>;
const action = bladeburner.getTypeAndNameFromActionId(bladeburner.action);
if (action.type === "Idle") return <></>;
return (
<>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>Bladeburner:</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>
{action.type}: {action.name}
</Typography>
</TableCell>
</TableRow>
</>
);
}
2021-09-18 01:43:08 +02:00
function Work(): React.ReactElement {
const player = use.Player();
const router = use.Router();
2021-09-16 23:30:47 +02:00
const classes = useStyles();
2021-09-18 01:43:08 +02:00
if (!player.isWorking || player.focus) return <></>;
2022-01-09 21:22:23 +01:00
if (player.className !== "") {
return (
<>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>Work&nbsp;in&nbsp;progress:</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>{player.className}</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" align="center" colSpan={2} classes={{ root: classes.cellNone }}>
<Button
onClick={() => {
player.startFocusing();
router.toWork();
}}
>
Focus
</Button>
</TableCell>
</TableRow>
</>
);
}
if (player.createProgramName !== "") {
return (
<>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>Work&nbsp;in&nbsp;progress:</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>
{player.createProgramName}{" "}
{((player.timeWorkedCreateProgram / player.timeNeededToCompleteWork) * 100).toFixed(2)}%
</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" align="center" colSpan={2} classes={{ root: classes.cellNone }}>
<Button
onClick={() => {
player.startFocusing();
router.toWork();
}}
>
Focus
</Button>
</TableCell>
</TableRow>
</>
);
}
2021-09-16 23:30:47 +02:00
return (
2021-09-13 00:03:07 +02:00
<>
2021-09-16 23:30:47 +02:00
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
<Typography>Work&nbsp;in&nbsp;progress:</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" colSpan={2} classes={{ root: classes.cellNone }}>
2021-10-01 19:08:37 +02:00
<Typography>
+<Reputation reputation={player.workRepGained} /> rep
</Typography>
2021-09-16 23:30:47 +02:00
</TableCell>
</TableRow>
<TableRow>
<TableCell component="th" scope="row" align="center" colSpan={2} classes={{ root: classes.cellNone }}>
2021-09-18 01:43:08 +02:00
<Button
onClick={() => {
player.startFocusing();
router.toWork();
}}
>
Focus
</Button>
2021-09-16 23:30:47 +02:00
</TableCell>
</TableRow>
2021-09-13 00:03:07 +02:00
</>
);
2021-09-16 23:30:47 +02:00
}
2021-09-21 02:42:13 +02:00
const useStyles = makeStyles((theme: Theme) =>
createStyles({
cellNone: {
borderBottom: "none",
padding: 0,
margin: 0,
},
cell: {
padding: 0,
margin: 0,
},
hp: {
color: theme.colors.hp,
},
money: {
color: theme.colors.money,
},
hack: {
color: theme.colors.hack,
},
combat: {
color: theme.colors.combat,
},
cha: {
color: theme.colors.cha,
},
int: {
color: theme.colors.int,
},
}),
);
2021-09-16 23:30:47 +02:00
export { useStyles as characterOverviewStyles };
export function CharacterOverview({ save, killScripts, router, allowBackButton }: IProps): React.ReactElement {
2021-10-26 21:50:55 +02:00
const [killOpen, setKillOpen] = useState(false);
2021-09-18 01:43:08 +02:00
const player = use.Player();
2021-09-16 23:30:47 +02:00
const setRerender = useState(false)[1];
useEffect(() => {
const id = setInterval(() => setRerender((old) => !old), 600);
return () => clearInterval(id);
}, []);
2021-09-13 00:03:07 +02:00
2021-09-16 23:30:47 +02:00
const classes = useStyles();
const theme = useTheme();
const hackingProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.hacking_exp,
player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier,
);
const strengthProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.strength_exp,
player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier,
);
const defenseProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.defense_exp,
player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier,
);
const dexterityProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.dexterity_exp,
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
);
const agilityProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.agility_exp,
player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier,
);
const charismaProgress = player.calculateSkillProgress(
2022-01-09 21:22:23 +01:00
player.charisma_exp,
player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier,
);
const previousPageName = router.previousPage() < 0
? '' : Page[router.previousPage() ?? 0].replace(/([a-z])([A-Z])/g, '$1 $2');
2021-09-13 00:03:07 +02:00
return (
2021-10-26 21:50:55 +02:00
<>
<Table sx={{ display: "block", m: 1 }}>
<TableBody>
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.hp }}>HP&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.hp }}>
{numeralWrapper.formatHp(player.hp)}&nbsp;/&nbsp;{numeralWrapper.formatHp(player.max_hp)}
</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-hp-hook" classes={{ root: classes.hp }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.money }}>Money&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
2021-11-12 03:35:26 +01:00
<Typography classes={{ root: classes.money }}>{numeralWrapper.formatMoney(player.money)}</Typography>
2021-10-26 21:50:55 +02:00
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-money-hook" classes={{ root: classes.money }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
2021-10-26 21:50:55 +02:00
<Typography classes={{ root: classes.hack }}>Hack&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
2021-11-05 22:12:52 +01:00
<Typography classes={{ root: classes.hack }}>{numeralWrapper.formatSkill(player.hacking)}</Typography>
2021-10-26 21:50:55 +02:00
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={hackingProgress} color={theme.colors.hack} />
)}
</TableRow>
<TableRow>
2022-01-09 21:22:23 +01:00
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.hack }}></Typography>
</TableCell>
2021-10-26 21:50:55 +02:00
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography id="overview-hack-hook" classes={{ root: classes.hack }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>Str&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>{numeralWrapper.formatSkill(player.strength)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-str-hook" classes={{ root: classes.combat }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={strengthProgress} color={theme.colors.combat} />
)}
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>Def&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>{numeralWrapper.formatSkill(player.defense)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-def-hook" classes={{ root: classes.combat }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={defenseProgress} color={theme.colors.combat} />
)}
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>Dex&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.combat }}>{numeralWrapper.formatSkill(player.dexterity)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-dex-hook" classes={{ root: classes.combat }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={dexterityProgress} color={theme.colors.combat} />
)}
</TableRow>
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.combat }}>Agi&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography classes={{ root: classes.combat }}>{numeralWrapper.formatSkill(player.agility)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cell }}>
<Typography id="overview-agi-hook" classes={{ root: classes.combat }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={agilityProgress} color={theme.colors.combat} />
)}
</TableRow>
2021-09-19 06:46:39 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.cha }}>Cha&nbsp;</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography classes={{ root: classes.cha }}>{numeralWrapper.formatSkill(player.charisma)}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography id="overview-cha-hook" classes={{ root: classes.cha }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<TableRow>
{!Settings.DisableOverviewProgressBars && (
<StatsProgressOverviewCell progress={charismaProgress} color={theme.colors.cha} />
)}
</TableRow>
2021-10-26 21:50:55 +02:00
<Intelligence />
2021-09-19 20:39:34 +02:00
2021-10-26 21:50:55 +02:00
<TableRow>
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
<Typography id="overview-extra-hook-0" classes={{ root: classes.hack }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
<TableCell component="th" scope="row" align="right" classes={{ root: classes.cell }}>
<Typography id="overview-extra-hook-1" classes={{ root: classes.hack }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
<TableCell component="th" scope="row" align="right" classes={{ root: classes.cell }}>
<Typography id="overview-extra-hook-2" classes={{ root: classes.hack }}>
{/*Hook for player scripts*/}
</Typography>
</TableCell>
</TableRow>
<Work />
<Bladeburner />
</TableBody>
</Table>
<Box sx={{ display: 'flex', borderTop: `1px solid ${Settings.theme.welllight}` }}>
<Box sx={{ display: 'flex', flex: 1, justifyContent: 'flex-start', alignItems: 'center' }}>
<IconButton onClick={save}>
<Tooltip title="Save game">
<SaveIcon color={Settings.AutosaveInterval !== 0 ? "primary" : "error"} />
</Tooltip>
</IconButton>
{allowBackButton && (
<IconButton
disabled={!previousPageName}
onClick={() => router.toPreviousPage()}>
<Tooltip title={previousPageName ? `Go back to "${previousPageName}"` : ''}>
<ArrowBackIcon />
</Tooltip>
</IconButton>
)}
</Box>
<Box sx={{ display: 'flex', flex: 1, justifyContent: 'flex-end', alignItems: 'center' }}>
<IconButton onClick={() => setKillOpen(true)}>
<Tooltip title="Kill all running scripts">
<ClearAllIcon color="error" />
</Tooltip>
</IconButton>
</Box>
</Box>
2021-10-26 21:50:55 +02:00
<KillScriptsModal open={killOpen} onClose={() => setKillOpen(false)} killScripts={killScripts} />
</>
2021-09-13 00:03:07 +02:00
);
}