Files
Jander_Semester2/Semesterprojekt/docs/item-model.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

140 lines
3.7 KiB
Markdown

# Item-Modell
Hierarchie aus abstraktem `Item` und drei konkreten Subtypen. Liegt im Subpackage `thb.jeanluc.adventure.model.item`.
## Hierarchie
```mermaid
classDiagram
class Item {
<<abstract>>
#String id
#String name
#String description
+use(GameContext)* void
}
class ReadableItem {
-String readText
+use(GameContext) void
}
class SwitchableItem {
-boolean state
-boolean initialState
-String onText
-String offText
+use(GameContext) void
+isOn() boolean
}
class PlainItem {
+use(GameContext) void
}
Item <|-- ReadableItem
Item <|-- SwitchableItem
Item <|-- PlainItem
```
## Felder pro Klasse
### `Item` (abstract)
| Feld | Typ | Hinweis |
|---|---|---|
| `id` | `String` | unique slug, Lookup-Key |
| `name` | `String` | Anzeigename |
| `description` | `String` | `examine`-Output |
Abstrakte Methode: `public abstract void use(GameContext ctx)`
### `ReadableItem`
| Feld | Typ | Hinweis |
|---|---|---|
| `readText` | `String` | wird beim `read`/`use` ausgegeben |
`use()` schreibt `readText` über `ctx.io()`.
### `SwitchableItem`
| Feld | Typ | Hinweis |
|---|---|---|
| `state` | `boolean` | aktueller Zustand (mutable) |
| `initialState` | `boolean` | aus YAML, im Konstruktor an `state` durchgereicht |
| `onText` | `String` | Nachricht beim Einschalten |
| `offText` | `String` | Nachricht beim Ausschalten |
`use()` toggelt `state` und schreibt den entsprechenden Text.
Bewusste Entscheidung: `boolean` statt `enum SwitchState`. Wenn später `BROKEN` o.ä. nötig wird, refactoren.
### `PlainItem`
Keine eigenen Felder. `use()` schreibt eine generische Nachricht („You can't use the X by itself."). Existiert, damit alle Items polymorph `use()` haben und das YAML einen konsistenten `type:`-Discriminator hat.
## Lombok-Setup
`@SuperBuilder` ist Pflicht, weil normales `@Builder` Vererbung nicht beherrscht.
```java
@Getter
@SuperBuilder
@RequiredArgsConstructor
public abstract class Item {
protected final String id;
protected final String name;
protected final String description;
public abstract void use(GameContext ctx);
}
@Getter
@SuperBuilder
public class ReadableItem extends Item {
private final String readText;
@Override
public void use(GameContext ctx) {
ctx.getIo().write(readText);
}
}
```
Konstruktion:
```java
ReadableItem.builder()
.id("letter").name("Letter").description("A crumpled paper.")
.readText("Meet me at midnight.")
.build();
```
## Jackson Polymorphism
```java
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ReadableItem.class, name = "readable"),
@JsonSubTypes.Type(value = SwitchableItem.class, name = "switchable"),
@JsonSubTypes.Type(value = PlainItem.class, name = "plain")
})
public abstract class Item { ... }
```
YAML-Pflichtfeld pro Item: `type: readable|switchable|plain`.
## Verworfen / bewusst nicht im MVP
- **`use X on Y`** (targeted use) — Items kennen ihren Kontext über `GameContext`, kein zweites Item als Parameter.
- **Hidden Items** (sichtbar erst nach Aktion) — keine `visible`-Flag, alle Items sofort sichtbar.
- **Item kennt seinen Standort** — Items sind „dumm", nur Room/Player wissen wer sie hält.
- **Item-State beeinflusst Raumbeschreibung** (z.B. „Cellar dark unless lamp on") — wenn nötig, später per Conditions-System.
- **`hasBeenRead`-Tracking** — Lesen bleibt idempotent.
## Player-Input-Matching
Player tippt `take lamp` → Match gegen `id`. Multi-Word-Items haben snake_case ids, also `take oil_lamp`.
Alias-Feld (`aliases: [lamp, oil]`) ist YAGNI bis ein konkreter Bedarf entsteht.