85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
selectEnemyChainTargets,
|
|
type EnemyChainTargetCandidate,
|
|
} from "./enemyChainTargeting";
|
|
|
|
const target = (
|
|
id: string,
|
|
x: number,
|
|
alive = true,
|
|
): EnemyChainTargetCandidate => ({
|
|
id,
|
|
alive,
|
|
position: [x, 0, 0],
|
|
});
|
|
|
|
describe("enemy chain target selection", () => {
|
|
it("keeps the primary first and selects the nearest target from each prior hit", () => {
|
|
const primary = target("primary", 0);
|
|
const hits = selectEnemyChainTargets({
|
|
primaryTarget: primary,
|
|
candidates: [target("east", 6), target("west", -5), target("west-next", -13)],
|
|
maximumTargets: 3,
|
|
jumpRange: 10,
|
|
damageMultiplierPerBounce: 0.6,
|
|
hasLineOfSight: () => true,
|
|
});
|
|
|
|
expect(hits.map(({ target: hit, jumpIndex, damageMultiplier }) => ({
|
|
id: hit.id,
|
|
jumpIndex,
|
|
damageMultiplier,
|
|
}))).toEqual([
|
|
{ id: "primary", jumpIndex: 0, damageMultiplier: 1 },
|
|
{ id: "west", jumpIndex: 1, damageMultiplier: 0.6 },
|
|
{ id: "west-next", jumpIndex: 2, damageMultiplier: 0.36 },
|
|
]);
|
|
});
|
|
|
|
it("skips dead, out-of-pool, and blocked candidates without repeating actor IDs", () => {
|
|
const primary = target("primary", 0);
|
|
const hits = selectEnemyChainTargets({
|
|
primaryTarget: primary,
|
|
candidates: [
|
|
target("blocked", 1),
|
|
target("first", 3),
|
|
target("first", 3.1),
|
|
target("dead", 3.2, false),
|
|
target("second", 7),
|
|
target("outside-search-pool", 41),
|
|
],
|
|
maximumTargets: 4,
|
|
jumpRange: 10,
|
|
damageMultiplierPerBounce: 0.7,
|
|
hasLineOfSight: (_source, destination) => destination[0] !== 1,
|
|
});
|
|
|
|
expect(hits.map(({ target: hit }) => hit.id)).toEqual(["primary", "first", "second"]);
|
|
expect(hits.map(({ damageMultiplier }) => damageMultiplier)).toEqual([1, 0.7, 0.7 * 0.7]);
|
|
});
|
|
|
|
it("aborts for a dead primary and never replaces a living primary with a nearer candidate", () => {
|
|
const deadPrimary = target("dead-primary", 0, false);
|
|
expect(selectEnemyChainTargets({
|
|
primaryTarget: deadPrimary,
|
|
candidates: [target("nearby", 0.1)],
|
|
maximumTargets: 3,
|
|
jumpRange: 10,
|
|
damageMultiplierPerBounce: 0.6,
|
|
hasLineOfSight: () => true,
|
|
})).toEqual([]);
|
|
|
|
const primary = target("primary", 0);
|
|
const hits = selectEnemyChainTargets({
|
|
primaryTarget: primary,
|
|
candidates: [target("nearby", 0.1)],
|
|
maximumTargets: 3,
|
|
jumpRange: 10,
|
|
damageMultiplierPerBounce: 0.6,
|
|
hasLineOfSight: () => true,
|
|
});
|
|
expect(hits.map(({ target: hit }) => hit.id)).toEqual(["primary", "nearby"]);
|
|
});
|
|
});
|