From 905e13090fc6bdb16f36a879218a70f4088a457e Mon Sep 17 00:00:00 2001
From: Max Cherris <MCherris@protonmail.com>
Date: Mon, 3 Feb 2025 18:40:58 +0100
Subject: [PATCH 01/10] Add comment to calcState function

---
 src/game/Unit.hpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index 544c3d9..4814e7a 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -105,9 +105,14 @@ class Unit
         This function needs to be able to determine the possible movement-paths the unit can take
         MUST take into consideration that different units behave differently on certain terrain
         MUST show all movements possible
+        Requires dijkstras algorithm and the required graphs
         */
         void calculateMovement();
-
+        
+        /*
+        This function calculates the difference between current position and desired position.
+        It updates the unit_state accordingly, so that the units face the correct direction.
+        */
         void calcState(int posX, int posY);
 
         /*
-- 
GitLab


From d8fb0a0a2684803834de313001f42f5b2cb1df6c Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Tue, 4 Feb 2025 19:47:51 +0100
Subject: [PATCH 02/10] all Units get their attributes form the xml file, First
 parts of wavefront

---
 config.xml           |  4 ++--
 src/game/Config.cpp  | 47 ++++++++++++++++++---------------------
 src/game/Config.hpp  |  4 ++--
 src/game/Level.cpp   | 53 +++++++++++++++++++++++++++++++++++++++++++-
 src/game/Level.hpp   |  6 +++++
 src/game/Tile.cpp    |  4 ++++
 src/game/Tile.hpp    |  1 +
 src/game/Unit.cpp    | 41 +++++++++++++++++++++++++++-------
 src/game/Unit.hpp    | 20 ++++++++++++++---
 src/game/ui/Menu.cpp |  5 ++++-
 10 files changed, 142 insertions(+), 43 deletions(-)

diff --git a/config.xml b/config.xml
index d240753..5b5b962 100644
--- a/config.xml
+++ b/config.xml
@@ -397,8 +397,8 @@
                     <Damage unitId="battle_helicopter" value="105"/>
                     <Damage unitId="fighter" value="85"/>
                     <Damage unitId="bomber" value="100"/>
-                    <Damage unitId="Cruiser" value="25" />
-                    <Damage unitId="Battleship" value="5" />
+                    <Damage unitId="cruiser" value="25" />
+                    <Damage unitId="battleship" value="5" />
                 </DamageTable>
             </PrimaryWeapon>
             <SecondaryWeapon name="Anti-Air Gun">
diff --git a/src/game/Config.cpp b/src/game/Config.cpp
index 823a738..2a01848 100644
--- a/src/game/Config.cpp
+++ b/src/game/Config.cpp
@@ -3,6 +3,7 @@
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/xml_parser.hpp>
 #include <iostream>
+#include <optional>
 #include <stdexcept>
 #include <string>
 #include <unordered_map>
@@ -206,7 +207,7 @@ std::string Config::getUnitPrimaryWeapon(UnitId id) const
     {
         return it->second;
     }
-    throw std::runtime_error("Primary weapon for unit ID not found");
+    return "";
 }
 
 std::string Config::getUnitSecondaryWeapon(UnitId id) const
@@ -216,36 +217,30 @@ std::string Config::getUnitSecondaryWeapon(UnitId id) const
     {
         return it->second;
     }
-    throw std::runtime_error("Secondary weapon for unit ID not found");
+    return "";
 }
 
-int Config::getUnitPrimaryWeaponDamage(UnitId attackerid, UnitId defenderid) const
-{
-    auto it = m_primaryWeaponDamage.find(attackerid);
-    if (it != m_primaryWeaponDamage.end())
-    {
-        auto damageIt = it->second.find(defenderid);
-        if (damageIt != it->second.end())
-        {
-            return damageIt->second;
+std::optional<int> Config::getUnitPrimaryWeaponDamage(UnitId attackerId, UnitId targetId) const {
+        auto attackerMapIt = m_primaryWeaponDamage.find(attackerId);
+        if (attackerMapIt != m_primaryWeaponDamage.end()) {
+            auto damageIt = attackerMapIt->second.find(targetId);
+            if (damageIt != attackerMapIt->second.end()) {
+                return damageIt->second;
+            }
         }
+        // Kein spezifischer Schaden vorhanden
+        return std::nullopt;
     }
-    throw std::runtime_error(
-        "Primary weapon damage not found for given attacker/defender combination");
-}
 
-int Config::getUnitSecondaryWeaponDamage(UnitId attackerid, UnitId defenderid) const
-{
-    auto it = m_secondaryWeaponDamage.find(attackerid);
-    if (it != m_secondaryWeaponDamage.end())
-    {
-        auto damageIt = it->second.find(defenderid);
-        if (damageIt != it->second.end())
-        {
-            return damageIt->second;
+std::optional<int> Config::getUnitSecondaryWeaponDamage(UnitId attackerId, UnitId targetId) const {
+        auto attackerMapIt = m_secondaryWeaponDamage.find(attackerId);
+        if (attackerMapIt != m_secondaryWeaponDamage.end()) {
+            auto damageIt = attackerMapIt->second.find(targetId);
+            if (damageIt != attackerMapIt->second.end()) {
+                return damageIt->second;
+            }
         }
+        // Kein spezifischer Schaden vorhanden
+        return std::nullopt;
     }
-    throw std::runtime_error(
-        "Secondary weapon damage not found for given attacker/defender combination");
-}
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Config.hpp b/src/game/Config.hpp
index 2b03c1b..d3f43fd 100644
--- a/src/game/Config.hpp
+++ b/src/game/Config.hpp
@@ -53,11 +53,11 @@ class Config
 
         /** @brief Retrieves the damage value of a unit's primary weapon against a target unit type.
          */
-        int getUnitPrimaryWeaponDamage(UnitId attackerid, UnitId defenderid) const;
+        std::optional<int> getUnitPrimaryWeaponDamage(UnitId attackerid, UnitId defenderid) const;
 
         /** @brief Retrieves the damage value of a unit's secondary weapon against a target unit
          * type. */
-        int getUnitSecondaryWeaponDamage(UnitId attackerid, UnitId defenderid) const;
+        std::optional<int> getUnitSecondaryWeaponDamage(UnitId attackerid, UnitId defenderid) const;
 
         /** @brief Retrieves the movement type of a given unit type. */
         MovementType getUnitMovementType(UnitId id) const;
diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index 67e35e5..b4458af 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -4,9 +4,11 @@
 #include "Engine.hpp"
 #include "Spritesheet.hpp"
 #include "Unit.hpp"
+#include "Config.hpp"
 #include "highfive/H5File.hpp"
 #include "ui/Contextmenu.hpp"
 #include "ui/Pausemenu.hpp"
+#include <queue>
 #include <SDL.h>
 #include <algorithm>
 #include <boost/property_tree/ptree.hpp>
@@ -235,7 +237,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                 }
                 else
                 {
-
+                    calculateMovementRange(m_units.at(m_selectedUnit));
                     m_units.at(m_selectedUnit).updatePosition(tileX, tileY);
                 }
             }
@@ -277,6 +279,55 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
     }
 }
 
+std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) {
+    std::vector<std::pair<int, int>> reachableTiles;
+    std::queue<std::tuple<int, int, int>> wavefrontQueue; // x, y, remainingMovement
+
+    wavefrontQueue.push(std::make_tuple(unit.m_x, unit.m_y, unit.m_movementPoints));
+    std::unordered_map<int, std::unordered_map<int, bool>> visited;
+
+    while (!wavefrontQueue.empty()) {
+        auto [x, y, remainingMovement] = wavefrontQueue.front();
+        wavefrontQueue.pop();
+
+        if (visited[x][y]) continue;
+        visited[x][y] = true;
+
+        reachableTiles.emplace_back(x, y);
+
+        static const std::vector<std::pair<int, int>> directions = {
+            { 1,  0},
+            {-1,  0},
+            { 0,  1},
+            { 0, -1}
+        };
+
+        for (const auto& [dx, dy] : directions) {
+            int nx = x + dx;
+            int ny = y + dy;
+
+            if (nx < 0 || nx >= m_width || ny < 0 || ny >= m_height) continue; // Boundary check
+
+            int cost = getMoveCost(m_tiles[ny * m_width + nx].getType(), unit.m_movementType);
+            if (cost >= 0 && remainingMovement >= cost) {
+                wavefrontQueue.push(std::make_tuple(nx, ny, remainingMovement - cost));
+            }
+        }
+    }
+
+     std::cout << "Reachable Tiles: " << std::endl;
+    for (const auto& tile : reachableTiles) {
+        std::cout << "(" << tile.first << ", " << tile.second << ")" << std::endl;
+    }
+    
+
+    return reachableTiles;
+}
+int Level::getMoveCost(TileId type, MovementType movementType) {
+    // Implementieren Sie die Logik zur Berechnung der Bewegungskosten hier
+    return 1; // Beispielrückgabe, passen Sie dies nach Bedarf an
+}
+
 void Level::render(Engine& engine)
 {
 
diff --git a/src/game/Level.hpp b/src/game/Level.hpp
index 49c076f..53aa865 100644
--- a/src/game/Level.hpp
+++ b/src/game/Level.hpp
@@ -15,6 +15,8 @@
 namespace advanced_wars
 {
 
+   
+
 /**
  * @brief The main window of the game
  */
@@ -43,6 +45,10 @@ class Level : public Scene
 
         Effect removeEffect(int id);
 
+        std::vector<std::pair<int, int>> calculateMovementRange(Unit& unit);
+
+        int getMoveCost(TileId type, MovementType movementType);
+
     private:
         std::string m_name;
         int         m_width;
diff --git a/src/game/Tile.cpp b/src/game/Tile.cpp
index bf393db..b7e93a4 100644
--- a/src/game/Tile.cpp
+++ b/src/game/Tile.cpp
@@ -30,4 +30,8 @@ void Tile::render(Engine& engine, int scale)
         &dest, 0, NULL, SDL_FLIP_NONE);
 }
 
+TileId Tile::getType() const {
+    return m_id;  // Gibt den gespeicherten TileId zurück
+}
+
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Tile.hpp b/src/game/Tile.hpp
index 44611fa..7a3d838 100644
--- a/src/game/Tile.hpp
+++ b/src/game/Tile.hpp
@@ -49,6 +49,7 @@ class Tile
         int    m_y;
 
         void render(Engine& engine, int scale);
+        TileId getType() const; 
 };
 
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 657f24c..e013e97 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -1,21 +1,45 @@
 #include "Unit.hpp"
+#include "Config.hpp"
 #include <iostream>
 
 namespace advanced_wars
 {
 
-Unit::Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state)
+Unit::Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state, Config& config)
     : m_x(x), m_y(y), m_faction(faction), m_id(id), m_state(state), m_maxHealth(100)
 {
-    // das ist nur für Testzwecke
-    if (m_id == UnitId::INFANTERY)
+    // Allgemeine Einheiteneinstellungen aus Konfiguration holen
+    m_cost = config.getUnitCost(id);
+    m_movementPoints = config.getUnitMovementPoints(id);
+    m_ammo = config.getUnitAmmo(id);
+    m_minRange = config.getUnitMinRange(id);
+    m_maxRange = config.getUnitMaxRange(id);
+    m_health = m_maxHealth;
+
+    m_movementType = config.getUnitMovementType(id);
+
+    // Initialisieren der Primär- und Sekundärwaffe
+    std::unordered_map<UnitId, int> primaryDamage;
+    std::unordered_map<UnitId, int> secondaryDamage;
+
+    for (int targetIt = static_cast<int>(UnitId::FIRST); targetIt <= static_cast<int>(UnitId::LAST);
+         ++targetIt)
     {
-        m_secondaryWeapon = Weapon(
-            "Machine-Gun", {
-                               {UnitId::INFANTERY, 55}
-        });
+        UnitId targetId = static_cast<UnitId>(targetIt);
+
+        // Prüfen, ob ein gültiger Schadenswert vorhanden ist, und nur dann hinzufügen
+        if (auto damage = config.getUnitPrimaryWeaponDamage(id, targetId))
+        {
+            primaryDamage[targetId] = *damage;
+        }
+        if (auto damage = config.getUnitSecondaryWeaponDamage(id, targetId))
+        {
+            secondaryDamage[targetId] = *damage;
+        }
     }
-    m_health = m_maxHealth;
+
+    m_primaryWeapon = Weapon(config.getUnitPrimaryWeapon(id), primaryDamage);
+    m_secondaryWeapon = Weapon(config.getUnitSecondaryWeapon(id), secondaryDamage);
 }
 
 void Unit::render(Engine& engine, int scale)
@@ -83,6 +107,7 @@ void Unit::attack(Unit& enemy)
 {
     // Angenommen, primary_weapon und secondary_weapon wurden bereits korrekt
     // initialisiert
+
     auto primary_weapon_damage_it = m_primaryWeapon.m_damage.find(enemy.m_id);
     auto secondary_weapon_damage_it = m_secondaryWeapon.m_damage.find(enemy.m_id);
 
diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index 4814e7a..b9f645b 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "Engine.hpp"
+
 #include "Weapon.hpp"
 #include <optional>
 #include <unordered_map>
@@ -8,6 +9,8 @@
 namespace advanced_wars
 {
 
+class Config;
+
 enum class UnitFaction
 {
     URED = 0,
@@ -38,6 +41,9 @@ enum class UnitId
     CRUISER = 16,
     LANDER = 17,
     SUBMARINE = 18,
+
+    FIRST= INFANTERY,
+    LAST = SUBMARINE
 };
 
 enum class UnitState
@@ -69,7 +75,10 @@ class Unit
         int m_y;
         int m_health; // health equals max_health at construction
 
-        Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state);
+        int m_movementPoints;
+        MovementType m_movementType;
+
+        Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state, Config& config);
         ~Unit()
         {
             // Assuming that the destruktion of a unit triggers events
@@ -108,7 +117,7 @@ class Unit
         Requires dijkstras algorithm and the required graphs
         */
         void calculateMovement();
-        
+
         /*
         This function calculates the difference between current position and desired position.
         It updates the unit_state accordingly, so that the units face the correct direction.
@@ -128,8 +137,9 @@ class Unit
 
         int m_maxHealth; // max_health required for damage_scaling
         int m_range;
+        /*
         int m_fuel;
-        int m_maxFuel;
+        int m_maxFuel;*/
 
         bool m_hasMoved;
         bool m_hasAttacked;
@@ -139,7 +149,11 @@ class Unit
         Weapon m_secondaryWeapon;
         Weapon m_primaryWeapon;
 
+        int m_cost;
+        
         int m_ammo;
+        int m_minRange;
+        int m_maxRange;
 };
 
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/ui/Menu.cpp b/src/game/ui/Menu.cpp
index 392209b..c7a7c1f 100644
--- a/src/game/ui/Menu.cpp
+++ b/src/game/ui/Menu.cpp
@@ -1,6 +1,7 @@
 #include "Menu.hpp"
 #include "../Building.hpp"
 #include "../Level.hpp"
+#include "../Config.hpp"
 #include "../Spritesheet.hpp"
 #include "../Tile.hpp"
 #include "../Unit.hpp"
@@ -126,6 +127,7 @@ void Menu::handleEvent(Engine& engine, SDL_Event& event)
             {
                 std::cout << "Starting game..." << std::endl;
 
+
                 // Construct a level
                 std::vector<Tile> tiles;
                 for (int y = 0; y < 20; y++)
@@ -179,6 +181,7 @@ void Menu::handleEvent(Engine& engine, SDL_Event& event)
                     }
                 }
 
+                Config config = Config("../config.xml");
                 // Units
                 std::vector<Unit> units;
 
@@ -188,7 +191,7 @@ void Menu::handleEvent(Engine& engine, SDL_Event& event)
                     {
                         units.push_back(Unit(
                             x + 9, y + 2, UnitFaction::URED, static_cast<UnitId>(y),
-                            static_cast<UnitState>(x)));
+                            static_cast<UnitState>(x), config));
                     }
                 }
 
-- 
GitLab


From f1d52b3dc4837cff30478b0da488532abedfb7fb Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Tue, 4 Feb 2025 21:25:27 +0100
Subject: [PATCH 03/10] wavefront now uses different costs for combination of
 MoveType+TileId

---
 src/game/Level.cpp | 47 ++++++++++++++++++++++++++++++++++------------
 src/game/Level.hpp | 45 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 12 deletions(-)

diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index b4458af..da19c85 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -200,7 +200,9 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
 
                 if (m_selectedUnit > -1)
                 {
+                    m_reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
                     m_units.at(m_selectedUnit).on_left_click(event);
+                    m_showReachableTiles = true;
                 }
 
                 if (m_selectedBuilding > -1)
@@ -214,6 +216,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                 std::cout << "Neither building nor unit clicked!" << std::endl;
                 m_selectedUnit = -1;
                 m_selectedBuilding = -1;
+                m_showReachableTiles = false;
             }
         }
         else if (event.button.button == SDL_BUTTON_RIGHT)
@@ -237,8 +240,18 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                 }
                 else
                 {
-                    calculateMovementRange(m_units.at(m_selectedUnit));
-                    m_units.at(m_selectedUnit).updatePosition(tileX, tileY);
+                    // Calculate movement range as a vector of pairs
+                    auto reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
+
+                    // Use std::find to check presence of {tileX, tileY} in reachableTiles vector
+                    if (std::find(reachableTiles.begin(), reachableTiles.end(),std::make_pair(tileX, tileY)) != reachableTiles.end())
+                    {
+                        m_units.at(m_selectedUnit).updatePosition(tileX, tileY);
+                    }
+                    else
+                    {
+                        std::cout << "Invalid move position!" << std::endl;
+                    }
                 }
             }
             else
@@ -313,19 +326,15 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) {
                 wavefrontQueue.push(std::make_tuple(nx, ny, remainingMovement - cost));
             }
         }
-    }
-
-     std::cout << "Reachable Tiles: " << std::endl;
-    for (const auto& tile : reachableTiles) {
-        std::cout << "(" << tile.first << ", " << tile.second << ")" << std::endl;
-    }
-    
+    }  
 
     return reachableTiles;
 }
-int Level::getMoveCost(TileId type, MovementType movementType) {
-    // Implementieren Sie die Logik zur Berechnung der Bewegungskosten hier
-    return 1; // Beispielrückgabe, passen Sie dies nach Bedarf an
+
+
+
+int Level::getMoveCost(TileId tileId, MovementType movementType) {
+    return moveCostTable[static_cast<int>(tileId)][static_cast<int>(movementType)];
 }
 
 void Level::render(Engine& engine)
@@ -345,6 +354,20 @@ void Level::render(Engine& engine)
         tile.render(engine, RENDERING_SCALE);
     }
 
+    if (m_showReachableTiles) {
+        SDL_SetRenderDrawColor(engine.renderer(), 255, 255, 0, 128); // Gelb mit leichtem Alpha
+
+        for (const auto& [x, y] : m_reachableTiles) {
+            SDL_Rect rect = { x * 16 * RENDERING_SCALE, y * 16 * RENDERING_SCALE,
+                              16 * RENDERING_SCALE, 16 * RENDERING_SCALE };
+            SDL_RenderFillRect(engine.renderer(), &rect);
+        }
+
+        // Reset draw color if required (depends on your rendering setup)
+        SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
+    }
+
+
     // Buildings
     for (auto& [id, building] : m_buildings)
     {
diff --git a/src/game/Level.hpp b/src/game/Level.hpp
index 53aa865..d44363b 100644
--- a/src/game/Level.hpp
+++ b/src/game/Level.hpp
@@ -11,10 +11,51 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <array>
+
+
 
 namespace advanced_wars
 {
 
+
+const int NUM_TILE_IDS = 30; // Aktualisieren, falls weitere IDs hinzugefügt werden
+const int NUM_MOVEMENT_TYPES = 6;
+
+
+const std::array<std::array<int, NUM_MOVEMENT_TYPES>, NUM_TILE_IDS> moveCostTable = {{
+    // FOOT, WHEELED, TREAD, AIR, SEA, LANDER
+    {  1,      2,       1,    1, 999,   999 }, // PLAIN
+    {999,    999,     999,    1,   1,     1 }, // WATER
+    {  1,      3,       2,    1, 999,   999 }, // FOREST
+    {  2,    999,     999,    1, 999,   999 }, // MOUNTAIN
+    {  1,      1,       1,    1, 999,   999 }, // BRIDGE_HORIZONTAL
+    {  1,      1,       1,    1, 999,   999 }, // STREET_HORIZONTAL
+    {  1,      1,       1,    1, 999,   999 }, // STREET_VERTICAL
+    {  1,      1,       1,    1, 999,   999 }, // STREET_CROSSING
+    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_RIGHT
+    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_LEFT
+    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_DOWN
+    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_UP
+    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_TOP_LEFT
+    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_TOP_RIGHT
+    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_BOTTOM_LEFT
+    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_BOTTOM_RIGHT 
+    {999,    999,     999,    1,   2,     2 }, // RIFF
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_TOP
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_BOTTOM
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_LEFT
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_RIGHT
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_TOP_LEFT
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_TOP_RIGHT
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_BOTTOM_LEFT
+    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_BOTTOM_RIGHT
+    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_TOP_LEFT
+    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_TOP_RIGHT
+    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_BOTTOM_LEFT
+    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_BOTTOM_RIGHT
+}};
+
    
 
 /**
@@ -49,6 +90,9 @@ class Level : public Scene
 
         int getMoveCost(TileId type, MovementType movementType);
 
+        std::vector<std::pair<int, int>> m_reachableTiles;
+        
+
     private:
         std::string m_name;
         int         m_width;
@@ -74,6 +118,7 @@ class Level : public Scene
 
         bool clickCheckLeft(int mouseX, int mouseY);
         bool clickCheckRight(int mouseX, int mouseY);
+        bool m_showReachableTiles;
 };
 
 } // namespace advanced_wars
-- 
GitLab


From 76da6a1f1afd734bf9f9d4745ffa7f6e070ec44e Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Tue, 4 Feb 2025 23:28:52 +0100
Subject: [PATCH 04/10] Made getUnitsInRangeWithDamagePotential function

---
 src/game/Level.cpp | 119 +++++++++++++++++++++++++++++++++++++--------
 src/game/Level.hpp |   9 ++++
 src/game/Unit.cpp  |  52 ++++++++++++++++----
 src/game/Unit.hpp  |   3 ++
 4 files changed, 152 insertions(+), 31 deletions(-)

diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index da19c85..2c2d2e8 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -1,19 +1,19 @@
 #include "Level.hpp"
 #include "Building.hpp"
+#include "Config.hpp"
 #include "Effect.hpp"
 #include "Engine.hpp"
 #include "Spritesheet.hpp"
 #include "Unit.hpp"
-#include "Config.hpp"
 #include "highfive/H5File.hpp"
 #include "ui/Contextmenu.hpp"
 #include "ui/Pausemenu.hpp"
-#include <queue>
 #include <SDL.h>
 #include <algorithm>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/xml_parser.hpp>
 #include <iostream>
+#include <queue>
 #include <string>
 
 namespace advanced_wars
@@ -203,6 +203,49 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                     m_reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
                     m_units.at(m_selectedUnit).on_left_click(event);
                     m_showReachableTiles = true;
+
+                    std::vector<Unit*> allUnits;
+                    allUnits.reserve(m_units.size());
+
+                    for (auto& [id, unit] : m_units)
+                    {
+                        allUnits.push_back(&unit); // Fügen Sie Zeiger hinzu, nicht Kopien
+                    }
+                    /*
+
+                    std::vector<Unit*> attackableTargets =
+                        m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
+
+                    m_attackableTiles.clear();
+                    m_showAttackableTiles = true;
+                    for (Unit* target : attackableTargets)
+                    {
+                        // Füge die Position jedes angreifbaren Ziels hinzu
+                        m_attackableTiles.emplace_back(target->m_x, target->m_y);
+                    }*/
+
+                    std::vector<Unit*> attackableTargets =
+                        m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
+
+                    m_attackableTiles.clear();
+                    m_showAttackableTiles = true;
+                    m_attackableUnitIds.clear(); // <-- Fügen Sie dies hier hinzu
+
+                    for (Unit* target : attackableTargets)
+                    {
+                        // Füge die Position jedes angreifbaren Ziels hinzu
+                        m_attackableTiles.emplace_back(target->m_x, target->m_y);
+
+                        // Angreifbaren Einheits-ID setzen
+                        for (auto& [id, unit] : m_units)
+                        {
+                            if (&unit == target)
+                            {
+                                m_attackableUnitIds.insert(id);
+                                break;
+                            }
+                        }
+                    }
                 }
 
                 if (m_selectedBuilding > -1)
@@ -217,6 +260,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                 m_selectedUnit = -1;
                 m_selectedBuilding = -1;
                 m_showReachableTiles = false;
+                m_showAttackableTiles = false;
             }
         }
         else if (event.button.button == SDL_BUTTON_RIGHT)
@@ -231,11 +275,19 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                 if (clickCheckRight(tileX, tileY))
                 {
 
-                    m_units.at(m_selectedUnit).attack((m_units.at(m_targetedUnit)));
+                    if (m_attackableUnitIds.find(m_targetedUnit) != m_attackableUnitIds.end())
+                    {
+                        // Attack if the unit is a valid target
+                        m_units.at(m_selectedUnit).attack(m_units.at(m_targetedUnit));
 
-                    if (m_units.at(m_selectedUnit).m_health <= 0)
+                        if (m_units.at(m_selectedUnit).m_health <= 0)
+                        {
+                            removeUnit(m_selectedUnit);
+                        }
+                    }
+                    else
                     {
-                        removeUnit(m_selectedUnit);
+                        std::cout << "Invalid attack target!" << std::endl;
                     }
                 }
                 else
@@ -244,7 +296,9 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                     auto reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
 
                     // Use std::find to check presence of {tileX, tileY} in reachableTiles vector
-                    if (std::find(reachableTiles.begin(), reachableTiles.end(),std::make_pair(tileX, tileY)) != reachableTiles.end())
+                    if (std::find(
+                            reachableTiles.begin(), reachableTiles.end(),
+                            std::make_pair(tileX, tileY)) != reachableTiles.end())
                     {
                         m_units.at(m_selectedUnit).updatePosition(tileX, tileY);
                     }
@@ -292,18 +346,21 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
     }
 }
 
-std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) {
-    std::vector<std::pair<int, int>> reachableTiles;
+std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
+{
+    std::vector<std::pair<int, int>>      reachableTiles;
     std::queue<std::tuple<int, int, int>> wavefrontQueue; // x, y, remainingMovement
 
     wavefrontQueue.push(std::make_tuple(unit.m_x, unit.m_y, unit.m_movementPoints));
     std::unordered_map<int, std::unordered_map<int, bool>> visited;
 
-    while (!wavefrontQueue.empty()) {
+    while (!wavefrontQueue.empty())
+    {
         auto [x, y, remainingMovement] = wavefrontQueue.front();
         wavefrontQueue.pop();
 
-        if (visited[x][y]) continue;
+        if (visited[x][y])
+            continue;
         visited[x][y] = true;
 
         reachableTiles.emplace_back(x, y);
@@ -315,25 +372,27 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) {
             { 0, -1}
         };
 
-        for (const auto& [dx, dy] : directions) {
+        for (const auto& [dx, dy] : directions)
+        {
             int nx = x + dx;
             int ny = y + dy;
 
-            if (nx < 0 || nx >= m_width || ny < 0 || ny >= m_height) continue; // Boundary check
+            if (nx < 0 || nx >= m_width || ny < 0 || ny >= m_height)
+                continue; // Boundary check
 
             int cost = getMoveCost(m_tiles[ny * m_width + nx].getType(), unit.m_movementType);
-            if (cost >= 0 && remainingMovement >= cost) {
+            if (cost >= 0 && remainingMovement >= cost)
+            {
                 wavefrontQueue.push(std::make_tuple(nx, ny, remainingMovement - cost));
             }
         }
-    }  
+    }
 
     return reachableTiles;
 }
 
-
-
-int Level::getMoveCost(TileId tileId, MovementType movementType) {
+int Level::getMoveCost(TileId tileId, MovementType movementType)
+{
     return moveCostTable[static_cast<int>(tileId)][static_cast<int>(movementType)];
 }
 
@@ -354,12 +413,15 @@ void Level::render(Engine& engine)
         tile.render(engine, RENDERING_SCALE);
     }
 
-    if (m_showReachableTiles) {
+    if (m_showReachableTiles)
+    {
         SDL_SetRenderDrawColor(engine.renderer(), 255, 255, 0, 128); // Gelb mit leichtem Alpha
 
-        for (const auto& [x, y] : m_reachableTiles) {
-            SDL_Rect rect = { x * 16 * RENDERING_SCALE, y * 16 * RENDERING_SCALE,
-                              16 * RENDERING_SCALE, 16 * RENDERING_SCALE };
+        for (const auto& [x, y] : m_reachableTiles)
+        {
+            SDL_Rect rect = {
+                x * 16 * RENDERING_SCALE, y * 16 * RENDERING_SCALE, 16 * RENDERING_SCALE,
+                16 * RENDERING_SCALE};
             SDL_RenderFillRect(engine.renderer(), &rect);
         }
 
@@ -367,6 +429,21 @@ void Level::render(Engine& engine)
         SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
     }
 
+    if (m_showAttackableTiles)
+    {
+        SDL_SetRenderDrawColor(engine.renderer(), 255, 0, 0, 128); // Rot mit leichtem Alpha
+
+        for (const auto& [x, y] : m_attackableTiles)
+        {
+            SDL_Rect rect = {
+                x * 16 * RENDERING_SCALE, y * 16 * RENDERING_SCALE, 16 * RENDERING_SCALE,
+                16 * RENDERING_SCALE};
+            SDL_RenderFillRect(engine.renderer(), &rect);
+        }
+
+        // Optionale Rücksetzung der Zeichenfarbe
+        SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
+    }
 
     // Buildings
     for (auto& [id, building] : m_buildings)
diff --git a/src/game/Level.hpp b/src/game/Level.hpp
index d44363b..0799a7f 100644
--- a/src/game/Level.hpp
+++ b/src/game/Level.hpp
@@ -12,6 +12,8 @@
 #include <unordered_map>
 #include <vector>
 #include <array>
+#include <unordered_set>
+
 
 
 
@@ -91,6 +93,10 @@ class Level : public Scene
         int getMoveCost(TileId type, MovementType movementType);
 
         std::vector<std::pair<int, int>> m_reachableTiles;
+
+        std::vector<std::pair<int, int>> m_attackableTiles;
+
+        
         
 
     private:
@@ -119,6 +125,9 @@ class Level : public Scene
         bool clickCheckLeft(int mouseX, int mouseY);
         bool clickCheckRight(int mouseX, int mouseY);
         bool m_showReachableTiles;
+        bool m_showAttackableTiles;
+
+        std::unordered_set<int> m_attackableUnitIds;
 };
 
 } // namespace advanced_wars
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index e013e97..b0d7824 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -228,17 +228,49 @@ void Unit::on_left_click(SDL_Event event)
     std::cout << "Left-button pressed on unit: " << this->m_health << std::endl;
 }
 
-bool Unit::inRange(Unit& enemy)
+std::vector<Unit*> Unit::getUnitsInRangeWithDamagePotential(const std::vector<Unit*>& allUnits)
 {
-    if (this->m_x == enemy.m_x)
-    {
-        return abs(this->m_y - enemy.m_y) <= this->m_range;
-    }
-    else if (this->m_y == enemy.m_y)
-    {
-        return abs(this->m_x - enemy.m_x) <= this->m_range;
+    std::vector<Unit*> unitsInRangeWithDamage;
+
+    for (Unit* unit : allUnits)
+    { // Iteriere über Zeiger
+        // Ignoriere sich selbst
+        if (unit == this)
+        {
+            continue;
+        }
+
+        int distanceX = std::abs(unit->m_x - m_x);
+        int distanceY = std::abs(unit->m_y - m_y);
+
+        // Manhattan-Distanz Berechnung
+        int distance = distanceX + distanceY;
+        if (distance >= m_minRange && distance <= m_maxRange)
+        {
+            // Prüfen ob Schaden möglich ist
+            auto primaryDamageIter = m_primaryWeapon.m_damage.find(unit->m_id);
+            auto secondaryDamageIter = m_secondaryWeapon.m_damage.find(unit->m_id);
+
+            bool canDealDamage = false;
+
+            // Prüfen, ob Primärwaffe Schaden machen kann
+            if (primaryDamageIter != m_primaryWeapon.m_damage.end() && m_ammo > 0)
+            {
+                canDealDamage = true;
+            }
+            // Prüfen, ob Sekundärwaffe Schaden machen kann
+            if (secondaryDamageIter != m_secondaryWeapon.m_damage.end())
+            {
+                canDealDamage = true;
+            }
+
+            if (canDealDamage)
+            {
+                unitsInRangeWithDamage.push_back(unit);
+            }
+        }
     }
-    return false;
-}
 
+    return unitsInRangeWithDamage;
+}
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index b9f645b..d373076 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -130,6 +130,9 @@ class Unit
         */
         void on_left_click(SDL_Event event);
 
+        std::vector<Unit*> getUnitsInRangeWithDamagePotential(const std::vector<Unit*>& allUnits);
+
+
     private:
         UnitFaction m_faction;
         UnitId      m_id;
-- 
GitLab


From d38ddd7091fa00107c23113cf11b489526b162aa Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Wed, 5 Feb 2025 17:11:12 +0100
Subject: [PATCH 05/10] updated attack function + ammo is deducted + inrange
 check for retaliation

---
 src/game/Level.cpp |  24 ++-------
 src/game/Unit.cpp  | 128 ++++++++++++++++++++++++---------------------
 src/game/Unit.hpp  |   4 ++
 3 files changed, 75 insertions(+), 81 deletions(-)

diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index 2c2d2e8..dd737e9 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -127,14 +127,11 @@ bool Level::clickCheckRight(int tileX, int tileY)
 bool Level::selectUnit(int tileX, int tileY)
 {
 
-    // std::cout << "tileX:" << tileX << "tileX:" << tileY << std::endl;
     for (auto& [id, unit] : m_units)
     {
 
         if (unit.m_x == tileX && unit.m_y == tileY)
         {
-            // std::cout << "unitX:" << unit.x << "unitY:" << unit.y << std::endl;
-
             m_selectedUnit = id;
             return true;
         }
@@ -146,14 +143,11 @@ bool Level::selectUnit(int tileX, int tileY)
 bool Level::targetUnit(int tileX, int tileY)
 {
 
-    // std::cout << "tileX:" << tileX << "tileX:" << tileY << std::endl;
     for (auto& [id, unit] : m_units)
     {
 
         if (unit.m_x == tileX && unit.m_y == tileY)
         {
-            // std::cout << "unitX:" << unit.x << "unitY:" << unit.y << std::endl;
-
             m_targetedUnit = id;
             return true;
         }
@@ -209,27 +203,15 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
 
                     for (auto& [id, unit] : m_units)
                     {
-                        allUnits.push_back(&unit); // Fügen Sie Zeiger hinzu, nicht Kopien
+                        allUnits.push_back(&unit);
                     }
-                    /*
-
-                    std::vector<Unit*> attackableTargets =
-                        m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
-
-                    m_attackableTiles.clear();
-                    m_showAttackableTiles = true;
-                    for (Unit* target : attackableTargets)
-                    {
-                        // Füge die Position jedes angreifbaren Ziels hinzu
-                        m_attackableTiles.emplace_back(target->m_x, target->m_y);
-                    }*/
-
+                    
                     std::vector<Unit*> attackableTargets =
                         m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
 
                     m_attackableTiles.clear();
                     m_showAttackableTiles = true;
-                    m_attackableUnitIds.clear(); // <-- Fügen Sie dies hier hinzu
+                    m_attackableUnitIds.clear();
 
                     for (Unit* target : attackableTargets)
                     {
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index b0d7824..796730d 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -105,78 +105,86 @@ void Unit::render(Engine& engine, int scale)
 
 void Unit::attack(Unit& enemy)
 {
-    // Angenommen, primary_weapon und secondary_weapon wurden bereits korrekt
-    // initialisiert
+    int attacker_damage_value = calculateDamage(enemy);
 
-    auto primary_weapon_damage_it = m_primaryWeapon.m_damage.find(enemy.m_id);
-    auto secondary_weapon_damage_it = m_secondaryWeapon.m_damage.find(enemy.m_id);
-
-    int attacker_damage_value = 0;
-
-    // Die Waffe mit dem höchsten Schaden wählen
-    if (secondary_weapon_damage_it != m_secondaryWeapon.m_damage.end())
+    if (attacker_damage_value > 0)
     {
-        attacker_damage_value = secondary_weapon_damage_it->second;
-    }
+        performAttack(enemy, attacker_damage_value);
+        std::cout << "Enemy health after attack: " << enemy.m_health << std::endl;
 
-    if (primary_weapon_damage_it != m_primaryWeapon.m_damage.end())
-    {
-        if (primary_weapon_damage_it->second > attacker_damage_value)
+        // Check if the enemy is still alive for counter-attack
+        if (enemy.m_health > 0)
         {
-            // Munitionsabzug sollte hier erfolgen, falls zutreffend
-            attacker_damage_value = primary_weapon_damage_it->second;
+            // Check if the enemy is within attack range
+            int distanceX = std::abs(enemy.m_x - m_x);
+            int distanceY = std::abs(enemy.m_y - m_y);
+            int distance = distanceX + distanceY;
+
+            if (distance >= enemy.m_minRange && distance <= enemy.m_maxRange)
+            {
+                // Now, they are reversed for the counter-attack
+                int defender_damage_value = enemy.calculateDamage(*this);
+                if (defender_damage_value > 0)
+                {
+                    enemy.performAttack(*this, defender_damage_value);
+                    std::cout << "Ally health after retaliation: " << this->m_health << std::endl;
+                }
+            }
+            else
+            {
+                std::cout << "Enemy out of range for counter-attack." << std::endl;
+            }
         }
     }
-
-    if (attacker_damage_value == 0)
+    else
     {
         std::cout << "No damage value found for attack from unit " << static_cast<int>(m_id)
                   << " against unit " << static_cast<int>(enemy.m_id) << std::endl;
     }
-    else
+}
+
+int Unit::calculateDamage(Unit& target)
+{
+    // Pointers to Weapon objects
+    Weapon* primaryWeapon =  &m_primaryWeapon;
+    Weapon* secondaryWeapon = &m_secondaryWeapon;
+    
+    // Find the corresponding damage values
+    auto primary_damage_it = primaryWeapon->m_damage.find(target.m_id);
+    auto secondary_damage_it = secondaryWeapon->m_damage.find(target.m_id);
+
+    int damage_value = 0;
+
+    // Calculate damage using secondary weapon if available
+    if (secondary_damage_it != secondaryWeapon->m_damage.end())
     {
-        int off_damage = attacker_damage_value * (static_cast<float>(m_health) / m_maxHealth);
-        enemy.m_health -= off_damage;
-        enemy.m_health = std::max(
-            0,
-            enemy.m_health); // Sicherstellen, dass die Gesundheit nicht negativ wird
-        std::cout << "Enemy health after attack: " << enemy.m_health << std::endl;
+        damage_value = secondary_damage_it->second;
+    }
 
-        // Prüfen, ob der Gegner noch am Leben ist um zurückzuschlagen
-        if (enemy.m_health > 0)
+    // Calculate damage using primary weapon if higher and ammo is available
+    if (primary_damage_it != primaryWeapon->m_damage.end())
+    {
+        // Check ammo correctly
+        int& ammo = m_ammo;
+
+        if (primary_damage_it->second > damage_value && ammo > 0)
         {
-            // Weapon tables for the defender
-            auto defender_primary_weapon_damage_it = enemy.m_primaryWeapon.m_damage.find(m_id);
-            auto defender_secondary_weapon_damage_it = enemy.m_secondaryWeapon.m_damage.find(m_id);
+            ammo -= 1;
+            damage_value = primary_damage_it->second;
+            std::cout << " ammo = " << ammo << std::endl;
+        }
+    }
 
-            int defender_damage_value = 0; // Declare outside for later use
+    return damage_value;
+}
 
-            // Determine the damage value for the defender
-            if (defender_secondary_weapon_damage_it != enemy.m_secondaryWeapon.m_damage.end())
-            {
-                defender_damage_value = defender_secondary_weapon_damage_it->second;
-            }
 
-            if (defender_primary_weapon_damage_it != enemy.m_primaryWeapon.m_damage.end())
-            {
-                if (defender_primary_weapon_damage_it->second > defender_damage_value)
-                {
-                    // Munitionsabzug für primäre Waffe, falls zutreffend
-                    defender_damage_value = defender_primary_weapon_damage_it->second;
-                }
-            }
 
-            // If a valid damage value was determined for retaliation
-            if (defender_damage_value > 0)
-            {
-                int def_damage = static_cast<int>(
-                    defender_damage_value * static_cast<float>(enemy.m_health) / enemy.m_maxHealth);
-                this->m_health -= def_damage;
-                this->m_health = std::max(0, this->m_health); // Safeguard against negative health
-                std::cout << "Ally health after retaliation: " << this->m_health << std::endl;
-            }
-        }
-    }
+void Unit::performAttack(Unit& target, int damage)
+{
+    int effective_damage = damage * (static_cast<float>(m_health) / m_maxHealth);
+    target.m_health -= effective_damage;
+    target.m_health = std::max(0, target.m_health);
 }
 
 void Unit::updatePosition(int posX, int posY)
@@ -233,8 +241,8 @@ std::vector<Unit*> Unit::getUnitsInRangeWithDamagePotential(const std::vector<Un
     std::vector<Unit*> unitsInRangeWithDamage;
 
     for (Unit* unit : allUnits)
-    { // Iteriere über Zeiger
-        // Ignoriere sich selbst
+    { //Iterate over all units
+        // except itself
         if (unit == this)
         {
             continue;
@@ -243,7 +251,7 @@ std::vector<Unit*> Unit::getUnitsInRangeWithDamagePotential(const std::vector<Un
         int distanceX = std::abs(unit->m_x - m_x);
         int distanceY = std::abs(unit->m_y - m_y);
 
-        // Manhattan-Distanz Berechnung
+        
         int distance = distanceX + distanceY;
         if (distance >= m_minRange && distance <= m_maxRange)
         {
@@ -254,12 +262,12 @@ std::vector<Unit*> Unit::getUnitsInRangeWithDamagePotential(const std::vector<Un
             bool canDealDamage = false;
 
             // Prüfen, ob Primärwaffe Schaden machen kann
-            if (primaryDamageIter != m_primaryWeapon.m_damage.end() && m_ammo > 0)
+            if (primaryDamageIt != m_primaryWeapon.m_damage.end() && m_ammo > 0)
             {
                 canDealDamage = true;
             }
             // Prüfen, ob Sekundärwaffe Schaden machen kann
-            if (secondaryDamageIter != m_secondaryWeapon.m_damage.end())
+            if (secondaryDamageIt != m_secondaryWeapon.m_damage.end())
             {
                 canDealDamage = true;
             }
diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index d373076..e855cd8 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -104,6 +104,10 @@ class Unit
 
         void attack(Unit& enemy);
 
+        void performAttack(Unit& target, int damage);
+
+        int calculateDamage(Unit& target);
+
         /*
         @params Takes the desired position of the unit and updates its values
         This will teleport the unit, there is no smooth transition between tiles
-- 
GitLab


From 2af8c4d3b7a08887818929edb695cef2a3353986 Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Wed, 5 Feb 2025 17:35:39 +0100
Subject: [PATCH 06/10] updatet calculateMovementRange function only none
 occupied tiles are now reachable

---
 src/game/Level.cpp | 29 +++++++++++++++++++++--------
 src/game/Unit.cpp  |  4 ++--
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index dd737e9..6633236 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -330,7 +330,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
 
 std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
 {
-    std::vector<std::pair<int, int>>      reachableTiles;
+    std::vector<std::pair<int, int>> reachableTiles;
     std::queue<std::tuple<int, int, int>> wavefrontQueue; // x, y, remainingMovement
 
     wavefrontQueue.push(std::make_tuple(unit.m_x, unit.m_y, unit.m_movementPoints));
@@ -341,17 +341,29 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
         auto [x, y, remainingMovement] = wavefrontQueue.front();
         wavefrontQueue.pop();
 
+        // Check if this tile has been visited already
         if (visited[x][y])
             continue;
         visited[x][y] = true;
 
-        reachableTiles.emplace_back(x, y);
+        // Check if a unit is on the current tile, skip adding it if true
+        bool isOccupied = false;
+        for (const auto& [id, otherUnit] : m_units)
+        {
+            if (otherUnit.m_x == x && otherUnit.m_y == y && id != m_selectedUnit)
+            {
+                isOccupied = true;
+                break;
+            }
+        }
+        // Add to reachable tiles only if not occupied
+        if (!isOccupied)
+        {
+            reachableTiles.emplace_back(x, y);
+        }
 
         static const std::vector<std::pair<int, int>> directions = {
-            { 1,  0},
-            {-1,  0},
-            { 0,  1},
-            { 0, -1}
+            {1, 0}, {-1, 0}, {0, 1}, {0, -1}
         };
 
         for (const auto& [dx, dy] : directions)
@@ -373,6 +385,7 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
     return reachableTiles;
 }
 
+
 int Level::getMoveCost(TileId tileId, MovementType movementType)
 {
     return moveCostTable[static_cast<int>(tileId)][static_cast<int>(movementType)];
@@ -407,7 +420,7 @@ void Level::render(Engine& engine)
             SDL_RenderFillRect(engine.renderer(), &rect);
         }
 
-        // Reset draw color if required (depends on your rendering setup)
+        
         SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
     }
 
@@ -423,7 +436,7 @@ void Level::render(Engine& engine)
             SDL_RenderFillRect(engine.renderer(), &rect);
         }
 
-        // Optionale Rücksetzung der Zeichenfarbe
+        
         SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
     }
 
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 796730d..6b441df 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -256,8 +256,8 @@ std::vector<Unit*> Unit::getUnitsInRangeWithDamagePotential(const std::vector<Un
         if (distance >= m_minRange && distance <= m_maxRange)
         {
             // Prüfen ob Schaden möglich ist
-            auto primaryDamageIter = m_primaryWeapon.m_damage.find(unit->m_id);
-            auto secondaryDamageIter = m_secondaryWeapon.m_damage.find(unit->m_id);
+            auto primaryDamageIt = m_primaryWeapon.m_damage.find(unit->m_id);
+            auto secondaryDamageIt = m_secondaryWeapon.m_damage.find(unit->m_id);
 
             bool canDealDamage = false;
 
-- 
GitLab


From 96c66e4b70a034f5cc0b981d0d3f3afa731a9958 Mon Sep 17 00:00:00 2001
From: Lorenz <lorenz-martin.diel@informatik.hs-fulda.de>
Date: Wed, 5 Feb 2025 18:23:56 +0100
Subject: [PATCH 07/10] Small Changes

---
 src/game/Level.cpp |  35 ++++++----
 src/game/Unit.cpp  |   2 +
 src/game/Unit.hpp  | 170 ++++++++++++++++++++++++++++-----------------
 3 files changed, 130 insertions(+), 77 deletions(-)

diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index 6633236..00f140e 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -199,13 +199,12 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                     m_showReachableTiles = true;
 
                     std::vector<Unit*> allUnits;
-                    allUnits.reserve(m_units.size());
 
                     for (auto& [id, unit] : m_units)
                     {
                         allUnits.push_back(&unit);
                     }
-                    
+
                     std::vector<Unit*> attackableTargets =
                         m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
 
@@ -266,6 +265,10 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                         {
                             removeUnit(m_selectedUnit);
                         }
+                        if (m_units.at(m_targetedUnit).m_health <= 0)
+                        {
+                            removeUnit(m_targetedUnit);
+                        }
                     }
                     else
                     {
@@ -277,16 +280,24 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
                     // Calculate movement range as a vector of pairs
                     auto reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
 
-                    // Use std::find to check presence of {tileX, tileY} in reachableTiles vector
-                    if (std::find(
-                            reachableTiles.begin(), reachableTiles.end(),
-                            std::make_pair(tileX, tileY)) != reachableTiles.end())
+                    bool isReachable = false;
+
+                    for (const auto& pos : reachableTiles)
+                    {
+                        if (pos == std::make_pair(tileX, tileY))
+                        {
+                            isReachable = true;
+                            break;
+                        }
+                    }
+                    
+                    if (isReachable)
                     {
                         m_units.at(m_selectedUnit).updatePosition(tileX, tileY);
                     }
                     else
                     {
-                        std::cout << "Invalid move position!" << std::endl;
+                        std::cout << "Ungültige Bewegungsposition!" << std::endl;
                     }
                 }
             }
@@ -330,7 +341,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
 
 std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
 {
-    std::vector<std::pair<int, int>> reachableTiles;
+    std::vector<std::pair<int, int>>      reachableTiles;
     std::queue<std::tuple<int, int, int>> wavefrontQueue; // x, y, remainingMovement
 
     wavefrontQueue.push(std::make_tuple(unit.m_x, unit.m_y, unit.m_movementPoints));
@@ -363,7 +374,10 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
         }
 
         static const std::vector<std::pair<int, int>> directions = {
-            {1, 0}, {-1, 0}, {0, 1}, {0, -1}
+            { 1,  0},
+            {-1,  0},
+            { 0,  1},
+            { 0, -1}
         };
 
         for (const auto& [dx, dy] : directions)
@@ -385,7 +399,6 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit)
     return reachableTiles;
 }
 
-
 int Level::getMoveCost(TileId tileId, MovementType movementType)
 {
     return moveCostTable[static_cast<int>(tileId)][static_cast<int>(movementType)];
@@ -420,7 +433,6 @@ void Level::render(Engine& engine)
             SDL_RenderFillRect(engine.renderer(), &rect);
         }
 
-        
         SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
     }
 
@@ -436,7 +448,6 @@ void Level::render(Engine& engine)
             SDL_RenderFillRect(engine.renderer(), &rect);
         }
 
-        
         SDL_SetRenderDrawColor(engine.renderer(), 0, 0, 0, 255);
     }
 
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 6b441df..1c03e31 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -42,6 +42,8 @@ Unit::Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state, Config
     m_secondaryWeapon = Weapon(config.getUnitSecondaryWeapon(id), secondaryDamage);
 }
 
+ 
+
 void Unit::render(Engine& engine, int scale)
 {
     Spritesheet* spritesheet = engine.getSpritesheet();
diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index e855cd8..b58bb6f 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -42,7 +42,7 @@ enum class UnitId
     LANDER = 17,
     SUBMARINE = 18,
 
-    FIRST= INFANTERY,
+    FIRST = INFANTERY,
     LAST = SUBMARINE
 };
 
@@ -73,94 +73,134 @@ class Unit
     public:
         int m_x;
         int m_y;
-        int m_health; // health equals max_health at construction
+        int m_health; // Current health of the unit, initialized to max health at construction.
 
-        int m_movementPoints;
-        MovementType m_movementType;
+        int          m_movementPoints; // The number of tiles this unit can move per turn.
+        MovementType m_movementType;   // The type of movement this unit has (e.g., foot, wheeled).
 
+        /**
+         * Constructor for Unit.
+         * Initializes the unit's position, faction, identifier, state, and configuration settings.
+         */
         Unit(int x, int y, UnitFaction faction, UnitId id, UnitState state, Config& config);
-        ~Unit()
-        {
-            // Assuming that the destruktion of a unit triggers events
-        }
 
+        /**
+         * Destructor for Unit.
+         * Handles any cleanup necessary when a unit is destroyed.
+         * (Currently assumes this triggers certain game events, though not explicitly detailed
+         * here.)
+         */
+        ~Unit(){};
+
+        /**
+         * Renders the unit on the game screen.
+         * Uses the engine's rendering capabilities to draw the unit based on its state and faction.
+         *
+         * @param engine The game engine responsible for rendering.
+         * @param scale Scaling factor for rendering the unit.
+         */
         void render(Engine& engine, int scale);
 
-        /*
-        Check if attacker is in Range to initiate combat
-        TODO: This should probably tie back into rendering the units differently
-        If a unit is selected, it should call inRange on all other enemy units on the field
-        */
-
+        /**
+         * Determines if another unit (enemy) is within attack range.
+         * Checks for the range based on the unit's weapon capabilities.
+         *
+         * @param enemy The enemy unit to check range against.
+         * @return true if the enemy is in range, false otherwise.
+         */
         bool inRange(Unit& enemy);
 
-        /*
-        The attacker will move towards the defender and thus initiate combat
-        @params Takes a reference to the defender
-
-        Will Update the health for both units
-        Attacker deals damage to the defender first
-        */
-
+        /**
+         * Initiates an attack on a specified enemy unit.
+         * Calculates damage and updates health values for both the attacker and defender.
+         * Attacker damages the enemy first; if the enemy survives, a counter-attack may occur.
+         *
+         * @param enemy The unit being attacked.
+         */
         void attack(Unit& enemy);
 
+        /**
+         * Performs the calculated damage on a target unit, adjusting its health accordingly.
+         * Considers this unit's current health for scaling damage.
+         *
+         * @param target The target unit receiving damage.
+         * @param damage The amount of damage calculated to be applied.
+         */
         void performAttack(Unit& target, int damage);
 
+        /**
+         * Calculates the potential damage this unit can inflict on a target.
+         * Considers primary and secondary weapons' damage tables, and checks ammunition
+         * availability.
+         *
+         * @param target The unit to calculate damage against.
+         * @return The calculated damage value.
+         */
         int calculateDamage(Unit& target);
 
-        /*
-        @params Takes the desired position of the unit and updates its values
-        This will teleport the unit, there is no smooth transition between tiles
-        */
+        /**
+         * Updates this unit's position on the game field.
+         * Changes the internal position and recalculates the unit's state (e.g., direction it's
+         * facing) based on movement to a new position.
+         *
+         * @param posX The new x-coordinate for the unit.
+         * @param posY The new y-coordinate for the unit.
+         */
         void updatePosition(int posX, int posY);
 
-        /*
-        This function needs to be able to determine the possible movement-paths the unit can take
-        MUST take into consideration that different units behave differently on certain terrain
-        MUST show all movements possible
-        Requires dijkstras algorithm and the required graphs
-        */
+        /**
+         * Determines potential movement paths based on the unit's movement type and current
+         * terrain. (Intended to use Dijkstra's algorithm, though implementation details are omitted
+         * here.)
+         */
         void calculateMovement();
 
-        /*
-        This function calculates the difference between current position and desired position.
-        It updates the unit_state accordingly, so that the units face the correct direction.
-        */
+        /**
+         * Recalculates and updates the unit's state based on movement direction.
+         * Ensures that the unit faces the correct direction after a move.
+         *
+         * @param posX The x-coordinate of the desired position.
+         * @param posY The y-coordinate of the desired position.
+         */
         void calcState(int posX, int posY);
 
-        /*
-        This function will be called by an external event-handler, eventually.
-        It should start displaying standard unit information, such as UI and move_range
-        */
+        /**
+         * Processes a left-click event on this unit.
+         * Typically triggers display of unit information (e.g., UI and movement range).
+         *
+         * @param event SDL event captured, specifically mouse click event.
+         */
         void on_left_click(SDL_Event event);
 
+        /**
+         * Retrieves units within range that this unit can deal damage to.
+         * Considers all units provided in 'allUnits', excluding itself, and checks movement and
+         * weapon range.
+         *
+         * @param allUnits Vector of pointers to all units on the field to check against.
+         * @return Vector of pointers to units in range that can be engaged.
+         */
         std::vector<Unit*> getUnitsInRangeWithDamagePotential(const std::vector<Unit*>& allUnits);
 
-
     private:
-        UnitFaction m_faction;
-        UnitId      m_id;
-        UnitState   m_state;
-
-        int m_maxHealth; // max_health required for damage_scaling
-        int m_range;
-        /*
-        int m_fuel;
-        int m_maxFuel;*/
-
-        bool m_hasMoved;
-        bool m_hasAttacked;
-        bool m_isSelected;
-        bool m_isTargeted;
-
-        Weapon m_secondaryWeapon;
-        Weapon m_primaryWeapon;
-
-        int m_cost;
-        
-        int m_ammo;
-        int m_minRange;
-        int m_maxRange;
-};
+        UnitFaction m_faction; // The faction to which this unit belongs.
+        UnitId      m_id;      // The identifier for the unit type.
+        UnitState   m_state;   // The current state of the unit (idle, moving, etc.).
 
+        int m_maxHealth; // The maximum health of the unit.
+        int m_range;     // Possible range for future use, depending on specific unit abilities.
+
+        bool m_hasMoved;    // Indicates whether the unit has moved this turn.
+        bool m_hasAttacked; // Indicates whether the unit has attacked this turn.
+        bool m_isSelected;  // Indicates whether the unit is currently selected.
+        bool m_isTargeted;  // Indicates whether the unit is currently targeted by an enemy.
+
+        Weapon m_secondaryWeapon; // The unit's secondary weapon.
+        Weapon m_primaryWeapon;   // The unit's primary weapon.
+
+        int m_cost;     // The cost associated with deploying this unit.
+        int m_ammo;     // The amount of available ammo for attacks.
+        int m_minRange; // The minimum range of the unit's attack capability.
+        int m_maxRange; // The maximum range of the unit's attack capability.
+};
 } // namespace advanced_wars
\ No newline at end of file
-- 
GitLab


From dfc7bff529ba07bcfa266d65ed800dc0570f9bfd Mon Sep 17 00:00:00 2001
From: Frederik <frederik@prasch.de>
Date: Thu, 6 Feb 2025 01:24:29 +0100
Subject: [PATCH 08/10] Fix circular import by giving Config Ownership of all
 enums

---
 src/game/Building.hpp |  18 -------
 src/game/Config.cpp   |  44 +++++++++-------
 src/game/Config.hpp   | 114 +++++++++++++++++++++++++++++++++++++++++-
 src/game/Engine.cpp   |   2 +-
 src/game/Engine.hpp   |   6 +++
 src/game/Level.cpp    |   1 -
 src/game/Level.hpp    |  12 ++---
 src/game/Tile.hpp     |  38 +-------------
 src/game/Unit.hpp     |  61 ++--------------------
 9 files changed, 153 insertions(+), 143 deletions(-)

diff --git a/src/game/Building.hpp b/src/game/Building.hpp
index 2bceaa9..8dcb5cd 100644
--- a/src/game/Building.hpp
+++ b/src/game/Building.hpp
@@ -8,24 +8,6 @@
 namespace advanced_wars
 {
 
-enum class BuildingFaction
-{
-    URED = 0,
-    UBLUE = 1,
-    UGREEN = 2,
-    UYELLOW = 3,
-    UPURPLE = 4,
-};
-
-enum class BuildingId
-{
-    HEADQUARTER = 0,
-    CITY = 1,
-    FACTORY = 2,
-    AIRPORT = 3,
-    PORT = 4,
-};
-
 class Building
 {
     public:
diff --git a/src/game/Config.cpp b/src/game/Config.cpp
index 2a01848..b68d38f 100644
--- a/src/game/Config.cpp
+++ b/src/game/Config.cpp
@@ -11,7 +11,7 @@
 namespace advanced_wars
 {
 
-Config::Config(const std::string& filename)
+Config::Config(std::string filename)
 {
     namespace pt = boost::property_tree;
     pt::ptree tree;
@@ -220,27 +220,33 @@ std::string Config::getUnitSecondaryWeapon(UnitId id) const
     return "";
 }
 
-std::optional<int> Config::getUnitPrimaryWeaponDamage(UnitId attackerId, UnitId targetId) const {
-        auto attackerMapIt = m_primaryWeaponDamage.find(attackerId);
-        if (attackerMapIt != m_primaryWeaponDamage.end()) {
-            auto damageIt = attackerMapIt->second.find(targetId);
-            if (damageIt != attackerMapIt->second.end()) {
-                return damageIt->second;
-            }
+std::optional<int> Config::getUnitPrimaryWeaponDamage(UnitId attackerId, UnitId targetId) const
+{
+    auto attackerMapIt = m_primaryWeaponDamage.find(attackerId);
+    if (attackerMapIt != m_primaryWeaponDamage.end())
+    {
+        auto damageIt = attackerMapIt->second.find(targetId);
+        if (damageIt != attackerMapIt->second.end())
+        {
+            return damageIt->second;
         }
-        // Kein spezifischer Schaden vorhanden
-        return std::nullopt;
     }
+    // Kein spezifischer Schaden vorhanden
+    return std::nullopt;
+}
 
-std::optional<int> Config::getUnitSecondaryWeaponDamage(UnitId attackerId, UnitId targetId) const {
-        auto attackerMapIt = m_secondaryWeaponDamage.find(attackerId);
-        if (attackerMapIt != m_secondaryWeaponDamage.end()) {
-            auto damageIt = attackerMapIt->second.find(targetId);
-            if (damageIt != attackerMapIt->second.end()) {
-                return damageIt->second;
-            }
+std::optional<int> Config::getUnitSecondaryWeaponDamage(UnitId attackerId, UnitId targetId) const
+{
+    auto attackerMapIt = m_secondaryWeaponDamage.find(attackerId);
+    if (attackerMapIt != m_secondaryWeaponDamage.end())
+    {
+        auto damageIt = attackerMapIt->second.find(targetId);
+        if (damageIt != attackerMapIt->second.end())
+        {
+            return damageIt->second;
         }
-        // Kein spezifischer Schaden vorhanden
-        return std::nullopt;
     }
+    // Kein spezifischer Schaden vorhanden
+    return std::nullopt;
+}
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Config.hpp b/src/game/Config.hpp
index d3f43fd..b0289ce 100644
--- a/src/game/Config.hpp
+++ b/src/game/Config.hpp
@@ -1,14 +1,124 @@
 #pragma once
 
-#include "Unit.hpp" // Include for UnitId and MovementType
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/xml_parser.hpp>
+#include <optional>
 #include <stdexcept>
 #include <string>
 #include <unordered_map>
 
 namespace advanced_wars
 {
+/* ENUMS FOR GLOBAL USE*/
+enum class BuildingFaction
+{
+    URED = 0,
+    UBLUE = 1,
+    UGREEN = 2,
+    UYELLOW = 3,
+    UPURPLE = 4,
+};
+
+enum class BuildingId
+{
+    HEADQUARTER = 0,
+    CITY = 1,
+    FACTORY = 2,
+    AIRPORT = 3,
+    PORT = 4,
+};
+
+enum class UnitFaction
+{
+    URED = 0,
+    UBLUE = 1,
+    UGREEN = 2,
+    UYELLOW = 3,
+    UPURPLE = 4,
+};
+
+enum class UnitId
+{
+    INFANTERY = 0,
+    MECHANIZED_INFANTERY = 1,
+    RECON = 2,
+    MEDIUM_TANK = 3,
+    HEAVY_TANK = 4,
+    NEO_TANK = 5,
+    APC = 6,
+    ANTI_AIR_TANK = 7,
+    ARTILLERY = 8,
+    ROCKET_ARTILLERY = 9,
+    ANTI_AIR_MISSILE_LAUNCHER = 10,
+    FIGHTER = 11,
+    BOMBER = 12,
+    BATTLE_HELICOPTER = 13,
+    TRANSPORT_HELICOPTER = 14,
+    BATTLESHIP = 15,
+    CRUISER = 16,
+    LANDER = 17,
+    SUBMARINE = 18,
+
+    FIRST = INFANTERY,
+    LAST = SUBMARINE
+};
+
+enum class UnitState
+{
+    IDLE = 0,
+    UNAVAILABLE = 1,
+    MOVEMENTLEFT = 2,
+    MOVEMENTRIGHT = 3,
+    MOVEMENTDOWN = 4,
+    MOVEMENTUP = 5,
+};
+
+enum class MovementType
+{
+    FOOT = 0,
+    WHEELED = 1,
+    TREAD = 2,
+    AIR = 3,
+    SEA = 4,
+    LANDER = 5,
+};
+
+enum class TileId
+{
+    PLAIN = 0,
+    WATER = 1,
+    FOREST = 2,
+    MOUNTAIN = 3,
+    BRIDGE_HORIZONTAL = 4,
+    BRIDGE_VERTICAL = 5,
+    STREET_HORIZONTAL = 6,
+    STREET_VERTICAL = 7,
+    STREET_CROSSING = 8,
+    STREET_JUNCTION_RIGHT = 9,
+    STREET_JUNCTION_LEFT = 10,
+    STREET_JUNCTION_DOWN = 11,
+    STREET_JUNCTION_UP = 12,
+    STREET_CORNER_TOP_LEFT = 13,
+    STREET_CORNER_TOP_RIGHT = 14,
+    STREET_CORNER_BOTTOM_LEFT = 15,
+    STREET_CORNER_BOTTOM_RIGHT = 16,
+    RIFF = 17,
+    CLIFF_TOP = 18,
+    CLIFF_BOTTOM = 19,
+    CLIFF_LEFT = 20,
+    CLIFF_RIGHT = 21,
+    CLIFF_CORNER_TOP_LEFT = 22,
+    CLIFF_CORNER_TOP_RIGHT = 23,
+    CLIFF_CORNER_BOTTOM_LEFT = 24,
+    CLIFF_CORNER_BOTTOM_RIGHT = 25,
+    CLIFF_INVERSE_CORNER_TOP_LEFT = 26,
+    CLIFF_INVERSE_CORNER_TOP_RIGHT = 27,
+    CLIFF_INVERSE_CORNER_BOTTOM_LEFT = 28,
+    CLIFF_INVERSE_CORNER_BOTTOM_RIGHT = 29,
+};
+
+/* END OF ALL ENUMS*/
+
 /**
  * @class Config
  * @brief Parses and stores unit configuration data from an XML file.
@@ -28,7 +138,7 @@ class Config
          * @param filename Path to the XML configuration file.
          * @throws std::runtime_error if the file cannot be read or parsed.
          */
-        explicit Config(const std::string& filename);
+        Config(std::string filename);
 
         /** @brief Retrieves the cost of a given unit type. */
         int getUnitCost(UnitId id) const;
diff --git a/src/game/Engine.cpp b/src/game/Engine.cpp
index 7639be5..b1c7039 100644
--- a/src/game/Engine.cpp
+++ b/src/game/Engine.cpp
@@ -15,7 +15,7 @@
 namespace advanced_wars
 {
 
-Engine::Engine(Window& window) : m_window(window), m_quit(false)
+Engine::Engine(Window& window) : m_window(window), m_quit(false), m_unitConfig("../config.xml")
 {
 
     this->m_SDLRenderer = SDL_CreateRenderer(
diff --git a/src/game/Engine.hpp b/src/game/Engine.hpp
index 4ecbf8b..feb8447 100644
--- a/src/game/Engine.hpp
+++ b/src/game/Engine.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "Config.hpp"
 #include "SDL_events.h"
 #include "Scene.hpp"
 #include "Spritesheet.hpp"
@@ -15,6 +16,7 @@ namespace advanced_wars
 
 // Forward declaration
 class Scene;
+class Config;
 
 /**
  * @brief The main window of the game
@@ -47,6 +49,8 @@ class Engine
 
         int getStage();
 
+        Config& getUnitConfig();
+
         void render();
 
         SDL_Renderer* renderer();
@@ -62,6 +66,8 @@ class Engine
 
         bool m_quit;
         int  m_stage;
+
+        Config m_unitConfig;
 };
 
 } // namespace advanced_wars
diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index fa2ff42..d08f68e 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -149,7 +149,6 @@ int Level::selectBuilding(int tileX, int tileY)
     return -1;
 }
 
-
 void Level::handleEvent(Engine& engine, SDL_Event& event)
 {
     switch (m_state)
diff --git a/src/game/Level.hpp b/src/game/Level.hpp
index ba69b98..f3f25a1 100644
--- a/src/game/Level.hpp
+++ b/src/game/Level.hpp
@@ -7,17 +7,14 @@
 #include "Tile.hpp"
 #include "Unit.hpp"
 #include "ui/Contextmenu.hpp"
-#include "ui/TileMarker.hpp"
 #include "ui/Recruitingmenu.hpp"
+#include "ui/TileMarker.hpp"
 #include <SDL.h>
+#include <array>
 #include <string>
 #include <unordered_map>
-#include <vector>
-#include <array>
 #include <unordered_set>
-
-
-
+#include <vector>
 
 namespace advanced_wars
 {
@@ -120,9 +117,6 @@ class Level : public Scene
 
         std::vector<std::pair<int, int>> m_attackableTiles;
 
-        
-        
-
     private:
         std::string                       m_name;
         int                               m_width;
diff --git a/src/game/Tile.hpp b/src/game/Tile.hpp
index 7a3d838..ff137b8 100644
--- a/src/game/Tile.hpp
+++ b/src/game/Tile.hpp
@@ -6,40 +6,6 @@
 namespace advanced_wars
 {
 
-enum class TileId
-{
-    PLAIN = 0,
-    WATER = 1,
-    FOREST = 2,
-    MOUNTAIN = 3,
-    BRIDGE_HORIZONTAL = 4,
-    BRIDGE_VERTICAL = 5,
-    STREET_HORIZONTAL = 6,
-    STREET_VERTICAL = 7,
-    STREET_CROSSING = 8,
-    STREET_JUNCTION_RIGHT = 9,
-    STREET_JUNCTION_LEFT = 10,
-    STREET_JUNCTION_DOWN = 11,
-    STREET_JUNCTION_UP = 12,
-    STREET_CORNER_TOP_LEFT = 13,
-    STREET_CORNER_TOP_RIGHT = 14,
-    STREET_CORNER_BOTTOM_LEFT = 15,
-    STREET_CORNER_BOTTOM_RIGHT = 16,
-    RIFF = 17,
-    CLIFF_TOP = 18,
-    CLIFF_BOTTOM = 19,
-    CLIFF_LEFT = 20,
-    CLIFF_RIGHT = 21,
-    CLIFF_CORNER_TOP_LEFT = 22,
-    CLIFF_CORNER_TOP_RIGHT = 23,
-    CLIFF_CORNER_BOTTOM_LEFT = 24,
-    CLIFF_CORNER_BOTTOM_RIGHT = 25,
-    CLIFF_INVERSE_CORNER_TOP_LEFT = 26,
-    CLIFF_INVERSE_CORNER_TOP_RIGHT = 27,
-    CLIFF_INVERSE_CORNER_BOTTOM_LEFT = 28,
-    CLIFF_INVERSE_CORNER_BOTTOM_RIGHT = 29,
-};
-
 class Tile
 {
     public:
@@ -48,8 +14,8 @@ class Tile
         int    m_x;
         int    m_y;
 
-        void render(Engine& engine, int scale);
-        TileId getType() const; 
+        void   render(Engine& engine, int scale);
+        TileId getType() const;
 };
 
 } // namespace advanced_wars
\ No newline at end of file
diff --git a/src/game/Unit.hpp b/src/game/Unit.hpp
index 249783c..2202f93 100644
--- a/src/game/Unit.hpp
+++ b/src/game/Unit.hpp
@@ -3,69 +3,16 @@
 #include "Engine.hpp"
 
 #include "Weapon.hpp"
+#include <SDL_events.h>
 #include <optional>
 #include <unordered_map>
+#include <vector>
 
 namespace advanced_wars
 {
-
+class Engine;
 class Config;
 
-enum class UnitFaction
-{
-    URED = 0,
-    UBLUE = 1,
-    UGREEN = 2,
-    UYELLOW = 3,
-    UPURPLE = 4,
-};
-
-enum class UnitId
-{
-    INFANTERY = 0,
-    MECHANIZED_INFANTERY = 1,
-    RECON = 2,
-    MEDIUM_TANK = 3,
-    HEAVY_TANK = 4,
-    NEO_TANK = 5,
-    APC = 6,
-    ANTI_AIR_TANK = 7,
-    ARTILLERY = 8,
-    ROCKET_ARTILLERY = 9,
-    ANTI_AIR_MISSILE_LAUNCHER = 10,
-    FIGHTER = 11,
-    BOMBER = 12,
-    BATTLE_HELICOPTER = 13,
-    TRANSPORT_HELICOPTER = 14,
-    BATTLESHIP = 15,
-    CRUISER = 16,
-    LANDER = 17,
-    SUBMARINE = 18,
-
-    FIRST = INFANTERY,
-    LAST = SUBMARINE
-};
-
-enum class UnitState
-{
-    IDLE = 0,
-    UNAVAILABLE = 1,
-    MOVEMENTLEFT = 2,
-    MOVEMENTRIGHT = 3,
-    MOVEMENTDOWN = 4,
-    MOVEMENTUP = 5,
-};
-
-enum class MovementType
-{
-    FOOT = 0,
-    WHEELED = 1,
-    TREAD = 2,
-    AIR = 3,
-    SEA = 4,
-    LANDER = 5,
-};
-
 using MatchupTable = std::unordered_map<UnitId, std::unordered_map<UnitId, int>>;
 
 class Unit
@@ -91,7 +38,7 @@ class Unit
          * (Currently assumes this triggers certain game events, though not explicitly detailed
          * here.)
          */
-        ~Unit(){};
+        ~Unit() {};
 
         /**
          * Renders the unit on the game screen.
-- 
GitLab


From 58a847207d008053567330e3d6b412d81e52d21c Mon Sep 17 00:00:00 2001
From: Frederik <frederik@prasch.de>
Date: Thu, 6 Feb 2025 01:25:26 +0100
Subject: [PATCH 09/10] Fix EventHandler for Movement and Attack range that got
 broken by merge

---
 src/game/Engine.cpp |   5 ++
 src/game/Level.cpp  | 129 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 103 insertions(+), 31 deletions(-)

diff --git a/src/game/Engine.cpp b/src/game/Engine.cpp
index b1c7039..83f03f5 100644
--- a/src/game/Engine.cpp
+++ b/src/game/Engine.cpp
@@ -120,6 +120,11 @@ Spritesheet* Engine::getSpritesheet()
     return m_spritesheet.value();
 }
 
+Config& Engine::getUnitConfig()
+{
+    return m_unitConfig;
+}
+
 SDL_Renderer* Engine::renderer()
 {
     return this->m_SDLRenderer;
diff --git a/src/game/Level.cpp b/src/game/Level.cpp
index d08f68e..44f36ee 100644
--- a/src/game/Level.cpp
+++ b/src/game/Level.cpp
@@ -371,7 +371,8 @@ Effect Level::removeEffect(int id)
     return value;
 }
 
-void Level::handleRecruitingEvent(Engine& engine, SDL_Event& event) {
+void Level::handleRecruitingEvent(Engine& engine, SDL_Event& event)
+{
 
     switch (event.type)
     {
@@ -384,21 +385,25 @@ void Level::handleRecruitingEvent(Engine& engine, SDL_Event& event) {
         {
             m_recruitingMenu.handleEvent(engine, event);
         }
-        if (event.key.keysym.sym == SDLK_RETURN) 
+        if (event.key.keysym.sym == SDLK_RETURN)
         {
-            Building& b = m_buildings.at(m_selectedBuilding);
-            UnitFaction u_faction = static_cast<UnitFaction> (b.m_faction);
-            UnitId unit_id = m_recruitingMenu.getSelectedOption();
+            Building&   b = m_buildings.at(m_selectedBuilding);
+            UnitFaction u_faction = static_cast<UnitFaction>(b.m_faction);
+            UnitId      unit_id = m_recruitingMenu.getSelectedOption();
 
-            if(b.check_money(500)) {
-                if(b.check_spawn(m_units)){
-                    addUnit(Unit(b.m_x, b.m_y, u_faction, unit_id, UnitState::IDLE));
+            if (b.check_money(500))
+            {
+                if (b.check_spawn(m_units))
+                {
+                    addUnit(Unit(
+                        b.m_x, b.m_y, u_faction, unit_id, UnitState::IDLE, engine.getUnitConfig()));
                     m_state = LevelState::SELECTING_STATE;
                     m_selectedBuilding = -1;
                 }
             }
         }
-}}
+    }
+}
 
 //*******************helper functions for event Handling*************************************
 
@@ -415,17 +420,27 @@ void Level::handleAttack(std::pair<int, int> tilePos)
 
         Unit& attacking = m_units.at(m_selectedUnit);
         Unit& defending = m_units.at(targetedUnit);
-        attacking.attack(defending);
-        if (attacking.m_health <= 0)
+
+        if (m_attackableUnitIds.find(targetedUnit) != m_attackableUnitIds.end())
         {
-            removeUnit(m_selectedUnit);
+            attacking.attack(defending);
+            if (attacking.m_health <= 0)
+            {
+                removeUnit(m_selectedUnit);
+            }
+            if (defending.m_health <= 0)
+            {
+                removeUnit(targetedUnit);
+            }
+            m_selectedUnit = -1;
+            m_showAttackableTiles = false;
+            m_showReachableTiles = false;
+            m_state = LevelState::SELECTING_STATE;
         }
-        if (defending.m_health <= 0)
+        else
         {
-            removeUnit(targetedUnit);
+            std::cout << "No target in range clicked!" << std::endl;
         }
-        m_selectedUnit = -1;
-        m_state = LevelState::SELECTING_STATE;
     }
     else
     {
@@ -444,9 +459,30 @@ void Level::handleMovement(std::pair<int, int> tilePos)
             return;
         }
     }
-    m_units.at(m_selectedUnit).updatePosition(tilePos.first, tilePos.second);
-    m_selectedUnit = -1;
-    m_state = LevelState::SELECTING_STATE;
+
+    bool isReachable = false;
+
+    for (auto& pos : m_reachableTiles)
+    {
+        if (pos == tilePos)
+        {
+            isReachable = true;
+            break;
+        }
+    }
+
+    if (isReachable)
+    {
+        m_units.at(m_selectedUnit).updatePosition(tilePos.first, tilePos.second);
+        m_selectedUnit = -1;
+        m_showAttackableTiles = false;
+        m_showReachableTiles = false;
+        m_state = LevelState::SELECTING_STATE;
+    }
+    else
+    {
+        std::cout << "Unglültige Bewegunsposition!" << std::endl;
+    }
 }
 
 void Level::handlePositionMarker(Engine& engine, SDL_Event& event)
@@ -486,6 +522,40 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event)
                     (tilePos.second * 16 + 15) * RENDERING_SCALE);
                 if (m_selectedUnit >= 0)
                 {
+                    m_reachableTiles = calculateMovementRange(m_units.at(m_selectedUnit));
+                    m_units.at(m_selectedUnit).on_left_click(event);
+                    m_showReachableTiles = true;
+
+                    std::vector<Unit*> allUnits;
+
+                    for (auto& [id, unit] : m_units)
+                    {
+                        allUnits.push_back(&unit);
+                    }
+
+                    std::vector<Unit*> attackableTargets =
+                        m_units.at(m_selectedUnit).getUnitsInRangeWithDamagePotential(allUnits);
+
+                    m_attackableTiles.clear();
+                    m_showAttackableTiles = true;
+                    m_attackableUnitIds.clear();
+
+                    for (Unit* target : attackableTargets)
+                    {
+                        // Füge die Position jedes angreifbaren Ziels hinzu
+                        m_attackableTiles.emplace_back(target->m_x, target->m_y);
+
+                        // Angreifbaren Einheits-ID setzen
+                        for (auto& [id, unit] : m_units)
+                        {
+                            if (&unit == target)
+                            {
+                                m_attackableUnitIds.insert(id);
+                                break;
+                            }
+                        }
+                    }
+
                     m_contextMenu.setOptions({"Move", "Attack", "Info", "Wait"});
                 }
                 else
@@ -519,6 +589,8 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event)
             }
             else
             {
+                m_showReachableTiles = false;
+                m_showAttackableTiles = false;
                 m_state = LevelState::SELECTING_STATE;
             }
         }
@@ -537,6 +609,8 @@ void Level::handleMenuActiveEvents(Engine& engine, SDL_Event& event)
             m_selectedUnit = -1;
             m_selectedBuilding = -1;
             m_state = LevelState::SELECTING_STATE;
+            m_showAttackableTiles = false;
+            m_showReachableTiles = false;
         }
         if (event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_DOWN)
         {
@@ -580,18 +654,11 @@ void Level::handleMenuActiveEvents(Engine& engine, SDL_Event& event)
                 m_recruitingMenu.update(
                     (tilePos.first * 16 + 15) * RENDERING_SCALE,
                     (tilePos.second * 16 + 15) * RENDERING_SCALE);
-                m_recruitingMenu.setOptions({
-            UnitId::INFANTERY,
-            UnitId::MECHANIZED_INFANTERY,
-            UnitId::RECON,
-            UnitId::APC,
-            UnitId::ARTILLERY,
-            UnitId::ANTI_AIR_TANK,
-            UnitId::ANTI_AIR_MISSILE_LAUNCHER,
-            UnitId::ROCKET_ARTILLERY,
-            UnitId::MEDIUM_TANK,
-            UnitId::NEO_TANK,
-            UnitId::HEAVY_TANK});
+                m_recruitingMenu.setOptions(
+                    {UnitId::INFANTERY, UnitId::MECHANIZED_INFANTERY, UnitId::RECON, UnitId::APC,
+                     UnitId::ARTILLERY, UnitId::ANTI_AIR_TANK, UnitId::ANTI_AIR_MISSILE_LAUNCHER,
+                     UnitId::ROCKET_ARTILLERY, UnitId::MEDIUM_TANK, UnitId::NEO_TANK,
+                     UnitId::HEAVY_TANK});
                 std::cout << "no training here" << std::endl;
             }
         }
-- 
GitLab


From 0291139d27babe00618eb30a8be98b51964399f0 Mon Sep 17 00:00:00 2001
From: Frederik <frederik@prasch.de>
Date: Thu, 6 Feb 2025 01:27:15 +0100
Subject: [PATCH 10/10] Fix Inverse cliff corners having wrong move cost

---
 src/game/Level.hpp | 67 +++++++++++++++++++++++-----------------------
 1 file changed, 34 insertions(+), 33 deletions(-)

diff --git a/src/game/Level.hpp b/src/game/Level.hpp
index f3f25a1..c4d0628 100644
--- a/src/game/Level.hpp
+++ b/src/game/Level.hpp
@@ -22,39 +22,40 @@ namespace advanced_wars
 const int NUM_TILE_IDS = 30; // Aktualisieren, falls weitere IDs hinzugefügt werden
 const int NUM_MOVEMENT_TYPES = 6;
 
-
-const std::array<std::array<int, NUM_MOVEMENT_TYPES>, NUM_TILE_IDS> moveCostTable = {{
-    // FOOT, WHEELED, TREAD, AIR, SEA, LANDER
-    {  1,      2,       1,    1, 999,   999 }, // PLAIN
-    {999,    999,     999,    1,   1,     1 }, // WATER
-    {  1,      3,       2,    1, 999,   999 }, // FOREST
-    {  2,    999,     999,    1, 999,   999 }, // MOUNTAIN
-    {  1,      1,       1,    1, 999,   999 }, // BRIDGE_HORIZONTAL
-    {  1,      1,       1,    1, 999,   999 }, // STREET_HORIZONTAL
-    {  1,      1,       1,    1, 999,   999 }, // STREET_VERTICAL
-    {  1,      1,       1,    1, 999,   999 }, // STREET_CROSSING
-    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_RIGHT
-    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_LEFT
-    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_DOWN
-    {  1,      1,       1,    1, 999,   999 }, // STREET_JUNCTION_UP
-    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_TOP_LEFT
-    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_TOP_RIGHT
-    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_BOTTOM_LEFT
-    {  1,      1,       1,    1, 999,   999 }, // STREET_CORNER_BOTTOM_RIGHT 
-    {999,    999,     999,    1,   2,     2 }, // RIFF
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_TOP
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_BOTTOM
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_LEFT
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_RIGHT
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_TOP_LEFT
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_TOP_RIGHT
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_BOTTOM_LEFT
-    {999,    999,     999,    1,   1,     1 }, // CLIFF_CORNER_BOTTOM_RIGHT
-    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_TOP_LEFT
-    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_TOP_RIGHT
-    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_BOTTOM_LEFT
-    {  1,      2,       1,    1, 999,   999 }, // CLIFF_INVERSE_CORNER_BOTTOM_RIGHT
-}};
+const std::array<std::array<int, NUM_MOVEMENT_TYPES>, NUM_TILE_IDS> moveCostTable = {
+    {
+     // FOOT, WHEELED, TREAD, AIR, SEA, LANDER
+        {1, 2, 1, 1, 999, 999},     // PLAIN
+        {999, 999, 999, 1, 1, 1},   // WATER
+        {1, 3, 2, 1, 999, 999},     // FOREST
+        {2, 999, 999, 1, 999, 999}, // MOUNTAIN
+        {1, 1, 1, 1, 999, 999},     // BRIDGE_HORIZONTAL
+        {1, 1, 1, 1, 999, 999},     // STREET_HORIZONTAL
+        {1, 1, 1, 1, 999, 999},     // STREET_VERTICAL
+        {1, 1, 1, 1, 999, 999},     // STREET_CROSSING
+        {1, 1, 1, 1, 999, 999},     // STREET_JUNCTION_RIGHT
+        {1, 1, 1, 1, 999, 999},     // STREET_JUNCTION_LEFT
+        {1, 1, 1, 1, 999, 999},     // STREET_JUNCTION_DOWN
+        {1, 1, 1, 1, 999, 999},     // STREET_JUNCTION_UP
+        {1, 1, 1, 1, 999, 999},     // STREET_CORNER_TOP_LEFT
+        {1, 1, 1, 1, 999, 999},     // STREET_CORNER_TOP_RIGHT
+        {1, 1, 1, 1, 999, 999},     // STREET_CORNER_BOTTOM_LEFT
+        {1, 1, 1, 1, 999, 999},     // STREET_CORNER_BOTTOM_RIGHT
+        {999, 999, 999, 1, 2, 2},   // RIFF
+        {999, 999, 999, 1, 1, 1},   // CLIFF_TOP
+        {999, 999, 999, 1, 1, 1},   // CLIFF_BOTTOM
+        {999, 999, 999, 1, 1, 1},   // CLIFF_LEFT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_RIGHT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_CORNER_TOP_LEFT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_CORNER_TOP_RIGHT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_CORNER_BOTTOM_LEFT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_CORNER_BOTTOM_RIGHT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_INVERSE_CORNER_TOP_LEFT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_INVERSE_CORNER_TOP_RIGHT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_INVERSE_CORNER_BOTTOM_LEFT
+        {999, 999, 999, 1, 1, 1},   // CLIFF_INVERSE_CORNER_BOTTOM_RIGHT
+    }
+};
 
 enum class LevelState
 {
-- 
GitLab