Attacking while a combat is already active returned COMBAT_ALREADY_ACTIVE
and left the hunt page showing an error the player could not act on, with
no way back into the fight they were already in.
Add GET /api/combats/active so the client can resolve that combat, and
have the hunt page navigate into it when an attack is rejected for this
reason. CombatStore now also exposes the error code so callers can tell
this case apart from a genuinely failed attack.
CombatService only had engine-level coverage of the LOST transition.
Add service-level tests that force a loss (character.baseHp: 1) and
assert the persisted status, completedAt, further-action rejection,
and getCombat refresh behavior for a LOST combat.
Provide and export CharacterCombatStatsService from CharactersModule,
create CombatModule (registering the combat entities, controllers,
CombatService and CombatEngineService, and importing TravelModule and
CharactersModule), and register CombatModule in AppModule so the three
combat endpoints (attack, get combat, post action) are reachable from
the running app.
Wires the pure combat engine, character combat stats, and domain errors
into a transactional service that validates the HuntEncounter boundary,
snapshots stats into a new Combat row, and persists engine results.
vertical-slice.seed.ts and danger-rating.spec.ts had line-wrapping
that no longer matched prettier's output, which a CI prettier --check
would flag. Formatting only, no logic change.
Registers HuntingModule (POST /api/hunts) into the DI graph alongside its
new entities, and adds possibleMonsters (enabled LocationMonster pool,
weight-descending, empty when hunting is disabled) to
WorldService.getCurrentLocation. Also updates the pre-existing
DB-less app.e2e-spec.ts to override HuntingModule the same way the other
feature modules already are, since it now needs a real DataSource.
Adds startHunt's server-authoritative flow: complete due travel, verify
the location allows hunting, weighted-random-roll exactly 3 encounters
from the location's enabled monster pool inside a locked transaction
that supersedes any prior active hunt, and compute a danger rating per
encounter from the rolled monster's own stats. Mirrors TravelService's
transaction/locking pattern and error conventions.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the two starter monster definitions and their location-monster
mapping (weights 70/30) to the vertical-slice seed, following the
same findOneBy/update-or-insert pattern used for locations, plus an
upsert on (locationId, monsterId) for the mapping. Copies the source
artwork into the served images/monsters directory and extends the
seed spec harness to cover both idempotent inserts.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Adds the migration and metadata spec for the hunting schema (monster
definitions, location monster spawn tables, hunts, and hunt encounters)
required by Playable Slice 0.2. Mirrors the raw-SQL style of the visible
vertical slice migration; explicitly asserts the CASCADE-vs-RESTRICT
deviation on HuntEncounter's relation to Hunt.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Adds Task 1 of Playable Slice 0.2: pure entity/enum/helper definitions
for the Hunt/Encounter system (MonsterDefinition, LocationMonster,
Hunt, HuntEncounter, EncounterType, HuntStatus, RandomSource,
DangerRating). No DB migration, module wiring, or seed data yet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Document the migration/seed/API/web workflow in a root README, add an
API e2e smoke test that always checks /api/health and additionally
exercises the real DatabaseModule/seeded data plus the arrivesAt
validation rejection when DATABASE_URL is available, and add a
`test:e2e` root script.
Also fix `.env` loading so the documented root-level `.env` is actually
found: `main.ts` never loaded dotenv at all, and `data-source.ts`
loaded it relative to `process.cwd()`, which is `apps/api` (not the
repo root) whenever npm runs a `--workspace` script. Both now resolve
the repo-root `.env` explicitly. Also narrowed the CLI migrations glob
to numeric-prefixed files so it no longer tries to load the colocated
`*.migration.spec.ts` as a migration.
Verified end-to-end against a real PostgreSQL instance: migrate, seed
twice (idempotent), start the API, and exercise every documented route
including a rejected POST /api/travel body containing arrivesAt.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>