BUGFIX: Wrong calculation in team casualties of Bladeburner action (#1672)

This commit is contained in:
catloversg 2024-10-08 13:55:11 +07:00 committed by GitHub
parent 2fa8dd41ac
commit cace34d759
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 17 deletions

@ -26,22 +26,31 @@ 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);
export function resolveTeamCasualties(action: TeamActionWithCasualties, team: OperationTeam, success: boolean): number {
if (action.teamCount <= 0) {
return 0;
}
/** 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;
// 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) : 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 deaths;
return losses;
}

@ -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<BlackOperation> | ActionIdFor<Operation>) => {
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);