bitburner-src/src/ui/CharacterStats.tsx

499 lines
16 KiB
TypeScript
Raw Normal View History

2021-09-10 21:08:51 +02:00
import React, { useState, useEffect } from "react";
import { numeralWrapper } from "../ui/numeralFormat";
2021-09-25 20:42:57 +02:00
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
import { HacknetServerConstants } from "../Hacknet/data/Constants";
import { StatsTable } from "./React/StatsTable";
import { Money } from "./React/Money";
2021-09-18 09:00:07 +02:00
import { use } from "./Context";
2021-09-20 05:29:02 +02:00
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { BitNodes } from "../BitNode/BitNode";
2021-09-18 18:13:20 +02:00
import Typography from "@mui/material/Typography";
2021-09-18 19:29:01 +02:00
import Box from "@mui/material/Box";
import IconButton from "@mui/material/IconButton";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import { Modal } from "./React/Modal";
import TableBody from "@mui/material/TableBody";
import { Table, TableCell } from "./React/Table";
import TableRow from "@mui/material/TableRow";
2021-09-18 18:13:20 +02:00
2021-09-18 09:00:07 +02:00
function LastEmployer(): React.ReactElement {
const player = use.Player();
if (player.companyName) {
2021-09-18 19:29:01 +02:00
return <Typography>Employer at which you last worked: {player.companyName}</Typography>;
2021-09-18 09:00:07 +02:00
}
return <></>;
2021-09-10 21:08:51 +02:00
}
2021-09-18 09:00:07 +02:00
function LastJob(): React.ReactElement {
const player = use.Player();
if (player.companyName !== "") {
2021-09-18 19:29:01 +02:00
return <Typography>Job you last worked: {player.jobs[player.companyName]}</Typography>;
2021-09-10 21:08:51 +02:00
}
2021-09-18 09:00:07 +02:00
return <></>;
}
2021-09-10 21:08:51 +02:00
2021-09-18 09:00:07 +02:00
function Employers(): React.ReactElement {
const player = use.Player();
if (player.jobs && Object.keys(player.jobs).length !== 0)
return (
<>
2021-09-18 19:29:01 +02:00
<Typography>All Employers:</Typography>
2021-09-18 09:00:07 +02:00
<ul>
{Object.keys(player.jobs).map((j) => (
2021-09-18 19:29:01 +02:00
<Typography key={j}> * {j}</Typography>
2021-09-18 09:00:07 +02:00
))}
</ul>
</>
);
return <></>;
}
2021-09-10 21:08:51 +02:00
2021-09-18 09:00:07 +02:00
function Hacknet(): React.ReactElement {
const player = use.Player();
// Can't import HacknetHelpers for some reason.
if (!(player.bitNodeN === 9 || SourceFileFlags[9] > 0)) {
return (
<>
2021-09-18 19:29:01 +02:00
<Typography>{`Hacknet Nodes owned: ${player.hacknetNodes.length}`}</Typography>
2021-09-18 09:00:07 +02:00
<br />
</>
);
} else {
return (
<>
2021-09-18 19:29:01 +02:00
<Typography>{`Hacknet Servers owned: ${player.hacknetNodes.length} / ${HacknetServerConstants.MaxServers}`}</Typography>
2021-09-18 09:00:07 +02:00
<br />
</>
);
}
}
function Intelligence(): React.ReactElement {
const player = use.Player();
if (player.intelligence > 0 && (player.bitNodeN === 5 || SourceFileFlags[5] > 0)) {
return (
2021-09-18 19:29:01 +02:00
<TableRow>
<TableCell>
<Typography>Intelligence:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography>{numeralWrapper.formatSkill(player.intelligence)}&nbsp;</Typography>
</TableCell>
</TableRow>
2021-09-18 09:00:07 +02:00
);
2021-09-05 01:09:30 +02:00
}
2021-09-18 09:00:07 +02:00
return <></>;
}
function MultiplierTable(props: any): React.ReactElement {
function bn5Stat(r: any): JSX.Element {
if (SourceFileFlags[5] > 0 && r.length > 2 && r[1] != r[2]) {
2021-09-05 01:09:30 +02:00
return (
2021-09-18 19:29:01 +02:00
<TableCell key="2" align="right">
<Typography noWrap>({numeralWrapper.formatPercentage(r[2])})</Typography>
</TableCell>
2021-09-05 01:09:30 +02:00
);
}
2021-09-05 01:09:30 +02:00
return <></>;
}
2021-09-18 09:00:07 +02:00
return (
<>
2021-09-18 19:29:01 +02:00
<Table size="small" padding="none">
<TableBody>
2021-09-18 09:00:07 +02:00
{props.rows.map((r: any) => (
2021-09-18 19:29:01 +02:00
<TableRow key={r[0]}>
<TableCell key="0">
<Typography noWrap>{`${r[0]} multiplier:`}&nbsp;</Typography>
</TableCell>
<TableCell key="1" align="right">
<Typography noWrap>{numeralWrapper.formatPercentage(r[1])}</Typography>
</TableCell>
2021-09-18 09:00:07 +02:00
{bn5Stat(r)}
2021-09-18 19:29:01 +02:00
</TableRow>
2021-09-18 09:00:07 +02:00
))}
2021-09-18 19:29:01 +02:00
</TableBody>
</Table>
2021-09-18 09:00:07 +02:00
</>
);
}
function BladeburnerMults(): React.ReactElement {
const player = use.Player();
if (!player.canAccessBladeburner()) return <></>;
return (
2021-09-18 19:29:01 +02:00
<MultiplierTable
rows={[
["Bladeburner Success Chance", player.bladeburner_success_chance_mult],
["Bladeburner Max Stamina", player.bladeburner_max_stamina_mult],
["Bladeburner Stamina Gain", player.bladeburner_stamina_gain_mult],
["Bladeburner Field Analysis", player.bladeburner_analysis_mult],
2021-09-18 19:29:01 +02:00
]}
/>
2021-09-18 09:00:07 +02:00
);
}
function CurrentBitNode(): React.ReactElement {
const player = use.Player();
if (player.sourceFiles.length > 0) {
const index = "BitNode" + player.bitNodeN;
return (
<>
2021-09-25 09:09:27 +02:00
<Typography variant="h4">
2021-09-18 19:33:15 +02:00
BitNode {player.bitNodeN}: {BitNodes[index].name}
2021-09-18 19:29:01 +02:00
</Typography>
<Typography sx={{ mx: 2 }} style={{ whiteSpace: "pre-wrap", overflowWrap: "break-word" }}>
{BitNodes[index].info}
</Typography>
2021-09-18 09:00:07 +02:00
</>
);
2021-09-05 01:09:30 +02:00
}
2021-09-18 09:00:07 +02:00
return <></>;
}
2021-09-18 19:29:01 +02:00
interface IMoneyModalProps {
open: boolean;
onClose: () => void;
}
2021-09-18 09:00:07 +02:00
2021-09-18 19:29:01 +02:00
function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
const player = use.Player();
2021-09-09 05:47:34 +02:00
function convertMoneySourceTrackerToString(src: MoneySourceTracker): React.ReactElement {
2021-09-05 01:09:30 +02:00
const parts: any[][] = [[`Total:`, <Money money={src.total} />]];
2021-10-27 20:18:33 +02:00
if (src.augmentations) {
parts.push([`Augmentations:`, <Money money={src.augmentations} />]);
}
2021-09-05 01:09:30 +02:00
if (src.bladeburner) {
parts.push([`Bladeburner:`, <Money money={src.bladeburner} />]);
}
2021-10-27 20:18:33 +02:00
if (src.casino) {
parts.push([`Casino:`, <Money money={src.casino} />]);
}
2021-09-05 01:09:30 +02:00
if (src.codingcontract) {
parts.push([`Coding Contracts:`, <Money money={src.codingcontract} />]);
}
2021-09-05 01:09:30 +02:00
if (src.work) {
parts.push([`Company Work:`, <Money money={src.work} />]);
}
if (src.class) {
parts.push([`Class:`, <Money money={src.class} />]);
}
if (src.corporation) {
parts.push([`Corporation:`, <Money money={src.corporation} />]);
}
if (src.crime) {
parts.push([`Crimes:`, <Money money={src.crime} />]);
}
if (src.gang) {
parts.push([`Gang:`, <Money money={src.gang} />]);
}
if (src.hacking) {
parts.push([`Hacking:`, <Money money={src.hacking} />]);
}
2021-10-27 20:18:33 +02:00
if (src.hacknet) {
parts.push([`Hacknet Nodes:`, <Money money={src.hacknet} />]);
2021-09-05 01:09:30 +02:00
}
2021-11-06 02:01:23 +01:00
if (src.hacknet_expenses) {
parts.push([`Hacknet Nodes Expenses:`, <Money money={src.hacknet_expenses} />]);
}
2021-09-05 01:09:30 +02:00
if (src.hospitalization) {
parts.push([`Hospitalization:`, <Money money={src.hospitalization} />]);
}
if (src.infiltration) {
parts.push([`Infiltration:`, <Money money={src.infiltration} />]);
}
2021-10-27 20:18:33 +02:00
if (src.servers) {
parts.push([`Servers:`, <Money money={src.servers} />]);
}
2021-09-05 01:09:30 +02:00
if (src.stock) {
parts.push([`Stock Market:`, <Money money={src.stock} />]);
}
if (src.sleeves) {
parts.push([`Sleeves:`, <Money money={src.sleeves} />]);
}
2021-10-27 20:18:33 +02:00
if (src.other) {
parts.push([`Other:`, <Money money={src.other} />]);
}
2021-09-18 19:29:01 +02:00
return <StatsTable rows={parts} wide />;
2021-09-05 01:09:30 +02:00
}
2021-09-18 19:29:01 +02:00
let content = (
<>
<Typography variant="h6" color="primary">
Money earned since you last installed Augmentations
</Typography>
<br />
{convertMoneySourceTrackerToString(player.moneySourceA)}
</>
);
if (player.sourceFiles.length !== 0) {
content = (
2021-09-05 01:09:30 +02:00
<>
2021-09-18 19:29:01 +02:00
{content}
2021-09-05 01:09:30 +02:00
<br />
2021-09-18 19:29:01 +02:00
<br />
<Typography variant="h6" color="primary">
Money earned in this BitNode
</Typography>
<br />
{convertMoneySourceTrackerToString(player.moneySourceB)}
2021-09-05 01:09:30 +02:00
</>
);
2021-09-18 19:29:01 +02:00
}
2021-09-18 19:29:01 +02:00
return (
<Modal open={open} onClose={onClose}>
{content}
</Modal>
);
}
export function CharacterStats(): React.ReactElement {
const player = use.Player();
const [moneyOpen, setMoneyOpen] = useState(false);
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
2021-09-05 01:09:30 +02:00
}
2021-09-18 19:29:01 +02:00
useEffect(() => {
2021-09-25 19:31:42 +02:00
const id = setInterval(rerender, 200);
2021-09-18 19:29:01 +02:00
return () => clearInterval(id);
}, []);
2021-09-10 21:08:51 +02:00
const timeRows = [
2021-09-18 09:00:07 +02:00
["Time played since last Augmentation:", convertTimeMsToTimeElapsedString(player.playtimeSinceLastAug)],
2021-09-10 21:08:51 +02:00
];
2021-09-18 09:00:07 +02:00
if (player.sourceFiles.length > 0) {
2021-09-05 01:09:30 +02:00
timeRows.push([
"Time played since last Bitnode destroyed:",
2021-09-18 09:00:07 +02:00
convertTimeMsToTimeElapsedString(player.playtimeSinceLastBitnode),
2021-09-05 01:09:30 +02:00
]);
}
2021-09-18 09:00:07 +02:00
timeRows.push(["Total Time played:", convertTimeMsToTimeElapsedString(player.totalPlaytime)]);
2021-09-05 01:09:30 +02:00
return (
2021-09-11 18:24:09 +02:00
<>
2021-09-25 09:09:27 +02:00
<Typography variant="h4">General</Typography>
2021-09-18 19:29:01 +02:00
<Box sx={{ mx: 2 }}>
<Typography>Current City: {player.city}</Typography>
<LastEmployer />
<LastJob />
<Employers />
2021-09-18 19:29:01 +02:00
<Typography>
2021-11-12 03:35:26 +01:00
Money: <Money money={player.money} />
2021-09-18 19:29:01 +02:00
<IconButton onClick={() => setMoneyOpen(true)}>
<MoreHorizIcon color="info" />
</IconButton>
</Typography>
</Box>
<br />
2021-09-25 09:09:27 +02:00
<Typography variant="h4">Stats</Typography>
2021-09-18 19:29:01 +02:00
<Box sx={{ mx: 2 }}>
<Table size="small" padding="none">
<TableBody>
<TableRow>
<TableCell>
<Typography noWrap>Hacking:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
2021-11-05 22:12:52 +01:00
<Typography noWrap>{numeralWrapper.formatSkill(player.hacking)}&nbsp;</Typography>
2021-09-18 19:29:01 +02:00
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.hacking_exp)} exp)</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Strength:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>{numeralWrapper.formatSkill(player.strength)}&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.strength_exp)} exp)</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Defense:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>{numeralWrapper.formatSkill(player.defense)}&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.defense_exp)} exp)</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Dexterity:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>{numeralWrapper.formatSkill(player.dexterity)}&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.dexterity_exp)} exp)</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Agility:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>{numeralWrapper.formatSkill(player.agility)}&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.agility_exp)} exp)</Typography>
</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Charisma:&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>{numeralWrapper.formatSkill(player.charisma)}&nbsp;</Typography>
</TableCell>
<TableCell align="right">
<Typography noWrap>({numeralWrapper.formatExp(player.charisma_exp)} exp)</Typography>
</TableCell>
</TableRow>
<Intelligence />
2021-09-18 19:29:01 +02:00
</TableBody>
</Table>
<br />
2021-09-18 19:29:01 +02:00
</Box>
<br />
2021-09-25 09:09:27 +02:00
<Typography variant="h4">Multipliers</Typography>
2021-09-18 19:29:01 +02:00
<Box sx={{ mx: 2 }}>
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Hacking Chance", player.hacking_chance_mult],
["Hacking Speed", player.hacking_speed_mult],
[
"Hacking Money",
2021-09-18 09:00:07 +02:00
player.hacking_money_mult,
player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney,
],
[
"Hacking Growth",
2021-09-18 09:00:07 +02:00
player.hacking_grow_mult,
player.hacking_grow_mult * BitNodeMultipliers.ServerGrowthRate,
],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Hacking Level", player.hacking_mult, player.hacking_mult * BitNodeMultipliers.HackingLevelMultiplier],
["Hacking Experience", player.hacking_exp_mult, player.hacking_exp_mult * BitNodeMultipliers.HackExpGain],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Strength Level", player.strength_mult, player.strength_mult * BitNodeMultipliers.StrengthLevelMultiplier],
["Strength Experience", player.strength_exp_mult],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Defense Level", player.defense_mult, player.defense_mult * BitNodeMultipliers.DefenseLevelMultiplier],
["Defense Experience", player.defense_exp_mult],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Dexterity Level",
2021-09-18 09:00:07 +02:00
player.dexterity_mult,
player.dexterity_mult * BitNodeMultipliers.DexterityLevelMultiplier,
],
2021-09-18 09:00:07 +02:00
["Dexterity Experience", player.dexterity_exp_mult],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Agility Level", player.agility_mult, player.agility_mult * BitNodeMultipliers.AgilityLevelMultiplier],
["Agility Experience", player.agility_exp_mult],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Charisma Level", player.charisma_mult, player.charisma_mult * BitNodeMultipliers.CharismaLevelMultiplier],
["Charisma Experience", player.charisma_exp_mult],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Hacknet Node production",
2021-09-18 09:00:07 +02:00
player.hacknet_node_money_mult,
player.hacknet_node_money_mult * BitNodeMultipliers.HacknetNodeMoney,
],
2021-09-18 09:00:07 +02:00
["Hacknet Node purchase cost", player.hacknet_node_purchase_cost_mult],
["Hacknet Node RAM upgrade cost", player.hacknet_node_ram_cost_mult],
["Hacknet Node Core purchase cost", player.hacknet_node_core_cost_mult],
["Hacknet Node level upgrade cost", player.hacknet_node_level_cost_mult],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Company reputation gain", player.company_rep_mult],
[
"Faction reputation gain",
2021-09-18 09:00:07 +02:00
player.faction_rep_mult,
player.faction_rep_mult * BitNodeMultipliers.FactionWorkRepGain,
],
2021-09-18 09:00:07 +02:00
["Salary", player.work_money_mult, player.work_money_mult * BitNodeMultipliers.CompanyWorkMoney],
]}
/>
<br />
<MultiplierTable
rows={[
2021-09-18 09:00:07 +02:00
["Crime success", player.crime_success_mult],
["Crime money", player.crime_money_mult, player.crime_money_mult * BitNodeMultipliers.CrimeMoney],
]}
/>
<br />
<BladeburnerMults />
2021-09-18 19:29:01 +02:00
</Box>
<br />
2021-09-25 09:09:27 +02:00
<Typography variant="h4">Misc</Typography>
2021-09-18 19:29:01 +02:00
<Box sx={{ mx: 2 }}>
<Typography>{`Servers owned: ${player.purchasedServers.length} / ${getPurchaseServerLimit()}`}</Typography>
<Hacknet />
2021-09-18 19:29:01 +02:00
<Typography>{`Augmentations installed: ${player.augmentations.length}`}</Typography>
<StatsTable rows={timeRows} />
</Box>
<br />
<CurrentBitNode />
<MoneyModal open={moneyOpen} onClose={() => setMoneyOpen(false)} />
2021-09-11 18:24:09 +02:00
</>
2021-09-05 01:09:30 +02:00
);
}