Release Healer Man 0.1.9

This commit is contained in:
phenom committed 2026-08-30 14:16:56 -04:00
1 parent c245a199b6
commit d060296ade
74 files changed
+5901 -334

No files matched your search

+44 -4
View File
@@ -5,21 +5,33 @@ import {
formatTimedEffectTimer,
timedEffectRemainingMs,
} from "../game/timedEffectDisplay";
import {
timedEffectDescription,
type StatusEffectInspectHandler,
type StatusEffectInspection,
} from "./statusEffectInspection";
export type TimedEffectKind = TimedCombatEffect["kind"];
interface TimedEffectStripProps {
readonly targetId: string | null;
readonly targetIds?: readonly (string | null)[];
readonly kinds?: readonly TimedEffectKind[];
readonly className?: string;
readonly onInspect?: StatusEffectInspectHandler;
readonly tooltipId?: string;
}
function LiveTimedEffectStrip({
effects,
className = "",
onInspect,
tooltipId,
}: {
readonly effects: readonly TimedCombatEffect[];
readonly className?: string;
readonly onInspect?: StatusEffectInspectHandler;
readonly tooltipId?: string;
}) {
const [now, setNow] = useState(() => Date.now());
@@ -45,12 +57,29 @@ function LiveTimedEffectStrip({
{visibleEffects.map(({ effect, ability, remainingMs }) => {
const label = ability?.name ?? effect.sourceAbilityId;
const timer = formatTimedEffectTimer(remainingMs);
const disposition = effect.kind === "hot" ? "buff" : "debuff";
const inspection: StatusEffectInspection = {
id: effect.id,
name: label,
disposition,
description: timedEffectDescription(effect.kind, ability?.description),
remainingLabel: `${timer} remaining`,
stacks: 1,
};
return (
<span
key={effect.id}
className={`timed-effect timed-effect--${effect.kind}`}
className={`timed-effect timed-effect--${effect.kind} ${onInspect ? "timed-effect--inspectable" : ""}`.trim()}
tabIndex={onInspect ? 0 : undefined}
aria-label={`${label}, ${effect.kind === "hot" ? "healing" : "damage"} over time, ${timer} remaining`}
title={`${label} · ${timer} remaining`}
aria-describedby={onInspect ? tooltipId : undefined}
title={onInspect ? undefined : `${label} · ${timer} remaining`}
onPointerEnter={onInspect ? () => onInspect(inspection) : undefined}
onPointerLeave={onInspect ? (event) => {
if (event.currentTarget !== document.activeElement) onInspect(null);
} : undefined}
onFocus={onInspect ? () => onInspect(inspection) : undefined}
onBlur={onInspect ? () => onInspect(null) : undefined}
>
{ability?.icon
? <img src={ability.icon} alt="" draggable={false} />
@@ -69,14 +98,25 @@ function LiveTimedEffectStrip({
*/
export function TimedEffectStrip({
targetId,
targetIds,
kinds = ["dot", "hot"],
className,
onInspect,
tooltipId,
}: TimedEffectStripProps) {
const allEffects = useCombatStore((state) => state.effects);
const requestedTargetIds = targetIds ?? [targetId];
const effects = allEffects.filter((effect) => (
effect.targetId === targetId && kinds.includes(effect.kind)
requestedTargetIds.includes(effect.targetId) && kinds.includes(effect.kind)
));
if (!effects.length) return null;
return <LiveTimedEffectStrip effects={effects} className={className} />;
return (
<LiveTimedEffectStrip
effects={effects}
className={className}
onInspect={onInspect}
tooltipId={tooltipId}
/>
);
}