diff --git a/Makefile b/Makefile index 6144bd3..39d1b1b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ debug: build debug_run: build gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe -debug_walk: build +debug_walk: build test gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe t clean: diff --git a/components.hpp b/components.hpp index 39b0912..27a2b08 100644 --- a/components.hpp +++ b/components.hpp @@ -49,8 +49,6 @@ namespace components { std::string ai_script; std::string ai_start_name; std::string ai_goal_name; - ai::State ai_start; - ai::State ai_goal; }; struct Debug { diff --git a/dinkyecs.hpp b/dinkyecs.hpp index 1b568fc..1434558 100644 --- a/dinkyecs.hpp +++ b/dinkyecs.hpp @@ -198,7 +198,10 @@ namespace DinkyECS return !queue.empty(); } - /* std::optional can't do references. Don't try it! */ + /* std::optional can't do references. Don't try it! + * Actually, this sucks, either delete it or have it + * return pointers (assuming optional can handle pointers) + */ template std::optional get_if(DinkyECS::Entity entity) { if(has(entity)) { diff --git a/gui_fsm.cpp b/gui_fsm.cpp index 6e2c036..1888cac 100644 --- a/gui_fsm.cpp +++ b/gui_fsm.cpp @@ -340,6 +340,7 @@ namespace gui { } void FSM::run_systems() { + System::generate_paths($level); System::enemy_ai($level); System::enemy_pathing($level); System::collision($level); diff --git a/systems.cpp b/systems.cpp index d2f11e9..a7def38 100644 --- a/systems.cpp +++ b/systems.cpp @@ -18,6 +18,32 @@ using namespace components; using lighting::LightSource; using ftxui::Color; +struct EntityAI { + std::string script; + ai::State start; + ai::State goal; + ai::ActionPlan plan; + + EntityAI(std::string script, ai::State start, ai::State goal) : + script(script), start(start), goal(goal) + { + } + + EntityAI() {}; + + bool wants_to(std::string name) { + return plan.script[0].name == name; + } + + void set_state(std::string name, bool setting) { + ai::set(start, name, setting); + } + + void update() { + plan = ai::plan(script, start, goal); + } +}; + void System::lighting(GameLevel &level) { auto &light = *level.lights; auto &world = *level.world; @@ -36,26 +62,34 @@ void System::lighting(GameLevel &level) { }); } +void System::generate_paths(GameLevel &level) { + auto player = level.world->get_the(); + const auto &player_position = level.world->get(player.entity); + + level.map->set_target(player_position.location); + level.map->make_paths(); +} + void System::enemy_ai(GameLevel &level) { auto &world = *level.world; auto &map = *level.map; - auto player = world.get_the(); - const auto &player_position = world.get(player.entity); - map.set_target(player_position.location); - map.make_paths(); world.query([&](const auto ent, auto& pos, auto& config) { - config.ai_start = ai::load_state(config.ai_start_name); - config.ai_goal = ai::load_state(config.ai_goal_name); - - ai::set(config.ai_start, "detect_enemy", - map.distance(pos.location) < config.hearing_distance); + if(world.has(ent)) { + auto&enemy = world.get(ent); + enemy.set_state("detect_enemy", map.distance(pos.location) < config.hearing_distance); + enemy.update(); + } else { + auto ai_start = ai::load_state(config.ai_start_name); + auto ai_goal = ai::load_state(config.ai_goal_name); - auto a_plan = ai::plan(config.ai_script, config.ai_start, config.ai_goal); + EntityAI enemy(config.ai_script, ai_start, ai_goal); + enemy.set_state("detect_enemy", map.distance(pos.location) < config.hearing_distance); + enemy.update(); - ai::dump_script("\n\n\n-----ENEMY SCRIPT", config.ai_start, a_plan.script); - auto action = a_plan.script.front(); - world.set(ent, action); + ai::dump_script("\n\n\n-----ENEMY SCRIPT", enemy.start, enemy.plan.script); + world.set(ent, enemy); + } }); } @@ -65,13 +99,12 @@ void System::enemy_pathing(GameLevel &level) { auto player = world.get_the(); const auto &player_position = world.get(player.entity); - map.set_target(player_position.location); - map.make_paths(); world.query([&](auto ent, auto &position, auto &motion) { if(ent != player.entity) { - auto action = world.get_if(ent); - if(action && (*action).name == "find_enemy") { + auto& action = world.get(ent); + + if(action.wants_to("find_enemy")) { Point out = position.location; // copy map.neighbors(out, motion.random); motion = { int(out.x - position.location.x), int(out.y - position.location.y)}; @@ -154,6 +187,7 @@ void System::death(GameLevel &level, components::ComponentMap& components) { world.remove(ent); world.remove(ent); world.remove(ent); + world.remove(ent); world.remove(ent); if(auto snd = world.get_if(ent)) { @@ -181,29 +215,32 @@ void System::combat(GameLevel &level) { // this is guaranteed to not return the given position auto [found, nearby] = collider.neighbors(player_position.location); - if(found) { for(auto entity : nearby) { - // AI: process AI combat actions here + if(world.has(entity)) { + auto& enemy_ai = world.get(entity); + enemy_ai.set_state("enemy_found", true); + enemy_ai.update(); - if(world.has(entity)) { - auto& enemy_combat = world.get(entity); + if(enemy_ai.wants_to("kill_enemy")) { + auto& enemy_combat = world.get(entity); - Events::Combat result { - player_combat.attack(enemy_combat), - enemy_combat.attack(player_combat) - }; + Events::Combat result { + player_combat.attack(enemy_combat), + enemy_combat.attack(player_combat) + }; - if(world.has(entity)) { - auto& animation = world.get(entity); - animation.play(); - } + if(world.has(entity)) { + auto& animation = world.get(entity); + animation.play(); + } - if(auto snd = world.get_if(entity)) { - sound::play(snd->attack); - } + if(auto snd = world.get_if(entity)) { + sound::play(snd->attack); + } - world.send(Events::GUI::COMBAT, entity, result); + world.send(Events::GUI::COMBAT, entity, result); + } } } } diff --git a/systems.hpp b/systems.hpp index 38c1853..27ce4c7 100644 --- a/systems.hpp +++ b/systems.hpp @@ -11,6 +11,7 @@ namespace System { void motion(GameLevel &level); void collision(GameLevel &level); void death(GameLevel &level, components::ComponentMap& components); + void generate_paths(GameLevel &level); void enemy_pathing(GameLevel &level); void enemy_ai(GameLevel &level);