feat: tick Dying timer on party turn; mark is_dead when timer expires

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aaron Wood 2026-04-12 01:26:14 -04:00
parent d4790edc1a
commit 612843da39

View file

@ -103,6 +103,55 @@ async function insertRollLog(
return saved[0];
}
// ── Death timer ────────────────────────────────────────────────────────────
async function tickDeathTimers(io: Server, campaignId: number): Promise<void> {
// Find all living characters in this campaign with a Dying condition
const [charRows] = await db.execute<RowDataPacket[]>(
"SELECT id FROM characters WHERE campaign_id = ? AND is_dead = FALSE",
[campaignId]
);
if (charRows.length === 0) return;
const charIds = (charRows as RowDataPacket[]).map((r) => r.id as number);
const placeholders = charIds.map(() => "?").join(", ");
const [dyingRows] = await db.execute<RowDataPacket[]>(
`SELECT * FROM character_conditions WHERE name = 'Dying' AND character_id IN (${placeholders})`,
charIds
);
if (dyingRows.length === 0) return;
for (const condition of dyingRows) {
const newRounds = (condition.rounds_remaining as number) - 1;
if (newRounds <= 0) {
// Timer expired — remove Dying condition and mark permanently dead
await db.execute("DELETE FROM character_conditions WHERE id = ?", [condition.id]);
await db.execute("UPDATE characters SET is_dead = TRUE WHERE id = ?", [condition.character_id]);
} else {
await db.execute(
"UPDATE character_conditions SET rounds_remaining = ? WHERE id = ?",
[newRounds, condition.id]
);
}
// Broadcast updated character to the campaign room
const [charRow] = await db.execute<RowDataPacket[]>(
"SELECT * FROM characters WHERE id = ?",
[condition.character_id]
);
const [updatedConditions] = await db.execute<RowDataPacket[]>(
"SELECT * FROM character_conditions WHERE character_id = ?",
[condition.character_id]
);
io.to(`campaign:${campaignId}`).emit("character:updated", {
...charRow[0],
conditions: updatedConditions,
});
}
}
// ── Handler registration ───────────────────────────────────────────────────
export function registerInitiativeHandlers(io: Server, socket: Socket): void {
@ -291,6 +340,12 @@ export function registerInitiativeHandlers(io: Server, socket: Socket): void {
});
await saveCombats(data.campaignId, updated);
broadcast(io, socket, data.campaignId, updated, true);
// Tick death timers when the party's turn begins
const flippedCombat = updated.find((c) => c.id === data.combatId);
if (flippedCombat && flippedCombat.current_side === "party") {
await tickDeathTimers(io, data.campaignId);
}
} catch (err) {
console.error("[initiative]", err);
}