import { Player } from "@player"; import { type BitNodeOptions } from "@nsdefs"; import { GetServer } from "../Server/AllServers"; import { Server } from "../Server/Server"; import { SpecialServers } from "../Server/data/SpecialServers"; import { JSONMap } from "../Types/Jsonable"; import { validBitNodes } from "./Constants"; export function isBitNodeFinished(): boolean { const wd = GetServer(SpecialServers.WorldDaemon); if (!(wd instanceof Server)) { throw new Error("WorldDaemon is not a normal server. This is a bug. Please contact developers."); } return wd.backdoorInstalled; } export function canAccessBitNodeFeature(bitNode: number): boolean { return Player.bitNodeN === bitNode || Player.activeSourceFileLvl(bitNode) > 0; } export function knowAboutBitverse(): boolean { for (const sfActiveLevel of Player.activeSourceFiles.values()) { if (sfActiveLevel > 0) { return true; } } return false; } export function getDefaultBitNodeOptions(): BitNodeOptions { return { sourceFileOverrides: new JSONMap(), intelligenceOverride: undefined, restrictHomePCUpgrade: false, disableGang: false, disableCorporation: false, disableBladeburner: false, disable4SData: false, disableHacknetServer: false, disableSleeveExpAndAugmentation: false, }; } export function validateSourceFileOverrides( sourceFileOverrides: Map, isDataFromPlayer: boolean, ): { valid: boolean; message?: string; } { if (!isDataFromPlayer && !(sourceFileOverrides instanceof JSONMap)) { return { valid: false, message: `It must be a JSONMap.` }; } for (const [sfNumber, sfLevel] of sourceFileOverrides.entries()) { if (!validBitNodes.includes(sfNumber)) { return { valid: false, message: `Invalid BitNode: ${sfNumber}.` }; } if (!Number.isFinite(sfLevel)) { return { valid: false, message: `Invalid SF level: ${sfLevel}.` }; } const maxSfLevel = Player.sourceFileLvl(sfNumber); if (sfLevel > maxSfLevel) { return { valid: false, message: `Invalid SF level: ${sfLevel}. Max level: ${maxSfLevel}.` }; } } return { valid: true }; } export function setBitNodeOptions(bitNodeOptions: BitNodeOptions): void { const validationResultForSourceFileOverrides = validateSourceFileOverrides(bitNodeOptions.sourceFileOverrides, false); if (!validationResultForSourceFileOverrides.valid) { throw new Error(`sourceFileOverrides is invalid. Reason: ${validationResultForSourceFileOverrides.message}`); } if ( bitNodeOptions.intelligenceOverride !== undefined && (!Number.isInteger(bitNodeOptions.intelligenceOverride) || bitNodeOptions.intelligenceOverride < 0) ) { throw new Error(`intelligenceOverride is invalid. It must be a non-negative integer.`); } Object.assign(Player.bitNodeOptions, bitNodeOptions); } /** * This function only sets the backdoorInstalled flag of the WD server. The caller must call Router.toPage() to route * the UI to the BitVerse page. Importing Router from src\ui\GameRoot.tsx brings too many unnecessary dependencies to * this utility file. */ export function finishBitNode() { const wd = GetServer(SpecialServers.WorldDaemon); if (!(wd instanceof Server)) { throw new Error("WorldDaemon is not a normal server. This is a bug. Please contact developers."); } wd.backdoorInstalled = true; } /** * BitNode level is not something that is stored, but rather calculated from the current BN and SF level. The concept * appeared because saying "Enter BN1.2" is shorter than saying "Enter BN1 with SF1.1". This is how we display it in the * BitVerse UI and other places. This function is used to consistently calculate this "level". */ export function getBitNodeLevel(bn = Player.bitNodeN, sfLevel = Player.activeSourceFileLvl(bn)): number { return Math.min(sfLevel + 1, bn === 12 ? Number.MAX_VALUE : 3); }