Files
Jander_Semester2/Semesterprojekt/docs/npcs.md
Jean-Luc Makiola 83643a192f semesterprojekt: implement full text adventure (phases 1-7)
Walking skeleton through Swing GUI: YAML-driven world (4 rooms,
4 items, 1 NPC), HashMap command dispatch with parser, three-tier
item hierarchy (readable / switchable / plain), and end-to-end
NPC give/receive flow. 67 tests green.
2026-05-25 21:37:59 +02:00

120 lines
3.0 KiB
Markdown

# NPCs
Nicht-Spieler-Figuren — optionaler Bonusteil laut Aufgabenstellung. Hier mit Talk- und Give-Interaktion modelliert.
## Domain-Modell
```mermaid
classDiagram
class Npc {
-String id
-String name
-String description
-String greeting
-Map~String, NpcReaction~ reactions
+talk(GameContext) void
+receive(Item, GameContext) boolean
}
class NpcReaction {
-Item consumes
-Item gives
-String response
+apply(Player) void
}
Npc "1" --> "*" NpcReaction : reactions
```
- `reactions` ist `HashMap<String, NpcReaction>` mit dem Trigger-Item-id als Key. O(1) Nachschlagen beim `gib X an Y`.
## Interaktionen
### `talk <npc>`
- Sucht NPC im aktuellen Raum.
- Wirft `greeting`-Text aus.
- Mutiert nichts.
### `gib <item> an <npc>`
```mermaid
sequenceDiagram
actor Spieler
participant Cmd as GiveCommand
participant P as Player
participant N as Npc
participant IO
Spieler->>Cmd: give lamp old_man
Cmd->>P: hasItem("lamp")?
P-->>Cmd: yes
Cmd->>N: receive(lamp)
N->>N: reactions.get("lamp")
alt Reaktion existiert
N->>P: inventory.remove(lamp)
N->>P: inventory.add(key)
N-->>Cmd: response text
Cmd->>IO: write(response)
else keine Reaktion
N-->>Cmd: false
Cmd->>IO: write("The NPC does not react.")
end
```
## YAML-Beispiel
```yaml
- id: old_man
name: Old Man
description: A stooped old man with a grey beard.
greeting: |
"Hello traveller. If you bring me the lamp,
I will show you the way to the cellar."
reactions:
- onReceive: lamp
response: |
"Thank you! Here, take this key."
gives: key
consumes: lamp
```
Felder einer Reaktion:
| Feld | Pflicht | Bedeutung |
|---|---|---|
| `onReceive` | ja | Item-id, das ausgelöst werden muss |
| `response` | ja | Antworttext nach erfolgreicher Übergabe |
| `gives` | nein | Item-id, das der NPC zurückgibt |
| `consumes` | nein | Item-id, das aus Spielerinventar entfernt wird (oft = `onReceive`) |
## Speichern in Räumen
Räume halten ihre NPCs analog zu Items:
```java
private final LinkedHashMap<String, Npc> npcs = new LinkedHashMap<>();
```
- `LinkedHashMap` weil O(1)-Lookup beim `talk <npc>` *und* stabile Reihenfolge in der Raumbeschreibung („Here is: Old Man, Innkeeper").
## Erweiterungen (bewusst nicht im MVP)
- Bedingte Dialoge („wenn Quest X erledigt, sag Y")
- Kauf/Verkauf mit Gold
- NPC bewegt sich zwischen Räumen
- Mehrfache Reaktionsketten (NPC-Memory)
Diese würden ein eigenes Quest-/Event-System rechtfertigen. Für 3 Bonuspunkte überdimensioniert.
## Validierungsregeln
Wiederholung aus [yaml-schemas.md](yaml-schemas.md), hier explizit pro NPC:
1. `id` eindeutig in `npcs.yaml`
2. `greeting` nicht leer (sonst sinnloses NPC)
3. Jede `onReceive`-id existiert in `items.yaml`
4. Jede `gives`-id existiert in `items.yaml`
5. Jede `consumes`-id existiert in `items.yaml`
6. Innerhalb eines NPCs ist `onReceive` eindeutig (keine zwei Reaktionen auf dasselbe Item)