Update Healer Man server
This commit is contained in:
1 parent
39458d5de6
commit
6cc1b9217f
203 files changed
+133929
-31271
No files matched your search
@@ -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
|
||||
|
||||
Reference in new issue
Block a user