diff --git a/Makefile b/Makefile index a1533ce..ed2bdee 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,9 @@ debug: build debug_run: build gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe +debug_walk: build + gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe t + clean: meson compile --clean -C builddir diff --git a/autowalker.cpp b/autowalker.cpp index f4abe76..9658b66 100644 --- a/autowalker.cpp +++ b/autowalker.cpp @@ -1,9 +1,29 @@ #include "autowalker.hpp" +Pathing Autowalker::compute_paths() { + Pathing paths{fsm.$level.map->width(), fsm.$level.map->height()}; + enemy_count = 0; + + fsm.$level.world->query( + [&](const auto ent, auto& position, auto&) { + if(ent != fsm.$level.player) { + paths.set_target(position.location); + enemy_count++; + } + }); -void Autowalker::autowalk() { - fmt::println("I'M WALKIN' HEAR!"); + fmt::println("PATHING to {} count enemies", enemy_count); + + // BUG: using walls() will cause a map full of walls? + dbc::check(matrix::width(fsm.$level.map->$walls) == paths.$width, "WTF the maps's walls width changed?"); + dbc::check(matrix::height(fsm.$level.map->$walls) == paths.$height, "WTF the maps's walls height changed?"); + + paths.compute_paths(fsm.$level.map->$walls); + + return paths; +} +void Autowalker::window_events() { fsm.$window.handleEvents( [&](const sf::Event::KeyPressed &) { fsm.autowalking = false; @@ -14,35 +34,44 @@ void Autowalker::autowalk() { fmt::println("ABORT AUTOWALK"); } ); +} - if(!fsm.autowalking) return; - - while(fsm.in_state(gui::State::IN_COMBAT) || fsm.in_state(gui::State::ATTACKING)) { +void Autowalker::process_combat() { + while(fsm.in_state(gui::State::IN_COMBAT) + || fsm.in_state(gui::State::ATTACKING)) + { if(fsm.in_state(gui::State::ATTACKING)) { - fsm.event(gui::Event::TICK); + send_event(gui::Event::TICK); } else { - fsm.event(gui::Event::ATTACK); + send_event(gui::Event::ATTACK); } - - fsm.handle_world_events(); } +} +Point Autowalker::get_current_position() { auto& player_position = fsm.$level.world->get(fsm.$level.player); - auto current = player_position.location; - Point target = current; - bool found = fsm.$level.map->neighbors(target, false, -1); + return player_position.location; +} + +bool Autowalker::path_player(Pathing& paths, Point& target_out) { + bool found = paths.random_walk(target_out, false, PATHING_TOWARD); + if(!found) { dbc::log("no neighbor found, aborting autowalk"); fsm.autowalking = false; - return; + return false; } - if(!fsm.$level.map->can_move(target)) { + if(!fsm.$level.map->can_move(target_out)) { dbc::log("neighbors is telling me to go to a bad spot."); fsm.autowalking = false; - return; + return false; } + return true; +} + +void Autowalker::rotate_player(Point current, Point target) { int delta_x = int(target.x) - int(current.x); int delta_y = int(target.y) - int(current.y); @@ -79,32 +108,65 @@ void Autowalker::autowalk() { auto dir = facing < target_facing ? gui::Event::ROTATE_LEFT : gui::Event::ROTATE_RIGHT; while(facing != target_facing) { - fsm.event(dir); - fsm.render(); - fsm.handle_world_events(); + send_event(dir); facing = fsm.$main_ui.$compass_dir; } dbc::check(fsm.$main_ui.$compass_dir == target_facing, "player isn't facing the correct direction"); +} - if(!fsm.in_state(gui::State::IN_COMBAT)) { - if(fsm.in_state(gui::State::ATTACKING)) { - fsm.event(gui::Event::TICK); - } else { - fsm.event(gui::Event::MOVE_FORWARD); - } +void Autowalker::autowalk() { + window_events(); + if(!fsm.autowalking) return; - fsm.handle_world_events(); + process_combat(); + auto paths = compute_paths(); - do { - fmt::println("IN WHILE MOVING"); - fsm.event(gui::Event::TICK); - fsm.event(gui::Event::ATTACK); - fsm.render(); - fsm.handle_world_events(); - } while(fsm.in_state(gui::State::MOVING)); + Point current = get_current_position(); + Point target = current; + + matrix::dump("AUTO PATHS", paths.$paths, current.x, current.y); + + if(!path_player(paths, target)) { + dbc::log("no paths found, aborting autowalk"); + fsm.autowalking = false; + return; + } else if(enemy_count == 0) { + dbc::log("Nobody left to kill. You win."); + fsm.autowalking = false; + return; + } else { + dbc::log("Hunting down more enemies."); } + + rotate_player(current, target); + + int move_attempts = 0; + do { + process_combat(); + process_move(); + // BUG: sometimes in idle but there's an enemy near but combat hasn't started + // for now just toss out an ATTACK and it'll be ignored or cause combat + send_event(gui::Event::ATTACK); + move_attempts++; + } while(move_attempts < 100 && !player_has_moved(target)); +} + +void Autowalker::process_move() { + send_event(gui::Event::MOVE_FORWARD); + while(fsm.in_state(gui::State::MOVING)) send_event(gui::Event::TICK); +} + +bool Autowalker::player_has_moved(Point target) { + Point current = get_current_position(); + return current.x == target.x && current.y == target.y; +} + +void Autowalker::send_event(gui::Event ev) { + fsm.event(ev); + fsm.render(); + fsm.handle_world_events(); } void Autowalker::start_autowalk() { diff --git a/autowalker.hpp b/autowalker.hpp index 27fff85..3b45178 100644 --- a/autowalker.hpp +++ b/autowalker.hpp @@ -3,6 +3,7 @@ #include "gui_fsm.hpp" struct Autowalker { + int enemy_count = 0; gui::FSM& fsm; Autowalker(gui::FSM& fsm) @@ -10,4 +11,13 @@ struct Autowalker { void autowalk(); void start_autowalk(); + void send_event(gui::Event ev); + Pathing compute_paths(); + void window_events(); + void process_combat(); + bool path_player(Pathing& paths, Point &target_out); + Point get_current_position(); + void rotate_player(Point current, Point target); + bool player_has_moved(Point target); + void process_move(); }; diff --git a/gui_fsm.cpp b/gui_fsm.cpp index d93170b..8c0c25a 100644 --- a/gui_fsm.cpp +++ b/gui_fsm.cpp @@ -1,3 +1,4 @@ +#define FSM_DEBUG 1 #include "gui_fsm.hpp" #include #include diff --git a/map.hpp b/map.hpp index 87349fc..1dccbe2 100644 --- a/map.hpp +++ b/map.hpp @@ -52,7 +52,7 @@ public: bool iswall(size_t x, size_t y); bool can_move(Point move_to); // BUG: this isn't really neighbors anymore. Maybe move? Walk? - bool neighbors(Point &out, bool random=false, int direction=1); + bool neighbors(Point &out, bool random=false, int direction=PATHING_TOWARD); void make_paths(); void set_target(const Point &at, int value=0); diff --git a/pathing.hpp b/pathing.hpp index 1f62073..f13150f 100644 --- a/pathing.hpp +++ b/pathing.hpp @@ -5,6 +5,9 @@ using matrix::Matrix; +constexpr const int PATHING_TOWARD=1; +constexpr const int PATHING_AWAY=-1; + class Pathing { public: size_t $width;