From 8976d545320aee5de10e1486ba416c20f7cf7f08 Mon Sep 17 00:00:00 2001 From: catloversg <152669316+catloversg@users.noreply.github.com> Date: Thu, 31 Jul 2025 04:44:06 +0700 Subject: [PATCH] API: Add ns.singularity.getHackingLevelRequirementOfProgram (#2271) --- .../bitburner.singularity.createprogram.md | 2 +- ...ity.gethackinglevelrequirementofprogram.md | 32 +++++++++++++++++++ markdown/bitburner.singularity.md | 1 + src/Netscript/RamCostGenerator.ts | 1 + src/NetscriptFunctions/Singularity.ts | 28 ++++++++++++++-- src/Programs/Programs.ts | 7 +++- src/ScriptEditor/NetscriptDefinitions.d.ts | 27 +++++++++------- 7 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 markdown/bitburner.singularity.gethackinglevelrequirementofprogram.md diff --git a/markdown/bitburner.singularity.createprogram.md b/markdown/bitburner.singularity.createprogram.md index b53488d74..82283aa33 100644 --- a/markdown/bitburner.singularity.createprogram.md +++ b/markdown/bitburner.singularity.createprogram.md @@ -33,7 +33,7 @@ This function will automatically set you to start working on creating the specif This function returns true if you successfully start working on the specified program, and false otherwise. -Note that creating a program using this function has the same hacking level requirements as it normally would. These level requirements are:
- BruteSSH.exe: 50
- FTPCrack.exe: 100
- relaySMTP.exe: 250
- HTTPWorm.exe: 500
- SQLInject.exe: 750
- DeepscanV1.exe: 75
- DeepscanV2.exe: 400
- ServerProfiler.exe: 75
- AutoLink.exe: 25 +Note that creating a program using this function has the same hacking level requirements as it normally would. You can call [getHackingLevelRequirementOfProgram](./bitburner.singularity.gethackinglevelrequirementofprogram.md) to get that value. ## Example diff --git a/markdown/bitburner.singularity.gethackinglevelrequirementofprogram.md b/markdown/bitburner.singularity.gethackinglevelrequirementofprogram.md new file mode 100644 index 000000000..d37f56e9d --- /dev/null +++ b/markdown/bitburner.singularity.gethackinglevelrequirementofprogram.md @@ -0,0 +1,32 @@ + + +[Home](./index.md) > [bitburner](./bitburner.md) > [Singularity](./bitburner.singularity.md) > [getHackingLevelRequirementOfProgram](./bitburner.singularity.gethackinglevelrequirementofprogram.md) + +## Singularity.getHackingLevelRequirementOfProgram() method + +Get the hacking level requirement of a program. + +**Signature:** + +```typescript +getHackingLevelRequirementOfProgram(program: string): number; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| program | string | Name of program to create. | + +**Returns:** + +number + +Hacking level requirement. Return Infinity if the specified program cannot be created. + +## Remarks + +RAM cost: 5 GB \* 16/4/1 + +In order to create a program via UI or [createProgram](./bitburner.singularity.createprogram.md), your hacking level must meet the requirement of that program. This API returns that value. + diff --git a/markdown/bitburner.singularity.md b/markdown/bitburner.singularity.md index 301809b6f..bd386e303 100644 --- a/markdown/bitburner.singularity.md +++ b/markdown/bitburner.singularity.md @@ -55,6 +55,7 @@ This API requires Source-File 4 to use. The RAM cost of all these functions is m | [getFactionInviteRequirements(faction)](./bitburner.singularity.getfactioninviterequirements.md) | List conditions for being invited to a faction. | | [getFactionRep(faction)](./bitburner.singularity.getfactionrep.md) | Get faction reputation. | | [getFactionWorkTypes(faction)](./bitburner.singularity.getfactionworktypes.md) | Get the work types of a faction. | +| [getHackingLevelRequirementOfProgram(program)](./bitburner.singularity.gethackinglevelrequirementofprogram.md) | Get the hacking level requirement of a program. | | [getOwnedAugmentations(purchased)](./bitburner.singularity.getownedaugmentations.md) | Get a list of owned augmentation. | | [getOwnedSourceFiles()](./bitburner.singularity.getownedsourcefiles.md) | Get a list of acquired Source-Files. | | [getSaveData()](./bitburner.singularity.getsavedata.md) | This function returns the save data. | diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index 5b1c27db6..36fe4487e 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -199,6 +199,7 @@ const singularity = { getFactionFavorGain: SF4Cost(RamCostConstants.SingularityFn2 / 4), donateToFaction: SF4Cost(RamCostConstants.SingularityFn3), createProgram: SF4Cost(RamCostConstants.SingularityFn3), + getHackingLevelRequirementOfProgram: SF4Cost(RamCostConstants.SingularityFn3), commitCrime: SF4Cost(RamCostConstants.SingularityFn3), getCrimeChance: SF4Cost(RamCostConstants.SingularityFn3), getCrimeStats: SF4Cost(RamCostConstants.SingularityFn3), diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index bbf017661..d66a48eb3 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -1,7 +1,7 @@ import type { Singularity as ISingularity } from "@nsdefs"; import { Player } from "@player"; -import { CityName, FactionWorkType, LocationName } from "@enums"; +import { CityName, CompletedProgramName, FactionWorkType, LocationName } from "@enums"; import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers"; import { startWorkerScript } from "../NetscriptWorker"; import { Augmentations } from "../Augmentation/Augmentations"; @@ -16,7 +16,7 @@ import { Page } from "../ui/Router"; import { SpecialServers } from "../Server/data/SpecialServers"; import { Locations } from "../Locations/Locations"; import { GetServer } from "../Server/AllServers"; -import { Programs } from "../Programs/Programs"; +import { getEffectiveHackingLevelRequirement, Programs } from "../Programs/Programs"; import { formatMoney, formatRam, formatReputation } from "../ui/formatNumber"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { Companies } from "../Company/Companies"; @@ -963,7 +963,7 @@ export function NetscriptSingularity(): InternalAPI { const p = Object.values(Programs).find((p) => p.name.toLowerCase() === programName); if (p == null) { - helpers.log(ctx, () => `The specified program does not exist: '${programName}`); + helpers.log(ctx, () => `The specified program does not exist: '${programName}'`); return false; } @@ -1002,6 +1002,28 @@ export function NetscriptSingularity(): InternalAPI { helpers.log(ctx, () => `Began creating program: '${programName}'`); return true; }, + getHackingLevelRequirementOfProgram: (ctx) => (_programName) => { + helpers.checkSingularityAccess(ctx); + const programName = helpers.string(ctx, "programName", _programName).toLowerCase(); + + const program = Object.values(Programs).find((p) => p.name.toLowerCase() === programName); + if (program == null) { + throw helpers.errorMessage(ctx, `The specified program does not exist: '${programName}'`); + } + + const create = program.create; + // Return Infinity if this program cannot be created. + if (create === null) { + return Infinity; + } + + // The hacking level requirement of bitFlume is exactly 1. It does not depend on Intelligence. + if (program.name === CompletedProgramName.bitFlume) { + return 1; + } + + return getEffectiveHackingLevelRequirement(create.level); + }, commitCrime: (ctx) => (_crimeType, _focus) => { helpers.checkSingularityAccess(ctx); const crimeType = getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType); diff --git a/src/Programs/Programs.ts b/src/Programs/Programs.ts index 68bb35ed8..d822ea658 100644 --- a/src/Programs/Programs.ts +++ b/src/Programs/Programs.ts @@ -14,13 +14,18 @@ import { CompletedProgramName, FactionName } from "@enums"; import { Router } from "../ui/GameRoot"; import { Page } from "../ui/Router"; import { knowAboutBitverse } from "../BitNode/BitNodeUtils"; +import { clampNumber } from "../utils/helpers/clampNumber"; function requireHackingLevel(lvl: number) { return function () { - return Player.skills.hacking + Player.skills.intelligence / 2 >= lvl; + return Player.skills.hacking >= getEffectiveHackingLevelRequirement(lvl); }; } +export function getEffectiveHackingLevelRequirement(level: number): number { + return clampNumber(level - Player.skills.intelligence / 2, 1); +} + function bitFlumeRequirements() { return function () { return knowAboutBitverse() && Player.skills.hacking >= 1; diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index aa5de5102..fc1ab58fd 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -2418,17 +2418,9 @@ export interface Singularity { * * This function returns true if you successfully start working on the specified program, and false otherwise. * - * Note that creating a program using this function has the same hacking level requirements as it normally would. - * These level requirements are:
- * - BruteSSH.exe: 50
- * - FTPCrack.exe: 100
- * - relaySMTP.exe: 250
- * - HTTPWorm.exe: 500
- * - SQLInject.exe: 750
- * - DeepscanV1.exe: 75
- * - DeepscanV2.exe: 400
- * - ServerProfiler.exe: 75
- * - AutoLink.exe: 25 + * Note that creating a program using this function has the same hacking level requirements as it normally would. You + * can call {@link Singularity.getHackingLevelRequirementOfProgram | getHackingLevelRequirementOfProgram} to get that + * value. * * @example * ```js @@ -2442,6 +2434,19 @@ export interface Singularity { */ createProgram(program: string, focus?: boolean): boolean; + /** + * Get the hacking level requirement of a program. + * @remarks + * RAM cost: 5 GB * 16/4/1 + * + * In order to create a program via UI or {@link Singularity.createProgram | createProgram}, your hacking level must + * meet the requirement of that program. This API returns that value. + * + * @param program - Name of program to create. + * @returns Hacking level requirement. Return Infinity if the specified program cannot be created. + */ + getHackingLevelRequirementOfProgram(program: string): number; + /** * Commit a crime. * @remarks