docs: record the Slice 0.9 quest system and its deviations
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1354,13 +1354,22 @@ Erster NPC: **Borin, Quartermaster** an `south-gate` (Graufurt) mit
|
|||||||
DIALOGUE + MERCHANT + RESOURCE_EXCHANGE gleichzeitig — der Kompositionsfall
|
DIALOGUE + MERCHANT + RESOURCE_EXCHANGE gleichzeitig — der Kompositionsfall
|
||||||
aus §2/§26 in echt.
|
aus §2/§26 in echt.
|
||||||
|
|
||||||
## Abweichung 1 — kein `NpcQuestAssignment`
|
## Abweichung 1 — kein `NpcQuestAssignment` — **aufgelöst in Slice 0.9**
|
||||||
|
|
||||||
§34 listet es im V1-Scope, aber es gibt noch kein Questsystem (Slice 0.9).
|
§34 listet es im V1-Scope, aber es gab in Slice 0.8 noch kein Questsystem.
|
||||||
Eine Tabelle mit Fremdschlüssel auf eine nicht existierende `quests`-Tabelle
|
Eine Tabelle mit Fremdschlüssel auf eine nicht existierende `quests`-Tabelle
|
||||||
ist nicht baubar, und ein `questKey`-String ohne Validierung wäre spekulative
|
ist nicht baubar, und ein `questKey`-String ohne Validierung wäre spekulative
|
||||||
Architektur (AGENTS §1.7). Nachzuholen mit Slice 0.9, zusammen mit den
|
Architektur (AGENTS §1.7).
|
||||||
Dialog-Actions `START_QUEST` / `COMPLETE_QUEST`.
|
|
||||||
|
Slice 0.9 hat das nachgeholt: `NpcQuestAssignment` liegt unter
|
||||||
|
`apps/api/src/quests/entities/npc-quest-assignment.entity.ts` und trägt die
|
||||||
|
Rollen `OFFER` / `TURN_IN` / `PROGRESS` aus §14. Der Unique-Index umfasst die
|
||||||
|
Rolle mit, damit derselbe NPC eine Quest sowohl vergeben als auch annehmen
|
||||||
|
kann — genau der Fall aus §14, den die erste Questkette benutzt: der South
|
||||||
|
Gate Warden vergibt und nimmt an, Borin steht als `PROGRESS` dazwischen.
|
||||||
|
|
||||||
|
Die Dialog-Actions `START_QUEST` / `COMPLETE_QUEST` bleiben offen, siehe
|
||||||
|
Abweichung 4.
|
||||||
|
|
||||||
## Abweichung 2 — kein `NpcDialogueProfile`
|
## Abweichung 2 — kein `NpcDialogueProfile`
|
||||||
|
|
||||||
@@ -1372,14 +1381,52 @@ neu zu schreiben.
|
|||||||
|
|
||||||
## Abweichung 3 — Conditions, die (noch) nichts beantworten kann
|
## Abweichung 3 — Conditions, die (noch) nichts beantworten kann
|
||||||
|
|
||||||
`GameConditionType` enthält die vollständige V1-Liste aus §19, aber nur
|
`GameConditionType` enthält die vollständige V1-Liste aus §19, aber nicht jeder
|
||||||
`REGION_REPUTATION`, `WORLD_RENOWN`, `FLAG_SET` und `HAS_ITEM` sind
|
Typ hat ein System dahinter.
|
||||||
auswertbar. `QUEST_ACTIVE`, `QUEST_COMPLETED`, `BOSS_DEFEATED` und
|
|
||||||
`LOCATION_DISCOVERED` haben noch kein System dahinter.
|
|
||||||
|
|
||||||
Sie werten **fail-closed** aus, also immer "nicht erfüllt". Für ein Gate ist
|
Seit Slice 0.9 auswertbar: `REGION_REPUTATION`, `WORLD_RENOWN`, `FLAG_SET`,
|
||||||
die sichere Richtung eines Fehlers zu, nicht offen — ein Quest-Gate darf
|
`HAS_ITEM`, `QUEST_ACTIVE`, `QUEST_COMPLETED`. Offen bleiben `BOSS_DEFEATED`
|
||||||
niemals aufgehen, nur weil es keine Quests gibt.
|
(Slice 0.11) und `LOCATION_DISCOVERED` (wird pro Charakter nicht getrackt).
|
||||||
|
|
||||||
|
Die beiden Quest-Typen werten boolesch aus wie `FLAG_SET`, nicht numerisch:
|
||||||
|
eine Quest läuft oder nicht, `actual` bleibt `null`. `value: false` ist die Art,
|
||||||
|
wie Content die Verneinung ausdrückt — die Angebotszeile des Wardens braucht
|
||||||
|
"noch nicht begonnen und noch nicht abgeschlossen", ohne dass die
|
||||||
|
Condition-Sprache ein NOT bekommt.
|
||||||
|
|
||||||
|
Die verbleibenden Typen werten **fail-closed** aus, also immer "nicht erfüllt".
|
||||||
|
Für ein Gate ist die sichere Richtung eines Fehlers zu, nicht offen.
|
||||||
|
|
||||||
|
## Abweichung 4 — Questschritte laufen nicht über Dialog-Actions
|
||||||
|
|
||||||
|
`DialogueActionType` enthält `START_QUEST` und `COMPLETE_QUEST`, aber beide
|
||||||
|
bleiben auch mit dem Questsystem aus Slice 0.9 wirkungslos.
|
||||||
|
|
||||||
|
Sie auszuführen bräuchte zwei Dinge, die es nicht gibt: einen Endpoint, über
|
||||||
|
den der Client eine Dialog-Response *auswählt*, und einen Action-Executor
|
||||||
|
dahinter. Playable Slice 0.9 §10 verlangt ausdrücklich einen
|
||||||
|
schrittbasierten Questautomaten und verbietet eine verzweigende
|
||||||
|
Narrative-Engine — und ein Response-Endpoint plus Executor wäre genau deren
|
||||||
|
Anfang, für eine Kette mit fünf Schritten.
|
||||||
|
|
||||||
|
Stattdessen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
POST /api/npcs/:npcKey/quests/:questKey/accept
|
||||||
|
POST /api/npcs/:npcKey/quests/:questKey/advance
|
||||||
|
```
|
||||||
|
|
||||||
|
Keine der beiden Routen nimmt einen Body. Welcher Schritt gerade dran ist, was
|
||||||
|
er vergibt und was er verbraucht, entscheidet der Server (AGENTS §5). Der Satz,
|
||||||
|
den der NPC zu einem Schritt sagt, ist Content auf dem `QuestObjective`
|
||||||
|
(`npc_line`) und kommt mit der Antwort zurück.
|
||||||
|
|
||||||
|
Nachzuholen wäre das, sobald ein NPC wirklich verzweigende Antworten braucht:
|
||||||
|
dann ein Response-Auswahl-Endpoint, ein Executor über
|
||||||
|
`SUPPORTED_DIALOGUE_ACTIONS`, und die Questschritte können auf Dialog-Actions
|
||||||
|
umziehen, ohne dass die Questtabellen sich ändern.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Offene Designfrage — World Renown im Tausch
|
## Offene Designfrage — World Renown im Tausch
|
||||||
|
|
||||||
@@ -1398,3 +1445,40 @@ anzufassen.
|
|||||||
|
|
||||||
Falls Renown später doch als Punktwährung gedacht ist, muss das zuerst in
|
Falls Renown später doch als Punktwährung gedacht ist, muss das zuerst in
|
||||||
0.6.5 geändert werden — nicht hier.
|
0.6.5 geändert werden — nicht hier.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 41. Implementierungsstand (Slice 0.9)
|
||||||
|
|
||||||
|
```text
|
||||||
|
QuestDefinition / QuestObjective apps/api/src/quests/entities/
|
||||||
|
NpcQuestAssignment Rollen aus §14
|
||||||
|
CharacterQuest Player-State, ein Row pro Charakter/Quest
|
||||||
|
QuestProgressService leitet den aktiven Schritt ab (lesend)
|
||||||
|
QuestService accept / advance, Effekte, Belohnungen
|
||||||
|
QuestController / NpcQuestController apps/api/src/quests/quest.controller.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Erste Questkette: **Trouble Beyond the Gate**, vergeben und angenommen von
|
||||||
|
Halvik am Südtor, mit Borin als Zwischenschritt — der Mehr-NPC-Fall aus §14
|
||||||
|
in echt.
|
||||||
|
|
||||||
|
Zwei Module statt einem: `QuestProgressModule` enthält nur den lesenden Teil,
|
||||||
|
weil `NpcService` Questmarker braucht und `QuestService` umgekehrt `NpcService`
|
||||||
|
für die Erreichbarkeitsprüfung. Der Schnitt hält den Modulgraphen zyklenfrei,
|
||||||
|
ohne `forwardRef`.
|
||||||
|
|
||||||
|
Es gibt bewusst **keine** Tabelle für Objective-Fortschritt. Slice 0.9 §11
|
||||||
|
verlangt, dass Sammelschritte ihren Stand aus dem aktuellen Besitz ableiten;
|
||||||
|
genau das macht `QuestProgressService`, und dadurch fallen die Softlock-Fälle
|
||||||
|
aus §11 von selbst weg, statt einzeln behandelt zu werden.
|
||||||
|
|
||||||
|
Was ein Schritt *tut*, steht als Content auf dem `QuestObjective`
|
||||||
|
(`sets_flag_key` / `sets_flag_npc_key`, `grants_loot_bag_key`,
|
||||||
|
`consume_on_complete`, `advance_when_blocked`). `QuestService` wendet an, was
|
||||||
|
es vorfindet, und verzweigt nirgends auf einen Questkey (AGENTS §9).
|
||||||
|
|
||||||
|
Markerregeln für die Ortsansicht (§24, Slice 0.9 §12): höchstens ein
|
||||||
|
Questmarker pro NPC, Reihenfolge `QUEST_TURN_IN` > `QUEST_AVAILABLE` >
|
||||||
|
`QUEST_IN_PROGRESS`. Halvik hält für dieselbe Quest zwei Rollen; ohne
|
||||||
|
Vorrangregel trüge er zwei Symbole und keines würde etwas aussagen.
|
||||||
|
|||||||
@@ -314,9 +314,85 @@ Hide Capacity: 5
|
|||||||
- [ ] Quest grants no XP.
|
- [ ] Quest grants no XP.
|
||||||
- [ ] All dialogue/UI text is English.
|
- [ ] All dialogue/UI text is English.
|
||||||
|
|
||||||
|
### Verification status
|
||||||
|
|
||||||
|
Every criterion above is covered by automated tests: the quest chain in
|
||||||
|
`quest-state.spec.ts` and `quest.service.spec.ts`, the content in
|
||||||
|
`vertical-slice.seed.spec.ts`, the markers in `npc.service.spec.ts`, and the
|
||||||
|
three UI requirements of §12 in the web specs for the journal, the NPC screen
|
||||||
|
and the location hotspots.
|
||||||
|
|
||||||
|
The boxes stay unticked because two things have not been run: the migration and
|
||||||
|
seed against a real PostgreSQL database, and a hand-played pass through the
|
||||||
|
chain in the running app. Neither was possible in the environment this slice was
|
||||||
|
built in — no database was reachable. Do both before ticking, following the
|
||||||
|
walkthrough in the implementation plan
|
||||||
|
(`docs/superpowers/plans/2026-08-22-first-quest-and-bag-tutorial.md`, Task 13).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15. Out of Scope
|
## 15. Implementation Decisions
|
||||||
|
|
||||||
|
Recorded here rather than only in the implementation plan, so the next slice
|
||||||
|
reads them from the specification.
|
||||||
|
|
||||||
|
### D1 — The Basic Hide Bag is granted, not sold
|
||||||
|
|
||||||
|
§6 has Borin say "Take this" while also describing the Slice 0.8.5 offer, which
|
||||||
|
costs 35 Silver. A player standing at that step has close to none, so the
|
||||||
|
purchase path alone would stall the chain.
|
||||||
|
|
||||||
|
Borin's quest step therefore hands the bag over directly and idempotently. The
|
||||||
|
referral flag is still written to the character's Borin state, so the 0.8.5
|
||||||
|
`bypassConditions` gate opens the offer as well — a visible consequence, and a
|
||||||
|
way back to a bag that is somehow lost. Nothing about reputation changes.
|
||||||
|
|
||||||
|
### D2 — No World Renown milestone
|
||||||
|
|
||||||
|
§9 lists one as optional. The demo character sits at Renown 1 and the first
|
||||||
|
trade-in takes them to 2; a quest milestone would reach 3 and unlock Borin's
|
||||||
|
Bandit Blade, which Slice 0.8.5 deliberately placed out of reach until Slice
|
||||||
|
0.11. The quest pays regional reputation instead: **+10 Border Watch**.
|
||||||
|
|
||||||
|
### D3 — No Silver reward
|
||||||
|
|
||||||
|
§9 warns against a Silver reward that undermines the merchant trade loop, and
|
||||||
|
names the bag and system knowledge as the point of the chain. `rewardSilver` is
|
||||||
|
a content column set to 0, so retuning it later is a seed change.
|
||||||
|
|
||||||
|
### D4 — Quest steps use their own endpoints
|
||||||
|
|
||||||
|
NPC spec §40 asked Slice 0.9 to also wire the `START_QUEST` / `COMPLETE_QUEST`
|
||||||
|
dialogue actions. There is no dialogue-response endpoint at all, and building
|
||||||
|
one plus an action executor is the branching narrative engine §10 rules out.
|
||||||
|
|
||||||
|
Steps run through `POST /api/npcs/:npcKey/quests/:questKey/{accept,advance}`.
|
||||||
|
Neither takes a body — which step is current, what it grants and what it
|
||||||
|
consumes are the server's to decide. The line an NPC speaks for a step is
|
||||||
|
content on the objective. Recorded as Abweichung 4 in the NPC specification.
|
||||||
|
|
||||||
|
### D5 — The demo character starts with no loot bag
|
||||||
|
|
||||||
|
The vertical-slice seed handed over a free Basic Hide Bag as a stopgap between
|
||||||
|
Slices 0.8.5 and 0.9, with a note to remove it once a quest could grant one.
|
||||||
|
That is done: the bagless HIDE capacity of 1 is the whole premise of §4. The
|
||||||
|
migration also clears that one row for the demo character on databases seeded
|
||||||
|
before this change.
|
||||||
|
|
||||||
|
### Addition — a hint for the second pelt hunt
|
||||||
|
|
||||||
|
Not in the specification, but the same courtesy §4 asks for. The Hide Bag holds
|
||||||
|
five of *any* hide, so Tough Hides can crowd out the fifth Ashen Pelt. That step
|
||||||
|
must not give up the way the first one does — it is meant to be finished (§7) —
|
||||||
|
so it carries a hint instead:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Your hide bag is full of other goods. Trade some to Borin to make room for pelts.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Out of Scope
|
||||||
|
|
||||||
Do not implement:
|
Do not implement:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user