diff --git a/src/features/combat/EncounterTracker.tsx b/src/features/combat/EncounterTracker.tsx
index c2401d0..ecff130 100644
--- a/src/features/combat/EncounterTracker.tsx
+++ b/src/features/combat/EncounterTracker.tsx
@@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from 'react';
import {
ArrowDown,
ArrowUp,
+ BrainCircuit,
ChevronLeft,
ChevronRight,
Dices,
@@ -81,11 +82,14 @@ export function EncounterTracker({ encounter, campaign }: { encounter: Encounter
*/
const noteConcentrationCheck = (combatant: Combatant, damage: number) => {
if (damage <= 0) return;
+ // The GM-set combatant flag works for any creature (monster/NPC/PC); fall back to
+ // the linked Character's concentration (set when a seated player casts a spell).
const ch = pcCharacter(combatant);
- if (!ch?.concentration) return;
+ const spellName = combatant.concentrating || ch?.concentration?.spellName;
+ if (!spellName) return;
const dc = concentrationDC(damage);
void encountersRepo.mutate(encounter.id, (e) =>
- logEvent(e, `${ch.name}: roll a DC ${dc} Constitution save or lose concentration on ${ch.concentration!.spellName}.`));
+ logEvent(e, `${combatant.name}: roll a DC ${dc} Constitution save or lose concentration on ${spellName}.`));
};
/** Advance the turn; remind (don't roll) when a downed PC's turn begins. */
@@ -481,6 +485,16 @@ function CombatantRow({
)}
{c.kind}
+
{dead && (
DOWN
diff --git a/src/lib/schemas/encounter.ts b/src/lib/schemas/encounter.ts
index 393800d..9808d43 100644
--- a/src/lib/schemas/encounter.ts
+++ b/src/lib/schemas/encounter.ts
@@ -34,6 +34,8 @@ export const combatantSchema = z.object({
ac: int,
hp: hpSchema,
conditions: z.array(conditionSchema).default([]),
+ /** Spell this combatant is concentrating on (GM-set). Drives the post-damage save prompt. */
+ concentrating: z.string().max(120).nullable().optional(),
notes: z.string().max(2000).default(''),
/** damage resistances/immunities snapshotted from the bestiary, if known */
damageDefenses: damageDefensesSchema.optional(),