Browse Source

Funktionalität einiger Tiles erweitert, kleine Änderungen beim Umherziehen der Tiles, ResourceManager hinzugefügt zum Verwalten und hinzufügen der Ressourcen, Inventar erweitert zum Darstellen von Images, Main Menu Anfang (Welt-auswahl)

Jan 6 months ago
parent
commit
b1e5c10397
29 changed files with 665 additions and 201 deletions
  1. 382 127
      src/main/java/controller/GameController.java
  2. 18 12
      src/main/java/controller/GameMouseListener.java
  3. 0 4
      src/main/java/controller/InputHandler.java
  4. 0 4
      src/main/java/controller/MenuController.java
  5. 54 0
      src/main/java/controller/RessourceManager.java
  6. 4 1
      src/main/java/controller/entity/EntityController.java
  7. 2 2
      src/main/java/controller/tiles/interactive/InteractiveTileController.java
  8. 5 2
      src/main/java/controller/tiles/interactive/upgradeable/IronMineController.java
  9. 1 4
      src/main/java/controller/tiles/interactive/upgradeable/MineController.java
  10. 5 2
      src/main/java/controller/tiles/interactive/upgradeable/SawmillController.java
  11. 0 1
      src/main/java/main/Main.java
  12. 4 5
      src/main/java/model/Inventory.java
  13. 1 1
      src/main/java/model/items/ITEM_NAME.java
  14. 3 1
      src/main/java/model/items/Item.java
  15. 54 2
      src/main/java/model/tiles/InteractiveTileModel.java
  16. 1 1
      src/main/java/util/GAMESTATE.java
  17. 4 4
      src/main/java/view/Camera.java
  18. 20 2
      src/main/java/view/GamePanel.java
  19. 41 17
      src/main/java/view/InventoryView.java
  20. 38 0
      src/main/java/view/MainMenu.java
  21. 10 3
      src/main/java/view/UI.java
  22. 3 0
      src/main/java/view/entity/EntityManager.java
  23. 11 6
      src/main/java/view/popUpMenu/UpgradeMenu.java
  24. BIN
      src/main/resources/items/iron.png
  25. BIN
      src/main/resources/items/stone.png
  26. BIN
      src/main/resources/items/wood.png
  27. 2 0
      src/main/resources/lang/de_de.json
  28. 2 0
      src/main/resources/lang/en_us.json
  29. 0 0
      src/main/resources/lang/translation.json

+ 382 - 127
src/main/java/controller/GameController.java

@@ -8,6 +8,7 @@ import controller.tiles.interactive.*;
 import controller.tiles.interactive.upgradeable.*;
 import model.GameModel;
 import model.GameSaver;
+import model.Inventory;
 import model.entity.EntityModel;
 import model.entity.EntityType;
 import model.items.Item;
@@ -21,331 +22,585 @@ import view.tile.interactive.InteractiveTileView;
 import java.io.Serializable;
 import java.util.ArrayList;
 
+/**
+ * Controls the main game loop, input handling, entities, and interactive tiles.
+ */
 public class GameController implements Runnable, Serializable {
+
     public final String worldPath = "gamefiles/worlds/world_0.txt";
     private GameModel gameModel;
     private boolean running = true;
     public final int fps = 60;
 
-
     private transient KeyHandler keyHandler;
     private transient Thread gameThread;
+    private transient RessourceManager ressourceManager;
     private transient GamePanel view;
     public transient ArrayList<EntityController> entityControllers;
     public transient ArrayList<InteractiveTileController> interactiveTileControllers;
     private transient InteractiveTileController draggingTile;
     private transient int residualShiftX, residualShiftY;
+    private boolean gameActive;
 
-
+    /**
+     * Constructs a GameController, sets up model, view, input, inventory, entities, and interactive tiles.
+     */
     public GameController() {
-        this.keyHandler = new KeyHandler(this);
-        this.gameModel = new GameModel();
-        this.view = new GamePanel(this);
-        entityControllers = new ArrayList<>();
-        interactiveTileControllers = new ArrayList<>();
-        setStartInventory();
-        setupInteractiveTiles();
-        setupEntities();
+        initModel();
+        initView();
+        initInputHandler();
+        initControllerLists();
+        initializeStartInventory();
+        initializeInteractiveTiles();
+        initializeEntities();
+        initResourceManager();
         view.loadMap(worldPath);
     }
 
-    private void setupInteractiveTiles() {
-        LighthouseController lighthouse = new LighthouseController(this, setupInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE));
-        addInteractiveTile(lighthouse);
-
-        MineController mineController = new MineController(this, setupInteractiveTileModel(25,20, InteractiveTileType.MINE));
-        addInteractiveTile(mineController);
-
-        BarracksController barracksController = new BarracksController(this, setupInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS));
-        addInteractiveTile(barracksController);
-
-        IronMineController ironMineController = new IronMineController(this, setupInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE));
-        addInteractiveTile(ironMineController);
+    /**
+     * Creates a new ResourceManager
+     */
+    private void initResourceManager() {
+        ressourceManager = new RessourceManager(this);
+        ressourceManager.start();
+    }
 
-        AnimalEnclosureController animal = new AnimalEnclosureController(this, setupInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE));
-        addInteractiveTile(animal);
+    /**
+     * Initializes the GameModel.
+     */
+    private void initModel() {
+        this.gameModel = new GameModel();
+    }
 
-        SawmillController sawmillController = new SawmillController(this, setupInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL));
-        addInteractiveTile(sawmillController);
+    /**
+     * Initializes the GamePanel view.
+     */
+    private void initView() {
+        this.view = new GamePanel(this);
     }
 
-    private void setupEntities(){
-        VillagerController villager = new VillagerController(this, setupEntityModel(22,20, EntityType.VILLAGER));
-        addEntity(villager);
+    /**
+     * Initializes the key handler.
+     */
+    private void initInputHandler() {
+        this.keyHandler = new KeyHandler(this);
     }
 
-    private void addEntity(EntityController entityController) {
-        entityControllers.add(entityController);
+    /**
+     * Initializes lists for entity and interactive tile controllers.
+     */
+    private void initControllerLists() {
+        entityControllers = new ArrayList<>();
+        interactiveTileControllers = new ArrayList<>();
     }
 
-    private void addInteractiveTile(InteractiveTileController controller) {
-        interactiveTileControllers.add(controller);
+    /**
+     * Populates the starting inventory with basic items.
+     */
+    private void initializeStartInventory() {
+        Inventory inv = getModel().getInventory();
+        inv.addToInventory(new Item(ITEM_NAME.stone));
+        inv.addToInventory(new Item(ITEM_NAME.wood));
+    }
+
+    /**
+     * Sets up predefined interactive tiles in the world.
+     */
+    private void initializeInteractiveTiles() {
+        addInteractiveTileController(new LighthouseController(this,
+                createInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE)));
+        addInteractiveTileController(new MineController(this,
+                createInteractiveTileModel(25, 20, InteractiveTileType.MINE)));
+        addInteractiveTileController(new BarracksController(this,
+                createInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS)));
+        addInteractiveTileController(new IronMineController(this,
+                createInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE)));
+        addInteractiveTileController(new AnimalEnclosureController(this,
+                createInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE)));
+        addInteractiveTileController(new SawmillController(this,
+                createInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL)));
+    }
+
+    /**
+     * Sets up predefined entities in the world.
+     */
+    private void initializeEntities() {
+        addEntityController(new VillagerController(this,
+                createEntityModel(22, 20, EntityType.VILLAGER)));
+    }
+
+    /**
+     * Adds an EntityController to the controller list.
+     *
+     * @param entityController the entity controller to add
+     */
+    private void addEntityController(EntityController entityController) {
+        entityControllers.add(entityController);
     }
 
-    private EntityModel setupEntityModel(int worldX, int worldY, EntityType type) {
-        EntityModel model = new EntityModel(worldX, worldY, getView().tileSize, getView().tileSize, type);
-        gameModel.addEntityModel(model);
+    /**
+     * Adds an InteractiveTileController to the controller list.
+     *
+     * @param tileController the interactive tile controller to add
+     */
+    private void addInteractiveTileController(InteractiveTileController tileController) {
+        interactiveTileControllers.add(tileController);
+    }
+
+    /**
+     * Creates and registers an EntityModel in the GameModel.
+     *
+     * @param worldX X position in world grid
+     * @param worldY Y position in world grid
+     * @param type   type of entity
+     * @return the created EntityModel
+     */
+    private EntityModel createEntityModel(int worldX, int worldY, EntityType type) {
+        int size = getView().tileSize;
+        EntityModel model = new EntityModel(worldX, worldY, size, size, type);
+        getModel().addEntityModel(model);
         return model;
     }
 
-    public InteractiveTileModel setupInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type){
+    /**
+     * Creates and registers an InteractiveTileModel in the GameModel.
+     *
+     * @param worldGridX X grid coordinate
+     * @param worldGridY Y grid coordinate
+     * @param type       type of interactive tile
+     * @return the created InteractiveTileModel
+     */
+    public InteractiveTileModel createInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type) {
         InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY, type);
-        gameModel.addInteractiveTileModel(model);
+        getModel().addInteractiveTileModel(model);
         return model;
     }
-    private void setStartInventory() {
-        gameModel.getInventory().addToInventory(new Item(ITEM_NAME.stone));
-        gameModel.getInventory().addToInventory(new Item(ITEM_NAME.water));
-        gameModel.getInventory().addToInventory(new Item(ITEM_NAME.wood));
-    }
 
-    public void setView(GamePanel gp){
-        view = gp;
+    /**
+     * Sets the GamePanel view.
+     *
+     * @param gp the GamePanel to set
+     */
+    public void setView(GamePanel gp) {
+        this.view = gp;
     }
 
+    /**
+     * Handles a click on the inventory UI.
+     *
+     * @param x screen x-coordinate of click
+     * @param y screen y-coordinate of click
+     */
     public void handleInventoryClick(int x, int y) {
         int slot = view.getInventoryView().getClickedInventorySlot(x, y);
-        gameModel.getInventory().select(slot);
+        getModel().getInventory().select(slot);
     }
 
+    /**
+     * Starts the main game loop and resource manager thread.
+     */
     public void startGameLoop() {
-        gameThread = new Thread(this);
+        gameActive = true;
+        gameThread = new Thread(this, "GameLoopThread");
         gameThread.start();
     }
 
+    /**
+     * Stops the main game loop.
+     */
     public void stopGameLoop() {
-        running = false;
+        gameActive = false;
     }
 
+    /**
+     * Performs update logic once per frame.
+     * Updates camera or handles save state depending on game state.
+     */
     public void update() {
-        if (view.gameState == GAMESTATE.PLAY || view.gameState == GAMESTATE.INVENTORY) {
-            view.camera.update();
-        }
-        if(view.gameState == GAMESTATE.SAVE){
-            GameSaver.saveGame(this);
-            view.gameState = GAMESTATE.PLAY;
+        GAMESTATE state = view.gameState;
+        if (state == GAMESTATE.PLAY || state == GAMESTATE.INVENTORY) {
+            updateCamera();
+        } else if (state == GAMESTATE.SAVE) {
+            performSaveAndResume();
         }
+    }
+
+    /**
+     * Updates the camera position.
+     */
+    private void updateCamera() {
+        view.camera.update();
+    }
 
+    /**
+     * Saves the game and returns to PLAY state.
+     */
+    private void performSaveAndResume() {
+        GameSaver.saveGame(this);
+        view.gameState = GAMESTATE.PLAY;
     }
 
+    /**
+     * The main run loop implementing Runnable.
+     * Controls timing for updates and rendering.
+     */
     @Override
     public void run() {
+        runGameLoop();
+    }
+
+    /**
+     * Implements the game loop timing logic based on fps.
+     */
+    private void runGameLoop() {
         double drawInterval = 1_000_000_000.0 / fps;
         double delta = 0;
         long lastTime = System.nanoTime();
-        long currentTime;
         long timer = 0;
         int drawCount = 0;
 
         while (running) {
-            currentTime = System.nanoTime();
+            long currentTime = System.nanoTime();
             delta += (currentTime - lastTime) / drawInterval;
             timer += (currentTime - lastTime);
             lastTime = currentTime;
 
             if (delta >= 1) {
-                update();           // Logic update
-                view.repaint();     // Triggers paintComponent in view
-                moveEntities();
+                if(gameActive){
+                    update();
+                    moveAllEntities();
+                }
+                view.repaint();
                 delta--;
                 drawCount++;
             }
 
             if (timer >= 1_000_000_000) {
+                // Could log fps: drawCount
                 drawCount = 0;
                 timer = 0;
             }
         }
     }
 
-    private void moveEntities() {
-        if(entityControllers == null) return;
-        for(EntityController entityController : entityControllers){
+    /**
+     * Invokes movement logic on all entity controllers.
+     */
+    private void moveAllEntities() {
+        if (entityControllers == null) return;
+        for (EntityController entityController : entityControllers) {
             entityController.convertRepaintSpeedToMovementLogic();
         }
     }
 
-    public void zoomInOut(int i) {
-        view.zoomInOut(i);
+    /**
+     * Zooms camera in or out and closes any open menus.
+     *
+     * @param amount positive to zoom in, negative to zoom out
+     */
+    public void zoomInOut(int amount) {
+        view.zoomInOut(amount);
         view.closeMenus();
     }
 
+    /**
+     * Toggles between PLAY and PAUSED or exits INVENTORY state.
+     */
     public void togglePauseOrExitInventory() {
-        if (view.gameState == GAMESTATE.INVENTORY) {
+        GAMESTATE state = view.gameState;
+        if (state == GAMESTATE.INVENTORY) {
             view.gameState = GAMESTATE.PLAY;
-        } else if (view.gameState == GAMESTATE.PLAY) {
+        } else if (state == GAMESTATE.PLAY) {
             view.gameState = GAMESTATE.PAUSED;
-        } else if (view.gameState == GAMESTATE.PAUSED) {
+        } else if (state == GAMESTATE.PAUSED) {
             view.gameState = GAMESTATE.PLAY;
         }
     }
 
+    /**
+     * Toggles the inventory UI: enters or exits INVENTORY state.
+     * Deselects inventory item when closing.
+     */
     public void toggleInventory() {
         if (view.gameState == GAMESTATE.INVENTORY) {
             view.gameState = GAMESTATE.PLAY;
-            gameModel.getInventory().deselect();
+            getModel().getInventory().deselectAll();
         } else if (view.gameState == GAMESTATE.PLAY) {
             view.gameState = GAMESTATE.INVENTORY;
         }
     }
-    public GamePanel getView(){
-        if(view == null){
-            setView(new GamePanel(this));
+
+    /**
+     * Returns the GamePanel view, creating if necessary.
+     *
+     * @return the GamePanel
+     */
+    public GamePanel getView() {
+        if (view == null) {
+            view = new GamePanel(this);
         }
         return view;
     }
 
+    /**
+     * Returns the GameModel, creating if necessary.
+     *
+     * @return the GameModel
+     */
     public GameModel getModel() {
-        if(gameModel == null) gameModel = new GameModel();
+        if (gameModel == null) {
+            gameModel = new GameModel();
+        }
         return gameModel;
     }
 
+    /**
+     * Returns the KeyHandler, creating if necessary.
+     *
+     * @return the KeyHandler
+     */
     public KeyHandler getKeyHandler() {
-        if(keyHandler == null) keyHandler = new KeyHandler(this);
+        if (keyHandler == null) {
+            keyHandler = new KeyHandler(this);
+        }
         return keyHandler;
     }
 
-    public void loadWorld(){
-        if(view == null) this.view = new GamePanel(this);
+    /**
+     * Loads the world from the default worldPath.
+     */
+    public void loadWorld() {
+        if (view == null) {
+            view = new GamePanel(this);
+        }
         view.loadMap(worldPath);
     }
+
+    /**
+     * Asks the view to generate a new world.
+     */
     public void generateNewWorld() {
-        view.generateNewWorld();
+        getView().generateNewWorld();
     }
 
+    /**
+     * Handles dragging shifts in screen coordinates, converting to world-grid movement.
+     *
+     * @param dx pixel shift in x
+     * @param dy pixel shift in y
+     */
     public void handleTileShift(int dx, int dy) {
         if (draggingTile == null) {
             return;
         }
-        // Accumulate residual pixel movement:
+        accumulateResidualShift(dx, dy);
+        applyGridShiftIfNeeded();
+    }
+
+    /**
+     * Accumulates residual pixel shifts before converting to grid movement.
+     *
+     * @param dx pixel delta x
+     * @param dy pixel delta y
+     */
+    private void accumulateResidualShift(int dx, int dy) {
         residualShiftX += dx;
         residualShiftY += dy;
+    }
 
+    /**
+     * Checks if enough residual has accumulated to shift by whole tiles, and applies if valid.
+     */
+    private void applyGridShiftIfNeeded() {
         int tileSize = getView().tileSize;
-
-        // Compute whole-tile shifts:
         int gridShiftX = residualShiftX / tileSize;
         int gridShiftY = residualShiftY / tileSize;
-
         if (gridShiftX == 0 && gridShiftY == 0) {
-            return; // not enough movement yet
+            return;
         }
-
-        // Subtract the used pixels, keep leftover:
+        // Remove used pixels
         residualShiftX -= gridShiftX * tileSize;
         residualShiftY -= gridShiftY * tileSize;
 
-        // Now shift the stored tile model:
+        attemptTilePositionShift(gridShiftX, gridShiftY);
+    }
+
+    /**
+     * Attempts to shift the dragging tile model by given grid offsets. Reverts residuals if invalid.
+     *
+     * @param gridShiftX number of tiles to shift in x
+     * @param gridShiftY number of tiles to shift in y
+     */
+    private void attemptTilePositionShift(int gridShiftX, int gridShiftY) {
         InteractiveTileModel model = draggingTile.getModel();
         int oldX = model.getWorldGridX();
         int oldY = model.getWorldGridY();
         int newX = oldX + gridShiftX;
         int newY = oldY + gridShiftY;
 
-        // OPTIONAL: check bounds/collisions before applying:
         if (!isValidPosition(newX, newY)) {
-            // If invalid, you may want to revert residuals or clamp:
-            // e.g., undo the part of residual that caused invalid shift:
-            // residualShiftX += gridShiftX * tileSize;
-            // residualShiftY += gridShiftY * tileSize;
-            //System.out.printf("Cannot shift tile to (%d,%d): out of bounds or collision%n", newX, newY);
+            // Revert residual since shift is invalid
+            int tileSize = getView().tileSize;
+            residualShiftX += gridShiftX * tileSize;
+            residualShiftY += gridShiftY * tileSize;
             return;
         }
 
         model.setWorldGridX(newX);
         model.setWorldGridY(newY);
-        //System.out.printf("Tile shifted from (%d, %d) to (%d, %d)%n", oldX, oldY, newX, newY);
     }
 
+    /**
+     * Checks if draggingTile can be placed at new grid coordinates without out-of-bounds or collision.
+     *
+     * @param newX target grid X
+     * @param newY target grid Y
+     * @return true if valid position
+     */
     private boolean isValidPosition(int newX, int newY) {
-        if (draggingTile == null) return false;
-
+        if (draggingTile == null) {
+            return false;
+        }
         InteractiveTileModel model = draggingTile.getModel();
-        InteractiveTileView view = draggingTile.getView();
-
-        int width = view.getScaleX();  // how many tiles wide
-        int height = view.getScaleY(); // how many tiles high
-
-        // Check if tile stays within world bounds
-        if (newX < 0 || newY < 0 ||
-                newX + width > GamePanel.maxWorldCol ||
-                newY + height > GamePanel.maxWorldRow) {
+        InteractiveTileView tileView = draggingTile.getView();
+        int width = tileView.getScaleX();
+        int height = tileView.getScaleY();
+
+        // Check world bounds
+        if (newX < 0 || newY < 0
+                || newX + width > GamePanel.maxWorldCol
+                || newY + height > GamePanel.maxWorldRow) {
             return false;
         }
-
-        // Check each tile the dragged tile would occupy
+        // Check collisions
         for (int x = newX; x < newX + width; x++) {
             for (int y = newY; y < newY + height; y++) {
-                InteractiveTileController occupyingTile = getTileAt(x, y);
-                if (occupyingTile != null && occupyingTile != draggingTile) {
-                    return false; // collision
+                InteractiveTileController other = getTileAt(x, y);
+                if (other != null && other != draggingTile) {
+                    return false;
                 }
             }
         }
-
         return true;
     }
 
-    // Hilfsmethoden, um von Screen-Koordinaten in Weltkoordinaten umzurechnen
+    /**
+     * Converts a screen X coordinate to world grid X.
+     *
+     * @param screenX screen X in pixels
+     * @return world grid X coordinate
+     */
     public int screenToWorldX(int screenX) {
-        return (int)((getView().camera.worldX + screenX - getView().camera.screenX) / getView().tileSize);
+        GamePanel gp = getView();
+        return (gp.camera.worldX + screenX - gp.camera.screenX) / gp.tileSize;
     }
 
+    /**
+     * Converts a screen Y coordinate to world grid Y.
+     *
+     * @param screenY screen Y in pixels
+     * @return world grid Y coordinate
+     */
     public int screenToWorldY(int screenY) {
-        return (int)((getView().camera.worldY + screenY - getView().camera.screenY) / getView().tileSize);
+        GamePanel gp = getView();
+        return (gp.camera.worldY + screenY - gp.camera.screenY) / gp.tileSize;
     }
 
-    // Methode, um das Tile unter der aktuellen Weltposition zu bekommen
+    /**
+     * Returns the InteractiveTileController at the specified grid coordinates, or null if none.
+     *
+     * @param worldX grid X coordinate
+     * @param worldY grid Y coordinate
+     * @return the tile controller at that position, or null
+     */
     public InteractiveTileController getTileAt(int worldX, int worldY) {
+        if (interactiveTileControllers == null) {
+            return null;
+        }
         for (InteractiveTileController tile : interactiveTileControllers) {
             InteractiveTileModel model = tile.getModel();
-
-            if (   (worldX >= model.getWorldGridX()
-                    && worldX < model.getWorldGridX() + tile.getView().getScaleX()
-                    && worldY >= model.getWorldGridY()
-                    && worldY < model.getWorldGridY() + tile.getView().getScaleY())
-                    || (worldX == model.getWorldGridX() && worldY == model.getWorldGridY())) {
+            int tileX = model.getWorldGridX();
+            int tileY = model.getWorldGridY();
+            int width = tile.getView().getScaleX();
+            int height = tile.getView().getScaleY();
+
+            boolean withinX = (worldX >= tileX && worldX < tileX + width);
+            boolean withinY = (worldY >= tileY && worldY < tileY + height);
+            if (withinX && withinY) {
                 return tile;
             }
         }
         return null;
     }
 
-    public void setDraggingTile(InteractiveTileController tileAt) {
-        draggingTile = tileAt;
+    /**
+     * Sets the tile currently being dragged.
+     *
+     * @param tile the InteractiveTileController being dragged
+     */
+    public void setDraggingTile(InteractiveTileController tile) {
+        this.draggingTile = tile;
     }
 
+    /**
+     * Resets any accumulated residual pixel shift (e.g., when drag ends).
+     */
     public void resetResidualShift() {
         residualShiftX = 0;
         residualShiftY = 0;
     }
+
+    /**
+     * Loads interactive tiles and entities from the saved GameModel.
+     */
+    public void loadGame() {
+        loadInteractiveTilesFromSave();
+        loadEntitiesFromSave();
+    }
+
+    /**
+     * Re-initializes interactiveTileControllers from models in gameModel.
+     */
     private void loadInteractiveTilesFromSave() {
         interactiveTileControllers = new ArrayList<>();
-        for (InteractiveTileModel model : gameModel.getInteractiveTileModels()) {
+        for (InteractiveTileModel model : getModel().getInteractiveTileModels()) {
             InteractiveTileController controller = InteractiveTileFactory.createTile(this, model);
             if (controller != null) {
-                addInteractiveTile(controller);
+                addInteractiveTileController(controller);
             } else {
                 System.err.println("Unknown tile type: " + model.getTileType());
             }
         }
     }
 
+    /**
+     * Re-initializes entityControllers from models in gameModel.
+     */
     private void loadEntitiesFromSave() {
         entityControllers = new ArrayList<>();
-        for (EntityModel model : gameModel.getEntityModels()) {
+        for (EntityModel model : getModel().getEntityModels()) {
             EntityController controller = EntityFactory.createEntity(this, model);
             if (controller != null) {
-                addEntity(controller);
+                addEntityController(controller);
             } else {
                 System.err.println("Unknown entity type: " + model.getEntityType());
             }
         }
     }
 
-    public void loadGame() {
-        loadInteractiveTilesFromSave();
-        loadEntitiesFromSave();
+    /**
+     *  Initializes the Main Menu for changing worlds etc.
+     */
+    public void loadMainMenu() {
+
     }
 
+    public boolean isRunning() {
+        return running;
+    }
+
+    public void addToInventory(Item collected) {
+        getModel().getInventory().addToInventory(collected);
+    }
 }
+

+ 18 - 12
src/main/java/controller/GameMouseListener.java

@@ -24,19 +24,23 @@ public class GameMouseListener implements MouseListener, MouseMotionListener {
     }
     @Override
     public void mouseDragged(MouseEvent e) {
-        int diffY = e.getY() - lastX;
-        int diffX = e.getX() - lastY;
+        if(gamePanel.gameState == GAMESTATE.INVENTORY || gamePanel.gameState == GAMESTATE.PLAY){
+            int diffY = e.getY() - lastX;
+            int diffX = e.getX() - lastY;
 
-        if(SwingUtilities.isLeftMouseButton(e)){
+            if(SwingUtilities.isLeftMouseButton(e)){
 
-            camera.move(diffX, diffY);
-            gamePanel.closeMenus();
+                camera.move(diffX, diffY);
+                gamePanel.closeMenus();
 
-        }else if(SwingUtilities.isRightMouseButton(e)){
-            controller.handleTileShift(diffX, diffY);
+            }else if(SwingUtilities.isRightMouseButton(e)){
+                controller.handleTileShift(diffX, diffY);
+                gamePanel.closeMenus();
+            }
+            lastY = e.getX();
+            lastX = e.getY();
         }
-        lastY = e.getX();
-        lastX = e.getY();
+
     }
 
     @Override
@@ -46,15 +50,17 @@ public class GameMouseListener implements MouseListener, MouseMotionListener {
 
     @Override
     public void mouseClicked(MouseEvent e) {
-        if(gamePanel.gameState == GAMESTATE.PLAY ){
+        if(gamePanel.gameState == GAMESTATE.PLAY || gamePanel.gameState == GAMESTATE.INVENTORY){
             gamePanel.ui.handleClick(e.getX(), e.getY());
-        }else if (gamePanel.gameState == GAMESTATE.INVENTORY && e.getButton() == MouseEvent.BUTTON1) {
+        }
+        if (gamePanel.gameState == GAMESTATE.INVENTORY && e.getButton() == MouseEvent.BUTTON1) {
             controller.handleInventoryClick(e.getX(), e.getY());
         }else if(gamePanel.gameState == GAMESTATE.PAUSED){
             gamePanel.ui.handleMenuClick(e.getX(), e.getY());
+        }else if(gamePanel.gameState == GAMESTATE.MAIN_MENU){
+            gamePanel.handleMainMenuClick(e.getX(), e.getY());
         }
 
-
     }
 
     @Override

+ 0 - 4
src/main/java/controller/InputHandler.java

@@ -1,4 +0,0 @@
-package controller;
-
-public class InputHandler {
-}

+ 0 - 4
src/main/java/controller/MenuController.java

@@ -1,4 +0,0 @@
-package controller;
-
-public class MenuController {
-}

+ 54 - 0
src/main/java/controller/RessourceManager.java

@@ -0,0 +1,54 @@
+package controller;
+
+import controller.tiles.interactive.InteractiveTileController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+
+public class RessourceManager {
+    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+    private final GameController gameController;
+
+    public RessourceManager(GameController gameController) {
+        this.gameController = gameController;
+    }
+
+    public void start() {
+        scheduler.scheduleAtFixedRate(() -> {
+            if (!gameController.isRunning()) {
+                scheduler.shutdown();
+                return;
+            }
+            calculateResources();
+        }, 0, 1, TimeUnit.SECONDS);
+    }
+
+    public void stop() {
+        scheduler.shutdownNow();
+    }
+
+    private void calculateResources() {
+        // If interactiveTileControllers can change concurrently, consider making a snapshot:
+        List<InteractiveTileController> snapshot;
+        synchronized(gameController.interactiveTileControllers) {
+            snapshot = new ArrayList<>(gameController.interactiveTileControllers);
+        }
+        for (InteractiveTileController c : snapshot) {
+            int spI = c.getModel().getSecondsPerItem();
+            // Avoid division by zero or spI <= 0:
+            if (spI > 0) {
+                // You need to track elapsed seconds per controller or use a shared seconds counter:
+                // For simplicity, you could store a counter in each model:
+                c.getModel().incrementSecondCounter();
+                if (c.getModel().getSecondCounter() % spI == 0) {
+                    c.getModel().addItem();
+                    System.out.println("New amount: " + c.getModel().getItemAmount());
+                }
+            }
+        }
+    }
+}

+ 4 - 1
src/main/java/controller/entity/EntityController.java

@@ -3,6 +3,7 @@ package controller.entity;
 import controller.GameController;
 import controller.InteractiveController;
 import model.entity.EntityModel;
+import util.GAMESTATE;
 import view.Camera;
 import view.entity.EntityView;
 import view.popUpMenu.PopupMenu;
@@ -119,7 +120,9 @@ public abstract class EntityController implements InteractiveController {
     }
     public void convertRepaintSpeedToMovementLogic() {
         if(updateCount >= gameController.fps){
-            findPath();
+            if(gameController.getView().gameState == GAMESTATE.PLAY || gameController.getView().gameState == GAMESTATE.INVENTORY){
+                findPath();
+            }
             updateCount = 0;
         }else{
             updateCount++;

+ 2 - 2
src/main/java/controller/tiles/interactive/InteractiveTileController.java

@@ -11,7 +11,7 @@ import view.tile.interactive.InteractiveTileView;
 import java.awt.*;
 
 public abstract class InteractiveTileController implements InteractiveController {
-    private GameController gameController;
+    protected GameController gameController;
     private InteractiveTileView view;
     private InteractiveTileModel model;
     protected ONCLICKTYPE onclicktype;
@@ -22,7 +22,7 @@ public abstract class InteractiveTileController implements InteractiveController
     public InteractiveTileController(InteractiveTileModel model, InteractiveTileView view, GameController gameController){
         this.view = view;
         this.model = model;
-        this.gameController =  gameController;
+        this.gameController = gameController;
     }
 
     public void setModel(InteractiveTileModel model){

+ 5 - 2
src/main/java/controller/tiles/interactive/upgradeable/IronMineController.java

@@ -20,11 +20,14 @@ public class IronMineController extends InteractiveTileController {
 
     @Override
     public void upgrade() {
-
+        boolean condition = false;
+        if(condition){
+            getModel().upgrade();
+        }
     }
 
     @Override
     public void collect() {
-
+        gameController.addToInventory(getModel().collect());
     }
 }

+ 1 - 4
src/main/java/controller/tiles/interactive/upgradeable/MineController.java

@@ -27,9 +27,6 @@ public class MineController extends InteractiveTileController {
 
     @Override
     public void collect() {
-        boolean condition = false;
-        if(condition){
-            getModel().collect();
-        }
+        gameController.addToInventory(getModel().collect());
     }
 }

+ 5 - 2
src/main/java/controller/tiles/interactive/upgradeable/SawmillController.java

@@ -20,11 +20,14 @@ public class SawmillController extends InteractiveTileController {
 
     @Override
     public void upgrade() {
-
+        boolean condition = false;
+        if(condition){
+            getModel().upgrade();
+        }
     }
 
     @Override
     public void collect() {
-
+        gameController.addToInventory(getModel().collect());
     }
 }

+ 0 - 1
src/main/java/main/Main.java

@@ -22,7 +22,6 @@ public class Main {
 
         gameController.loadGame();
 
-        System.out.println("Starte Spiel...");
         JFrame window = new JFrame();
         window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
         window.setResizable(false);

+ 4 - 5
src/main/java/model/Inventory.java

@@ -45,14 +45,13 @@ public class Inventory implements Serializable {
 
     public void select(int clickedSlot) {
         if(clickedSlot != -1){
-            getItemList().forEach((item) -> {
-                item.setSelected(false);
-            });
-            getItemList().get(clickedSlot).setSelected();
+            boolean selected = getItemList().get(clickedSlot).isSelected();
+            deselectAll();
+            getItemList().get(clickedSlot).setSelected(!selected);
         }
     }
 
-    public void deselect() {
+    public void deselectAll() {
         getItemList().forEach((item) -> {
             item.setSelected(false);
         });

+ 1 - 1
src/main/java/model/items/ITEM_NAME.java

@@ -5,5 +5,5 @@ import java.io.Serializable;
 public enum ITEM_NAME implements Serializable {
     wood,
     stone,
-    water,
+    water, iron,
 }

+ 3 - 1
src/main/java/model/items/Item.java

@@ -1,5 +1,7 @@
 package model.items;
 
+import util.Translator;
+
 import java.io.Serializable;
 
 public class Item implements Serializable {
@@ -32,7 +34,7 @@ public class Item implements Serializable {
         return itemName;
     }
     public String getItemNamePlusCount(){
-        return itemName + ": " + count;
+        return Translator.translate("item." + itemName) + ": " + count;
     }
     public void addCount(int count){
         this.count += count;

+ 54 - 2
src/main/java/model/tiles/InteractiveTileModel.java

@@ -1,15 +1,24 @@
 package model.tiles;
 
+import model.items.ITEM_NAME;
 import model.items.Item;
 
 import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
 
 public class InteractiveTileModel implements Serializable {
     protected int worldGridX, worldGridY;
     private boolean clicked;
     private int level;
-    private Item items;
+    private Item item;
     private InteractiveTileType type;
+    private static final Map<ITEM_NAME, List<Integer>> secondsPerItem = Map.of(
+            ITEM_NAME.stone, List.of(2, 22, 18, 12),
+            ITEM_NAME.wood, List.of(2, 22, 18, 12),
+            ITEM_NAME.iron, List.of(2, 22, 18, 12)
+    );
+    private int secondsPassed;
 
     public InteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type) {
         this.worldGridX = worldGridX;
@@ -17,7 +26,31 @@ public class InteractiveTileModel implements Serializable {
         this.clicked = false;
         this.level = 1;
         this.type = type;
+        setupItem();
     }
+    public String getItemNamePlusCount(){
+        return item.getItemNamePlusCount();
+    }
+
+    private void setupItem(){
+        switch (type){
+            case MINE -> item = new Item(ITEM_NAME.stone);
+            case IRON_MINE -> item = new Item(ITEM_NAME.iron);
+            case SAWMILL -> item = new Item(ITEM_NAME.wood);
+            default -> item = new Item(ITEM_NAME.water);
+        }
+    }
+    public int getSecondsPerItem(){
+        List<Integer> secondsPerItem = null;
+        switch (type){
+            case MINE -> secondsPerItem = InteractiveTileModel.secondsPerItem.get(ITEM_NAME.stone);
+            case IRON_MINE -> secondsPerItem = InteractiveTileModel.secondsPerItem.get(ITEM_NAME.iron);
+            case SAWMILL -> secondsPerItem = InteractiveTileModel.secondsPerItem.get(ITEM_NAME.wood);
+            default -> secondsPerItem = List.of(50,50,50,50,50);
+        }
+        return secondsPerItem.get(level-1);
+    }
+
     public int getLevel(){
         return level;
     }
@@ -47,7 +80,7 @@ public class InteractiveTileModel implements Serializable {
     }
 
     public Item collect() {
-        return items.takeItems(items.getCount());
+        return item.takeItems(item.getCount());
     }
 
     public void setWorldGridX(int snappedX) {
@@ -61,4 +94,23 @@ public class InteractiveTileModel implements Serializable {
     public InteractiveTileType getTileType() {
         return type;
     }
+
+    public void addItem() {
+        item.addCount(1);
+    }
+
+    public int getItemAmount() {
+        return item.getCount();
+    }
+
+    public void incrementSecondCounter() {
+        if(secondsPassed >= getSecondsPerItem()){
+            secondsPassed = 0;
+        }
+        secondsPassed ++;
+    }
+
+    public int getSecondCounter() {
+        return secondsPassed;
+    }
 }

+ 1 - 1
src/main/java/util/GAMESTATE.java

@@ -5,5 +5,5 @@ public enum GAMESTATE {
     PAUSED,
     INVENTORY,
     QUIT,
-    SAVE
+    MAIN_MENU, SAVE
 }

+ 4 - 4
src/main/java/view/Camera.java

@@ -68,16 +68,16 @@ public class Camera{
 
     public void update(){
         if(keyH.upPressed){
-            move(0, -speed);
+            move(0, speed);
         }
         if(keyH.downPressed){
-            move(0, speed);
+            move(0, -speed);
         }
         if(keyH.leftPressed){
-            move(-speed, 0);
+            move(speed, 0);
         }
         if(keyH.rightPressed){
-            move(speed, 0);
+            move(-speed, 0);
         }
     }
 

+ 20 - 2
src/main/java/view/GamePanel.java

@@ -48,7 +48,7 @@ public class GamePanel extends JPanel{
     private PopupManager popupManager;
     private InventoryView inventoryView;
     public Camera camera;
-
+    private MainMenu mainMenu;
 
 
     public GamePanel(GameController controller) {
@@ -59,7 +59,7 @@ public class GamePanel extends JPanel{
         this.tileManager = new TileManager(this);
         this.entityManager = new EntityManager(this);
         this.popupManager = new PopupManager(this, new ArrayList<>(Arrays.asList(tileManager, entityManager)));
-
+        this.mainMenu = new MainMenu(this);
         Inventory inventory = gameController.getModel().getInventory();
         this.inventoryView = new InventoryView(inventory);
 
@@ -110,6 +110,7 @@ public class GamePanel extends JPanel{
 
         camera.worldX = (int)(camera.worldX * widthMultiplier);
         camera.worldY = (int)(camera.worldY * heightMultiplier);
+        camera.move(0,0);
     }
     public void closeMenus(){
         ui.closeMenus();
@@ -118,15 +119,25 @@ public class GamePanel extends JPanel{
     public InventoryView getInventoryView(){
         return inventoryView;
     }
+
     @Override
     public void paintComponent(Graphics g) {
         super.paintComponent(g);
         g2 = (Graphics2D) g;
 
+        if(gameState == GAMESTATE.MAIN_MENU){
+            //GameSaver.saveGame(gameController);
+            mainMenu.draw(g2);
+            g2.dispose();
+            return;
+        }
+
         tileManager.draw(g2);
         entityManager.draw(g2);
         popupManager.drawPopups(g2);
 
+
+
         if (gameState == GAMESTATE.INVENTORY) {
             inventoryView.drawInventoryOverlay(g2);
         }
@@ -135,6 +146,9 @@ public class GamePanel extends JPanel{
             GameSaver.saveGame(gameController);
             System.exit(0);
         }
+
+
+
         ui.draw(g2);
         g2.dispose();
     }
@@ -146,4 +160,8 @@ public class GamePanel extends JPanel{
     public double getZoom() {
         return originalTileSize/tileSize;
     }
+
+    public void handleMainMenuClick(int x, int y) {
+        mainMenu.handleClick(x,y);
+    }
 }

+ 41 - 17
src/main/java/view/InventoryView.java

@@ -1,10 +1,14 @@
 package view;
 
 import model.Inventory;
+import model.items.Item;
 import util.TextUtil;
 import util.Translator;
 
+import javax.imageio.ImageIO;
 import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
 
 public class InventoryView {
     private Inventory inventory;
@@ -22,33 +26,53 @@ public class InventoryView {
         int overlayWidth = slotSize + 2* slotSpacing;
         int overlayHeight = (slotSize + slotSpacing) * slotCount + slotSpacing;
 
-        // Background panel
-        g2.setColor(new Color(0, 0, 0, 160)); // semi-transparent black
+        g2.setColor(new Color(0, 0, 0, 160));
         g2.fillRoundRect(overlayX, overlayY, overlayWidth, overlayHeight, 15, 15);
 
-        // Draw slots
         for (int i = 0; i < slotCount; i++) {
-            if(inventory.getItemList().get(i).isSelected()){
-                g2.setColor(Color.WHITE);
-            }else{
-                g2.setColor(Color.LIGHT_GRAY);
-            }
-            int x = overlayX + slotSpacing;
-            int y = overlayY + slotSpacing + i * (slotSize + slotSpacing);
-            g2.fillRoundRect(x, y, slotSize, slotSize, 10, 10);
+            drawSlot(g2, i);
+        }
+    }
+
+    private void drawSlot(Graphics2D g2, int slot){
+        Item item = inventory.getItemList().get(slot);
 
-            g2.setColor(Color.DARK_GRAY);
+        if(item.isSelected()){
+            g2.setColor(Color.WHITE);
+        }else{
+            g2.setColor(Color.LIGHT_GRAY);
+        }
 
-            String itemName = inventory.getItemList().get(i).getItemName().toString();
+        int x = overlayX + slotSpacing;
+        int y = overlayY + slotSpacing + slot * (slotSize + slotSpacing);
 
-            TextUtil.setFontAppropriateToSize(itemName, slotSize - slotSpacing/2, g2);
+        g2.fillRoundRect(x, y, slotSize, slotSize, 10, 10);
+        g2.setColor(Color.DARK_GRAY);
 
-            g2.drawString(Translator.translate("item."+itemName), x + slotSpacing/4, y + slotSize / 2 + 5);
-            g2.drawString( "" + inventory.getItemList().get(i).getCount() , x + slotSize - slotSize/5, y + slotSize -2);
+        String itemName = item.getItemName().toString();
 
-            g2.setColor(Color.LIGHT_GRAY); // reset color for next slot
+        int offset = 20;
+        g2.drawImage(getImage("/items/" + itemName + ".png"), x + offset/2, y + offset/2, slotSize - offset, slotSize -offset, null);
+
+        //g2.drawString(Translator.translate("item."+itemName), x + slotSpacing/4, y + slotSize / 2 + 5);
+
+        FontMetrics fm = g2.getFontMetrics();
+        String amount = "" + item.getCount();
+        int amountWidth = fm.stringWidth(amount);
+        g2.drawString( amount , x + slotSize - amountWidth - 3, y + slotSize - 3);
+
+        g2.setColor(Color.LIGHT_GRAY);
+    }
+
+    public BufferedImage getImage(String imagePath){
+        try {
+            return ImageIO.read(getClass().getResourceAsStream(imagePath));
+        } catch (IOException e) {
+            e.printStackTrace();
         }
+        return null;
     }
+
     public int getClickedInventorySlot(int mouseX, int mouseY) {
         for (int i = 0; i < slotCount; i++) {
             int x = overlayX + slotSpacing;

+ 38 - 0
src/main/java/view/MainMenu.java

@@ -0,0 +1,38 @@
+package view;
+
+import util.GAMESTATE;
+import view.components.Button;
+
+import java.awt.*;
+import java.util.ArrayList;
+
+public class MainMenu {
+    GamePanel gamePanel;
+    private ArrayList<Button> activeButtons;
+    private Graphics2D g2;
+
+    public MainMenu(GamePanel gp){
+        this.gamePanel = gp;
+        activeButtons = new ArrayList<>();
+    }
+    public void draw(Graphics2D g2){
+        this.g2 = g2;
+        Button newGameButton = new Button(100, 100, "Hello", () -> {
+            gamePanel.gameState = GAMESTATE.PLAY;
+        });
+        drawAndRegisterButton(newGameButton, 10, 10);
+    }
+    public void handleClick(int screenX, int screenY) {
+        for (Button button : activeButtons) {
+            if (button.wasClicked(screenX, screenY)) {
+                button.click();
+                break;
+            }
+        }
+    }
+    private void drawAndRegisterButton(Button button, int buttonX, int buttonY){
+        button.setScreenCoordinates(buttonX, buttonY);
+        button.draw(g2);
+        activeButtons.add(button);
+    }
+}

+ 10 - 3
src/main/java/view/UI.java

@@ -40,6 +40,7 @@ public class UI {
             }
         }
     }
+
     public void handleClick(int screenX, int screenY){
         for (InteractiveTileController tile : gp.gameController.interactiveTileControllers) {
             handleClickForController(tile, screenX, screenY);
@@ -48,6 +49,7 @@ public class UI {
             handleClickForController(controller, screenX, screenY);
         }
     }
+
     private void handleClickForController(InteractiveController interactiveController, int screenX, int screenY){
         if(interactiveController.getClicked() && interactiveController.getOnClickType() == ONCLICKTYPE.POPUP){
             PopupMenu popupMenu = interactiveController.getPopupMenu();
@@ -66,8 +68,6 @@ public class UI {
     }
 
     private void drawPauseScreen(Graphics2D g2, String message) {
-
-
         // Background overlay
         g2.setColor(new Color(0, 0, 0, 150));
         g2.fillRect(0, 0, gp.screenWidth, gp.screenHeight);
@@ -96,7 +96,8 @@ public class UI {
         int buttonX = gp.screenWidth / 2 - buttonWidth / 2;
         int resumeY = boxY + 100;
         int saveY = resumeY + buttonHeight + spacing;
-        int exitY = resumeY + buttonHeight + buttonHeight + spacing + spacing;
+        int exitY = saveY + buttonHeight + spacing;
+        int menuY = exitY + buttonHeight + spacing;
         Button resumeButton = new Button(buttonWidth, buttonHeight, Translator.translate("menu.resume"), () -> {
             gp.gameState = GAMESTATE.PLAY;
         });
@@ -111,6 +112,11 @@ public class UI {
             gp.gameState = GAMESTATE.SAVE;
         });
         drawAndRegisterButton(saveButton, buttonX, saveY);
+
+        Button menuButton = new Button(buttonWidth, buttonHeight, Translator.translate("menu.main_menu"), () -> {
+            gp.gameState = GAMESTATE.MAIN_MENU;
+        });
+        drawAndRegisterButton(menuButton, buttonX, menuY);
     }
 
     private void drawAndRegisterButton(Button button, int buttonX, int buttonY){
@@ -118,6 +124,7 @@ public class UI {
         button.draw(g2);
         activeButtons.add(button);
     }
+
     public int getXForCenteredText(String text){
         int length = (int)g2.getFontMetrics().getStringBounds(text, g2).getWidth();
         return gp.screenWidth/2 - length/2;

+ 3 - 0
src/main/java/view/entity/EntityManager.java

@@ -2,6 +2,7 @@ package view.entity;
 
 import controller.entity.EntityController;
 import model.entity.EntityModel;
+import util.GAMESTATE;
 import view.GamePanel;
 import view.util.RenderingManager;
 
@@ -19,12 +20,14 @@ public class EntityManager implements RenderingManager {
     }
 
     public void draw(Graphics2D g2){
+
         for (EntityController entity : gamePanel.gameController.entityControllers) {
             EntityModel model = entity.getModel();
             entity.updateCoordinates(worldColToScreenX(model.getWorldX()), worldRowToScreenY(model.getWorldY()));
             entity.drawSprite(g2);
         }
     }
+
     public int getTileSize(){
         return gamePanel.tileSize;
     }

+ 11 - 6
src/main/java/view/popUpMenu/UpgradeMenu.java

@@ -14,12 +14,14 @@ public class UpgradeMenu extends PopupMenu {
         super(width, height, title);
         this.controller = controller;
         addButton( new Button(80, 25, Translator.translate("popup.upgrade"), this::upgrade), 10, 40 );
-        addButton( new Button(80,25, Translator.translate("popup.collect"),this::collect), 10, 70);
+        addButton( new Button(80,25, Translator.translate("popup.collect"), this::collect), 10, 70);
     }
+
     @Override
     public void draw(int x, int y, Graphics2D g2){
         FontMetrics fm = g2.getFontMetrics();
-        int msgWidth = fm.stringWidth(title);
+        String title_with_level = title + " (" + controller.getLevel() + ")";
+        int msgWidth = fm.stringWidth(title_with_level);
         if(overlayWidth < msgWidth) overlayWidth = msgWidth + 20;
 
         centerButtons();
@@ -29,11 +31,14 @@ public class UpgradeMenu extends PopupMenu {
         g2.setColor(Color.WHITE);
         g2.drawRoundRect(x,y,overlayWidth,overlayHeight, 15, 15);
 
-        g2.drawString(title, x + ((overlayWidth - msgWidth )/2), y+ 20);
+        g2.drawString(title_with_level, x + ((overlayWidth - msgWidth )/2), y+ 20);
+
+        String amountStr = controller.getModel().getItemNamePlusCount();
+
+        int amountStrWidth = fm.stringWidth(amountStr);
+
+        g2.drawString(amountStr, x + ((overlayWidth - amountStrWidth )/2), y + 35);
 
-        String levelStr = "Level: " + controller.getLevel();
-        int lvlStrWidth = fm.stringWidth(levelStr);
-        g2.drawString(levelStr, x + ((overlayWidth - lvlStrWidth )/2), y+ 35);
         for (Button button : buttonArrayList){
             button.setRelativeScreenCoordinates(x,y);
             button.draw(g2);

BIN
src/main/resources/items/iron.png


BIN
src/main/resources/items/stone.png


BIN
src/main/resources/items/wood.png


+ 2 - 0
src/main/resources/lang/de_de.json

@@ -5,11 +5,13 @@
   "menu.resume": "Fortsetzen",
   "menu.quit": "Beenden",
   "menu.save": "Speichern",
+  "menu.main_menu": "Hauptmenu",
   "popup.collect": "Sammeln",
   "popup.upgrade": "Verbessern",
   "item.wood": "Holz",
   "item.water": "Wasser",
   "item.stone": "Stein",
+  "item.iron": "Eisen",
   "popup.title.animal_enclosure": "Tierstall",
   "popup.title.barracks": "Kaserne",
   "popup.title.lighthouse": "Leuchtturm",

+ 2 - 0
src/main/resources/lang/en_us.json

@@ -5,11 +5,13 @@
   "menu.resume": "Resume",
   "menu.quit": "Quit",
   "menu.save": "Save",
+  "menu.main_menu": "Main Menu",
   "popup.collect": "Collect",
   "popup.upgrade": "Upgrade",
   "item.wood": "Wood",
   "item.water": "Water",
   "item.stone": "Stone",
+  "item.iron": "Iron",
   "popup.title.animal_enclosure": "Animal Enclosure",
   "popup.title.barracks": "Barracks",
   "popup.title.lighthouse": "Lighthouse",

+ 0 - 0
src/main/resources/lang/translation.json