feat: auto-start Dying condition when HP hits 0, clear when HP recovers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ee6026b8b4
commit
d4790edc1a
1 changed files with 44 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ import db from "../db.js";
|
||||||
import { broadcastToCampaign } from "../socket.js";
|
import { broadcastToCampaign } from "../socket.js";
|
||||||
import { parseJson } from "../utils/parseJson.js";
|
import { parseJson } from "../utils/parseJson.js";
|
||||||
import { requireAuth } from "../auth/middleware.js";
|
import { requireAuth } from "../auth/middleware.js";
|
||||||
|
import { rollDice } from "../dice.js";
|
||||||
|
|
||||||
type CampaignParams = ParamsDictionary & { campaignId: string };
|
type CampaignParams = ParamsDictionary & { campaignId: string };
|
||||||
|
|
||||||
|
|
@ -192,7 +193,7 @@ router.patch("/:id", requireAuth, async (req, res) => {
|
||||||
"name", "class", "ancestry", "level", "xp", "hp_current", "hp_max",
|
"name", "class", "ancestry", "level", "xp", "hp_current", "hp_max",
|
||||||
"ac", "alignment", "title", "notes", "background", "deity", "languages",
|
"ac", "alignment", "title", "notes", "background", "deity", "languages",
|
||||||
"gp", "sp", "cp", "gear_slots_max", "overrides", "color", "luck_token",
|
"gp", "sp", "cp", "gear_slots_max", "overrides", "color", "luck_token",
|
||||||
"torch_lit_at",
|
"torch_lit_at", "is_dead",
|
||||||
];
|
];
|
||||||
|
|
||||||
const updates: string[] = [];
|
const updates: string[] = [];
|
||||||
|
|
@ -218,6 +219,48 @@ router.patch("/:id", requireAuth, async (req, res) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-start or clear Dying condition based on HP change
|
||||||
|
if (req.body.hp_current !== undefined) {
|
||||||
|
const newHp = Number(req.body.hp_current);
|
||||||
|
|
||||||
|
if (newHp <= 0) {
|
||||||
|
// Check if already dying or permanently dead
|
||||||
|
const [dyingRows] = await db.execute<RowDataPacket[]>(
|
||||||
|
"SELECT id FROM character_conditions WHERE character_id = ? AND name = 'Dying'",
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
const [deadRows] = await db.execute<RowDataPacket[]>(
|
||||||
|
"SELECT is_dead FROM characters WHERE id = ?",
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
const isAlreadyDying = dyingRows.length > 0;
|
||||||
|
const isAlreadyDead = Boolean(deadRows[0]?.is_dead);
|
||||||
|
|
||||||
|
if (!isAlreadyDying && !isAlreadyDead) {
|
||||||
|
// Roll 1d4, add CON modifier, clamp to minimum 1
|
||||||
|
const d4 = rollDice("1d4");
|
||||||
|
const [statRows] = await db.execute<RowDataPacket[]>(
|
||||||
|
"SELECT value FROM character_stats WHERE character_id = ? AND stat_name = 'CON'",
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
const conValue = (statRows[0]?.value as number) ?? 10;
|
||||||
|
const conMod = Math.floor((conValue - 10) / 2);
|
||||||
|
const roundsRemaining = Math.max(1, d4.total + conMod);
|
||||||
|
|
||||||
|
await db.execute(
|
||||||
|
"INSERT INTO character_conditions (character_id, name, description, rounds_remaining) VALUES (?, 'Dying', '', ?)",
|
||||||
|
[id, roundsRemaining]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// HP above 0: remove any Dying condition (character was healed)
|
||||||
|
await db.execute(
|
||||||
|
"DELETE FROM character_conditions WHERE character_id = ? AND name = 'Dying'",
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [rows] = await db.execute<RowDataPacket[]>(
|
const [rows] = await db.execute<RowDataPacket[]>(
|
||||||
"SELECT * FROM characters WHERE id = ?",
|
"SELECT * FROM characters WHERE id = ?",
|
||||||
[id]
|
[id]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue