Improved the code so it uses ai::EntityAI and it now will find healing when it gets low. Has a bug where it stalls when finding healing and gets into combat.

This commit is contained in:
Zed A. Shaw 2025-09-07 23:56:24 -04:00
parent 7207d53885
commit 0afaa20c1d
4 changed files with 31 additions and 29 deletions

View file

@ -37,7 +37,7 @@ tracy_build:
meson compile -j 10 -C builddir meson compile -j 10 -C builddir
test: test:
./builddir/runtests -d yes "[systems-rotate]" ./builddir/runtests -d yes
run: build test run: build test
ifeq '$(OS)' 'Windows_NT' ifeq '$(OS)' 'Windows_NT'
@ -60,7 +60,7 @@ clean:
meson compile --clean -C builddir meson compile --clean -C builddir
debug_test: build debug_test: build
gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e "[systems-rotate]" gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests -e
win_installer: win_installer:
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp' powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'

View file

@ -23,6 +23,7 @@
"enemy_found": false "enemy_found": false
}, },
"effects": { "effects": {
"in_combat": true,
"enemy_found": true "enemy_found": true
} }
}, },
@ -67,7 +68,7 @@
}, },
{ {
"name": "find_healing", "name": "find_healing",
"cost": 5, "cost": 2,
"needs": { "needs": {
"have_healing": false, "have_healing": false,
"in_combat": false, "in_combat": false,
@ -79,11 +80,10 @@
}, },
{ {
"name": "use_healing", "name": "use_healing",
"cost": 0, "cost": 1,
"needs": { "needs": {
"have_item": true, "have_item": true,
"have_healing": true, "have_healing": true,
"in_combat": false,
"health_good": false "health_good": false
}, },
"effects": { "effects": {
@ -132,6 +132,7 @@
["find_enemy", ["find_enemy",
"kill_enemy", "kill_enemy",
"collect_items", "collect_items",
"find_healing",
"use_healing"], "use_healing"],
"Enemy::actions": "Enemy::actions":
["find_enemy", "run_away", "kill_enemy", "use_healing"] ["find_enemy", "run_away", "kill_enemy", "use_healing"]

View file

@ -153,27 +153,25 @@ void Autowalker::rotate_player(Point target) {
fsm.autowalking = player.aiming_at == target; fsm.autowalking = player.aiming_at == target;
} }
ai::State Autowalker::update_state(ai::State start) { void Autowalker::update_state(ai::EntityAI& player_ai) {
int enemy_count = number_left<components::Combat>(); int enemy_count = number_left<components::Combat>();
int item_count = number_left<components::InventoryItem>(); int item_count = number_left<components::InventoryItem>();
ai::set(start, "no_more_enemies", enemy_count == 0); player_ai.set_state("no_more_enemies", enemy_count == 0);
ai::set(start, "no_more_items", item_count == 0); player_ai.set_state("no_more_items", item_count == 0);
// BUG: so isn't this wrong? we "find" an enemy when we are aiming at one player_ai.set_state("enemy_found", found_enemy());
ai::set(start, "enemy_found", found_enemy()); player_ai.set_state("health_good", player_health_good());
ai::set(start, "health_good", player_health_good()); player_ai.set_state("in_combat",
ai::set(start, "in_combat",
fsm.in_state(gui::State::IN_COMBAT) || fsm.in_state(gui::State::IN_COMBAT) ||
fsm.in_state(gui::State::ATTACKING)); fsm.in_state(gui::State::ATTACKING));
auto inv = player_item_count(); auto inv = player_item_count();
ai::set(start, "have_item", inv.other > 0 || inv.healing > 0); player_ai.set_state("have_item", inv.other > 0 || inv.healing > 0);
ai::set(start, "have_healing", inv.healing > 0); player_ai.set_state("have_healing", inv.healing > 0);
return start; player_ai.update();
} }
void Autowalker::handle_boss_fight() { void Autowalker::handle_boss_fight() {
@ -186,20 +184,18 @@ void Autowalker::handle_boss_fight() {
} }
void Autowalker::handle_player_walk(ai::State& start, ai::State& goal) { void Autowalker::handle_player_walk(ai::State& start, ai::State& goal) {
start = update_state(start); ai::EntityAI player_ai("Host::actions", start, goal);
auto a_plan = ai::plan("Host::actions", start, goal); update_state(player_ai);
auto action = a_plan.script.front();
auto level = GameDB::current_level(); auto level = GameDB::current_level();
// ai::dump_script("AUTOWALK", start, a_plan.script);
if(action.name == "find_enemy") { if(player_ai.wants_to("find_enemy")) {
status(L"FINDING ENEMY"); status(L"FINDING ENEMY");
auto paths = path_to_enemies(); auto paths = path_to_enemies();
process_move(paths, [&](auto target) -> bool { process_move(paths, [&](auto target) -> bool {
return level.collision->occupied(target); return level.collision->occupied(target);
}); });
face_enemy(); face_enemy();
} else if(action.name == "kill_enemy") { } else if(player_ai.wants_to("kill_enemy")) {
status(L"KILLING ENEMY"); status(L"KILLING ENEMY");
if(fsm.in_state(gui::State::IN_COMBAT)) { if(fsm.in_state(gui::State::IN_COMBAT)) {
@ -207,11 +203,13 @@ void Autowalker::handle_player_walk(ai::State& start, ai::State& goal) {
process_combat(); process_combat();
} }
} }
} else if(action.name == "use_healing") { } else if(player_ai.wants_to("use_healing")) {
status(L"USING HEALING"); status(L"USING HEALING");
player_use_healing(); player_use_healing();
} else if(action.name == "collect_items" || action.name == "find_healing") { } else if(player_ai.wants_to("collect_items") || player_ai.wants_to("find_healing")) {
status(action.name == "collection_items" ? L"COLLECTING ITEMS" : L"FIND HEALING"); fmt::println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
status(player_ai.wants_to("collect_items") ? L"COLLECTING ITEMS" : L"FIND HEALING");
player_ai.dump();
auto paths = path_to_items(); auto paths = path_to_items();
@ -225,13 +223,14 @@ void Autowalker::handle_player_walk(ai::State& start, ai::State& goal) {
}); });
if(found_it) pickup_item(); if(found_it) pickup_item();
} else if(action == ai::FINAL_ACTION) { fmt::println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
} else if(!player_ai.active()) {
close_status(); close_status();
log(L"FINAL ACTION! Autowalk done."); log(L"FINAL ACTION! Autowalk done.");
fsm.autowalking = false; fsm.autowalking = false;
} else { } else {
close_status(); close_status();
dbc::log(fmt::format("Unknown action: {}", action.name)); dbc::log(fmt::format("Unknown action: {}", player_ai.to_string()));
} }
} }
@ -358,7 +357,9 @@ bool Autowalker::player_health_good() {
auto world = GameDB::current_world(); auto world = GameDB::current_world();
auto player = GameDB::the_player(); auto player = GameDB::the_player();
auto combat = world->get<components::Combat>(player); auto combat = world->get<components::Combat>(player);
return float(combat.hp) / float(combat.max_hp) > 0.5f; float health = float(combat.hp) / float(combat.max_hp);
fmt::println("!!!!!!!!!! HEALTH: {}", health);
return health > 0.5f;
} }
InventoryStats Autowalker::player_item_count() { InventoryStats Autowalker::player_item_count() {

View file

@ -41,7 +41,7 @@ struct Autowalker {
bool player_health_good(); bool player_health_good();
void player_use_healing(); void player_use_healing();
InventoryStats player_item_count(); InventoryStats player_item_count();
ai::State update_state(ai::State start); void update_state(ai::EntityAI& player_ai);
DinkyECS::Entity camera_aim(); DinkyECS::Entity camera_aim();
Pathing path_to_enemies(); Pathing path_to_enemies();