diff --git a/src/BitNode/BitNode.tsx b/src/BitNode/BitNode.tsx
index 02ee94387..01741816b 100644
--- a/src/BitNode/BitNode.tsx
+++ b/src/BitNode/BitNode.tsx
@@ -467,7 +467,7 @@ export function initBitNodes() {
Level 2: Permanently unlocks the go.cheat API
- Level 3: 25% increased success rate for the go.cheat API
+ Level 3: 25% additive increased success rate for the go.cheat API
This Source-File also increases the maximum favor you can gain for each faction from IPvGO to:
diff --git a/src/Go/effects/netscriptGoImplementation.ts b/src/Go/effects/netscriptGoImplementation.ts
index ac6094fb1..74d82535d 100644
--- a/src/Go/effects/netscriptGoImplementation.ts
+++ b/src/Go/effects/netscriptGoImplementation.ts
@@ -416,10 +416,25 @@ export async function determineCheatSuccess(
/**
* Cheating success rate scales with player's crime success rate, and decreases with prior cheat attempts.
+ *
+ * The source file bonus is additive success chance on top of the other multipliers.
+ *
+ * Cheat success chance required for N cheats with 100% success rate in a game:
+ *
+ * 1 100% success rate cheat requires +66% increased crime success rate
+ * 2 100% success cheats: +145% increased crime success rate
+ * 3: +282%
+ * 4: +535%
+ * 5: +1027%
+ * 7: +4278%
+ * 10: +59,854%
+ * 12: +534,704%
+ * 15: +31,358,645%
*/
export function cheatSuccessChance(cheatCount: number) {
- const sourceFileBonus = Player.sourceFileLvl(14) === 3 ? 1.25 : 1;
- return Math.min(0.6 * 0.65 ** cheatCount * Player.mults.crime_success * sourceFileBonus, 1);
+ const sourceFileBonus = Player.sourceFileLvl(14) === 3 ? 0.25 : 0;
+ const cheatCountScalar = (0.7 - 0.02 * cheatCount) ** cheatCount;
+ return Math.max(Math.min(0.6 * cheatCountScalar * Player.mults.crime_success + sourceFileBonus, 1), 0);
}
/**
diff --git a/src/SourceFile/SourceFiles.tsx b/src/SourceFile/SourceFiles.tsx
index 07a4b8418..0b2a9a86c 100644
--- a/src/SourceFile/SourceFiles.tsx
+++ b/src/SourceFile/SourceFiles.tsx
@@ -243,7 +243,7 @@ export function initSourceFiles() {
Level 2: Permanently unlocks the go.cheat API in other BitNodes
- Level 3: 25% increased success rate for the go.cheat API
+ Level 3: 25% additive increased success rate for the go.cheat API
This Source-File also increases the maximum favor you can gain for each faction from IPvGO to:
diff --git a/test/jest/Go/NetscriptGo.test.ts b/test/jest/Go/NetscriptGo.test.ts
index f771031ce..85a6174ee 100644
--- a/test/jest/Go/NetscriptGo.test.ts
+++ b/test/jest/Go/NetscriptGo.test.ts
@@ -1,11 +1,12 @@
-import { setPlayer } from "@player";
-import { GoColor, GoOpponent, GoPlayType } from "@enums";
+import { Player, setPlayer } from "@player";
+import { AugmentationName, GoColor, GoOpponent, GoPlayType } from "@enums";
import { Go } from "../../../src/Go/Go";
import { boardStateFromSimpleBoard, simpleBoardFromBoard } from "../../../src/Go/boardAnalysis/boardAnalysis";
import {
cheatPlayTwoMoves,
cheatRemoveRouter,
cheatRepairOfflineNode,
+ cheatSuccessChance,
getChains,
getControlledEmptyNodes,
getGameState,
@@ -19,12 +20,24 @@ import {
import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
import "../../../src/Faction/Factions";
import { getNewBoardState } from "../../../src/Go/boardState/boardState";
+import { installAugmentations } from "../../../src/Augmentation/AugmentationHelpers";
+import { AddToAllServers } from "../../../src/Server/AllServers";
+import { Server } from "../../../src/Server/Server";
+import { initSourceFiles } from "../../../src/SourceFile/SourceFiles";
jest.mock("../../../src/Faction/Factions", () => ({
Factions: {},
}));
+jest.mock("../../../src/ui/GameRoot", () => ({
+ Router: {
+ page: () => ({}),
+ toPage: () => ({}),
+ },
+}));
+
setPlayer(new PlayerObject());
+AddToAllServers(new Server({ hostname: "home" }));
describe("Netscript Go API unit tests", () => {
describe("makeMove() tests", () => {
@@ -304,4 +317,27 @@ describe("Netscript Go API unit tests", () => {
expect(Go.currentGame.board[4]?.[4]?.color).toEqual(GoColor.empty);
});
});
+
+ describe("Cheat success chance unit tests", () => {
+ it("should have a base chance", () => {
+ expect(cheatSuccessChance(0)).toEqual(0.6);
+ });
+
+ it("should have a scaled chance based on cheat count", () => {
+ expect(cheatSuccessChance(4)).toEqual(0.6 * (0.7 - 0.08) ** 4);
+ });
+
+ it("should have a scaled chance based on layer cheat success level", () => {
+ Player.setBitNodeNumber(13);
+ initSourceFiles();
+ Player.queueAugmentation(AugmentationName.BrachiBlades);
+ Player.queueAugmentation(AugmentationName.GrapheneBrachiBlades);
+ Player.queueAugmentation(AugmentationName.INFRARet);
+ Player.queueAugmentation(AugmentationName.PCMatrix);
+ Player.queueAugmentation(AugmentationName.NeuroFluxGovernor);
+ installAugmentations();
+
+ expect(cheatSuccessChance(4)).toEqual(0.6 * (0.7 - 0.08) ** 4 * Player.mults.crime_success);
+ });
+ });
});