forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
4fb7a0b9c8
commit
4c768fbec6
24 files changed
+654
-22
No files matched your search
+60
-7
@@ -157,6 +157,7 @@ import {
|
||||
wow335DruidFeralInstinctEnrageAura,
|
||||
wow335DruidFeralInstinctTigerAura,
|
||||
} from "./wow335DruidTalentRuntime";
|
||||
import { WOW335_GLYPH_OF_SWIFTMEND_ID } from "./wow335GlyphCatalog";
|
||||
import {
|
||||
WOW335_WARLOCK_METAMORPHOSIS_AURA_TAG,
|
||||
WOW335_WARLOCK_METAMORPHOSIS_IMMOLATION_TAG,
|
||||
@@ -922,6 +923,7 @@ export interface CharacterCombatSeed {
|
||||
/** Backward-compatible profile field accepted by the integration bridge. */
|
||||
readonly experience?: number;
|
||||
readonly talentRanks?: TalentRanks;
|
||||
readonly glyphIds?: readonly string[];
|
||||
readonly actionBindings?: unknown;
|
||||
readonly inventory?: unknown;
|
||||
readonly bossCards?: unknown;
|
||||
@@ -1084,6 +1086,7 @@ export interface CombatState {
|
||||
lastCombatResult: CombatResult | null;
|
||||
bossLootRewards: readonly BossLootReward[];
|
||||
talentRanks: TalentRanks;
|
||||
glyphIds: readonly string[];
|
||||
talentModifiers: readonly TalentModifier[];
|
||||
actionBindings: ActionBindings;
|
||||
inventory: readonly InventoryItem[];
|
||||
@@ -1181,6 +1184,7 @@ export interface CombatState {
|
||||
readonly preserveDefeatedIds?: readonly string[];
|
||||
}) => void;
|
||||
allocateTalent: (treeId: string) => boolean;
|
||||
setGlyphActive: (glyphId: string, active: boolean) => boolean;
|
||||
resetTalents: () => void;
|
||||
setActionBinding: (layer: ActionBindingLayer, control: ActionBindingControl, abilityId: string | null) => boolean;
|
||||
resetActionBindingLayer: (layer: ActionBindingLayer) => void;
|
||||
@@ -1763,6 +1767,7 @@ function talentAdjustedMaxHealth(
|
||||
|
||||
function abilityAttackKind(classId: ClassId, ability: AbilityDefinition): WotlkAttackKind {
|
||||
if (romWarriorPhysicalWeaponTooltip(ability)) return "melee";
|
||||
if (ability.effects.some((effect) => effect.kind === "damage" && effect.weaponHand)) return "melee";
|
||||
if (ability.source === "runewaker") {
|
||||
const sourceHit = ability.effects.find((effect) => effect.kind === "damage" || effect.kind === "dot");
|
||||
if (sourceHit && (sourceHit.kind === "damage" || sourceHit.kind === "dot") && sourceHit.school && sourceHit.school !== "physical") {
|
||||
@@ -7818,6 +7823,7 @@ function initialState() {
|
||||
lastCombatResult: null,
|
||||
bossLootRewards: [] as readonly BossLootReward[],
|
||||
talentRanks,
|
||||
glyphIds: [],
|
||||
talentModifiers,
|
||||
actionBindings: defaultActionBindings(defaultActionBarForClass(classId)),
|
||||
inventory: [] as readonly InventoryItem[],
|
||||
@@ -7843,6 +7849,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
const progression = normalizeProgression(profile.level ?? 1, profile.xp ?? profile.experience ?? 0);
|
||||
const resource = resourceProfileForClass(classId);
|
||||
const talentRanks = normalizeTalentRanks(classId, progression.level, profile.talentRanks ?? {});
|
||||
const glyphIds = classId === "druid" && profile.glyphIds?.includes(WOW335_GLYPH_OF_SWIFTMEND_ID)
|
||||
? [WOW335_GLYPH_OF_SWIFTMEND_ID]
|
||||
: [];
|
||||
const talentModifiers = characterStatModifiers(classId, progression.level, talentRanks);
|
||||
const abilities = abilitiesForCharacter(classId, secondaryClassId);
|
||||
const inventory = normalizeInventory(profile.inventory);
|
||||
@@ -7898,6 +7907,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
deathKnightRunes: classId === "death-knight" ? createDeathKnightRunes() : [],
|
||||
auras: syncPassiveAuras([], abilities, progression.level, talentRanks, combatNow()),
|
||||
talentRanks,
|
||||
glyphIds,
|
||||
talentModifiers,
|
||||
actionBindings: withoutUnlearnedTalentBindings(
|
||||
normalizeActionBindings(profile.actionBindings, defaultActionBarForCharacter(classId, secondaryClassId, progression.level)),
|
||||
@@ -10243,6 +10253,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
const shamanLavaLashOffhandSpeedMs = state.classId === "shaman" && ability.name === "Lava Lash"
|
||||
? playerEquippedMeleeWeapon(state, "off-hand")?.speedMs
|
||||
: undefined;
|
||||
const shamanStormstrikeOffhandWeapon = state.classId === "shaman" && ability.name === "Stormstrike"
|
||||
? playerEquippedMeleeWeapon(state, "off-hand")
|
||||
: null;
|
||||
let shamanTidalWavesProcAttempted = false;
|
||||
const combatEventIdBeforeAbilityEffects = work.combatEvents.at(-1)?.id ?? 0;
|
||||
let suddenDoomTrigger: ReturnType<typeof wow335DeathKnightSuddenDoomTriggerForLandedHit> = null;
|
||||
@@ -10267,6 +10280,20 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
)
|
||||
) continue;
|
||||
if (effect.kind === "damage") {
|
||||
const weaponHitProfile = effect.weaponHand === "main-hand"
|
||||
? playerAutoAttackProfile(
|
||||
state,
|
||||
aurasForEntity(work.auras, PLAYER_AURA_ENTITY_ID),
|
||||
playerEquippedMeleeWeapon(state, "main-hand") ?? undefined,
|
||||
)
|
||||
: effect.weaponHand === "off-hand" && shamanStormstrikeOffhandWeapon
|
||||
? playerOffhandAutoAttackProfile(
|
||||
state,
|
||||
shamanStormstrikeOffhandWeapon,
|
||||
aurasForEntity(work.auras, PLAYER_AURA_ENTITY_ID),
|
||||
)
|
||||
: null;
|
||||
if (effect.weaponHand && !weaponHitProfile) continue;
|
||||
const amount = talentAdjustedAmount(
|
||||
(() => {
|
||||
const conflagrateDot = state.classId === "warlock" && ability.name === "Conflagrate"
|
||||
@@ -10274,7 +10301,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
: null;
|
||||
const sourceAbility = conflagrateDot ? abilityById(conflagrateDot.sourceAbilityId) : null;
|
||||
const burstSeconds = sourceAbility?.name === "Immolate" ? 12 : 8;
|
||||
const baseDamage = conflagrateDot && sourceAbility
|
||||
const baseDamage = weaponHitProfile
|
||||
? weaponHitProfile.damage * effect.coefficient
|
||||
: conflagrateDot && sourceAbility
|
||||
? (conflagrateDot.fixedAmount ?? equipmentAdjustedCombatAmount(
|
||||
conflagrateDot,
|
||||
work.progression.level,
|
||||
@@ -10326,13 +10355,19 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
castThreatSource,
|
||||
effectSchool === "physical" ? attackKind : "spell",
|
||||
effectSchool,
|
||||
`${castThreatSource.actorId}:${ability.id}:${id}:${now}:direct`,
|
||||
`${castThreatSource.actorId}:${ability.id}:${id}:${now}:direct${effect.weaponHand ? `:${effect.weaponHand}` : ""}`,
|
||||
ability,
|
||||
false,
|
||||
ability.name === "Shiv" || (consumesSurgeOfLight && ability.name === "Smite")
|
||||
? { canCrit: false } : {},
|
||||
mageArcanePotencyCriticalChanceBonusPercent,
|
||||
shamanLavaLashOffhandSpeedMs,
|
||||
effect.weaponHand === "main-hand"
|
||||
? playerEquippedMeleeWeapon(state, "main-hand")?.speedMs
|
||||
?? work.gearStats.meleeWeapon?.speedMs
|
||||
?? WOW335_SHAMAN_MAELSTROM_WEAPON_DEFAULT_SPEED_MS
|
||||
: effect.weaponHand === "off-hand"
|
||||
? shamanStormstrikeOffhandWeapon?.speedMs
|
||||
: shamanLavaLashOffhandSpeedMs,
|
||||
);
|
||||
if (state.classId === "death-knight"
|
||||
&& effect.kind === "damage"
|
||||
@@ -10678,7 +10713,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
healingTargetHealth,
|
||||
healingTargetMaxHealth,
|
||||
);
|
||||
if (swiftmendHot) {
|
||||
if (swiftmendHot && !state.glyphIds.includes(WOW335_GLYPH_OF_SWIFTMEND_ID)) {
|
||||
work.effects = work.effects.filter((candidate) => candidate.id !== swiftmendHot.id);
|
||||
}
|
||||
const riptideAdjustedAmount = shamanRiptideHot
|
||||
@@ -16405,10 +16440,11 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
&& (!autoAttackSource || isPositionInFacingArc(autoAttackSource, autoAttackTargetPosition ?? state.playerPosition, Math.PI))
|
||||
);
|
||||
if (canAutoAttack) {
|
||||
const mainHandWeapon = state.classId === "rogue"
|
||||
const supportsPlayerOffhandSwings = state.classId === "rogue" || state.classId === "shaman";
|
||||
const mainHandWeapon = supportsPlayerOffhandSwings
|
||||
? playerEquippedMeleeWeapon(state, "main-hand")
|
||||
: null;
|
||||
const offHandWeapon = state.classId === "rogue"
|
||||
const offHandWeapon = supportsPlayerOffhandSwings
|
||||
? playerEquippedMeleeWeapon(state, "off-hand")
|
||||
: null;
|
||||
const profile = playerAutoAttackProfile(
|
||||
@@ -16433,6 +16469,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
}
|
||||
if (now >= nextAutoAttackAt) {
|
||||
const isDualWielding = Boolean(offHandWeapon);
|
||||
const mainHandSpeedMs = mainHandWeapon?.speedMs
|
||||
?? state.gearStats.meleeWeapon?.speedMs
|
||||
?? WOW335_SHAMAN_MAELSTROM_WEAPON_DEFAULT_SPEED_MS;
|
||||
const autoAttackSchool = mainHandWeapon?.damageSchool
|
||||
?? (offHandWeapon ? "physical" : state.gearStats.meleeWeapon?.damageSchool)
|
||||
?? "physical";
|
||||
@@ -16449,6 +16488,8 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
undefined,
|
||||
false,
|
||||
{ isAutoAttack: true, isDualWielding },
|
||||
0,
|
||||
mainHandSpeedMs,
|
||||
);
|
||||
let autoAttackKilled = result.killed;
|
||||
const enchantedThrowActive = work.auras.some((aura) => (
|
||||
@@ -16542,7 +16583,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
nextOffhandAutoAttackAt = 0;
|
||||
}
|
||||
}
|
||||
if (state.classId !== "rogue" || !offHandWeapon || !autoAttackTargetId) {
|
||||
if (!supportsPlayerOffhandSwings || !offHandWeapon || !autoAttackTargetId) {
|
||||
nextOffhandAutoAttackAt = 0;
|
||||
} else if (now >= nextOffhandAutoAttackAt) {
|
||||
const offhandProfile = playerOffhandAutoAttackProfile(
|
||||
@@ -16565,6 +16606,8 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
undefined,
|
||||
false,
|
||||
{ isAutoAttack: true, isDualWielding: true },
|
||||
0,
|
||||
offHandWeapon.speedMs,
|
||||
);
|
||||
if (result.combatResult?.landed) {
|
||||
maybeProcRogueCombatPotencyInWork(work, offhandSeed, now);
|
||||
@@ -17910,6 +17953,16 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
};
|
||||
}),
|
||||
|
||||
setGlyphActive: (glyphId, active) => {
|
||||
const state = get();
|
||||
if (state.classId !== "druid" || glyphId !== WOW335_GLYPH_OF_SWIFTMEND_ID) return false;
|
||||
const glyphIds = active
|
||||
? [WOW335_GLYPH_OF_SWIFTMEND_ID]
|
||||
: state.glyphIds.filter((id) => id !== WOW335_GLYPH_OF_SWIFTMEND_ID);
|
||||
if (glyphIds.length !== state.glyphIds.length) set({ glyphIds });
|
||||
return true;
|
||||
},
|
||||
|
||||
allocateTalent: (treeId) => {
|
||||
const state = get();
|
||||
const result = allocateTalentPoint(state.talentRanks, state.classId, treeId, state.level);
|
||||
|
||||
Reference in new issue
Block a user