Fix benchmark maintained aura selection (#18)

This commit is contained in:
warren authored and Codex (Root combat coordinator) committed 2026-10-15 09:10:55 -04:00
1 parent 89b6f4f79d
commit 72a67ac1e3
5 files changed
+205 -13

No files matched your search

+47 -5
View File
@@ -94,6 +94,11 @@ export interface RotationContext {
readonly targetId: string;
readonly remainingMs: number;
}[];
/** Active applied auras with their actual recipient, filtered for expiry. */
readonly maintainedAuras?: readonly {
readonly auraId: string;
readonly targetId: string;
}[];
readonly activeAuraExclusiveGroups?: ReadonlySet<string>;
readonly activeSummonAbilityIds?: ReadonlySet<string>;
readonly hasActivePet?: boolean;
@@ -378,6 +383,36 @@ function targetForAbility(
return null;
}
/** Whether this applied-aura action is already active on the recipient it would use. */
export function abilityAuraMaintainedOnTarget(
ability: AbilityDefinition,
context: RotationContext,
targetId: string | null,
): boolean {
// An aura can be a side effect of an attack. Keep those casts available for
// their damage or healing; this guard only handles maintenance actions.
if (ability.effects.some((effect) => effect.kind === "damage" || effect.kind === "dot"
|| effect.kind === "heal" || effect.kind === "hot" || effect.kind === "shield"
|| effect.kind === "finisher-damage" || effect.kind === "execute")) return false;
const auraEffects = ability.effects.filter((effect) => effect.kind === "apply-aura");
if (auraEffects.length === 0) return false;
const maintainedAuras = context.maintainedAuras;
if (maintainedAuras !== undefined) {
return auraEffects.some((effect) => {
const recipientId = effect.recipient === "caster"
? context.selfId ?? null
: effect.recipient === "pet" ? null : targetId;
return recipientId !== null && maintainedAuras.some((aura) => (
aura.targetId === recipientId && aura.auraId === effect.aura.id
));
});
}
// Older selector callers only expose caster-owned exclusive groups. Keep
// their conservative behavior until they provide recipient-scoped auras.
return auraEffects.some((effect) => Boolean(effect.aura.exclusiveGroup
&& context.activeAuraExclusiveGroups?.has(effect.aura.exclusiveGroup)));
}
interface ScoredRotationAbility {
readonly ability: AbilityDefinition;
readonly score: number;
@@ -410,13 +445,20 @@ function scoreAbility(
&& ability.effects.some((effect) => effect.kind === "dot" || effect.kind === "hot");
const coaPeriodic = context.maintainedPeriodicEffects !== undefined && Boolean(context.selfId)
&& usesCoaTargetedPeriodicMaintenance(ability, context);
const maintenanceTargetId = targetForAbility(ability, context, lowest)
?? (ability.target === "self" ? context.selfId ?? null : null);
const periodicMaintained = coaPeriodic
? coaPeriodicActionMaintainedOnTarget(ability, context, targetForAbility(ability, context, lowest))
: !nativePeriodic && (context.maintainedAbilityIds?.has(ability.id) ?? false);
? coaPeriodicActionMaintainedOnTarget(ability, context, maintenanceTargetId)
: !nativePeriodic && (context.maintainedPeriodicEffects !== undefined
? context.maintainedPeriodicEffects.some((effect) => (
effect.abilityId === ability.id
&& effect.sourceActorId === context.selfId
&& effect.targetId === maintenanceTargetId
&& effect.remainingMs > 0
))
: (context.maintainedAbilityIds?.has(ability.id) ?? false));
const maintained = periodicMaintained
|| ability.effects.some((effect) => effect.kind === "apply-aura"
&& Boolean(effect.aura.exclusiveGroup
&& context.activeAuraExclusiveGroups?.has(effect.aura.exclusiveGroup)));
|| abilityAuraMaintainedOnTarget(ability, context, maintenanceTargetId);
const activeSummon = context.activeSummonAbilityIds?.has(ability.id) ?? false;
const petSummon = isPetSummon(ability);
const offensiveSummon = isOffensiveSummon(ability);