Update Healer Man server
This commit is contained in:
1 parent
6cc1b9217f
commit
6114a2295f
67 files changed
+6241
-347
No files matched your search
+174
-13
@@ -565,6 +565,15 @@ import {
|
||||
ROM_KNIGHT_PANTHERS_BLESSING_ABILITY_ID,
|
||||
romKnightPanthersBlessingRestoreOnDodge,
|
||||
} from "./romKnightPanthersBlessingRuntime";
|
||||
import {
|
||||
hasOwnedRomScoutBloodArrow,
|
||||
isRomBloodArrowOwner,
|
||||
isRomScoutBloodArrowAbility,
|
||||
romBloodArrowCastCosts,
|
||||
ROM_SCOUT_BLOOD_ARROW_ABILITY_ID,
|
||||
ROM_SCOUT_BLOOD_ARROW_AURA_TAG,
|
||||
ROM_SCOUT_BLOOD_ARROW_DEACTIVATION_COOLDOWN_MS,
|
||||
} from "./romBloodArrow";
|
||||
import {
|
||||
ROM_COA_KNIGHT_ROGUE_GODS_SWORD_ID,
|
||||
romCoaKnightRogueGodsSwordBonusLightDamage,
|
||||
@@ -1562,6 +1571,7 @@ export interface CombatState {
|
||||
selectFriendlyActor: (id: string | null) => boolean;
|
||||
setPlayerPosition: (position: CombatPosition) => void;
|
||||
castAbility: (abilityId: string, requestOrOrigin?: CastRequest | CombatPosition, now?: number, completingCast?: ActiveCast) => CastResult;
|
||||
deactivateRomScoutBloodArrow: (ownerId: string, now?: number) => boolean;
|
||||
beginGroundTarget: (abilityId: string) => boolean;
|
||||
moveGroundTarget: (moveX: number, moveForward: number, yaw: number, deltaSeconds: number) => void;
|
||||
confirmGroundTarget: (position?: CombatPosition, now?: number) => CastResult;
|
||||
@@ -10958,13 +10968,26 @@ function damageCompanionActorInWork(work: MutableCastWork, id: string, amount: n
|
||||
if (!actor || actor.health <= 0 || requested <= 0) return 0;
|
||||
const applied = Math.min(actor.health, requested);
|
||||
const health = actor.health - applied;
|
||||
const next = Object.freeze({ ...actor, health, alive: health > 0, cast: health > 0 ? actor.cast : null });
|
||||
const next = Object.freeze({
|
||||
...actor,
|
||||
health,
|
||||
alive: health > 0,
|
||||
cast: health > 0 ? actor.cast : null,
|
||||
...(health <= 0 ? {
|
||||
cooldowns: Object.fromEntries(Object.entries(actor.cooldowns)
|
||||
.filter(([abilityId]) => abilityId !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
} : {}),
|
||||
});
|
||||
work.actors[id] = next;
|
||||
mirrorCompanionActor(next);
|
||||
if (health <= 0) {
|
||||
work.auras = work.auras.filter((aura) => !(aura.targetId === id
|
||||
&& aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)));
|
||||
usePartyStore.setState((party) => ({
|
||||
members: party.members.map((member) => member.id === id
|
||||
? { ...member, status: "down", activeCast: null, activeCastTargetId: null }
|
||||
? { ...member, status: "down", activeCast: null, activeCastTargetId: null,
|
||||
cooldowns: Object.fromEntries(Object.entries(member.cooldowns)
|
||||
.filter(([abilityId]) => abilityId !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)) }
|
||||
: member),
|
||||
}));
|
||||
}
|
||||
@@ -11985,13 +12008,38 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
cancelGroundTarget: () => set({ pendingGroundTarget: null }),
|
||||
|
||||
synchronizeActors: () => {
|
||||
const partyMembers = usePartyStore.getState().members;
|
||||
const livingCompanionIds = new Set(partyMembers.filter((member) => member.health > 0).map((member) => member.id));
|
||||
let actors: Readonly<Record<string, CombatActorState>> = {};
|
||||
set((state) => {
|
||||
actors = combatActorSnapshots(state);
|
||||
return { actors };
|
||||
const activeBloodArrowOwners = new Set(livingCompanionIds);
|
||||
if (state.health > 0) activeBloodArrowOwners.add(PLAYER_AURA_ENTITY_ID);
|
||||
actors = Object.freeze(Object.fromEntries(Object.entries(combatActorSnapshots(state)).map(([id, actor]) => (
|
||||
activeBloodArrowOwners.has(id) ? [id, actor] : [id, {
|
||||
...actor,
|
||||
cooldowns: Object.fromEntries(Object.entries(actor.cooldowns)
|
||||
.filter(([abilityId]) => abilityId !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
}]
|
||||
))));
|
||||
const auras = state.auras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)
|
||||
|| aura.sourceId !== aura.targetId
|
||||
|| (aura.sourceId === PLAYER_AURA_ENTITY_ID
|
||||
? state.health > 0
|
||||
: livingCompanionIds.has(aura.sourceId)));
|
||||
const cooldowns = state.health > 0
|
||||
? state.cooldowns
|
||||
: Object.fromEntries(Object.entries(state.cooldowns).filter(([id]) => id !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID));
|
||||
return { actors, auras, cooldowns };
|
||||
});
|
||||
usePartyStore.setState((party) => ({
|
||||
members: party.members.map((member) => memberFromCompanionActor(member, actors[member.id])),
|
||||
members: party.members.map((member) => {
|
||||
const runtime = memberFromCompanionActor(member, actors[member.id]);
|
||||
return member.health > 0 ? runtime : {
|
||||
...runtime,
|
||||
cooldowns: Object.fromEntries(Object.entries(runtime.cooldowns)
|
||||
.filter(([id]) => id !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
},
|
||||
applyDefaultPartyBuffs: (now = combatNow()) => {
|
||||
@@ -12226,6 +12274,7 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
get().synchronizeActors();
|
||||
},
|
||||
commitCompanionActors: (members) => {
|
||||
const livingCompanionIds = new Set(members.filter((member) => member.health > 0).map((member) => member.id));
|
||||
let actors: Readonly<Record<string, CombatActorState>> = {};
|
||||
set((state) => {
|
||||
const next = { ...state.actors };
|
||||
@@ -12234,15 +12283,40 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
member,
|
||||
entityAbsorbAmount(state.auras, member.id),
|
||||
);
|
||||
next[member.id] = companionActorWithMemberRuntime(existing, member);
|
||||
const runtime = companionActorWithMemberRuntime(existing, member);
|
||||
next[member.id] = member.health > 0 ? runtime : {
|
||||
...runtime,
|
||||
cooldowns: Object.fromEntries(Object.entries(runtime.cooldowns)
|
||||
.filter(([id]) => id !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
};
|
||||
}
|
||||
const activeBloodArrowOwners = new Set(livingCompanionIds);
|
||||
if (state.health > 0) activeBloodArrowOwners.add(PLAYER_AURA_ENTITY_ID);
|
||||
for (const [id, actor] of Object.entries(next)) {
|
||||
if (activeBloodArrowOwners.has(id) || actor.cooldowns[ROM_SCOUT_BLOOD_ARROW_ABILITY_ID] === undefined) continue;
|
||||
next[id] = {
|
||||
...actor,
|
||||
cooldowns: Object.fromEntries(Object.entries(actor.cooldowns)
|
||||
.filter(([abilityId]) => abilityId !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
};
|
||||
}
|
||||
actors = Object.freeze(next);
|
||||
return { actors };
|
||||
const auras = state.auras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)
|
||||
|| aura.sourceId !== aura.targetId
|
||||
|| (aura.sourceId === PLAYER_AURA_ENTITY_ID
|
||||
? state.health > 0
|
||||
: livingCompanionIds.has(aura.sourceId)));
|
||||
return { actors, auras };
|
||||
});
|
||||
usePartyStore.setState((party) => ({
|
||||
members: party.members.map((member) => {
|
||||
const runtime = members.find((candidate) => candidate.id === member.id) ?? member;
|
||||
return memberFromCompanionActor(runtime, actors[member.id]);
|
||||
const projected = memberFromCompanionActor(runtime, actors[member.id]);
|
||||
return projected.health > 0 ? projected : {
|
||||
...projected,
|
||||
cooldowns: Object.fromEntries(Object.entries(projected.cooldowns)
|
||||
.filter(([id]) => id !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
},
|
||||
@@ -12267,6 +12341,20 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
const suddenDoomFreeDeathCoil = request[WOW335_DEATH_KNIGHT_SUDDEN_DOOM_FREE_CAST] === true
|
||||
&& ability?.id === WOW335_DEATH_KNIGHT_SUDDEN_DOOM_DEATH_COIL_ABILITY_ID;
|
||||
const activePlayerAuras = aurasForEntity(state.auras, PLAYER_AURA_ENTITY_ID);
|
||||
if (!completingCast && ability && isRomScoutBloodArrowAbility(ability)
|
||||
&& isRomBloodArrowOwner({ classId: state.classId, secondaryClassId: state.secondaryClassId })
|
||||
&& state.abilities.some((entry) => entry.id === ability!.id)
|
||||
&& hasOwnedRomScoutBloodArrow(state.auras, PLAYER_AURA_ENTITY_ID, now)
|
||||
&& get().deactivateRomScoutBloodArrow(PLAYER_AURA_ENTITY_ID, now)) {
|
||||
return {
|
||||
ok: true,
|
||||
abilityId,
|
||||
affectedMobIds: [],
|
||||
damage: 0,
|
||||
healing: 0,
|
||||
levelsGained: 0,
|
||||
};
|
||||
}
|
||||
const druidMasterShapeshifterHealingModifiers = state.classId === "druid"
|
||||
? wow335DruidMasterShapeshifterModifiersForForm(
|
||||
state.talentRanks[WOW335_DRUID_MASTER_SHAPESHIFTER_TALENT_ID] ?? 0,
|
||||
@@ -12691,16 +12779,29 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
: state.classId === "warrior" && ability?.name === "Execute"
|
||||
? Math.min(3, Math.max(0, Math.trunc(state.talentRanks["talent-1542"] ?? 0))) * 2
|
||||
: 0;
|
||||
const costs = ability && !consumesInnerFocus && !consumesDruidClearcasting && !consumesSurgeOfLight
|
||||
? resolvedAbilityCosts(ability, modifiers, { ...state, now }).map((cost) => {
|
||||
const costs = [
|
||||
...(ability && !consumesInnerFocus && !consumesDruidClearcasting && !consumesSurgeOfLight
|
||||
? resolvedAbilityCosts(ability, modifiers, { ...state, now }).map((cost) => {
|
||||
if (suddenDoomFreeDeathCoil && cost.resource === "runic-power") return { ...cost, amount: 0 };
|
||||
if (consumesHunterLockAndLoad && cost.resource === "mana") return { ...cost, amount: 0 };
|
||||
if (state.classId !== "warrior" || cost.resource !== "rage") return cost;
|
||||
return warriorFlatRageCostReduction > 0
|
||||
? { ...cost, amount: Math.max(0, cost.amount - warriorFlatRageCostReduction) }
|
||||
: cost;
|
||||
})
|
||||
: [];
|
||||
})
|
||||
: []),
|
||||
...(ability ? romBloodArrowCastCosts(
|
||||
ability,
|
||||
{ classId: state.classId, secondaryClassId: state.secondaryClassId },
|
||||
activePlayerAuras,
|
||||
PLAYER_AURA_ENTITY_ID,
|
||||
state.maxHealth,
|
||||
resourceProfileForClass(state.classId).type === "mana"
|
||||
? state.maxResource
|
||||
: state.maxResourcePools.mana ?? 0,
|
||||
now,
|
||||
) : []),
|
||||
];
|
||||
const resourceCost = ability && !suddenDoomFreeDeathCoil
|
||||
&& !consumesInnerFocus && !consumesDruidClearcasting && !consumesSurgeOfLight
|
||||
? Math.max(0, talentAdjustedResourceCost(ability, modifiers)
|
||||
@@ -17103,6 +17204,45 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
return result;
|
||||
},
|
||||
|
||||
deactivateRomScoutBloodArrow: (ownerId, now = combatNow()) => {
|
||||
const state = get();
|
||||
const playerOwner = ownerId === PLAYER_AURA_ENTITY_ID;
|
||||
const member = playerOwner
|
||||
? null
|
||||
: usePartyStore.getState().members.find((candidate) => candidate.id === ownerId) ?? null;
|
||||
const ownerBuild = playerOwner ? state : member;
|
||||
if (!ownerBuild || !isRomBloodArrowOwner(ownerBuild)
|
||||
|| !hasOwnedRomScoutBloodArrow(state.auras, ownerId, now)) return false;
|
||||
if ((playerOwner && state.health <= 0) || (!playerOwner && (!member || member.health <= 0))) return false;
|
||||
|
||||
const readyAt = now + ROM_SCOUT_BLOOD_ARROW_DEACTIVATION_COOLDOWN_MS;
|
||||
const auras = state.auras.filter((aura) => !(aura.sourceId === ownerId
|
||||
&& aura.targetId === ownerId
|
||||
&& aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)));
|
||||
const actors = state.actors[ownerId]
|
||||
? { ...state.actors, [ownerId]: {
|
||||
...state.actors[ownerId],
|
||||
cooldowns: { ...state.actors[ownerId].cooldowns, [ROM_SCOUT_BLOOD_ARROW_ABILITY_ID]: readyAt },
|
||||
} }
|
||||
: state.actors;
|
||||
if (playerOwner) {
|
||||
set({
|
||||
auras,
|
||||
actors,
|
||||
cooldowns: { ...state.cooldowns, [ROM_SCOUT_BLOOD_ARROW_ABILITY_ID]: readyAt },
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
usePartyStore.setState((party) => ({
|
||||
members: party.members.map((candidate) => candidate.id === ownerId
|
||||
? { ...candidate, cooldowns: { ...candidate.cooldowns, [ROM_SCOUT_BLOOD_ARROW_ABILITY_ID]: readyAt } }
|
||||
: candidate),
|
||||
}));
|
||||
set({ auras, actors });
|
||||
return true;
|
||||
},
|
||||
|
||||
consumeActorAuraTag: (actorId, tag) => {
|
||||
set((state) => ({
|
||||
auras: state.auras.filter((aura) => !(aura.targetId === actorId
|
||||
@@ -18944,7 +19084,12 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
}
|
||||
set({
|
||||
auras: health <= 0 ? nextAuras.filter((aura) => !(aura.targetId === PLAYER_AURA_ENTITY_ID
|
||||
&& aura.definition.utilityTags?.includes("wow335-rogue-killing-spree"))) : nextAuras,
|
||||
&& (aura.definition.utilityTags?.includes("wow335-rogue-killing-spree")
|
||||
|| aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)))) : nextAuras,
|
||||
cooldowns: health <= 0
|
||||
? Object.fromEntries(Object.entries(state.cooldowns)
|
||||
.filter(([id]) => id !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID))
|
||||
: state.cooldowns,
|
||||
killingSpreeWindows: health <= 0
|
||||
? state.killingSpreeWindows.filter((window) => window.ownerActorId !== PLAYER_AURA_ENTITY_ID)
|
||||
: state.killingSpreeWindows,
|
||||
@@ -21036,6 +21181,11 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
combatResult.dodged ? "dodge" : combatResult.landed && combatResult.rawDamage > 0 ? "hit" : "other",
|
||||
now,
|
||||
)];
|
||||
if (procWork.health <= 0) {
|
||||
procWork.auras = procWork.auras.filter((aura) => !(aura.targetId === PLAYER_AURA_ENTITY_ID
|
||||
&& aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)));
|
||||
delete procWork.cooldowns[ROM_SCOUT_BLOOD_ARROW_ABILITY_ID];
|
||||
}
|
||||
const playerPushbackReduction = healthDamage > 0
|
||||
? paladinConcentrationAuraPushbackReductionForTarget(
|
||||
procWork.auras,
|
||||
@@ -22078,6 +22228,17 @@ export const useCombatStore = create<CombatState>((set, get) => ({
|
||||
combatResult.dodged ? "dodge" : combatResult.landed && combatResult.rawDamage > 0 ? "hit" : "other",
|
||||
now,
|
||||
)];
|
||||
if (nextActor.health <= 0) {
|
||||
aurasAfterProcs = aurasAfterProcs.filter((aura) => !(aura.targetId === member.id
|
||||
&& aura.definition.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)));
|
||||
nextActor = {
|
||||
...nextActor,
|
||||
cooldowns: Object.fromEntries(Object.entries(nextActor.cooldowns)
|
||||
.filter(([abilityId]) => abilityId !== ROM_SCOUT_BLOOD_ARROW_ABILITY_ID)),
|
||||
};
|
||||
actorsAfterHit = { ...actorsAfterHit, [nextActor.id]: nextActor };
|
||||
mirrorCompanionActor(nextActor);
|
||||
}
|
||||
set({
|
||||
actors: actorsAfterHit,
|
||||
summons: nextSummons,
|
||||
|
||||
Reference in new issue
Block a user