Update Healer Man server
This commit is contained in:
1 parent
9c5fb4c614
commit
bd073fb00f
113 files changed
+4902
-273
No files matched your search
+56
-16
@@ -1,4 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import { permanentBuffEffects } from "./partyBuffPolicy";
|
||||
import { usePartyBuffPolicyStore } from "./partyBuffPolicyStore";
|
||||
import { combatNow } from "./combatClock";
|
||||
import { useDungeonSimulationStore } from "./dungeonSimulationStore";
|
||||
import { useGameStore } from "./store";
|
||||
@@ -2166,7 +2168,7 @@ function auraDefinitionForAbility(
|
||||
description: definition.description ?? ability.description,
|
||||
icon: definition.icon ?? ability.icon,
|
||||
durationMs,
|
||||
...(defaultPartyBuffFamily ? {
|
||||
...(defaultPartyBuffFamily && !definition.exclusiveGroup ? {
|
||||
uniqueBySource: false,
|
||||
exclusiveGroup: `default-party-buff:${defaultPartyBuffFamily}`,
|
||||
} : {}),
|
||||
@@ -4699,19 +4701,50 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
},
|
||||
applyDefaultPartyBuffs: (now = combatNow()) => {
|
||||
get().synchronizeActors();
|
||||
const state = get();
|
||||
const partyMembers = usePartyStore.getState().members;
|
||||
set((state) => {
|
||||
const auras = state.auras.filter((aura) => !aura.definition.exclusiveGroup?.startsWith("gm-party-buff:"));
|
||||
if (auras.length === state.auras.length) return state;
|
||||
const maxHealth = auraAdjustedPlayerMaxHealth(state.classId, state.level, state.talentModifiers,
|
||||
state.gearStats, state.raceId, state.secondaryClassId, auras);
|
||||
const health = state.health <= 0 ? 0 : clamp(state.health + maxHealth - state.maxHealth, 1, maxHealth);
|
||||
const actors = { ...state.actors };
|
||||
if (actors[PLAYER_AURA_ENTITY_ID]) actors[PLAYER_AURA_ENTITY_ID] = {
|
||||
...actors[PLAYER_AURA_ENTITY_ID], health, maxHealth,
|
||||
};
|
||||
for (const member of partyMembers) {
|
||||
const actor = actors[member.id];
|
||||
if (!actor) continue;
|
||||
const base = deriveCharacterStats(member.classId, member.level, member.gearStats, member.raceId);
|
||||
const delta = auraMaximumHealthBonus(base, auras, member.id)
|
||||
- auraMaximumHealthBonus(base, state.auras, member.id);
|
||||
const memberMaxHealth = Math.max(1, actor.maxHealth + delta);
|
||||
actors[member.id] = {
|
||||
...actor,
|
||||
maxHealth: memberMaxHealth,
|
||||
health: actor.health <= 0 ? 0 : clamp(actor.health + delta, 1, memberMaxHealth),
|
||||
};
|
||||
}
|
||||
return { auras, health, maxHealth, actors };
|
||||
});
|
||||
get().synchronizeActors();
|
||||
const state = get();
|
||||
const rules = usePartyBuffPolicyStore.getState().config.rules;
|
||||
const includePlayer = useDungeonSimulationStore.getState().sessionMode === "play";
|
||||
const sources = [
|
||||
...(includePlayer ? [{
|
||||
id: PLAYER_AURA_ENTITY_ID,
|
||||
classId: state.classId,
|
||||
role: state.gearRole,
|
||||
level: state.level,
|
||||
abilities: state.abilities,
|
||||
}] : []),
|
||||
...partyMembers.filter((member) => member.health > 0).map((member) => ({
|
||||
id: member.id,
|
||||
classId: member.classId,
|
||||
role: member.role,
|
||||
level: member.level,
|
||||
abilities: abilitiesForClass(member.classId),
|
||||
abilities: abilitiesForCharacter(member.classId, member.secondaryClassId),
|
||||
})),
|
||||
];
|
||||
const selected = new Map<string, {
|
||||
@@ -4719,34 +4752,33 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
ability: AbilityDefinition;
|
||||
effects: readonly Extract<AbilityEffect, { kind: "apply-aura" }>[];
|
||||
potency: number;
|
||||
scope: "party" | "tank" | "healer";
|
||||
}>();
|
||||
for (const source of sources) {
|
||||
for (const catalogAbility of source.abilities) {
|
||||
const family = DEFAULT_PARTY_BUFF_FAMILY.get(catalogAbility.name.toLowerCase());
|
||||
if (!family || catalogAbility.passive || !isAbilityUnlocked(catalogAbility, source.level)) continue;
|
||||
for (const rule of rules) {
|
||||
for (const source of sources) {
|
||||
const catalogAbility = source.abilities.find((ability) => ability.id === rule.abilityId);
|
||||
if (!catalogAbility || !isAbilityUnlocked(catalogAbility, source.level)) continue;
|
||||
const ability = abilityAtLevel(catalogAbility, source.level);
|
||||
const effects = ability.effects.filter((effect): effect is Extract<AbilityEffect, { kind: "apply-aura" }> => (
|
||||
effect.kind === "apply-aura" && effect.aura.disposition === "buff"
|
||||
));
|
||||
const effects = permanentBuffEffects(ability);
|
||||
if (!effects.length) continue;
|
||||
const family = DEFAULT_PARTY_BUFF_FAMILY.get(ability.name.toLowerCase()) ?? ability.id;
|
||||
const potency = defaultPartyBuffPotency(effects);
|
||||
if ((selected.get(family)?.potency ?? Number.NEGATIVE_INFINITY) >= potency) continue;
|
||||
selected.set(family, { sourceId: source.id, ability, effects, potency });
|
||||
selected.set(family, { sourceId: source.id, ability, effects, potency, scope: rule.scope });
|
||||
}
|
||||
}
|
||||
const recipients = [
|
||||
...(includePlayer ? [PLAYER_AURA_ENTITY_ID] : []),
|
||||
...partyMembers.filter((member) => member.health > 0).map((member) => member.id),
|
||||
];
|
||||
for (const [family, buff] of selected) {
|
||||
const recipients = sources.filter((source) => buff.scope === "party" || source.role === buff.scope)
|
||||
.map((source) => source.id);
|
||||
for (const recipientId of recipients) {
|
||||
for (const effect of buff.effects) {
|
||||
get().applyActorAura(buff.sourceId, recipientId, buff.ability, {
|
||||
...effect,
|
||||
aura: {
|
||||
...effect.aura,
|
||||
durationMs: null,
|
||||
uniqueBySource: false,
|
||||
exclusiveGroup: `default-party-buff:${family}`,
|
||||
exclusiveGroup: `gm-party-buff:${family}`,
|
||||
},
|
||||
}, now);
|
||||
}
|
||||
@@ -6040,6 +6072,9 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
: [targetId ?? PLAYER_AURA_ENTITY_ID];
|
||||
for (const recipientId of recipients.filter((id) => !effect.excludeCaster || id !== PLAYER_AURA_ENTITY_ID)) {
|
||||
const previousAuras = work.auras;
|
||||
const family = DEFAULT_PARTY_BUFF_FAMILY.get(ability.name.toLowerCase()) ?? ability.id;
|
||||
if (previousAuras.some((aura) => aura.targetId === recipientId
|
||||
&& aura.definition.exclusiveGroup === `gm-party-buff:${family}`)) continue;
|
||||
if (effect.control && work.mobs[recipientId]?.characterDefender && work.mobs[recipientId].mechanicImmunities.includes(effect.control.kind as AzerothCoreMechanic)) continue;
|
||||
const auraResult = applyCombatAura(previousAuras, {
|
||||
definition: auraDefinition,
|
||||
@@ -7396,6 +7431,11 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
const state = get();
|
||||
if (!state.actors[sourceActorId] || (!state.actors[targetActorId] && !state.mobs[targetActorId])) return false;
|
||||
if (ability.name === "Power Word: Shield" && hasWeakenedSoul(state.auras, targetActorId, now)) return false;
|
||||
const family = DEFAULT_PARTY_BUFF_FAMILY.get(ability.name.toLowerCase()) ?? ability.id;
|
||||
const gmGroup = `gm-party-buff:${family}`;
|
||||
if (effect.aura.exclusiveGroup !== gmGroup && state.auras.some((aura) => (
|
||||
aura.targetId === targetActorId && aura.definition.exclusiveGroup === gmGroup
|
||||
))) return true;
|
||||
const durationMs = effect.aura.durationMs;
|
||||
const definition = auraDefinitionForAbility(effect.aura, ability, durationMs);
|
||||
const applied = applyCombatAura(state.auras, {
|
||||
|
||||
Reference in new issue
Block a user