The Battle for Wesnoth  1.15.2+dev
lua_team.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "scripting/lua_team.hpp"
16 
17 #include "scripting/lua_common.hpp"
18 #include "scripting/push_check.hpp"
20 #include "team.hpp"
21 #include "resources.hpp" // for gameboard
22 #include "game_board.hpp"
23 #include "game_display.hpp"
24 #include "map/map.hpp"
25 
26 #include <string>
27 
28 #include "lua/lua.h"
29 #include "lua/lauxlib.h"
30 
31 /**
32  * Implementation for a lua reference to a team,
33  * used by the wesnoth in-game sides table.
34  *
35  * (The userdata has type team** because lua holds
36  * only a pointer to a team, not a full-size team.
37  * If it were a full object then we would cast to
38  * type team *, since checkudata returns a pointer
39  * to the type corresponding to the sizeof expr
40  * used when we allocated the userdata.)
41  */
42 
43 // Registry key
44 static const char * Team = "side";
45 static const char teamVar[] = "side variables";
46 
47 /**
48  * Gets some data on a side (__index metamethod).
49  * - Arg 1: full userdata containing the team.
50  * - Arg 2: string containing the name of the property.
51  * - Ret 1: something containing the attribute.
52  */
53 static int impl_side_get(lua_State *L)
54 {
55  // Hidden metamethod, so arg1 has to be a pointer to a team.
56  team &t = luaW_checkteam(L, 1);
57  char const *m = luaL_checkstring(L, 2);
58 
59  // Find the corresponding attribute.
60  return_int_attrib("side", t.side());
61  return_string_attrib("save_id", t.save_id());
62  return_int_attrib("gold", t.gold());
63  return_tstring_attrib("objectives", t.objectives());
64  return_int_attrib("village_gold", t.village_gold());
65  return_int_attrib("village_support", t.village_support());
66  return_int_attrib("num_villages", t.villages().size());
67  return_int_attrib("recall_cost", t.recall_cost());
68  return_int_attrib("base_income", t.base_income());
69  return_int_attrib("total_income", t.total_income());
70  return_bool_attrib("objectives_changed", t.objectives_changed());
71  return_bool_attrib("fog", t.uses_fog());
72  return_bool_attrib("shroud", t.uses_shroud());
73  return_bool_attrib("hidden", t.hidden());
74  return_bool_attrib("scroll_to_leader", t.get_scroll_to_leader());
75  return_string_attrib("flag", t.flag().empty() ? game_config::images::flag : t.flag());
77  return_tstring_attrib("user_team_name", t.user_team_name());
78  return_string_attrib("team_name", t.team_name());
79  return_string_attrib("faction", t.faction());
80  return_tstring_attrib("faction_name", t.faction_name());
81  return_string_attrib("color", t.color());
82  return_cstring_attrib("controller", t.controller().to_string().c_str());
83  return_bool_attrib("is_local", t.is_local());
84  return_string_attrib("defeat_condition", t.defeat_condition().to_string());
85  return_string_attrib("share_vision", t.share_vision().to_string());
86  return_float_attrib("carryover_bonus", t.carryover_bonus());
87  return_int_attrib("carryover_percentage", t.carryover_percentage());
88  return_bool_attrib("carryover_add", t.carryover_add());
89  return_bool_attrib("lost", t.lost());
90  return_bool_attrib("persistent", t.persistent());
91  return_bool_attrib("suppress_end_turn_confirmation", t.no_turn_confirmation());
92  return_string_attrib("share_vision", t.share_vision().to_string());
93  return_bool_attrib("share_maps", t.share_maps());
94  return_bool_attrib("share_view", t.share_view());
95  return_bool_attrib("chose_random", t.chose_random());
96  return_tstring_attrib("side_name", t.side_name_tstr());
97 
98  if (strcmp(m, "recruit") == 0) {
99  const std::set<std::string>& recruits = t.recruits();
100  lua_createtable(L, recruits.size(), 0);
101  int i = 1;
102  for (const std::string& r : t.recruits()) {
103  lua_pushstring(L, r.c_str());
104  lua_rawseti(L, -2, i++);
105  }
106  return 1;
107  }
108  if(strcmp(m, "variables") == 0) {
109  lua_createtable(L, 1, 0);
110  lua_pushvalue(L, 1);
111  lua_rawseti(L, -2, 1);
113  return 1;
114  }
115  if(strcmp(m, "starting_location") == 0) {
116  const map_location& starting_pos = resources::gameboard->map().starting_position(t.side());
117  if(!resources::gameboard->map().on_board(starting_pos)) return 0;
118 
119  luaW_pushlocation(L, starting_pos);
120  return 1;
121  }
122 
123  // These are blocked together because they are all part of the team_data struct.
124  // Some of these values involve iterating over the units map to calculate them.
125  auto d = [&](){ return team_data(*resources::gameboard, t); };
126  return_int_attrib("num_units", d().units);
127  return_int_attrib("total_upkeep", d().upkeep);
128  return_int_attrib("expenses", d().expenses);
129  return_int_attrib("net_income", d().net_income);
130 
131  return_cfg_attrib("__cfg", t.write(cfg));
132  if(luaW_getglobal(L, "wesnoth", "sides", m)) {
133  return 1;
134  }
135  return 0;
136 }
137 
138 /**
139  * Turns a lua proxy side to string. (__tostring metamethod)
140  */
142 {
143  const team& team = luaW_checkteam(L, 1);
144  std::ostringstream str;
145 
146  str << "side: <" << team.side();
147  if(!team.side_name().empty()) {
148  str << " " << team.side_name();
149  }
150  str << '>';
151 
152  lua_push(L, str.str());
153  return 1;
154 }
155 
156 /**
157  * Sets some data on a side (__newindex metamethod).
158  * - Arg 1: full userdata containing the team.
159  * - Arg 2: string containing the name of the property.
160  * - Arg 3: something containing the attribute.
161  */
162 static int impl_side_set(lua_State *L)
163 {
164  // Hidden metamethod, so arg1 has to be a pointer to a team.
165  team &t = luaW_checkteam(L, 1);
166  char const *m = luaL_checkstring(L, 2);
167 
168  const auto& reinit_flag_for_team = [&L] (const team& t) -> void {
169  auto* disp = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).get_display();
170  if(disp) {
171  disp->reinit_flags_for_team(t);
172  }
173  };
174  // Find the corresponding attribute.
175  modify_int_attrib("gold", t.set_gold(value));
176  modify_tstring_attrib("objectives", t.set_objectives(value, true));
177  //maybe add a setter for save_id too?
178  modify_int_attrib("village_gold", t.set_village_gold(value));
179  modify_int_attrib("village_support", t.set_village_support(value));
180  modify_int_attrib("recall_cost", t.set_recall_cost(value));
181  modify_int_attrib("base_income", t.set_base_income(value));
182  modify_bool_attrib("objectives_changed", t.set_objectives_changed(value));
183  modify_bool_attrib("hidden", t.set_hidden(value));
184  modify_bool_attrib("scroll_to_leader", t.set_scroll_to_leader(value));
185  modify_string_attrib("flag", {
186  t.set_flag(value);
187  reinit_flag_for_team(t);
188  });
189  modify_string_attrib("flag_icon", t.set_flag_icon(value));
190  modify_tstring_attrib("user_team_name", t.change_team(t.team_name(), value));
191  modify_string_attrib("team_name", t.change_team(value, t.user_team_name()));
192  modify_string_attrib("controller", t.change_controller_by_wml(value));
193  modify_string_attrib("color", {
194  t.set_color(value);
195  reinit_flag_for_team(t);
196  });
197  modify_string_attrib("defeat_condition", t.set_defeat_condition_string(value));
198  modify_int_attrib("carryover_percentage", t.set_carryover_percentage(value));
199  modify_bool_attrib("carryover_add", t.set_carryover_add(value));
200  modify_bool_attrib("lost", t.set_lost(value));
201  modify_bool_attrib("persistent", t.set_persistent(value));
202  modify_bool_attrib("suppress_end_turn_confirmation", t.set_no_turn_confirmation(value));
203  modify_bool_attrib("shroud", t.set_shroud(value));
204  modify_bool_attrib("fog", t.set_fog(value));
205  modify_string_attrib("flag_icon", t.set_flag_icon(value));
206  modify_tstring_attrib("side_name", t.set_side_name(value));
207  modify_string_attrib("share_vision", {
208  team::SHARE_VISION v;
209  if(v.parse(value)) {
210  t.set_share_vision(v);
211  } else {
212  return luaL_argerror(L, 3, "Invalid share_vision value (should be 'all', 'none', or 'shroud')");
213  }
214  });
215 
216  if (strcmp(m, "carryover_bonus") == 0) {
217  t.set_carryover_bonus(luaL_checknumber(L, 3));
218  return 0;
219  }
220 
221  if (strcmp(m, "recruit") == 0) {
222  t.set_recruits(std::set<std::string>());
223  if (!lua_istable(L, 3)) return 0;
224  for (int i = 1;; ++i) {
225  lua_rawgeti(L, 3, i);
226  if (lua_isnil(L, -1)) break;
227  t.add_recruit(lua_tostring(L, -1));
228  lua_pop(L, 1);
229  }
230  return 0;
231  }
232 
233  std::string err_msg = "unknown modifiable property of side: ";
234  err_msg += m;
235  return luaL_argerror(L, 2, err_msg.c_str());
236 }
237 
238 static int impl_side_equal(lua_State *L)
239 {
240  // Hidden metamethod, so arg1 has to be a pointer to a team.
241  team &t1 = luaW_checkteam(L, 1);
242  if(team* t2 = luaW_toteam(L, 2)) {
243  lua_pushboolean(L, t1.side() == t2->side());
244  } else {
245  lua_pushboolean(L, false);
246  }
247  return 1;
248 }
249 
250 /**
251  * Gets the variable of a side (__index metamethod).
252  * - Arg 1: table containing the userdata containing the side id.
253  * - Arg 2: string containing the name of the status.
254  * - Ret 1: boolean.
255  */
256 static int impl_side_variables_get(lua_State *L)
257 {
258  if(!lua_istable(L, 1)) {
259  return luaW_type_error(L, 1, "side variables");
260  }
261  lua_rawgeti(L, 1, 1);
262  const team& side = luaW_checkteam(L, -1);
263 
264  char const *m = luaL_checkstring(L, 2);
265  return_cfgref_attrib("__cfg", side.variables());
266 
267  variable_access_const v(m, side.variables());
268  return luaW_pushvariable(L, v) ? 1 : 0;
269 }
270 
271 /**
272  * Sets the variable of a side (__newindex metamethod).
273  * - Arg 1: table containing the userdata containing the side id.
274  * - Arg 2: string containing the name of the status.
275  * - Arg 3: scalar.
276  */
277 static int impl_side_variables_set(lua_State *L)
278 {
279  if(!lua_istable(L, 1)) {
280  return luaW_type_error(L, 1, "side variables");
281  }
282  lua_rawgeti(L, 1, 1);
283  team& side = luaW_checkteam(L, -1);
284 
285  char const *m = luaL_checkstring(L, 2);
286  if(strcmp(m, "__cfg") == 0) {
287  side.variables() = luaW_checkconfig(L, 3);
288  return 0;
289  }
290  config& vars = side.variables();
291  if(lua_isnoneornil(L, 3)) {
292  try {
293  variable_access_throw(m, vars).clear(false);
294  } catch(const invalid_variablename_exception&) {
295  }
296  return 0;
297  }
298  variable_access_create v(m, vars);
299  luaW_checkvariable(L, v, 3);
300  return 0;
301 }
302 
303 namespace lua_team {
304 
305  std::string register_metatable(lua_State * L)
306  {
307  std::ostringstream cmd_out;
308 
309  cmd_out << "Adding getside metatable...\n";
310 
311  luaL_newmetatable(L, Team);
312 
313  static luaL_Reg const callbacks[] {
314  { "__index", &impl_side_get},
315  { "__newindex", &impl_side_set},
316  { "__eq", &impl_side_equal},
317  { "__tostring", &impl_side_tostring},
318  { nullptr, nullptr }
319  };
320  luaL_setfuncs(L, callbacks, 0);
321 
322  lua_pushstring(L, Team);
323  lua_setfield(L, -2, "__metatable");
324 
325  // Create the side variables metatable.
326  cmd_out << "Adding side variables metatable...\n";
327 
328  luaL_newmetatable(L, teamVar);
329  lua_pushcfunction(L, impl_side_variables_get);
330  lua_setfield(L, -2, "__index");
331  lua_pushcfunction(L, impl_side_variables_set);
332  lua_setfield(L, -2, "__newindex");
333  lua_pushstring(L, "side variables");
334  lua_setfield(L, -2, "__metatable");
335 
336  return cmd_out.str();
337  }
338 }
339 
340 void luaW_pushteam(lua_State *L, team & tm)
341 {
342  team** t = static_cast<team**>(lua_newuserdata(L, sizeof(team*)));
343  *t = &tm;
344  luaL_setmetatable(L, Team);
345 }
346 
347 team& luaW_checkteam(lua_State* L, int idx)
348 {
349  return **static_cast<team **>(luaL_checkudata(L, idx, Team));
350 }
351 
352 team* luaW_toteam(lua_State* L, int idx)
353 {
354  if(void* p = luaL_testudata(L, idx, Team)) {
355  return *static_cast<team **>(p);
356  }
357  return nullptr;
358 }
bool no_turn_confirmation() const
Definition: team.hpp:365
LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
Definition: lapi.cpp:684
#define return_tstring_attrib(name, accessor)
Definition: lua_common.hpp:201
team & luaW_checkteam(lua_State *L, int idx)
Test if the top stack element is a team, and if not, error.
Definition: lua_team.cpp:347
bool persistent() const
Definition: team.hpp:349
const std::string & side_name() const
Definition: team.hpp:308
t_string side_name_tstr() const
Definition: team.hpp:309
const std::string & flag() const
Definition: team.hpp:301
bool carryover_add() const
Definition: team.hpp:357
bool share_view() const
Definition: team.hpp:390
LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n)
Definition: lapi.cpp:817
bool objectives_changed() const
Definition: team.hpp:241
virtual const gamemap & map() const override
Definition: game_board.hpp:109
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:217
const std::string & save_id() const
Definition: team.hpp:231
#define d
LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:312
-file sdl_utils.hpp
double carryover_bonus() const
Definition: team.hpp:359
int village_support() const
Definition: team.hpp:199
const std::string & faction() const
Definition: team.hpp:311
static const char * Team
Implementation for a lua reference to a team, used by the wesnoth in-game sides table.
Definition: lua_team.cpp:44
std::string flag_icon
bool uses_fog() const
Definition: team.hpp:319
int gold() const
Definition: team.hpp:189
int village_gold() const
Definition: team.hpp:192
void write(config &cfg) const
Definition: team.cpp:405
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
SHARE_VISION share_vision() const
Definition: team.hpp:391
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:226
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...
Definition: lua_common.cpp:869
bool uses_shroud() const
Definition: team.hpp:318
int carryover_percentage() const
Definition: team.hpp:355
game_board * gameboard
Definition: resources.cpp:20
const t_string & faction_name() const
Definition: team.hpp:312
static const char teamVar[]
Definition: lua_team.cpp:45
bool chose_random() const
Definition: team.hpp:410
bool hidden() const
Definition: team.hpp:347
int recall_cost() const
Definition: team.hpp:193
Encapsulates the map of the game.
Definition: location.hpp:42
#define return_cfg_attrib(name, accessor)
Definition: lua_common.hpp:250
bool shroud()
Definition: game.cpp:573
std::size_t i
Definition: function.cpp:933
const std::string & flag_icon() const
Definition: team.hpp:302
const t_string & objectives() const
Definition: team.hpp:240
map_location starting_position(int side) const
Definition: map.cpp:331
DEFEAT_CONDITION defeat_condition() const
Definition: team.hpp:342
LUA_API void lua_pushvalue(lua_State *L, int idx)
Definition: lapi.cpp:237
bool is_local() const
Definition: team.hpp:261
static int impl_side_tostring(lua_State *L)
Turns a lua proxy side to string.
Definition: lua_team.cpp:141
bool get_scroll_to_leader() const
Definition: team.hpp:220
#define return_bool_attrib(name, accessor)
Definition: lua_common.hpp:242
const std::string & color() const
Definition: team.hpp:256
bool share_maps() const
Definition: team.hpp:389
double t
Definition: astarsearch.cpp:64
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.
Definition: lua_common.cpp:660
#define return_float_attrib(name, accessor)
Definition: lua_common.hpp:234
static int impl_side_get(lua_State *L)
Gets some data on a side (__index metamethod).
Definition: lua_team.cpp:53
int base_income() const
Definition: team.hpp:191
int side() const
Definition: team.hpp:188
int total_income() const
Definition: team.hpp:196
const std::set< map_location > & villages() const
Definition: team.hpp:184
LUA_API const char * lua_pushstring(lua_State *L, const char *s)
Definition: lapi.cpp:491
bool lost() const
Definition: team.hpp:352
const std::string & team_name() const
Definition: team.hpp:297
const t_string & user_team_name() const
Definition: team.hpp:298
const std::set< std::string > & recruits() const
Definition: team.hpp:223
#define return_cstring_attrib(name, accessor)
Definition: lua_common.hpp:209
#define luaL_checkstring(L, n)
Definition: lauxlib.h:124
CONTROLLER controller() const
Definition: team.hpp:255