45 #define LOG_LUA LOG_STREAM(info, log_ai_engine_lua)
46 #define WRN_LUA LOG_STREAM(warn, log_ai_engine_lua)
47 #define ERR_LUA LOG_STREAM(err, log_ai_engine_lua)
49 static char const aisKey[] =
"ai contexts";
50 static char const atkKey[] =
"attack analysis";
53 inline static auto metatable =
atkKey;
68 lua_setfield(
L, LUA_REGISTRYINDEX,
aisKey);
73 int top = lua_gettop(
L);
75 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
76 lua_rawgeti(
L, -1,
num_);
78 lua_getfield(
L, -1,
"params");
86 int top = lua_gettop(
L);
88 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
89 lua_rawgeti(
L, -1,
num_);
92 lua_setfield(
L, -2,
"params");
99 int top = lua_gettop(
L);
101 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
102 lua_rawgeti(
L, -1,
num_);
104 lua_getfield(
L, -1,
"data");
112 int top = lua_gettop(
L);
114 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
115 lua_rawgeti(
L, -1,
num_);
118 lua_setfield(
L, -2,
"data");
125 if(!lua_islightuserdata(L,
n)) {
126 lua_pushstring(L,
"AI engine pointer was invalid");
152 lua_setfield(L, -2,
"ok");
154 lua_setfield(L, -2,
"gamestate_changed");
156 lua_setfield(L, -2,
"status");
158 lua_setfield(L, -2,
"result");
167 unit* leader =
nullptr;
168 if (lua_isuserdata(L,
index))
171 if (!leader)
return luaL_argerror(L, 1,
"unknown unit");
181 lua_pushinteger(L, res.
wml_x());
182 lua_pushinteger(L, res.
wml_y());
187 static int ai_move(lua_State *L,
bool exec,
bool remove_movement)
192 bool unreach_is_ok =
false;
193 if (lua_isboolean(L, 3)) {
207 return ai_move(L,
true,
false);
212 return ai_move(L,
false,
false);
223 int attacker_weapon = -1;
226 if (!lua_isnoneornil(L, 3)) {
227 attacker_weapon = lua_tointeger(L, 3);
228 if (attacker_weapon != -1) {
237 if (!lua_isnoneornil(L, 4) && lua_isnumber(L,4)) {
238 aggression = lua_tonumber(L, 4);
286 const char *
unit_name = luaL_checkstring(L, 1);
307 const char *unit_id = luaL_checkstring(L, 1);
339 lua_createtable(L, 0, 0);
342 lua_pushinteger(L,
i);
345 lua_createtable(L, 3, 0);
347 lua_pushstring(L,
"type");
351 lua_pushstring(L,
"loc");
355 lua_pushstring(L,
"value");
356 lua_pushnumber(L, it->value);
369 lua_pushnumber(L, aggression);
378 lua_createtable(L, attacks.size(), 0);
379 int table_index = lua_gettop(L);
381 ai::attacks_vector::const_iterator it = attacks.begin();
382 for (
int i = 1; it != attacks.end(); ++it, ++
i)
386 lua_rawseti(L, table_index,
i);
393 std::set<map_location> locs;
395 avoid.get_locations(locs);
404 lua_pushnumber(L, caution);
411 lua_pushstring(L, grouping.c_str());
418 lua_pushnumber(L, leader_aggression);
432 void visit_helper(lua_State* L,
const utils::variant<
bool, std::vector<std::string>>& input)
437 lua_pushboolean(L, v);
439 lua_createtable(L, v.size(), 0);
440 for(
const std::string& str : v) {
441 lua_pushlstring(L, str.c_str(), str.size());
442 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
459 lua_pushnumber(L, leader_value);
478 int size = recruiting.size();
479 lua_createtable(L,
size, 0);
482 lua_pushinteger(L,
i + 1);
483 lua_pushstring(L, recruiting[
i].c_str());
492 lua_pushnumber(L, scout_village_targeting);
499 lua_pushboolean(L, simple_targeting);
506 lua_pushboolean(L, support_villages);
513 lua_pushnumber(L, village_value);
520 lua_pushnumber(L, villages_per_scout);
530 lua_getiuservalue(L, -1, 1);
534 double rating = aa_ptr->
rating(aggression, roc);
536 lua_pushnumber(L, rating);
540 static void push_movements(lua_State *L,
const std::vector< std::pair < map_location, map_location > > & moves)
542 lua_createtable(L, moves.size(), 0);
544 int table_index = lua_gettop(L);
546 std::vector< std::pair < map_location, map_location > >::const_iterator move = moves.begin();
548 for (
int i = 1; move != moves.end(); ++move, ++
i)
550 lua_createtable(L, 2, 0);
552 lua_pushstring(L,
"src");
556 lua_pushstring(L,
"dst");
560 lua_rawseti(L, table_index,
i);
568 atk->~attack_analysis();
577 lua_pushstring(L,
"attack analysis @ (%d,%d)");
578 lua_pushinteger(L, atk->target.wml_x());
579 lua_pushinteger(L, atk->target.wml_y());
584 #define ATTACK_GETTER(name, type) LATTR_GETTER(name, type, attack_analysis, atk)
600 if(luaL_newmetatable(L,
atkKey)) {
601 static luaL_Reg
const callbacks[] {
608 luaL_setfuncs(L, callbacks, 0);
609 lua_pushstring(L,
atkKey);
610 lua_setfield(L, -2,
"__metatable");
612 lua_setmetatable(L, -2);
615 lua_setiuservalue(L, -2, 1);
635 return atk.target_value;
639 return atk.avg_losses;
643 return atk.chance_to_kill;
647 return atk.avg_damage_inflicted;
651 return atk.target_starting_damage;
655 return atk.avg_damage_taken;
659 return atk.resources_used;
663 return atk.terrain_quality;
667 return atk.alternative_terrain_quality;
671 return atk.vulnerability;
679 return atk.leader_threat;
683 return atk.uses_leader;
687 return atk.is_surrounded;
692 lua_createtable(L, 0, 0);
699 move_map::const_iterator it = m.begin();
708 lua_pushinteger(L, lhash(key));
710 lua_createtable(L, 0, 0);
712 while (key == it->first) {
715 lua_rawseti(L, -2,
index);
726 }
while (it != m.end());
764 lua_pushboolean(L, valid);
771 lua_pushboolean(L, valid);
778 lua_pushboolean(L, valid);
785 lua_pushboolean(L, valid);
804 return std::dynamic_pointer_cast<typesafe_aspect<T> >(
p).
get();
810 aspect_map::const_iterator iter = aspects.find(luaL_checkstring(L, 2));
811 if(iter == aspects.end()) {
818 aspect_attacks_base* real_aspect =
dynamic_cast<aspect_attacks_base*
>(aspect_as_attacks_vector);
819 while(real_aspect ==
nullptr) {
823 real_aspect =
dynamic_cast<aspect_attacks_base*
>(aspect_as_attacks_vector);
826 std::vector<unit_const_ptr> attackers, enemies;
831 if(u->side() == my_side && real_aspect->is_allowed_attacker(*u)) {
832 attackers.push_back(u.get_shared_ptr());
833 }
else if(u->side() != my_side && real_aspect->is_allowed_enemy(*u)) {
834 enemies.push_back(u.get_shared_ptr());
837 lua_createtable(L, 0, 2);
838 lua_createtable(L, attackers.size(), 0);
839 for(std::size_t
i = 0;
i < attackers.size();
i++) {
841 lua_rawseti(L, -2,
i + 1);
843 lua_setfield(L, -2,
"own");
844 lua_createtable(L, enemies.size(), 0);
845 for(std::size_t
i = 0;
i < enemies.size();
i++) {
847 lua_rawseti(L, -2,
i + 1);
849 lua_setfield(L, -2,
"enemy");
856 if (!u.valid() || u->side() != my_side) {
859 lua_pushinteger(L, lhash(u->get_location()));
864 iter->second->get_lua(L);
872 std::vector<std::string> aspect_names;
873 std::transform(aspects.begin(), aspects.end(), std::back_inserter(aspect_names), std::mem_fn(&aspect_map::value_type::first));
880 lua_pushstring(L,
"attempted to write to the ai.aspects table, which is read-only");
899 if(!lua_isstring(L,2)) {
903 std::string m = lua_tostring(L,2);
911 lua_pushlightuserdata(L, &
engine);
913 lua_setfield(L, -2,
"__index");
915 lua_setfield(L, -2,
"__newindex");
916 lua_pushlightuserdata(L, &
engine);
918 lua_setfield(L, -2,
"__dir");
919 lua_setmetatable(L, -2);
922 lua_pushstring(L,
"read_only");
931 lua_pushlightuserdata(L, &
engine);
932 lua_pushcclosure(L,
p->func, 1);
941 auto callbacks = lua_check<std::vector<std::string>>(L, 2);
942 callbacks.push_back(
"side");
943 callbacks.push_back(
"aspects");
946 callbacks.push_back(
c->name);
956 static luaL_Reg
const callbacks[] = {
1000 for (
const luaL_Reg*
p = callbacks;
p->name; ++
p) {
1001 lua_pushlightuserdata(L,
engine);
1002 lua_pushcclosure(L,
p->func, 1);
1003 lua_pushstring(L,
p->name);
1004 lua_pushvalue(L, -2);
1009 lua_pushlightuserdata(L,
engine);
1011 lua_setfield(L, -2,
"__index");
1013 lua_setfield(L, -2,
"__dir");
1014 lua_setmetatable(L, -2);
1020 lua_getfield(L, LUA_REGISTRYINDEX,
aisKey);
1021 std::size_t length_ai = lua_rawlen(L, -1);
1024 lua_setfield(L, -2,
"ai");
1025 lua_pushvalue(L, -1);
1026 lua_rawseti(L, -3, length_ai + 1);
1028 return length_ai + 1;
1040 int res_ai = luaL_loadbufferx(
L, code, strlen(code), code,
"t");
1044 char const *m = lua_tostring(
L, -1);
1045 ERR_LUA <<
"error while initializing ai: " <<m;
1051 lua_pushvalue(
L, -2);
1052 lua_setfield(
L, -2,
"update_self");
1053 lua_pushlightuserdata(
L,
engine);
1054 lua_setfield(
L, -2,
"engine");
1064 lua_getfield(
L, -1,
"update_self");
1065 lua_getfield(
L, -2,
"params");
1066 lua_getfield(
L, -3,
"data");
1074 lua_setfield(
L, -2,
"self");
1082 int res = luaL_loadbufferx(
L, code, strlen(code), code,
"t");
1085 char const *m = lua_tostring(
L, -1);
1086 ERR_LUA <<
"error while creating ai function: " <<m;
1092 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
1094 std::size_t length = lua_rawlen(
L, -1);
1095 lua_pushvalue(
L, -2);
1096 lua_rawseti(
L, -2, length + 1);
1108 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
1109 lua_rawgeti(
L, -1, ctx.
num_);
1113 lua_getglobal(
L,
"ai");
1114 if(!lua_isnoneornil(
L, -1)) {
1116 lua_getfield(
L, -1,
"read_only");
1120 lua_pushstring(
L,
"read_only");
1121 lua_pushboolean(
L, read_only);
1127 lua_getfield(
L, -1,
"ai");
1128 lua_pushstring(
L,
"read_only");
1129 lua_pushboolean(
L, read_only);
1131 lua_setglobal(
L,
"ai");
1141 lua_setglobal(
L,
"ai");
1144 lua_getglobal(
L,
"ai");
1145 lua_pushstring(
L,
"read_only");
1155 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
1157 lua_rawseti(
L, -2,
num_);
1163 int initial_top = lua_gettop(
L);
1169 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
1170 lua_rawgeti(
L, -1,
num_);
1174 int iState = lua_absindex(
L, -2);
1175 lua_getfield(
L, iState,
"self");
1177 lua_getfield(
L, iState,
"data");
1180 if (!filter_own.
empty()) {
1188 l_obj->store(
L, -1);
1191 lua_settop(
L, initial_top);
1197 lua_getfield(
L, LUA_REGISTRYINDEX,
aisKey);
1199 lua_rawseti(
L, -2,
num_);
Managing the AI-Game interaction - AI actions and their results.
bool is_gamestate_changed() const
static recall_result_ptr execute_recall_action(side_number side, bool execute, const std::string &unit_id, const map_location &where, const map_location &from)
Ask the game to recall a unit for us on specified location.
static const std::string & get_error_name(int error_code)
get human-readable name of the error by code.
static attack_result_ptr execute_attack_action(side_number side, bool execute, const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon, double aggression)
Ask the game to attack an enemy defender using our unit attacker from attackers current location,...
static move_result_ptr execute_move_action(side_number side, bool execute, const map_location &from, const map_location &to, bool remove_movement, bool unreach_is_ok=false)
Ask the game to move our unit from location 'from' to location 'to', optionally - doing a partial mov...
static recruit_result_ptr execute_recruit_action(side_number side, bool execute, const std::string &unit_name, const map_location &where, const map_location &from)
Ask the game to recruit a unit for us on specified location.
static stopunit_result_ptr execute_stopunit_action(side_number side, bool execute, const map_location &unit_location, bool remove_movement, bool remove_attacks)
Ask the game to remove unit movements and/or attack.
double rating(double aggression, const readonly_context &ai_obj) const
virtual std::vector< target > find_targets(const move_map &enemy_dstsrc)=0
virtual ai_context_ptr get_ai_context()
readonly_context & get_readonly_context()
Proxy class for calling AI action handlers defined in Lua.
lua_ai_context & context_
lua_ai_action_handler(lua_State *l, lua_ai_context &context, int num)
static lua_ai_action_handler * create(lua_State *L, char const *code, lua_ai_context &context)
void handle(const config &cfg, const config &filter_own, bool read_only, const lua_object_ptr &l_obj)
Proxy table for the AI context.
void set_persistent_data(const config &)
void get_persistent_data(config &) const
lua_ai_context(lua_State *l, int num, int side)
static void init(lua_State *L)
static lua_ai_context * create(lua_State *L, char const *code, engine_lua *engine)
void set_arguments(const config &)
void get_arguments(config &) const
void apply_micro_ai(const config &cfg)
lua_ai_load(lua_ai_context &ctx, bool read_only)
virtual int get_villages_per_scout() const =0
virtual std::string get_grouping() const =0
virtual const terrain_filter & get_avoid() const =0
virtual bool get_simple_targeting() const =0
virtual void recalculate_move_maps() const =0
virtual const aspect_map & get_aspects() const =0
virtual const attacks_vector & get_attacks() const =0
virtual void set_dst_src_valid_lua()=0
virtual const move_map & get_enemy_srcdst() const =0
virtual const move_map & get_enemy_dstsrc() const =0
virtual bool is_src_dst_enemy_valid_lua() const =0
virtual config get_leader_goal() const =0
virtual double get_aggression() const =0
virtual bool is_src_dst_valid_lua() const =0
virtual bool is_dst_src_enemy_valid_lua() const =0
virtual const team & current_team() const =0
virtual const map_location & suitable_keep(const map_location &leader_location, const pathfind::paths &leader_paths) const =0
get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return near...
virtual void set_src_dst_enemy_valid_lua()=0
virtual const move_map & get_srcdst() const =0
virtual void set_dst_src_enemy_valid_lua()=0
virtual double get_caution() const =0
virtual void recalculate_move_maps_enemy() const =0
virtual bool is_dst_src_valid_lua() const =0
virtual const std::vector< std::string > get_recruitment_pattern() const =0
virtual double get_scout_village_targeting() const =0
virtual double get_leader_aggression() const =0
virtual bool get_support_villages() const =0
virtual const move_map & get_dstsrc() const =0
virtual void set_src_dst_valid_lua()=0
virtual double get_village_value() const =0
virtual double get_leader_value() const =0
virtual side_number get_side() const =0
Get the side number.
const std::vector< std::string > get_advancements(const unit_map::const_iterator &unit) const
A config object defines a single node in a WML file, with access to child nodes.
virtual const unit_map & units() const override
This class represents a single unit of a specific type.
static lg::log_domain log_ai_engine_lua("ai/engine/lua")
static char const atkKey[]
static char const aisKey[]
LUA AI Support engine - creating specific ai components from config.
const map_location & get_location() const
The current map location this unit is at.
Standard logging facilities (interface).
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
void luaW_pushlocation(lua_State *L, const map_location &ml)
Converts a map location object to a Lua table pushed at the top of the stack.
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
int luaW_push_locationset(lua_State *L, const std::set< map_location > &locs)
Converts a set of map locations to a Lua table pushed at the top of the stack.
bool luaW_tolocation(lua_State *L, int index, map_location &loc)
Converts an optional table or pair of integers to a map location object.
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil.
Lua object(value) wrapper implementation.
unit * luaW_tounit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
lua_unit * luaW_pushunit(lua_State *L, Args... args)
A small explanation about what's going on here: Each action has access to two game_info objects First...
static int cfun_ai_is_src_dst_valid(lua_State *L)
static int cfun_ai_get_leader_value(lua_State *L)
static int cfun_ai_get_simple_targeting(lua_State *L)
typesafe_aspect< T > * try_aspect_as(const aspect_ptr &p)
static int cfun_ai_execute_stopunit_all(lua_State *L)
std::vector< attack_analysis > attacks_vector
std::shared_ptr< recruit_result > recruit_result_ptr
static int ai_recruit(lua_State *L, bool exec)
static int impl_ai_aspect_set(lua_State *L)
static int cfun_ai_get_recruitment_pattern(lua_State *L)
static int cfun_ai_get_villages_per_scout(lua_State *L)
static ai::engine_lua & get_engine(lua_State *L, int n)
static int cfun_ai_execute_stopunit_moves(lua_State *L)
static int impl_ai_list(lua_State *L)
static int impl_attack_rating(lua_State *L)
static int cfun_ai_get_targets(lua_State *L)
static int ai_move(lua_State *L, bool exec, bool remove_movement)
static void generate_and_push_ai_table(lua_State *L, ai::engine_lua *engine)
static int cfun_ai_fallback_human(lua_State *)
static int cfun_ai_recalculate_move_maps_enemy(lua_State *L)
static int cfun_ai_get_enemy_srcdst(lua_State *L)
static luaW_Registry atkAnalysisReg
static int impl_atkstat_get(lua_State *L)
static int cfun_ai_check_attack(lua_State *L)
static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
static int cfun_ai_is_dst_src_valid(lua_State *L)
std::shared_ptr< lua_object_base > lua_object_ptr
std::shared_ptr< aspect > aspect_ptr
static int cfun_ai_get_avoid(lua_State *L)
std::shared_ptr< attack_result > attack_result_ptr
static int cfun_ai_get_scout_village_targeting(lua_State *L)
static int cfun_ai_check_stopunit(lua_State *L)
static int cfun_ai_execute_attack(lua_State *L)
static int cfun_ai_get_leader_goal(lua_State *L)
static std::size_t generate_and_push_ai_state(lua_State *L, ai::engine_lua *engine)
static int impl_atkstat_tostring(lua_State *L)
static void push_attack_analysis(lua_State *L, const attack_analysis &)
std::shared_ptr< stopunit_result > stopunit_result_ptr
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
static int cfun_ai_execute_recall(lua_State *L)
static int cfun_ai_check_move(lua_State *L)
static int cfun_ai_execute_stopunit_attacks(lua_State *L)
static int cfun_ai_get_caution(lua_State *L)
static int cfun_ai_execute_recruit(lua_State *L)
static int cfun_ai_execute_move_partial(lua_State *L)
static int ai_recall(lua_State *L, bool exec)
static int cfun_ai_get_enemy_dstsrc(lua_State *L)
static int impl_atkstat_destroy(lua_State *L)
static void push_move_map(lua_State *L, const move_map &m)
static int impl_ai_aspect_list(lua_State *L)
static int impl_ai_aspect_get(lua_State *L)
static int cfun_ai_check_recruit(lua_State *L)
static int transform_ai_action(lua_State *L, const ai::action_result_ptr &action_result)
static int ai_attack(lua_State *L, bool exec)
static int cfun_ai_get_leader_ignores_keep(lua_State *L)
static int cfun_ai_get_leader_aggression(lua_State *L)
static int cfun_ai_get_passive_leader_shares_keep(lua_State *L)
static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
static int cfun_ai_recalculate_move_maps(lua_State *L)
static int impl_ai_get(lua_State *L)
static int cfun_ai_get_passive_leader(lua_State *L)
static int cfun_ai_get_dstsrc(lua_State *L)
static int cfun_ai_get_suitable_keep(lua_State *L)
static int cfun_ai_get_aggression(lua_State *L)
static int cfun_ai_execute_move_full(lua_State *L)
std::shared_ptr< move_result > move_result_ptr
static int ai_stopunit_select(lua_State *L, bool exec, bool remove_movement, bool remove_attacks)
static void push_movements(lua_State *L, const std::vector< std::pair< map_location, map_location > > &moves)
static int cfun_ai_get_attacks(lua_State *L)
std::shared_ptr< action_result > action_result_ptr
static int impl_atkstat_dir(lua_State *L)
static int cfun_ai_check_recall(lua_State *L)
static int cfun_ai_get_srcdst(lua_State *L)
std::shared_ptr< recall_result > recall_result_ptr
static int cfun_ai_get_grouping(lua_State *L)
ATTACK_GETTER("rating", lua_index_raw)
std::map< std::string, aspect_ptr > aspect_map
static int cfun_ai_get_support_villages(lua_State *L)
static ai::readonly_context & get_readonly_context(lua_State *L)
static int cfun_ai_get_village_value(lua_State *L)
static luaL_Reg const mutating_callbacks[]
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
std::string::const_iterator iterator
This module contains various pathfinding functions and utilities.
void lua_push(lua_State *L, const T &val)
std::decay_t< T > luaW_table_get_def(lua_State *L, int index, std::string_view k, const T &def)
returns t[k] where k is the table at index index and k is k or def if it is not convertible to the co...
static config unit_name(const unit *u)
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int get(lua_State *L)
Implement __index metamethod.
static ai::attack_analysis get(lua_State *L, int n)
Encapsulates the map of the game.
static const map_location & null_location()
Object which contains all the possible locations a unit can move to, with associated best routes to t...
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
static map_location::direction n