# Haunted Manor – Textadventure Semesterprojekt im Modul Algorithmen und Datenstrukturen (2. Semester). Ein textbasiertes Adventure in Java: Der Spieler navigiert durch die Räume eines Spukhauses, sammelt Gegenstände, spricht mit NPCs, löst Rätsel und findet einen Weg hinaus. Die Spielwelt ist vollständig datengetrieben – Räume, Gegenstände, NPCs, Quests und Enden werden aus YAML-Dateien geladen, nicht im Code festverdrahtet. **Umfang:** 14 Räume, 19 Gegenstände, 3 NPCs, 259 Tests. --- ## Schnellstart Es gibt **zwei Wege**, das Spiel zu starten. Wenn Sie nur spielen wollen, nehmen Sie Weg A – dafür wird kein Maven benötigt. ### Voraussetzung **Java 21 oder neuer** (LTS). Gebaut wird gegen `maven.compiler.release=21`; das neueste genutzte Sprachfeature ist `List.getFirst()` (SequencedCollection, Java 21). Neuere JDKs (22–25) funktionieren ebenfalls. Prüfen mit: ```bash java -version ``` ### Weg A – fertige JARs starten (ohne Maven) Im Ordner [`release/`](release/) liegen zwei eigenständige JARs, die alle Abhängigkeiten bereits enthalten. Es wird **nur Java** gebraucht, kein Maven, keine Internetverbindung: ```bash java -jar release/HauntedManor-Console.jar # Konsolen-Version (~5 MB) java -jar release/HauntedManor-GUI.jar # Swing-GUI (~17 MB) ``` - Die **Konsolen-Version** läuft in jedem Terminal, auch ohne grafische Oberfläche. - Die **GUI-Version** (Bonus) braucht einen Desktop und spielt zusätzlich Hintergrundmusik. Die Konsolen-JAR enthält weder die Musikdateien noch die OGG-Bibliotheken – im Textmodus gibt es keine Musik, daher sind sie dort weggelassen. ### Weg B – mit Maven bauen und starten Der mitgelieferte **Maven Wrapper** (`./mvnw`) lädt die passende Maven-Version beim ersten Aufruf selbst herunter – eine separate Maven-Installation ist nicht nötig. Unter Windows `mvnw.cmd` statt `./mvnw` verwenden. Ein systemweit installiertes `mvn` funktioniert identisch. ```bash ./mvnw clean test # alle 259 Tests ausführen ./mvnw clean package # baut beide JARs neu nach release/ ./mvnw exec:java@run # Konsolen-Version starten (thb.jeanluc.adventure.App) ./mvnw exec:java@gui # Swing-GUI starten (thb.jeanluc.adventure.AppGui) ``` `./mvnw exec:java` ohne Profil startet ebenfalls die Konsolen-Version. > **Hinweis:** Der erste Maven-Aufruf lädt die Abhängigkeiten (Jackson, Lombok, > JUnit, Logback) aus dem Internet. Wer offline ist, nimmt Weg A. Speicherstände und Einstellungen legt das Spiel in einem Ordner `saves/` neben dem Arbeitsverzeichnis an, aus dem es gestartet wurde. --- ## Befehle im Spiel Befehle funktionieren auf **Englisch und Deutsch** – die deutschen Beispiele aus der Aufgabenstellung (`Gehe nach Norden`, `Nimm Brief`, `Lies Brief`, `Benutze Schaufel`) laufen also direkt. Gegenstands-IDs bleiben englisch (`letter`, `shovel`), Himmelsrichtungen verstehen beide Sprachen (`north` / `norden`). | Befehl | Aliase | Deutsch | Wirkung | |---|---|---|---| | `go ` | `move`, `walk` | `gehe`, `geh` | In eine Himmelsrichtung gehen | | `go to ` | | | Automatisch zu einem bekannten Raum laufen | | `look` | `l` | `schau`, `umsehen` | Aktuellen Raum beschreiben | | `map` | `m` | `karte` | Karte der erkundeten Räume anzeigen | | `quests` | `log`, `journal` | `aufgaben` | Aktive und erledigte Quests anzeigen | | `inventory` | `inv`, `i` | `inventar` | Inventar anzeigen | | `take ` | `pick`, `get` | `nimm`, `nehme` | Gegenstand aufnehmen | | `drop ` | `put` | `lege`, `ablegen` | Gegenstand ablegen | | `use ` | | `benutze` | Gegenstand benutzen / schalten | | `use on ` | | | Zwei Gegenstände kombinieren | | `read ` | | `lies`, `lese` | Lesbaren Gegenstand lesen | | `examine ` | `x`, `inspect` | `untersuche` | Gegenstand genauer ansehen | | `talk ` | `speak` | `rede`, `sprich` | Mit einem NPC sprechen | | `give ` | | `gib` | NPC einen Gegenstand geben | | `save` | | `speichern` | Spielstand speichern | | `help` | `?` | `hilfe` | Befehlsübersicht anzeigen | | `quit` | `exit` | `beenden` | Speichern und zurück ins Hauptmenü | Zu Beginn führt ein kurzes, überspringbares Tutorial (`skip`) durch die wichtigsten Befehle. --- ## Wo die Aufgabenstellung umgesetzt ist | Anforderung | Wo im Code | Umsetzung | |---|---|---| | **Raum-Klasse + Navigation**, mind. 4 Räume | [`model/Room.java`](src/main/java/thb/jeanluc/adventure/model/Room.java), [`model/Direction.java`](src/main/java/thb/jeanluc/adventure/model/Direction.java) | **14 Räume.** `Room` hält direkte Referenzen auf seine Nachbarräume in einer `EnumMap` – ein echter Objektgraph, keine String-IDs. | | **`gehen`-Befehl** (Tipp: switch / if-else / HashMap) | [`command/CommandRegistry.java`](src/main/java/thb/jeanluc/adventure/command/CommandRegistry.java), [`command/impl/GoCommand.java`](src/main/java/thb/jeanluc/adventure/command/impl/GoCommand.java) | Dispatch über `HashMap` (O(1); Aliase = mehrere Keys auf dieselbe Instanz, statt eines wachsenden `switch`). Die Richtung danach O(1) per `EnumMap`-Lookup. | | **Gegenstände + Inventar**, mind. 3 Items | [`model/Player.java`](src/main/java/thb/jeanluc/adventure/model/Player.java), [`model/item/`](src/main/java/thb/jeanluc/adventure/model/item/) | **19 Gegenstände.** Inventar = `LinkedHashMap` (O(1)-Zugriff *und* stabile Anzeigereihenfolge). Hierarchie: `PlainItem`, `ReadableItem`, `SwitchableItem`. | | **Aufnehmen / Ablegen / Benutzen / Lesen** | [`command/impl/`](src/main/java/thb/jeanluc/adventure/command/impl/) | `TakeCommand`, `DropCommand`, `UseCommand`, `ReadCommand` – inklusive `letter` („Brief") und `shovel` („Schaufel") aus den Beispielen der Aufgabenstellung. | | **Wahl der Datenstrukturen** | [`docs/data-structures.md`](docs/data-structures.md) | Begründung je Anwendungsfall, plus Tabelle „Bewusst NICHT gewählt". | | **NPCs** (Bonus) | [`model/Npc.java`](src/main/java/thb/jeanluc/adventure/model/Npc.java) | 3 NPCs, die auf den Spielerzustand **reagieren** (`talk`, `give`). | | **Swing-GUI** (Bonus) | [`io/SwingIO.java`](src/main/java/thb/jeanluc/adventure/io/SwingIO.java) | `JTextField` für die Eingabe (siehe Hinweis unten). | | **Javadoc** | gesamtes `src/main/java` | An Klassen, Methoden und Instanzvariablen. | **Hinweis zur GUI:** Die Aufgabe nennt `JTextField` **und** `JTextArea`. Die Eingabe ist wie gefordert ein `JTextField`. Für die **Ausgabe** wird bewusst ein `JTextPane` statt einer `JTextArea` verwendet: `JTextArea` kann ausschließlich unformatierten Text darstellen, das Spiel rendert aber farbig gestylte Ausgabe (`StyledText` → `StyledDocument`), damit Raumnamen, Gegenstände und Hinweise optisch unterscheidbar sind. `JTextPane` ist dafür die passende Swing-Komponente und funktional eine Obermenge von `JTextArea`. --- ## Projektstruktur ``` Semesterprojekt/ ├── src/main/java/thb/jeanluc/adventure/ │ ├── App.java – Einstiegspunkt Konsole │ ├── AppGui.java – Einstiegspunkt Swing-GUI │ ├── model/ – Domänenmodell: Room, Player, Npc, item/ … │ ├── command/ – Parser, Registry + impl/ (15 Kommandos) │ ├── game/ – Spielschleife, Engines, Light, Pathfinder, MapLayout │ ├── io/ – GameIO-Abstraktion: ConsoleIO, SwingIO + text/ │ ├── loader/ – YAML-Laden: dto/, Factories, Resolver, Validator │ ├── save/ – Speicherstände und Einstellungen (JSON) │ └── menu/ – Hauptmenü und Einstellungen ├── src/main/resources/world/ │ ├── game.yaml – Metadaten (Titel, Startraum, Begrüßung) │ ├── rooms.yaml – Räume mit Ausgängen, Gegenständen, NPCs │ ├── items.yaml – Gegenstände │ ├── npcs.yaml – NPCs und ihre Reaktionen │ ├── quests.yaml – Quests und ihre Stufen │ ├── endings.yaml – Spielenden │ └── combinations.yaml – Gegenstands-Kombinationen (`use X on Y`) ├── src/test/java/ – 259 Tests (JUnit 5 + AssertJ) ├── release/ – fertig gebaute JARs (Console + GUI) └── docs/ – Design- und Architekturdokumentation ``` ## Technologie-Stack - **Java 21 (LTS)** - **Jackson** (YAML) für das Laden der Spielwelt - **Lombok** zur Reduktion von Boilerplate - **JUnit 5 + AssertJ + Mockito** für die Tests - **SLF4J + Logback** für Logging - **Swing** für die GUI (Bonus) ## Dokumentation Ausführliche Design- und Architekturdokumentation liegt unter [`docs/`](docs/README.md): Package-Struktur, Wahl der Datenstrukturen, Item-Modell, Befehle, NPC-Modell, YAML-Schemas und Lade-Ablauf.