Add support for AI candidate actions written in lua.
patch LuaW_pcall to support LUA_MULTRET. Patch #1558 by Darkas.
This commit is contained in:
parent
19428efb5e
commit
f2b8b94d0b
6 changed files with 79 additions and 12 deletions
|
@ -2,6 +2,7 @@ Version 1.7.15+svn:
|
|||
* AI:
|
||||
* Fixed bug #14247: Make formula AI behave correctly if the side has only 1
|
||||
potential recruit.
|
||||
* Added support for candidate actions written in lua.
|
||||
* Campaigns:
|
||||
* Legend of Wesmere:
|
||||
* Fixed bug #15631: Scenario 3: arrival of Kalenz failed
|
||||
|
|
|
@ -205,11 +205,32 @@ local my_ai = { }
|
|||
local ai_stdlib = wesnoth.require('ai/lua/stdlib.lua');
|
||||
ai_stdlib.init(ai)
|
||||
|
||||
function my_ai:execute()
|
||||
ai.say_hello()
|
||||
function my_ai:stage_hello()
|
||||
wesnoth.message('hello from stage!')
|
||||
end
|
||||
|
||||
function my_ai:candidate_action_evaluation_hello()
|
||||
wesnoth.message('hello from candidate action evaluation!')
|
||||
return 42, {test=123}
|
||||
end
|
||||
|
||||
function my_ai:candidate_action_execution_hello(cfg)
|
||||
wesnoth.message('hello from candidate action execution!')
|
||||
wesnoth.message('test value is ' .. cfg.test)
|
||||
self:do_moves()
|
||||
end
|
||||
|
||||
function my_ai:candidate_action_evaluation_hello2()
|
||||
wesnoth.message('hello from second candidate action evaluation!')
|
||||
return 99
|
||||
end
|
||||
|
||||
function my_ai:candidate_action_execution_hello2()
|
||||
wesnoth.message('hello from second candidate action execution!')
|
||||
self:do_moves()
|
||||
end
|
||||
|
||||
|
||||
function my_ai:do_moves()
|
||||
my_leader = wesnoth.get_units({canrecruit = true, side = ai.side})[1]
|
||||
--! move (partial move)
|
||||
|
@ -237,9 +258,24 @@ return my_ai
|
|||
--! ==============================================================
|
||||
>>
|
||||
[/engine]
|
||||
[stage]
|
||||
name=testing_ai_default::candidate_action_evaluation_loop
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
name=first
|
||||
evaluation="return (...):candidate_action_evaluation_hello()"
|
||||
execution="local ai, cfg = ...; ai:candidate_action_execution_hello(cfg)"
|
||||
[/candidate_action]
|
||||
[candidate_action]
|
||||
engine=lua
|
||||
name=second
|
||||
evaluation="return (...):candidate_action_evaluation_hello2()"
|
||||
execution="(...):candidate_action_execution_hello2()"
|
||||
[/candidate_action]
|
||||
[/stage]
|
||||
[stage]
|
||||
engine="lua"
|
||||
code= "(...):execute()"
|
||||
code= "(...):stage_hello()"
|
||||
[/stage]
|
||||
[/ai]
|
||||
[/side]
|
||||
|
|
|
@ -799,6 +799,9 @@
|
|||
[entry]
|
||||
name = "Alesis Novik"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "André Knispel"
|
||||
[/entry]
|
||||
[entry]
|
||||
name = "Andrea Palmatè (afxgroup)"
|
||||
[/entry]
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
{
|
||||
serialized_evaluation_state_ = config();
|
||||
if (evaluation_action_handler_) {
|
||||
evaluation_action_handler_->handle(serialized_evaluation_state_);
|
||||
evaluation_action_handler_->handle(serialized_evaluation_state_, true);
|
||||
} else {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
|
|
|
@ -364,6 +364,8 @@ static bool luaW_pcall(lua_State *L
|
|||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_insert(L, -2 - nArgs);
|
||||
|
||||
int error_handler_index = lua_gettop(L) - nArgs - 1;
|
||||
|
||||
// Call the function.
|
||||
int res = lua_pcall(L, nArgs, nRets, -2 - nArgs);
|
||||
if (res)
|
||||
|
@ -382,7 +384,13 @@ static bool luaW_pcall(lua_State *L
|
|||
}
|
||||
|
||||
// Remove the error handler.
|
||||
lua_remove(L, -1 - nRets);
|
||||
|
||||
if(nRets == LUA_MULTRET) {
|
||||
lua_remove(L, error_handler_index);
|
||||
} else {
|
||||
lua_remove(L, -1 - nRets);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2735,19 +2743,38 @@ lua_ai_context::~lua_ai_context()
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* handling of config in-out parameter will be done later
|
||||
*/
|
||||
void lua_ai_action_handler::handle(config &/*cfg*/)
|
||||
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]
|
||||
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]
|
||||
luaW_pcall(L, 1, 0, true);
|
||||
|
||||
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"] = str_cast(score);//write score to the config
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, initial_top);//empty stack
|
||||
}
|
||||
|
||||
lua_ai_action_handler::~lua_ai_action_handler()
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
{
|
||||
}
|
||||
~lua_ai_action_handler();
|
||||
void handle(config &);
|
||||
void handle(config &, bool configOut = false);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue