#include #include "Components/Configs/WorldConfig.hpp" #include "Core/WorldInstance.h" #include "Components/Resource.hpp" #include "Components/Inventory.hpp" TEST_SUITE("Resource") { TEST_CASE("basic resource gathering produces item after one tick") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); WorldInstance world{ config }; // Create a resource entity with gatherTicks = 1 auto entity = world.GetEcsWorld().entity(); Resource_Ore_Helper(entity, stoneID, 1); world.ProcessFrame(); auto& inv = world.GetEcsWorld().ensure(); CHECK(inv.GetItemsAmount(stoneID) >= 1); } TEST_CASE("resource with 20 tick gather time produces item after 20 ticks") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Ore_Helper(entity, stoneID, 20); for (int i = 0; i < 19; ++i) world.ProcessFrame(); auto& inv = world.GetEcsWorld().ensure(); CHECK(inv.GetItemsAmount(stoneID) == 0); world.ProcessFrame(); CHECK(inv.GetItemsAmount(stoneID) >= 1); } } TEST_SUITE("Resource - Health & Renewing") { TEST_CASE("tree resource loses health each gather cycle") { WorldConfig config{}; uint16_t woodID = config.RegisterItem("Wood"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Tree_Helper(entity, woodID, 1, 3, 5); world.ProcessFrame(); auto& inv = world.GetEcsWorld().ensure(); CHECK(inv.GetItemsAmount(woodID) == 1); auto health = entity.get(); CHECK(health.Health == 2); } TEST_CASE("tree enters renewing state when health reaches 0") { WorldConfig config{}; uint16_t woodID = config.RegisterItem("Wood"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Tree_Helper(entity, woodID, 1, 2, 5); // 2 gather cycles to deplete health world.ProcessFrame(); world.ProcessFrame(); auto& inv = world.GetEcsWorld().ensure(); CHECK(inv.GetItemsAmount(woodID) == 2); CHECK(entity.has()); // one more tick should not produce items while renewing world.ProcessFrame(); CHECK(inv.GetItemsAmount(woodID) == 2); } TEST_CASE("tree restores health after renewal period") { WorldConfig config{}; uint16_t woodID = config.RegisterItem("Wood"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Tree_Helper(entity, woodID, 1, 1, 5); // 1 gather cycle depletes health world.ProcessFrame(); CHECK(entity.has()); // 5 ticks for renewal for (int i = 0; i < 5; ++i) world.ProcessFrame(); CHECK_FALSE(entity.has()); CHECK(entity.has()); auto health = entity.get(); CHECK(health.Health == health.MaxHealth); } TEST_CASE("tree resumes gathering after renewal") { WorldConfig config{}; uint16_t woodID = config.RegisterItem("Wood"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Tree_Helper(entity, woodID, 1, 1, 5); // deplete world.ProcessFrame(); auto& inv = world.GetEcsWorld().ensure(); CHECK(inv.GetItemsAmount(woodID) == 1); // renew (5 ticks) for (int i = 0; i < 5; ++i) world.ProcessFrame(); CHECK_FALSE(entity.has()); // should gather again world.ProcessFrame(); CHECK(inv.GetItemsAmount(woodID) == 2); } } TEST_SUITE("Inventory Entity") { TEST_CASE("resource harvests into local inventory when present") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Ore_Helper(entity, stoneID, 1); Inventory_Helper(entity, config, 10); world.ProcessFrame(); auto localInv = entity.get(); CHECK(localInv.GetItemsAmount(stoneID) == 1); auto& worldInv = world.GetEcsWorld().ensure(); CHECK(worldInv.GetItemsAmount(stoneID) == 0); } TEST_CASE("overflow goes to world inventory when local is full") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); WorldInstance world{ config }; auto entity = world.GetEcsWorld().entity(); Resource_Ore_Helper(entity, stoneID, 1); Inventory_Helper(entity, config, 2); // fill local inventory (max 2) world.ProcessFrame(); world.ProcessFrame(); auto localInv = entity.get(); CHECK(localInv.GetItemsAmount(stoneID) == 2); auto& worldInv = world.GetEcsWorld().ensure(); CHECK(worldInv.GetItemsAmount(stoneID) == 0); // next item should overflow to world inventory world.ProcessFrame(); localInv = entity.get(); CHECK(localInv.GetItemsAmount(stoneID) == 2); CHECK(worldInv.GetItemsAmount(stoneID) == 1); } TEST_CASE("inventory tracks multiple item types independently") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); uint16_t ironID = config.RegisterItem("Iron"); WorldInstance world{ config }; auto stoneEntity = world.GetEcsWorld().entity(); Resource_Ore_Helper(stoneEntity, stoneID, 1); Inventory_Helper(stoneEntity, config, 5); auto ironEntity = world.GetEcsWorld().entity(); Resource_Ore_Helper(ironEntity, ironID, 1); Inventory_Helper(ironEntity, config, 5); world.ProcessFrame(); auto stoneInv = stoneEntity.get(); CHECK(stoneInv.GetItemsAmount(stoneID) == 1); CHECK(stoneInv.GetItemsAmount(ironID) == 0); auto ironInv = ironEntity.get(); CHECK(ironInv.GetItemsAmount(ironID) == 1); CHECK(ironInv.GetItemsAmount(stoneID) == 0); } TEST_CASE("two producers share a separate inventory entity") { WorldConfig config{}; uint16_t stoneID = config.RegisterItem("Stone"); uint16_t ironID = config.RegisterItem("Iron"); WorldInstance world{ config }; // inventory entity (chest/barrel) auto chest = world.GetEcsWorld().entity(); Inventory_Helper(chest, config, 10); // copy the shared inventory to both producers auto chestInv = chest.get(); auto stoneProducer = world.GetEcsWorld().entity(); Resource_Ore_Helper(stoneProducer, stoneID, 1); stoneProducer.set(chestInv); auto ironProducer = world.GetEcsWorld().entity(); Resource_Ore_Helper(ironProducer, ironID, 1); ironProducer.set(chestInv); world.ProcessFrame(); world.ProcessFrame(); world.ProcessFrame(); // all items should be in the shared inventory auto resultInv = chest.get(); CHECK(resultInv.GetItemsAmount(stoneID) == 3); CHECK(resultInv.GetItemsAmount(ironID) == 3); // world inventory should be empty auto& worldInv = world.GetEcsWorld().ensure(); CHECK(worldInv.GetItemsAmount(stoneID) == 0); CHECK(worldInv.GetItemsAmount(ironID) == 0); } }