Add AC field (character, monster/npc, participant edit); layout polish
AC (Armor Class) optional field across all participant entry points: - shared: ac field on makeParticipant + buildMonsterParticipant + buildCharacterParticipant, defaults null - CharacterManager: defaultAc state + add form field + inline edit field + display in character list - Monster add form: AC field - EditParticipantModal: AC field next to Initiative - ParticipantManager (DM list): AC badge on name row (sky-blue, stylized, large value, small label) for at-a-glance reading - Player display: no AC (DM only) Layout polish: - Add participants form: 12-col grid, 5 fields single row (Init Mod, Initiative, AC, Max HP, HP Formula), shrunk from oversized fields - Character add form: 12-col grid, name grows (col-span-6), Init Mod/AC/HP small right-aligned, order matches add participants - Character inline edit: labels added (Name/HP/Init Mod/AC), name flex-grows - HP Formula: label trimmed (example moved to placeholder 'e.g. 2d6+9'), Reroll button in edit modal - ParticipantManager init input shrunk (w-8, centered) Tests: 6 new AC builder tests (turn.ac.test.js). Existing test labels updated for renamed fields.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// AC field on participant + builders.
|
||||
const shared = require('@ttrpg/shared');
|
||||
const { makeParticipant, buildMonsterParticipant, buildCharacterParticipant, rollHpFormula } = shared;
|
||||
|
||||
describe('AC field', () => {
|
||||
test('makeParticipant accepts ac', () => {
|
||||
const p = makeParticipant({ name: 'Orc', type: 'monster', initiative: 10, maxHp: 15, currentHp: 15, ac: 13 });
|
||||
expect(p.ac).toBe(13);
|
||||
});
|
||||
|
||||
test('makeParticipant ac defaults null', () => {
|
||||
const p = makeParticipant({ name: 'Orc', type: 'monster', initiative: 10, maxHp: 15, currentHp: 15 });
|
||||
expect(p.ac).toBeNull();
|
||||
});
|
||||
|
||||
test('buildMonsterParticipant accepts ac', () => {
|
||||
const { participant } = buildMonsterParticipant({ name: 'Goblin', maxHp: 7, initMod: 2, ac: 15 });
|
||||
expect(participant.ac).toBe(15);
|
||||
});
|
||||
|
||||
test('buildMonsterParticipant ac defaults null', () => {
|
||||
const { participant } = buildMonsterParticipant({ name: 'Goblin', maxHp: 7 });
|
||||
expect(participant.ac).toBeNull();
|
||||
});
|
||||
|
||||
test('buildCharacterParticipant accepts character ac', () => {
|
||||
const { participant } = buildCharacterParticipant({ id: 'c1', name: 'Fighter', defaultMaxHp: 30, defaultInitMod: 2, defaultAc: 18 });
|
||||
expect(participant.ac).toBe(18);
|
||||
});
|
||||
|
||||
test('buildCharacterParticipant ac defaults null when unset', () => {
|
||||
const { participant } = buildCharacterParticipant({ id: 'c1', name: 'Fighter', defaultMaxHp: 30 });
|
||||
expect(participant.ac).toBeNull();
|
||||
});
|
||||
});
|
||||
+4
-1
@@ -361,6 +361,7 @@ function makeParticipant(opts) {
|
||||
deathSaveSuccesses: opts.deathSaveSuccesses || 0,
|
||||
deathSaveFailures: opts.deathSaveFailures || 0,
|
||||
hpFormula: opts.hpFormula || null,
|
||||
ac: opts.ac !== undefined ? opts.ac : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -377,12 +378,13 @@ function buildCharacterParticipant(character) {
|
||||
initiative: finalInitiative,
|
||||
maxHp,
|
||||
currentHp: maxHp,
|
||||
ac: character.defaultAc !== undefined ? character.defaultAc : null,
|
||||
}),
|
||||
roll: { roll: initiativeRoll, mod: modifier, total: finalInitiative },
|
||||
};
|
||||
}
|
||||
|
||||
function buildMonsterParticipant({ name, maxHp, initMod, asNpc, hpFormula }) {
|
||||
function buildMonsterParticipant({ name, maxHp, initMod, asNpc, hpFormula, ac }) {
|
||||
const initiativeRoll = rollD20();
|
||||
const modifier = initMod !== undefined ? initMod : MONSTER_DEFAULT_INIT_MOD;
|
||||
const finalInitiative = initiativeRoll + modifier;
|
||||
@@ -406,6 +408,7 @@ function buildMonsterParticipant({ name, maxHp, initMod, asNpc, hpFormula }) {
|
||||
maxHp: hp,
|
||||
currentHp: hp,
|
||||
hpFormula: hpFormula || null,
|
||||
ac: ac !== undefined ? ac : null,
|
||||
}),
|
||||
roll: { roll: initiativeRoll, mod: modifier, total: finalInitiative, hpRoll },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user