diff --git a/dinkyecs.hpp b/dinkyecs.hpp index 9d1a7a9..5eb4fe9 100644 --- a/dinkyecs.hpp +++ b/dinkyecs.hpp @@ -18,6 +18,7 @@ namespace DinkyECS { struct Event { int event = 0; Entity entity = 0; + std::any data; }; typedef std::queue EventQueue; @@ -105,9 +106,9 @@ namespace DinkyECS { } template - void send(Comp event, Entity entity) { + void send(Comp event, Entity entity, std::any data) { EventQueue &queue = queue_map_for(); - queue.push({event, entity}); + queue.push({event, entity, data}); } template @@ -115,6 +116,7 @@ namespace DinkyECS { EventQueue &queue = queue_map_for(); Event evt = queue.front(); queue.pop(); + // I could use tie here to auto extract the any return evt; } diff --git a/events.hpp b/events.hpp index 2079474..5ac0289 100644 --- a/events.hpp +++ b/events.hpp @@ -2,6 +2,11 @@ namespace Events { enum GUI { - START, HIT, MISS, DEAD, LOOT + START, COMBAT, LOOT + }; + + struct Combat { + int player_did; + int enemy_did; }; } diff --git a/gui.cpp b/gui.cpp index 69775e3..7f57121 100644 --- a/gui.cpp +++ b/gui.cpp @@ -104,31 +104,30 @@ void GUI::handle_world_events() { auto player = $world.get_the(); while($world.has_event()) { - auto [evt, entity] = $world.recv(); + auto [evt, entity, data] = $world.recv(); + switch(evt) { - case eGUI::HIT: { - auto combat = $world.get(entity); + case eGUI::COMBAT: { + auto &damage = std::any_cast(data); + auto enemy_combat = $world.get(entity); - if(entity == player.entity) { - $log.log(format("Enemy HIT YOU, you have {} HP!", combat.hp)); + if(damage.enemy_did > 0) { + $log.log(format("Enemy HIT YOU for {} damage!", damage.enemy_did)); + $log.log(format("-- Enemy has {} HP left.", enemy_combat.hp)); $sounds.play("hit"); } else { - $log.log(format("You HIT enemy, they have {} HP!", combat.hp)); + $log.log("Enemy MISSED YOU."); + } + + if(damage.player_did > 0) { + $log.log(format("You HIT enemy for {} damage!", damage.player_did)); $sounds.play("hit"); + } else { + $log.log("You MISSED the enemy."); } } break; - case eGUI::MISS: - if(entity == player.entity) { - $log.log("You MISSED the enemy."); - } else { - $log.log("Enemy MISSED YOU."); - } - break; - case eGUI::DEAD: - $log.log("--- ENEMY DEAD!"); - break; case eGUI::LOOT: { - auto loot = $world.get(entity); + auto &loot = std::any_cast(data); auto inventory = $world.get(player.entity); $log.log(format("You found {} gold. You have {} now.", loot.amount, inventory.gold)); @@ -182,7 +181,7 @@ void GUI::run_systems() { auto player = $world.get_the(); System::enemy_pathing($world, $game_map, player); System::motion($world, $game_map); - System::combat($world, player); + System::collision($world, player); System::death($world); } diff --git a/status.txt b/status.txt index 71bf0ab..0ce0bb9 100644 --- a/status.txt +++ b/status.txt @@ -2,9 +2,7 @@ NOTES: TODO: - -* Event system could take additional data so that the events can be more coarse and simpler. -* Simplify the combat/collision system so that it's not a bunch of if-cases. +* Save file isn't saving gold. * Inventory needs to be better, but need some kinds of "weapons" or other loot to get and not just gold. * Run the ansi_parser on the whole UI so I can use colors and other glyphs. * Create a few more enemy types to fight. diff --git a/systems.cpp b/systems.cpp index e787780..f8cf76b 100644 --- a/systems.cpp +++ b/systems.cpp @@ -91,7 +91,7 @@ void System::death(DinkyECS::World &world) { }); } -void System::combat(DinkyECS::World &world, Player &player) { +void System::collision(DinkyECS::World &world, Player &player) { auto& collider = world.get_the(); const auto& player_position = world.get(player.entity); auto& player_combat = world.get(player.entity); @@ -100,36 +100,23 @@ void System::combat(DinkyECS::World &world, Player &player) { auto [found, nearby] = collider.neighbors(player_position.location); if(found) { - // save some keystrokes - using eGUI = Events::GUI; for(auto entity : nearby) { if(world.has(entity)) { auto& enemy_combat = world.get(entity); - int player_dmg = player_combat.attack(enemy_combat); - - if(player_dmg > 0) { - world.send(eGUI::HIT, entity); - } else { - world.send(eGUI::MISS, entity); - } - - if(enemy_combat.hp > 0) { - int enemy_dmg = enemy_combat.attack(player_combat); - - if(enemy_dmg > 0) { - world.send(eGUI::HIT, player.entity); - } else { - world.send(eGUI::MISS, player.entity); - } - } else { - world.send(eGUI::DEAD, entity); - } + + Events::Combat result { + player_combat.attack(enemy_combat), + enemy_combat.attack(player_combat) + }; + + world.send(Events::GUI::COMBAT, entity, result); } else if(world.has(entity)) { - world.send(eGUI::LOOT, entity); - auto &loot = world.get(entity); + auto loot = world.get(entity); auto &loot_pos = world.get(entity); auto &inventory = world.get(player.entity); + + world.send(Events::GUI::LOOT, entity, loot); inventory.gold += loot.amount; collider.remove(loot_pos.location); } else { diff --git a/systems.hpp b/systems.hpp index 9f1dc31..96ea011 100644 --- a/systems.hpp +++ b/systems.hpp @@ -8,7 +8,7 @@ using namespace components; namespace System { void motion(DinkyECS::World &world, Map &game_map); - void combat(DinkyECS::World &world, Player &player); + void collision(DinkyECS::World &world, Player &player); void death(DinkyECS::World &world); void enemy_pathing(DinkyECS::World &world, Map &game_map, Player &player); void draw_map(DinkyECS::World &world, Map &game_map, ftxui::Canvas &canvas, size_t view_x, size_t view_y); diff --git a/tests/dinkyecs.cpp b/tests/dinkyecs.cpp index fe8967d..d8ab9ec 100644 --- a/tests/dinkyecs.cpp +++ b/tests/dinkyecs.cpp @@ -5,9 +5,10 @@ using namespace fmt; using DinkyECS::Entity; +using std::string; struct Player { - std::string name; + string name; Entity eid; }; @@ -129,22 +130,18 @@ enum GUIEvent { TEST_CASE("confirm that the event system works", "[ecs]") { DinkyECS::World world; - DinkyECS::Entity gui_ent = world.entity(); DinkyECS::Entity player = world.entity(); - GUIEvent gui{GUIEvent::HIT}; - world.set(gui_ent, gui); - auto &gui_test = world.get(gui_ent); - REQUIRE(gui == gui_test); - - world.send(GUIEvent::HIT, player); + world.send(GUIEvent::HIT, player, string{"hello"}); bool ready = world.has_event(); REQUIRE(ready == true); - auto [event, entity] = world.recv(); + auto [event, entity, data] = world.recv(); REQUIRE(event == GUIEvent::HIT); REQUIRE(entity == player); + auto &str_data = std::any_cast(data); + REQUIRE(string{"hello"} == str_data); ready = world.has_event(); REQUIRE(ready == false);