forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
4c768fbec6
commit
b16821e92e
330 files changed
+35406
-1760
No files matched your search
@@ -5,7 +5,8 @@ import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore";
|
||||
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry";
|
||||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||||
import { DEFAULT_ENEMY_ATTACK } from "./enemyAttacks";
|
||||
import { usePartyStore } from "./partyStore";
|
||||
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
|
||||
import { EMPTY_ITEM_STATS } from "./itemStats";
|
||||
import { romEffectsForCast, type RomCastMechanics } from "./romCombatMechanics";
|
||||
import {
|
||||
ROM_WARDEN_BRIAR_SHIELD_TAG,
|
||||
@@ -442,6 +443,115 @@ describe("RoM Warden and Warden-linked source behaviors", () => {
|
||||
.toBeCloseTo(ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, 1);
|
||||
});
|
||||
|
||||
it("transfers party Warden damage once to a live pet within 300 range, and respects pet expiry", () => {
|
||||
const resolvePartyHit = (options: {
|
||||
readonly petDistance?: number;
|
||||
readonly petExpiresAt?: number;
|
||||
readonly transferAura?: boolean;
|
||||
} = {}) => {
|
||||
const seed = "warden-party-damage-transfer";
|
||||
const now = 1_000;
|
||||
const hitAt = 1_450;
|
||||
initializeRomCharacter("rom-warden");
|
||||
usePartyStore.getState().initializeParty(seed, 80, useCombatStore.getState().health);
|
||||
const warden = createConfiguredPartyMember({
|
||||
name: "Warden Companion",
|
||||
classId: "rom-warden",
|
||||
specialization: "Primary",
|
||||
specializationId: "rom-warden:primary",
|
||||
talentTreeId: "rom-warden-primary",
|
||||
role: "tank",
|
||||
}, 80, 0, seed);
|
||||
usePartyStore.setState({ members: [{ ...warden, gearStats: EMPTY_ITEM_STATS }] });
|
||||
registerPartyRuntimePosition(warden.id, [0, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
|
||||
const summonAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493333)!;
|
||||
const summonEffect = summonAbility.effects.find((effect) => effect.kind === "summon");
|
||||
expect(summonEffect?.kind).toBe("summon");
|
||||
if (!summonEffect || summonEffect.kind !== "summon") throw new Error("Warden summon effect missing");
|
||||
const petId = useCombatStore.getState().summonActor(
|
||||
warden.id,
|
||||
summonAbility,
|
||||
summonEffect,
|
||||
[options.petDistance ?? 0, 0, 0],
|
||||
null,
|
||||
now,
|
||||
);
|
||||
expect(petId).toBeTruthy();
|
||||
useCombatStore.setState((state) => ({
|
||||
summons: state.summons.map((summon) => summon.id === petId
|
||||
? { ...summon, expiresAt: options.petExpiresAt ?? now + 20_000 }
|
||||
: summon),
|
||||
}));
|
||||
|
||||
const transferEffects = effectsFor(493399).filter((effect) => effect.kind === "apply-aura"
|
||||
&& effect.aura.utilityTags?.includes(ROM_WARDEN_DAMAGE_TRANSFER_TAG));
|
||||
expect(transferEffects).toHaveLength(2);
|
||||
expect(transferEffects.every((effect) => effect.kind === "apply-aura"
|
||||
&& effect.aura.durationMs === 10_000)).toBe(true);
|
||||
if (options.transferAura !== false) {
|
||||
useCombatStore.setState((state) => ({ auras: transferEffects.reduce((auras, effect) => {
|
||||
if (effect.kind !== "apply-aura") return auras;
|
||||
return applyAura(auras, {
|
||||
definition: effect.aura,
|
||||
sourceId: warden.id,
|
||||
targetId: warden.id,
|
||||
now,
|
||||
}).auras;
|
||||
}, state.auras) }));
|
||||
}
|
||||
|
||||
const mobId = "warden-party-transfer-attacker";
|
||||
useCombatStore.getState().registerMob(mobId, {
|
||||
name: "Warden transfer attacker",
|
||||
maxHealth: 100_000,
|
||||
level: 100,
|
||||
attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: "warden-party-transfer-swing", delivery: "projectile",
|
||||
range: 100, initialCooldownMs: [0, 0] }],
|
||||
});
|
||||
setMobPosition(mobId, [2, 0, 0]);
|
||||
useCombatStore.getState().damageMob(mobId, 1, now, { actorId: warden.id, role: "tank" });
|
||||
const memberBefore = usePartyStore.getState().members.find((member) => member.id === warden.id)!.health;
|
||||
const petBefore = useCombatStore.getState().summons.find((summon) => summon.id === petId)?.health ?? 0;
|
||||
useCombatStore.getState().advanceMobCombat(hitAt, [0, 0, 0]);
|
||||
const state = useCombatStore.getState();
|
||||
const memberAfter = usePartyStore.getState().members.find((member) => member.id === warden.id)!.health;
|
||||
const petAfter = state.summons.find((summon) => summon.id === petId)?.health ?? 0;
|
||||
const hitEvents = state.combatEvents.filter((event) => event.occurredAt === hitAt
|
||||
&& event.abilityId === "warden-party-transfer-swing");
|
||||
return {
|
||||
memberDamage: memberBefore - memberAfter,
|
||||
petDamage: petBefore - petAfter,
|
||||
petEvents: hitEvents.filter((event) => event.targetActorId === petId),
|
||||
ownerEvents: hitEvents.filter((event) => event.targetActorId === warden.id),
|
||||
petAlive: state.actors[petId!]?.alive ?? false,
|
||||
};
|
||||
};
|
||||
|
||||
const baseline = resolvePartyHit({ transferAura: false });
|
||||
const inRange = resolvePartyHit({ petDistance: 300 });
|
||||
expect(baseline.memberDamage).toBeGreaterThan(0);
|
||||
expect(inRange.memberDamage).toBeGreaterThan(0);
|
||||
expect(inRange.petDamage).toBeGreaterThan(0);
|
||||
expect(inRange.memberDamage + inRange.petDamage).toBeCloseTo(baseline.memberDamage, 0);
|
||||
expect(inRange.petDamage / (inRange.memberDamage + inRange.petDamage))
|
||||
.toBeCloseTo(ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, 1);
|
||||
expect(inRange.ownerEvents).toHaveLength(1);
|
||||
expect(inRange.petEvents).toHaveLength(1);
|
||||
expect(inRange.petAlive).toBe(true);
|
||||
|
||||
const outOfRange = resolvePartyHit({ petDistance: 301 });
|
||||
expect(outOfRange.memberDamage).toBe(baseline.memberDamage);
|
||||
expect(outOfRange.petDamage).toBe(0);
|
||||
expect(outOfRange.petEvents).toHaveLength(0);
|
||||
|
||||
const expired = resolvePartyHit({ petExpiresAt: 1_450 });
|
||||
expect(expired.memberDamage).toBe(baseline.memberDamage);
|
||||
expect(expired.petDamage).toBe(0);
|
||||
expect(expired.petEvents).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("removes the unquantified Weak Point Strike bonus and models Awakening immunity and next critical", () => {
|
||||
const weakPoint = effectsFor(494043);
|
||||
expect(weakPoint.filter((effect) => effect.kind === "damage")).toHaveLength(1);
|
||||
|
||||
Reference in new issue
Block a user