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. 118
      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
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

@ -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<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("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<components::Position>(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);
void Autowalker::autowalk() {
window_events();
if(!fsm.autowalking) return;
process_combat();
auto paths = compute_paths();
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 {
fsm.event(gui::Event::MOVE_FORWARD);
dbc::log("Hunting down more enemies.");
}
fsm.handle_world_events();
rotate_player(current, target);
int move_attempts = 0;
do {
fmt::println("IN WHILE MOVING");
fsm.event(gui::Event::TICK);
fsm.event(gui::Event::ATTACK);
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();
} while(fsm.in_state(gui::State::MOVING));
}
}
void Autowalker::start_autowalk() {

@ -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();
};

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

@ -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);

@ -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;