forked from phenom/healer-man
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import type { StructuredCombatEvent } from "../game/combatEvents";
|
|
|
|
export const PARTY_HEAL_POPUP_LIFETIME_MS = 1_500;
|
|
export const MAX_PARTY_HEAL_POPUPS = 20;
|
|
|
|
export interface PartyHealPopup {
|
|
readonly key: string;
|
|
readonly targetActorId: string;
|
|
readonly amount: number;
|
|
readonly critical: boolean;
|
|
readonly horizontalOffset: number;
|
|
}
|
|
|
|
function eventKey(event: StructuredCombatEvent): string {
|
|
return `${event.occurredAt}:${event.id}`;
|
|
}
|
|
|
|
/** Convert only newly committed, effective in-combat heals into party-frame UI events. */
|
|
export function addedPartyHealPopups(
|
|
previousEvents: readonly StructuredCombatEvent[],
|
|
nextEvents: readonly StructuredCombatEvent[],
|
|
inCombat: boolean,
|
|
): PartyHealPopup[] {
|
|
if (!inCombat || previousEvents === nextEvents) return [];
|
|
const previousKeys = new Set(previousEvents.map(eventKey));
|
|
return nextEvents
|
|
.filter((event) => (
|
|
event.kind === "healing"
|
|
&& event.effectiveAmount > 0
|
|
&& !previousKeys.has(eventKey(event))
|
|
))
|
|
.map((event) => ({
|
|
key: eventKey(event),
|
|
targetActorId: event.targetActorId,
|
|
amount: Math.max(1, Math.round(event.effectiveAmount)),
|
|
critical: event.critical,
|
|
horizontalOffset: ((event.id % 3) - 1) * 14,
|
|
}));
|
|
}
|
|
|
|
export function appendPartyHealPopups(
|
|
current: readonly PartyHealPopup[],
|
|
added: readonly PartyHealPopup[],
|
|
): PartyHealPopup[] {
|
|
if (added.length === 0) return [...current];
|
|
const addedKeys = new Set(added.map((popup) => popup.key));
|
|
return [...current.filter((popup) => !addedKeys.has(popup.key)), ...added]
|
|
.slice(-MAX_PARTY_HEAL_POPUPS);
|
|
}
|