mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-05 09:33:36 +00:00
split wesnoth.synchronize_choice function
previously there was one function which sometimes returned a wml table and sometimes a map integer to wml tables dependent on its parameters. Now there are 2 different functions: wesnoth.synchronize_choice and wesnoth.synchronize_choices. the first one handles the case where you just want to get a choice from one side and thus it returns just one wml table. The second function handles the case where you want to get choices from multiple sides. that function retruns a table of wml tables. I also added an optional string parameter to that function specifying the type of that choice (this is useful to make replays more robust and readable)
This commit is contained in:
parent
4c034d7705
commit
9c9f8f5a6e
@ -2909,44 +2909,48 @@ int game_lua_kernel::intf_skip_messages(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
struct lua_synchronize : mp_sync::user_choice
|
||||
{
|
||||
typedef boost::function<void(std::string const &, std::string const &)> error_reporter;
|
||||
lua_State *L;
|
||||
const std::vector<team> & teams_;
|
||||
error_reporter error_reporter_;
|
||||
lua_synchronize(lua_State *l, const std::vector<team> & t, error_reporter & eh)
|
||||
int user_choice_index;
|
||||
int random_choice_index;
|
||||
int ai_choice_index;
|
||||
|
||||
lua_synchronize(lua_State *l, int user_index, int random_index = 0, int ai_index = 0)
|
||||
: L(l)
|
||||
, teams_(t)
|
||||
, error_reporter_(eh)
|
||||
, user_choice_index(user_index)
|
||||
, random_choice_index(random_index)
|
||||
, ai_choice_index(ai_index != 0 ? ai_index : user_index)
|
||||
{}
|
||||
|
||||
virtual config query_user(int side) const
|
||||
{
|
||||
bool is_local_ai = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).teams()[side - 1].is_local_ai();
|
||||
config cfg;
|
||||
int index = 1;
|
||||
if (!lua_isnoneornil(L, 2)) {
|
||||
if (teams_[side - 1].is_local_ai())
|
||||
index = 2;
|
||||
}
|
||||
lua_pushvalue(L, index);
|
||||
lua_pushnumber(L, side);
|
||||
if (luaW_pcall(L, 1, 1, false)) {
|
||||
if(!luaW_toconfig(L, -1, cfg)) {
|
||||
std::string message = "function returned to wesnoth.synchronize_choice a table which was partially invalid";
|
||||
if (game_config::debug) {
|
||||
error_reporter_("Lua warning", message.c_str());
|
||||
}
|
||||
WRN_LUA << message << std::endl;
|
||||
}
|
||||
}
|
||||
query_lua(side, is_local_ai ? ai_choice_index : user_choice_index, cfg);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
virtual config random_choice(int /*side*/) const
|
||||
virtual config random_choice(int side) const
|
||||
{
|
||||
return config();
|
||||
config cfg;
|
||||
if(random_choice_index != 0 && lua_isfunction(L, random_choice_index)) {
|
||||
query_lua(side, random_choice_index, cfg);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
void query_lua(int side, int function_index, config& cfg) const
|
||||
{
|
||||
assert(cfg.empty());
|
||||
lua_pushvalue(L, function_index);
|
||||
lua_pushnumber(L, side);
|
||||
if (luaW_pcall(L, 1, 1, false)) {
|
||||
if(!luaW_toconfig(L, -1, cfg)) {
|
||||
lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).log_error("function returned to wesnoth.synchronize_choice a table which was partially invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
//Although luas sync_choice can show a dialog, (and will in most cases)
|
||||
//we return false to enable other possible things that do not contain UI things.
|
||||
@ -2957,44 +2961,72 @@ namespace {
|
||||
|
||||
/**
|
||||
* Ensures a value is synchronized among all the clients.
|
||||
* - Arg 1: function to compute the value, called if the client is the master.
|
||||
* - Arg 2: optional function, called instead of the first function if the user is not human.
|
||||
* - Arg 3: optional array of integers specifying, on which side the function should be evaluated.
|
||||
* - Arg 1: optional string specifying the type id of the choice.
|
||||
* - Arg 2: function to compute the value, called if the client is the master.
|
||||
* - Arg 3: optional function, called instead of the first function if the user is not human.
|
||||
* - Arg 4: optional integer specifying, on which side the function should be evaluated.
|
||||
* - Ret 1: WML table returned by the function.
|
||||
*/
|
||||
int game_lua_kernel::intf_synchronize_choice(lua_State *L)
|
||||
static int intf_synchronize_choice(lua_State *L)
|
||||
{
|
||||
if(lua_istable(L, 3))
|
||||
{
|
||||
std::set<int> vals;
|
||||
//read the third parameter
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 3) != 0) {
|
||||
/* uses 'key' (at index -2) and 'value' (at index -1) */
|
||||
int val = luaL_checkint(L, -1);
|
||||
vals.insert(val);
|
||||
/* removes 'value'; keeps 'key' for next iteration */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
typedef std::map<int,config> retv_t;
|
||||
lua_synchronize::error_reporter er = boost::bind(&game_lua_kernel::lua_chat, this, _1, _2);
|
||||
retv_t r = mp_sync::get_user_choice_multiple_sides("input", lua_synchronize(L, teams(), er), vals);
|
||||
lua_newtable(L);
|
||||
BOOST_FOREACH(retv_t::value_type& pair, r)
|
||||
{
|
||||
lua_pushinteger(L, pair.first);
|
||||
luaW_pushconfig(L, pair.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
std::string tagname = "input";
|
||||
int human_func = 0;
|
||||
int ai_func = 0;
|
||||
int side_for;
|
||||
|
||||
int nextarg = 1;
|
||||
if(!lua_isfunction(L, nextarg) && lua_isstring(L, nextarg) ) {
|
||||
tagname = lua_check<std::string>(L, nextarg++);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_synchronize::error_reporter er = boost::bind(&game_lua_kernel::lua_chat, this, _1, _2);
|
||||
config cfg = mp_sync::get_user_choice("input", lua_synchronize(L, teams(), er));
|
||||
luaW_pushconfig(L, cfg);
|
||||
if(lua_isfunction(L, nextarg)) {
|
||||
human_func = nextarg++;
|
||||
}
|
||||
else {
|
||||
return luaL_argerror(L, nextarg, "expected a function");
|
||||
}
|
||||
if(lua_isfunction(L, nextarg)) {
|
||||
ai_func = nextarg++;
|
||||
}
|
||||
side_for = lua_tointeger(L, nextarg);
|
||||
|
||||
config cfg = mp_sync::get_user_choice(tagname, lua_synchronize(L, human_func, 0, ai_func), side_for);
|
||||
luaW_pushconfig(L, cfg);
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* Ensures a value is synchronized among all the clients.
|
||||
* - Arg 1: optional string the id of this type of user input, may only contain chracters a-z and '_'
|
||||
* - Arg 2: function to compute the value, called if the client is the master.
|
||||
* - Arg 3: an optional function to compute the value, if the side was null/empty controlled.
|
||||
* - Arg 4: an array of integers specifying, on which side the function should be evaluated.
|
||||
* - Ret 1: a map int -> WML tabls.
|
||||
*/
|
||||
static int intf_synchronize_choices(lua_State *L)
|
||||
{
|
||||
std::string tagname = "input";
|
||||
int human_func = 0;
|
||||
int null_func = 0;
|
||||
std::vector<int> sides_for;
|
||||
|
||||
int nextarg = 1;
|
||||
if(!lua_isfunction(L, nextarg) && lua_isstring(L, nextarg) ) {
|
||||
tagname = lua_check<std::string>(L, nextarg++);
|
||||
}
|
||||
if(lua_isfunction(L, nextarg)) {
|
||||
human_func = nextarg++;
|
||||
}
|
||||
else {
|
||||
return luaL_argerror(L, nextarg, "expected a function");
|
||||
}
|
||||
if(lua_isfunction(L, nextarg)) {
|
||||
null_func = nextarg++;
|
||||
};
|
||||
sides_for = lua_check<std::vector<int> >(L, nextarg++);
|
||||
|
||||
lua_push(L, mp_sync::get_user_choice_multiple_sides(tagname, lua_synchronize(L, human_func, null_func), std::set<int>(sides_for.begin(), sides_for.end())));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function in an unsynced context (this specially means that all random calls used by that function will be unsynced).
|
||||
@ -4229,7 +4261,8 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
|
||||
{ "set_variable", &dispatch<&game_lua_kernel::intf_set_variable > },
|
||||
{ "set_village_owner", &dispatch<&game_lua_kernel::intf_set_village_owner > },
|
||||
{ "simulate_combat", &dispatch<&game_lua_kernel::intf_simulate_combat > },
|
||||
{ "synchronize_choice", &dispatch<&game_lua_kernel::intf_synchronize_choice > },
|
||||
{ "synchronize_choice", &intf_synchronize_choice },
|
||||
{ "synchronize_choices", &intf_synchronize_choices },
|
||||
{ "view_locked", &dispatch<&game_lua_kernel::intf_view_locked > },
|
||||
{ "place_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, true > },
|
||||
{ "remove_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, false > },
|
||||
|
@ -55,7 +55,6 @@ class game_lua_kernel : public lua_kernel_base
|
||||
game_board & board();
|
||||
unit_map & units();
|
||||
const gamemap & map();
|
||||
std::vector<team> & teams();
|
||||
game_data & gamedata();
|
||||
tod_manager & tod_man();
|
||||
|
||||
@ -132,7 +131,6 @@ class game_lua_kernel : public lua_kernel_base
|
||||
int intf_deselect_hex(lua_State *L);
|
||||
int intf_is_skipping_messages(lua_State *L);
|
||||
int intf_skip_messages(lua_State *L);
|
||||
int intf_synchronize_choice(lua_State *L);
|
||||
int intf_get_locations(lua_State *L);
|
||||
int intf_get_villages(lua_State *L);
|
||||
int intf_match_location(lua_State *L);
|
||||
@ -165,6 +163,7 @@ class game_lua_kernel : public lua_kernel_base
|
||||
std::vector<int> get_sides_vector(const vconfig& cfg);
|
||||
|
||||
public:
|
||||
std::vector<team> & teams();
|
||||
game_lua_kernel(CVideo *, game_state &, play_controller &, reports &);
|
||||
|
||||
void set_game_display(game_display * gd);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include "tstring.hpp"
|
||||
#include "lua/lauxlib.h"
|
||||
#include "lua/lua.h"
|
||||
@ -199,7 +200,8 @@ namespace lua_check_impl
|
||||
typename boost::enable_if<
|
||||
typename boost::mpl::and_<
|
||||
typename is_container<T>::type,
|
||||
typename boost::mpl::not_<typename boost::is_same<T, std::string> >::type
|
||||
typename boost::mpl::not_<typename boost::is_same<T, std::string> >::type,
|
||||
typename boost::mpl::not_<typename is_map<T>::type >::type
|
||||
>::type,
|
||||
void
|
||||
>::type
|
||||
@ -212,6 +214,24 @@ namespace lua_check_impl
|
||||
lua_check_impl::lua_push<typename remove_constref<typename T::value_type>::type>(L, list[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//accepts std::map TODO: add a check function for that
|
||||
template<typename T>
|
||||
typename boost::enable_if<
|
||||
typename is_map<T>::type,
|
||||
void
|
||||
>::type
|
||||
lua_push(lua_State * L, const T& map )
|
||||
{
|
||||
lua_newtable(L);
|
||||
BOOST_FOREACH(const typename T::value_type& pair, map)
|
||||
{
|
||||
lua_check_impl::lua_push<typename remove_constref<typename T::key_type>::type>(L, pair.first);
|
||||
lua_check_impl::lua_push<typename remove_constref<typename T::mapped_type>::type>(L, pair.second);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user