Prechádzať zdrojové kódy

Merge branch 'dev' into 'main'

1.1.0

See merge request FIS-VSE/4IT115/2025ZS/ct1800/scho07/gui-textova-adventura!2
Ondřej Schlaichert 8 mesiacov pred
rodič
commit
be7edfdd47
56 zmenil súbory, kde vykonal 584 pridanie a 96 odobranie
  1. 18 0
      README.md
  2. 6 1
      pom.xml
  3. 2 0
      src/main/java/eu/oschl/cli/commands/Explore.java
  4. 23 9
      src/main/java/eu/oschl/gui/ActionProcessor.java
  5. 5 0
      src/main/java/eu/oschl/gui/ButtonData.java
  6. 83 9
      src/main/java/eu/oschl/gui/GameController.java
  7. 5 0
      src/main/java/eu/oschl/gui/Observable.java
  8. 5 0
      src/main/java/eu/oschl/gui/Observer.java
  9. 5 0
      src/main/java/eu/oschl/gui/Output.java
  10. 98 3
      src/main/java/eu/oschl/gui/Session.java
  11. 1 1
      src/main/java/eu/oschl/gui/actions/Action.java
  12. 6 0
      src/main/java/eu/oschl/gui/actions/Enter.java
  13. 7 0
      src/main/java/eu/oschl/gui/actions/Explore.java
  14. 5 0
      src/main/java/eu/oschl/gui/actions/PressButton.java
  15. 30 0
      src/main/java/eu/oschl/gui/actions/Quit.java
  16. 5 0
      src/main/java/eu/oschl/gui/actions/Slay.java
  17. 5 0
      src/main/java/eu/oschl/gui/actions/TakeItem.java
  18. 5 0
      src/main/java/eu/oschl/gui/actions/UseItem.java
  19. 35 0
      src/main/java/eu/oschl/schmorn/Launcher.java
  20. 3 21
      src/main/java/eu/oschl/schmorn/Main.java
  21. 63 25
      src/main/java/eu/oschl/schmorn/Setup.java
  22. 21 2
      src/main/java/eu/oschl/textadventure/map/Room.java
  23. 7 0
      src/main/java/eu/oschl/textadventure/objects/InventoryItem.java
  24. 16 0
      src/main/java/eu/oschl/textadventure/objects/PickableObject.java
  25. 6 0
      src/main/java/eu/oschl/textadventure/objects/Weapon.java
  26. 3 0
      src/main/java/module-info.java
  27. 21 17
      src/main/resources/eu/oschl/gui/css/style.css
  28. BIN
      src/main/resources/eu/oschl/gui/fonts/Iosevka-Slab-01.ttf
  29. BIN
      src/main/resources/eu/oschl/gui/fonts/SGr-IosevkaSlab-Regular.ttc
  30. 2 8
      src/main/resources/eu/oschl/gui/game.fxml
  31. 93 0
      src/main/resources/eu/oschl/gui/help.html
  32. BIN
      src/main/resources/eu/oschl/gui/images/items/blood_stone.png
  33. BIN
      src/main/resources/eu/oschl/gui/images/items/dark_key.png
  34. BIN
      src/main/resources/eu/oschl/gui/images/items/fire_stone.png
  35. BIN
      src/main/resources/eu/oschl/gui/images/items/frozen_stone.png
  36. BIN
      src/main/resources/eu/oschl/gui/images/items/kitchen_key.png
  37. BIN
      src/main/resources/eu/oschl/gui/images/items/ratsword.png
  38. BIN
      src/main/resources/eu/oschl/gui/images/items/unbreakable_ladle.png
  39. BIN
      src/main/resources/eu/oschl/gui/images/map/black_altar.png
  40. BIN
      src/main/resources/eu/oschl/gui/images/map/cell_a.png
  41. BIN
      src/main/resources/eu/oschl/gui/images/map/cell_b.png
  42. BIN
      src/main/resources/eu/oschl/gui/images/map/crossroads.png
  43. BIN
      src/main/resources/eu/oschl/gui/images/map/dark_entrance.png
  44. BIN
      src/main/resources/eu/oschl/gui/images/map/dungeon_exit.png
  45. BIN
      src/main/resources/eu/oschl/gui/images/map/guard_room.png
  46. BIN
      src/main/resources/eu/oschl/gui/images/map/kitchens_end.png
  47. BIN
      src/main/resources/eu/oschl/gui/images/map/pantry.png
  48. BIN
      src/main/resources/eu/oschl/gui/images/map/pathways_end.png
  49. BIN
      src/main/resources/eu/oschl/gui/images/map/prison_entrance.png
  50. BIN
      src/main/resources/eu/oschl/gui/images/map/prisons_end.png
  51. BIN
      src/main/resources/eu/oschl/gui/images/map/royal_kitchens_entrance.png
  52. BIN
      src/main/resources/eu/oschl/gui/images/map/royal_well.png
  53. BIN
      src/main/resources/eu/oschl/gui/images/map/sewer_entrance.png
  54. BIN
      src/main/resources/eu/oschl/gui/images/map/shadow_chamber.png
  55. BIN
      src/main/resources/eu/oschl/gui/images/map/swordsmith_rats_lair.png
  56. BIN
      src/main/resources/eu/oschl/gui/images/rooms/well.png

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+# schmorn
+
+> *The sun sets over a misty day as the witch Oglunda, ruler of the Seven Swamps, rides her carriage down the Royal Road. An agreement has been made, and she comes now to fulfil her side of it.*
+
+**Schmorn** is a simple GUI text adventure game made in Java as part of the **4IT115** course at the **Prague University of Economics and Business (VŠE)**.
+
+The game tells a story of Schmorn, a weak, inept and power-hungry prince, who gets turned into a worm as a punishment for seeking unlimited power from Oglunda, a powerful witch. The witch casts Schmorn into his Royal Well, forcing him to crawl through the Royal Underground to reach the surface and get his revenge.
+
+- author: **Ondřej Schlaichert**
+- semester: **ZS 2025/2026**
+- version: **1.1.0**
+
+## How to play
+- All gameplay is handled by pressing appropriate buttons. Press buttons to explore, fight enemies, etc.
+- The inventory is also interactable: click on a collected item to use it.
+- Press **Ctrl+R** to restart the game at any time.
+- Press **F1** to show this help screens available, which lists all commands and their descriptions.
+- Run the game with the `--cli` argument to play in the command line interface.

+ 6 - 1
pom.xml

@@ -6,7 +6,7 @@
 
     <groupId>eu.oschl</groupId>
     <artifactId>schmorn-gui</artifactId>
-    <version>1.0-SNAPSHOT</version>
+    <version>1.1.0</version>
     <name>schmorn-gui</name>
 
     <properties>
@@ -25,6 +25,11 @@
             <artifactId>javafx-fxml</artifactId>
             <version>21.0.6</version>
         </dependency>
+        <dependency>
+            <groupId>org.openjfx</groupId>
+            <artifactId>javafx-web</artifactId>
+            <version>21.0.6</version>
+        </dependency>
 
         <dependency>
             <groupId>org.junit.jupiter</groupId>

+ 2 - 0
src/main/java/eu/oschl/cli/commands/Explore.java

@@ -46,6 +46,8 @@ public class Explore implements Command {
         var objects = room.getObjects();
         var passages = room.getPassages();
 
+        room.setExplored(true);
+
         Console.print(room.getName(), ConsoleColor.BG_BLUE);
         Console.printLine();
         Console.print(room.getDescription(), ConsoleColor.BLUE);

+ 23 - 9
src/main/java/eu/oschl/gui/ActionProcessor.java

@@ -7,8 +7,13 @@ import eu.oschl.textadventure.Game;
 import java.util.ArrayList;
 import java.util.List;
 
+/**
+ * Processes and manages actions within the game.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class ActionProcessor extends Observable {
-    private final ArrayList<Action> actions;
+    private ArrayList<Action> actions;
 
     public ActionProcessor(ArrayList<Action> actions) {
         this.actions = actions;
@@ -25,18 +30,27 @@ public class ActionProcessor extends Observable {
      * @return a new ActionProcessor instance with initialized actions
      */
     public static ActionProcessor create(Game game) {
-        ArrayList<Action> actions = new ArrayList<>(List.of(
-            new Explore(game),
-            new Slay(game),
-            new PressButton(game),
-            new TakeItem(game),
-            new Enter(game),
-            new UseItem(game)
-        ));
+        ArrayList<Action> actions = getActions(game);
 
         return new ActionProcessor(actions);
     }
 
+    private static ArrayList<Action> getActions(Game game) {
+        return new ArrayList<>(List.of(
+                new Explore(game),
+                new Slay(game),
+                new PressButton(game),
+                new TakeItem(game),
+                new Enter(game),
+                new UseItem(game),
+                new Quit()
+        ));
+    }
+
+    public void changeGame(Game game) {
+        this.actions = getActions(game);
+    }
+
     /**
      * Executes the action of the provided ID and arguments.
      *

+ 5 - 0
src/main/java/eu/oschl/gui/ButtonData.java

@@ -1,5 +1,10 @@
 package eu.oschl.gui;
 
+/**
+ * Data class representing a button action with its associated ID and arguments.
+ *
+ * @author Ondřej Schlaichert
+ */
 public record ButtonData(
         String actionId,
         String... arguments

+ 83 - 9
src/main/java/eu/oschl/gui/GameController.java

@@ -5,11 +5,19 @@ import eu.oschl.gui.exceptions.InvalidActionId;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
 import javafx.scene.layout.VBox;
 import javafx.scene.text.TextFlow;
 
 import java.util.ArrayList;
+import java.util.Objects;
 
+/**
+ * Controller class for managing the game UI and interactions.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class GameController implements Observer {
     @FXML
     private TextFlow output;
@@ -20,6 +28,9 @@ public class GameController implements Observer {
     @FXML
     private VBox inventoryContainer;
 
+    @FXML
+    private ImageView mapContainer;
+
     @FXML
     public void initialize() {
         Output.setOutputElement(output);
@@ -48,6 +59,7 @@ public class GameController implements Observer {
 
         renderActionButtons();
         renderInventoryItems();
+        renderMapImage();
     }
 
     private void renderActionButtons() {
@@ -55,6 +67,12 @@ public class GameController implements Observer {
 
         var newButtons = new ArrayList<Button>();
 
+        if (!Session.getGame().isRunning()) {
+            newButtons.add(createActionButton("Quit game", new ButtonData("quit")));
+            inputButtonContainer.getChildren().addAll(newButtons);
+            return;
+        }
+
         for (Action action : Session.getActionProcessor().getActions()) {
             switch (action) {
                 case Enter enter -> {
@@ -62,6 +80,12 @@ public class GameController implements Observer {
                     var passages = room.getPassages();
 
                     for (var passage : passages) {
+                        var lastPassage = Session.getGame().getLastPassage();
+
+                        if (!Session.getGame().getCurrentRoom().isExplored() && (lastPassage.isEmpty() || passage != lastPassage.get())) {
+                            continue;
+                        }
+
                         var label = passage.isSeeThrough() || passage.getOtherRoom(room).wasEntered()
                                 ? enter.getName() + " " + passage.getName() + " (>> " + passage.getOtherRoom(Session.getGame().getCurrentRoom()).getName() + ")"
                                 : enter.getName() + " " + passage.getName() + " (>> ???)";
@@ -75,6 +99,10 @@ public class GameController implements Observer {
                     }
                 }
                 case PressButton pressButton -> {
+                    if (!Session.getGame().getCurrentRoom().isExplored()) {
+                        continue;
+                    }
+
                     if (Session.getGame().getCurrentRoom().isBlockedByEnemy()) {
                         continue;
                     }
@@ -95,6 +123,10 @@ public class GameController implements Observer {
                     }
                 }
                 case Slay slay -> {
+                    if (!Session.getGame().getCurrentRoom().isExplored()) {
+                        continue;
+                    }
+
                     var enemy = Session.getGame().getCurrentRoom().getEnemy();
 
                     if (enemy.isPresent() && enemy.get().isAlive()) {
@@ -109,6 +141,10 @@ public class GameController implements Observer {
                     }
                 }
                 case TakeItem takeItem -> {
+                    if (!Session.getGame().getCurrentRoom().isExplored()) {
+                        continue;
+                    }
+
                     if (Session.getGame().getCurrentRoom().isBlockedByEnemy()) {
                         continue;
                     }
@@ -128,7 +164,7 @@ public class GameController implements Observer {
                         }
                     }
                 }
-                case UseItem _ -> {
+                case UseItem _, Quit _ -> {
                 }
                 default -> newButtons.add(createActionButton(action.getName(), new ButtonData(action.getId())));
             }
@@ -146,7 +182,7 @@ public class GameController implements Observer {
             var label = item.getName();
             var buttonData = new ButtonData("useitem", item.getName());
 
-            var button = createActionButton(label, buttonData);
+            var button = createInventoryButton(label, buttonData, item.getIconImagePath().orElse(null));
             button.getStyleClass().add("inventory-item");
 
             newItems.add(button);
@@ -155,7 +191,7 @@ public class GameController implements Observer {
         if (Session.getGame().getInventory().getWeapon().isPresent()) {
             var weapon = Session.getGame().getInventory().getWeapon().get();
 
-            var button = createActionButton(weapon.getName(), new ButtonData(""));
+            var button = createInventoryButton(weapon.getName(), new ButtonData(""), weapon.getIconImagePath().orElse(null));
             button.getStyleClass().add("inventory-item");
             button.getStyleClass().add("weapon");
             button.setDisable(true);
@@ -166,6 +202,26 @@ public class GameController implements Observer {
         inventoryContainer.getChildren().addAll(newItems);
     }
 
+    private void finishGame() {
+        Output.printLine();
+        Output.printLine();
+        Output.print(Session.getGame().getEpilogue());
+
+        renderActionButtons();
+    }
+
+    private void renderMapImage() {
+        var room = Session.getGame().getCurrentRoom();
+
+        if (room.getMapImagePath().isEmpty()) {
+            return;
+        }
+
+        var image = loadImage(room.getMapImagePath().get());
+
+        mapContainer.setImage(image);
+    }
+
     private Button createActionButton(String label, ButtonData buttonData) {
         Button actionButton = new Button(label);
 
@@ -176,12 +232,30 @@ public class GameController implements Observer {
         return actionButton;
     }
 
-    private void finishGame() {
-        inputButtonContainer.getChildren().clear();
-        inventoryContainer.getChildren().clear();
+    private Button createInventoryButton(String label, ButtonData buttonData, String imagePath) {
+        Button inventoryButton = new Button(label);
 
-        Output.printLine();
-        Output.printLine();
-        Output.print(Session.getGame().getEpilogue());
+        inventoryButton.setUserData(buttonData);
+        inventoryButton.setOnAction(this::exectuteAction);
+        inventoryButton.setMaxWidth(Double.MAX_VALUE);
+
+        if (imagePath != null) {
+            var image = loadImage(imagePath);
+
+            ImageView icon = new ImageView(image);
+
+            icon.setFitWidth(24);
+            icon.setFitHeight(24);
+            icon.setPreserveRatio(true);
+
+            inventoryButton.setGraphic(icon);
+        }
+
+        return inventoryButton;
+    }
+
+    private Image loadImage(String imagePath) {
+        var imageResource = Objects.requireNonNull(getClass().getResource(imagePath)).toExternalForm();
+        return new Image(imageResource);
     }
 }

+ 5 - 0
src/main/java/eu/oschl/gui/Observable.java

@@ -3,6 +3,11 @@ package eu.oschl.gui;
 import java.util.HashSet;
 import java.util.Set;
 
+/**
+ * Observable class for implementing the Observer design pattern.
+ *
+ * @author Ondřej Schlaichert
+ */
 public abstract class Observable {
     protected Set<Observer> observers = new HashSet<>();
 

+ 5 - 0
src/main/java/eu/oschl/gui/Observer.java

@@ -1,5 +1,10 @@
 package eu.oschl.gui;
 
+/**
+ * Observer interface for implementing the Observer design pattern.
+ *
+ * @author Ondřej Schlaichert
+ */
 public interface Observer {
     void update();
 }

+ 5 - 0
src/main/java/eu/oschl/gui/Output.java

@@ -4,6 +4,11 @@ import javafx.scene.paint.Color;
 import javafx.scene.text.Text;
 import javafx.scene.text.TextFlow;
 
+/**
+ * Utility class for managing output display in the GUI and printing messages with colours.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class Output {
     private static TextFlow outputElement;
 

+ 98 - 3
src/main/java/eu/oschl/gui/Session.java

@@ -1,14 +1,31 @@
 package eu.oschl.gui;
 
+import eu.oschl.schmorn.Setup;
 import eu.oschl.textadventure.Game;
 import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.event.Event;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.Scene;
+import javafx.scene.control.Alert;
+import javafx.scene.control.ButtonType;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.scene.input.KeyCombination;
+import javafx.scene.text.Font;
+import javafx.scene.web.WebView;
 import javafx.stage.Stage;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Objects;
+import java.util.Optional;
 
+/**
+ * Main session class for managing the game state and launching the GUI.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class Session extends Application {
     private static Game game;
     private static ActionProcessor actionProcessor;
@@ -21,24 +38,102 @@ public class Session extends Application {
         return actionProcessor;
     }
 
-    public static void launchGui(Game game, String[] args)
+    public static void launchGui(String[] args)
     {
-        Session.game = game;
+        createNewGame();
+
         Session.actionProcessor = ActionProcessor.create(game);
 
         Application.launch(Session.class, args);
     }
 
+    private static void createNewGame() {
+        Session.game = Setup.createGame();
+
+        if (Session.actionProcessor != null) {
+            Session.actionProcessor.changeGame(Session.game);
+        } else {
+            Session.actionProcessor = ActionProcessor.create(Session.game);
+        }
+
+        Session.actionProcessor.sendEvent();
+    }
+
     @Override
     public void start(Stage stage) throws IOException {
         FXMLLoader fxmlLoader = new FXMLLoader(Session.class.getResource("game.fxml"));
         Scene scene = new Scene(fxmlLoader.load(), 1280, 720);
 
-        String cssPath = Objects.requireNonNull(Session.class.getResource("css/style.css")).toExternalForm();
+        try (InputStream fontStream = Session.class.getResourceAsStream("fonts/Iosevka-Slab-01.ttf")) {
+            Font.loadFont(fontStream, 10);
+        } catch (IOException _) {
+        }
+
+        var cssPath = Objects.requireNonNull(Session.class.getResource("css/style.css")).toExternalForm();
         scene.getStylesheets().add(cssPath);
 
         stage.setTitle("Schmorn");
         stage.setScene(scene);
+
+        stage.setOnCloseRequest(event -> handleCloseRequest(stage, event));
+
+        KeyCombination restartKeyCombination = new KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN);
+        scene.getAccelerators().put(restartKeyCombination, () -> handleRestartRequest(stage));
+
+        KeyCombination helpKeyCombination = new KeyCodeCombination(KeyCode.F1);
+        scene.getAccelerators().put(helpKeyCombination, this::handleHelpRequest);
+
         stage.show();
     }
+
+    private void handleCloseRequest(Stage stage, Event event) {
+        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
+        alert.initOwner(stage);
+        alert.setTitle("Quit Game");
+        alert.setHeaderText("You are about to quit playing.");
+        alert.setContentText("Are you sure you want to quit?");
+
+        Optional<ButtonType> result = alert.showAndWait();
+
+        if (result.isPresent() && result.get() == ButtonType.OK) {
+            Platform.exit();
+        } else {
+            event.consume();
+        }
+    }
+
+    private void handleRestartRequest(Stage stage) {
+        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
+        alert.initOwner(stage);
+        alert.setTitle("Restart Game");
+        alert.setHeaderText("You are about to restart the game.");
+        alert.setContentText("Are you sure you want to restart?");
+
+        Optional<ButtonType> result = alert.showAndWait();
+
+        if (result.isPresent() && result.get() == ButtonType.OK) {
+            createNewGame();
+
+            Output.clear();
+            Output.print(game.getPrologue());
+        }
+    }
+
+    private void handleHelpRequest() {
+        var helpStage = new Stage();
+        WebView webView = new WebView();
+
+        Scene helpScene = new Scene(webView);
+
+        helpStage.setScene(helpScene);
+        helpStage.setTitle("Schmorn Help");
+        helpStage.show();
+
+        var helpPath = Objects.requireNonNull(Session.class.getResource("help.html")).toExternalForm();
+
+        webView.getEngine().load(helpPath);
+
+        helpStage.setWidth(1280);
+        helpStage.setHeight(720);
+    }
 }

+ 1 - 1
src/main/java/eu/oschl/gui/actions/Action.java

@@ -1,7 +1,7 @@
 package eu.oschl.gui.actions;
 
 /***
- * This interface defines the structure for commands in the console application.
+ * This interface defines the structure for actions in the GUI application.
  *
  * @author Ondřej Schlaichert
  */

+ 6 - 0
src/main/java/eu/oschl/gui/actions/Enter.java

@@ -6,6 +6,11 @@ import eu.oschl.textadventure.exceptions.InvalidGameState;
 import eu.oschl.textadventure.map.Passage;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for entering a passage to another room.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class Enter implements Action {
     private final Game game;
 
@@ -42,6 +47,7 @@ public class Enter implements Action {
             }
         }
 
+        assert passage != null;
         var printEnterText = !passage.getOtherRoom(game.getCurrentRoom()).wasEntered();
 
         var result = passage.passThrough(false);

+ 7 - 0
src/main/java/eu/oschl/gui/actions/Explore.java

@@ -5,6 +5,11 @@ import eu.oschl.textadventure.Game;
 import eu.oschl.textadventure.map.Passage;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for exploring the current room and displaying its details.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class Explore implements Action {
     private final Game game;
 
@@ -32,6 +37,8 @@ public class Explore implements Action {
         var objects = room.getObjects();
         var passages = room.getPassages();
 
+        room.setExplored(true);
+
         Output.print(room.getName(), Color.ALICEBLUE);
         Output.printLine();
         Output.print(room.getDescription(), Color.LIGHTBLUE);

+ 5 - 0
src/main/java/eu/oschl/gui/actions/PressButton.java

@@ -5,6 +5,11 @@ import eu.oschl.textadventure.Game;
 import eu.oschl.textadventure.objects.Button;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for pressing a button in the current room.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class PressButton implements Action {
     private final Game game;
 

+ 30 - 0
src/main/java/eu/oschl/gui/actions/Quit.java

@@ -0,0 +1,30 @@
+package eu.oschl.gui.actions;
+
+import javafx.application.Platform;
+
+/**
+ * This action quits the game application.
+ *
+ * @author Ondřej Schlaichert
+ */
+public class Quit implements Action {
+    @Override
+    public String getId() {
+        return "quit";
+    }
+
+    @Override
+    public String getName() {
+        return "Quit game";
+    }
+
+    @Override
+    public String getDescription() {
+        return "quit the game";
+    }
+
+    @Override
+    public void execute(String[] args) {
+        Platform.exit();
+    }
+}

+ 5 - 0
src/main/java/eu/oschl/gui/actions/Slay.java

@@ -4,6 +4,11 @@ import eu.oschl.gui.Output;
 import eu.oschl.textadventure.Game;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for slaying an enemy in the current room.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class Slay implements Action {
     private final Game game;
 

+ 5 - 0
src/main/java/eu/oschl/gui/actions/TakeItem.java

@@ -6,6 +6,11 @@ import eu.oschl.textadventure.objects.PickableObject;
 import eu.oschl.textadventure.objects.Weapon;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for taking an item from the current room.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class TakeItem implements Action {
     private final Game game;
 

+ 5 - 0
src/main/java/eu/oschl/gui/actions/UseItem.java

@@ -4,6 +4,11 @@ import eu.oschl.gui.Output;
 import eu.oschl.textadventure.Game;
 import javafx.scene.paint.Color;
 
+/**
+ * Action for taking an item from the current room.
+ *
+ * @author Ondřej Schlaichert
+ */
 public class UseItem implements Action {
     private final Game game;
 

+ 35 - 0
src/main/java/eu/oschl/schmorn/Launcher.java

@@ -0,0 +1,35 @@
+package eu.oschl.schmorn;
+
+import eu.oschl.textadventure.Game;
+
+/**
+ * Handles starting either CLI or GUI version of the game
+ *
+ * @author Ondřej Schlaichert
+ */
+public class Launcher {
+    private static String[] args;
+
+    public static void setArgs(String[] args) {
+        Launcher.args = args;
+    }
+
+    public static void startGame() {
+        var useCli = Launcher.args.length > 0 && args[0].equalsIgnoreCase("--cli");
+
+        if (useCli) {
+            startCli(Setup.createGame());
+        } else {
+            startGui(args);
+        }
+    }
+
+    private static void startCli(Game game) {
+        var session = new eu.oschl.cli.Session(game);
+        session.start();
+    }
+
+    private static void startGui(String[] args) {
+        eu.oschl.gui.Session.launchGui(args);
+    }
+}

+ 3 - 21
src/main/java/eu/oschl/schmorn/Main.java

@@ -1,31 +1,13 @@
 package eu.oschl.schmorn;
 
-import eu.oschl.textadventure.Game;
-
 /**
- * Serves as an entry point, handles starting either CLI or GUI version of the game.
+ * Serves as an entry point, passes args to Launcher and starts the game.
  *
  * @author Ondřej Schlaichert
  */
 class Main {
     static void main(String[] args) {
-        var useCli = args.length > 0 && args[0].equalsIgnoreCase("--cli");
-
-        var game = Setup.createGame();
-
-        if (useCli) {
-            startCli(game);
-        } else {
-            startGui(game, args);
-        }
-    }
-
-    private static void startCli(Game game) {
-        var session = new eu.oschl.cli.Session(game);
-        session.start();
-    }
-
-    private static void startGui(Game game, String[] args) {
-        eu.oschl.gui.Session.launchGui(game, args);
+        Launcher.setArgs(args);
+        Launcher.startGame();
     }
 }

+ 63 - 25
src/main/java/eu/oschl/schmorn/Setup.java

@@ -14,7 +14,7 @@ import eu.oschl.textadventure.objects.Weapon;
  *
  * @author Ondřej Schlaichert
  */
-class Setup {
+public class Setup {
     public static Game createGame() {
         // Base game setup
         var prologue = """
@@ -67,84 +67,114 @@ class Setup {
         // Rooms
         var royalWell = new Room(
                 "Royal Well",
-                "The bottom of the deepest well of the Grey Princedom. Fortunately for the prince, there is no water in it."
+                "The bottom of the deepest well of the Grey Princedom. Fortunately for the prince, there is no water in it.",
+                null,
+                "images/map/royal_well.png"
         );
 
         var crossroads = new Room(
                 "Crossroads",
-                "A damp chamber in the Royal Dungeon, full of unnerving, dark tunnels and entrances to other locations."
+                "A damp chamber in the Royal Dungeon, full of unnerving, dark tunnels and entrances to other locations.",
+                null,
+                "images/map/crossroads.png"
         );
 
         var sewerEntrance = new Room(
                 "Sewer Entrance",
-                "An entrance room of the Royal Sewer."
+                "An entrance room of the Royal Sewer.",
+                null,
+                "images/map/sewer_entrance.png"
         );
 
         var swordsmithRatsLair = new Room(
                 "Swordsmith Rat's Lair",
                 "The lair of the Rat Swordsmith. He is a master of his craft, but he is also a rat.",
-                "Schmorn enters the chamber and is greeted by an unnerving sight. The Swordsmith Rat is lying on the floor, surrounded by his tools and weapons. He looks up at Schmorn with a mixture of fear and confusion - somehow, he seems to recognise Schmorn despite his new worm-like appearance. Once a swordsmith of the greatest reputation, he has been broken down by his imprisonment and has produced no remarkable weapons to speak of."
+                "Schmorn enters the chamber and is greeted by an unnerving sight. The Swordsmith Rat is lying on the floor, surrounded by his tools and weapons. He looks up at Schmorn with a mixture of fear and confusion - somehow, he seems to recognise Schmorn despite his new worm-like appearance. Once a swordsmith of the greatest reputation, he has been broken down by his imprisonment and has produced no remarkable weapons to speak of.",
+                "images/map/swordsmith_rats_lair.png"
         );
 
         var prisonEntrance = new Room(
                 "Prison Entrance",
-                "An entrance room to Schmorn's Royal Prison."
+                "An entrance room to Schmorn's Royal Prison.",
+                null,
+                "images/map/prison_entrance.png"
         );
 
         var cellA = new Room(
                 "Cell A",
-                "The first cell of the Royal Prison."
+                "The first cell of the Royal Prison.",
+                null,
+                "images/map/cell_a.png"
         );
 
         var cellB = new Room(
                 "Cell B",
-                "The second cell of the Royal Prison."
+                "The second cell of the Royal Prison.",
+                null,
+                "images/map/cell_b.png"
         );
 
         var guardRoom = new Room(
                 "Guard Room",
-                "In days long gone, when the Grey Princedom wasn't in disarray, this room was occuppied by a guard who took care of the prisoners."
+                "In days long gone, when the Grey Princedom wasn't in disarray, this room was occuppied by a guard who took care of the prisoners.",
+                null,
+                "images/map/guard_room.png"
         );
 
         var prisonsEnd = new Room(
                 "Prison's End",
-                "The prison does not continue beyond this point."
+                "The prison does not continue beyond this point.",
+                null,
+                "images/map/prisons_end.png"
         );
 
         var darkEntrance = new Room(
                 "Dark Entrance",
-                "An entrance to the deepest and darkest parts of the Royal Dungeon."
+                "An entrance to the deepest and darkest parts of the Royal Dungeon.",
+                null,
+                "images/map/dark_entrance.png"
         );
 
         var blackAltar = new Room(
                 "Black Altar",
                 "An enormous, menacing room, full of bones and dead bodies. The centerpiece is a large, black altar made of stone, surrounded by a circle of candles. On the surface are strange runes and symbols, which appear to be bleeding.",
-                "As Schmorn enters, fear and nausea overcomes him. The air is putrid, the room stinks of death. In the middle stands a stone altar, surrounded by candles. On the surface are strange runes and symbols, which appear to be bleeding. Schmorn knows he is not alone. There is a being here, one not of this world."
+                "As Schmorn enters, fear and nausea overcomes him. The air is putrid, the room stinks of death. In the middle stands a stone altar, surrounded by candles. On the surface are strange runes and symbols, which appear to be bleeding. Schmorn knows he is not alone. There is a being here, one not of this world.",
+                "images/map/black_altar.png"
         );
 
         var shadowChamber = new Room(
                 "Shadow Chamber",
-                "A dark chamber in the Royal Dungeon, where lanterns don't work and shadows reign."
+                "A dark chamber in the Royal Dungeon, where lanterns don't work and shadows reign.",
+                null,
+                "images/map/shadow_chamber.png"
         );
 
         var pathwaysEnd = new Room(
                 "Pathway's End",
-                "The Pathway of Darkness, the darkest part of the Royal Dungeon, does not continue beyond this point."
+                "The Pathway of Darkness, the darkest part of the Royal Dungeon, does not continue beyond this point.",
+                null,
+                "images/map/pathways_end.png"
         );
 
         var royalKitchensEntrance = new Room(
                 "Royal Kitchens Entrance",
-                "An entrance to the Royal Kitchens."
+                "An entrance to the Royal Kitchens.",
+                null,
+                "images/map/royal_kitchens_entrance.png"
         );
 
         var pantry = new Room(
                 "Pantry",
-                "A room with food and supplies for the Royal Kitchens."
+                "A room with food and supplies for the Royal Kitchens.",
+                null,
+                "images/map/pantry.png"
         );
 
         var kitchensEnd = new Room(
                 "Kitchen's End",
-                "The Royal Kitchens end here."
+                "The Royal Kitchens end here.",
+                null,
+                "images/map/kitchens_end.png"
         );
 
         var dungeonExit = new Room(
@@ -156,7 +186,8 @@ class Setup {
                         "And so, here you are, you determined failure of a man. You have made it this far, but you will not leave this place. Not as a worm, not as a prince, not as anything. I stand in your path, and I will not let you pass. You have made your choice, and now you must live with the consequences."
                     
                         Schmorn stares at her, fearful yet defiant. In his worm mouth, he holds the mighty Unbreakable Ladle, the most powerful weapon in his kingdom. He is ready to fight. Oglunda does not know what's coming.
-                        """
+                        """,
+                "images/map/dungeon_exit.png"
         );
 
         var royalWellCrossroadsPassage = new Passage("crack in the wall", true);
@@ -264,7 +295,8 @@ class Setup {
                 "ratsword",
                 "a steel sword, expertly crafted by the Swordsmith Rat",
                 "Schmorn attacks with the ratsword.",
-                10
+                10,
+                "images/items/ratsword.png"
         );
         swordsmithRatsLair.addObject(sword);
 
@@ -273,7 +305,8 @@ class Setup {
                 "a huge, menacing key, made out of black iron",
                 "Schmorn used the key to unlock the dark passage.",
                 new Room[]{crossroads},
-                crossroadsDarkEntrancePassageBlockage
+                crossroadsDarkEntrancePassageBlockage,
+                "images/items/dark_key.png"
         );
         guardRoom.addObject(darkKey);
 
@@ -282,7 +315,8 @@ class Setup {
                 "a small, golden, delicate key",
                 "Schmorn used the key to unlock the kitchen door.",
                 new Room[]{crossroads},
-                crossroadsRoyalKitchensEntrancePassageBlockage
+                crossroadsRoyalKitchensEntrancePassageBlockage,
+                "images/items/kitchen_key.png"
         );
         shadowChamber.addObject(kitchenKey);
 
@@ -291,7 +325,8 @@ class Setup {
                 "a mysteriously shaped stone that is so cold it hurts to touch",
                 "Schmorn inserted the stone into the lift panel.",
                 new Room[]{crossroads},
-                crossroadsDungeonExitPassageBlockage
+                crossroadsDungeonExitPassageBlockage,
+                "images/items/frozen_stone.png"
         );
         prisonsEnd.addObject(frozenStone);
 
@@ -300,7 +335,8 @@ class Setup {
                 "a blood-red stone, always wet with fresh blood, which cannot be washed off",
                 "Schmorn inserted the stone into the lift panel.",
                 new Room[]{crossroads},
-                crossroadsDungeonExitPassageBlockage
+                crossroadsDungeonExitPassageBlockage,
+                "images/items/blood_stone.png"
         );
         pathwaysEnd.addObject(bloodStone);
 
@@ -309,7 +345,8 @@ class Setup {
                 "a mysteriously shaped stone that is so hot it's almost impossible to carry",
                 "Schmorn inserted the stone into the lift panel.",
                 new Room[]{crossroads},
-                crossroadsDungeonExitPassageBlockage
+                crossroadsDungeonExitPassageBlockage,
+                "images/items/fire_stone.png"
         );
         kitchensEnd.addObject(fireStone);
 
@@ -317,7 +354,8 @@ class Setup {
                 "unbreakable ladle",
                 "a mighty weapon, the most prized possession of the Head Chef, stronger than any sword",
                 "Schmorn performs a powerful attack with the mighy Unbreakable Ladle.",
-                20
+                20,
+                "images/items/unbreakable_ladle.png"
         );
         royalKitchensEntrance.addObject(unbreakableLadle);
 

+ 21 - 2
src/main/java/eu/oschl/textadventure/map/Room.java

@@ -19,24 +19,31 @@ public class Room {
     private final String name;
     private final String description;
     private final String enterText;
+    private final String mapImagePath;
 
     private final HashSet<Passage> passages;
     private final ArrayList<GameObject> objects;
     private Enemy enemy;
 
+    private boolean explored;
     private boolean entered;
 
-    public Room(String name, String description, String enterText) {
+    public Room(String name, String description, String enterText, String mapImagePath) {
         this.name = name;
         this.description = description;
         this.enterText = enterText;
         this.passages = new HashSet<>();
         this.objects = new ArrayList<>();
         this.entered = false;
+        this.mapImagePath = mapImagePath;
+    }
+
+    public Room(String name, String description, String enterText) {
+        this(name, description, enterText, null);
     }
 
     public Room(String name, String description) {
-        this(name, description, null);
+        this(name, description, null, null);
     }
 
     /**
@@ -92,6 +99,18 @@ public class Room {
         return entered;
     }
 
+    public boolean isExplored() {
+        return explored;
+    }
+
+    public void setExplored(boolean explored) {
+        this.explored = explored;
+    }
+
+    public Optional<String> getMapImagePath() {
+        return Optional.ofNullable(mapImagePath);
+    }
+
     /**
      * Checks if the room is blocked by an enemy.
      * An enemy is considered to block the room if it is present and alive.

+ 7 - 0
src/main/java/eu/oschl/textadventure/objects/InventoryItem.java

@@ -15,6 +15,13 @@ public class InventoryItem extends PickableObject {
     private final Room[] canBeUsedIn;
     private final Blockage interactsWith;
 
+    public InventoryItem(String name, String description, String useText, Room[] canBeUsedIn, Blockage interactsWith, String iconImagePath) {
+        super(name, description, iconImagePath);
+        this.useText = useText;
+        this.canBeUsedIn = canBeUsedIn;
+        this.interactsWith = interactsWith;
+    }
+
     public InventoryItem(String name, String description, String useText, Room[] canBeUsedIn, Blockage interactsWith) {
         super(name, description);
         this.useText = useText;

+ 16 - 0
src/main/java/eu/oschl/textadventure/objects/PickableObject.java

@@ -1,5 +1,7 @@
 package eu.oschl.textadventure.objects;
 
+import java.util.Optional;
+
 /**
  * Represents an object in the game that can be picked up by the player.
  * This class serves as a base for all pickable objects, providing common properties and methods.
@@ -7,8 +9,22 @@ package eu.oschl.textadventure.objects;
  * @author Ondřej Schlaichert
  */
 public abstract class PickableObject extends GameObject {
+    private final String iconImagePath;
+
+    public PickableObject(String name, String description, String iconImagePath) {
+        super(name, description);
+
+        this.iconImagePath = iconImagePath;
+    }
+
     public PickableObject(String name, String description) {
         super(name, description);
+
+        this.iconImagePath = null;
+    }
+
+    public Optional<String> getIconImagePath() {
+        return Optional.ofNullable(iconImagePath);
     }
 
     /**

+ 6 - 0
src/main/java/eu/oschl/textadventure/objects/Weapon.java

@@ -9,6 +9,12 @@ public class Weapon extends PickableObject {
     public final String attackText;
     public final int damage;
 
+    public Weapon(String name, String description, String attackText, int damage, String iconImagePath) {
+        super(name, description, iconImagePath);
+        this.attackText = attackText;
+        this.damage = damage;
+    }
+
     public Weapon(String name, String description, String attackText, int damage) {
         super(name, description);
         this.attackText = attackText;

+ 3 - 0
src/main/java/module-info.java

@@ -1,7 +1,10 @@
 module eu.oschl.gui {
     requires javafx.controls;
     requires javafx.fxml;
+    requires javafx.web;
 
     opens eu.oschl.gui to javafx.fxml;
     exports eu.oschl.gui;
+    exports eu.oschl.schmorn;
+    opens eu.oschl.schmorn to javafx.fxml;
 }

+ 21 - 17
src/main/resources/eu/oschl/gui/css/style.css

@@ -1,8 +1,3 @@
-@font-face {
-	font-family: "Iosevka Slab";
-	src: url("fonts/SGr-IosevkaSlab-Regular.ttc");
-}
-
 .root {
 	-fx-background-color: #000000;
 	-fx-font-family: "Iosevka Slab", serif;
@@ -108,32 +103,28 @@
 }
 
 .inventory-item {
-	/* Base style: No background, no border, transparent */
 	-fx-background-color: transparent;
 	-fx-border-color: transparent;
-	-fx-border-width: 1px; /* Keep border-width for smooth hover transition */
+	-fx-border-width: 1px;
 	-fx-background-radius: 0;
 	-fx-border-radius: 0;
-	-fx-padding: 6px 12px; /* Inherit or define padding */
+	-fx-padding: 6px 12px;
 }
 
 .inventory-item:hover {
-	/* Hover state: Opaque border (select box) */
-	-fx-background-color: transparent; /* No background change */
-	-fx-border-color: #e0e0e0; /* Opaque white/light-gray border */
-	-fx-text-fill: #ffffff; /* Slightly brighter text */
+	-fx-background-color: transparent;
+	-fx-border-color: #e0e0e0;
+	-fx-text-fill: #ffffff;
 }
 
 .inventory-item:focused {
-	/* Focused state: Retain a visible focus indicator */
-	-fx-border-color: #aaaaaa; /* A clear, visible focus color */
+	-fx-border-color: #aaaaaa;
 	-fx-border-width: 1px;
 	-fx-background-color: transparent;
 }
 
 .inventory-item:pressed {
-	/* Pressed state: Slight visual feedback */
-	-fx-background-color: rgba(224, 224, 224, 0.1); /* Very subtle dark overlay */
+	-fx-background-color: rgba(224, 224, 224, 0.1);
 	-fx-border-color: #e0e0e0;
 }
 
@@ -146,9 +137,22 @@
 	-fx-opacity: 1 !important;
 }
 
-.button:hover { -fx-cursor: hand; }
+.button:hover {
+	-fx-cursor: hand;
+}
 
 .button:disabled,
 .button:disabled:hover {
 	-fx-cursor: default;
+}
+
+.dialog-pane {
+	-fx-background-color: #000000;
+	-fx-border-color: #555555;
+	-fx-border-width: 1px;
+}
+
+.dialog-pane .header-panel,
+.dialog-pane .button-bar {
+	-fx-background-color: transparent;
 }

BIN
src/main/resources/eu/oschl/gui/fonts/Iosevka-Slab-01.ttf


BIN
src/main/resources/eu/oschl/gui/fonts/SGr-IosevkaSlab-Regular.ttc


+ 2 - 8
src/main/resources/eu/oschl/gui/game.fxml

@@ -2,7 +2,6 @@
 
 <?import javafx.geometry.Insets?>
 <?import javafx.scene.control.ScrollPane?>
-<?import javafx.scene.image.Image?>
 <?import javafx.scene.image.ImageView?>
 <?import javafx.scene.layout.ColumnConstraints?>
 <?import javafx.scene.layout.GridPane?>
@@ -12,14 +11,10 @@
 
 <?import javafx.scene.layout.StackPane?>
 <?import javafx.scene.shape.Rectangle?>
-<?import javafx.scene.control.Button?>
-<GridPane xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1"
-          fx:controller="eu.oschl.gui.GameController">
-
+<GridPane xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="eu.oschl.gui.GameController">
     <columnConstraints>
         <ColumnConstraints hgrow="ALWAYS"/>
     </columnConstraints>
-
     <rowConstraints>
         <RowConstraints minHeight="10.0" percentHeight="75.0" vgrow="ALWAYS"/>
         <RowConstraints minHeight="10.0" percentHeight="25.0" vgrow="ALWAYS"/>
@@ -56,8 +51,7 @@
                 <clip>
                     <Rectangle width="${cell.width}" height="${cell.height}"/>
                 </clip>
-                <ImageView preserveRatio="true" fitWidth="${cell.width}">
-                    <Image url="@images/rooms/well.png"/>
+                <ImageView fx:id="mapContainer" preserveRatio="true" fitWidth="${cell.width}">
                 </ImageView>
             </StackPane>
             <ScrollPane fitToWidth="true" fitToHeight="true" GridPane.rowIndex="1">

+ 93 - 0
src/main/resources/eu/oschl/gui/help.html

@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Schmorn Help & Information</title>
+    <style>
+		body {
+			font-family: 'Iosevka Slab', monospace;
+            font-size: 1.3rem;
+			line-height: 1.6;
+			padding: 20px;
+			background-color: #000000;
+			color: #ffffff;
+			max-width: 800px;
+			margin: 0 auto;
+		}
+		h1 {
+			color: #ffffff;
+			border-bottom: 1px solid #ffffff;
+			padding-bottom: 10px;
+			margin-top: 0;
+			font-weight: 700;
+		}
+		h2 {
+			color: #ffffff;
+			margin-top: 25px;
+			font-weight: 700;
+		}
+		p {
+			margin-bottom: 15px;
+		}
+		ul {
+			list-style-type: none;
+			margin-left: 0;
+			padding-left: 0;
+		}
+		li {
+			margin-bottom: 8px;
+			padding-left: 1.2em;
+			position: relative;
+		}
+		li:before {
+			content: '-';
+			position: absolute;
+			left: 0;
+			color: #ffffff;
+		}
+		code {
+			background-color: #333333;
+			padding: 2px 4px;
+			border-radius: 2px;
+			font-family: 'Iosevka Slab', monospace;
+			color: #ffffff;
+		}
+		strong {
+			color: #ffffff;
+		}
+		hr {
+			border: none;
+			border-top: 1px solid #555555;
+			margin: 30px 0;
+		}
+    </style>
+</head>
+<body>
+
+<h1>Schmorn Help</h1>
+<p><strong>Schmorn</strong> is a simple text adventure game made in Java as part of the <strong>4IT115</strong> course at the <strong>Prague University of Economics and Business (VŠE)</strong>.</p>
+<p>The game tells a story of Schmorn, a weak, inept and power-hungry prince, who gets turned into a worm as a punishment for seeking unlimited power from Oglunda, a powerful witch. The witch casts Schmorn into his Royal Well, forcing him to crawl through the Royal Underground to reach the surface and get his revenge.</p>
+
+<hr>
+
+<h2>How to play?</h2>
+<ul>
+    <li>All gameplay is handled by pressing appropriate buttons. Press buttons to explore, fight enemies, etc.</li>
+    <li>The inventory is also interactable: click on a collected item to use it.</li>
+    <li>Press <strong>Ctrl+R</strong> to restart the game at any time.</li>
+    <li>Press <strong>F1</strong> to show this help screen.</li>
+    <li>Run the game with the <code>--cli</code> argument to play in the command line interface.</li>
+</ul>
+
+<hr>
+
+<h2>Additional information</h2>
+<ul>
+    <li>Author: <strong>Ondřej Schlaichert</strong></li>
+    <li>Semester: <strong>ZS 2025/2026</strong></li>
+    <li>Version: <strong>1.0.0</strong></li>
+</ul>
+
+</body>
+</html>

BIN
src/main/resources/eu/oschl/gui/images/items/blood_stone.png


BIN
src/main/resources/eu/oschl/gui/images/items/dark_key.png


BIN
src/main/resources/eu/oschl/gui/images/items/fire_stone.png


BIN
src/main/resources/eu/oschl/gui/images/items/frozen_stone.png


BIN
src/main/resources/eu/oschl/gui/images/items/kitchen_key.png


BIN
src/main/resources/eu/oschl/gui/images/items/ratsword.png


BIN
src/main/resources/eu/oschl/gui/images/items/unbreakable_ladle.png


BIN
src/main/resources/eu/oschl/gui/images/map/black_altar.png


BIN
src/main/resources/eu/oschl/gui/images/map/cell_a.png


BIN
src/main/resources/eu/oschl/gui/images/map/cell_b.png


BIN
src/main/resources/eu/oschl/gui/images/map/crossroads.png


BIN
src/main/resources/eu/oschl/gui/images/map/dark_entrance.png


BIN
src/main/resources/eu/oschl/gui/images/map/dungeon_exit.png


BIN
src/main/resources/eu/oschl/gui/images/map/guard_room.png


BIN
src/main/resources/eu/oschl/gui/images/map/kitchens_end.png


BIN
src/main/resources/eu/oschl/gui/images/map/pantry.png


BIN
src/main/resources/eu/oschl/gui/images/map/pathways_end.png


BIN
src/main/resources/eu/oschl/gui/images/map/prison_entrance.png


BIN
src/main/resources/eu/oschl/gui/images/map/prisons_end.png


BIN
src/main/resources/eu/oschl/gui/images/map/royal_kitchens_entrance.png


BIN
src/main/resources/eu/oschl/gui/images/map/royal_well.png


BIN
src/main/resources/eu/oschl/gui/images/map/sewer_entrance.png


BIN
src/main/resources/eu/oschl/gui/images/map/shadow_chamber.png


BIN
src/main/resources/eu/oschl/gui/images/map/swordsmith_rats_lair.png


BIN
src/main/resources/eu/oschl/gui/images/rooms/well.png