The Battle for Wesnoth  1.19.7+dev
lua_unit_type.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
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 
19 #include "scripting/lua_common.hpp"
21 #include "scripting/push_check.hpp"
22 #include "units/types.hpp"
23 
24 #include <string>
25 #include <cstring>
26 
27 
28 /**
29  * Implementation for a lua reference to a unit_type.
30  */
31 
32 // Registry key
33 static const char UnitType[] = "unit type";
34 static const char UnitTypeTable[] = "unit types";
35 
36 #define UNIT_TYPE_GETTER(name, type) LATTR_GETTER(name, type, unit_type, ut)
37 #define UNIT_TYPE_VALID(name) LATTR_VALID(name, unit_type, ut)
39 
40 template<> struct lua_object_traits<unit_type> {
41  inline static auto metatable = UnitType;
42  inline static const unit_type& get(lua_State* L, int n) {
43  return luaW_checkunittype(L, n);
44  }
45 };
46 
48  return ut.type_name();
49 }
50 
51 UNIT_TYPE_GETTER("id", std::string) {
52  return ut.id();
53 }
54 
55 UNIT_TYPE_GETTER("alignment", std::string) {
56  return unit_alignments::get_string(ut.alignment());
57 }
58 
59 UNIT_TYPE_GETTER("race", std::string) {
60  return ut.race_id();
61 }
62 
63 UNIT_TYPE_GETTER("image", std::string) {
64  return ut.image();
65 }
66 
67 UNIT_TYPE_GETTER("icon", std::string) {
68  return ut.icon();
69 }
70 
71 UNIT_TYPE_GETTER("profile", std::string) {
72  return ut.big_profile();
73 }
74 
75 UNIT_TYPE_GETTER("small_profile", std::string) {
76  return ut.small_profile();
77 }
78 
79 UNIT_TYPE_GETTER("max_hitpoints", int) {
80  return ut.hitpoints();
81 }
82 
83 UNIT_TYPE_GETTER("max_moves", int) {
84  return ut.movement();
85 }
86 
87 UNIT_TYPE_GETTER("max_experience", int) {
88  return ut.experience_needed();
89 }
90 
91 UNIT_TYPE_GETTER("cost", int) {
92  return ut.cost();
93 }
94 
95 UNIT_TYPE_GETTER("level", int) {
96  return ut.level();
97 }
98 
99 UNIT_TYPE_GETTER("recall_cost", int) {
100  return ut.recall_cost();
101 }
102 
103 UNIT_TYPE_GETTER("advances_to", std::vector<std::string>) {
104  return ut.advances_to();
105 }
106 
107 UNIT_TYPE_GETTER("advances_from", std::vector<std::string>) {
108  return ut.advances_from();
109 }
110 
112  return ut.get_cfg();
113 }
114 
115 using traits_map = std::map<std::string,config>;
117  traits_map traits;
118  for (const config& trait : ut.possible_traits()) {
119  traits.emplace(trait["id"], trait);
120  }
121  return traits;
122 }
123 
124 UNIT_TYPE_GETTER("abilities", std::vector<std::string>) {
125  return ut.get_ability_list();
126 }
127 
129  (void)ut;
131  return lua_index_raw(L);
132 }
133 
134 UNIT_TYPE_VALID("variations") {
135  return ut.variation_id().empty();
136 }
137 
139  // TODO: Should this only exist for base units?
140  *new(L) const unit_type* = &ut;
141  luaL_setmetatable(L, UnitTypeTable);
142  return lua_index_raw(L);
143 }
144 
145 /**
146  * Gets some data on a unit type (__index metamethod).
147  * - Arg 1: table containing an "id" field.
148  * - Arg 2: string containing the name of the property.
149  * - Ret 1: something containing the attribute.
150  */
151 static int impl_unit_type_get(lua_State *L)
152 {
153  return unitTypeReg.get(L);
154 }
155 
156 /**
157  * Gets a list of data on a unit type (__dir metamethod).
158  * - Ret 1: a list of attributes.
159  */
160 static int impl_unit_type_dir(lua_State *L)
161 {
162  return unitTypeReg.dir(L);
163 }
164 
165 static int impl_unit_type_equal(lua_State* L)
166 {
167  const unit_type& ut1 = luaW_checkunittype(L, 1);
168  if(const unit_type* ut2 = luaW_tounittype(L, 2)) {
169  lua_pushboolean(L, &ut1 == ut2);
170  } else {
171  lua_pushboolean(L, false);
172  }
173  return 1;
174 }
175 
176 static int impl_unit_type_list(lua_State* L) {
177  std::vector<std::string> keys;
178  if(const unit_type* base = *static_cast<const unit_type**>(luaL_testudata(L, 1, UnitTypeTable))) {
179  keys = base->variations();
180  if(base->has_gender_variation(unit_race::MALE)) {
181  keys.push_back("male");
182  }
183  if(base->has_gender_variation(unit_race::FEMALE)) {
184  keys.push_back("female");
185  }
186  } else {
187  keys.reserve(unit_types.types().size());
188  for(const auto& p : unit_types.types()) {
189  keys.push_back(p.first);
190  }
191  }
192  lua_push(L, keys);
193  return 1;
194 }
195 
196 static int impl_unit_type_lookup(lua_State* L)
197 {
198  std::string id = luaL_checkstring(L, 2);
199  const unit_type* ut;
200  if(const unit_type* base = *static_cast<const unit_type**>(luaL_testudata(L, 1, UnitTypeTable))) {
201  if(id == "male" || id == "female") {
202  ut = &base->get_gender_unit_type(id);
203  } else {
204  ut = &base->get_variation(id);
205  }
206  } else {
207  ut = unit_types.find(id);
208  }
209  if(ut) {
210  luaW_pushunittype(L, *ut);
211  return 1;
212  }
213  return 0;
214 }
215 
216 static int impl_unit_type_new(lua_State* L)
217 {
218  // This could someday become a hook to construct new unit types on the fly?
219  // For now though, it's just an error
220  lua_pushstring(L, "unit_types table is read-only");
221  return lua_error(L);
222 }
223 
224 static int impl_unit_type_count(lua_State* L)
225 {
226  lua_pushnumber(L, unit_types.types().size());
227  return 1;
228 }
229 
230 static int impl_unit_type_next(lua_State* L)
231 {
232  const unit_type* base = *static_cast<const unit_type**>(luaL_checkudata(L, 1, UnitTypeTable));
233  const auto& unit_map = base ? base->variation_types() : unit_types.types();
234  auto it = unit_map.end();
235  if(lua_isnoneornil(L, 2)) {
236  if(base) {
238  lua_pushstring(L, "male");
240  return 2;
241  } else if(base->has_gender_variation(unit_race::FEMALE)) {
242  lua_pushstring(L, "female");
244  return 2;
245  }
246  }
247  it = unit_map.begin();
248  } else {
249  const std::string id = luaL_checkstring(L, 2);
250  if(base) {
251  if(id == "male" && base->has_gender_variation(unit_race::FEMALE)) {
252  lua_pushstring(L, "female");
254  return 2;
255  } else if(id == "male" || id == "female") {
256  it = unit_map.begin();
257  }
258  }
259  if(it == unit_map.end()) {
260  it = unit_map.find(id);
261  }
262  if(it == unit_map.end()) {
263  return 0;
264  }
265  ++it;
266  }
267  if (it == unit_map.end()) {
268  return 0;
269  }
270  lua_pushlstring(L, it->first.c_str(), it->first.size());
271  luaW_pushunittype(L, it->second);
272  if(!base) {
273  // Make sure the unit is built.
275  }
276  return 2;
277 }
278 
279 static int impl_unit_type_pairs(lua_State* L) {
280  lua_pushcfunction(L, &impl_unit_type_next);
281  lua_pushvalue(L, -2);
282  lua_pushnil(L);
283  return 3;
284 }
285 
286 /**
287  * Turns a lua proxy unit type to string. (__tostring metamethod)
288  */
289 static int impl_unit_type_tostring(lua_State* L)
290 {
291  const unit_type& ut = luaW_checkunittype(L, 1);
292  std::ostringstream str;
293 
294  str << "unit type: <" << ut.id() << '>';
295 
296  lua_push(L, str.str());
297  return 1;
298 }
299 
300 namespace lua_unit_type {
301  std::string register_metatable(lua_State * L)
302  {
303  luaL_newmetatable(L, UnitType);
304 
305  lua_pushcfunction(L, impl_unit_type_get);
306  lua_setfield(L, -2, "__index");
307  lua_pushcfunction(L, impl_unit_type_dir);
308  lua_setfield(L, -2, "__dir");
309  lua_pushcfunction(L, impl_unit_type_tostring);
310  lua_setfield(L, -2, "__tostring");
311  lua_pushcfunction(L, impl_unit_type_equal);
312  lua_setfield(L, -2, "__eq");
313  lua_pushstring(L, UnitType);
314  lua_setfield(L, -2, "__metatable");
315 
316  return "Adding unit type metatable...\n";
317  }
318 
319  std::string register_table(lua_State* L)
320  {
321  lua_getglobal(L, "wesnoth");
322  *new(L) unit_type* = nullptr;
323  luaL_newmetatable(L, UnitTypeTable);
324  lua_pushcfunction(L, impl_unit_type_lookup);
325  lua_setfield(L, -2, "__index");
326  lua_pushcfunction(L, impl_unit_type_list);
327  lua_setfield(L, -2, "__dir");
328  lua_pushcfunction(L, impl_unit_type_new);
329  lua_setfield(L, -2, "__newindex");
330  lua_pushcfunction(L, impl_unit_type_count);
331  lua_setfield(L, -2, "__len");
332  lua_pushcfunction(L, impl_unit_type_pairs);
333  lua_setfield(L, -2, "__pairs");
334  lua_pushstring(L, UnitTypeTable);
335  lua_setfield(L, -2, "__metatable");
336  lua_setmetatable(L, -2);
337  lua_setfield(L, -2, "unit_types");
338  lua_pop(L, 1);
339 
340  return "Adding unit_types table...\n";
341  }
342 }
343 
344 void luaW_pushunittype(lua_State *L, const unit_type& ut)
345 {
346  *static_cast<const unit_type**>(lua_newuserdatauv(L, sizeof(unit_type*), 0)) = &ut;
347  luaL_setmetatable(L, UnitType);
348 }
349 
350 const unit_type* luaW_tounittype(lua_State* L, int idx)
351 {
352  if(void* p = luaL_testudata(L, idx, UnitType)) {
353  return *static_cast<const unit_type**>(p);
354  }
355  return nullptr;
356 }
357 
358 const unit_type& luaW_checkunittype(lua_State* L, int idx)
359 {
360  return **static_cast<const unit_type**>(luaL_checkudata(L, idx, UnitType));
361 }
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
unit_iterator find(std::size_t id)
Definition: map.cpp:302
unit_iterator begin()
Definition: map.hpp:418
@ FEMALE
Definition: race.hpp:28
@ MALE
Definition: race.hpp:28
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1265
void build_unit_type(const unit_type &ut, unit_type::BUILD_STATUS status) const
Makes sure the provided unit_type is built to the specified level.
Definition: types.cpp:1257
const unit_type_map & types() const
Definition: types.hpp:396
A single unit type that the player may recruit.
Definition: types.hpp:43
const unit_type & get_gender_unit_type(const std::string &gender) const
Returns a gendered variant of this unit_type.
Definition: types.cpp:455
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:141
const unit_type & get_variation(const std::string &id) const
Definition: types.cpp:476
const variations_map & variation_types() const
Definition: types.hpp:256
bool has_gender_variation(const unit_race::GENDER gender) const
Definition: types.hpp:250
@ FULL
Definition: types.hpp:74
void push_unit_attacks_table(lua_State *L, int idx)
static int impl_unit_type_lookup(lua_State *L)
static int impl_unit_type_tostring(lua_State *L)
Turns a lua proxy unit type to string.
std::map< std::string, config > traits_map
static int impl_unit_type_next(lua_State *L)
#define UNIT_TYPE_VALID(name)
static int impl_unit_type_dir(lua_State *L)
Gets a list of data on a unit type (__dir metamethod).
const unit_type * luaW_tounittype(lua_State *L, int idx)
Test if a stack element is a unit type, and return it if so.
static int impl_unit_type_new(lua_State *L)
static int impl_unit_type_get(lua_State *L)
Gets some data on a unit type (__index metamethod).
static int impl_unit_type_equal(lua_State *L)
const unit_type & luaW_checkunittype(lua_State *L, int idx)
Test if a stack element is a unit type, and return it if so.
static const char UnitType[]
Implementation for a lua reference to a unit_type.
#define UNIT_TYPE_GETTER(name, type)
static int impl_unit_type_count(lua_State *L)
static int impl_unit_type_list(lua_State *L)
void luaW_pushunittype(lua_State *L, const unit_type &ut)
Create a lua object containing a reference to a unittype, and a metatable to access the properties.
static const char UnitTypeTable[]
luaW_Registry unitTypeReg
static int impl_unit_type_pairs(lua_State *L)
This namespace contains bindings for lua to hold a reference to a unit type and access its stats.
std::string register_metatable(lua_State *L)
std::string register_table(lua_State *L)
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int get(lua_State *L)
Implement __index metamethod.
static const unit_type & get(lua_State *L, int n)
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
mock_party p
static map_location::direction n
unit_type_data unit_types
Definition: types.cpp:1500