Commit Graph

227 Commits

Author SHA1 Message Date
Bastian Wagner
71f58bc1b6 feat(api): add CharacterVitalsService for anchored HP regeneration
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:32:18 +02:00
Bastian Wagner
7609c49899 feat(characters): expose renown on GET /api/characters/me instead of level/experience 2026-08-21 14:31:03 +02:00
Bastian Wagner
e5752c7ee9 fix(content): stop promising rewards the burned road can no longer drop
The location view's "Mögliche Belohnungen" preview listed Silber and
Erfahrung. This slice made both false:

- Experience no longer exists as a concept (spec 1).
- Every monster seeded on this road now rolls silverMin/silverMax = 0
  (design R7), so a kill yields no silver. Silver reaches the player
  through turn-ins instead.

The list's own comment states the rule it was breaking: the view may not
promise a drop the roll does not guarantee (spec 8). Equipment and
material stay -- the loot tables still back both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 14:30:53 +02:00
Bastian Wagner
ea26e4b844 feat(api): add HP regeneration rate constant 2026-08-21 14:29:35 +02:00
Bastian Wagner
40ff950390 test(combat): stop asserting the deleted experience reward contract
combat.service.spec.ts mocked CombatRewardService, so it never noticed
that design R8 removed CombatRewardDto.experience. Its mocks returned
{ experience, silver, items } and one assertion required experience: 8
back out -- encoding a contract the production DTO no longer has. A mock
lying about the real shape is worse than no test: it would keep passing
if the real DTO drifted further.

The rollback test deliberately wrote two independent fields so its
assertions could not pass vacuously ("rolled back" vs "never written").
Swapped the abolished experience for renown rather than dropping to a
single field, preserving that intent.

Monster level is untouched -- it is a monster stat this slice keeps, not
the abolished character level.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 14:27:20 +02:00
Bastian Wagner
19e08f0b16 feat(api): add hp_regen_since column for persistent HP regeneration
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 14:26:44 +02:00
Bastian Wagner
b55518b451 refactor(api): move Clock abstraction from travel to shared 2026-08-21 14:21:39 +02:00
Bastian Wagner
34a7bb9dbd fix(api): sweep every remaining test fixture off level/experience/requiredLevel/experienceReward 2026-08-21 14:19:12 +02:00
Bastian Wagner
2579b23a5c Add implementation plan for persistent HP and out-of-combat regeneration
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 14:12:38 +02:00
Bastian Wagner
8835671657 fix(monsters): finish deleting experienceReward, column included
Design ruling R7 abolishes XP as a concept and says the column goes with
it, but no task in the plan actually dropped it -- the plan only dropped
characters.experience and combat_rewards.experience_granted. Task 9
removed experienceReward from the seed literals, leaving
monster_definitions.experience_reward as a NOT NULL column with no
default that nothing supplies. The first monster insert against a real
database would have failed on a constraint violation.

No suite here could have caught it: none of them connect to Postgres.

Drops the column in the slice migration (which has never been run, so
amending it in place is correct rather than stacking a second one),
removes the entity field, and clears the three test fixtures that still
set it. silver_min/silver_max deliberately stay -- spec 15 keeps a
direct currency drop available as a lore-valid exception, and XP has no
such carve-out.

Also retargets the seed idempotency test off renown: 1, which is the
seed's own default and so could not distinguish "preserved" from
"reset to default".

NOTE ON SCOPE: this commit also absorbs a Prettier reformatting pass
that was already sitting uncommitted in the working tree, which is why
it touches ~59 files. That churn is purely cosmetic line-rewrapping --
verified by inspection, and the suite is green at 267/267 with the build
at exactly the 3 expected errors owned by Tasks 10 and 11. The repo is
not Prettier-clean at baseline (119 files still flagged), so this was a
partial run by an earlier step, not a deliberate repo-wide format.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 14:10:19 +02:00
Bastian Wagner
a75a670509 Add design doc for persistent character HP and out-of-combat regeneration
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 13:56:43 +02:00
Bastian Wagner
dce26e00ad feat(content): migrate ItemType, seed Räuberabzeichen/Grenzwacht/turn-ins, zero direct monster rewards 2026-08-21 13:49:49 +02:00
Bastian Wagner
dd90e05446 optik 2026-08-21 13:39:52 +02:00
Bastian Wagner
413fafd574 feat(equipment): remove the requiredLevel equipment gate - owned items are always equippable 2026-08-21 13:34:10 +02:00
Bastian Wagner
83eef5d9e5 docs(rewards): drop the stale XP reference from the no-partial-writes comment
The comment sat two lines above the deleted experience computation and
still named XP as something the guard protects. Only silver survives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:28:53 +02:00
Bastian Wagner
c9d9144b5f feat(rewards): remove classical XP from the combat reward pipeline 2026-08-21 13:23:46 +02:00
Bastian Wagner
6fb61792e7 test(turn-in): cover the unknown-character rejection path
TurnInService locks and validates the character row before touching
inventory, silver, or reputation, but no test exercised that branch.
Both sibling services in this slice (renown, reputation) have the
equivalent test; this closes the gap.

`characterNotFound` is shared from travel.errors and so is not a
TurnInDomainError -- assert on the wire contract (code + status) the
way reputation.service.spec.ts does for the same shared error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:19:17 +02:00
Bastian Wagner
4e3af9fe39 feat(turn-in): add TurnInService with atomic item/silver/reputation exchange and POST /api/turn-ins 2026-08-21 13:07:46 +02:00
Bastian Wagner
987242541d inventory 2026-08-21 12:52:44 +02:00
Bastian Wagner
321738496d fix(reputation): validate the character exists before granting reputation 2026-08-21 09:30:04 +02:00
Bastian Wagner
79d4e04172 feat(reputation): add ReputationService, rank resolver integration, and GET /api/reputation 2026-08-21 09:22:36 +02:00
Bastian Wagner
4c9397336f feat(renown): add RenownService with milestone completion and base-stat recomputation 2026-08-21 09:14:36 +02:00
Bastian Wagner
152499acfc Pair every API suite verification with a build
apps/api runs ts-jest with isolatedModules: true, which skips cross-file
type checking. Task 3 proved the gap concretely: the suite reported
233/234 green while npm run build reported 21 real errors across 6
files. Every full-suite step now runs test && build, with a Global
Constraints note explaining why the build half is not redundant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 09:07:37 +02:00
Bastian Wagner
4fa1923525 feat(renown): add Reputation/Renown/TurnIn entities and update Character/ItemDefinition/CombatReward 2026-08-21 09:03:37 +02:00
Bastian Wagner
3662029ec9 test(renown): pin the migration's backfill and constraint statement ordering
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:56:48 +02:00
Bastian Wagner
1a50e817f1 feat(renown): migrate Character/ItemDefinition schema and add Reputation/Renown/TurnIn tables
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UT2tLMQ2HfbWGkZyotocKm
2026-08-21 08:48:54 +02:00
Bastian Wagner
88b98aa605 feat(renown): add the Renown power-curve table and reputation-rank resolver 2026-08-21 08:42:29 +02:00
Bastian Wagner
e14f6dcbce Fix two plan defects found in SDD pre-flight scan
1. inventory.service.ts (API production code) surfaces requiredLevel in
   its response DTO. Task 3 deletes the entity column, so this would
   fail to compile and keep shipping a dead field. No task covered it:
   Task 10 swept only test fixtures, Task 12 only the web model. Folded
   into Task 10 as a new Step 0.

2. No web-side sweep task existed. Task 12's model changes break
   CharacterResponse/InventoryItem fixtures in app.spec.ts,
   world.store.spec.ts, and inventory.store.spec.ts, none of which
   Tasks 13-16 touch. Added Task 17 mirroring Task 10's sweep rule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 08:39:43 +02:00
Bastian Wagner
a376fb7128 Add implementation plan for Playable Slice 0.6.5 (Renown & Reputation)
16 tasks: pure-function power curve and rank resolver, one migration
covering Character/ItemDefinition/ItemType/CombatReward changes plus
five new tables, three new domain services (Renown, Reputation,
TurnIn), XP removal from the combat reward pipeline, requiredLevel
gate removal, seed content for Grenzwacht/Räuberabzeichen/turn-ins,
a fixture sweep, and the web-side Renown/Reputation surfaces.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 08:34:22 +02:00
Bastian Wagner
65dfb466cd Add design doc for Playable Slice 0.6.5 (Renown & Reputation Foundation)
Records every judgment call the spec left open — Renown/Reputation
data model, service signatures, migration strategy, combat reward
pipeline changes, and API/frontend surface — as an explicit, auditable
ruling with its cost if wrong, per instruction to implement this slice
without confirmation stops.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 08:21:14 +02:00
Bastian Wagner
62d6677298 fix(combat): show the potion heal immediately instead of folding it into the monster's reply 2026-08-20 23:54:02 +02:00
Bastian Wagner
1aac3416fa fix(combat): clear the monster's pending action once it is defeated 2026-08-20 23:10:47 +02:00
Bastian Wagner
e2f29d5eb6 fix(combat): keep the busy() re-entrancy guard, split the action-mapping test instead
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 22:38:52 +02:00
Bastian Wagner
0126d1dea1 feat(combat): add the five-action bar, telegraph banner, and generalized round animation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 22:19:13 +02:00
Bastian Wagner
b8d00278b8 feat(combat): generalize the web combat action and expose potions/monster intent 2026-08-20 22:01:28 +02:00
Bastian Wagner
c7b9601eb4 feat(combat): validate potions, persist telegraph state, and expose both on the combat DTO
Also updates the pre-existing exact-equality playerState assertion in
combat-equipment-integration.spec.ts, which broke from the new
potionsRemaining field but wasn't listed in the task brief's file scope.
2026-08-20 21:48:51 +02:00
Bastian Wagner
43d2085d2c feat(combat): add the COMBAT_NO_POTIONS_REMAINING domain error 2026-08-20 21:40:56 +02:00
Bastian Wagner
6eb0f21360 test(combat): cover DEFEND mitigating a resolving Heavy Attack 2026-08-20 21:37:36 +02:00
Bastian Wagner
b3dac8f61c feat(combat): implement HEAVY_STRIKE, SHIELD_BASH, DEFEND, POTION, and monster telegraphing 2026-08-20 21:27:12 +02:00
Bastian Wagner
fc1873e41f feat(combat): model monster intent and potion count in combat state types 2026-08-20 21:21:08 +02:00
Bastian Wagner
922c12f20f feat(combat): migrate combat_event_type_enum for Slice 0.6 event types 2026-08-20 21:17:37 +02:00
Bastian Wagner
6f1afaf5a3 feat(combat): add the Slice 0.6 action and event-type enum members 2026-08-20 21:12:46 +02:00
Bastian Wagner
eed247d318 feat(combat): support a damage multiplier in calculateDamage 2026-08-20 21:06:54 +02:00
Bastian Wagner
96d04d8ba3 Fix plan defect found in SDD pre-flight scan: Task 8 fixture patch
hunt-page.component.spec.ts and resume-combat.spec.ts each build a
direct type-annotated Combat literal that the new required
CombatPlayer/CombatMonster fields would break at compile time.
Verified with an isolated tsc --strict probe, and used the same probe
to confirm the combat.service.spec.ts `as Combat` fixtures do NOT
break (structural widening through the type assertion), so no change
needed there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 21:04:19 +02:00
Bastian Wagner
67df86a818 Ignore .worktrees/ for isolated feature-branch workspaces
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 20:52:36 +02:00
Bastian Wagner
9d396b7d96 Add implementation plan for Playable Slice 0.6 (Full First Combat)
Covers the engine rewrite for HEAVY_STRIKE/SHIELD_BASH/DEFEND/POTION,
deterministic monster telegraphing/interrupt, the DB migration for the
new combat event types, and the web action bar + telegraph banner.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 20:51:17 +02:00
Bastian Wagner
49a0008a2b Merge branch 'worktree-playable-slice-0.5-first-upgrade'
# Conflicts:
#	apps/web/src/app/core/api/game-api.service.ts
#	apps/web/src/app/features/combat/combat-page/combat-page.component.html
#	apps/web/src/app/features/combat/combat-page/combat-page.component.scss
#	apps/web/src/app/features/combat/combat-page/combat-page.component.spec.ts
#	apps/web/src/app/features/combat/combat-page/combat-page.component.ts
2026-08-20 19:42:10 +02:00
Bastian Wagner
0ce3b420e6 fix: address final-review findings (TopBar hydration, snapshot test, armor doc, inventory refresh test)
Fixes 4 Important findings from the final whole-branch review:
- /inventory never called WorldStore.load(), leaving the TopBar stuck on
  "loading" and characterLevel() silently defaulting to 1 for any character
  above level 1. Mirrors the same guard already used in HuntPageComponent.
- The combat/equipment snapshot-immutability integration test asserted only
  status/round, never the actual playerState snapshot the whole test claims
  to prove is untouched after a post-fight equip.
- Documented (comment only, no behavior change) that the demo character's
  armor dropping from the old hardcoded 6 to 0 is an intentional,
  spec-sanctioned tradeoff (Slice 0.5 spec Section19), not a bug.
- inventory.store.spec.ts's equip test used an identical inventory fixture
  before and after equip(), so a regression dropping the post-equip
  inventory re-fetch would still have passed. Now asserts the refetched
  fixture is actually reflected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 18:44:39 +02:00
Bastian Wagner
7f031ac1ce test(web): update app.spec.ts for the now-enabled Inventar nav button 2026-08-20 18:15:30 +02:00
Bastian Wagner
b1968da754 feat(web): add Inventar öffnen button to the victory screen 2026-08-20 18:04:13 +02:00