Commit Graph

38 Commits

Author SHA1 Message Date
Bastian Wagner
07984110bf feat(loot): add LootService with deterministic independent rolls
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 00:05:59 +02:00
Bastian Wagner
c58a46b7d9 feat(loot): seed tier-1 items and the ash rat and road bandit loot tables
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:59:08 +02:00
Bastian Wagner
fe130c597e feat(loot): add loot and reward migration
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:39:17 +02:00
Bastian Wagner
af9d422e8b feat(loot): add item, loot table, and combat reward entities
Declares every new TypeORM entity Slice 0.4 needs (ItemDefinition,
CharacterItem, LootTable, LootTableEntry, CombatReward, CombatRewardItem)
plus the ItemType/EquipmentSlot/ItemRarity enums, and adds the two columns
existing entities gain: Character.silver and MonsterDefinition.lootTableId.
No migration SQL or service logic yet - just schema declarations backed by
a metadata-driven schema spec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:29:30 +02:00
Bastian Wagner
a5f7772a6d refactor(api): move RandomSource to shared and add rollInclusive
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:19:05 +02:00
Bastian Wagner
f33b0c0e4a feat(combat): rejoin the running combat instead of dead-ending
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.
2026-08-19 22:45:53 +02:00
Bastian Wagner
18f30a1ba1 test(combat): cover CombatService LOST persistence
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.
2026-08-19 21:42:01 +02:00
Bastian Wagner
bb42195ef5 feat(combat): wire CombatModule into the application
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.
2026-08-19 16:19:06 +02:00
Bastian Wagner
4831dc20b0 feat(combat): add HTTP controllers for starting, reading, and acting on combats
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 16:09:08 +02:00
Bastian Wagner
498349b5eb feat(combat): add CombatService orchestration and persistence
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.
2026-08-19 16:01:17 +02:00
Bastian Wagner
90f6a8cd78 feat(combat): add combat domain errors 2026-08-19 15:50:52 +02:00
Bastian Wagner
bd8a00227f feat(characters): add temporary combat-stats stand-in for equipment 2026-08-19 15:48:11 +02:00
Bastian Wagner
edae1af39a feat(combat): add deterministic combat engine for ATTACK resolution 2026-08-19 15:43:24 +02:00
Bastian Wagner
6cb4d02613 feat(combat): add deterministic damage formula 2026-08-19 15:39:17 +02:00
Bastian Wagner
47931ff717 feat(combat): add CreateCombatSystem migration 2026-08-19 15:34:46 +02:00
Bastian Wagner
68edc04ed6 feat(combat): add combat domain enums, entities, and encounter consumption field 2026-08-19 15:27:05 +02:00
Bastian Wagner
137a18f4e7 style: fix prettier formatting drift in two API files
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.
2026-08-19 14:33:41 +02:00
Bastian Wagner
bb307da0ff feat: wire HuntingController/HuntingModule and enrich current-location with monster pool
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.
2026-08-19 12:53:09 +02:00
Bastian Wagner
568478dcd2 feat: add HuntingService core domain logic for first-hunt slice
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>
2026-08-19 12:24:46 +02:00
Bastian Wagner
9423c28bd8 feat: seed Aschenratte and Straßenräuber for Verbrannte Straße
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>
2026-08-19 12:08:26 +02:00
Bastian Wagner
e04827cd5a feat: add hunting system schema migration
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>
2026-08-19 11:55:21 +02:00
Bastian Wagner
0c2f079a6e feat: add hunt/monster domain entities and pure danger-rating helper
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>
2026-08-19 11:41:09 +02:00
Bastian Wagner
d09476ba41 test: cover the successful travel start happy path in the e2e smoke suite
The DB-gated e2e suite covered health, seeded reads, and the arrivesAt
whitelist rejection, but never asserted that a valid POST /api/travel
actually transitions to TRAVELLING, that a concurrent second start is
rejected with 409/TRAVEL_ALREADY_ACTIVE, or that a travel completes and
moves the character. Added one test covering all three plus GET
/api/world/current-location reflecting the move, and restores the demo
character to its original location afterward so the suite stays safely
re-runnable.
2026-08-19 10:50:30 +02:00
Bastian Wagner
2f53e5ba80 docs: add visible slice local workflow
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>
2026-08-19 09:41:16 +02:00
Bastian Wagner
6c35c18018 bilder 2026-08-19 09:06:10 +02:00
Bastian Wagner
1e2bfe6e4b feat: render interactive ashen fields world 2026-08-19 08:25:42 +02:00
Bastian Wagner
c641168c7d feat: expose current world location 2026-08-18 20:57:30 +02:00
Bastian Wagner
d06f05047b feat: add server authoritative travel flow 2026-08-18 20:30:09 +02:00
Bastian Wagner
e9b111daf8 feat: expose health and demo character APIs 2026-08-18 20:00:40 +02:00
Bastian Wagner
0615bb1841 fix: seed character at resolved south gate 2026-08-18 19:45:05 +02:00
Bastian Wagner
c35859a4de fix: preserve seeded location identities 2026-08-18 19:40:13 +02:00
Bastian Wagner
067134b684 feat: seed demo character and first locations 2026-08-18 19:30:31 +02:00
Bastian Wagner
a97152cded test: assert migration execution order 2026-08-18 19:17:57 +02:00
Bastian Wagner
21f701e904 fix: harden world travel migration 2026-08-18 19:03:21 +02:00
Bastian Wagner
492765d8ca feat: add world travel database schema 2026-08-18 18:27:21 +02:00
Bastian Wagner
1210ba2d15 fix: prefix API routes 2026-08-18 18:13:48 +02:00
Bastian Wagner
2903a0d670 chore: configure angular and postgres foundation 2026-08-18 18:02:40 +02:00
Bastian Wagner
9e92731645 chore: bootstrap ashen realms monorepo 2026-08-18 17:01:21 +02:00