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} {rowsArray}
) : ( <> ); }; 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 ; }