import { Paper, Table, TableBody, Box, IconButton, Typography, Container, Tooltip } from "@mui/material";
import { MoreHoriz, Info } from "@mui/icons-material";
import React, { useState } from "react";
import { BitNodes } from "../BitNode/BitNode";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { BitNodeMultipliersDisplay } from "../BitNode/ui/BitnodeMultipliersDescription";
import { HacknetServerConstants } from "../Hacknet/data/Constants";
import { getPurchaseServerLimit } from "../Server/ServerPurchases";
import { Settings } from "../Settings/Settings";
import { MoneySourceTracker } from "../utils/MoneySourceTracker";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { Player } from "@player";
import { formatPercent, formatNumber } from "./formatNumber";
import { Modal } from "./React/Modal";
import { Money } from "./React/Money";
import { StatsRow } from "./React/StatsRow";
import { StatsTable } from "./React/StatsTable";
import { useRerender } from "./React/hooks";
import { getMaxFavor } from "../Go/effects/effect";
interface EmployersModalProps {
open: boolean;
onClose: () => void;
}
const EmployersModal = ({ open, onClose }: EmployersModalProps): React.ReactElement => {
return (
<>
All Employers
{Object.keys(Player.jobs).map((j) => (
* {j}
))}
>
);
};
interface IMultRow {
// The name of the multiplier
mult: string;
// The player's raw multiplier value
value: number;
// The player's effective multiplier value, affected by BitNode mults
effValue?: number;
// The text color for the row
color?: string;
// Whether to format as percent or scalar
isNumber?: boolean;
}
interface MultTableProps {
rows: IMultRow[];
color: string;
noMargin?: boolean;
}
function MultiplierTable(props: MultTableProps): React.ReactElement {
return (
{props.rows.map((data) => {
const { mult, value, effValue = null, color = props.color } = data;
if (effValue !== null && effValue !== value && Player.sourceFileLvl(5) > 0) {
return (
<>
{data.isNumber ? (
formatNumber(value, 0)
) : (
<>
{formatPercent(value)} {formatPercent(effValue)}
>
)}
>
);
}
return (
);
})}
);
}
function CurrentBitNode(): React.ReactElement {
if (Player.sourceFiles.size > 0) {
const index = "BitNode" + Player.bitNodeN;
const lvl = Math.min(Player.sourceFileLvl(Player.bitNodeN) + 1, Player.bitNodeN === 12 ? Infinity : 3);
return (
BitNode {Player.bitNodeN}: {BitNodes[index].name} (Level {lvl})
{BitNodes[index].info}
);
}
return <>>;
}
interface IMoneyModalProps {
open: boolean;
onClose: () => void;
}
function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement {
function convertMoneySourceTrackerToString(src: MoneySourceTracker): React.ReactElement {
const parts: [string, JSX.Element][] = [[`Total:`, ]];
if (src.augmentations) {
parts.push([`Augmentations:`, ]);
}
if (src.bladeburner) {
parts.push([`Bladeburner:`, ]);
}
if (src.casino) {
parts.push([`Casino:`, ]);
}
if (src.codingcontract) {
parts.push([`Coding Contracts:`, ]);
}
if (src.work) {
parts.push([`Company Work:`, ]);
}
if (src.class) {
parts.push([`Class:`, ]);
}
if (src.corporation) {
parts.push([`Corporation:`, ]);
}
if (src.crime) {
parts.push([`Crimes:`, ]);
}
if (src.gang) {
parts.push([`Gang:`, ]);
}
if (src.gang_expenses) {
parts.push([`Gang Expenses:`, ]);
}
if (src.hacking) {
parts.push([`Hacking:`, ]);
}
if (src.hacknet) {
parts.push([`Hacknet:`, ]);
}
if (src.hacknet_expenses) {
parts.push([`Hacknet Expenses:`, ]);
}
if (src.hospitalization) {
parts.push([`Hospitalization:`, ]);
}
if (src.infiltration) {
parts.push([`Infiltration:`, ]);
}
if (src.servers) {
parts.push([`Servers:`, ]);
}
if (src.stock) {
parts.push([`Stock Market:`, ]);
}
if (src.sleeves) {
parts.push([`Sleeves:`, ]);
}
if (src.other) {
parts.push([`Other:`, ]);
}
return ;
}
let content = (
<>
Money earned since you last installed Augmentations
{convertMoneySourceTrackerToString(Player.moneySourceA)}
>
);
if (Player.sourceFiles.size > 0) {
content = (
<>
{content}
Money earned in this BitNode
{convertMoneySourceTrackerToString(Player.moneySourceB)}
>
);
}
return (
{content}
);
}
export function CharacterStats(): React.ReactElement {
const [moneyOpen, setMoneyOpen] = useState(false);
const [employersOpen, setEmployersOpen] = useState(false);
useRerender(200);
const timeRows = [
["Since last Augmentation installation", convertTimeMsToTimeElapsedString(Player.playtimeSinceLastAug)],
];
if (Player.sourceFiles.size > 0) {
timeRows.push(["Since last Bitnode destroyed", convertTimeMsToTimeElapsedString(Player.playtimeSinceLastBitnode)]);
}
timeRows.push(["Total", convertTimeMsToTimeElapsedString(Player.totalPlaytime)]);
let showBitNodeMults = false;
if (Player.sourceFileLvl(5) > 0) showBitNodeMults = true;
return (
Stats
General
<>
setMoneyOpen(true)} sx={{ p: 0 }}>
>
{Player.jobs && Object.keys(Player.jobs).length !== 0 ? (
<>
{Object.keys(Player.jobs).length} total
setEmployersOpen(true)} sx={{ p: 0 }}>
>
) : (
<>>
)}
0 ? "Servers" : "Nodes"} owned`}
color={Settings.theme.primary}
data={{
content: `${Player.hacknetNodes.length}${
Player.bitNodeN === 9 || Player.sourceFileLvl(9) > 0
? ` / ${HacknetServerConstants.MaxServers}`
: ""
}`,
}}
/>
Skills
{Player.skills.intelligence > 0 && (Player.bitNodeN === 5 || Player.sourceFileLvl(5) > 0) && (
)}
Multipliers
{Player.sourceFileLvl(5) > 0 && (
Displays your current multipliers.
When there is a dim number next to a multiplier, that means that the multiplier in question is being
affected by BitNode multipliers.
The dim number is the raw multiplier, and the undimmed number is the effective multiplier, as dictated
by the BitNode.
}
>
)}
{Player.canAccessBladeburner() && currentNodeMults.BladeburnerRank > 0 && (
)}
{(Player.sourceFileLvl(14) || Player.bitNodeN === 14) && (
)}
Time Played
{timeRows.map(([name, content]) => (
))}
{showBitNodeMults && (
BitNode Multipliers
)}
setMoneyOpen(false)} />
setEmployersOpen(false)} />
);
}