Nimbin[12]?SDL & Graphics / mapcreator / commits / 3121b26

mapcreator git · master

SDL3 2.5D game and engine using assets, with map editor

sdl3 c++ game engine map-editor cmake · first commit 2025-10-31 · last commit 2026-09-07 (1 month ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-spieleentwicklung/map_creator

C++ 99.3%
git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gz

Add Consume food

Christian Immanuel · 2026-02-15 12:49 · 3121b2666c239c95087b2b6cfbb1e4032721adee

 src/character/animation.hpp   |   1 +
 src/character/character.cpp   | 254 +++++++++++++++++++++++++++++++++---------
 src/character/character.hpp   |  56 +++++++---
 src/character/enemy.cpp       |   6 +-
 src/character/message.cpp     |   1 +
 src/character/message.hpp     |   1 +
 src/defaults/ui.cpp           | 199 ++++++++++++++++++++++++++++-----
 src/defaults/ui.hpp           |   2 +-
 src/game/state_playing.cpp    |   4 +-
 src/inventory/inventory.cpp   |  12 +-
 src/inventory/inventory.hpp   |   9 +-
 src/vegetables/vegetables.cpp |  14 +--
 src/vegetables/vegetables.hpp |  10 ++
 13 files changed, 461 insertions(+), 108 deletions(-)

diff --git a/src/character/animation.hpp b/src/character/animation.hpp
index df3bf2a..693b0a3 100644
--- a/src/character/animation.hpp
+++ b/src/character/animation.hpp
@@ -44,6 +44,7 @@ struct CharacterAnimation {
     std::unordered_map<WalkDirection, AnimationData> craft;
     std::unordered_map<WalkDirection, AnimationData> block;
     std::unordered_map<WalkDirection, AnimationData> drinking_river;
+    std::unordered_map<WalkDirection, AnimationData> eating;
 };
 
 namespace Animation {
diff --git a/src/character/character.cpp b/src/character/character.cpp
index 2369794..76da0a5 100644
--- a/src/character/character.cpp
+++ b/src/character/character.cpp
@@ -58,16 +58,17 @@ Character::Init(SDL_Renderer* renderer) {
     arm_reach_radius = 6;
     collecting_logic.is_collecting = false;
 
-    stats = { 10, 10, 10, 10, 50, 100, 1};
+    stats = { 25, 0, 25, 0, 50, 100, 2};
 
     attacking_logic   = { 0.0f, nullptr, AttackingLogicStatus_e::NONE, false, nullptr };
-    consuming_logic   = { 0.0f, 3.0f, false, nullptr };
+    consuming_logic   = { 0.0f, 3.0f, false, false, nullptr };
     cultivation_logic = { 0.0f, 3.0f, false, false, {0,0} };
     planting_logic    = { 0.0f, 3.0f, false, {0,0}, VegetableData::Type::NONE, false};
     sprintstart_logic = {0, 0.8, false};
 
     death_duration = 0;
     death_duration_max = 0.8;
+    death_shuffler = nullptr;
 
     is_placing_build = false;
 
@@ -135,6 +136,10 @@ Character::Init(SDL_Renderer* renderer) {
     animation.drinking_river[WalkDirection::SIDE] = Animation::load(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Collect_Base/Collect_Side-Sheet.png", tile_size, tile_size, "character.drink", false, false);
     animation.drinking_river[WalkDirection::UP]   = Animation::load(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Collect_Base/Collect_Up-Sheet.png",   tile_size, tile_size, "character.drink", false, false);
 
+    animation.eating[WalkDirection::DOWN] = Animation::load(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Collect_Base/Collect_Down-Sheet.png", tile_size, tile_size, "character.eat", false, false);
+    animation.eating[WalkDirection::SIDE] = Animation::load(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Collect_Base/Collect_Side-Sheet.png", tile_size, tile_size, "character.eat", false, false);
+    animation.eating[WalkDirection::UP]   = Animation::load(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Collect_Base/Collect_Up-Sheet.png",   tile_size, tile_size, "character.eat", false, false);
+
     Animation::audio->RegisterSound("character.dead", "music/character.dead.wav");
 
     handle_Animation();
@@ -671,6 +676,48 @@ Character::interact_WithBuilding(Building* building, Input& input) {
 }
 
 
+bool
+Character::is_StatsBonusAlready(InventoryObjectType object_type, uint32_t type) {
+    for (CharacterStatsBonus& b : stats_bonus)
+        if (b.object_type == object_type && b.type == type)
+            return true;
+
+    return false;
+}
+
+void
+Character::add_ToStatsBonus(InventoryObjectType object_type,
+                            uint32_t type,
+                            ConsumingStatsBonus sb) {
+    for (auto& entry : stats_bonus) {
+        if (entry.object_type == object_type &&
+            entry.type == type)
+        {
+            entry.stats = sb;
+            return;
+        }
+    }
+
+    if (stats_bonus.size() >= 2) {
+        std::cout << "I am overfed\n";
+        return;
+    }
+
+    stats_bonus.push_back({object_type, type, sb.duration, sb});
+}
+
+void
+Character::reduce_StatsBonus() {
+    for (auto it = stats_bonus.begin(); it != stats_bonus.end(); ) {
+        it->duration -= Default::delta_time;
+
+        if (it->duration <= 0.0f)
+            it = stats_bonus.erase(it);
+        else
+            ++it;
+    }
+}
+
 void
 Character::attack_Start() {
     std::cout << "Attack Start\n";
@@ -802,6 +849,49 @@ Character::building_Stop() {
     is_placing_build = false;
 }
 
+
+void
+Character::eat_Start() {
+    std::cout << "Eating Start\n";
+    if ( stats_bonus.size() >= 2 &&
+         !is_StatsBonusAlready(selected_item->object_type, static_cast<uint32_t>(static_cast<InventoryVegetable*>(selected_item)->type)))
+            return;
+
+    messages->Add(MessageKey::EAT_APPRECIATION);
+    set_Status(CharacterStatus::EATING);
+    handle_Animation();
+    consuming_logic.duration     = 0.0;
+    consuming_logic.duration_max = 3.0f;
+    consuming_logic.is_consuming = true;
+    consuming_logic.is_drinking  = false;
+}
+
+void
+Character::eat_Something() {
+    // std::cout << "Eating ...\n";
+    if (consuming_logic.duration < consuming_logic.duration_max) {
+        consuming_logic.duration += Default::delta_time;
+        float stamina_per_second = 0.01f / consuming_logic.duration_max;
+        stamina_Reduce(stamina_per_second);
+        if (stamina_Get() <= 0) {
+            stamina_StopReg();
+            messages->Add(MessageKey::PLAYER_EXHAUSTED);
+            consume_Stop();
+        }
+        return;
+    }
+
+    std::cout << "EATING COMPLETE\n";
+    //InventoryVegetable
+    if (selected_item->object_type == InventoryObjectType::VEGETABLE) {
+        InventoryVegetable* it = static_cast<InventoryVegetable*>(selected_item);
+        inventory->remove_Vegetable(it->type, 1);
+        add_ToStatsBonus(InventoryObjectType::VEGETABLE, static_cast<uint32_t>(it->type), it->stats_bonus);
+    }
+
+    consume_Stop();
+}
+
 void
 Character::drink_Start() {
     std::cout << "Drinking Start\n";
@@ -812,22 +902,23 @@ Character::drink_Start() {
     handle_Animation();
     consuming_logic.duration = 0.0;
     consuming_logic.is_consuming = true;
+    consuming_logic.is_drinking  = true;
 }
 
 void
 Character::drink_River() {
     // std::cout << "Drinking ...\n";
     if (consuming_logic.duration < consuming_logic.duration_max) {
-        if (stats.stamina <= 0 || stats.thirst >= stats.thirst_max) {
-            drink_Stop();
+        if (stamina_Get() <= 0 || stats.thirst >= stats.thirst_max) {
+            consume_Stop();
             return;
         }
         consuming_logic.duration += Default::delta_time;
         float amount_per_second = 25.0f / consuming_logic.duration_max;
         stats.thirst += amount_per_second * Default::delta_time;
         float stamina_per_second = 0.01f / consuming_logic.duration_max;
-        stats.stamina -= stamina_per_second;
-        if (stats.stamina <= 0) {
+        stamina_Reduce(stamina_per_second);
+        if (stamina_Get() <= 0) {
             stamina_StopReg();
             messages->Add(MessageKey::PLAYER_EXHAUSTED);
         }
@@ -836,14 +927,14 @@ Character::drink_River() {
 
     if (stats.thirst > stats.thirst_max)
         stats.thirst = stats.thirst_max;
-    stats.health += 2;
-    if (stats.health > stats.health_max)
-        stats.health = stats.health_max;
-    drink_Stop();
+
+    health_Increase(2);
+
+    consume_Stop();
 }
 void
-Character::drink_Stop() {
-    std::cout << "Drinking Stopped\n";
+Character::consume_Stop() {
+    std::cout << "Consuming Stopped\n";
     consuming_logic.duration = 0.0;
     consuming_logic.is_consuming = false;
     set_Status(CharacterStatus::IDLE);
@@ -856,7 +947,7 @@ Character::cultivate_Start() {
     std::cout << "FT: " << floor_type << " " << Map::get_IdFromTilePoint(tile_world) << std::endl;
     if (!Tile::floor_props[floor_type].can_buid_on)
         return;
-    if (stats.stamina <= 0)
+    if (stamina_Get() <= 0)
         return;
 
     if ( Farm::soil_IsMaptile(tile_world) &&
@@ -871,15 +962,15 @@ Character::cultivate_Start() {
 }
 void
 Character::cultivate_Soil() {
-    if (stats.stamina <= 0) {
+    if (stamina_Get() <= 0) {
         cultivate_Stop();
         return;
     }
     cultivation_logic.duration += Default::delta_time;
 
     float stamina_per_second = 0.06f / cultivation_logic.duration_max;
-    stats.stamina -= stamina_per_second;
-    if (stats.stamina <= 0) {
+    stamina_Reduce(stamina_per_second);
+    if (stamina_Get() <= 0) {
         stamina_StopReg();
         messages->Add(MessageKey::PLAYER_EXHAUSTED);
         cultivate_Stop();
@@ -904,7 +995,7 @@ Character::cultivate_Stop() {
 void
 Character::plant_Start() {
     std::cout << "Plant Start\n";
-    if (stats.stamina <= 0)
+    if (stamina_Get() <= 0)
         return;
     if (!Farm::soil_IsMaptile(tile_world))
         return;
@@ -924,15 +1015,15 @@ Character::plant_Start() {
 
 void
 Character::plant_Vegetable() {
-    if (stats.stamina <= 0) {
+    if (stamina_Get() <= 0) {
         plant_Stop();
         return;
     }
     planting_logic.duration += Default::delta_time;
 
     float stamina_per_second = 0.06f / planting_logic.duration_max;
-    stats.stamina -= stamina_per_second;
-    if (stats.stamina <= 0) {
+    stamina_Reduce(stamina_per_second);
+    if (stamina_Get() <= 0) {
         stamina_StopReg();
         messages->Add(MessageKey::PLAYER_EXHAUSTED);
         plant_Stop();
@@ -963,9 +1054,63 @@ Character::plant_Stop() {
 }
 
 
+float
+Character::health_Get() {
+    return health_Max() - stats.health_reduced;
+}
+float
+Character::health_Max() {
+    return stats.health_max + health_MaxBonus();
+}
+float
+Character::health_MaxBonus() {
+    float h = 0.0f;
+    for (auto& e : stats_bonus) {
+        h += e.stats.health;
+    }
+    return h;
+}
+void
+Character::health_Reduce(float amount) {
+    stats.health_reduced += amount;
+}
+void
+Character::health_Increase(float amount) {
+    stats.health_reduced -= amount;
+    if (stats.health_reduced < 0.0f)
+        stats.health_reduced = 0.0;
+}
+
+float
+Character::stamina_Get() {
+    return stamina_Max() - stats.stamina_reduced;
+}
+float
+Character::stamina_Max() {
+    return stats.stamina_max + stamina_MaxBonus();
+}
+float
+Character::stamina_MaxBonus() {
+    float s = 0.0f;
+    for (auto& e : stats_bonus) {
+        s += e.stats.stamina;
+    }
+    return s;
+}
+void
+Character::stamina_Reduce(float amount) {
+    stats.stamina_reduced += amount;
+}
+void
+Character::stamina_Increase(float amount) {
+    stats.stamina_reduced -= amount;
+    if (stats.stamina_reduced < 0.0f)
+        stats.stamina_reduced = 0.0;
+}
+
 void
 Character::stamina_StartReg() {
-    if (stats.stamina >= stats.stamina_max)
+    if (stamina_Get() >= stamina_Max())
         return;
 
     if (!stamina_regen_logic.is_regenerating) {
@@ -977,8 +1122,8 @@ Character::stamina_StartReg() {
         if (status == CharacterStatus::WALK) {
             amount_per_second *= 0.5;
         }
-        stats.stamina += amount_per_second * Default::delta_time;
-        if (stats.stamina >= stats.stamina_max)
+        stamina_Increase(amount_per_second * Default::delta_time);
+        if (stamina_Get() >= stamina_Max())
             stamina_StopReg();
 
     }
@@ -988,8 +1133,6 @@ void
 Character::stamina_StopReg() {
     stamina_regen_logic.is_regenerating = false;
     stamina_regen_logic.delay_is  = 0;
-    if (stats.stamina < 0)
-        stats.stamina = 0;
 }
 
 
@@ -1000,10 +1143,7 @@ Character::thirst_Drain() {
 
     if (stats.thirst <= 0) {
         float amount_per_second = 1;
-        stats.health -= amount_per_second * Default::delta_time;
-        if (stats.health <= 0) {
-            stats.health = 0;
-        }
+        health_Reduce(amount_per_second * Default::delta_time);
         return;
     } else {
         thirst_drain_logic.send_message_0 = false;
@@ -1035,16 +1175,12 @@ Character::getting_Hit(float demage) {
     if (attacking_logic.is_attacking == AttackingLogicStatus_e::NONE)
         set_Status(CharacterStatus::HIT);
     collecting_logic.is_collecting = false;
-    if ((attacking_logic.is_attacking == AttackingLogicStatus_e::BLOCKING_RUNNING && stats.stamina >= block_staming))
-        stats.stamina -= block_staming;
+    if ((attacking_logic.is_attacking == AttackingLogicStatus_e::BLOCKING_RUNNING && stamina_Get() >= block_staming))
+        stamina_Reduce(block_staming);
     else
-        stats.health -= demage;
-
-    std::cout << "Char: Getting hit! " << stats.health << std::endl;
+        health_Reduce(demage);
 
-    if (stats.health <= 0) {
-        stats.health = 0;
-    }
+    std::cout << "Char: Getting hit! " << std::endl;
 }
 
 void
@@ -1185,7 +1321,7 @@ Character::Resurrect() {
 
 void
 Character::Revive() {
-    stats.health = stats.health_max;
+    stats.health_reduced = 0.0f;
     stats.thirst = stats.thirst_max;
     move_logic.automove = false;
     set_Status(CharacterStatus::IDLE);
@@ -1286,6 +1422,10 @@ Character::handle_Animation() {
             active_anim_ref = &animation.drinking_river[dir];
             break;
 
+        case CharacterStatus::EATING:
+            active_anim_ref = &animation.eating[dir];
+            break;
+
         default:
             active_anim_ref = &animation.idle[dir];
             break;
@@ -1338,7 +1478,7 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
     */
 
     thirst_Drain();
-    if (stats.health == 0) {
+    if (health_Get() <= 0.0f) {
         death();
         return;
     }
@@ -1422,16 +1562,13 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
                 if (inventory->selected_inventory.vegetable != VegetableData::Type::NONE) {
                     InventoryVegetable& iv = inventory->vegetables.at(inventory->selected_inventory.vegetable);
                     setted_hotbar = inventory->set_HotbarItem(Inventory::selected_hotbar, &iv);
-                    std::cout << "NOOO \n";
                     //inventory->Equip(it);
                 } else
                 if (inventory->selected_inventory.seed != VegetableData::Type::NONE) {
                     InventoryVegetable& iv = inventory->seeds.at(inventory->selected_inventory.seed);
-                    std::cout << "JEEE " << iv.is_seed << "\n";
                     setted_hotbar = inventory->set_HotbarItem(Inventory::selected_hotbar, &iv);
                     //inventory->Equip(it);
                 } else {
-                    std::cout << "FUCK \n";
                     setted_hotbar = inventory->set_HotbarItem(Inventory::selected_hotbar, inventory->selected_inventory.item);
                     if (setted_hotbar) {
                         if (sel_item) inventory->Equip(sel_item);
@@ -1439,6 +1576,9 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
                     
                 }
                 if (setted_hotbar) {
+                    if (consuming_logic.is_consuming && !consuming_logic.is_drinking)
+                        consume_Stop();
+
                     selected_item = inventory->get_SelectedHotbarItem();
                     sel_item = nullptr;
                     if (selected_item->object_type == InventoryObjectType::ITEM) {
@@ -1584,14 +1724,18 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
         // LEFT CLICK
         if (input.click_left) {
             if (sel_item) {
+                // START CULTIVATE
                 if ( sel_item->type == ItemType::CULTIVATOR && 
                      status != CharacterStatus::CULTIVATING)
                     cultivate_Start();
                 else
+                // START BUILD
                 if (sel_item->type == ItemType::BUILDING_TOOL) {
                     build_Start();
                     return;
-                } else if (using_Weapon() &&
+                } else
+                // START ATTACK
+                if (using_Weapon() &&
                         ( attacking_logic.is_attacking == AttackingLogicStatus_e::NONE ||
                           attacking_logic.is_attacking == AttackingLogicStatus_e::BLOCKING_RUNNING)) {
                     collecting_logic.is_collecting = false;
@@ -1599,7 +1743,8 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
                     return;
                 }
             } else {
-                if (!planting_logic.is_planting) {
+                if (!planting_logic.is_planting &&
+                     Farm::soil_IsMaptile(tile_world)) {
                     switch (selected_item->object_type) {
                         case InventoryObjectType::VEGETABLE:
                         case InventoryObjectType::SEED:
@@ -1607,6 +1752,9 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
                             return;
                         default: break;
                     }
+                } else
+                if (!consuming_logic.is_consuming && selected_item->object_type == InventoryObjectType::VEGETABLE) {
+                    eat_Start();
                 }
             }
         } else
@@ -1626,7 +1774,10 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
 
 
     if (consuming_logic.is_consuming) {
-        drink_River();
+        if (consuming_logic.is_drinking)
+            drink_River();
+        else
+            eat_Something();
         return;
     }
 
@@ -1640,7 +1791,7 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
         collect_Stop();
     }
 
-    if (input.pressed_shift && stats.stamina > 0 &&
+    if (input.pressed_shift && stamina_Get() > 0 &&
         (status == CharacterStatus::WALK || status == CharacterStatus::RUN)) {
 
         // START SPRINT
@@ -1662,8 +1813,8 @@ Character::handle_Input(Input& input, SDL_Rect win_size) {
             }
         }
 
-        stats.stamina -= stamina_drain;
-        if (stats.stamina <= 0) {
+        stamina_Reduce(stamina_drain);
+        if (stamina_Get() <= 0) {
             stamina_StopReg();
             messages->Add(MessageKey::PLAYER_EXHAUSTED);
         }
@@ -1796,11 +1947,10 @@ void Character::handle_Move() {
     }
 
 
-    if (collecting_logic.is_collecting) {
+    if (collecting_logic.is_collecting)
         collect_Stop();
-    }
     if (consuming_logic.is_consuming)
-        drink_Stop();
+        consume_Stop();
 
     attacking_logic.is_attacking = AttackingLogicStatus_e::NONE;
 
@@ -1882,6 +2032,8 @@ void Character::Update() {
     //bird->set_Position({x,y});
     bird->Update(Default::delta_time, collider_world);
 
+    reduce_StatsBonus();
+
     if (status == CharacterStatus::HIT && active_anim->current_frame == 3) {
         set_Status(CharacterStatus::IDLE);
     }
diff --git a/src/character/character.hpp b/src/character/character.hpp
index e471761..4d550d3 100644
--- a/src/character/character.hpp
+++ b/src/character/character.hpp
@@ -45,6 +45,7 @@ enum class CharacterStatus {
     CRAFT,
     BLOCK,
     DRINK_RIVER,
+    EATING,
     CULTIVATING,
     PLANTING,
 };
@@ -85,6 +86,7 @@ struct CharacterConsumingLogic {
     float duration;
     float duration_max;
     bool  is_consuming;
+    bool  is_drinking;
     Resource* resource;
 };
 
@@ -106,21 +108,21 @@ struct CharacterPlantingLogic {
 };
 
 struct CharacterStats {
-    float  health;
-    float  health_max;
-    float  stamina;
-    float  stamina_max;
-    float  thirst;
-    float  thirst_max;
-
-    float  demage;
+    float health_max;
+    float health_reduced;
+    float stamina_max;
+    float stamina_reduced;
+    float thirst;
+    float thirst_max;
+
+    float demage;
 };
 
 struct CharacterStaminaRegeneration {
     bool  is_regenerating = false;
     float delay_max       = 2.8;
     float delay_is        = 0;
-    float regen_speed     = 1;
+    float regen_speed     = 2.4;
 };
 
 struct CharacterThirstDrainLogic {
@@ -136,6 +138,13 @@ struct CharacterSprintStartLogic {
     bool   has_started = false;
 };
 
+struct CharacterStatsBonus {
+    InventoryObjectType object_type;
+    uint32_t type;
+    float duration;
+    ConsumingStatsBonus stats;
+};
+
 class Character {
     ////////////////////////////////////////
     /// Character
@@ -163,6 +172,8 @@ class Character {
     CharacterSprintStartLogic sprintstart_logic;
     Bird* bird = nullptr;
 
+    std::vector<CharacterStatsBonus> stats_bonus;
+
     PixelShuffler* death_shuffler;
     float shuffle_timer    = 0.0f;
     float shuffle_interval = 8.0f;
@@ -230,6 +241,21 @@ class Character {
     void update_Animation(AnimationData& anim, float delta_time);
     void Draw(SDL_Renderer* renderer);
 
+
+    float health_Get();
+    float health_Max();
+    float health_MaxBonus();
+    void  health_Reduce(float amount);
+    void  health_Increase(float amount);
+
+    float stamina_Get();
+    float stamina_Max();
+    float stamina_MaxBonus();
+    void  stamina_Reduce(float amount);
+    void  stamina_Increase(float amount);
+    void  stamina_StartReg();
+    void  stamina_StopReg();
+
     TileObject* find_ClosestObject(SDL_Point* tile_found, ObjectCategory category = ObjectCategory::NONE);
     void collect_Start(TileObject* map_object_p, SDL_Point tile_point);
     void collect_Object();
@@ -251,7 +277,11 @@ class Character {
 
     void drink_Start();
     void drink_River();
-    void drink_Stop();
+
+    void eat_Start();
+    void eat_Something();
+
+    void consume_Stop();
 
     void cultivate_Start();
     void cultivate_Soil();
@@ -261,13 +291,13 @@ class Character {
     void plant_Vegetable();
     void plant_Stop();
 
-    void stamina_StartReg();
-    void stamina_StopReg();
-
     void thirst_Drain();
 
     void interact_WithBuilding(Building* building, Input& input);
 
+    bool is_StatsBonusAlready(InventoryObjectType object_type, uint32_t type);
+    void add_ToStatsBonus(InventoryObjectType object_type, uint32_t type, ConsumingStatsBonus sb);
+    void reduce_StatsBonus();
 
     void getting_Hit(float demage);
     void death();
diff --git a/src/character/enemy.cpp b/src/character/enemy.cpp
index 17e0df6..a445ea4 100644
--- a/src/character/enemy.cpp
+++ b/src/character/enemy.cpp
@@ -758,7 +758,7 @@ void
 Enemy::init_SpawnEnemy(double delay_to_spawn_in_sec, WeaponType weapon_type = WeaponType::SWORD,
                        WeaponMaterial weapon_material = WeaponMaterial::WOOD,
                        SDL_FPoint position = {100,100},
-                       EnemyStats status = {6,6,1,false,false,0,1.2}) {
+                       EnemyStats status = {16,16,2,false,false,0,1.2}) {
 
     double spawn_date = delay_to_spawn_in_sec + Default::get_TimeSinceStartInSec();
     Enemy::enemies_to_spawn.push_back({spawn_date,
@@ -881,7 +881,7 @@ Enemy::set_MoveLogic(EnemyMovingType& type, Character& player) {
             break;
         }
         case EnemyMovingType::CHARACTER: {
-            bool is_player_alive = player.stats.health > 0;
+            bool is_player_alive = player.health_Get() > 0;
             if (!is_player_alive) {
                 moving_logic.move_type = EnemyMovingType::NONE;
                 break;
@@ -1078,7 +1078,7 @@ Enemy::attack_Stop() {
     stats.has_attacked = false;
 
     if (moving_logic.move_type == EnemyMovingType::CHARACTER) {
-        if (static_cast<Character*>(moving_logic.object)->stats.health <= 0)
+        if (static_cast<Character*>(moving_logic.object)->health_Get() <= 0)
             moving_logic.move_type = EnemyMovingType::NONE;
 
     }
diff --git a/src/character/message.cpp b/src/character/message.cpp
index 2eabcf7..897dc3f 100644
--- a/src/character/message.cpp
+++ b/src/character/message.cpp
@@ -20,6 +20,7 @@ Messages::Messages() {
         {MessageKey::THIRST_20,     {10, MessageType::CHARACTER, "I should drink something.."}},
         {MessageKey::THIRST_0,      {10, MessageType::CHARACTER, "No water no life.."}},
         {MessageKey::WATER_APPRECIATION, {5, MessageType::CHARACTER, "Hmmm water"}},
+        {MessageKey::EAT_APPRECIATION,   {5, MessageType::CHARACTER, "Omnjomnjom"}},
         {MessageKey::CRAFTED_ITEM,  {10, MessageType::CHARACTER, "Whatever i can do with that.."}},
         {MessageKey::ADD_INVENTORY, {10, MessageType::INVENTORY, "Added item: "}},
         {MessageKey::ADD_RESOURCE,  {10, MessageType::RESOURCE,  "Resource "}},
diff --git a/src/character/message.hpp b/src/character/message.hpp
index bc3656d..311dc50 100644
--- a/src/character/message.hpp
+++ b/src/character/message.hpp
@@ -32,6 +32,7 @@ enum class MessageKey {
     THIRST_20,
     THIRST_0,
     WATER_APPRECIATION,
+    EAT_APPRECIATION,
     CRAFTED_ITEM,
     ADD_INVENTORY,
     ADD_RESOURCE,
diff --git a/src/defaults/ui.cpp b/src/defaults/ui.cpp
index 0e14ad6..0a08b44 100644
--- a/src/defaults/ui.cpp
+++ b/src/defaults/ui.cpp
@@ -253,7 +253,8 @@ namespace Ui {
         SDL_DestroySurface(surface_text);
     }
 
-    void draw_BottomLeftBars(SDL_Renderer* renderer, SDL_Rect win_size, const Character& player) {
+    void
+    draw_BottomLeftBars(SDL_Renderer* renderer, SDL_Rect win_size, Character& player) {
         const float health_w = 20.0f;
         const float energy_w = health_w * 0.5f;
         const float thirst_w = health_w * 0.4f;
@@ -263,48 +264,194 @@ namespace Ui {
         float start_x = 20.0f;
         float start_y = static_cast<float>(win_size.h) - bar_h - 20.0f;
 
-        // Clamp helper
         auto clamp01 = [](float v) {
             return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v);
         };
 
-        float energy_ratio = clamp01(player.stats.stamina / player.stats.stamina_max);
-        float health_ratio = clamp01(player.stats.health / player.stats.health_max);
-        float thirst_ratio = clamp01(player.stats.thirst / player.stats.thirst_max);
+        float thirst_max = player.stats.thirst_max;
+        if (thirst_max <= 0.0f) thirst_max = 1.0f;
 
-        // Thirst bar
+        float thirst_ratio = clamp01(player.stats.thirst / thirst_max);
 
-        // Backgrounds (dark)
-        SDL_FRect health_bg = { start_x + energy_w + spacing, start_y, health_w, bar_h };
-        SDL_FRect energy_bg = { start_x, start_y, energy_w, bar_h };
-        SDL_FRect thirst_bg = { health_bg.x + health_w + spacing, start_y, thirst_w, bar_h };
+        // ---------------- HEALTH ----------------
 
-        SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
-        SDL_RenderFillRect(renderer, &energy_bg);
-        SDL_RenderFillRect(renderer, &health_bg);
-        SDL_RenderFillRect(renderer, &thirst_bg);
+        float health_max   = player.health_Max();
+        float health_bonus = player.health_MaxBonus();
+        float health_base_max = health_max - health_bonus;
+        if (health_base_max < 0.0f) health_base_max = 0.0f;
 
-        // Filled portions (fill from bottom up)
-        SDL_FRect health_fill = { health_bg.x, start_y + bar_h * (1.0f - health_ratio), health_w, bar_h * health_ratio };
-        SDL_FRect energy_fill = { energy_bg.x, start_y + bar_h * (1.0f - energy_ratio), energy_w, bar_h * energy_ratio };
-        SDL_FRect thirst_fill = { thirst_bg.x, start_y + bar_h * (1.0f - thirst_ratio), thirst_w, bar_h * thirst_ratio };
-        // std::cout << thirst_ratio << " " << player.stats.thirst << " " << player.stats.thirst_max << std::endl;
+        float health_capacity_ratio = clamp01(health_max / thirst_max);
+        float health_bar_max_h = bar_h * health_capacity_ratio;
 
+        float health_base_capacity_ratio =
+            health_max > 0.0f ? clamp01(health_base_max / health_max) : 0.0f;
 
-        SDL_SetRenderDrawColor(renderer, 200, 40, 40, 255);
-        SDL_RenderFillRect(renderer, &health_fill);
+        float health_base_cap_h  = health_bar_max_h * health_base_capacity_ratio;
+        float health_bonus_cap_h = health_bar_max_h - health_base_cap_h;
 
-        SDL_SetRenderDrawColor(renderer, 200, 200, 40, 255);
-        SDL_RenderFillRect(renderer, &energy_fill);
+        float health_val = player.health_Get();
+
+        float health_base_ratio =
+            health_base_max > 0.0f ? clamp01(health_val / health_base_max) : 0.0f;
+
+        float health_bonus_ratio =
+            health_bonus > 0.0f
+                ? clamp01((health_val - health_base_max) / health_bonus)
+                : 0.0f;
+
+        float health_bottom_y = start_y + (bar_h - health_bar_max_h);
+
+        // ---------------- STAMINA ----------------
+
+        float stamina_max   = player.stamina_Max();
+        float stamina_bonus = player.stamina_MaxBonus();
+        float stamina_base_max = stamina_max - stamina_bonus;
+        if (stamina_base_max < 0.0f) stamina_base_max = 0.0f;
+
+        float stamina_capacity_ratio = clamp01(stamina_max / thirst_max);
+        float stamina_bar_max_h = bar_h * stamina_capacity_ratio;
+
+        float stamina_base_capacity_ratio =
+            stamina_max > 0.0f ? clamp01(stamina_base_max / stamina_max) : 0.0f;
+
+        float stamina_base_cap_h  = stamina_bar_max_h * stamina_base_capacity_ratio;
+        float stamina_bonus_cap_h = stamina_bar_max_h - stamina_base_cap_h;
+
+        float stamina_val = player.stamina_Get();
+
+        float stamina_base_ratio =
+            stamina_base_max > 0.0f ? clamp01(stamina_val / stamina_base_max) : 0.0f;
+
+        float stamina_bonus_ratio =
+            stamina_bonus > 0.0f
+                ? clamp01((stamina_val - stamina_base_max) / stamina_bonus)
+                : 0.0f;
+
+        float stamina_bottom_y = start_y + (bar_h - stamina_bar_max_h);
+
+        // ---------------- RECTS ----------------
+
+        SDL_FRect thirst_bg  = { start_x, start_y, thirst_w, bar_h };
+        SDL_FRect energy_bg  = {
+            thirst_bg.x + thirst_w + spacing,
+            stamina_bottom_y,
+            energy_w,
+            stamina_bar_max_h
+        };
+        SDL_FRect health_bg  = {
+            energy_bg.x + energy_w + spacing,
+            health_bottom_y,
+            health_w,
+            health_bar_max_h
+        };
 
+        // ---------------- BACKGROUND ----------------
+
+        // thirst background
+        SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
+        SDL_RenderFillRect(renderer, &thirst_bg);
+
+        // stamina background base
+        SDL_FRect stamina_bg_base = {
+            energy_bg.x,
+            stamina_bottom_y + stamina_bonus_cap_h,
+            energy_w,
+            stamina_base_cap_h
+        };
+        SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
+        SDL_RenderFillRect(renderer, &stamina_bg_base);
+
+        // stamina background bonus (slightly lighter)
+        SDL_FRect stamina_bg_bonus = {
+            energy_bg.x,
+            stamina_bottom_y,
+            energy_w,
+            stamina_bonus_cap_h
+        };
+        SDL_SetRenderDrawColor(renderer, 45, 45, 45, 255);
+        SDL_RenderFillRect(renderer, &stamina_bg_bonus);
+
+        // health background base
+        SDL_FRect health_bg_base = {
+            health_bg.x,
+            health_bottom_y + health_bonus_cap_h,
+            health_w,
+            health_base_cap_h
+        };
+        SDL_SetRenderDrawColor(renderer, 30, 30, 30, 255);
+        SDL_RenderFillRect(renderer, &health_bg_base);
+
+        // health background bonus (slightly lighter)
+        SDL_FRect health_bg_bonus = {
+            health_bg.x,
+            health_bottom_y,
+            health_w,
+            health_bonus_cap_h
+        };
+        SDL_SetRenderDrawColor(renderer, 45, 45, 45, 255);
+        SDL_RenderFillRect(renderer, &health_bg_bonus);
+
+        // ---------------- FOREGROUND ----------------
+
+        // health base fill
+        SDL_FRect health_fill_base = {
+            health_bg.x,
+            health_bottom_y + health_bonus_cap_h
+                + health_base_cap_h * (1.0f - health_base_ratio),
+            health_w,
+            health_base_cap_h * health_base_ratio
+        };
+        SDL_SetRenderDrawColor(renderer, 200, 40, 40, 255);
+        SDL_RenderFillRect(renderer, &health_fill_base);
+
+        // health bonus fill (lighter red)
+        SDL_FRect health_fill_bonus = {
+            health_bg.x,
+            health_bottom_y
+                + health_bonus_cap_h * (1.0f - health_bonus_ratio),
+            health_w,
+            health_bonus_cap_h * health_bonus_ratio
+        };
+        SDL_SetRenderDrawColor(renderer, 255, 100, 100, 255);
+        SDL_RenderFillRect(renderer, &health_fill_bonus);
+
+        // stamina base fill
+        SDL_FRect stamina_fill_base = {
+            energy_bg.x,
+            stamina_bottom_y + stamina_bonus_cap_h
+                + stamina_base_cap_h * (1.0f - stamina_base_ratio),
+            energy_w,
+            stamina_base_cap_h * stamina_base_ratio
+        };
+        SDL_SetRenderDrawColor(renderer, 200, 200, 40, 255);
+        SDL_RenderFillRect(renderer, &stamina_fill_base);
+
+        // stamina bonus fill (lighter yellow)
+        SDL_FRect stamina_fill_bonus = {
+            energy_bg.x,
+            stamina_bottom_y
+                + stamina_bonus_cap_h * (1.0f - stamina_bonus_ratio),
+            energy_w,
+            stamina_bonus_cap_h * stamina_bonus_ratio
+        };
+        SDL_SetRenderDrawColor(renderer, 255, 255, 120, 255);
+        SDL_RenderFillRect(renderer, &stamina_fill_bonus);
+
+        // thirst fill
+        SDL_FRect thirst_fill = {
+            thirst_bg.x,
+            start_y + bar_h * (1.0f - thirst_ratio),
+            thirst_w,
+            bar_h * thirst_ratio
+        };
         SDL_SetRenderDrawColor(renderer, 40, 120, 200, 255);
         SDL_RenderFillRect(renderer, &thirst_fill);
 
-        // borders
+        // ---------------- BORDERS ----------------
+
         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+        SDL_RenderRect(renderer, &thirst_bg);
         SDL_RenderRect(renderer, &energy_bg);
         SDL_RenderRect(renderer, &health_bg);
-        SDL_RenderRect(renderer, &thirst_bg);
-
     }
 }
diff --git a/src/defaults/ui.hpp b/src/defaults/ui.hpp
index 608885c..f9ef969 100644
--- a/src/defaults/ui.hpp
+++ b/src/defaults/ui.hpp
@@ -32,5 +32,5 @@ namespace Ui {
 
     void draw_TopBarTileInfo(SDL_Renderer* renderer, SDL_Rect win_size);
 
-    void draw_BottomLeftBars(SDL_Renderer* renderer, SDL_Rect win_size, const Character& player);
+    void draw_BottomLeftBars(SDL_Renderer* renderer, SDL_Rect win_size, Character& player);
 }
diff --git a/src/game/state_playing.cpp b/src/game/state_playing.cpp
index fa27642..4102f13 100644
--- a/src/game/state_playing.cpp
+++ b/src/game/state_playing.cpp
@@ -158,10 +158,10 @@ void StatePlaying::handle_Events(SDL_Event& event, Game* game) {
                     break;
                 }
                 case SDL_SCANCODE_F5:
-                    player->stats.health = 0;
+                    player->health_Reduce(100000000);
                     break;
                 case SDL_SCANCODE_F11: // FOR TESTING
-                    Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {6,6,1,false,false,0,1.2});
+                    Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {16,16,2,false,false,0,1.2});
                     return;
                 default:
                     break;
diff --git a/src/inventory/inventory.cpp b/src/inventory/inventory.cpp
index f50b850..1e7438c 100644
--- a/src/inventory/inventory.cpp
+++ b/src/inventory/inventory.cpp
@@ -105,8 +105,12 @@ Inventory::remove_Vegetable(VegetableData::Type type, size_t amount) {
 
     std::cout << "TSCHÖÖ VEG\n";
     it->second.count -= amount;
-    if (it->second.count == 0)
+    if (it->second.count == 0) {
         vegetables.erase(it);
+        bool setted_hotbar = set_HotbarItem(Inventory::selected_hotbar, Inventory::hotbar_hands);
+        if (setted_hotbar)
+            Equip(Inventory::hotbar_hands);
+    }
     return true;
 }
 
@@ -139,8 +143,12 @@ Inventory::remove_Seed(VegetableData::Type type, size_t amount) {
         return false;
 
     it->second.count -= amount;
-    if (it->second.count == 0)
+    if (it->second.count == 0) {
         seeds.erase(it);
+        bool setted_hotbar = set_HotbarItem(Inventory::selected_hotbar, Inventory::hotbar_hands);
+        if (setted_hotbar)
+            Equip(Inventory::hotbar_hands);
+    }
     return true;
 }
 
diff --git a/src/inventory/inventory.hpp b/src/inventory/inventory.hpp
index e1d7cda..e87b719 100644
--- a/src/inventory/inventory.hpp
+++ b/src/inventory/inventory.hpp
@@ -12,6 +12,7 @@
 #include "defaults/icons.hpp"
 #include "vegetables/vegetables.hpp"
 
+
 enum class InventoryObjectType : uint8_t {
     NONE,
     ITEM,
@@ -52,10 +53,12 @@ struct InventoryVegetable : Inventory_s {
     size_t count = 0;
     bool   is_seed = false;
     VegetableData::Type type;
+    const ConsumingStatsBonus& stats_bonus;
     InventoryVegetable(size_t d, VegetableData::Type t, bool s)
-        : Inventory_s(d, s ? InventoryObjectType::SEED : InventoryObjectType::VEGETABLE), is_seed(s), type(t)
-    {
-    }
+        : Inventory_s(d, s ? InventoryObjectType::SEED : InventoryObjectType::VEGETABLE),
+          is_seed(s), type(t),
+          stats_bonus(VegetableData::crop_defs[static_cast<uint32_t>(t)].stats_bonus)
+    { }
 };
 
 
diff --git a/src/vegetables/vegetables.cpp b/src/vegetables/vegetables.cpp
index 42e34cb..2f20cb1 100644
--- a/src/vegetables/vegetables.cpp
+++ b/src/vegetables/vegetables.cpp
@@ -8,13 +8,13 @@ namespace VegetableData {
 
     const CropDefinition crop_defs[(int)Type::COUNT] = {
         //        STAGE: 0    1    2    3    4
-        { "",0,0,0,0,0,0,0,0,0,0,0,false },
-        { "carrot",      2,1, 5,1, 6,1, 7,1, 23,0, (5-2+1)+1, false},
-        { "raddish",     2,3, 5,3, 6,3, 7,3, 23,1, (5-2+1)+1, false},
-        { "cabbage",     2,5, 5,5, 6,5, 7,5, 23,2, (5-2+1)+1, false},
-        { "salad",       2,7, 5,7, 6,7, 7,7, 23,3, (5-2+1)+1, false},
-        { "broccoli",    2,9, 5,9, 6,9, 7,9, 23,4, (5-2+1)+1, false},
-        { "onion",       2,11,5,11,6,11,7,11,23,5, (5-2+1)+1, false}
+        { "",0,0,0,0,0,0,0,0,0,0,0,false , { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "carrot",   2,1, 5,1, 6,1, 7,1, 23,0, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "raddish",  2,3, 5,3, 6,3, 7,3, 23,1, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "cabbage",  2,5, 5,5, 6,5, 7,5, 23,2, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "salad",    2,7, 5,7, 6,7, 7,7, 23,3, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "broccoli", 2,9, 5,9, 6,9, 7,9, 23,4, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } },
+        { "onion",    2,11,5,11,6,11,7,11,23,5, (5-2+1)+1, false, { 5.0f, 5.0f, 0.0f, 0.0f, 300.0f } }
     };
 
     const CropDefinition* get_DataByType(Type type) {
diff --git a/src/vegetables/vegetables.hpp b/src/vegetables/vegetables.hpp
index c83aa42..5031a97 100644
--- a/src/vegetables/vegetables.hpp
+++ b/src/vegetables/vegetables.hpp
@@ -10,6 +10,15 @@ enum class EquipmentSlot;
 
 class Vegetable;
 
+
+struct ConsumingStatsBonus {
+    float health   = 0.0f;
+    float stamina  = 0.0f;
+    float thirst   = 0.0f;
+    float demage   = 0.0f;
+    float duration = 0.0f;
+};
+
 namespace VegetableData {
     extern std::vector<Vegetable*> all_vegetables;
 
@@ -38,6 +47,7 @@ namespace VegetableData {
         int icon_tile_y;
         size_t total_stages;   // auto-calculated = (grown-start)+1 + rotten
         bool is_seed;
+        ConsumingStatsBonus stats_bonus;
     };