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
|
meson compile -j 10 -C builddir
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
./builddir/runtests
|
./builddir/runtests "[ai-enemy]"
|
||||||
|
|
||||||
run: build test
|
run: build test
|
||||||
powershell "cp ./builddir/zedcaster.exe ."
|
powershell "cp ./builddir/zedcaster.exe ."
|
||||||
|
|
10
ai.cpp
10
ai.cpp
|
@ -93,8 +93,8 @@ namespace ai {
|
||||||
auto& scripts = config["scripts"];
|
auto& scripts = config["scripts"];
|
||||||
for(auto& [script_name, action_names] : scripts.items()) {
|
for(auto& [script_name, action_names] : scripts.items()) {
|
||||||
std::vector<Action> the_script;
|
std::vector<Action> the_script;
|
||||||
for(auto name : action_names) {
|
|
||||||
|
|
||||||
|
for(auto name : action_names) {
|
||||||
check(AIMGR.actions.contains(name),
|
check(AIMGR.actions.contains(name),
|
||||||
fmt::format("ai::init(): script {} uses action {} that doesn't exist",
|
fmt::format("ai::init(): script {} uses action {} that doesn't exist",
|
||||||
(std::string)script_name, (std::string)name));
|
(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) {
|
State load_state(std::string state_name) {
|
||||||
check(initialized, "you forgot to initialize the AI first.");
|
check(initialized, "you forgot to initialize the AI first.");
|
||||||
check(AIMGR.states.contains(state_name), fmt::format(
|
check(AIMGR.states.contains(state_name), fmt::format(
|
||||||
|
@ -158,8 +164,8 @@ namespace ai {
|
||||||
return &AIMGR.profile;
|
return &AIMGR.profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EntityAI::wants_to(std::string name) {
|
bool EntityAI::wants_to(std::string name) {
|
||||||
|
ai::check_valid_action(name, "EntityAI::wants_to");
|
||||||
return plan.script[0].name == name;
|
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 set_state(std::string name, bool setting);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
void dump();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AIManager {
|
struct AIManager {
|
||||||
|
@ -55,4 +57,5 @@ namespace ai {
|
||||||
|
|
||||||
/* Mostly used for debugging and validation. */
|
/* Mostly used for debugging and validation. */
|
||||||
AIProfile* profile();
|
AIProfile* profile();
|
||||||
|
void check_valid_action(std::string name, std::string msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,4 +56,8 @@ namespace ai {
|
||||||
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityAI::dump() {
|
||||||
|
dump_script(script, start, plan.script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"name": "kill_enemy",
|
"name": "kill_enemy",
|
||||||
"cost": 5,
|
"cost": 5,
|
||||||
"needs": {
|
"needs": {
|
||||||
|
"health_good": true,
|
||||||
"no_more_enemies": false,
|
"no_more_enemies": false,
|
||||||
"enemy_found": true,
|
"enemy_found": true,
|
||||||
"enemy_dead": false
|
"enemy_dead": false
|
||||||
|
@ -54,11 +55,24 @@
|
||||||
"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": {
|
||||||
"health_good": true
|
"health_good": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "run_away",
|
||||||
|
"cost": 0,
|
||||||
|
"needs": {
|
||||||
|
"in_combat": true,
|
||||||
|
"have_healing": false,
|
||||||
|
"health_good": false
|
||||||
|
},
|
||||||
|
"effects": {
|
||||||
|
"in_combat": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"states": {
|
"states": {
|
||||||
|
@ -102,6 +116,6 @@
|
||||||
"collect_items",
|
"collect_items",
|
||||||
"use_healing"],
|
"use_healing"],
|
||||||
"Enemy::actions":
|
"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"));
|
REQUIRE(ai::test(result, "no_more_enemies"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Confirm EntityAI behaves as expected", "[ai]") {
|
TEST_CASE("Confirm EntityAI behaves as expected", "[ai-enemy]") {
|
||||||
// nothing yet
|
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