Explorar el Código

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 hace 6 meses
padre
commit
b1e5c10397
Se han modificado 29 ficheros con 665 adiciones y 201 borrados
  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