636 lines
30 KiB
Markdown
636 lines
30 KiB
Markdown
# AGENTS.md - Codex Guide for Deathwatch Roller
|
|
|
|
This file gives Codex repo-specific context for working on Deathwatch Roller.
|
|
Prefer the live code and `package.json` over older docs when they disagree.
|
|
|
|
## Project Snapshot
|
|
|
|
Deathwatch Roller is a Create React App + Express application for running
|
|
Deathwatch tabletop RPG sessions. It includes player login and character data,
|
|
dice rolling, missions, simulations, a requisition shop, bestiary, rules search,
|
|
weapon references, GM tools, and user-submitted error reports.
|
|
|
|
The repository is currently a single-root JavaScript app:
|
|
|
|
- Frontend: React 18 JSX under `src/`
|
|
- Backend: Express server under `database/`
|
|
- Database: MariaDB via `mysql2/promise`, with some legacy SQLite artifacts
|
|
- Static data: JSON and generated assets under `public/`, `data/`, `database/`,
|
|
and `database/rules/`
|
|
- Tests: Jest + React Testing Library for frontend unit tests; separate
|
|
integration config for root-level integration tests
|
|
|
|
## High-Value Paths
|
|
|
|
- `src/App.js` - main React app, login/session state, tab wiring
|
|
- `src/components/` - feature UI components
|
|
- `src/components/DeathwatchRoller.jsx` - combat dice roller, weapon mapping,
|
|
attack rolls, damage, hit locations, history, presets, and tracker state
|
|
- `src/components/SkillRoller.jsx` - sheet-driven skill checks, manual d100
|
|
entry, target overrides, and fate-point roll modification
|
|
- `src/components/rollHelpers.js` - shared frontend d100, degrees of
|
|
success/failure, ids, and fate application helpers used by roller components
|
|
- `src/utils/diceRoller.js` - mission-safe dice helpers and
|
|
`MISSION_ROLL_CONTEXT_KEY`
|
|
- `src/components/MissionTab.jsx` - active mission play surface, scene reveal
|
|
state, check rolling, combat state, initiative, mission roll feed, and GM
|
|
progress controls
|
|
- `src/components/SimulationTab.jsx` - simulation report UI, run controls,
|
|
difficulty/profile selection, roll feed display, and saved reports
|
|
- `src/components/MissionSimTab.jsx` - older/generated mission simulator UI;
|
|
check current routing before extending it
|
|
- `src/utils/` - shared frontend utilities such as dice and XP logic
|
|
- `src/tests/` - Jest unit tests run by the default test config
|
|
- `database/server.js` - Express backend entrypoint and route mounting
|
|
- `database/routes/` - API routes for players, sessions, shop, rules, bestiary,
|
|
weapons, missions, simulations, staging, and error reports
|
|
- `database/routes/missionRoutes.js` - mission CRUD, active mission selection,
|
|
player-safe scene projection, active-scene patching, and shared roll feed APIs
|
|
- `database/routes/simulationRoutes.js` - backend simulation engine and
|
|
simulation CRUD/report APIs
|
|
- `database/mariadb.js` - MariaDB pool, schema creation, schema patching
|
|
- `database/sessionModel.js` - session storage helpers
|
|
- `database/shop-helpers.js` - requisition/shop business logic
|
|
- `scripts/` - import, cleanup, validation, generation, and local CI helpers
|
|
- `docs/` - user/developer docs; some structure docs are stale and still refer
|
|
to non-existent `backend/` and `frontend/` directories
|
|
|
|
## Commands
|
|
|
|
Run commands from the repository root unless noted.
|
|
|
|
```bash
|
|
npm install
|
|
npm start
|
|
npm run server:notest
|
|
npm run test:unit
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
Useful variants:
|
|
|
|
```bash
|
|
npm run server # runs tests first, then database/server.js
|
|
npm run test:integration
|
|
npm run build:fast # skips tests, then reloads PM2
|
|
./scripts/local-ci.sh
|
|
```
|
|
|
|
Local ports:
|
|
|
|
- Frontend dev server: `http://localhost:3000`
|
|
- Backend API: `http://localhost:5000`
|
|
- CRA proxy points frontend API requests at `http://localhost:5000`
|
|
|
|
## Environment And Runtime Notes
|
|
|
|
- Backend loads environment variables with `dotenv` from the backend process
|
|
working directory. `npm run server:notest` runs from `database/`, so
|
|
`database/.env` is relevant.
|
|
- MariaDB connection defaults are hard-coded in `database/mariadb.js`:
|
|
host `192.168.1.113`, user `deathwatch`, database `deathwatch`, port `3307`,
|
|
password from `DB_PASSWORD` or `defaultpassword`.
|
|
- GM upload auth checks `GM_SECRET` and falls back to `defaultsecret`.
|
|
- `/api/narrate` calls Ollama using `OLLAMA_BASE` and `NARRATOR_MODEL`.
|
|
- The backend can serve `build/` statically when a production build exists.
|
|
|
|
## Testing Guidance
|
|
|
|
- Use `npm run test:unit` for normal frontend changes.
|
|
- Use targeted Jest commands when iterating, for example:
|
|
|
|
```bash
|
|
npm test -- src/tests/login.test.js
|
|
```
|
|
|
|
- Use `npm run test:integration` only when backend/API behavior is touched and
|
|
PM2/MariaDB are available.
|
|
- `npm run build` runs unit tests before `react-scripts build`.
|
|
- If tests fail because MariaDB, PM2, Ollama, or local services are unavailable,
|
|
report that explicitly rather than masking the failure.
|
|
|
|
## Implementation Conventions
|
|
|
|
- The codebase is plain JavaScript/JSX, not TypeScript. Match the surrounding
|
|
style unless a broader migration is explicitly requested.
|
|
- Prefer existing React hooks/component patterns in `src/components/`.
|
|
- Keep state persistence keys stable; the app uses `localStorage` keys such as
|
|
`dw:shop:authedPlayer`, `dw:shop:sessionId`, and `dw:shop:playerData`.
|
|
- API calls from the frontend generally use relative `/api/...` URLs through
|
|
the CRA proxy.
|
|
- Preserve backend response shapes used by existing components and tests.
|
|
- Keep database writes parameterized through `mysql2` APIs.
|
|
- Avoid broad refactors in data import scripts unless the task is specifically
|
|
about those scripts.
|
|
|
|
## Dice Roller, Mission, And Simulation Notes
|
|
|
|
### Dice Roller
|
|
|
|
- The main dice roller lives in `src/components/DeathwatchRoller.jsx`.
|
|
- Shared roller primitives live in two places:
|
|
- `src/components/rollHelpers.js` for UI roller and skill roller behavior.
|
|
- `src/utils/diceRoller.js` for mission-safe helpers and the mission roll
|
|
context storage key.
|
|
- Core roll semantics:
|
|
- `d100()` returns 1-100.
|
|
- `degrees(target, roll)` treats `roll <= target` as success and reports
|
|
Degree of Success or Degree of Failure in 10-point bands.
|
|
- Skill and combat roll targets should stay clamped to sensible d100 bounds.
|
|
- Combat helpers in `DeathwatchRoller.jsx` cover dice expressions, weapon
|
|
normalization, RoF modes, hit counts from DoS, hit location from reversed
|
|
d100, tearing/proven damage dice, and damage mitigation.
|
|
- Skill rolling is delegated to `SkillRoller.jsx`, which reads the logged-in
|
|
player's sheet skills/characteristics, applies training modifiers, supports a
|
|
manual d100 roll, and can override the target number.
|
|
- Fate handling is shared by `FateControls.jsx`, `useFate.js`, and
|
|
`applyFateToTest()` in `rollHelpers.js`. Spending fate persists through
|
|
`POST /api/players/:name/spend-fate`.
|
|
- Persistent browser state keys used by the roller include:
|
|
- `dw:presets:v3`
|
|
- `dw:history:v2`
|
|
- `dw:weapons:v3`
|
|
- `dw:tracker:v1`
|
|
- `dw:mission:rollContext`
|
|
|
|
### Mission Play
|
|
|
|
- `MissionTab.jsx` is the current mission play implementation used from
|
|
`App.js`.
|
|
- GM users are identified in the UI with `authedPlayer === 'gm'`.
|
|
- GM flow:
|
|
- Load all missions with `GET /api/missions`.
|
|
- Load the current active mission with `GET /api/missions/active/current`.
|
|
- Create/update/delete missions through `POST/PUT/DELETE /api/missions`.
|
|
- Set the active mission with `POST /api/missions/:id/active`.
|
|
- Save progress and scene edits with `PUT /api/missions/:id/progress`.
|
|
- Player flow:
|
|
- Load only the player-safe active scene with
|
|
`GET /api/missions/active/player`.
|
|
- Hidden scene fields are stripped in `playerScene()` in
|
|
`database/routes/missionRoutes.js`.
|
|
- Player mini rollers patch only the active scene through
|
|
`PUT /api/missions/active/scene` so they do not overwrite the full mission.
|
|
- The shared mission roll feed is backed by the `mission_rolls` table:
|
|
- Read with `GET /api/missions/active/rolls/feed?limit=50`.
|
|
- Create with `POST /api/missions/rolls`.
|
|
- Delete with `DELETE /api/missions/rolls/:id`.
|
|
- Mission scenes may contain checks, objectives, complications, extra
|
|
challenges, combat state, reveal state, play prompts, enemies, rewards,
|
|
`storyHook`, `secret`, GM notes, and ending text. Preserve unknown scene
|
|
fields when patching scenes.
|
|
- Generated missions should give every scene a GM-only `storyHook` that acts as
|
|
a thread toward the mission's main story. Skill check rewards are the visible
|
|
triggers that reveal the hook; failures should use fail-forward consequences
|
|
instead of blocking the clue.
|
|
- Combat state is scene-local and includes round, initiatives, conditions, and
|
|
fear rating. Initiative rolls use `1d10 + Ag bonus`; fear/check rolls use the
|
|
same d100 degree helpers as the roller.
|
|
- When changing mission roll behavior, verify both GM and player perspectives:
|
|
the GM sees the full mission, while players only receive the active safe scene.
|
|
|
|
### Simulation
|
|
|
|
- `SimulationTab.jsx` is the current simulation report and control UI.
|
|
- `database/routes/simulationRoutes.js` contains the backend simulation engine.
|
|
It loads mission/player data, builds temporary player combat state from
|
|
`tabInfo`, runs scenes, and saves reports through `simulationHelpers`.
|
|
- Simulation endpoints:
|
|
- `POST /api/simulations` runs and saves a new simulation.
|
|
- `GET /api/simulations?limit=50` lists saved simulation summaries.
|
|
- `GET /api/simulations/:id` returns a full saved report.
|
|
- `DELETE /api/simulations/:id` removes a saved report.
|
|
- Simulation request inputs include `mission_id`, `player_names`, `difficulty`,
|
|
per-player `combat_profiles`, and `enemy_profile`.
|
|
- Difficulty levels are 1-5 and affect wounds, enemy BS, check modifiers, fear,
|
|
extra enemies, recovery, and max combat rounds.
|
|
- Combat profiles include `auto`, `balanced`, `ranged`, and `melee`; they affect
|
|
weapon choice, grenade use, and enemy attack style.
|
|
- The simulation engine normalizes weapons from player `tabInfo.weapons`,
|
|
infers ammo/clip defaults for common Deathwatch weapons, tracks ammo spend,
|
|
resolves single/semi/full-auto hit counts, rolls initiative each combat round,
|
|
applies conditions, performs fear tests, spends fate once when useful, and
|
|
builds roll feeds/player report cards.
|
|
- Saved simulation reports include result, earned XP, total rounds, total rolls,
|
|
overall success rate, combat success rate, puzzle/check success rate, scene
|
|
results, player cards, roll feed, story hooks, findings, `difficulty_level`,
|
|
and `enemy_profile`.
|
|
- Because simulations use `Math.random()` directly and are not seeded, tests and
|
|
docs should avoid assuming deterministic exact roll output.
|
|
|
|
## App Tabs
|
|
|
|
Tabs are selected in `src/App.js` with the `tab` state. Login/session state is
|
|
owned by `App.js` and passed to tabs as `authedPlayer` and `sessionId` where
|
|
needed. Navigation actions are logged with `logUserAction()`.
|
|
|
|
### Mission
|
|
|
|
- Component: `src/components/MissionTab.jsx`
|
|
- Default tab: `mission`
|
|
- Availability: all logged-in states, but GM and player views differ.
|
|
- Backend: `/api/missions`, `/api/missions/active/current`,
|
|
`/api/missions/active/player`, `/api/missions/active/scene`, and mission roll
|
|
feed endpoints.
|
|
- Notes: GM sees full mission state; players receive only the active safe scene.
|
|
Preserve unknown scene fields and avoid replacing the full scene array from
|
|
player-facing actions.
|
|
|
|
### Dice Roller
|
|
|
|
- Component: `src/components/DeathwatchRoller.jsx`
|
|
- Tab key: `roller`
|
|
- Availability: visible to all users.
|
|
- Backend: player sheet/fate endpoints, bestiary enemy data where loaded, and
|
|
mission roll context when launched from mission play.
|
|
- Notes: Depends on `SkillRoller.jsx`, `FateControls.jsx`, `useFate.js`,
|
|
`rollHelpers.js`, and `src/utils/diceRoller.js`. Keep d100/DoS behavior
|
|
aligned across mission, skill, and combat rolls.
|
|
|
|
### Requisition Shop
|
|
|
|
- Component: `src/components/RequisitionShop.jsx`
|
|
- Tab key: `shop`
|
|
- Availability: visible to all users; GM controls appear for `authedPlayer ===
|
|
'gm'`.
|
|
- Backend: `GET /api/shop`, `POST /api/shop/purchase`,
|
|
`GET /api/players/:name`, `GET /api/players`, `POST /api/players/gm/set-rp`,
|
|
and `POST /api/players/gm/set-renown`.
|
|
- Data source: `public/deathwatch-armoury.json` through `shopRoutes.js`.
|
|
- Notes: Purchases deduct `tabInfo.rp` and append/update `tabInfo.gear`.
|
|
Renown gating uses the local rank order in the component.
|
|
|
|
### Character Sheet
|
|
|
|
- Component: `src/components/PlayerTab.jsx`
|
|
- Tab key: fallback branch when no other tab matches; nav label is
|
|
`Character Sheet`.
|
|
- Availability: visible to all users; GM edit tools are enabled only when the
|
|
logged-in user is `gm`.
|
|
- Backend: `GET /api/players`, `GET /api/players/:name`,
|
|
`PUT /api/players/:name`, avatar upload under
|
|
`POST /api/players/:name/avatar` if present, and GM player endpoints.
|
|
- Local state: caches player data under `dw:shop:players:v1` and also consumes
|
|
`dw:shop:playerData` as a fallback.
|
|
- Notes: Character data is stored primarily in `tabInfo` and includes
|
|
characteristics, skills, weapons, armour, gear, wounds, fate, XP, XP spent,
|
|
renown, movement, insanity, corruption, notes, and avatar/picture data.
|
|
Preserve `tabInfo` shape because the roller and simulator read it directly.
|
|
|
|
### Rules
|
|
|
|
- Component: `src/components/RulesTab.jsx`
|
|
- Tab key: `rules`
|
|
- Availability: visible to all users.
|
|
- Backend: `GET /api/rules/categories`, `GET /api/rules/search`,
|
|
`GET /api/rules/rule/:id`, and `GET /api/rules/random`.
|
|
- Local state: recent searches are stored as `dw:rules:recent`.
|
|
- Notes: Results include structured fields such as summary, examples,
|
|
category, source, page, aliases, tags, and midgame priority. Keep highlighting
|
|
and compact/full rendering behavior when changing rule result shapes.
|
|
|
|
### Weapons
|
|
|
|
- Component: `src/components/WeaponsTab.jsx`
|
|
- Tab key: `weapons`
|
|
- Availability: visible to all users.
|
|
- Backend: `GET /api/weapons`.
|
|
- Data source: MariaDB weapons when available, with fallback to
|
|
`public/deathwatch-armoury.json`.
|
|
- Notes: The tab normalizes displayed categories into ranged, melee, grenade,
|
|
armour, and other. Ranged stat strings may be parsed from semicolon-separated
|
|
fields in `stats.damage`.
|
|
|
|
### Error Reports
|
|
|
|
- Component: `src/components/ErrorReports.jsx`
|
|
- Tab key: `errors`
|
|
- Availability: visible to all logged-in users; GM sees all reports and can
|
|
resolve/delete.
|
|
- Backend: `GET /api/errors`, `POST /api/errors`,
|
|
`PUT /api/errors/:id/resolve`, `PUT /api/errors/:id/status`, and
|
|
`DELETE /api/errors/:id`.
|
|
- Auth: requires `x-session-id`; backend uses `requireSession`.
|
|
- Notes: Non-GM users should only see their own reports. Form submissions
|
|
default `pageUrl` to the current browser path when not provided.
|
|
|
|
### Bestiary
|
|
|
|
- Component: `src/components/BestiaryTab.jsx`
|
|
- Tab key: `bestiary`
|
|
- Availability: GM-only in `App.js`; non-GM users see an access denied panel.
|
|
- Backend: `GET /api/bestiary/full`, `POST /api/bestiary/reload`, and
|
|
`GET /api/bestiary/enemies` for dice roller enemy format.
|
|
- Local state: caches entries under `dw:enemies:v1`; DB-down warning dismissal
|
|
uses `dw:warning-dismiss-until:v1`.
|
|
- Data source: MariaDB bestiary rows with fallback to
|
|
`public/deathwatch-bestiary-extracted.json`.
|
|
- Notes: `normalizeEntry()` handles multiple imported statblock shapes. Keep
|
|
fallback/cache behavior intact so the tab remains useful when the DB is down.
|
|
|
|
### Player Management
|
|
|
|
- Component: `src/components/PlayerManagement.jsx`
|
|
- Tab key: `players`
|
|
- Availability: GM-only nav item. The component also expects GM context.
|
|
- Backend: `GET /api/players`, `POST /api/players/gm/add-or-update`,
|
|
`POST /api/players/gm/set-xp`, `POST /api/players/gm/set-xp-spent`,
|
|
`POST /api/players/gm/set-rp`, `POST /api/players/gm/set-renown`,
|
|
`POST /api/players/gm/reset-password`, and
|
|
`DELETE /api/players/gm/delete/:name`.
|
|
- Auth: sends `x-session-id` and `x-gm-secret` where available; backend GM
|
|
secret defaults are defined in `playerRoutes.js`.
|
|
- Notes: Bulk XP/RP operations update each player in sequence. The component
|
|
expects player economic and progression values in `tabInfo`.
|
|
|
|
### GM Kit
|
|
|
|
- Component: `src/components/GMKit.jsx`
|
|
- Tab key: `gmkit`
|
|
- Availability: GM-only nav item and component-level access check.
|
|
- Backend: none for the current table UI; `App.js` separately uses
|
|
`GET /api/gmkit/list` to choose the players-tab background.
|
|
- Notes: Current GM Kit is static reference tables inside the component:
|
|
difficulty modifiers, hit locations, combat actions, weapons, armour,
|
|
critical hits, weapon qualities, cover, renown, and related GM references.
|
|
There are older `GMKit_old.jsx` and `GMKit_new.jsx` files; check routing
|
|
before editing them.
|
|
|
|
### Simulation Lab
|
|
|
|
- Component: `src/components/SimulationTab.jsx`
|
|
- Tab key: `simulation`
|
|
- Availability: GM-only nav item in `App.js`.
|
|
- Backend: `/api/simulations` endpoints and mission/player data loaded by the
|
|
backend simulation route.
|
|
- Notes: Reports include roll feeds, scene logs, player report cards, story
|
|
hooks, findings, difficulty, and enemy profile. Simulation output is
|
|
non-deterministic.
|
|
|
|
### External Utility Pages
|
|
|
|
- `public/cards.html` is linked from nav as `Kort` and opens in a new tab. It is
|
|
a printable card-sheet view and fetches app/static data directly from the
|
|
served public site.
|
|
- `public/print.html` is linked from nav as `Print` and opens in a new tab. It
|
|
is a printable quick-reference sheet.
|
|
- These are not React tabs. They are static public pages served by CRA/dev
|
|
server or by Express static serving in production.
|
|
|
|
## Deathwatch RPG Domain Notes
|
|
|
|
Use these notes when changing the app's roller, mission, simulation, shop,
|
|
rules, bestiary, and character-sheet flows. They are summarized from the local
|
|
rules database and app data, not copied from rulebook text. Do not paste long
|
|
rulebook passages into UI or docs; link/search the local rules DB and summarize
|
|
mechanics in original wording.
|
|
|
|
### Source Data In This Repo
|
|
|
|
- Rules index: `database/rules/rules-database.json`
|
|
- Categories include `actions`, `combat`, `damage`, `conditions`,
|
|
`requisition`, `renown`, `cohesion`, `squad_mode`, `psychic`, `hordes`,
|
|
`gm_tables`, `mission`, `skills`, `talents`, and `traits`.
|
|
- Skill import/reference data: `database/deathwatch_skills_p94_107.csv`
|
|
- Armoury/shop data: `public/deathwatch-armoury.json`
|
|
- Major groups include ranged weapons, melee weapons, grenades, other
|
|
weapons, power armour, helmets, carapace/natural/primitive/xenos armour,
|
|
shields, and other armour.
|
|
- Bestiary data: `public/deathwatch-bestiary-extracted.json` and
|
|
`database/deathwatch-bestiary-extracted.json`
|
|
- Entries generally include profile, movement, wounds, toughness, skills,
|
|
talents, traits, armour, book, page, and snippets.
|
|
- Backend may load rules, weapons, and bestiary from MariaDB first, then fall
|
|
back to the JSON files above.
|
|
|
|
### Core Resolution Model
|
|
|
|
- Deathwatch uses percentile tests: roll `d100` and succeed when the roll is
|
|
equal to or under the effective target.
|
|
- Effective target is normally characteristic + skill/training + situational
|
|
modifiers. The app generally clamps practical targets to d100 bounds.
|
|
- Degrees of Success/Failure are 10-point bands from the target/roll margin.
|
|
The app's shared helper returns 1 base degree plus one per full 10 points.
|
|
- Basic skills can be attempted broadly; untrained advanced skills should be
|
|
treated as unavailable or heavily constrained unless the app explicitly
|
|
allows an override.
|
|
- Common characteristics:
|
|
- `WS` Weapon Skill for melee attacks and parries.
|
|
- `BS` Ballistic Skill for ranged attacks.
|
|
- `S`, `T`, `Ag`, `Int`, `Per`, `Wp`, `Fel` for strength, toughness,
|
|
agility, intelligence, perception, willpower, and fellowship checks.
|
|
- When making UI for tests, expose the final target, roll, success/failure,
|
|
DoS/DoF, and the source of modifiers. This is more useful at the table than
|
|
only showing pass/fail.
|
|
|
|
### Combat Flow
|
|
|
|
- Combat is round-based and action-based. Common action concepts include Aim,
|
|
Charge, Standard Attack, Semi-Auto Burst, Full Auto Burst, Overwatch,
|
|
Suppressing Fire, Dodge, Parry, Ready, Reload, Move, Run, and Disengage.
|
|
- Initiative is relevant to combat order. In the simulator, each combat round
|
|
currently rolls player `Agility Bonus + d10` and enemy `agBonus + d10`, then
|
|
resolves actors from highest to lowest.
|
|
- Attack flow for app purposes:
|
|
- Choose WS or BS based on melee/ranged attack.
|
|
- Apply attack-mode and situation modifiers.
|
|
- Roll d100 against target.
|
|
- On a hit, derive hit count from fire mode and DoS.
|
|
- Determine hit location from the reversed d100 attack roll where needed.
|
|
- Roll damage, apply weapon qualities such as Tearing/Proven where supported.
|
|
- Reduce damage by armour and Toughness Bonus/Penetration handling as the
|
|
app model supports.
|
|
- Track wounds, critical damage threshold, defeat/downed status, and notable
|
|
events.
|
|
- Semi-auto and full-auto are not just labels. They change the attack modifier
|
|
and how additional hits scale with DoS. Keep roller and simulator hit-count
|
|
formulas aligned.
|
|
- Dodge and Parry are reactions that negate hits when allowed. Dodge is usually
|
|
the generic ranged/melee avoidance reaction; Parry is melee and WS-based.
|
|
- Suppressing fire and pinning matter in Deathwatch combat. Pinned targets are
|
|
constrained and should be represented as a condition when simulation or
|
|
mission play needs battlefield pressure.
|
|
- Righteous Fury is a special high-damage/exploding-damage style event on
|
|
successful attacks. The simulator currently records "critical hit"/hero
|
|
moments for high DoS, while the roller has damage dice mechanics; be explicit
|
|
if changing this behavior to match a stricter table interpretation.
|
|
|
|
### Weapons, Damage, Armour, And Qualities
|
|
|
|
- Weapon data often appears as compact strings like range, RoF, damage,
|
|
penetration, clip, reload, and qualities. Prefer structured parsing helpers
|
|
over ad hoc display-only splitting when adding behavior.
|
|
- Damage expressions use dice notation such as `1d10+9`, `2d10+2`, or
|
|
`3d10+4`, with a damage type marker in source data (`E`, `I`, `R`, `X`, etc.)
|
|
for energy, impact, rending, explosive, and related categories.
|
|
- Important weapon qualities represented in app data include Tearing, Reliable,
|
|
Accurate, Blast, Flame, Power Field, Razor Sharp, Unbalanced, Unwieldy,
|
|
Volatile, Scatter, Storm, Smoke, Toxic, and others.
|
|
- Tearing usually means roll extra damage dice and keep the better result for
|
|
supported dice. Proven sets a floor on supported damage dice. Only apply
|
|
qualities that the code explicitly models.
|
|
- Armour can be whole-body or location-based. Bestiary and armoury entries may
|
|
use different shapes for protection values, so normalize before using in
|
|
combat calculations.
|
|
- Penetration should reduce armour effectiveness, not Toughness, unless a local
|
|
helper intentionally abstracts damage.
|
|
|
|
### Missions, Requisition, Renown, And Economy
|
|
|
|
- Deathwatch missions are framed around a kill-team selecting mission gear,
|
|
entering an operation, resolving scenes, earning XP/renown, and returning
|
|
equipment.
|
|
- Requisition Points are mission equipment budget, not ordinary money. The shop
|
|
stores purchases as gear and deducts `tabInfo.rp`.
|
|
- Renown gates access to more prestigious or restricted equipment. The app rank
|
|
order is `None`, `Respected`, `Distinguished`, `Famed`, `Hero`; keep that
|
|
order consistent in shop and player-management flows.
|
|
- Mission scenes in this app can include objectives, complications, checks,
|
|
enemies, combat state, reveal state, extra challenges, rewards, and ending
|
|
text.
|
|
- Good mission UI should separate GM-only information from player-safe scene
|
|
information. The backend `playerScene()` projection strips hidden/GM fields.
|
|
|
|
### Skills And Scene Checks
|
|
|
|
- Useful scene-check skills from the local skill data include Awareness,
|
|
Command, Tactics, Tech-Use, Medicae, Scrutiny, Search, Logic, Inquiry,
|
|
Intimidate, Demolition, Tracking, Survival, Security, Psyniscience, and
|
|
relevant Lore skills.
|
|
- Tactics is an Intelligence skill and should be used for battlefield doctrine,
|
|
priority targets, ambush reads, deployments, or tactical approach. It should
|
|
not automatically grant Squad Mode abilities or Cohesion benefits unless a
|
|
mission rule explicitly says so.
|
|
- Awareness/Search/Tracking are good for threat and clue discovery.
|
|
- Tech-Use/Security/Demolition are good for machines, locks, traps, explosives,
|
|
and sabotage.
|
|
- Medicae/Chem-Use are good for injuries, toxins, infection, biology, and field
|
|
treatment.
|
|
- Command/Charm/Intimidate/Scrutiny/Deceive support social or morale scenes.
|
|
- Puzzle scenes should usually produce multiple checks with assigned best-fit
|
|
players, visible targets, complications on high DoF, and rewards on success.
|
|
|
|
### Cohesion, Squad Mode, Solo Mode, And Fate
|
|
|
|
- Cohesion is the kill-team resource around coordination and Squad Mode.
|
|
Existing app coverage is mostly reference/rules-search level; do not invent
|
|
persistent Cohesion behavior without adding explicit state and tests.
|
|
- Squad Mode and Solo Mode are distinct from ordinary skill checks. A successful
|
|
Tactics or Command roll should not silently toggle Squad Mode.
|
|
- Fate points can be spent to improve outcomes. In this app:
|
|
- The roller exposes re-roll, +10, and +DoS style fate actions.
|
|
- `useFate.js` reads and persists fate through player endpoints.
|
|
- The simulator may spend fate once on severe failed checks.
|
|
- Keep fate changes persistent and visible because players track remaining fate
|
|
across scenes/sessions.
|
|
|
|
### Psychic Powers And Warp Risk
|
|
|
|
- Psychic rules involve Focus Power tests, Psy Rating, and risk modes such as
|
|
safer/fettered use versus riskier high-output use.
|
|
- Psychic Phenomena and Perils of the Warp are significant consequences. If
|
|
adding psychic automation, model risk and output separately and expose the
|
|
roll trail clearly.
|
|
- Avoid treating psychic powers as generic skills unless the feature explicitly
|
|
asks for a simplified helper.
|
|
|
|
### Hordes And Large Enemy Groups
|
|
|
|
- Hordes are a special combat abstraction for many lesser enemies. They should
|
|
not be treated as a single normal NPC unless the app is intentionally using a
|
|
simplified profile.
|
|
- Horde-relevant UI should track magnitude/remaining threat, area effects,
|
|
full-auto/multi-hit attacks, Blast, Flame, and morale/breaking behavior.
|
|
- Current simulation uses simplified enemy lists and wounds, not a full horde
|
|
engine.
|
|
|
|
### Bestiary And Enemy Modeling
|
|
|
|
- Bestiary entries vary by source and import quality. Normalize names, profile
|
|
stats, wounds, armour, movement, talents, traits, and attacks before using
|
|
them in roller/simulation logic.
|
|
- Common enemy themes in app code include Tyranids, Chaos, Xenos/Tau, Orks, and
|
|
servitor/Imperial profiles.
|
|
- For combat simulation, prefer clear approximations and visible findings over
|
|
opaque precision. If a stat is missing, surface the fallback rather than
|
|
pretending it came from the book.
|
|
|
|
### Simulation Design Guidance
|
|
|
|
- Simulation is a balance/design tool, not an authoritative rules engine.
|
|
- Keep simulated rolls categorized. Current categories include:
|
|
- `combat` for attacks and combat-scene tactical checks.
|
|
- `puzzle` for non-combat scene checks.
|
|
- `fear` for fear tests.
|
|
- Reports should show overall success %, combat %, puzzle/check %, XP, rounds,
|
|
roll count, scene results, player report cards, ammo/fate use, conditions,
|
|
initiative events, and findings.
|
|
- Findings are scripted threshold notes, not AI. They do not use OpenAI/Ollama
|
|
tokens unless a future feature explicitly calls an AI endpoint.
|
|
- Story hooks are scripted from mission scene data. Mission generation stores a
|
|
GM-only `storyHook`/`secret` on each scene; simulation reports which checks or
|
|
combat outcomes revealed, partially revealed, or escalated those hooks.
|
|
- Scripted findings should give the GM actionable mission edits grounded in the
|
|
rules model: reduce or increase enemy pressure, add cover/Aim/Dodge/Parry
|
|
prompts, add non-attack combat objectives, tune puzzle difficulty, allow
|
|
assists/alternate skills, prevent single-roll clue bottlenecks, add recovery
|
|
beats for conditions/fear, and match player roles to checks.
|
|
- Evaluate combat and puzzle/skill pressure separately. A good sim report
|
|
should make it clear whether the mission is too lethal, too easy, too
|
|
attack-only, too clue-blocked, or mismatched to the party's stats.
|
|
- Because simulation uses `Math.random()` and is unseeded, never make exact
|
|
roll totals a test expectation. Test shape, categories, persistence, and
|
|
visible report fields instead.
|
|
|
|
### Copyright And Wording
|
|
|
|
- The repo contains local summaries, OCR, PDFs, and extracted data for gameplay
|
|
support. When writing UI/help/docs, use short summaries in original wording.
|
|
- Do not reproduce long rulebook sections, tables, or copyrighted passages in
|
|
new docs or UI. Prefer links/search into local rule entries and cite source
|
|
title/page metadata where helpful.
|
|
- If a requested feature needs exact rules text, build a lookup/display path
|
|
from the existing rules database instead of embedding copied text in code.
|
|
|
|
## API Surface
|
|
|
|
Mounted API prefixes in `database/server.js` include:
|
|
|
|
- `/api/players`
|
|
- `/api/sessions`
|
|
- `/api/shop`
|
|
- `/api/rules`
|
|
- `/api/weapons`
|
|
- `/api/bestiary`
|
|
- `/api/rules/staging`
|
|
- `/api/missions`
|
|
- `/api/simulations`
|
|
- `/api/errors`
|
|
- `/api/gmkit/list`
|
|
- `/api/gmkit/upload`
|
|
- `/api/copy-bestiary`
|
|
- `/api/narrate`
|
|
|
|
Static serving includes `/gmkit`, `/weapon-images`, and `/avatars`.
|
|
|
|
## Files To Treat Carefully
|
|
|
|
- Do not commit or churn runtime logs such as `database/backend.log` or
|
|
`database/server.log`.
|
|
- Do not overwrite database files, backups, generated JSON, PDFs, OCR output, or
|
|
imported rulebook data unless the user specifically asks for data work.
|
|
- `public/` and `database/` contain generated/reference JSON used by the app;
|
|
update paired files intentionally when scripts require it.
|
|
- There may be unrelated local changes. Inspect `git status --short` before
|
|
editing and avoid reverting user work.
|
|
|
|
## Documentation Notes
|
|
|
|
- `README.md` and `DEVELOPMENT_GUIDE.md` are useful, but several docs under
|
|
`docs/` and `CLAUDE.md` mention an older split `backend/` + `frontend/`
|
|
structure. The current live structure is root CRA frontend plus
|
|
`database/server.js` backend.
|
|
- When updating docs, prefer correcting stale structure references rather than
|
|
propagating them.
|