Better structure on the autowalker, but still gets stuck in some combat situations. Next is after we kill everything we head to the exit.

master
Zed A. Shaw 10 months ago
parent e6c225f1c8
commit 87e1c25cd5
  1. 3
      Makefile
  2. 126
      autowalker.cpp
  3. 10
      autowalker.hpp
  4. 1
      gui_fsm.cpp
  5. 2
      map.hpp
  6. 3
      pathing.hpp

@ -34,6 +34,9 @@ debug: build
debug_run: build debug_run: build
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe 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: clean:
meson compile --clean -C builddir meson compile --clean -C builddir

@ -1,9 +1,29 @@
#include "autowalker.hpp" #include "autowalker.hpp"
Pathing Autowalker::compute_paths() {
Pathing paths{fsm.$level.map->width(), fsm.$level.map->height()};
enemy_count = 0;
fsm.$level.world->query<components::Position, components::Combat>(
[&](const auto ent, auto& position, auto&) {
if(ent != fsm.$level.player) {
paths.set_target(position.location);
enemy_count++;
}
});
void Autowalker::autowalk() { fmt::println("PATHING to {} count enemies", enemy_count);
fmt::println("I'M WALKIN' HEAR!");
// 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( fsm.$window.handleEvents(
[&](const sf::Event::KeyPressed &) { [&](const sf::Event::KeyPressed &) {
fsm.autowalking = false; fsm.autowalking = false;
@ -14,35 +34,44 @@ void Autowalker::autowalk() {
fmt::println("ABORT AUTOWALK"); fmt::println("ABORT AUTOWALK");
} }
); );
}
if(!fsm.autowalking) return; void Autowalker::process_combat() {
while(fsm.in_state(gui::State::IN_COMBAT)
while(fsm.in_state(gui::State::IN_COMBAT) || fsm.in_state(gui::State::ATTACKING)) { || fsm.in_state(gui::State::ATTACKING))
{
if(fsm.in_state(gui::State::ATTACKING)) { if(fsm.in_state(gui::State::ATTACKING)) {
fsm.event(gui::Event::TICK); send_event(gui::Event::TICK);
} else { } 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<components::Position>(fsm.$level.player); auto& player_position = fsm.$level.world->get<components::Position>(fsm.$level.player);
auto current = player_position.location; return player_position.location;
Point target = current; }
bool found = fsm.$level.map->neighbors(target, false, -1);
bool Autowalker::path_player(Pathing& paths, Point& target_out) {
bool found = paths.random_walk(target_out, false, PATHING_TOWARD);
if(!found) { if(!found) {
dbc::log("no neighbor found, aborting autowalk"); dbc::log("no neighbor found, aborting autowalk");
fsm.autowalking = false; 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."); dbc::log("neighbors is telling me to go to a bad spot.");
fsm.autowalking = false; 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_x = int(target.x) - int(current.x);
int delta_y = int(target.y) - int(current.y); 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; auto dir = facing < target_facing ? gui::Event::ROTATE_LEFT : gui::Event::ROTATE_RIGHT;
while(facing != target_facing) { while(facing != target_facing) {
fsm.event(dir); send_event(dir);
fsm.render();
fsm.handle_world_events();
facing = fsm.$main_ui.$compass_dir; facing = fsm.$main_ui.$compass_dir;
} }
dbc::check(fsm.$main_ui.$compass_dir == target_facing, dbc::check(fsm.$main_ui.$compass_dir == target_facing,
"player isn't facing the correct direction"); "player isn't facing the correct direction");
}
if(!fsm.in_state(gui::State::IN_COMBAT)) { void Autowalker::autowalk() {
if(fsm.in_state(gui::State::ATTACKING)) { window_events();
fsm.event(gui::Event::TICK); if(!fsm.autowalking) return;
} else {
fsm.event(gui::Event::MOVE_FORWARD);
}
fsm.handle_world_events(); process_combat();
auto paths = compute_paths();
do { Point current = get_current_position();
fmt::println("IN WHILE MOVING"); Point target = current;
fsm.event(gui::Event::TICK);
fsm.event(gui::Event::ATTACK); matrix::dump("AUTO PATHS", paths.$paths, current.x, current.y);
fsm.render();
fsm.handle_world_events(); if(!path_player(paths, target)) {
} while(fsm.in_state(gui::State::MOVING)); 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() { void Autowalker::start_autowalk() {

@ -3,6 +3,7 @@
#include "gui_fsm.hpp" #include "gui_fsm.hpp"
struct Autowalker { struct Autowalker {
int enemy_count = 0;
gui::FSM& fsm; gui::FSM& fsm;
Autowalker(gui::FSM& fsm) Autowalker(gui::FSM& fsm)
@ -10,4 +11,13 @@ struct Autowalker {
void autowalk(); void autowalk();
void start_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();
}; };

@ -1,3 +1,4 @@
#define FSM_DEBUG 1
#include "gui_fsm.hpp" #include "gui_fsm.hpp"
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>

@ -52,7 +52,7 @@ public:
bool iswall(size_t x, size_t y); bool iswall(size_t x, size_t y);
bool can_move(Point move_to); bool can_move(Point move_to);
// BUG: this isn't really neighbors anymore. Maybe move? Walk? // 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 make_paths();
void set_target(const Point &at, int value=0); void set_target(const Point &at, int value=0);

@ -5,6 +5,9 @@
using matrix::Matrix; using matrix::Matrix;
constexpr const int PATHING_TOWARD=1;
constexpr const int PATHING_AWAY=-1;
class Pathing { class Pathing {
public: public:
size_t $width; size_t $width;