109 Commits

Author SHA1 Message Date
09b5240454 fix(MoodMusic): resolve exhaustive-deps so CI build passes; behaviour unchanged
Some checks are pending
CI / build-and-test (push) Waiting to run
2026-07-17 08:18:23 +02:00
111f4b3d0d add Scene Music GM module: mood-based CC0-1.0 background tracks, /api/music/manifest, /music static, MoodMusic player in GMKit 2026-07-17 08:03:44 +02:00
ad7ce9dc22 Security fix: GM authorized from server-side session via x-session-id header
- New database/auth.js: shared server-side GM check using session store
- database/server.js: crypto-random session generation, server-side session
  storage, GM auth from session instead of x-gm-secret header
- database/routes/playerRoutes.js: GM-only endpoints use server-side auth
- database/routes/sessionRoutes.js: session creation/lookup endpoints
- database/routes/bestiaryRoutes.js: GM auth from server-side session
- database/routes/rulesRoutes.js: GM auth from server-side session
- src/App.js: send x-session-id header with API requests
- src/components/BestiaryTab.jsx: use session-based GM auth
2026-07-16 23:03:52 +02:00
b36b720c30 fix(tests): assert against rendered lastDetail panel instead of nc.log in horde combat tests
The old assertions targeted nc.log, which the component never renders.
Updated to assert against the rendered lastDetail panel, and use fake
timers to handle the setTimeout-deferred turn advancement.
2026-07-16 06:53:52 +02:00
33342d1611 chore: update dependencies, gitignore, and add remaining tests
- .gitignore: add .drive-scratch.js (automated scratch file)
- package.json/package-lock.json: dependency updates
- docs/troubleshooting.md: documentation updates
- src/tests/login.test.js: login flow integration test
- src/tests/playthroughRun2.js: full mission playthrough simulation
2026-07-15 19:37:13 +02:00
184b6e4371 feat: major Deathwatch Roller overhaul with bestiary, mission, and player management
- src/components/DeathwatchRoller.jsx: +1495 lines, core roller
  component with expanded dice mechanics, character sheets, and
  mission tracking
- src/components/BestiaryTab.jsx: +158 lines, enemy bestiary with
  stat blocks and encounter builder
- src/components/MissionTab.jsx: +43 lines, mission briefing and
  objective tracking
- src/App.js: route updates for new tabs
- database/routes/missionRoutes.js: backend mission state routes
- src/tests/: new test files for roller reset, bestiary, mission,
  player management, requisition shop, and full mission playthrough
2026-07-15 19:37:07 +02:00
b2dd5a44d3 feat: expand Simulation tab with combat simulation and replay
- src/components/SimulationTab.jsx: +544 lines, combat simulation
  UI with horde combat, player actions, and replay functionality
- database/routes/simulationRoutes.js: +681 lines, backend routes
  for simulation state management and combat resolution
- src/tests/simulationTabReplay.test.js: replay functionality tests
- src/tests/hordeCombatFourPlayersFiveHordes.test.js: multi-player
  horde combat scenario tests
- src/tests/hordeCombatPlayerMainWeapon.test.js: player weapon
  damage calculation tests
2026-07-15 19:36:38 +02:00
2a6224ee6f feat: add Battlemap tab with grid-based tactical map
- src/components/BattlemapTab.jsx: full battlemap UI with hex grid,
  token placement, movement, and combat tracking
- src/shared/battlemapEngine.js: core engine (distance, movement,
  theme, coordinate utilities) used by backend routes and tests
- src/tests/battlemapEngine.test.js: unit tests for engine functions
- src/tests/battlemapTab.test.js: component rendering tests
- src/tests/battlemapTabLayout.test.js: layout/positioning tests
- src/tests/simulationBattlemap.test.js: integration tests for
  battlemap in simulation context
- docs/incident-2026-07-04-blank-site.md: post-mortem for the
  webpack CJS/ESM interop crash that caused blank pages;
  documents why BattlemapTab duplicates engine functions locally
2026-07-15 19:36:00 +02:00
cc5aa88703 docs: require live site verification 2026-07-03 15:02:35 +02:00
93fee15e32 Fix player weapon damage/types: christoffer weapons had empty damage, claes Power Fist type fixed 2026-07-02 18:20:33 +02:00
19f4dd0cca Fix bestiary data: sync profiles, armour, movement from stats; fix cross-contaminated entries 2026-07-02 17:36:41 +02:00
8225997107 Persist mission scene session state 2026-07-02 11:55:12 +02:00
0fa8c39c4d Update mission roller and simulation flow 2026-07-02 11:48:38 +02:00
2a8d72eb1e Add fate-point support to skill and combat rollers
Players can spend a fate point to re-roll, add +10, or add a degree of
success to their most recent roll. Spends are persisted to the player's
sheet via a new atomic POST /api/players/:name/spend-fate endpoint
(read-modify-write that preserves password and other tabInfo).

- rollHelpers.applyFateToTest: shared recompute for a test result
- useFate hook: loads current/total fate, spends + persists
- FateControls: shared current/total display + Re-roll/+10/+DoS buttons
- SkillRoller and the combat roller each track their last roll and
  replace it in history when fate is spent; combat also recomputes hits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:44:46 +02:00
edf0f8552c Combat roller: single enemy field; heavy weapons full-auto from RoF data
- Remove the redundant 'Attacker (from enemies)' dropdown and handler; the
  single Enemy selector remains as the target/defender profile.
- Parse the explicit single/semi/full RoF triplet (e.g. '-/-/6') from armoury
  stats so weapon modes/RoF come from data: the Heavy Bolter is now full-auto
  only at RoF 6. Bare numeric triplets defer to the class heuristic to avoid
  range-string collisions. Weapon selection already auto-fills damage/pen/rof/
  mode/tearing via computeWeaponDefaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:41:07 +02:00
36378ff702 Split roller into Skill and Combat tabs
Extract the skill-check UI/logic into a standalone SkillRoller component
and move shared dice helpers (d100, degrees, uid) into rollHelpers.js.
DeathwatchRoller now hosts the shared roll history + player sheet and a
Combat/Skill tab toggle; the skill-only characteristic/training helpers
moved into SkillRoller. Behaviour unchanged, including first-skill
preselect (now done inside SkillRoller) and the manual target override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:30:03 +02:00
d3305b957e Add manual target override to skill check
Allow setting an explicit target number to roll against instead of the
computed Per+training+mod. Works with no sheet skill selected (e.g. a
GM-set 'roll vs 43'). Empty field keeps the auto-computed behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:22:28 +02:00
c4c622c1b7 Remove orphaned SQLite-era scripts
Delete 17 one-off migration/admin scripts that imported the removed
./sqlite-db module. None are referenced by the app, package.json, or CI;
they broke at the SQLite->MariaDB migration. No live code imports
sqlite-db anymore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:19:15 +02:00
15785f2e70 Remove dead SQLite-era session middleware and healthcheck
Sessions are served from MariaDB via sessionModel.js + routes/sessionRoutes.
These files were orphaned by the SQLite->MariaDB migration:

- requireSession.js: unused (no importers), still required ./sqlite-db
- healthcheck.js: required removed ./sqlite-db; would crash every run
- server-healthcheck.yml: scheduled the broken healthcheck every 15 min

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:18:21 +02:00
8b4a15b6cc Bump healthcheck to Node 20; disable pointless cron schedule
healthcheck.js only opens the local committed SQLite DB on the runner
and never contacts the deployed server, so the every-15-min schedule
validated nothing and consumed Actions minutes. Keep workflow_dispatch
for manual runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:05:28 +02:00
e72fee218e Make unit tests an explicit CI step; bump Node, add npm cache
- Dedicated 'Run unit tests' step (npm run test:unit) so unit tests are
  visible and guaranteed in CI rather than implied by the build script.
- Build now calls react-scripts build directly, avoiding a redundant
  second Jest run (CI=true still fails the build on lint warnings).
- Bump Node 18 (EOL) -> 20 and enable npm dependency caching.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:03:07 +02:00
3a5e1f444f Fix react-hooks lint error failing CI build
Wrap fetchReports in useCallback so the useEffect dependency array
satisfies react-hooks/exhaustive-deps. CI treats build warnings as
errors (CI=true), so this lint warning was failing the build step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 11:57:36 +02:00
c28187decd Add standard scene actions and fix sim fire modes 2026-06-30 10:19:50 +02:00
44b2e283bd Add ammo and combat profiles to simulations 2026-06-30 10:08:10 +02:00
c54fd6c8fd Gate player skill conditions in missions 2026-06-30 09:07:55 +02:00
e7ef9ae2df Test mission skill modifiers 2026-06-30 08:53:44 +02:00
647869cba9 Add skill check modifiers to mission roller 2026-06-30 08:33:44 +02:00
a08afbaf0f Show skill target modifiers in mission roller 2026-06-30 08:18:09 +02:00
b6cff53b8e Add rules-based squad tactics checks 2026-06-29 14:00:19 +02:00
3aebcf8f0e Add examples to rules reference 2026-06-29 13:45:32 +02:00
fe884ac543 Prepare Deathwatch session tools 2026-06-29 13:37:02 +02:00
4630272171 feat: Error reports create GitHub Issues (alexpolo1/dwroller) 2026-06-25 18:56:30 +02:00
c0fc0d1aab fix: ErrorReports build errors - fix confirm/window.confirm and App.js JSX syntax 2026-06-25 18:45:20 +02:00
5c4c65abd7 Add error reporting system - logged-in users can submit bug reports, GM can resolve 2026-06-25 18:29:49 +02:00
e1bcf61498 fix: combat reveal toggle + eliminate poll flickering
Add 👁/🔒 toggle to combat row in Scene Secrets — players see
combat panel only when GM reveals it (scene.reveal.combat).

Stop flickering: background polls now run silent (no setLoading),
and state updates are skipped when JSON content is unchanged,
preventing unnecessary re-renders every 4s.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:06:37 +02:00
b3818bd727 feat: next game date banner + demo mission "Blodprøve"
Add amber banner at top of Mission Tab showing next session date
(Lørdag 28. juni 2026). Create 3-scene Danish demo mission
"Blodprøve: Deathwatch-protokol" (id 10) — Social briefing →
Investigation aboard a dark station → Combat vs Genestealer Patriarch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:01:58 +02:00
5d98ebec13 feat: granular per-element reveal system + GM manual dice entry
Replace single scene reveal toggle with individual unlock buttons for
title, mood, description, objectives, complications, and each check —
GM controls exactly what players see and when.

Add GM manual roll entry (🎲 button per check): select player, type
the physical dice result, submit records it to the mission roll feed
under that player's name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 14:57:29 +02:00
d6f2f0e5c7 feat: mood text per scene + Danish translation of Fabius Bile mission
- Mood text field on scenes shown as amber italic read-aloud block
  above scene description (gated by revealed flag for players)
- Scene editor includes Mood / Read-aloud textarea
- Scene editor moved full-width below two-column grid
- Mission "The Hunt for Fabius Bile" fully translated to Danish
  ("Jagten på Fabius Bile") with Danish names, descriptions,
  objectives, complications, checks and mood text for all 10 scenes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 14:48:31 +02:00
7873f450da feat: rules midgame priority system, mission enhancements, and requisition shop improvements
- Add midgame priority ranking for rules (midgamePriority field)
- Enhance rules search to support midgame filtering and sorting
- Improve mission simulation and midgame tracking
- Fix RequisitionShop player name handling
- Add rules midplay simulation tests
- Update MissionTab with midgame scene tracking
- Add backend logging for rules updates
2026-06-24 12:09:25 +02:00
7d038dd942 feat: GM mid-play scene editor in Mission Tab
Edit Scene button in Scene Secrets header opens an inline editor card
below Table State. Lets the GM edit scene title, type, description,
checks (name/skill/char/target/modifier/reward, add/remove), enemies
(name/wounds/BS/WS/damage/AP, add/remove), objectives, and
complications — all saved live via the existing patchScene path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 11:08:48 +02:00
2a63e43120 feat: simulation difficulty control (Recruit → Legendary)
5 tiers selectable in Sim Lab config panel. Each tier scales enemy
wounds/BS/AP, adds check penalties, adjusts max combat rounds,
inter-scene healing chance, fear bonus, and adds a 3rd Elite Guard
enemy at Brutal+. Difficulty stored in DB (difficulty_level column)
and shown as a badge in the sidebar and report header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 11:04:17 +02:00
a666b8b4b4 feat: Simulation Lab — GM tab to run and review mission simulations
Backend:
- Add `simulations` table to MariaDB (mission, players, result, XP,
  roll feed, player cards, scene log, findings — all persisted as JSON)
- simulationHelpers: save / getAll / getById / delete
- simulationRoutes.js: POST /api/simulations (run engine + save),
  GET /api/simulations (list), GET /:id (full report), DELETE /:id
- Simulation engine: d100 dice, fear tests, combat rounds with
  initiative, conditions, damage, fate re-rolls, skill checks,
  auto-assign checks to best-stat player, enemy pools from scene data,
  per-player report cards with grade A-D, hero moments, shame list

Frontend:
- SimulationTab.jsx: GM-only tab with sidebar list of past runs,
  "Run New Simulation" config panel (pick mission + players),
  collapsible scene log, player report cards, filterable roll feed,
  findings panel
- App.js: import SimulationTab, add "⚙ Sim Lab" nav button (GM only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 10:31:27 +02:00
a7721006ef test: add playthrough simulation #2 script (playthroughRun2.js)
Full standalone Node.js simulation of 'The Hunt for Fabius Bile'.
Real d100 rolls vs actual player stats, wound tracking, fear tests,
initiative, conditions, fate spends, and per-player report cards.
Run: node src/tests/playthroughRun2.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:55:42 +02:00
02ddc2686b fix: RequisitionShop — RP tracking, spending, and GM management panel
- Fetch player RP/renown/gear from GET /api/players/:name (public full data)
  instead of the name-only player list, so RP is never 0
- Player status bar: RP (amber), renown badge, collapsible gear inventory
- Purchase flow posts to /api/shop/purchase and reads newRp from response
- Affordable filter, renown filter, item cards show affordability state
- GM panel: all-player RP/renown/gear table, Set RP, Set Renown forms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:48:53 +02:00
8febe583ee feat: Dice Roller — player sheet auto-load, weapon filtering, condition modifiers
On load, each player's character sheet is fetched from /api/players/{name}:
- BS and WS set from tabInfo.characteristics
- Weapon dropdown replaced with only their personal weapons (normalised
  from tabInfo.weapons: type→class, ap→pen, default modes by type)
- First weapon pre-selected with all its damage/pen/rof/mode defaults applied
- maxWounds set from tabInfo.wounds; curWounds preserved from localStorage
  if the player was already tracking mid-session

Active scene conditions (synced from MissionTab via dw:combat-state) now
apply automatic attack modifiers:
- Pinned: –20 BS
- Stunned: –20 BS/WS
- Knocked Down: –20 BS/WS
- Fatigued: –10 BS/WS
- Grappled: –20 WS, ranged/heavy weapons hidden from weapon dropdown
- Bleeding: banner only (no roll modifier)

Condition banner appears above the roller when any condition is active,
showing each condition label and the net modifier to the attack target.
The status bar target display also shows the condition delta inline.

MissionTab: conditions map now included in dw:combat-state localStorage
write and CustomEvent payload so the Dice Roller receives per-player
condition state in real time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:38:32 +02:00
cdfd147f02 feat: Mission Tab — 11 playthrough fixes + 4 follow-up findings
All 11 issues from 4-player simulation of The Hunt for Fabius Bile:
1. Roll feed visible to all players (no GM auth guard)
2. Scene text gated by revealed flag; GM explicit reveal per scene
3. GM can add NPC/enemy entries to initiative tracker
4. Round counter synced to Dice Roller via localStorage + custom event
5. Check reward text hidden until player has rolled
6. Checks assignable to specific player via Scene Secrets ⚙ options
7. Fear test quick-roll panel with WP input appears when fearRating > 0
8. Decision checks show textarea/Declare instead of d100 roll button
9. Fate point re-roll: one per check per scene, resets on scene advance
10. Player poll reduced from 8s to 4s, combined mission + roll feed poll
11. Mission complete banner with scene stats and GM outcome notes field

4 follow-up findings from second simulation run:
- Finding #1: Activate mission now initialises revealed:false on all scenes
  so players never see scene text before the GM narrates
- Finding #2: Fear penalty auto-applied to WP display; button shows
  effective (penalised) target rather than raw WP input
- Finding #3: RollFeedRow moved outside component to avoid re-mount on
  every render; onDelete passed as prop
- Finding #4: Removed duplicate "Open for Players" quick-button from
  Scene Checks left panel — Scene Secrets is the sole entry point

New files:
- src/tests/missionPlaythrough.test.js — full GM+4-player simulation
  test suite covering all 11 issues and 4 findings (39 test cases)
- src/tests/missionTab.test.js — player/GM view isolation tests
- src/utils/diceRoller.js — shared d100/degrees/clampTarget utilities
- tests/missionRoutes.test.js — backend mission route unit tests
- tests/playerRoutesLogin.test.js — player login route tests
- tests/sessionRoutes.test.js — session validation tests

Note: React unit tests require jsdom; segfaults on ARM64 (Raspberry Pi)
due to a known jsdom/Node 20 incompatibility on aarch64. Tests pass on
x86 CI. Backend integration tests (tests/) run normally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:25:51 +02:00
cd180aad5b fix: CI tests - switch login to text input, fix session validation regex, fix playerManagement test 2026-06-23 15:33:36 +02:00
d610fa08fb fix: GM login - include GM in dropdown, auto-fill password, fix session validation regex 2026-06-23 15:18:33 +02:00
5b022a6426 Save mission 'The Hunt for Fabius Bile' to DB
- 10 scenes, 59 enemies, High threat, 4 players
- Includes all combat encounters, social, investigation, puzzle, epilogue
2026-06-23 14:52:34 +02:00
bfe3489060 Update player sheets with proper Deathwatch data
- All players: Adept renown (1 RP), 15 wounds, fate=1, full characteristics
- anders: Blood Angels Devastator, Heavy Bolter + Bolt Pistol
- christoffer: Ultramarines Chaplain (Hero, 3 RP), Crozius Arcanum + Bolt Pistol
- claes: Ultramarines Sergeant, Bolter + Chainsword + Power Fist + Bolt Pistol
- phillip: Ultramarines Space Marine, Bolter + Chainsword + Bolt Pistol
2026-06-23 14:48:26 +02:00