This commit is contained in:
Bastian Wagner
2026-08-22 16:41:47 +02:00
parent dfa62fd152
commit 081c9f83f9
137 changed files with 11594 additions and 1302 deletions

View File

@@ -1331,3 +1331,70 @@ Eine zentrale Condition Engine verbindet:
Der zentrale Grundsatz lautet:
> **NPCs sind datengetriebene Charaktere mit kombinierbaren Interaktionen keine voneinander getrennten Spezialklassen.**
---
# 40. Implementierungsstand (Slice 0.8)
Der V1-Scope aus §34 ist umgesetzt, mit drei bewussten Abweichungen. Sie sind
hier festgehalten statt still aufgelöst zu werden.
## Umgesetzt
```text
NpcDefinition apps/api/src/npcs/entities/
DialogueNode priorisiert, mit Conditions (§11)
CharacterNpcState vorbereitet, genutzt für first-met + Flags (§7, §35)
NpcShop / ShopOffer apps/api/src/shops/
NpcExchangeProfile / ExchangeRule apps/api/src/exchanges/
GameConditionService apps/api/src/conditions/
```
Erster NPC: **Borin, Quartermaster** an `south-gate` (Graufurt) mit
DIALOGUE + MERCHANT + RESOURCE_EXCHANGE gleichzeitig — der Kompositionsfall
aus §2/§26 in echt.
## Abweichung 1 — kein `NpcQuestAssignment`
§34 listet es im V1-Scope, aber es gibt noch kein Questsystem (Slice 0.9).
Eine Tabelle mit Fremdschlüssel auf eine nicht existierende `quests`-Tabelle
ist nicht baubar, und ein `questKey`-String ohne Validierung wäre spekulative
Architektur (AGENTS §1.7). Nachzuholen mit Slice 0.9, zusammen mit den
Dialog-Actions `START_QUEST` / `COMPLETE_QUEST`.
## Abweichung 2 — kein `NpcDialogueProfile`
§10 skizziert `NpcDialogueProfile` als Zwischenebene zwischen NPC und
`DialogueNode`. §34 verlangt dagegen nur "priorisierte DialogNodes +
Conditions", und das Profil hätte in V1 keine eigenen Felder. Nodes hängen
deshalb direkt am NPC. Ein Profil lässt sich später einziehen, ohne die Nodes
neu zu schreiben.
## Abweichung 3 — Conditions, die (noch) nichts beantworten kann
`GameConditionType` enthält die vollständige V1-Liste aus §19, aber nur
`REGION_REPUTATION`, `WORLD_RENOWN`, `FLAG_SET` und `HAS_ITEM` sind
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
die sichere Richtung eines Fehlers zu, nicht offen — ein Quest-Gate darf
niemals aufgehen, nur weil es keine Quests gibt.
## Offene Designfrage — World Renown im Tausch
Slice 0.8 §4/§9 skizziert `worldRenownPerUnit`. Das ist mit dem
implementierten Renown-System nicht verträglich: Renown ist ein Rang 115,
der bei jeder Änderung baseHp/baseAttack aus einer festen Kurve neu setzt
(Slice 0.6.5 §4). Renown pro Fell würde einen Spieler in wenigen Trips ans
Statmaximum bringen.
`ExchangeRule.renownMilestoneKey` verweist deshalb auf einen
`RenownMilestoneDefinition` — die "batch rule"-Variante aus 0.8 §4, und
deckungsgleich mit 0.6.5 §6, das "first meaningful trophy returned" als
Renown-2-Meilenstein nennt. Nicht wiederholbar: der erste Tausch löst ihn
aus, jeder weitere zahlt weiter Silber und Reputation, ohne den Rang
anzufassen.
Falls Renown später doch als Punktwährung gedacht ist, muss das zuerst in
0.6.5 geändert werden — nicht hier.