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];
|
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 ───────────────────────────────────────────────────
|
// ── Handler registration ───────────────────────────────────────────────────
|
||||||
|
|
||||||
export function registerInitiativeHandlers(io: Server, socket: Socket): void {
|
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);
|
await saveCombats(data.campaignId, updated);
|
||||||
broadcast(io, socket, data.campaignId, updated, true);
|
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) {
|
} catch (err) {
|
||||||
console.error("[initiative]", err);
|
console.error("[initiative]", err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue