Exclude combos where a single hit already one-shots

Closes #2762
This commit is contained in:
Kalle
2026-01-21 17:34:54 +02:00
parent c2f9aacae9
commit 49ea49a30b
2 changed files with 49 additions and 3 deletions

View File

@@ -171,6 +171,38 @@ describe("calculateDamageCombos - threshold filtering", () => {
});
});
describe("calculateDamageCombos - one-shot exclusion", () => {
test("excludes combos where main/special hit one-shots without sub", () => {
const combos = calculateDamageCombos([SPLAT_CHARGER_ID, SPLATTERSHOT_ID]);
for (const combo of combos) {
const hasNoSubWeapon = combo.segments.every((s) => !s.isSubWeapon);
const hasOneShot = combo.segments.some((s) => s.damageValue >= 100);
const isInvalidCombo = hasNoSubWeapon && hasOneShot;
expect(isInvalidCombo).toBe(false);
}
});
test("keeps combos with 100+ damage when sub weapon is present", () => {
const combos = calculateDamageCombos([SPLAT_CHARGER_ID, SPLATTERSHOT_ID]);
const comboWithSubAndOneShot = combos.find((combo) => {
const hasSub = combo.segments.some((s) => s.isSubWeapon);
const hasOneShot = combo.segments.some((s) => s.damageValue >= 100);
return hasSub && hasOneShot;
});
expect(comboWithSubAndOneShot).toBeDefined();
expect(
comboWithSubAndOneShot!.segments.some((s) => s.isSubWeapon),
).toBe(true);
expect(
comboWithSubAndOneShot!.segments.some((s) => s.damageValue >= 100),
).toBe(true);
});
});
describe("calculateDamageCombos - sorting", () => {
test("sorts results by totalDamage closest to 100 (lethal threshold)", () => {
const combos = calculateDamageCombos([

View File

@@ -302,9 +302,17 @@ function backtrack(
}
function filterAndSortCombos(combos: DamageCombo[]): DamageCombo[] {
const filtered = combos.filter(
(combo) => combo.totalDamage >= COMBO_DAMAGE_THRESHOLD,
);
const filtered = combos.filter((combo) => {
if (combo.totalDamage < COMBO_DAMAGE_THRESHOLD) {
return false;
}
if (hasOneShotWithoutSub(combo)) {
return false;
}
return true;
});
filtered.sort((a, b) => {
const aDistTo100 = Math.abs(a.totalDamage - 100);
@@ -318,6 +326,12 @@ function filterAndSortCombos(combos: DamageCombo[]): DamageCombo[] {
return filtered.slice(0, MAX_COMBOS_DISPLAYED);
}
function hasOneShotWithoutSub(combo: DamageCombo): boolean {
const hasNoSubWeapon = combo.segments.every((s) => !s.isSubWeapon);
const hasOneShot = combo.segments.some((s) => s.damageValue >= 100);
return hasNoSubWeapon && hasOneShot;
}
const SPLASH_O_MATIC_ID = 20;
/**