import React from "react";
import { uniqueId } from "lodash";
import { Box, Collapse, ListItemButton, ListItemText, Paper, Table, TableBody, Typography } from "@mui/material";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import { Player } from "@player";
import { SpecialServers } from "../../Server/data/SpecialServers";
import { Settings } from "../../Settings/Settings";
import { StatsRow } from "../../ui/React/StatsRow";
import { defaultMultipliers, getBitNodeMultipliers } from "../BitNode";
import { BitNodeMultipliers } from "../BitNodeMultipliers";
import { PartialRecord, getRecordEntries } from "../../Types/Record";
interface IProps {
n: number;
level?: number;
}
export function BitnodeMultiplierDescription({ n, level }: IProps): React.ReactElement {
const [open, setOpen] = React.useState(false);
if (n === 1) return <>>;
return (
setOpen((old) => !old)}>
Bitnode Multipliers} />
{open ? : }
);
}
export const BitNodeMultipliersDisplay = ({ n, level }: IProps): React.ReactElement => {
// If a level argument has been provided, use that as the multiplier level
// If not, then we have to assume that we want the next level up from the
// current node's source file, so we get the min of that, the SF's max level,
// or if it's BN12, ∞
const maxSfLevel = n === 12 ? Infinity : 3;
const mults = getBitNodeMultipliers(n, level ?? Math.min(Player.sourceFileLvl(n) + 1, maxSfLevel));
return (
);
};
type IBNMultRows = PartialRecord<
keyof BitNodeMultipliers,
{
name: string;
content?: string;
color?: string;
}
>;
interface IBNMultTableProps {
sectionName: string;
rowData: IBNMultRows;
mults: BitNodeMultipliers;
}
const BNMultTable = (props: IBNMultTableProps): React.ReactElement => {
const rowsArray = getRecordEntries(props.rowData)
.filter(([key]) => props.mults[key] !== defaultMultipliers[key])
.map(([key, value]) => (
));
return rowsArray.length > 0 ? (
{props.sectionName}
) : (
<>>
);
};
interface IMultsProps {
n: number;
mults: BitNodeMultipliers;
}
function GeneralMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
WorldDaemonDifficulty: { name: `${SpecialServers.WorldDaemon} Difficulty` },
DaedalusAugsRequirement: {
name: "Daedalus Augs Requirement",
content: String(mults.DaedalusAugsRequirement),
},
HacknetNodeMoney: { name: "Hacknet Production" },
CodingContractMoney: { name: "Coding Contract Reward" },
ClassGymExpGain: { name: "Class/Gym Exp" },
};
return ;
}
function AugmentationMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
AugmentationMoneyCost: { name: "Money Cost" },
AugmentationRepCost: {
name: "Reputation Cost",
color: Settings.theme.rep,
},
};
return ;
}
function CompanyMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
CompanyWorkMoney: {
name: "Work Money",
color: Settings.theme.money,
},
CompanyWorkExpGain: { name: "Work Exp" },
};
return ;
}
function StockMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
FourSigmaMarketDataCost: { name: "Market Data Cost" },
FourSigmaMarketDataApiCost: { name: "Market Data API Cost" },
};
return ;
}
function FactionMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
RepToDonateToFaction: { name: "Favor to Donate" },
FactionWorkRepGain: {
name: "Work Reputation",
color: Settings.theme.rep,
},
FactionWorkExpGain: { name: "Work Exp" },
FactionPassiveRepGain: {
name: "Passive Rep",
color: Settings.theme.rep,
},
};
return ;
}
function CrimeMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
CrimeExpGain: {
name: "Crime Exp",
color: Settings.theme.combat,
},
CrimeMoney: {
name: "Crime Money",
color: Settings.theme.combat,
},
};
return ;
}
function SkillMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
HackingLevelMultiplier: {
name: "Hacking Level",
color: Settings.theme.hack,
},
StrengthLevelMultiplier: {
name: "Strength Level",
color: Settings.theme.combat,
},
DefenseLevelMultiplier: {
name: "Defense Level",
color: Settings.theme.combat,
},
DexterityLevelMultiplier: {
name: "Dexterity Level",
color: Settings.theme.combat,
},
AgilityLevelMultiplier: {
name: "Agility Level",
color: Settings.theme.combat,
},
CharismaLevelMultiplier: {
name: "Charisma Level",
color: Settings.theme.cha,
},
};
return ;
}
function HackingMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
HackExpGain: {
name: "Hacking Exp",
color: Settings.theme.hack,
},
ServerGrowthRate: { name: "Server Growth Rate" },
ServerMaxMoney: { name: "Server Max Money" },
ServerStartingMoney: { name: "Server Starting Money" },
ServerStartingSecurity: { name: "Server Starting Security" },
ServerWeakenRate: { name: "Server Weaken Rate" },
ManualHackMoney: {
name: "Manual Hack Money",
color: Settings.theme.money,
},
ScriptHackMoney: {
name: "Script Hack Money",
color: Settings.theme.money,
},
ScriptHackMoneyGain: {
name: "Money Gained From Hack",
color: Settings.theme.money,
},
};
return ;
}
function PurchasedServersMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
PurchasedServerCost: {
name: "Base Cost",
content: mults.PurchasedServerCost.toFixed(3),
},
PurchasedServerSoftcap: {
name: "Softcap Cost",
content: mults.PurchasedServerSoftcap.toFixed(3),
},
PurchasedServerLimit: { name: "Server Limit" },
PurchasedServerMaxRam: { name: "Max RAM" },
HomeComputerRamCost: { name: "Home RAM Cost" },
};
return ;
}
function InfiltrationMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
InfiltrationMoney: {
name: "Infiltration Money",
color: Settings.theme.money,
},
InfiltrationRep: {
name: "Infiltration Reputation",
color: Settings.theme.rep,
},
};
return ;
}
function BladeburnerMults({ mults }: IMultsProps): React.ReactElement {
if (!Player.canAccessBladeburner()) return <>>;
if (mults.BladeburnerRank === 0) {
const rows: IBNMultRows = {
BladeburnerRank: { name: "Disabled", content: "" },
};
return ;
}
const rows: IBNMultRows = {
BladeburnerRank: { name: "Rank Gain" },
BladeburnerSkillCost: { name: "Skill Cost" },
};
return ;
}
function StanekMults({ mults }: IMultsProps): React.ReactElement {
if (!Player.canAccessCotMG()) return <>>;
const extraSize = mults.StaneksGiftExtraSize.toFixed(3);
const rows: IBNMultRows = {
StaneksGiftPowerMultiplier: { name: "Gift Power" },
StaneksGiftExtraSize: {
name: "Base Size Modifier",
content: `${mults.StaneksGiftExtraSize > defaultMultipliers.StaneksGiftExtraSize ? `+${extraSize}` : extraSize}`,
},
};
return ;
}
function GangMults({ mults }: IMultsProps): React.ReactElement {
if (Player.bitNodeN !== 2 && Player.sourceFileLvl(2) <= 0) return <>>;
const rows: IBNMultRows = {
GangSoftcap: {
name: "Gang Softcap",
content: mults.GangSoftcap.toFixed(3),
},
GangUniqueAugs: { name: "Unique Augmentations" },
};
return ;
}
function CorporationMults({ mults }: IMultsProps): React.ReactElement {
if (!Player.canAccessCorporation()) return <>>;
if (mults.CorporationSoftcap < 0.15) {
const rows: IBNMultRows = {
CorporationSoftcap: {
name: "Disabled",
content: "",
},
};
return ;
}
const rows: IBNMultRows = {
CorporationSoftcap: {
name: "Corporation Softcap",
content: mults.CorporationSoftcap.toFixed(3),
},
CorporationValuation: { name: "Valuation" },
CorporationDivisions: { name: "Division limit" },
};
return ;
}
function GoMults({ mults }: IMultsProps): React.ReactElement {
const rows: IBNMultRows = {
GoPower: { name: "IPvGO Node Power bonus" },
};
return ;
}