Release Healer Man 0.1.22

This commit is contained in:
phenom committed 2026-09-09 11:21:33 -04:00
1 parent f6f2375145
commit 7f6001723a
144 files changed
+54107 -690

No files matched your search

+27 -7
View File
@@ -16,6 +16,7 @@ import type { OnlineGroupMember } from "../app/onlineGroupTypes";
import { useOnlineSessionStore } from "../app/onlineSessionStore";
import type { OnlineSessionPlayer } from "../app/onlineSessionTypes";
import { onlinePlayerActorId } from "../game/onlineSessionRuntime";
import { auraDefinitionIsDispellableDebuff } from "./auraDisplay";
const PARTY_COMMANDS: readonly {
command: PartyCommand;
@@ -119,19 +120,19 @@ function MemberFrame({ member, selected, onSelect }: {
), 0));
const absorbPercent = Math.min(100 - percent, healthPercent(absorb, member.maxHealth));
const dispellableCount = useCombatStore((state) => state.auras.reduce((total, aura) => (
aura.targetId === member.id && aura.definition.disposition === "debuff" && aura.definition.dispelCategory
aura.targetId === member.id && auraDefinitionIsDispellableDebuff(aura.definition)
? total + 1
: total
), 0));
const dispellableNames = useCombatStore((state) => state.auras
.filter((aura) => aura.targetId === member.id && aura.definition.disposition === "debuff" && aura.definition.dispelCategory)
.filter((aura) => aura.targetId === member.id && auraDefinitionIsDispellableDebuff(aura.definition))
.map((aura) => aura.definition.name)
.join(", "));
const resourcePercent = healthPercent(member.resource, member.maxResource);
return (
<button
type="button"
className={`party-frame ${selected ? "is-selected" : ""} ${member.health <= 0 ? "is-down" : ""}`}
className={`party-frame ${selected ? "is-selected" : ""} ${dispellableCount ? "is-dispellable" : ""} ${member.health <= 0 ? "is-down" : ""}`}
onClick={onSelect}
aria-pressed={selected}
aria-label={`Target ${member.name}, ${member.gender} ${race.name}, ${member.specialization} ${characterClass.name}`}
@@ -149,7 +150,12 @@ function MemberFrame({ member, selected, onSelect }: {
<i style={{ width: `${resourcePercent}%` }} />
</span>
<TimedEffectStrip targetId={member.id} className="timed-effect-strip--party" />
<AuraStrip targetId={member.id} className="aura-strip--party" hideLongTerm />
<AuraStrip
targetId={member.id}
className="aura-strip--party"
hideLongTerm
highlightDispellableDebuffs
/>
</span>
</button>
);
@@ -214,6 +220,15 @@ export function PartyFrames() {
: total
), 0));
const playerShield = useCombatStore((state) => state.shield);
const playerDispellableCount = useCombatStore((state) => state.auras.reduce((total, aura) => (
aura.targetId === PLAYER_AGGRO_ID && auraDefinitionIsDispellableDebuff(aura.definition)
? total + 1
: total
), 0));
const playerDispellableNames = useCombatStore((state) => state.auras
.filter((aura) => aura.targetId === PLAYER_AGGRO_ID && auraDefinitionIsDispellableDebuff(aura.definition))
.map((aura) => aura.definition.name)
.join(", "));
const members = usePartyStore((state) => state.members);
const selectedMemberId = usePartyStore((state) => state.selectedMemberId);
const selfSelected = usePartyStore((state) => state.selfSelected);
@@ -232,7 +247,6 @@ export function PartyFrames() {
const onlinePlayersByAccount = new Map(
(onlineSession?.players ?? []).map((player) => [player.accountId, player]),
);
if (!members.length && !onlineMembers.length) return null;
const groupSize = members.length + onlineMembers.length + 1;
const selectMember = (id: string) => {
@@ -257,7 +271,7 @@ export function PartyFrames() {
{members.length ? <PartyCommandBar /> : null}
<button
type="button"
className={`party-frame party-frame--player ${selfSelected ? "is-selected" : ""} ${playerHealth <= 0 ? "is-down" : ""}`}
className={`party-frame party-frame--player ${selfSelected ? "is-selected" : ""} ${playerDispellableCount ? "is-dispellable" : ""} ${playerHealth <= 0 ? "is-down" : ""}`}
onClick={selectSelf}
aria-pressed={selfSelected}
aria-label={`Target ${character?.name ?? "Player"}, you`}
@@ -265,6 +279,7 @@ export function PartyFrames() {
<span className="party-frame__sigil">YOU</span>
<span className="party-frame__body">
<span className="party-frame__identity"><strong>{character?.name ?? "Adventurer"}</strong><small>You · {PARTY_ROLE_LABELS[playerRole]}</small></span>
{playerDispellableCount ? <span className="party-frame__dispel" title={playerDispellableNames}>DISPEL {playerDispellableCount}</span> : null}
<span className="party-frame__health" role="progressbar" aria-label="Player health" aria-valuemin={0} aria-valuemax={playerMaxHealth} aria-valuenow={Math.max(0, playerHealth)}>
<i style={{ width: `${playerPercent}%` }} />
{playerAbsorb > 0 ? <em style={{ left: `${playerPercent}%`, width: `${playerAbsorbPercent}%` }} /> : null}
@@ -278,7 +293,12 @@ export function PartyFrames() {
targetIds={[null, PLAYER_AGGRO_ID]}
className="timed-effect-strip--party"
/>
<AuraStrip targetId={PLAYER_AGGRO_ID} className="aura-strip--party" hideLongTerm />
<AuraStrip
targetId={PLAYER_AGGRO_ID}
className="aura-strip--party"
hideLongTerm
highlightDispellableDebuffs
/>
</span>
</button>
{onlineMembers.map((member) => {