move wesnoth lua ai support from scripting/lua.?pp...
...into separate files in src/ai/lua/
This commit is contained in:
parent
f6953c07ac
commit
41291670bb
16 changed files with 576 additions and 363 deletions
|
@ -98,6 +98,8 @@
|
|||
<Unit filename="..\..\src\ai\gamestate_observer.hpp" />
|
||||
<Unit filename="..\..\src\ai\interface.cpp" />
|
||||
<Unit filename="..\..\src\ai\interface.hpp" />
|
||||
<Unit filename="..\..\src\ai\lua\core.cpp" />
|
||||
<Unit filename="..\..\src\ai\lua\core.hpp" />
|
||||
<Unit filename="..\..\src\ai\manager.cpp" />
|
||||
<Unit filename="..\..\src\ai\manager.hpp" />
|
||||
<Unit filename="..\..\src\ai\registry.cpp" />
|
||||
|
@ -590,6 +592,7 @@
|
|||
<Unit filename="..\..\src\scoped_resource.hpp" />
|
||||
<Unit filename="..\..\src\scripting\lua.cpp" />
|
||||
<Unit filename="..\..\src\scripting\lua.hpp" />
|
||||
<Unit filename="..\..\src\scripting\lua_api.hpp" />
|
||||
<Unit filename="..\..\src\sdl_utils.cpp" />
|
||||
<Unit filename="..\..\src\sdl_utils.hpp" />
|
||||
<Unit filename="..\..\src\serialization\binary_or_text.cpp" />
|
||||
|
|
|
@ -127,6 +127,8 @@
|
|||
<Unit filename="..\..\src\ai\gamestate_observer.hpp" />
|
||||
<Unit filename="..\..\src\ai\interface.cpp" />
|
||||
<Unit filename="..\..\src\ai\interface.hpp" />
|
||||
<Unit filename="..\..\src\ai\lua\core.cpp" />
|
||||
<Unit filename="..\..\src\ai\lua\core.hpp" />
|
||||
<Unit filename="..\..\src\ai\manager.cpp" />
|
||||
<Unit filename="..\..\src\ai\manager.hpp" />
|
||||
<Unit filename="..\..\src\ai\registry.cpp" />
|
||||
|
@ -619,6 +621,7 @@
|
|||
<Unit filename="..\..\src\scoped_resource.hpp" />
|
||||
<Unit filename="..\..\src\scripting\lua.cpp" />
|
||||
<Unit filename="..\..\src\scripting\lua.hpp" />
|
||||
<Unit filename="..\..\src\scripting\lua_core.hpp" />
|
||||
<Unit filename="..\..\src\sdl_utils.cpp" />
|
||||
<Unit filename="..\..\src\sdl_utils.hpp" />
|
||||
<Unit filename="..\..\src\serialization\binary_or_text.cpp" />
|
||||
|
|
|
@ -4811,6 +4811,38 @@
|
|||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="lua"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\ai\lua\core.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\ai\lua\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\ai\lua\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug (fast)|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)\ai\lua\"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="testing"
|
||||
>
|
||||
|
@ -6010,6 +6042,10 @@
|
|||
RelativePath="..\..\src\scripting\lua.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\scripting\lua_api.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Storyscreen"
|
||||
|
@ -6174,6 +6210,14 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="lua"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\src\ai\lua\core.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="testing"
|
||||
>
|
||||
|
|
|
@ -241,6 +241,7 @@ set(wesnoth-main_SRC
|
|||
ai/game_info.cpp
|
||||
ai/gamestate_observer.cpp
|
||||
ai/interface.cpp
|
||||
ai/lua/core.cpp
|
||||
ai/manager.cpp
|
||||
ai/registry.cpp
|
||||
ai/testing/aspect_attacks.cpp
|
||||
|
|
|
@ -68,6 +68,7 @@ wesnoth_source = \
|
|||
ai/game_info.cpp \
|
||||
ai/gamestate_observer.cpp \
|
||||
ai/interface.cpp \
|
||||
ai/lua/core.cpp \
|
||||
ai/manager.cpp \
|
||||
ai/registry.cpp \
|
||||
ai/testing/aspect_attacks.cpp \
|
||||
|
|
|
@ -173,6 +173,7 @@ wesnoth_sources = Split("""
|
|||
ai/game_info.cpp
|
||||
ai/gamestate_observer.cpp
|
||||
ai/interface.cpp
|
||||
ai/lua/core.cpp
|
||||
ai/manager.cpp
|
||||
ai/registry.cpp
|
||||
ai/testing/aspect_attacks.cpp
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "../../log.hpp"
|
||||
#include "../../resources.hpp"
|
||||
#include "../lua/core.hpp"
|
||||
#include "../../scripting/lua.hpp"
|
||||
#include "../../util.hpp"
|
||||
|
||||
|
@ -49,8 +50,8 @@ public:
|
|||
lua_candidate_action_wrapper( rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
|
||||
: candidate_action(context,cfg),evaluation_(cfg["evaluation"]),evaluation_action_handler_(),execution_(cfg["execution"]),execution_action_handler_(),serialized_evaluation_state_()
|
||||
{
|
||||
evaluation_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_ai_action_handler(evaluation_.c_str(),lua_ai_ctx));
|
||||
execution_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_ai_action_handler(execution_.c_str(),lua_ai_ctx));
|
||||
evaluation_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(evaluation_.c_str(),lua_ai_ctx));
|
||||
execution_action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(execution_.c_str(),lua_ai_ctx));
|
||||
}
|
||||
|
||||
virtual ~lua_candidate_action_wrapper() {}
|
||||
|
@ -99,7 +100,7 @@ public:
|
|||
lua_stage_wrapper( ai_context &context, const config &cfg, lua_ai_context &lua_ai_ctx )
|
||||
: stage(context,cfg),action_handler_(),code_(cfg["code"]),serialized_evaluation_state_(cfg.child_or_empty("state"))
|
||||
{
|
||||
action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_ai_action_handler(code_.c_str(),lua_ai_ctx));
|
||||
action_handler_ = boost::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(),lua_ai_ctx));
|
||||
}
|
||||
|
||||
virtual ~lua_stage_wrapper()
|
||||
|
@ -136,9 +137,9 @@ private:
|
|||
*/
|
||||
engine_lua::engine_lua( readonly_context &context, const config &cfg )
|
||||
: engine(context,cfg)
|
||||
, lua_ai_context_(resources::lua_kernel->create_ai_context(
|
||||
, lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
|
||||
cfg["code"].c_str()
|
||||
, this)) //will be moved to set_ai_context
|
||||
, this))
|
||||
{
|
||||
name_ = "lua";
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
#include "engine.hpp"
|
||||
#include "../contexts.hpp"
|
||||
|
||||
class lua_ai_context;
|
||||
|
||||
//============================================================================
|
||||
namespace ai {
|
||||
|
||||
class lua_ai_context;
|
||||
|
||||
class engine_lua : public engine {
|
||||
public:
|
||||
engine_lua( readonly_context &context, const config &cfg );
|
||||
|
|
354
src/ai/lua/core.cpp
Normal file
354
src/ai/lua/core.cpp
Normal file
|
@ -0,0 +1,354 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 by Yurii Chernyi <terraninfo@terraninfo.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ai/lua/core.cpp
|
||||
* Provides core classes for the Lua AI.
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
}
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "core.hpp"
|
||||
#include "../../scripting/lua.hpp"
|
||||
#include "../../scripting/lua_api.hpp"
|
||||
|
||||
#include "../../actions.hpp"
|
||||
#include "../../attack_prediction.hpp"
|
||||
#include "../../filesystem.hpp"
|
||||
#include "../../foreach.hpp"
|
||||
#include "../../game_display.hpp"
|
||||
#include "../../gamestatus.hpp"
|
||||
#include "../../log.hpp"
|
||||
#include "../../map.hpp"
|
||||
#include "../../pathfind/pathfind.hpp"
|
||||
#include "../../play_controller.hpp"
|
||||
#include "../../resources.hpp"
|
||||
#include "../../terrain_translation.hpp"
|
||||
#include "../../unit.hpp"
|
||||
#include "../actions.hpp"
|
||||
#include "../composite/engine_lua.hpp"
|
||||
|
||||
static lg::log_domain log_ai_engine_lua("ai/engine/lua");
|
||||
#define LOG_LUA LOG_STREAM(info, log_ai_engine_lua)
|
||||
#define ERR_LUA LOG_STREAM(err, log_ai_engine_lua)
|
||||
|
||||
static char const aisKey = 0;
|
||||
|
||||
namespace ai {
|
||||
|
||||
void lua_ai_context::init(lua_State *L)
|
||||
{
|
||||
// Create the ai elements table.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_newtable(L);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
|
||||
static int transform_ai_action(lua_State *L, ai::action_result_ptr action_result)
|
||||
{
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L,action_result->is_ok());
|
||||
lua_setfield(L, -2, "ok");
|
||||
lua_pushboolean(L,action_result->is_gamestate_changed());
|
||||
lua_setfield(L, -2, "gamestate_changed");
|
||||
lua_pushinteger(L,action_result->get_status());
|
||||
lua_setfield(L, -2, "status");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool to_map_location(lua_State *L, int &index, map_location &res)
|
||||
{
|
||||
if (lua_isuserdata(L, index))
|
||||
{
|
||||
unit const *u = lua::luaW_tounit(L, index);
|
||||
if (!u) return false;
|
||||
res = u->get_location();
|
||||
++index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!lua_isnumber(L, index)) return false;
|
||||
res.x = lua_tointeger(L, index) - 1;
|
||||
++index;
|
||||
if (!lua_isnumber(L, index)) return false;
|
||||
res.y = lua_tointeger(L, index) - 1;
|
||||
++index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ai_execute_move(lua_State *L, bool remove_movement)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location from, to;
|
||||
if (!to_map_location(L, index, from)) goto error_call_destructors;
|
||||
if (!to_map_location(L, index, to)) goto error_call_destructors;
|
||||
ai::move_result_ptr move_result = ai::actions::execute_move_action(side,true,from,to,remove_movement);
|
||||
return transform_ai_action(L,move_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_move_full(lua_State *L)
|
||||
{
|
||||
return ai_execute_move(L, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_move_partial(lua_State *L)
|
||||
{
|
||||
return ai_execute_move(L, false);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_attack(lua_State *L)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
|
||||
ai::readonly_context &context = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context();
|
||||
|
||||
int side = context.get_side();
|
||||
map_location attacker, defender;
|
||||
if (!to_map_location(L, index, attacker)) goto error_call_destructors;
|
||||
if (!to_map_location(L, index, defender)) goto error_call_destructors;
|
||||
|
||||
int attacker_weapon = -1;//-1 means 'select what is best'
|
||||
double aggression = context.get_aggression();//use the aggression from the context
|
||||
|
||||
if (!lua_isnoneornil(L, index+1) && lua_isnumber(L,index+1)) {
|
||||
aggression = lua_tonumber(L, index+1);
|
||||
}
|
||||
|
||||
if (!lua_isnoneornil(L, index)) {
|
||||
attacker_weapon = lua_tointeger(L, index);
|
||||
}
|
||||
|
||||
ai::attack_result_ptr attack_result = ai::actions::execute_attack_action(side,true,attacker,defender,attacker_weapon,aggression);
|
||||
return transform_ai_action(L,attack_result);
|
||||
}
|
||||
|
||||
static int ai_execute_stopunit_select(lua_State *L, bool remove_movement, bool remove_attacks)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location loc;
|
||||
if (!to_map_location(L, index, loc)) goto error_call_destructors;
|
||||
|
||||
ai::stopunit_result_ptr stopunit_result = ai::actions::execute_stopunit_action(side,true,loc,remove_movement,remove_attacks);
|
||||
return transform_ai_action(L,stopunit_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_moves(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, true, false);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_attacks(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, false, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_all(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, true, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_recruit(lua_State *L)
|
||||
{
|
||||
const char *unit_name = luaL_checkstring(L, 1);
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location where;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
where.x = lua_tonumber(L, 2) - 1;
|
||||
where.y = lua_tonumber(L, 3) - 1;
|
||||
}
|
||||
|
||||
ai::recruit_result_ptr recruit_result = ai::actions::execute_recruit_action(side,true,std::string(unit_name),where);
|
||||
return transform_ai_action(L,recruit_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_recall(lua_State *L)
|
||||
{
|
||||
const char *unit_id = luaL_checkstring(L, 1);
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location where;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
where.x = lua_tonumber(L, 2) - 1;
|
||||
where.y = lua_tonumber(L, 3) - 1;
|
||||
}
|
||||
|
||||
ai::recall_result_ptr recall_result = ai::actions::execute_recall_action(side,true,std::string(unit_id),where);
|
||||
return transform_ai_action(L,recall_result);
|
||||
}
|
||||
|
||||
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]
|
||||
if (res_ai)
|
||||
{
|
||||
|
||||
char const *m = lua_tostring(L, -1);
|
||||
ERR_LUA << "error while initializing ai: " <<m << '\n';
|
||||
lua_pop(L, 2);//return with stack size 0 []
|
||||
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", &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 },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
//compile the ai as a closure
|
||||
if (!lua::luaW_pcall(L, 1, 1, true)) {
|
||||
return NULL;//return with stack size 0 []
|
||||
}
|
||||
|
||||
// Retrieve the ai elements table from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f]
|
||||
// Push the function in the table so that it is not collected.
|
||||
size_t length_ai = lua_objlen(L, -1);//length of ais_table
|
||||
lua_pushvalue(L, -2); //stack size is now 3: [-1: ai_context -2: ais_table -3: ai_context]
|
||||
lua_rawseti(L, -2, length_ai + 1);// ais_table[length+1]=ai_context. stack size is now 2 [-1: ais_table -2: ai_context]
|
||||
lua_pop(L, 2);
|
||||
return new lua_ai_context(L, length_ai + 1, engine->get_readonly_context().get_side());
|
||||
}
|
||||
|
||||
lua_ai_action_handler* lua_ai_action_handler::create(lua_State *L, char const *code, lua_ai_context &context)
|
||||
{
|
||||
int res = luaL_loadstring(L, code);//stack size is now 1 [ -1: f]
|
||||
if (res)
|
||||
{
|
||||
char const *m = lua_tostring(L, -1);
|
||||
ERR_LUA << "error while creating ai function: " <<m << '\n';
|
||||
lua_pop(L, 2);//return with stack size 0 []
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve the ai elements table from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f]
|
||||
// Push the function in the table so that it is not collected.
|
||||
size_t length = lua_objlen(L, -1);//length of ais_table
|
||||
lua_pushvalue(L, -2); //stack size is now 3: [-1: f -2: ais_table -3: f]
|
||||
lua_rawseti(L, -2, length + 1);// ais_table[length+1]=f. stack size is now 2 [-1: ais_table -2: f]
|
||||
lua_remove(L, -1);//stack size is now 1 [-1: f]
|
||||
lua_remove(L, -1);//stack size is now 0 []
|
||||
// Create the proxy C++ action handler.
|
||||
return new lua_ai_action_handler(L, context, length + 1);
|
||||
}
|
||||
|
||||
|
||||
void lua_ai_context::load()
|
||||
{
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);//stack size is now 1 [-1: ais_table key]
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
|
||||
lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_context -2: ais_table]
|
||||
lua_remove(L,-2);
|
||||
}
|
||||
|
||||
lua_ai_context::~lua_ai_context()
|
||||
{
|
||||
// Remove the ai context from the registry, so that it can be collected.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, -2, num_);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
void lua_ai_action_handler::handle(config &cfg, bool configOut)
|
||||
{
|
||||
int initial_top = lua_gettop(L);//get the old stack size
|
||||
|
||||
// Load the user function from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);//stack size is now 1 [-1: ais_table key]
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
|
||||
lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_action -2: ais_table]
|
||||
lua_remove(L, -2);//stack size is 1 [-1: ai_action]
|
||||
//load the lua ai context as a parameter
|
||||
context_.load();//stack size is 2 [-1: ai_context -2: ai_action]
|
||||
|
||||
if (!configOut)
|
||||
{
|
||||
lua_newtable(L);//stack size is 3 [-1: table -2: ai_context -3: ai_action]
|
||||
lua::table_of_wml_config(L, cfg);//the new table now contains the config
|
||||
lua::luaW_pcall(L, 2, LUA_MULTRET, true);
|
||||
}
|
||||
else if (lua_gettop(L) > initial_top)
|
||||
{
|
||||
if (lua::luaW_pcall(L, 1, LUA_MULTRET, true)) {
|
||||
int score = lua_tonumber(L, initial_top + 1);//get score
|
||||
|
||||
if (lua_gettop(L) >= initial_top + 2) {//check if we also have config
|
||||
lua::luaW_toconfig(L, initial_top + 2, cfg);//get config
|
||||
}
|
||||
|
||||
cfg["score"] = score; // write score to the config
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, initial_top);//empty stack
|
||||
}
|
||||
|
||||
lua_ai_action_handler::~lua_ai_action_handler()
|
||||
{
|
||||
// Remove the function from the registry, so that it can be collected.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, -2, num_);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
} // of namespace ai
|
72
src/ai/lua/core.hpp
Normal file
72
src/ai/lua/core.hpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2010 by Yurii Chernyi <terraninfo@terraninfo.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef AI_LUA_CORE_HPP
|
||||
#define AI_LUA_CORE_HPP
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace lua {
|
||||
class LuaKernel;
|
||||
} // of namespace lua
|
||||
|
||||
class config;
|
||||
|
||||
namespace ai {
|
||||
|
||||
class engine_lua;
|
||||
|
||||
/**
|
||||
* Proxy table for the AI context
|
||||
*/
|
||||
class lua_ai_context
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
int num_;
|
||||
int side_;
|
||||
lua_ai_context(lua_State *l, int num, int side) : L(l), num_(num), side_(side)
|
||||
{
|
||||
}
|
||||
static lua_ai_context* create(lua_State *L, char const *code, engine_lua *engine);
|
||||
public:
|
||||
~lua_ai_context();
|
||||
void load();
|
||||
static void init(lua_State *L);
|
||||
friend class lua::LuaKernel;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Proxy class for calling AI action handlers defined in Lua.
|
||||
*/
|
||||
class lua_ai_action_handler
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
lua_ai_context &context_;
|
||||
int num_;
|
||||
lua_ai_action_handler(lua_State *l, lua_ai_context &context, int num) : L(l), context_(context),num_(num)
|
||||
{
|
||||
}
|
||||
static lua_ai_action_handler* create(lua_State *L, char const *code, lua_ai_context &context);
|
||||
public:
|
||||
~lua_ai_action_handler();
|
||||
void handle(config &, bool configOut = false);
|
||||
friend class lua::LuaKernel;
|
||||
};
|
||||
|
||||
}//of namespace ai
|
||||
|
||||
#endif
|
|
@ -3369,7 +3369,7 @@ namespace game_events {
|
|||
unit_wml_ids.insert(id);
|
||||
}
|
||||
|
||||
resources::lua_kernel = new LuaKernel;
|
||||
resources::lua_kernel = new lua::LuaKernel;
|
||||
manager_running = true;
|
||||
|
||||
foreach (static_wml_action_map::value_type &action, static_wml_actions) {
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace resources
|
|||
unit_map *units;
|
||||
std::vector<team> *teams;
|
||||
game_state *state_of_game;
|
||||
LuaKernel *lua_kernel;
|
||||
lua::LuaKernel *lua_kernel;
|
||||
play_controller *controller;
|
||||
::tod_manager *tod_manager;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
class game_display;
|
||||
class gamemap;
|
||||
class game_state;
|
||||
class LuaKernel;
|
||||
namespace lua {
|
||||
class LuaKernel;
|
||||
} //of namespace lua
|
||||
|
||||
class play_controller;
|
||||
class team;
|
||||
class tod_manager;
|
||||
|
@ -36,7 +39,7 @@ namespace resources
|
|||
extern unit_map *units;
|
||||
extern std::vector<team> *teams;
|
||||
extern game_state *state_of_game;
|
||||
extern LuaKernel *lua_kernel;
|
||||
extern lua::LuaKernel *lua_kernel;
|
||||
extern play_controller *controller;
|
||||
extern tod_manager *tod_manager;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
|||
#include <cstring>
|
||||
|
||||
#include "scripting/lua.hpp"
|
||||
#include "scripting/lua_api.hpp"
|
||||
|
||||
#include "actions.hpp"
|
||||
#include "attack_prediction.hpp"
|
||||
|
@ -53,13 +54,13 @@ extern "C" {
|
|||
#include "resources.hpp"
|
||||
#include "terrain_translation.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "ai/actions.hpp"
|
||||
#include "ai/composite/engine_lua.hpp"
|
||||
#include "ai/lua/core.hpp"
|
||||
|
||||
static lg::log_domain log_scripting_lua("scripting/lua");
|
||||
#define LOG_LUA LOG_STREAM(info, log_scripting_lua)
|
||||
#define ERR_LUA LOG_STREAM(err, log_scripting_lua)
|
||||
|
||||
namespace lua {
|
||||
|
||||
/**
|
||||
* Stack storing the queued_event objects needed for calling WML actions.
|
||||
|
@ -97,7 +98,6 @@ static char const tstringKey = 0;
|
|||
static char const uactionKey = 0;
|
||||
static char const vconfigKey = 0;
|
||||
static char const wactionKey = 0;
|
||||
static char const aisKey = 0;
|
||||
|
||||
/* Global definition so that it does not leak on longjmp. */
|
||||
static std::string error_buffer;
|
||||
|
@ -162,7 +162,7 @@ static void luaW_pushscalar(lua_State *L, t_string const &v)
|
|||
/**
|
||||
* Returns true if the metatable of the object is the one found in the registry.
|
||||
*/
|
||||
static bool luaW_hasmetatable(lua_State *L, int index, char const &key)
|
||||
bool luaW_hasmetatable(lua_State *L, int index, char const &key)
|
||||
{
|
||||
if (!lua_getmetatable(L, index))
|
||||
return false;
|
||||
|
@ -203,7 +203,7 @@ static bool luaW_totstring(lua_State *L, int index, t_string &str)
|
|||
* The destination table should be at the top of the stack on entry. It is
|
||||
* still at the top on exit.
|
||||
*/
|
||||
static void table_of_wml_config(lua_State *L, config const &cfg)
|
||||
void table_of_wml_config(lua_State *L, config const &cfg)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return;
|
||||
|
@ -236,7 +236,7 @@ static void table_of_wml_config(lua_State *L, config const &cfg)
|
|||
* @note If the table has holes in the integer keys or floating-point keys,
|
||||
* some keys will be ignored and the error will go undetected.
|
||||
*/
|
||||
static bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta = 0)
|
||||
bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta)
|
||||
{
|
||||
if (!lua_checkstack(L, LUA_MINSTACK))
|
||||
return false;
|
||||
|
@ -357,8 +357,8 @@ static bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg, bool def = tr
|
|||
* Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
|
||||
* @return true if the call was successful and @a nRets return values are available.
|
||||
*/
|
||||
static bool luaW_pcall(lua_State *L
|
||||
, int nArgs, int nRets, bool allow_wml_error = false)
|
||||
bool luaW_pcall(lua_State *L
|
||||
, int nArgs, int nRets, bool allow_wml_error)
|
||||
{
|
||||
// Load the error handler before the function and its arguments.
|
||||
lua_pushlightuserdata(L, (void *)&executeKey);
|
||||
|
@ -395,23 +395,12 @@ static bool luaW_pcall(lua_State *L
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage for a unit, either one on the map, or one owned by the Lua code.
|
||||
*/
|
||||
class lua_unit
|
||||
{
|
||||
size_t uid;
|
||||
unit *ptr;
|
||||
lua_unit(lua_unit const &);
|
||||
|
||||
public:
|
||||
lua_unit(size_t u): uid(u), ptr(NULL) {}
|
||||
lua_unit(unit *u): uid(0), ptr(u) {}
|
||||
~lua_unit() { delete ptr; }
|
||||
bool on_map() const { return !ptr; }
|
||||
void reload();
|
||||
unit *get();
|
||||
};
|
||||
lua_unit::~lua_unit()
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
|
||||
unit *lua_unit::get()
|
||||
{
|
||||
|
@ -432,7 +421,7 @@ void lua_unit::reload()
|
|||
/**
|
||||
* Converts a Lua value to a unit pointer.
|
||||
*/
|
||||
static unit *luaW_tounit(lua_State *L, int index, bool only_on_map = false)
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map)
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, getunitKey)) return NULL;
|
||||
lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, index));
|
||||
|
@ -2379,10 +2368,7 @@ LuaKernel::LuaKernel()
|
|||
|
||||
|
||||
// Create the ai elements table.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_newtable(L);
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
|
||||
ai::lua_ai_context::init(L);
|
||||
|
||||
// Delete dofile and loadfile.
|
||||
lua_pushnil(L);
|
||||
|
@ -2535,294 +2521,15 @@ bool LuaKernel::execute(char const *prog, int nArgs, int nRets)
|
|||
return luaW_pcall(L, nArgs, nRets);
|
||||
}
|
||||
|
||||
static int transform_ai_action(lua_State *L, ai::action_result_ptr action_result)
|
||||
ai::lua_ai_context* LuaKernel::create_lua_ai_context(char const *code, ai::engine_lua *engine)
|
||||
{
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L,action_result->is_ok());
|
||||
lua_setfield(L, -2, "ok");
|
||||
lua_pushboolean(L,action_result->is_gamestate_changed());
|
||||
lua_setfield(L, -2, "gamestate_changed");
|
||||
lua_pushinteger(L,action_result->get_status());
|
||||
lua_setfield(L, -2, "status");
|
||||
return 1;
|
||||
ai::lua_ai_context::create(mState,code,engine);
|
||||
}
|
||||
|
||||
static bool to_map_location(lua_State *L, int &index, map_location &res)
|
||||
ai::lua_ai_action_handler* LuaKernel::create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context)
|
||||
{
|
||||
if (lua_isuserdata(L, index))
|
||||
{
|
||||
if (!luaW_hasmetatable(L, index, getunitKey)) return false;
|
||||
unit const *u = static_cast<lua_unit *>(lua_touserdata(L, index))->get();
|
||||
if (!u) return false;
|
||||
res = u->get_location();
|
||||
++index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!lua_isnumber(L, index)) return false;
|
||||
res.x = lua_tointeger(L, index) - 1;
|
||||
++index;
|
||||
if (!lua_isnumber(L, index)) return false;
|
||||
res.y = lua_tointeger(L, index) - 1;
|
||||
++index;
|
||||
}
|
||||
|
||||
return true;
|
||||
ai::lua_ai_action_handler::create(mState,code,context);
|
||||
}
|
||||
|
||||
static int ai_execute_move(lua_State *L, bool remove_movement)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
} // of namespace lua
|
||||
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location from, to;
|
||||
if (!to_map_location(L, index, from)) goto error_call_destructors;
|
||||
if (!to_map_location(L, index, to)) goto error_call_destructors;
|
||||
ai::move_result_ptr move_result = ai::actions::execute_move_action(side,true,from,to,remove_movement);
|
||||
return transform_ai_action(L,move_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_move_full(lua_State *L)
|
||||
{
|
||||
return ai_execute_move(L, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_move_partial(lua_State *L)
|
||||
{
|
||||
return ai_execute_move(L, false);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_attack(lua_State *L)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
|
||||
ai::readonly_context &context = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context();
|
||||
|
||||
int side = context.get_side();
|
||||
map_location attacker, defender;
|
||||
if (!to_map_location(L, index, attacker)) goto error_call_destructors;
|
||||
if (!to_map_location(L, index, defender)) goto error_call_destructors;
|
||||
|
||||
int attacker_weapon = -1;//-1 means 'select what is best'
|
||||
double aggression = context.get_aggression();//use the aggression from the context
|
||||
|
||||
if (!lua_isnoneornil(L, index+1) && lua_isnumber(L,index+1)) {
|
||||
aggression = lua_tonumber(L, index+1);
|
||||
}
|
||||
|
||||
if (!lua_isnoneornil(L, index)) {
|
||||
attacker_weapon = lua_tointeger(L, index);
|
||||
}
|
||||
|
||||
ai::attack_result_ptr attack_result = ai::actions::execute_attack_action(side,true,attacker,defender,attacker_weapon,aggression);
|
||||
return transform_ai_action(L,attack_result);
|
||||
}
|
||||
|
||||
static int ai_execute_stopunit_select(lua_State *L, bool remove_movement, bool remove_attacks)
|
||||
{
|
||||
int index = 1;
|
||||
if (false) {
|
||||
error_call_destructors:
|
||||
return luaL_typerror(L, index, "location (unit/integers)");
|
||||
}
|
||||
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location loc;
|
||||
if (!to_map_location(L, index, loc)) goto error_call_destructors;
|
||||
|
||||
ai::stopunit_result_ptr stopunit_result = ai::actions::execute_stopunit_action(side,true,loc,remove_movement,remove_attacks);
|
||||
return transform_ai_action(L,stopunit_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_moves(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, true, false);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_attacks(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, false, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_stopunit_all(lua_State *L)
|
||||
{
|
||||
return ai_execute_stopunit_select(L, true, true);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_recruit(lua_State *L)
|
||||
{
|
||||
const char *unit_name = luaL_checkstring(L, 1);
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location where;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
where.x = lua_tonumber(L, 2) - 1;
|
||||
where.y = lua_tonumber(L, 3) - 1;
|
||||
}
|
||||
|
||||
ai::recruit_result_ptr recruit_result = ai::actions::execute_recruit_action(side,true,std::string(unit_name),where);
|
||||
return transform_ai_action(L,recruit_result);
|
||||
}
|
||||
|
||||
static int cfun_ai_execute_recall(lua_State *L)
|
||||
{
|
||||
const char *unit_id = luaL_checkstring(L, 1);
|
||||
int side = ((ai::engine_lua*)lua_touserdata(L,lua_upvalueindex(1)))->get_readonly_context().get_side();
|
||||
map_location where;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
where.x = lua_tonumber(L, 2) - 1;
|
||||
where.y = lua_tonumber(L, 3) - 1;
|
||||
}
|
||||
|
||||
ai::recall_result_ptr recall_result = ai::actions::execute_recall_action(side,true,std::string(unit_id),where);
|
||||
return transform_ai_action(L,recall_result);
|
||||
}
|
||||
|
||||
lua_ai_context* LuaKernel::create_ai_context(char const *code, ai::engine_lua *engine)
|
||||
{
|
||||
lua_State *L = mState;
|
||||
int res_ai = luaL_loadstring(L, code);//stack size is now 1 [ -1: ai_context]
|
||||
if (res_ai)
|
||||
{
|
||||
|
||||
char const *m = lua_tostring(L, -1);
|
||||
ERR_LUA << "error while initializing ai: " <<m << '\n';
|
||||
lua_pop(L, 2);//return with stack size 0 []
|
||||
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", &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 },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
//compile the ai as a closure
|
||||
if (!luaW_pcall(L, 1, 1, true)) {
|
||||
return NULL;//return with stack size 0 []
|
||||
}
|
||||
|
||||
// Retrieve the ai elements table from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f]
|
||||
// Push the function in the table so that it is not collected.
|
||||
size_t length_ai = lua_objlen(L, -1);//length of ais_table
|
||||
lua_pushvalue(L, -2); //stack size is now 3: [-1: ai_context -2: ais_table -3: ai_context]
|
||||
lua_rawseti(L, -2, length_ai + 1);// ais_table[length+1]=ai_context. stack size is now 2 [-1: ais_table -2: ai_context]
|
||||
lua_pop(L, 2);
|
||||
return new lua_ai_context(L, length_ai + 1, engine->get_readonly_context().get_side());
|
||||
}
|
||||
|
||||
lua_ai_action_handler* LuaKernel::create_ai_action_handler(char const *code, lua_ai_context &context)
|
||||
{
|
||||
lua_State *L = mState;
|
||||
|
||||
int res = luaL_loadstring(L, code);//stack size is now 1 [ -1: f]
|
||||
if (res)
|
||||
{
|
||||
char const *m = lua_tostring(L, -1);
|
||||
ERR_LUA << "error while creating ai function: " <<m << '\n';
|
||||
lua_pop(L, 2);//return with stack size 0 []
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve the ai elements table from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f]
|
||||
// Push the function in the table so that it is not collected.
|
||||
size_t length = lua_objlen(L, -1);//length of ais_table
|
||||
lua_pushvalue(L, -2); //stack size is now 3: [-1: f -2: ais_table -3: f]
|
||||
lua_rawseti(L, -2, length + 1);// ais_table[length+1]=f. stack size is now 2 [-1: ais_table -2: f]
|
||||
lua_remove(L, -1);//stack size is now 1 [-1: f]
|
||||
lua_remove(L, -1);//stack size is now 0 []
|
||||
// Create the proxy C++ action handler.
|
||||
return new lua_ai_action_handler(L, context, length + 1);
|
||||
}
|
||||
|
||||
|
||||
void lua_ai_context::load()
|
||||
{
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);//stack size is now 1 [-1: ais_table key]
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
|
||||
lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_context -2: ais_table]
|
||||
lua_remove(L,-2);
|
||||
}
|
||||
|
||||
lua_ai_context::~lua_ai_context()
|
||||
{
|
||||
// Remove the ai context from the registry, so that it can be collected.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, -2, num_);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
void lua_ai_action_handler::handle(config &cfg, bool configOut)
|
||||
{
|
||||
int initial_top = lua_gettop(L);//get the old stack size
|
||||
|
||||
// Load the user function from the registry.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);//stack size is now 1 [-1: ais_table key]
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table]
|
||||
lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_action -2: ais_table]
|
||||
lua_remove(L, -2);//stack size is 1 [-1: ai_action]
|
||||
//load the lua ai context as a parameter
|
||||
context_.load();//stack size is 2 [-1: ai_context -2: ai_action]
|
||||
|
||||
if (!configOut)
|
||||
{
|
||||
lua_newtable(L);//stack size is 3 [-1: table -2: ai_context -3: ai_action]
|
||||
table_of_wml_config(L, cfg);//the new table now contains the config
|
||||
luaW_pcall(L, 2, LUA_MULTRET, true);
|
||||
}
|
||||
else if (lua_gettop(L) > initial_top)
|
||||
{
|
||||
if (luaW_pcall(L, 1, LUA_MULTRET, true)) {
|
||||
int score = lua_tonumber(L, initial_top + 1);//get score
|
||||
|
||||
if (lua_gettop(L) >= initial_top + 2) {//check if we also have config
|
||||
luaW_toconfig(L, initial_top + 2, cfg);//get config
|
||||
}
|
||||
|
||||
cfg["score"] = score; // write score to the config
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, initial_top);//empty stack
|
||||
}
|
||||
|
||||
lua_ai_action_handler::~lua_ai_action_handler()
|
||||
{
|
||||
// Remove the function from the registry, so that it can be collected.
|
||||
lua_pushlightuserdata(L, (void *)&aisKey);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, -2, num_);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
|
|
@ -20,44 +20,12 @@
|
|||
struct lua_State;
|
||||
|
||||
namespace ai {
|
||||
struct engine_lua;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy table for the AI context
|
||||
*/
|
||||
class lua_ai_context
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
int num_;
|
||||
int side_;
|
||||
public:
|
||||
lua_ai_context(lua_State *l, int num, int side) : L(l), num_(num), side_(side)
|
||||
{
|
||||
}
|
||||
~lua_ai_context();
|
||||
void load();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Proxy class for calling AI action handlers defined in Lua.
|
||||
*/
|
||||
class lua_ai_action_handler
|
||||
{
|
||||
private:
|
||||
lua_State *L;
|
||||
lua_ai_context &context_;
|
||||
int num_;
|
||||
public:
|
||||
lua_ai_action_handler(lua_State *l, lua_ai_context &context, int num) : L(l), context_(context),num_(num)
|
||||
{
|
||||
}
|
||||
~lua_ai_action_handler();
|
||||
void handle(config &, bool configOut = false);
|
||||
};
|
||||
class lua_ai_action_handler;
|
||||
class lua_ai_context;
|
||||
class engine_lua;
|
||||
} // of namespace ai
|
||||
|
||||
namespace lua {
|
||||
|
||||
class LuaKernel
|
||||
{
|
||||
|
@ -70,8 +38,10 @@ public:
|
|||
bool run_filter(char const *name, unit const &u);
|
||||
/** Runs a plain script. */
|
||||
void run(char const *prog) { execute(prog, 0, 0); }
|
||||
lua_ai_context* create_ai_context(char const *code, ai::engine_lua *engine);
|
||||
lua_ai_action_handler* create_ai_action_handler(char const *code, lua_ai_context &context);
|
||||
ai::lua_ai_context* create_lua_ai_context(char const *code, ai::engine_lua *engine);
|
||||
ai::lua_ai_action_handler* create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context);
|
||||
};
|
||||
|
||||
} //of namespace lua
|
||||
|
||||
#endif
|
||||
|
|
53
src/scripting/lua_api.hpp
Normal file
53
src/scripting/lua_api.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2009 - 2010 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTING_LUA_API_HPP
|
||||
#define SCRIPTING_LUA_API_HPP
|
||||
|
||||
#include "game_events.hpp"
|
||||
|
||||
struct lua_State;
|
||||
|
||||
|
||||
namespace lua {
|
||||
|
||||
bool luaW_pcall(lua_State *L , int nArgs, int nRets, bool allow_wml_error = false);
|
||||
|
||||
unit *luaW_tounit(lua_State *L, int index, bool only_on_map = false);
|
||||
|
||||
void table_of_wml_config(lua_State *L, config const &cfg);
|
||||
|
||||
bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta = 0);
|
||||
/**
|
||||
* Storage for a unit, either one on the map, or one owned by the Lua code.
|
||||
*/
|
||||
class lua_unit
|
||||
{
|
||||
size_t uid;
|
||||
unit *ptr;
|
||||
lua_unit(lua_unit const &);
|
||||
|
||||
public:
|
||||
lua_unit(size_t u): uid(u), ptr(NULL) {}
|
||||
lua_unit(unit *u): uid(0), ptr(u) {}
|
||||
~lua_unit();
|
||||
bool on_map() const { return !ptr; }
|
||||
void reload();
|
||||
unit *get();
|
||||
};
|
||||
|
||||
|
||||
} //of namespace lua
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue