- Hollowcrown: The Rift Between Worlds as its own seed (npm run seed:hollowcrown), built from the campaign book: pools, 58 monsters, 57 NPCs, 28 locations, 72 encounters with rewards, and DM notes. Shared seeding logic moved to prisma/seedCampaign.js. - What players can see: only encounters their own character is in; only the pool entries their character holds (plus starting options while building); only locations their character has been to; no invite code; no gold, inventory or money log of other players' characters. Socket events carry ids only and campaign rooms are members-only. - Encounters have a location; while one is in progress its characters are there, and visits are remembered. - Campaign setting to show players a health bar only for monsters and NPCs. - Initiative is entered as the d20 roll (1-20) and the bonus is added; players can enter their own character's roll. - Number fields enforce their limits when typing, and the API enforces the same limits. - Temp HP shows on HP bars and absorbs damage before real HP. - All packages at version 1.3.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
25 lines
1.0 KiB
TypeScript
25 lines
1.0 KiB
TypeScript
import { hpBarClass } from '../lib/format';
|
|
|
|
// A health bar with temporary hit points on it. Temp HP sits on top of real
|
|
// HP, so it is drawn as its own blue segment after the HP fill, and the bar
|
|
// stretches to fit when the two together come to more than the maximum (full
|
|
// health plus a buffer). The fill's colour still reflects real HP only: temp
|
|
// HP doesn't make a bloodied character look healthy.
|
|
export function HpBar({ current, max, temp = 0, height, className = 'mt-sm' }: {
|
|
current: number;
|
|
max: number;
|
|
temp?: number;
|
|
height?: number;
|
|
className?: string;
|
|
}) {
|
|
const hp = Math.max(0, Math.min(current, max));
|
|
const buffer = Math.max(0, temp);
|
|
const scale = Math.max(max, hp + buffer, 1);
|
|
return (
|
|
<div className={`hp-bar-track ${className}`} style={height ? { height } : undefined}>
|
|
<div className={hpBarClass(hp, max)} style={{ width: `${(hp / scale) * 100}%` }} />
|
|
{buffer > 0 && <div className="hp-bar-fill hp-temp" style={{ width: `${(buffer / scale) * 100}%` }} title="Temporary HP" />}
|
|
</div>
|
|
);
|
|
}
|