Update Healer Man server

This commit is contained in:
phenom committed 2026-09-27 14:31:15 -04:00
1 parent ab1434a3b8
commit e284f4fc76
60 files changed
+2704 -118

No files matched your search

+26 -15
View File
@@ -101,6 +101,7 @@ import {
type CombatPosition,
} from "./mobRuntimeRegistry";
import { enemyTelegraphContainsPosition } from "./enemyTelegraphGeometry";
import { raceAffixHasteMultiplier, raceAffixMobDamageMultiplier } from "./dungeonRaceAffixBuffs";
import {
getPartyRuntimePosition,
partyRuntimeDistanceSquared,
@@ -251,6 +252,7 @@ import {
} from "./combatRotation";
import {
emitCombatPresentation,
penancePulseVisualSpellId,
presentationDeliveryForAbility,
presentationSchoolForAbility,
presentationSourceForAbility,
@@ -975,17 +977,19 @@ function emitPlayerAbilityPresentation(
targetId: string | null,
targetPosition: CombatPosition | null,
instantCast = false,
penanceHostile = false,
): void {
const delivery = presentationDeliveryForAbility(ability);
const penancePulse = ability.id === "wow335-priest-penance" && phase === "tick";
const delivery = penancePulse ? "projectile" : presentationDeliveryForAbility(ability);
const presentationTargetId = targetId ?? (delivery === "aura" ? PLAYER_AURA_ENTITY_ID : null);
emitCombatPresentation({
const event = {
occurredAt,
phase,
actorGroup: "player",
sourceActorId: PLAYER_AGGRO_ID,
...(presentationTargetId ? { targetActorId: presentationTargetId } : {}),
abilityId: ability.id,
sourceSpellId: ability.dbcSpellId,
sourceSpellId: penancePulse ? penancePulseVisualSpellId(penanceHostile) : ability.dbcSpellId,
name: ability.name,
source: presentationSourceForAbility(ability),
school: presentationSchoolForAbility(ability),
@@ -995,7 +999,9 @@ function emitPlayerAbilityPresentation(
...(ability.radius === undefined ? {} : { radius: ability.radius }),
...(ability.castTimeMs > 0 ? { durationMs: ability.castTimeMs } : {}),
...(instantCast ? { instantCast: true } : {}),
});
} as const;
emitCombatPresentation(event);
if (penancePulse) emitCombatPresentation({ ...event, phase: "impact" });
}
function emitPlayerAbilityCancellation(abilityId: string, occurredAt: number, origin: CombatPosition): void {
@@ -1013,6 +1019,7 @@ function emitPlayerAbilityResolutionPresentation(
instantCast: boolean,
): void {
emitPlayerAbilityPresentation(ability, "release", occurredAt, origin, targetId, targetPosition, instantCast);
if (ability.id === "wow335-priest-penance") return;
emitPlayerAbilityPresentation(
ability,
presentationDeliveryForAbility(ability) === "aura" ? "aura-start" : "impact",
@@ -1128,7 +1135,8 @@ function playerAutoAttackProfile(
const weaponDamage = weapon
? (weapon.damageMin + weapon.damageMax) / 2
: playerCombatPower(state.level) * 0.35;
const intervalMs = hastedDuration(speedMs, stats.meleeHastePercent);
const intervalMs = Math.max(500, Math.round(hastedDuration(speedMs, stats.meleeHastePercent)
/ raceAffixHasteMultiplier()));
return {
damage: Math.max(1, Math.round(weaponDamage + stats.attackPower / 14 * speedSeconds)),
intervalMs,
@@ -1827,7 +1835,7 @@ function talentAdjustedCastTime(
duration,
ratingPercent(gearStats.hasteRating, "spellHaste", level, classId),
);
return Math.max(0, Math.round(duration / Math.max(0.1, hasteMultiplier)));
return Math.max(0, Math.round(duration / Math.max(0.1, hasteMultiplier * raceAffixHasteMultiplier())));
}
function talentAdjustedCooldown(ability: AbilityDefinition, modifiers: readonly TalentModifier[]): number {
@@ -1852,7 +1860,7 @@ function talentAdjustedGcd(
ratingPercent(gearStats.hasteRating, "spellHaste", level, classId),
1_000,
);
return Math.max(1_000, Math.round(duration / Math.max(0.1, hasteMultiplier)));
return Math.max(1_000, Math.round(duration / Math.max(0.1, hasteMultiplier * raceAffixHasteMultiplier())));
}
function talentAdjustedDuration(
@@ -3285,7 +3293,7 @@ function executeTriggeredSpellInWork(
maxHealth: Math.max(1, Math.round(work.maxHealth * 0.3)),
position: getMobPosition(targetId ?? "") ?? [0, 0, 0],
nextActionAt: now + 1_000,
pulseIntervalMs: /totem/i.test(ability.name) ? 2_000 : 2_200,
pulseIntervalMs: ability.name === "Shadowfiend" ? 1_500 : /totem/i.test(ability.name) ? 2_000 : 2_200,
attackDamage: Math.max(1, Math.round(playerCombatPower(work.progression.level) * Math.max(0.15, effect.coefficient))),
...initialSummonCombatRuntime(),
});
@@ -5779,7 +5787,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
maxHealth: Math.max(1, Math.round(work.maxHealth * 0.3)),
position: groundPosition ?? playerOrigin,
nextActionAt: now + 1_000,
pulseIntervalMs: /totem/i.test(ability.name) ? 2_000 : 2_200,
pulseIntervalMs: ability.name === "Shadowfiend" ? 1_500 : /totem/i.test(ability.name) ? 2_000 : 2_200,
attackDamage: Math.max(1, Math.round(playerCombatPower(work.progression.level) * Math.max(0.15, effect.coefficient))),
...initialSummonCombatRuntime(),
...(/totem/i.test(ability.name) ? { exclusiveGroup: "totem" } : {}),
@@ -7590,7 +7598,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
maxHealth,
position,
nextActionAt: now + 1_000,
pulseIntervalMs: isTotem ? 2_000 : 2_200,
pulseIntervalMs: ability.name === "Shadowfiend" ? 1_500 : isTotem ? 2_000 : 2_200,
attackDamage: Math.max(1, Math.round(owner.level * 4 * Math.max(0.15, effect.coefficient))),
...initialSummonCombatRuntime(),
...(isTotem ? { exclusiveGroup: `${ownerActorId}:totem` } : {}),
@@ -8685,7 +8693,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
hit.mob,
hit.attack,
defender,
talentAdjustedIncomingDamage(hit.amount, current.talentModifiers),
talentAdjustedIncomingDamage(Math.round(hit.amount * raceAffixMobDamageMultiplier(hit.mob.id, now)), current.talentModifiers),
hit.actorId,
hit.attackRevision,
now,
@@ -8943,7 +8951,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
hit.mob,
hit.attack,
defender,
hit.amount,
Math.round(hit.amount * raceAffixMobDamageMultiplier(hit.mob.id, now)),
hit.actorId,
hit.attackRevision,
now,
@@ -9644,8 +9652,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
targetId,
summon.attackDamage,
now,
{ actorId: summon.ownerActorId, role: "damage", abilityId: summon.sourceAbilityId },
"physical",
{ actorId: summonAbility?.name === "Shadowfiend" ? summon.id : summon.ownerActorId,
role: "damage", abilityId: summon.sourceAbilityId },
summonAbility?.name === "Shadowfiend" ? "shadow" : "physical",
);
if (summonAbility?.name === "Shadowfiend" && result.amount > 0) {
shadowfiendManaRestores.push({
@@ -9758,7 +9767,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
for (const restore of shadowfiendManaRestores) {
get().restoreActorResource(
restore.ownerActorId, "mana", 1, true, restore.summonId, restore.abilityId, now,
restore.ownerActorId, "mana", 5, true, restore.summonId, restore.abilityId, now,
);
}
@@ -10009,6 +10018,8 @@ export const useCombatStore = create<CombatState>((set, get) => ({
get().playerPosition,
cast.targetId,
cast.groundPosition ?? (cast.targetId ? getMobPosition(cast.targetId) : get().playerPosition),
false,
channelHostile,
);
ticksCompleted += 1;
nextTickAt = channelPulseAt(ability, cast.startedAt, cast.originalDurationMs, ticksCompleted);