AI/lua: Command 'lua wesnoth.debug_ai(2).ai' gives now access to ai-table

This commit is contained in:
flix/Felix Bauer 2013-04-27 04:57:57 +03:00 committed by flix
parent 5301eedbe6
commit f9a231f09d
6 changed files with 105 additions and 74 deletions

View file

@ -1,6 +1,8 @@
Version 1.11.4+dev:
* AI:
* Recruiting in Micro and Experimental AIs: allow more terrain codes for castles/keeps
* Improved/Added: Command 'lua wesnoth.debug_ai([side]).ai' will now give access to the
ai-table of [side].
* Campaigns:
* Legend of Wesmere:
* Scenario 05: Elvish Horse Archers can now carry the treasure

View file

@ -234,7 +234,7 @@ private:
*/
engine_lua::engine_lua( readonly_context &context, const config &cfg )
: engine(context,cfg)
, code_(cfg["code"])
, code_(get_engine_code(cfg))
, lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
get_engine_code(cfg).c_str(), this))
{
@ -269,7 +269,7 @@ void engine_lua::push_ai_table()
{
if (game_config::debug)
{
lua_ai_context_->load();
lua_ai_context_->load_and_inject_ai_table(this);
}
}

View file

@ -815,6 +815,76 @@ static int cfun_ai_recalculate_move_maps_enemy(lua_State *L)
return 1;
}
static void generate_and_push_ai_table(lua_State* L, ai::engine_lua* engine) {
//push data table here
lua_newtable(L);
lua_pushinteger(L, engine->get_readonly_context().get_side());
lua_setfield(L, -2, "side"); //stack size is 2 [- 1: new table; -2 ai as string]
static luaL_Reg const callbacks[] = {
{ "attack", &cfun_ai_execute_attack },
// Move maps
{ "get_new_dst_src", &cfun_ai_get_dstsrc },
{ "get_new_src_dst", &cfun_ai_get_srcdst },
{ "get_new_enemy_dst_src", &cfun_ai_get_enemy_dstsrc },
{ "get_new_enemy_src_dst", &cfun_ai_get_enemy_srcdst },
{ "recalculate_move_maps", &cfun_ai_recalculate_move_maps },
{ "recalculate_enemy_move_maps", &cfun_ai_recalculate_move_maps_enemy },
// End of move maps
// Goals and targets
{ "get_targets", &cfun_ai_get_targets },
// End of G & T
// Aspects
{ "get_aggression", &cfun_ai_get_aggression },
{ "get_avoid", &cfun_ai_get_avoid },
{ "get_attack_depth", &cfun_ai_get_attack_depth },
{ "get_attacks", &cfun_ai_get_attacks },
{ "get_caution", &cfun_ai_get_caution },
{ "get_grouping", &cfun_ai_get_grouping },
{ "get_leader_aggression", &cfun_ai_get_leader_aggression },
{ "get_leader_goal", &cfun_ai_get_leader_goal },
{ "get_leader_ignores_keep", &cfun_ai_get_leader_ignores_keep },
{ "get_leader_value", &cfun_ai_get_leader_value },
{ "get_number_of_possible_recruits_to_force_recruit", &cfun_ai_get_number_of_possible_recruits_to_force_recruit },
{ "get_passive_leader", &cfun_ai_get_passive_leader },
{ "get_passive_leader_shares_keep", &cfun_ai_get_passive_leader_shares_keep },
{ "get_recruitment_ignore_bad_combat", &cfun_ai_get_recruitment_ignore_bad_combat },
{ "get_recruitment_ignore_bad_movement", &cfun_ai_get_recruitment_ignore_bad_movement },
{ "get_recruitment_pattern", &cfun_ai_get_recruitment_pattern },
{ "get_scout_village_targeting", &cfun_ai_get_scout_village_targeting },
{ "get_simple_targeting", &cfun_ai_get_simple_targeting },
{ "get_support_villages", &cfun_ai_get_support_villages },
{ "get_village_value", &cfun_ai_get_village_value },
{ "get_villages_per_scout", &cfun_ai_get_villages_per_scout },
// End of aspects
// Validation/cache functions
{ "is_dst_src_valid", &cfun_ai_is_dst_src_valid },
{ "is_enemy_dst_src_valid", &cfun_ai_is_dst_src_enemy_valid },
{ "is_src_dst_valid", &cfun_ai_is_src_dst_valid },
{ "is_enemy_src_dst_valid", &cfun_ai_is_src_dst_enemy_valid },
// End of validation functions
{ "move", &cfun_ai_execute_move_partial },
{ "move_full", &cfun_ai_execute_move_full },
{ "recall", &cfun_ai_execute_recall },
{ "recruit", &cfun_ai_execute_recruit },
{ "stopunit_all", &cfun_ai_execute_stopunit_all },
{ "stopunit_attacks", &cfun_ai_execute_stopunit_attacks },
{ "stopunit_moves", &cfun_ai_execute_stopunit_moves },
{ "suitable_keep", &cfun_ai_get_suitable_keep },
{ "check_recall", &cfun_ai_check_recall },
{ "check_move", &cfun_ai_check_move },
{ "check_stopunit", &cfun_ai_check_stopunit },
{ "check_attack", &cfun_ai_check_attack },
{ "check_recruit", &cfun_ai_check_recruit },
//{ "",},
//{ "",},
{ NULL, NULL } };
for (const luaL_Reg* p = callbacks; p->name; ++p) {
lua_pushlightuserdata(L, engine);
lua_pushcclosure(L, p->func, 1);
lua_setfield(L, -2, p->name);
}
}
lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine)
{
int res_ai = luaL_loadstring(L, code);//stack size is now 1 [ -1: ai_context]
@ -827,76 +897,7 @@ lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engin
return NULL;
}
//push data table here
lua_newtable(L);// stack size is 2 [ -1: new table, -2: ai as string ]
lua_pushinteger(L, engine->get_readonly_context().get_side());
lua_setfield(L, -2, "side");//stack size is 2 [- 1: new table; -2 ai as string]
static luaL_Reg const callbacks[] = {
{ "attack", &cfun_ai_execute_attack },
// Move maps
{ "get_new_dst_src", &cfun_ai_get_dstsrc },
{ "get_new_src_dst", &cfun_ai_get_srcdst },
{ "get_new_enemy_dst_src", &cfun_ai_get_enemy_dstsrc },
{ "get_new_enemy_src_dst", &cfun_ai_get_enemy_srcdst },
{ "recalculate_move_maps", &cfun_ai_recalculate_move_maps },
{ "recalculate_enemy_move_maps",&cfun_ai_recalculate_move_maps_enemy },
// End of move maps
// Goals and targets
{ "get_targets", &cfun_ai_get_targets },
// End of G & T
// Aspects
{ "get_aggression", &cfun_ai_get_aggression },
{ "get_avoid", &cfun_ai_get_avoid },
{ "get_attack_depth", &cfun_ai_get_attack_depth },
{ "get_attacks", &cfun_ai_get_attacks },
{ "get_caution", &cfun_ai_get_caution },
{ "get_grouping", &cfun_ai_get_grouping },
{ "get_leader_aggression", &cfun_ai_get_leader_aggression },
{ "get_leader_goal", &cfun_ai_get_leader_goal },
{ "get_leader_ignores_keep", &cfun_ai_get_leader_ignores_keep},
{ "get_leader_value", &cfun_ai_get_leader_value },
{ "get_number_of_possible_recruits_to_force_recruit", &cfun_ai_get_number_of_possible_recruits_to_force_recruit},
{ "get_passive_leader", &cfun_ai_get_passive_leader },
{ "get_passive_leader_shares_keep", &cfun_ai_get_passive_leader_shares_keep},
{ "get_recruitment_ignore_bad_combat", &cfun_ai_get_recruitment_ignore_bad_combat},
{ "get_recruitment_ignore_bad_movement", &cfun_ai_get_recruitment_ignore_bad_movement},
{ "get_recruitment_pattern", &cfun_ai_get_recruitment_pattern },
{ "get_scout_village_targeting", &cfun_ai_get_scout_village_targeting },
{ "get_simple_targeting", &cfun_ai_get_simple_targeting },
{ "get_support_villages", &cfun_ai_get_support_villages },
{ "get_village_value", &cfun_ai_get_village_value },
{ "get_villages_per_scout", &cfun_ai_get_villages_per_scout },
// End of aspects
// Validation/cache functions
{ "is_dst_src_valid", &cfun_ai_is_dst_src_valid },
{ "is_enemy_dst_src_valid", &cfun_ai_is_dst_src_enemy_valid },
{ "is_src_dst_valid", &cfun_ai_is_src_dst_valid },
{ "is_enemy_src_dst_valid", &cfun_ai_is_src_dst_enemy_valid },
// End of validation functions
{ "move", &cfun_ai_execute_move_partial },
{ "move_full", &cfun_ai_execute_move_full },
{ "recall", &cfun_ai_execute_recall },
{ "recruit", &cfun_ai_execute_recruit },
{ "stopunit_all", &cfun_ai_execute_stopunit_all },
{ "stopunit_attacks", &cfun_ai_execute_stopunit_attacks },
{ "stopunit_moves", &cfun_ai_execute_stopunit_moves },
{ "suitable_keep", &cfun_ai_get_suitable_keep },
{ "check_recall", &cfun_ai_check_recall },
{ "check_move", &cfun_ai_check_move },
{ "check_stopunit", &cfun_ai_check_stopunit },
{ "check_attack", &cfun_ai_check_attack },
{ "check_recruit", &cfun_ai_check_recruit },
//{ "",},
//{ "",},
{ NULL, NULL }
};
for (const luaL_Reg *p = callbacks; p->name; ++p) {
lua_pushlightuserdata(L, engine);
lua_pushcclosure(L, p->func, 1);
lua_setfield(L, -2, p->name);
}
generate_and_push_ai_table(L, engine);
//compile the ai as a closure
if (!luaW_pcall(L, 1, 1, true)) {
@ -948,6 +949,13 @@ void lua_ai_context::load()
lua_remove(L,-2);
}
void lua_ai_context::load_and_inject_ai_table(ai::engine_lua* engine)
{
load(); //stack size is 1 [-1: ai_context]
generate_and_push_ai_table(L, engine); //stack size is 2 [-1: ai_table -2: ai_context]
lua_setfield(L, -2, "ai"); //stack size is 1 [-1: ai_context]
}
lua_ai_context::~lua_ai_context()
{
// Remove the ai context from the registry, so that it can be collected.

View file

@ -51,6 +51,7 @@ public:
{
}
void load();
void load_and_inject_ai_table(engine_lua* engine);
void get_persistent_data(config &) const;
void set_persistent_data(const config &);
static void init(lua_State *L);

View file

@ -286,6 +286,11 @@ component* holder::get_component(component *root, const std::string &path) {
if (root == NULL) // Return root component(ai_)
{
if (!this->ai_) {
this->init(this->side_);
}
assert(this->ai_);
return &*this->ai_;
}

View file

@ -59,6 +59,9 @@
#include "ai/lua/core.hpp"
#include "version.hpp"
#include "gui/widgets/clickable.hpp"
#include "ai/contexts.hpp"
#include "ai/configuration.hpp"
#include "ai/composite/ai.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
@ -3608,8 +3611,20 @@ static int intf_debug_ai(lua_State *L)
if (lua_engine == NULL)
{
lua_createtable(L, 0, 0);
return 1;
//no lua engine is defined for this side.
//so set up a dummy engine
ai::ai_composite * ai_ptr = dynamic_cast<ai::ai_composite *>(c);
ai::ai_context& ai_context = ai_ptr->get_ai_context();
config cfg = ai::configuration::get_default_ai_parameters();
lua_engine = new ai::engine_lua(ai_context, cfg);
LOG_LUA << "Created new dummy lua-engine for debug_ai(). \n";
//and add the dummy engine as a component
//to the manager, so we could use it later
cfg.add_child("engine", lua_engine->to_config());
ai::component_manager::add_component(c, "engine[]", cfg);
}
lua_engine->push_ai_table(); // stack: [-1: ai_context]