The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
lua_team.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
3 by Chris Beck <render787@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
17
22#include "team.hpp"
23#include "resources.hpp" // for gameboard
24#include "game_board.hpp"
25#include "game_display.hpp"
26#include "map/map.hpp"
27
28#include <string>
29
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
44static const char * Team = "side";
45static const char teamVar[] = "side variables";
46
47#define SIDE_GETTER(name, type) LATTR_GETTER(name, type, team, t)
48#define SIDE_SETTER(name, type) LATTR_SETTER(name, type, team, t)
49luaW_Registry sideReg{"wesnoth", "sides", Team};
50
51template<> struct lua_object_traits<team> {
52 inline static auto metatable = Team;
53 inline static team& get(lua_State* L, int n) {
54 return luaW_checkteam(L, n);
55 }
56};
57
58SIDE_GETTER("side", int) {
59 return t.side();
60}
61
62SIDE_GETTER("save_id", std::string) {
63 return t.save_id();
64}
65//maybe add a setter for save_id too?
66
67SIDE_GETTER("gold", int) {
68 return t.gold();
69}
70
71// allow setting gold from calculations without the need for manual conversion to int
72SIDE_SETTER("gold", double) {
73 t.set_gold(static_cast<int>(value));
74}
75
76SIDE_GETTER("objectives", t_string) {
77 return t.objectives();
78}
79
80SIDE_SETTER("objectives", t_string) {
81 t.set_objectives(value, true);
82}
83
84SIDE_GETTER("village_gold", int) {
85 return t.village_gold();
86}
87
88SIDE_SETTER("village_gold", int) {
89 t.set_village_gold(value);
90}
91
92SIDE_GETTER("village_support", int) {
93 return t.village_support();
94}
95
96SIDE_SETTER("village_support", int) {
97 t.set_village_support(value);
98}
99
100SIDE_GETTER("num_villages", int) {
101 return t.villages().size();
102}
103
104SIDE_GETTER("recall_cost", int) {
105 return t.recall_cost();
106}
107
108SIDE_SETTER("recall_cost", int) {
109 t.set_recall_cost(value);
110}
111
112SIDE_GETTER("base_income", int) {
113 return t.base_income();
114}
115
116SIDE_SETTER("base_income", int) {
117 t.set_base_income(value);
118}
119
120SIDE_GETTER("total_income", int) {
121 return t.total_income();
122}
123
124SIDE_GETTER("objectives_changed", bool) {
125 return t.objectives_changed();
126}
127
128SIDE_SETTER("objectives_changed", bool) {
129 t.set_objectives_changed(value);
130}
131
132SIDE_GETTER("fog", bool) {
133 return t.uses_fog();
134}
135
136SIDE_SETTER("fog", bool) {
137 t.set_fog(value);
138}
139
140SIDE_GETTER("shroud", bool) {
141 return t.uses_shroud();
142}
143
144SIDE_SETTER("shroud", bool) {
145 t.set_shroud(value);
146}
147
148SIDE_GETTER("hidden", bool) {
149 return t.hidden();
150}
151
152SIDE_SETTER("hidden", bool) {
153 t.set_hidden(value);
154}
155
156SIDE_GETTER("scroll_to_leader", bool) {
157 return t.get_scroll_to_leader();
158}
159
160SIDE_SETTER("scroll_to_leader", bool) {
161 t.set_scroll_to_leader(value);
162}
163
164static void reinit_flag_for_team(const team& t) {
165 if(auto disp = game_display::get_singleton()) {
166 disp->reinit_flags_for_team(t);
167 }
168}
169
170SIDE_GETTER("color", std::string) {
171 return t.color();
172}
173
174SIDE_SETTER("color", std::string) {
175 t.set_color(value);
177}
178
179SIDE_GETTER("flag", std::string) {
180 return t.flag().empty() ? game_config::images::flag : t.flag();
181}
182
183SIDE_SETTER("flag", std::string) {
184 t.set_flag(value);
186}
187
188SIDE_GETTER("flag_icon", std::string) {
189 return t.flag_icon().empty() ? game_config::images::flag_icon : t.flag_icon();
190}
191
192SIDE_SETTER("flag_icon", std::string) {
193 t.set_flag_icon(value);
194}
195
196SIDE_GETTER("user_team_name", t_string) {
197 return t.user_team_name();
198}
199
200SIDE_SETTER("user_team_name", t_string) {
201 t.change_team(t.team_name(), value);
202}
203
204SIDE_GETTER("team_name", std::string) {
205 return t.team_name();
206}
207
208SIDE_SETTER("team_name", std::string) {
209 t.change_team(value, t.user_team_name());
210}
211
212SIDE_GETTER("faction", std::string) {
213 return t.faction();
214}
215
216SIDE_GETTER("faction_name", t_string) {
217 return t.faction_name();
218}
219
220SIDE_GETTER("controller", std::string) {
221 return side_controller::get_string(t.controller());
222}
223
224SIDE_SETTER("controller", std::string) {
225 t.change_controller_by_wml(value);
226}
227
228SIDE_GETTER("is_local", bool) {
229 return t.is_local();
230}
231
232SIDE_GETTER("defeat_condition", std::string) {
233 return defeat_condition::get_string(t.defeat_cond());
234}
235
236SIDE_SETTER("defeat_condition", std::string) {
237 t.set_defeat_condition_string(value);
238}
239
240SIDE_GETTER("share_vision", std::string) {
241 return team_shared_vision::get_string(t.share_vision());
242}
243
244SIDE_SETTER("share_vision", std::string) {
246 if(v) {
247 t.set_share_vision(*v);
248 } else {
249 throw luaL_argerror(L, 3, "Invalid share_vision value (should be 'all', 'none', or 'shroud')");
250 }
251}
252
253SIDE_GETTER("carryover_bonus", double) {
254 return t.carryover_bonus();
255}
256
257SIDE_SETTER("carryover_bonus", double) {
258 t.set_carryover_bonus(value);
259}
260
261SIDE_GETTER("carryover_percentage", int) {
262 return t.carryover_percentage();
263}
264
265SIDE_SETTER("carryover_percentage", int) {
266 t.set_carryover_percentage(value);
267}
268
269SIDE_GETTER("carryover_gold", int) {
270 return t.carryover_gold();
271}
272
273SIDE_SETTER("carryover_gold", int) {
274 t.set_carryover_gold(value);
275}
276
277SIDE_GETTER("carryover_add", bool) {
278 return t.carryover_add();
279}
280
281SIDE_SETTER("carryover_add", bool) {
282 t.set_carryover_add(value);
283}
284
285SIDE_GETTER("lost", bool) {
286 return t.lost();
287}
288
289SIDE_SETTER("lost", bool) {
290 t.set_lost(value);
291}
292
293SIDE_GETTER("persistent", bool) {
294 return t.persistent();
295}
296
297SIDE_SETTER("persistent", bool) {
298 t.set_persistent(value);
299}
300
301SIDE_GETTER("suppress_end_turn_confirmation", bool) {
302 return t.no_turn_confirmation();
303}
304
305SIDE_SETTER("suppress_end_turn_confirmation", bool) {
306 t.set_no_turn_confirmation(value);
307}
308
309SIDE_GETTER("share_maps", bool) {
310 return t.share_maps();
311}
312
313SIDE_GETTER("share_view", bool) {
314 return t.share_view();
315}
316
317SIDE_GETTER("chose_random", bool) {
318 return t.chose_random();
319}
320
321SIDE_GETTER("side_name", t_string) {
322 return t.side_name_tstr();
323}
324
325SIDE_SETTER("side_name", t_string) {
326 t.set_side_name(value);
327}
328
329SIDE_GETTER("shroud_data", std::string) {
330 return t.shroud_data();
331}
332
333SIDE_SETTER("shroud_data", std::string) {
334 t.reshroud();
335 t.merge_shroud_map_data(value);
336}
337
338SIDE_GETTER("recruit", std::set<std::string>) {
339 return t.recruits();
340}
341
342SIDE_SETTER("recruit", std::set<std::string>) {
343 t.set_recruits(value);
344}
345
347 (void)t;
348 lua_createtable(L, 1, 0);
349 lua_pushvalue(L, 1);
350 lua_rawseti(L, -2, 1);
351 luaL_setmetatable(L, teamVar);
352 return lua_index_raw(L);
353}
354
355SIDE_GETTER("starting_location", utils::optional<map_location>) {
356 const map_location& starting_pos = resources::gameboard->map().starting_position(t.side());
357 if(!resources::gameboard->map().on_board(starting_pos)) return utils::nullopt;
358 return starting_pos;
359}
360
361SIDE_GETTER("num_units", int) {
363}
364
365SIDE_GETTER("total_upkeep", int) {
367}
368
369SIDE_GETTER("expenses", int) {
371}
372
373SIDE_GETTER("net_income", int) {
375}
376
378 config cfg;
379 t.write(cfg);
380 return cfg;
381}
382
383/**
384 * Gets some data on a side (__index metamethod).
385 * - Arg 1: full userdata containing the team.
386 * - Arg 2: string containing the name of the property.
387 * - Ret 1: something containing the attribute.
388 */
389static int impl_side_get(lua_State *L)
390{
391 return sideReg.get(L);
392}
393
394/**
395 * Gets a list of data on a side (__dir metamethod).
396 * - Arg 1: full userdata containing the team.
397 * - Ret 1: a list of attributes.
398 */
399static int impl_side_dir(lua_State *L)
400{
401 return sideReg.dir(L);
402}
403
404/**
405 * Turns a lua proxy side to string. (__tostring metamethod)
406 */
407static int impl_side_tostring(lua_State* L)
408{
409 const team& team = luaW_checkteam(L, 1);
410 std::ostringstream str;
411
412 str << "side: <" << team.side();
413 if(!team.side_name().empty()) {
414 str << " " << team.side_name();
415 }
416 str << '>';
417
418 lua_push(L, str.str());
419 return 1;
420}
421
422/**
423 * Sets some data on a side (__newindex metamethod).
424 * - Arg 1: full userdata containing the team.
425 * - Arg 2: string containing the name of the property.
426 * - Arg 3: something containing the attribute.
427 */
428static int impl_side_set(lua_State *L)
429{
430 return sideReg.set(L);
431}
432
433static int impl_side_equal(lua_State *L)
434{
435 // Hidden metamethod, so arg1 has to be a pointer to a team.
436 team &t1 = luaW_checkteam(L, 1);
437 if(team* t2 = luaW_toteam(L, 2)) {
438 lua_pushboolean(L, t1.side() == t2->side());
439 } else {
440 lua_pushboolean(L, false);
441 }
442 return 1;
443}
444
445/**
446 * Gets the variable of a side (__index metamethod).
447 * - Arg 1: table containing the userdata containing the side id.
448 * - Arg 2: string containing the name of the status.
449 * - Ret 1: boolean.
450 */
451static int impl_side_variables_get(lua_State *L)
452{
453 if(!lua_istable(L, 1)) {
454 return luaW_type_error(L, 1, "side variables");
455 }
456 lua_rawgeti(L, 1, 1);
457 const team& side = luaW_checkteam(L, -1);
458
459 char const *m = luaL_checkstring(L, 2);
460 return_cfgref_attrib("__cfg", side.variables());
461
462 variable_access_const v(m, side.variables());
463 return luaW_pushvariable(L, v) ? 1 : 0;
464}
465
466/**
467 * Sets the variable of a side (__newindex metamethod).
468 * - Arg 1: table containing the userdata containing the side id.
469 * - Arg 2: string containing the name of the status.
470 * - Arg 3: scalar.
471 */
472static int impl_side_variables_set(lua_State *L)
473{
474 if(!lua_istable(L, 1)) {
475 return luaW_type_error(L, 1, "side variables");
476 }
477 lua_rawgeti(L, 1, 1);
478 team& side = luaW_checkteam(L, -1);
479
480 char const *m = luaL_checkstring(L, 2);
481 if(strcmp(m, "__cfg") == 0) {
482 side.variables() = luaW_checkconfig(L, 3);
483 return 0;
484 }
485 config& vars = side.variables();
486 if(lua_isnoneornil(L, 3)) {
487 try {
488 variable_access_throw(m, vars).clear(false);
489 } catch(const invalid_variablename_exception&) {
490 }
491 return 0;
492 }
493 variable_access_create v(m, vars);
494 luaW_checkvariable(L, v, 3);
495 return 0;
496}
497
498namespace lua_team {
499
500 std::string register_metatable(lua_State * L)
501 {
502 std::ostringstream cmd_out;
503
504 cmd_out << "Adding getside metatable...\n";
505
506 luaL_newmetatable(L, Team);
507
508 static luaL_Reg const callbacks[] {
509 { "__index", &impl_side_get},
510 { "__newindex", &impl_side_set},
511 { "__dir", &impl_side_dir},
512 { "__eq", &impl_side_equal},
513 { "__tostring", &impl_side_tostring},
514 { nullptr, nullptr }
515 };
516 luaL_setfuncs(L, callbacks, 0);
517
518 lua_pushstring(L, Team);
519 lua_setfield(L, -2, "__metatable");
520
521 // Create the side variables metatable.
522 cmd_out << "Adding side variables metatable...\n";
523
524 luaL_newmetatable(L, teamVar);
525 lua_pushcfunction(L, impl_side_variables_get);
526 lua_setfield(L, -2, "__index");
527 lua_pushcfunction(L, impl_side_variables_set);
528 lua_setfield(L, -2, "__newindex");
529 lua_pushstring(L, "side variables");
530 lua_setfield(L, -2, "__metatable");
531
532 return cmd_out.str();
533 }
534}
535
536void luaW_pushteam(lua_State *L, team & tm)
537{
538 team** t = static_cast<team**>(lua_newuserdatauv(L, sizeof(team*), 0));
539 *t = &tm;
540 luaL_setmetatable(L, Team);
541}
542
543team& luaW_checkteam(lua_State* L, int idx)
544{
545 return **static_cast<team **>(luaL_checkudata(L, idx, Team));
546}
547
548team& luaW_checkteam(lua_State* L, int idx, game_board& board)
549{
550 if(lua_isinteger(L, idx)) {
551 int side = lua_tointeger(L, idx);
552 if(!board.has_team(side)) {
553 std::string error = "side " + std::to_string(side) + " does not exist";
554 luaL_argerror(L, 1, error.c_str());
555 // Unreachable
556 }
557 return board.get_team(side);
558 }
559 return **static_cast<team **>(luaL_checkudata(L, idx, Team));
560}
561
562team* luaW_toteam(lua_State* L, int idx)
563{
564 if(void* p = luaL_testudata(L, idx, Team)) {
565 return *static_cast<team **>(p);
566 }
567 return nullptr;
568}
double t
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
void clear()
Definition config.cpp:802
bool has_team(int side) const
Game board class.
virtual const gamemap & map() const override
team & get_team(int i)
static game_display * get_singleton()
map_location starting_position(int side) const
Definition map.cpp:286
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
const std::string & side_name() const
Definition team.hpp:334
int side() const
Definition team.hpp:182
config & variables()
Definition team.hpp:390
Additional functionality for a non-const variable_info.
Information on a WML variable.
const config * cfg
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
#define return_cfgref_attrib(name, accessor)
static int impl_side_set(lua_State *L)
Sets some data on a side (__newindex metamethod).
Definition lua_team.cpp:428
team * luaW_toteam(lua_State *L, int idx)
Test if the top stack element is a team, and if so, return it.
Definition lua_team.cpp:562
static int impl_side_variables_set(lua_State *L)
Sets the variable of a side (__newindex metamethod).
Definition lua_team.cpp:472
void luaW_pushteam(lua_State *L, team &tm)
Create a full userdata containing a pointer to the team.
Definition lua_team.cpp:536
static int impl_side_get(lua_State *L)
Gets some data on a side (__index metamethod).
Definition lua_team.cpp:389
#define SIDE_SETTER(name, type)
Definition lua_team.cpp:48
static int impl_side_variables_get(lua_State *L)
Gets the variable of a side (__index metamethod).
Definition lua_team.cpp:451
static const char teamVar[]
Definition lua_team.cpp:45
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
static int impl_side_equal(lua_State *L)
Definition lua_team.cpp:433
#define SIDE_GETTER(name, type)
Definition lua_team.cpp:47
static int impl_side_tostring(lua_State *L)
Turns a lua proxy side to string.
Definition lua_team.cpp:407
luaW_Registry sideReg
Definition lua_team.cpp:49
static void reinit_flag_for_team(const team &t)
Definition lua_team.cpp:164
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:543
static int impl_side_dir(lua_State *L)
Gets a list of data on a side (__dir metamethod).
Definition lua_team.cpp:399
This namespace contains bindings for lua to hold a pointer to a team, and to access and modify it.
Definition lua_team.cpp:498
std::string register_metatable(lua_State *L)
Definition lua_team.cpp:500
game_board * gameboard
Definition resources.cpp:20
void lua_push(lua_State *L, const T &val)
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
static team & get(lua_State *L, int n)
Definition lua_team.cpp:53
Encapsulates the map of the game.
Definition location.hpp:46
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition enum_base.hpp:46
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition enum_base.hpp:57
mock_party p
static map_location::direction n
variable_info_mutable< variable_info_implementation::vi_policy_throw > variable_access_throw
'Throw if nonexistent' access.