From ad777a6ec64794fa7c1c70de6396da579652d0d2 Mon Sep 17 00:00:00 2001 From: CatLover <152669316+catloversg@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:44:43 +0700 Subject: [PATCH 1/2] BUGFIX: Wrong calculation in team casualties of Bladeburner action --- src/Bladeburner/Actions/TeamCasualties.ts | 47 ++++++++++++-------- test/jest/Bladeburner/TeamCasualties.test.ts | 11 ++++- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/Bladeburner/Actions/TeamCasualties.ts b/src/Bladeburner/Actions/TeamCasualties.ts index 1f9724f74..aad405050 100644 --- a/src/Bladeburner/Actions/TeamCasualties.ts +++ b/src/Bladeburner/Actions/TeamCasualties.ts @@ -26,22 +26,33 @@ export interface TeamActionWithCasualties { * and may result in casualties, reducing the player's hp, killing team members * and killing sleeves (to shock them, sleeves are immortal) * */ -export function resolveTeamCasualties(action: TeamActionWithCasualties, team: OperationTeam, success: boolean) { - const severity = success ? CasualtyFactor.LOW_CASUALTIES : CasualtyFactor.HIGH_CASUALTIES; - const radius = action.teamCount * severity; - const worstCase = severity < 1 ? Math.ceil(radius) : Math.floor(radius); - /** Best case is always no deaths */ - const deaths = team.getTeamCasualtiesRoll(action.getMinimumCasualties(), worstCase); - const humans = action.teamCount - team.sleeveSize; - const humanDeaths = Math.min(humans, deaths); - /** Supporting Sleeves take damage when they are part of losses, - * e.g. 8 sleeves + 3 team members with 4 losses -> 1 sleeve takes damage */ - team.killRandomSupportingSleeves(deaths - humanDeaths); - - /** Clamped, bugfix for PR#1659 - * "BUGFIX: Wrong team size when all team members die in Bladeburner's action" */ - team.teamSize = Math.max(team.teamSize - humanDeaths, team.sleeveSize); - team.teamLost += deaths; - - return deaths; +export function resolveTeamCasualties(action: TeamActionWithCasualties, team: OperationTeam, success: boolean): number { + if (action.teamCount <= 0) { + return 0; + } + + // Operation actions and Black Operation actions have different min casualties: Min of Ops = 0. Min of BlackOps = 1. + const minCasualties = action.getMinimumCasualties(); + const maxCasualties = success + ? Math.ceil(action.teamCount * CasualtyFactor.LOW_CASUALTIES) + : Math.floor(action.teamCount * CasualtyFactor.HIGH_CASUALTIES); + /** + * In the current state, it's safe to assume that minCasualties <= maxCasualties. However, in the future, if we change + * min casualties, LOW_CASUALTIES, or HIGH_CASUALTIES, the call of getTeamCasualtiesRoll may crash. + * getTeamCasualtiesRoll is just getRandomIntInclusive, and that function's parameters need to be in the form of + * (min, max). + */ + const losses = + minCasualties <= maxCasualties + ? team.getTeamCasualtiesRoll(minCasualties, maxCasualties) + : team.getTeamCasualtiesRoll(maxCasualties, minCasualties); + team.teamSize -= losses; + if (team.teamSize < team.sleeveSize) { + team.killRandomSupportingSleeves(team.sleeveSize - team.teamSize); + // If this happens, all team members died and some sleeves took damage. In this case, teamSize = sleeveSize. + team.teamSize = team.sleeveSize; + } + team.teamLost += losses; + + return losses; } diff --git a/test/jest/Bladeburner/TeamCasualties.test.ts b/test/jest/Bladeburner/TeamCasualties.test.ts index 45c3c17c7..4d62056d2 100644 --- a/test/jest/Bladeburner/TeamCasualties.test.ts +++ b/test/jest/Bladeburner/TeamCasualties.test.ts @@ -18,7 +18,7 @@ import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject"; */ describe("Bladeburner Team", () => { const MAX_ROLL = (_: number, high: number) => high; - const MIN_ROLL = (low: number, _: number) => low; + const MIN_ROLL = (low: number, __: number) => low; const BLACK_OP = BlackOperation.createId(BladeburnerBlackOpName.OperationAnnihilus); const OP = Operation.createId(BladeburnerOperationName.Assassination); @@ -96,6 +96,15 @@ describe("Bladeburner Team", () => { }); describe("Casualties", () => { + it.each([[OP], [BLACK_OP]])( + "no change in team size when not using team. Action: %s", + (op: ActionIdFor | ActionIdFor) => { + teamSize(0), supportingSleeves(3), startAction(op), teamUsed(0), actionFails(); + expect(inst.teamSize).toBe(3); + expect(inst.teamLost).toBe(0); + }, + ); + it("do not affect contracts", () => { teamSize(3); inst.action = Contract.createId(BladeburnerContractName.Tracking); From 87d4c435ba44008079e221eb7ceee84d72ed2568 Mon Sep 17 00:00:00 2001 From: CatLover <152669316+catloversg@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:48:40 +0700 Subject: [PATCH 2/2] Update based on feedback --- src/Bladeburner/Actions/TeamCasualties.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Bladeburner/Actions/TeamCasualties.ts b/src/Bladeburner/Actions/TeamCasualties.ts index aad405050..34266c8a8 100644 --- a/src/Bladeburner/Actions/TeamCasualties.ts +++ b/src/Bladeburner/Actions/TeamCasualties.ts @@ -43,9 +43,7 @@ export function resolveTeamCasualties(action: TeamActionWithCasualties, team: Op * (min, max). */ const losses = - minCasualties <= maxCasualties - ? team.getTeamCasualtiesRoll(minCasualties, maxCasualties) - : team.getTeamCasualtiesRoll(maxCasualties, minCasualties); + minCasualties <= maxCasualties ? team.getTeamCasualtiesRoll(minCasualties, maxCasualties) : minCasualties; team.teamSize -= losses; if (team.teamSize < team.sleeveSize) { team.killRandomSupportingSleeves(team.sleeveSize - team.teamSize);