mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 23:19:39 -05:00
Filter out excessive combos in comp analyzer
This commit is contained in:
parent
1edbda787f
commit
3ec5af1128
|
|
@ -15,6 +15,8 @@ export const MAX_COMBOS_DISPLAYED = 50;
|
|||
|
||||
export const COMBO_DAMAGE_THRESHOLD = 80;
|
||||
|
||||
export const LETHAL_DAMAGE = 100;
|
||||
|
||||
export const SUB_WEAPON_CATEGORIES: Record<SubWeaponId, SubWeaponCategory> = {
|
||||
0: "LETHAL", // Splat Bomb
|
||||
1: "LETHAL", // Suction Bomb
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
specialWeaponImageUrl,
|
||||
subWeaponImageUrl,
|
||||
} from "~/utils/urls";
|
||||
import { LETHAL_DAMAGE } from "../comp-analyzer-constants";
|
||||
import { useTargetResAp, useTargetSubDefenseAp } from "../comp-analyzer-hooks";
|
||||
import type { DamageCombo, DamageSegment } from "../comp-analyzer-types";
|
||||
import {
|
||||
|
|
@ -36,7 +37,6 @@ function weaponTypeFromSegment(
|
|||
}
|
||||
|
||||
const SLOT_COLORS = ["yellow", "pink", "green", "blue"] as const;
|
||||
const LETHAL_DAMAGE = 100;
|
||||
|
||||
interface DamageComboBarProps {
|
||||
combo: DamageCombo;
|
||||
|
|
|
|||
|
|
@ -322,6 +322,51 @@ describe("calculateInkTimeToKill", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("calculateDamageCombos - excessive combo filtering", () => {
|
||||
test("filters out excessive combos (200+ damage where removing any hit still kills)", () => {
|
||||
const combos = calculateDamageCombos(
|
||||
[SPLATTERSHOT_ID, SPLAT_ROLLER_ID, SPLAT_CHARGER_ID, AEROSPRAY_MG_ID],
|
||||
[],
|
||||
0,
|
||||
1000,
|
||||
);
|
||||
|
||||
const hasExcessiveCombo = combos.some((combo) => {
|
||||
const flatDamages = combo.segments.flatMap((s) =>
|
||||
Array(s.count).fill(s.damageValue),
|
||||
);
|
||||
for (const damage of flatDamages) {
|
||||
const reducedDamage = combo.totalDamage - damage;
|
||||
if (reducedDamage >= 100) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(hasExcessiveCombo).toBe(false);
|
||||
});
|
||||
|
||||
test("allows combos where removing any hit drops below lethal threshold", () => {
|
||||
const combos = calculateDamageCombos(
|
||||
[SPLATTERSHOT_ID, SPLAT_ROLLER_ID],
|
||||
[],
|
||||
0,
|
||||
1000,
|
||||
);
|
||||
|
||||
for (const combo of combos) {
|
||||
const flatDamages = combo.segments.flatMap((s) =>
|
||||
Array(s.count).fill(s.damageValue),
|
||||
);
|
||||
const allHitsNecessary = flatDamages.every(
|
||||
(damage) => combo.totalDamage - damage < 100,
|
||||
);
|
||||
expect(allHitsNecessary).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("virtual damage combos", () => {
|
||||
test("Explosher has COMBO damage type combining DIRECT and DISTANCE", () => {
|
||||
const sources = extractDamageSources([EXPLOSHER_ID]);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { weaponParams } from "~/features/build-analyzer/core/utils";
|
|||
import type { MainWeaponId } from "~/modules/in-game-lists/types";
|
||||
import {
|
||||
COMBO_DAMAGE_THRESHOLD,
|
||||
LETHAL_DAMAGE,
|
||||
MAX_COMBOS_DISPLAYED,
|
||||
MAX_DAMAGE_TYPES_PER_COMBO,
|
||||
MAX_REPEATS_PER_DAMAGE_TYPE,
|
||||
|
|
@ -145,6 +146,7 @@ export function calculateDamageCombos(
|
|||
weaponIds: MainWeaponId[],
|
||||
excludedKeys: ExcludedDamageKey[] = [],
|
||||
targetSubDefenseAp = 0,
|
||||
maxCombosDisplayed = MAX_COMBOS_DISPLAYED,
|
||||
): DamageCombo[] {
|
||||
if (weaponIds.length < 2) {
|
||||
return [];
|
||||
|
|
@ -157,7 +159,7 @@ export function calculateDamageCombos(
|
|||
const sources = extractDamageSources(weaponIds, targetSubDefenseAp);
|
||||
const damageOptions = flattenToOptions(sources, excludedSet);
|
||||
const combos = generateCombinations(damageOptions);
|
||||
const filtered = filterAndSortCombos(combos);
|
||||
const filtered = filterAndSortCombos(combos, maxCombosDisplayed);
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
|
@ -301,7 +303,10 @@ function backtrack(
|
|||
}
|
||||
}
|
||||
|
||||
function filterAndSortCombos(combos: DamageCombo[]): DamageCombo[] {
|
||||
function filterAndSortCombos(
|
||||
combos: DamageCombo[],
|
||||
maxCombosDisplayed: number,
|
||||
): DamageCombo[] {
|
||||
const filtered = combos.filter((combo) => {
|
||||
if (combo.totalDamage < COMBO_DAMAGE_THRESHOLD) {
|
||||
return false;
|
||||
|
|
@ -311,6 +316,10 @@ function filterAndSortCombos(combos: DamageCombo[]): DamageCombo[] {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (isExcessiveCombo(combo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
@ -323,11 +332,29 @@ function filterAndSortCombos(combos: DamageCombo[]): DamageCombo[] {
|
|||
return a.hitCount - b.hitCount;
|
||||
});
|
||||
|
||||
return filtered.slice(0, MAX_COMBOS_DISPLAYED);
|
||||
return filtered.slice(0, maxCombosDisplayed);
|
||||
}
|
||||
|
||||
function hasOneShot(combo: DamageCombo): boolean {
|
||||
return combo.segments.some((s) => s.damageValue >= 100);
|
||||
return combo.segments.some((s) => s.damageValue >= LETHAL_DAMAGE);
|
||||
}
|
||||
|
||||
function isExcessiveCombo(combo: DamageCombo): boolean {
|
||||
const flatDamages = combo.segments.flatMap((s) =>
|
||||
Array(s.count).fill(s.damageValue),
|
||||
);
|
||||
const totalDamage = combo.totalDamage;
|
||||
|
||||
for (let i = 0; i < flatDamages.length; i++) {
|
||||
const damage = flatDamages[i];
|
||||
|
||||
const reducedDamage = totalDamage - damage;
|
||||
if (reducedDamage >= LETHAL_DAMAGE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const SPLASH_O_MATIC_ID = 20;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user