# Ashen Realms – NPC System Specification V1 ## Zweck dieser Dokumentation Dieses Dokument definiert das NPC-System von **Ashen Realms** für den ersten erweiterten Vertical Slice und die darauf aufbauende Spielarchitektur. Es beschreibt: - das gemeinsame NPC-Grundmodell - die Trennung zwischen NPC-Definition und spielerspezifischem Zustand - NPC-Fähigkeiten statt Klassenvererbung - Händler, Questgeber und gemischte Rollen - Dialoge und Dialogbedingungen - Ruf- und Freischaltbedingungen - Materialtausch und Verkaufslogik - Anbindung des Taschensystems - wiederverwendbare Conditions - technische Datenmodelle und Services - den empfohlenen V1-Scope Das System folgt den bestehenden Grundsätzen von Ashen Realms: - Content ist datengetrieben. - Spiellogik ist serverautoritativ. - Content-Definitionen und Player-State bleiben getrennt. - NPCs sollen Teil der Welt sein und nicht nur UI-Schaltflächen mit Portrait. - Neue Spezialfälle sollen möglichst über wiederverwendbare Bausteine modelliert werden. --- # 1. Designziel NPCs sind zentrale Interaktionspunkte der Welt. Sie können unter anderem: - Quests anbieten - Quests abschließen - Gegenstände verkaufen - Materialien ankaufen oder eintauschen - Ruf prüfen - besondere Waren freischalten - Taschen verkaufen oder vergeben - Informationen geben - Story und Lore vermitteln - Reisen oder andere Dienste anbieten Ein NPC darf mehrere dieser Funktionen gleichzeitig besitzen. Beispiel: **Elyra, die verbannte Jägerin** kann gleichzeitig: - Story-NPC sein - Jagdquests anbieten - Materialien annehmen - Dämmerwald-Ruf berücksichtigen - Gebietsausrüstung verkaufen - besondere Angebote nach Quests freischalten Grundsatz: > **NPCs sind Personen mit mehreren Fähigkeiten – keine voneinander getrennten NPC-Klassen.** --- # 2. Keine klassische NPC-Vererbung Für das NPC-System wird ausdrücklich keine tiefe Klassenhierarchie verwendet. Nicht vorgesehen: ```ts class Npc {} class MerchantNpc extends Npc {} class QuestNpc extends Npc {} class QuestMerchantNpc extends MerchantNpc {} ``` Dieses Modell skaliert schlecht, sobald ein NPC mehrere Rollen kombiniert. Stattdessen verwendet Ashen Realms: > **Composition / Capability-based NPC design** Ein NPC besitzt eine gemeinsame Identität und kann über verknüpfte Daten verschiedene Fähigkeiten erhalten. Beispiel: ```text NPC ├── Dialogue ├── Quest Assignments ├── Shop ├── Resource Exchange ├── Reputation Requirements └── Player-specific State ``` --- # 3. NPC Definition Jeder NPC besitzt eine persistierte Content-Definition. Vorgeschlagenes Modell: ```ts NpcDefinition { id: string; key: string; name: string; title?: string; description?: string; locationId: string; factionKey?: string; portraitPath: string; artworkPath?: string; dialogueProfileId?: string; enabled: boolean; createdAt: Date; updatedAt: Date; } ``` ## Pflichtfelder | Feld | Bedeutung | |---|---| | `id` | interne UUID | | `key` | stabiler fachlicher Key | | `name` | sichtbarer NPC-Name | | `locationId` | aktueller Standort | | `portraitPath` | Portrait für UI und Dialog | | `enabled` | NPC aktiv/inaktiv | ## Optionale Felder | Feld | Bedeutung | |---|---| | `title` | z. B. „Händler der Grenzwacht“ | | `description` | kurze Beschreibung | | `factionKey` | Fraktionszugehörigkeit | | `artworkPath` | größeres Artwork für lokale Ansicht | | `dialogueProfileId` | Dialogdefinition | --- # 4. Stabiler NPC-Key Jeder NPC benötigt einen stabilen fachlichen Key. Beispiele: ```text captain-garrick merchant-borin elyra-exiled-huntress brother-caelan ``` Dieser Key darf in: - Seeds - Quests - Dialogbedingungen - Shopbedingungen - Flags - Tests verwendet werden. Interne UUIDs sollen nicht zur fachlichen Referenzierung von Content benutzt werden. --- # 5. NPC Capabilities NPC-Fähigkeiten werden nicht über Vererbung bestimmt. Für V1 und spätere Erweiterungen sind folgende Capabilities vorgesehen: | Capability | Funktion | |---|---| | `DIALOGUE` | NPC kann angesprochen werden | | `QUEST_GIVER` | bietet Quests an | | `QUEST_TURN_IN` | nimmt Quests entgegen | | `MERCHANT` | besitzt normalen Shop | | `REPUTATION_MERCHANT` | Angebote hängen von Ruf ab | | `RESOURCE_EXCHANGE` | tauscht Materialien gegen Belohnungen | | `BAG_MERCHANT` | verkauft oder vergibt Taschen | | `LORE` | bietet Story-/Weltinformationen | | `TRAINER` | spätere Skills/Fähigkeiten | | `TRAVEL` | spätere Reiseleistung | | `SERVICE` | Heilung, Bank, Reparatur etc. | | `EVENT` | zeit- oder weltzustandsabhängige Funktion | Capabilities sind primär beschreibend. Die tatsächliche Funktion entsteht durch verknüpfte Daten wie: - `NpcShop` - `NpcQuestAssignment` - `NpcDialogueProfile` - `NpcExchangeProfile` --- # 6. NPC und Standort Ein NPC befindet sich grundsätzlich an einem Ort. V1: ```text NpcDefinition.locationId -> LocationDefinition.id ``` Später möglich: - NPC wechselt abhängig von Weltzustand den Ort - NPC erscheint nur während einer Quest - NPC wird nach Storyfortschritt ersetzt - NPC verschwindet temporär Für V1 wird der Standort statisch gespeichert. --- # 7. Trennung von Content und Player-State Ein NPC ist globaler Content. Der individuelle Zustand eines Spielers gegenüber diesem NPC ist separater Player-State. Nicht in `NpcDefinition` speichern: - ob ein Spieler den NPC bereits getroffen hat - persönliche Beziehung - individuelle Dialogflags - persönliche Freischaltungen Dafür existiert optional: ```ts CharacterNpcState { id: string; characterId: string; npcId: string; relationValue?: number; firstMetAt?: Date; lastInteractionAt?: Date; flags: Record; } ``` --- # 8. Ruf ist nicht automatisch NPC-Beziehung Ashen Realms unterscheidet ausdrücklich zwischen: ## Welt-/Gebiet-/Fraktionsruf Beispiele: ```text World Renown Graufurt Reputation Ashen Fields Reputation Duskwood Reputation Faction Reputation ``` und ## Persönlicher NPC-Beziehung Beispiele: ```text Borin kennt den Spieler Elyra vertraut dem Spieler Caelan reagiert auf eine Storyentscheidung ``` Ruf ist ein übergeordnetes Progressionssystem. NPC-Beziehung ist optionaler individueller Zustand. Ein Händler kann daher verlangen: ```text Graufurt Reputation >= 3 ``` ohne dass der Spieler automatisch „3 Ruf bei Borin“ besitzt. --- # 9. Character Reputation Ruf wird unabhängig von NPCs gespeichert. Beispielmodell: ```ts CharacterReputation { id: string; characterId: string; type: ReputationType; targetKey: string; value: number; } ``` Mögliche Typen: ```ts enum ReputationType { WORLD = 'WORLD', REGION = 'REGION', FACTION = 'FACTION', } ``` Beispiele: ```text WORLD / global / 4 REGION / graufurt / 3 REGION / duskwood / 2 FACTION / border-watch / 1 ``` --- # 10. NPC Dialogue System NPCs sollen nicht nur statische Texte besitzen. Dialoge reagieren auf: - Quests - Ruf - Items - Flags - besiegte Gegner oder Bosse - Storyfortschritt - erste Begegnung Vorgeschlagenes Modell: ```ts NpcDialogueProfile { id: string; key: string; npcId: string; } ``` ```ts DialogueNode { id: string; profileId: string; key: string; text: string; priority: number; conditions: GameCondition[]; actions: DialogueAction[]; responses: DialogueResponse[]; } ``` --- # 11. Dialogpriorität Mehrere Dialoge können gleichzeitig gültig sein. Daher besitzt jeder Node eine Priorität. Beispiel: ```text 1000 – Questabschluss verfügbar 900 – Quest aktiv 800 – neue wichtige Quest 500 – Ruf-basierter Dialog 100 – Standarddialog ``` Der Server ermittelt den höchstpriorisierten gültigen Dialog. Dadurch kann ein NPC situationsabhängig reagieren, ohne große If-/Else-Blöcke im Code. --- # 12. Dialogue Responses Ein Dialog kann mehrere auswählbare Antworten besitzen. ```ts DialogueResponse { id: string; nodeId: string; text: string; targetNodeKey?: string; conditions?: GameCondition[]; actions?: DialogueAction[]; } ``` Beispiele: ```text „Zeig mir deine Waren.“ „Was weißt du über die Aschengrube?“ „Ich habe die Felle gebracht.“ „Leb wohl.“ ``` --- # 13. Dialogue Actions Dialoge dürfen Aktionen auslösen. V1-relevante Actions: ```text START_QUEST COMPLETE_QUEST OPEN_SHOP OPEN_EXCHANGE GRANT_ITEM SET_FLAG ``` Später möglich: ```text START_TRAVEL OPEN_TRAINER OPEN_SERVICE CHANGE_RELATION DISCOVER_LOCATION START_EVENT ``` Beispiel: ```json { "type": "OPEN_SHOP", "shopKey": "borin-general-store" } ``` --- # 14. Quest-Zuordnung zu NPCs Questgeber und Questabgabe werden getrennt modelliert. Nicht vorgesehen: ```ts npc.isQuestGiver = true; ``` Stattdessen: ```ts NpcQuestAssignment { id: string; npcId: string; questId: string; role: NpcQuestRole; } ``` ```ts enum NpcQuestRole { OFFER = 'OFFER', TURN_IN = 'TURN_IN', PROGRESS = 'PROGRESS', } ``` Dadurch kann eine Quest mehrere NPCs verwenden. Beispiel: ```text Garrick -> OFFER Borin -> PROGRESS Garrick -> TURN_IN ``` --- # 15. Händler-System Ein Shop ist kein Spezialtyp von NPC. Ein NPC kann null, einen oder später mehrere Shops besitzen. ```ts NpcShop { id: string; key: string; npcId: string; name: string; enabled: boolean; } ``` ```ts ShopOffer { id: string; shopId: string; itemDefinitionId: string; currencyType: string; price: number; quantity?: number; repeatable: boolean; conditions: GameCondition[]; } ``` --- # 16. Rufbasierte Shop-Angebote Nicht mehrere Shops pro Rufstufe anlegen. Stattdessen erhält jedes Angebot eigene Conditions. Beispiel: ```text Großer Fellbeutel Preis: 140 Silber Bedingung: Graufurt Ruf >= 3 ``` Oder: ```text Dämmerjäger-Kapuze Preis: 28 Dämmermarken Bedingungen: - Dämmerwald Ruf >= 4 - Quest „Graufangs Spur“ abgeschlossen ``` Dadurch bleiben Shops vollständig datengetrieben. --- # 17. Resource Exchange Mit dem neuen Rufsystem können bestimmte NPCs Materialien annehmen. Dafür wird kein normaler Item-Shop missbraucht. Vorgesehen: ```ts NpcExchangeProfile { id: string; key: string; npcId: string; } ``` ```ts ExchangeRule { id: string; profileId: string; inputItemId: string; inputQuantity: number; silverReward?: number; worldRenownReward?: number; regionReputationReward?: number; factionReputationReward?: number; conditions: GameCondition[]; } ``` Beispiel: ```text 5 × Aschenfell → 18 Silber → 10 Graufurt-Ruf → 2 Weltruhm ``` Die genauen Werte werden separat gebalanced. --- # 18. Verbindung zum Taschensystem Das NPC-System muss das Taschensystem unterstützen. NPCs können: - Taschen verkaufen - Taschen einmalig vergeben - Taschen über Quests freischalten - größere Taschen erst ab Rufstufen anbieten Beispiel: ```text Borin ├── Einfacher Fellbeutel │ └── über Intro-Quest verfügbar │ ├── Verstärkter Fellbeutel │ └── Graufurt Ruf >= 2 │ └── Großer Jägerbeutel └── Graufurt Ruf >= 4 ``` Taschen selbst bleiben Teil des Item-/Bag-Systems. Der NPC kontrolliert nur: - Angebot - Freischaltung - Preis - Questbezug --- # 19. Game Conditions NPC-Systeme verwenden eine gemeinsame Condition Engine. V1 Condition Types: ```ts enum GameConditionType { QUEST_ACTIVE = 'QUEST_ACTIVE', QUEST_COMPLETED = 'QUEST_COMPLETED', HAS_ITEM = 'HAS_ITEM', REGION_REPUTATION = 'REGION_REPUTATION', WORLD_RENOWN = 'WORLD_RENOWN', FLAG_SET = 'FLAG_SET', BOSS_DEFEATED = 'BOSS_DEFEATED', LOCATION_DISCOVERED = 'LOCATION_DISCOVERED', } ``` Später möglich: ```text FACTION_REPUTATION NPC_RELATION HAS_EQUIPMENT BAG_OWNED MONSTER_KILL_COUNT ACHIEVEMENT_COMPLETED EVENT_ACTIVE TIME_WINDOW ``` --- # 20. Condition Struktur Conditions sollten möglichst generisch gespeichert werden. Beispiel: ```ts GameCondition { type: GameConditionType; key?: string; operator?: ComparisonOperator; value?: string | number | boolean; } ``` Beispiel: ```json { "type": "REGION_REPUTATION", "key": "graufurt", "operator": "GTE", "value": 3 } ``` --- # 21. Condition Evaluation Eine zentrale serverseitige Komponente wertet Conditions aus. ```ts GameConditionService { evaluate( characterId: string, conditions: GameCondition[], ): Promise; } ``` Sie kann wiederverwendet werden für: - Dialoge - Shop-Angebote - Quests - Materialtausch - Reiseverbindungen - Ortsinteraktionen - Bosszugänge - spätere Events Grundsatz: > **Keine separaten Condition-Systeme für jedes Feature bauen.** --- # 22. NPC Interaction API Der Client soll NPC-Logik nicht selbst auswerten. Mögliche API-Endpunkte: ```text GET /api/locations/:locationId/npcs GET /api/npcs/:npcId GET /api/npcs/:npcId/interaction POST /api/npcs/:npcId/dialogue/:nodeId/respond ``` Zusätzlich über separate Fachmodule: ```text GET /api/npcs/:npcId/shop POST /api/npcs/:npcId/shop/purchase GET /api/npcs/:npcId/exchange POST /api/npcs/:npcId/exchange ``` Questaktionen können über das Questmodul laufen. --- # 23. NPC Interaction Response Ein NPC-Interaction-Response kann enthalten: ```ts interface NpcInteractionDto { npc: { id: string; key: string; name: string; title?: string; portraitPath: string; }; dialogue?: DialogueNodeDto; availableActions: NpcActionDto[]; } ``` Beispiel Actions: ```text TALK OPEN_SHOP OPEN_EXCHANGE VIEW_QUESTS ``` Der Server entscheidet, welche Actions aktuell verfügbar sind. --- # 24. NPCs in der lokalen Ortsansicht NPCs werden in der lokalen Ortsansicht sichtbar dargestellt. Ein NPC-Eintrag zeigt mindestens: - Portrait oder Artwork - Name - Titel/Rolle - Interaktionsstatus Mögliche Marker: ```text ! neue Quest ? Quest abgabebereit ¤ Händler ↔ Materialtausch ● neue Dialoginformation ``` Die UI soll nicht jeden Capability-Typ als eigenes dauerhaftes Symbol erzwingen. Nur relevante Aktionen werden gezeigt. --- # 25. NPC-Verfügbarkeit V1 sind NPCs grundsätzlich dauerhaft verfügbar, solange: ```text enabled = true ``` Später können Conditions für NPC-Sichtbarkeit ergänzt werden. Beispiele: - NPC erscheint erst nach Quest - NPC stirbt oder verschwindet - anderer NPC ersetzt ihn - NPC wechselt Ort - Event-NPC erscheint temporär Dafür kann später ergänzt werden: ```ts NpcDefinition.visibilityConditions ``` Für V1 nicht erforderlich. --- # 26. Beispiel – Borin ```text Borin Händler der Grenzwacht Ort: Graufurt ``` Capabilities: ```text DIALOGUE MERCHANT RESOURCE_EXCHANGE BAG_MERCHANT ``` Funktionen: ```text Shop ├── Heiltrank ├── einfache Ausrüstung ├── Fellbeutel └── größere Taschen über Ruf Exchange ├── Aschenfell ├── zähes Fell └── weitere Tiermaterialien ``` Dialogzustände: ```text Erste Begegnung → reservierter Standarddialog Quest-Einführung aktiv → „Garrick schickt dich also.“ Graufurt-Ruf >= 2 → freundlicherer Dialog Graufurt-Ruf >= 4 → Spezialangebot verfügbar ``` --- # 27. Beispiel – Elyra ```text Elyra, die verbannte Jägerin Ort: Verfallener Jägerschrein ``` Capabilities: ```text DIALOGUE QUEST_GIVER QUEST_TURN_IN RESOURCE_EXCHANGE REPUTATION_MERCHANT LORE ``` Mögliche Funktionen: ```text Quests ├── Jagd auf Dämmerwölfe ├── Schwarzmähnen-Spur └── Graufang Exchange ├── Dämmerfell ├── Giftdrüse └── Elite-Trophäen Shop ├── Heiltrank ├── Gegengift ├── Bestienbeutel └── Dämmerjäger-Items ``` --- # 28. Beispiel – Bruder Caelan ```text Bruder Caelan Letzter Hüter Ort: Kapelle der letzten Wacht ``` Capabilities: ```text DIALOGUE QUEST_GIVER QUEST_TURN_IN REPUTATION_MERCHANT LORE ``` Mögliche Besonderheiten: - reagiert auf entdeckte Ruinen - erklärt Untote und Siegelbruchstücke - bietet spezielle Waren nach Sir Varos - besitzt Storydialoge zum Knochenfürsten --- # 29. Technische Modulstruktur Empfohlene Backend-Struktur: ```text apps/api/src/ ├── npcs/ │ ├── entities/ │ │ ├── npc-definition.entity.ts │ │ ├── npc-dialogue-profile.entity.ts │ │ ├── dialogue-node.entity.ts │ │ └── character-npc-state.entity.ts │ │ │ ├── npc.service.ts │ ├── npc.controller.ts │ └── npc.module.ts │ ├── shops/ │ ├── entities/ │ │ ├── npc-shop.entity.ts │ │ └── shop-offer.entity.ts │ └── ... │ ├── reputation/ │ ├── entities/ │ │ └── character-reputation.entity.ts │ └── ... │ ├── exchanges/ │ ├── entities/ │ │ ├── npc-exchange-profile.entity.ts │ │ └── exchange-rule.entity.ts │ └── ... │ ├── quests/ │ └── npc-quest-assignment.entity.ts │ └── conditions/ ├── game-condition.types.ts ├── game-condition.service.ts └── game-condition.service.spec.ts ``` --- # 30. Verantwortlichkeiten der Services ## `NpcService` Verantwortlich für: - NPCs eines Ortes laden - NPC-Definition laden - aktuell verfügbare Interaktionen bestimmen - relevanten Dialog ermitteln Nicht verantwortlich für: - Kauftransaktionen - Rufberechnung - Questfortschritt - Itemtransfer --- ## `GameConditionService` Verantwortlich für: - Conditions serverseitig auswerten - wiederverwendbare Freischaltlogik --- ## `ShopService` Verantwortlich für: - verfügbare Angebote bestimmen - Conditions prüfen - Preise validieren - Kauf atomar durchführen --- ## `ExchangeService` Verantwortlich für: - Materialbesitz prüfen - Taschen-/Inventarbezug beachten - Items entfernen - Silber/Ruf gewähren - Transaktion atomar durchführen --- # 31. Transaktionsregeln Folgende Aktionen müssen serverseitig und atomar ausgeführt werden: ```text Shop Purchase Material Exchange Quest Reward Item Grant Reputation Grant ``` Beispiel Materialtausch: ```text Material prüfen → Material entfernen → Silber gewähren → Regionalruf gewähren → Weltruhm gewähren → Commit ``` Ein Teilzustand darf nicht persistiert werden. --- # 32. Seeds NPC-Content wird über reproduzierbare Seeds angelegt. Empfohlene Dateien: ```text apps/api/src/database/seeds/ ├── npcs.seed.ts ├── npc-dialogues.seed.ts ├── npc-shops.seed.ts ├── npc-exchanges.seed.ts └── npc-quest-assignments.seed.ts ``` Seeds müssen idempotent sein. Fachliche Verknüpfungen verwenden stabile Keys. --- # 33. Tests Mindestens folgende Fälle sollten getestet werden: ## NPC - NPCs eines Ortes werden korrekt geladen - deaktivierte NPCs erscheinen nicht - NPC besitzt mehrere Capabilities gleichzeitig ## Dialog - Standarddialog wird angezeigt - höherpriorisierter Questdialog überschreibt Standarddialog - Rufdialog erscheint erst bei erfüllter Condition ## Shop - Rufanforderung wird serverseitig geprüft - Questanforderung wird geprüft - gesperrtes Item kann nicht direkt über API gekauft werden ## Exchange - benötigte Materialien werden geprüft - Materialien werden entfernt - Silber wird vergeben - Ruf wird vergeben - Transaktion bleibt atomar ## Quest - ein NPC kann Questgeber sein - anderer NPC kann Questfortschritt auslösen - dritter oder erster NPC kann Questabschluss übernehmen --- # 34. V1 Scope Für die erste Implementierung wird bewusst nur ein kleiner Teil benötigt. ## Implementieren ```text NpcDefinition NpcService NpcController NpcQuestAssignment NpcShop ShopOffer NpcExchangeProfile ExchangeRule GameConditionService Conditions: - QUEST_ACTIVE - QUEST_COMPLETED - REGION_REPUTATION - WORLD_RENOWN - FLAG_SET ``` Dialogsystem zunächst einfach: ```text priorisierte DialogNodes + Conditions + OPEN_SHOP + OPEN_EXCHANGE + START_QUEST + COMPLETE_QUEST ``` --- # 35. Noch nicht für V1 implementieren Noch nicht notwendig: - komplexe persönliche NPC-Beziehungen - Romance - NPC-Tagesabläufe - freie NPC-Bewegung - KI-gesteuerte NPCs - prozedurale Dialoge - Sprachausgabe - NPC-Inventare als physische Simulation - dynamische Preise - Verhandlungssystem - Diebstahl - Begleiter - NPC-Tod mit komplexen Weltfolgen - Echtzeit-Weltzustände `CharacterNpcState` kann vorbereitet, aber erst später vollständig genutzt werden. --- # 36. UI-Prinzip Ein NPC-Screen oder NPC-Panel soll weiterhin den visuellen Grundsätzen von Ashen Realms folgen. NPCs werden über: - großes Portrait oder Artwork - Namen - Titel - Dialogtext - klar sichtbare aktuelle Aktionen präsentiert. Nicht geeignet: - reine Tabellenansicht - generische Admin-Card - zehn gleichgewichtete Buttons Der NPC soll wie ein Teil der Welt wirken. --- # 37. Architekturregeln 1. **NPC-Funktionen werden über Composition modelliert, nicht über Klassenvererbung.** 2. **NPC-Definition und Player-State bleiben getrennt.** 3. **Ruf ist nicht automatisch persönliche NPC-Beziehung.** 4. **Ein NPC darf mehrere Rollen gleichzeitig besitzen.** 5. **Questgeber und Questabgabe sind getrennte Zuordnungen.** 6. **Shopangebote besitzen eigene Conditions.** 7. **Materialtausch ist ein eigenes System und kein normaler Shopverkauf.** 8. **Conditions werden zentral wiederverwendbar ausgewertet.** 9. **Der Client entscheidet nicht über Freischaltungen.** 10. **Alle relevanten Transaktionen sind serverautoritativ und atomar.** 11. **Content verwendet stabile fachliche Keys.** 12. **NPC-Spezialverhalten soll möglichst datengetrieben entstehen.** --- # 38. Zielbild Das NPC-System soll langfristig folgende Interaktionen ermöglichen, ohne für jeden NPC neuen Spezialcode zu schreiben: ```text Spieler spricht mit NPC ↓ Server prüft Quest-, Ruf- und Weltzustand ↓ passender Dialog wird gewählt ↓ verfügbare Aktionen werden angezeigt ↓ Spieler kann z. B. ├── Quest annehmen ├── Quest abgeben ├── Materialien eintauschen ├── Shop öffnen ├── Tasche kaufen └── Lore lesen ``` Der gleiche technische Unterbau kann für Borin, Elyra, Bruder Caelan und zukünftige NPCs wiederverwendet werden. --- # 39. Kurzfassung Ashen Realms verwendet ein gemeinsames NPC-Grundmodell. NPC-Typen wie Händler oder Questgeber werden **nicht** über Vererbung umgesetzt. Stattdessen besitzt ein NPC kombinierbare Funktionen: ```text NPC + Dialogue + Quests + Shop + Resource Exchange + Reputation Conditions + Bag Offers + Player State ``` Ruf bleibt ein separates Charakter-Progressionssystem. Persönliche NPC-Beziehung kann später zusätzlich ergänzt werden. Eine zentrale Condition Engine verbindet: - NPCs - Dialoge - Quests - Shops - Ruf - Materialtausch - Taschen - Weltfortschritt Der zentrale Grundsatz lautet: > **NPCs sind datengetriebene Charaktere mit kombinierbaren Interaktionen – keine voneinander getrennten Spezialklassen.**