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:
parent
d4790edc1a
commit
612843da39
1 changed files with 55 additions and 0 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue