import { type BitNodeBooleanOptions } from "@nsdefs"; import React from "react"; import { Box, Button, Collapse, ListItemButton, ListItemText, MenuItem, Paper, Select, TextField, Tooltip, Typography, } from "@mui/material"; import { OptionSwitch } from "../../ui/React/OptionSwitch"; import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip"; import { ExpandLess, ExpandMore } from "@mui/icons-material"; import { JSONMap } from "../../Types/Jsonable"; import { Settings } from "../../Settings/Settings"; import { Player } from "@player"; interface SourceFileButtonRowProps { sfNumber: number; sfLevel: number; sfActiveLevel: number; callbacks: BitNodeAdvancedOptionsProps["callbacks"]; } function SourceFileButtonRow({ sfNumber, sfLevel, sfActiveLevel, callbacks, }: SourceFileButtonRowProps): React.ReactElement { const title = `SF-${sfNumber}`; const sourceFileLevelTool = sfNumber !== 12 ? ( [...Array(sfLevel + 1).keys()].map((level) => ( )) ) : ( // The usage of TextField instead of NumberInput is intentional. { // Empty string will be automatically changed to "0". if (event.target.value === "") { callbacks.setSfActiveLevel(sfNumber, 0); return; } const level = Number.parseInt(event.target.value); if (!Number.isFinite(level) || level < 0 || level > sfLevel) { return; } callbacks.setSfActiveLevel(sfNumber, level); }} > ); const extraInfo = sfNumber === 12 ? ( Max level: {sfLevel} ) : null; return ( {title} {sourceFileLevelTool} {extraInfo} ); } function SourceFileOverrides({ currentSourceFiles, sourceFileOverrides, callbacks, getSfLevel, }: { currentSourceFiles: BitNodeAdvancedOptionsProps["currentSourceFiles"]; sourceFileOverrides: BitNodeAdvancedOptionsProps["sourceFileOverrides"]; callbacks: BitNodeAdvancedOptionsProps["callbacks"]; getSfLevel: (sfNumber: number) => number; }): React.ReactElement { const firstSourceFile = React.useMemo( () => (currentSourceFiles.size > 0 ? [...currentSourceFiles.keys()][0] : null), [currentSourceFiles], ); const [selectElementValue, setSelectElementValue] = React.useState(firstSourceFile); const getMenuItemList = (data: typeof sourceFileOverrides): number[] => { return [...currentSourceFiles.keys()].filter((sfNumber) => ![...data.keys()].includes(sfNumber)); }; const menuItemList = getMenuItemList(sourceFileOverrides); React.useEffect(() => { if (sourceFileOverrides.size === 0) { setSelectElementValue(firstSourceFile); } }, [sourceFileOverrides, firstSourceFile]); const basicNote = `Changing the active level of a SF is temporary; you still permanently own that SF level. For example, if you enter BN 1.3 while having SF 1.2 but with the active level set to 0, you will not get the bonuses from SF 1.1 or SF 1.2, but you will still earn SF 1.3 when destroying the BN.`; const note = currentSourceFiles.has(10) ? ( <> Note: ) : ( <> Note: {basicNote}
); return ( <> Override active level of Source-File:
{note}
{ callbacks.setSfOverrides(new JSONMap()); }} buttonProps={{ sx: { marginLeft: "1rem" } }} > Remove all

{sourceFileOverrides.size > 0 && ( <> {[...sourceFileOverrides.keys()].map((sfNumber) => ( ))}
Set all SF {[0, 1, 2, 3].map((level) => ( { const newSfOverrides = new JSONMap(sourceFileOverrides); for (const [sfNumber] of newSfOverrides) { newSfOverrides.set(sfNumber, Math.min(level, getSfLevel(sfNumber))); } callbacks.setSfOverrides(newSfOverrides); }} buttonProps={{ sx: { marginRight: "0.5rem", minWidth: "40px" } }} > {level} ))}

)} ); } function IntelligenceOverride({ intelligenceOverride, callbacks, }: { intelligenceOverride: BitNodeAdvancedOptionsProps["intelligenceOverride"]; callbacks: BitNodeAdvancedOptionsProps["callbacks"]; }): React.ReactElement { const [enabled, setEnabled] = React.useState(false); const [lastValueOfIntelligenceOverride, setLastValueOfIntelligenceOverride] = React.useState( Player.skills.intelligence, ); return ( { setEnabled(value); if (!value) { // If this option is disabled, save last value and reset data. setLastValueOfIntelligenceOverride(intelligenceOverride); callbacks.setIntelligenceOverride(undefined); return; } else { // If this option is enabled, load last value. callbacks.setIntelligenceOverride(lastValueOfIntelligenceOverride); } }} text={ <> Override Intelligence: { // Empty string will be automatically changed to "1". if (event.target.value === "") { callbacks.setIntelligenceOverride(1); return; } const value = Number.parseInt(event.target.value); if (!Number.isInteger(value) || value < 1) { return; } callbacks.setIntelligenceOverride(value); }} > } tooltip={ <> Your intelligence and your Sleeves' intelligence will be temporarily set to this value if it is lower than their current values. For example:
  • If your intelligence is 1000 and you set this value to 500, your intelligence will be temporarily set to 500.
  • If a Sleeve's intelligence is 200 and you set this value to 500, that Sleeve's intelligence is still 200.
Note that you still gain intelligence experience as normal.
For example, suppose you have 1e6 intelligence exp (intelligence skill = 242) and set the intelligence override to 100. At the start of the BitNode, your intelligence skill will be set to 100 (equivalent to ~11255.318 intelligence exp).
If you gain 500e3 intelligence exp during the BitNode, your intelligence skill will increase to 220 (total intelligence exp = 11255 + 500e3 = 511255). After performing bitflume, the exp gained during the BitNode is added to your original exp. Your intelligence skill will then become 255 (total intelligence exp = 1e6 + 500e3 = 1.5e6).

The overridden intelligence will be shown in the character overview. You can hover your mouse over it to see the original value. } /> ); } interface BitNodeAdvancedOptionsProps { targetBitNode: number; currentSourceFiles: Map; sourceFileOverrides: JSONMap; intelligenceOverride: number | undefined; bitNodeBooleanOptions: BitNodeBooleanOptions; callbacks: { setSfOverrides: (value: JSONMap) => void; setSfActiveLevel: (sfNumber: number, sfLevel: number) => void; setIntelligenceOverride: (value: number | undefined) => void; setBooleanOption: (key: keyof BitNodeBooleanOptions, value: boolean) => void; }; } export function BitNodeAdvancedOptions({ targetBitNode, currentSourceFiles, sourceFileOverrides, intelligenceOverride, bitNodeBooleanOptions, callbacks, }: BitNodeAdvancedOptionsProps): React.ReactElement { const [open, setOpen] = React.useState(false); const getSfLevel = React.useCallback( (sfNumber: number): number => { return currentSourceFiles.get(sfNumber) ?? 0; }, [currentSourceFiles], ); return ( setOpen((old) => !old)} sx={{ padding: "4px 8px" }}> Advanced options} /> {open ? : } These options enable unique gameplay that is intended for experienced players. If you are a new player, you can safely ignore these options and come back to try them later.
{ callbacks.setBooleanOption("restrictHomePCUpgrade", value); }} text="Restrict max RAM and core of Home PC" tooltip="The home computer's maximum RAM and number of cores are lower than normal. Max RAM: 128GB. Max core: 1." /> { callbacks.setBooleanOption("disableGang", value); }} text="Disable Gang" tooltip="Disable Gang, regardless of BitNode and SF level" /> { callbacks.setBooleanOption("disableCorporation", value); }} text="Disable Corporation" tooltip="Disable Corporation, regardless of BitNode and SF level" /> { callbacks.setBooleanOption("disableBladeburner", value); }} text="Disable Bladeburner" tooltip="Disable Bladeburner, regardless of BitNode and SF level" /> { callbacks.setBooleanOption("disable4SData", value); }} text="Disable 4S Market Data" tooltip="Disable 4S Market Data, regardless of BitNode and SF level" /> { callbacks.setBooleanOption("disableHacknetServer", value); }} text="Disable Hacknet Server" tooltip="Disable Hacknet Server, regardless of BitNode and SF level. Hacknet Node is re-enabled in place of Hacknet Server." /> { callbacks.setBooleanOption("disableSleeveExpAndAugmentation", value); }} text="Disable Sleeves' experience and augmentation" tooltip="Sleeves cannot gain experience or install augmentations" />
); }