V1.7.2: the combatant on turn cannot be their own target

- In a battle under way, whoever is on turn has no Target button on their
  card, and the server refuses a target list that includes them.
- All packages at version 1.7.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 13:28:28 +02:00
co-authored by Claude Opus 5.5
parent 754eb0ee68
commit f8462a6e31
8 changed files with 37 additions and 23 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "1.7.1",
"version": "1.7.2",
"type": "module",
"scripts": {
"dev": "vite",
+6 -6
View File
@@ -124,7 +124,7 @@ function CombatantCard({
// What an area attack adds to this target's AC; 0 when they are the only one.
acPenalty: number;
// Marks this combatant as a target, or unmarks them. Absent for someone who
// may not pick targets right now.
// may not pick targets right now, and on the card of whoever is on turn.
onTarget?: () => void;
onRemove: () => void;
onError: (err: unknown) => void;
@@ -490,8 +490,7 @@ function AttackBar({
const hit = targets.filter((t) => tracksHp(t) && !missed.includes(t.id));
const value = Number(amount) || 0;
const portions = shares(value, hit.length, isArea ? mode : 'EACH');
const selfOnly = targets.length === 1 && targets[0].id === attacker?.id;
const attacks = attacker && !selfOnly ? attackLines(attacker) : [];
const attacks = attacker ? attackLines(attacker) : [];
function apply(sign: 1 | -1) {
if (!value || hit.length === 0) return;
@@ -504,7 +503,7 @@ function AttackBar({
<div className="card attack-bar">
<div className="flex-between flex-wrap">
<div className="attack-bar-title">
{attacker && !selfOnly && <>{attacker.displayName} → </>}🎯 {isArea ? `${targets.length} targets` : targets[0].displayName}
{attacker && <>{attacker.displayName} → </>}🎯 {isArea ? `${targets.length} targets` : targets[0].displayName}
</div>
<button className="btn btn-ghost" onClick={onClear}>
✕ Clear {isArea ? 'targets' : 'target'}
@@ -894,10 +893,11 @@ export function EncounterPage() {
isActive={p.id === active?.id}
onPatch={(data) => patchParticipant.mutate({ participantId: p.id, ...data }, fail)}
canRollInitiative={isDM || (p.character != null && p.character.userId === user?.id)}
targetedBy={targetIds.includes(p.id) ? (active && active.id !== p.id ? active.displayName : '') : undefined}
targetedBy={targetIds.includes(p.id) ? (active?.displayName ?? '') : undefined}
acPenalty={areaPenalty(targets.length, acStep)}
onTarget={
canTarget
// Nobody targets themselves: the combatant on turn has no button.
canTarget && p.id !== active?.id
? () => setTargets.mutate(targetIds.includes(p.id) ? targetIds.filter((id) => id !== p.id) : [...targetIds, p.id], fail)
: undefined
}