Update Healer Man server

This commit is contained in:
phenom committed 2026-10-04 13:13:35 -04:00
1 parent 39458d5de6
commit 6cc1b9217f
203 files changed
+133929 -31271

No files matched your search

+45 -6
View File
@@ -15,7 +15,13 @@ import type { PartyState } from "../partyStore";
import { usePartyStore } from "../partyStore";
import type { PartyRole } from "../partyRoles";
import type { BenchmarkScenarioDefinition } from "./benchmarkTypes";
import { COMBAT_ROTATION_VERSION, evaluateCombatRotation } from "../combatRotation";
import { nativeRotationAbilityAllowed, nativeRotationProfileFor } from "../romFiveRotation";
import {
COMBAT_ROTATION_VERSION,
evaluateCombatRotation,
nativeEarlyPriestHealReserveBlocksAbility,
type RotationContext,
} from "../combatRotation";
export const BENCHMARK_POLICY_ID = `rotation-v4:${COMBAT_ROTATION_VERSION}`;
@@ -193,19 +199,37 @@ export class BenchmarkController {
) return { made: false, cast: false, resourceBlocked: false, invalidFailures: 0 };
const targets = friendlyTargets(combat, party);
const availableAbilities = combat.abilities
const learnedAbilities = combat.abilities
.map((ability) => learnedAbility(ability, combat))
.filter((ability): ability is AbilityDefinition => ability !== null)
.filter((ability) => !moving || ability.castTimeMs <= 0 || canAbilityCastWhileMoving(ability));
.filter((ability): ability is AbilityDefinition => ability !== null);
const availableAbilities = learnedAbilities
.filter((ability) => !moving || ability.castTimeMs <= 0 || canAbilityCastWhileMoving(ability))
.filter((ability) => combat.statRuleset !== "rom" || (
(combat.cooldowns[ability.id] ?? 0) <= now
&& (ability.target !== "hostile" || (() => {
const position = combat.selectedTargetId ? getMobPosition(combat.selectedTargetId) : null;
if (!position) return false;
const distance = Math.hypot(...position.map((value, index) => value - combat.playerPosition[index]));
return distance >= ability.range.min && distance <= ability.range.max;
})())
));
const candidates = availableAbilities
.map((ability) => scoreAbility(ability, role, scenario, combat, targets))
.filter((candidate): candidate is ScoredAbility => candidate !== null)
.sort((left, right) => right.score - left.score || left.ability.id.localeCompare(right.ability.id));
const hostileTarget = combat.selectedTargetId ? combat.mobs[combat.selectedTargetId] : null;
const sharedDecision = evaluateCombatRotation({
const rotationContext: RotationContext = {
now,
canUseAbility: combat.statRuleset === "rom" ? (ability) =>
resolvedAbilityCosts(ability, combat.talentModifiers, combat).every((cost) =>
cost.amount <= (cost.resource === "health" ? combat.health : combat.resourcePools[cost.resource] ?? 0))
: undefined,
manaCostForAbility: (ability) => resolvedAbilityCosts(ability, combat.talentModifiers, combat)
.filter((cost) => cost.resource === "mana")
.reduce((total, cost) => total + cost.amount, 0),
classId: combat.classId,
secondaryClassId: combat.secondaryClassId,
statRuleset: combat.statRuleset,
specializationId: combat.specializationId,
role,
level: combat.level,
@@ -219,6 +243,7 @@ export class BenchmarkController {
comboTargetId: combat.comboTargetId,
runes: combat.deathKnightRunes,
abilities: availableAbilities,
learnedAbilities,
knownDamagingAbilityNames: new Set(availableAbilities.filter((ability) => {
const categories = aiHintsForAbility(ability).categories;
return categories.includes("damage") || categories.includes("execute");
@@ -248,6 +273,12 @@ export class BenchmarkController {
&& effect.aura.id === aura.definition.id))
.map((ability) => ability.id)),
]),
maintainedPeriodicEffects: combat.effects.map((effect) => ({
abilityId: effect.sourceAbilityId,
sourceActorId: effect.sourceActorId,
targetId: effect.targetId ?? PLAYER_AGGRO_ID,
remainingMs: Math.max(0, effect.nextTickAt + (effect.remainingTicks - 1) * effect.intervalMs - now),
})),
activeAuraExclusiveGroups: new Set(combat.auras
.filter((aura) => aura.sourceId === PLAYER_AGGRO_ID && (aura.expiresAt === null || aura.expiresAt > now))
.flatMap((aura) => aura.definition.exclusiveGroup ? [aura.definition.exclusiveGroup] : [])),
@@ -260,7 +291,15 @@ export class BenchmarkController {
return source?.effects.some((effect) => effect.kind === "pet"
&& ["summon", "call", "resurrect", "tame"].includes(effect.action)) ?? false;
}),
});
};
const sharedDecision = evaluateCombatRotation(rotationContext);
for (let index = candidates.length - 1; index >= 0; index -= 1) {
const ability = candidates[index].ability;
if (nativeEarlyPriestHealReserveBlocksAbility(ability, rotationContext)
|| (nativeRotationProfileFor(rotationContext) && !nativeRotationAbilityAllowed(ability, rotationContext))) {
candidates.splice(index, 1);
}
}
if (sharedDecision) {
const friendlyTarget = sharedDecision.targetId
? targets.find((target) => target.id === sharedDecision.targetId) ?? null