Test now can work the enemy AI to prototype behavior.
This commit is contained in:
parent
db5a371766
commit
2815375836
6 changed files with 59 additions and 6 deletions
2
Makefile
2
Makefile
|
@ -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 ."
|
||||
|
|
10
ai.cpp
10
ai.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
3
ai.hpp
3
ai.hpp
|
@ -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"]
|
||||
}
|
||||
}
|
||||
|
|
30
tests/ai.cpp
30
tests/ai.cpp
|
@ -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…
Add table
Add a link
Reference in a new issue