Test now can work the enemy AI to prototype behavior.

master
Zed A. Shaw 2 weeks ago
parent db5a371766
commit 2815375836
  1. 2
      Makefile
  2. 10
      ai.cpp
  3. 3
      ai.hpp
  4. 4
      ai_debug.cpp
  5. 16
      assets/ai.json
  6. 30
      tests/ai.cpp

@ -22,7 +22,7 @@ tracy_build:
meson compile -j 10 -C builddir
test: build
./builddir/runtests
./builddir/runtests "[ai-enemy]"
run: build test
powershell "cp ./builddir/zedcaster.exe ."

@ -93,8 +93,8 @@ namespace ai {
auto& scripts = config["scripts"];
for(auto& [script_name, action_names] : scripts.items()) {
std::vector<Action> the_script;
for(auto name : action_names) {
for(auto name : action_names) {
check(AIMGR.actions.contains(name),
fmt::format("ai::init(): script {} uses action {} that doesn't exist",
(std::string)script_name, (std::string)name));
@ -110,6 +110,12 @@ namespace ai {
}
}
void check_valid_action(std::string name, std::string msg) {
dbc::check(AIMGR.actions.contains(name),
fmt::format("{} tried to access action that doesn't exist {}",
msg, name));
}
State load_state(std::string state_name) {
check(initialized, "you forgot to initialize the AI first.");
check(AIMGR.states.contains(state_name), fmt::format(
@ -158,8 +164,8 @@ namespace ai {
return &AIMGR.profile;
}
bool EntityAI::wants_to(std::string name) {
ai::check_valid_action(name, "EntityAI::wants_to");
return plan.script[0].name == name;
}

@ -27,6 +27,8 @@ namespace ai {
void set_state(std::string name, bool setting);
void update();
void dump();
};
struct AIManager {
@ -55,4 +57,5 @@ namespace ai {
/* Mostly used for debugging and validation. */
AIProfile* profile();
void check_valid_action(std::string name, std::string msg);
}

@ -56,4 +56,8 @@ namespace ai {
return start;
}
void EntityAI::dump() {
dump_script(script, start, plan.script);
}
}

@ -28,6 +28,7 @@
"name": "kill_enemy",
"cost": 5,
"needs": {
"health_good": true,
"no_more_enemies": false,
"enemy_found": true,
"enemy_dead": false
@ -54,11 +55,24 @@
"needs": {
"have_item": true,
"have_healing": true,
"in_combat": false,
"health_good": false
},
"effects": {
"health_good": true
}
},
{
"name": "run_away",
"cost": 0,
"needs": {
"in_combat": true,
"have_healing": false,
"health_good": false
},
"effects": {
"in_combat": false
}
}
],
"states": {
@ -102,6 +116,6 @@
"collect_items",
"use_healing"],
"Enemy::actions":
["find_enemy", "kill_enemy"]
["find_enemy", "kill_enemy", "run_away", "use_healing"]
}
}

@ -171,6 +171,32 @@ TEST_CASE("ai autowalker ai test", "[ai]") {
REQUIRE(ai::test(result, "no_more_enemies"));
}
TEST_CASE("Confirm EntityAI behaves as expected", "[ai]") {
// nothing yet
TEST_CASE("Confirm EntityAI behaves as expected", "[ai-enemy]") {
ai::reset();
ai::init("assets/ai.json");
auto ai_start = ai::load_state("Enemy::initial_state");
auto ai_goal = ai::load_state("Enemy::final_state");
ai::EntityAI enemy("Enemy::actions", ai_start, ai_goal);
enemy.set_state("detect_enemy", true);
enemy.update();
REQUIRE(enemy.wants_to("find_enemy"));
enemy.set_state("enemy_found", true);
enemy.update();
REQUIRE(enemy.wants_to("kill_enemy"));
enemy.set_state("in_combat", true);
enemy.set_state("health_good", false);
enemy.update();
enemy.dump();
REQUIRE(enemy.wants_to("run_away"));
enemy.set_state("have_item", true);
enemy.set_state("have_healing", true);
enemy.set_state("in_combat", false);
enemy.update();
enemy.dump();
REQUIRE(enemy.wants_to("use_healing"));
}

Loading…
Cancel
Save