The Battle for Wesnoth  1.19.0-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 
18 #include "scripting/lua_common.hpp"
20 #include "scripting/push_check.hpp"
21 #include "units/types.hpp"
22 
23 #include <string>
24 #include <cstring>
25 
26 
27 /**
28  * Implementation for a lua reference to a unit_type.
29  */
30 
31 // Registry key
32 static const char UnitType[] = "unit type";
33 static const char UnitTypeTable[] = "unit types";
34 
35 /**
36  * Gets some data on a unit type (__index metamethod).
37  * - Arg 1: table containing an "id" field.
38  * - Arg 2: string containing the name of the property.
39  * - Ret 1: something containing the attribute.
40  */
41 static int impl_unit_type_get(lua_State *L)
42 {
43  const unit_type& ut = luaW_checkunittype(L, 1);
44  char const *m = luaL_checkstring(L, 2);
45 
46  // Find the corresponding attribute.
47  return_tstring_attrib("name", ut.type_name());
48  return_string_attrib("id", ut.id());
50  return_string_attrib("race", ut.race_id());
51  return_string_attrib("image", ut.image());
52  return_string_attrib("icon", ut.icon());
53  return_string_attrib("profile", ut.big_profile());
54  return_string_attrib("small_profile", ut.small_profile());
55  return_int_attrib("max_hitpoints", ut.hitpoints());
56  return_int_attrib("max_moves", ut.movement());
57  return_int_attrib("max_experience", ut.experience_needed());
58  return_int_attrib("cost", ut.cost());
59  return_int_attrib("level", ut.level());
60  return_int_attrib("recall_cost", ut.recall_cost());
61  return_vector_string_attrib("advances_to", ut.advances_to());
62  return_vector_string_attrib("advances_from", ut.advances_from());
63  return_cfgref_attrib("__cfg", ut.get_cfg());
64  if (strcmp(m, "traits") == 0) {
65  lua_newtable(L);
66  for (const config& trait : ut.possible_traits()) {
67  const std::string& id = trait["id"];
68  lua_pushlstring(L, id.c_str(), id.length());
69  luaW_pushconfig(L, trait);
70  lua_rawset(L, -3);
71  }
72  return 1;
73  }
74  if (strcmp(m, "abilities") == 0) {
75  lua_push(L, ut.get_ability_list());
76  return 1;
77  }
78  if (strcmp(m, "attacks") == 0) {
80  return 1;
81  }
82  // TODO: Should this only exist for base units?
83  if(strcmp(m, "variations") == 0) {
84  *new(L) const unit_type* = &ut;
85  luaL_setmetatable(L, UnitTypeTable);
86  return 1;
87  }
88  return 0;
89 }
90 
91 static int impl_unit_type_equal(lua_State* L)
92 {
93  const unit_type& ut1 = luaW_checkunittype(L, 1);
94  if(const unit_type* ut2 = luaW_tounittype(L, 2)) {
95  lua_pushboolean(L, &ut1 == ut2);
96  } else {
97  lua_pushboolean(L, false);
98  }
99  return 1;
100 }
101 
102 static int impl_unit_type_lookup(lua_State* L)
103 {
104  std::string id = luaL_checkstring(L, 2);
105  const unit_type* ut;
106  if(const unit_type* base = *static_cast<const unit_type**>(luaL_testudata(L, 1, UnitTypeTable))) {
107  if(id == "male" || id == "female") {
108  ut = &base->get_gender_unit_type(id);
109  } else {
110  ut = &base->get_variation(id);
111  }
112  } else {
113  ut = unit_types.find(id);
114  }
115  if(ut) {
116  luaW_pushunittype(L, *ut);
117  return 1;
118  }
119  return 0;
120 }
121 
122 static int impl_unit_type_new(lua_State* L)
123 {
124  // This could someday become a hook to construct new unit types on the fly?
125  // For now though, it's just an error
126  lua_pushstring(L, "unit_types table is read-only");
127  return lua_error(L);
128 }
129 
130 static int impl_unit_type_count(lua_State* L)
131 {
132  lua_pushnumber(L, unit_types.types().size());
133  return 1;
134 }
135 
136 static int impl_unit_type_next(lua_State* L)
137 {
138  const unit_type* base = *static_cast<const unit_type**>(luaL_checkudata(L, 1, UnitTypeTable));
139  const auto& unit_map = base ? base->variation_types() : unit_types.types();
140  auto it = unit_map.end();
141  if(lua_isnoneornil(L, 2)) {
142  if(base) {
144  lua_pushstring(L, "male");
146  return 2;
147  } else if(base->has_gender_variation(unit_race::FEMALE)) {
148  lua_pushstring(L, "female");
150  return 2;
151  }
152  }
153  it = unit_map.begin();
154  } else {
155  const std::string id = luaL_checkstring(L, 2);
156  if(base) {
157  if(id == "male" && base->has_gender_variation(unit_race::FEMALE)) {
158  lua_pushstring(L, "female");
160  return 2;
161  } else if(id == "male" || id == "female") {
162  it = unit_map.begin();
163  }
164  }
165  if(it == unit_map.end()) {
166  it = unit_map.find(id);
167  }
168  if(it == unit_map.end()) {
169  return 0;
170  }
171  ++it;
172  }
173  if (it == unit_map.end()) {
174  return 0;
175  }
176  lua_pushlstring(L, it->first.c_str(), it->first.size());
177  luaW_pushunittype(L, it->second);
178  if(!base) {
179  // Make sure the unit is built.
181  }
182  return 2;
183 }
184 
185 static int impl_unit_type_pairs(lua_State* L) {
186  lua_pushcfunction(L, &impl_unit_type_next);
187  lua_pushvalue(L, -2);
188  lua_pushnil(L);
189  return 3;
190 }
191 
192 /**
193  * Turns a lua proxy unit type to string. (__tostring metamethod)
194  */
195 static int impl_unit_type_tostring(lua_State* L)
196 {
197  const unit_type& ut = luaW_checkunittype(L, 1);
198  std::ostringstream str;
199 
200  str << "unit type: <" << ut.id() << '>';
201 
202  lua_push(L, str.str());
203  return 1;
204 }
205 
206 namespace lua_unit_type {
207  std::string register_metatable(lua_State * L)
208  {
209  luaL_newmetatable(L, UnitType);
210 
211  lua_pushcfunction(L, impl_unit_type_get);
212  lua_setfield(L, -2, "__index");
213  lua_pushcfunction(L, impl_unit_type_tostring);
214  lua_setfield(L, -2, "__tostring");
215  lua_pushcfunction(L, impl_unit_type_equal);
216  lua_setfield(L, -2, "__eq");
217  lua_pushstring(L, UnitType);
218  lua_setfield(L, -2, "__metatable");
219 
220  return "Adding unit type metatable...\n";
221  }
222 
223  std::string register_table(lua_State* L)
224  {
225  lua_getglobal(L, "wesnoth");
226  *new(L) unit_type* = nullptr;
227  luaL_newmetatable(L, UnitTypeTable);
228  lua_pushcfunction(L, impl_unit_type_lookup);
229  lua_setfield(L, -2, "__index");
230  lua_pushcfunction(L, impl_unit_type_new);
231  lua_setfield(L, -2, "__newindex");
232  lua_pushcfunction(L, impl_unit_type_count);
233  lua_setfield(L, -2, "__len");
234  lua_pushcfunction(L, impl_unit_type_pairs);
235  lua_setfield(L, -2, "__pairs");
236  lua_pushstring(L, UnitTypeTable);
237  lua_setfield(L, -2, "__metatable");
238  lua_setmetatable(L, -2);
239  lua_setfield(L, -2, "unit_types");
240  lua_pop(L, 1);
241 
242  return "Adding unit_types table...\n";
243  }
244 }
245 
246 void luaW_pushunittype(lua_State *L, const unit_type& ut)
247 {
248  *static_cast<const unit_type**>(lua_newuserdatauv(L, sizeof(unit_type*), 0)) = &ut;
249  luaL_setmetatable(L, UnitType);
250 }
251 
252 const unit_type* luaW_tounittype(lua_State* L, int idx)
253 {
254  if(void* p = luaL_testudata(L, idx, UnitType)) {
255  return *static_cast<const unit_type**>(p);
256  }
257  return nullptr;
258 }
259 
260 const unit_type& luaW_checkunittype(lua_State* L, int idx)
261 {
262  return **static_cast<const unit_type**>(luaL_checkudata(L, idx, UnitType));
263 }
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
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:27
@ MALE
Definition: race.hpp:27
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:1267
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:1259
const unit_type_map & types() const
Definition: types.hpp:395
A single unit type that the player may recruit.
Definition: types.hpp:43
const std::vector< std::string > advances_from() const
A vector of unit_type ids that can advance to this unit_type.
Definition: types.cpp:652
std::string race_id() const
Returns the ID of this type's race without the need to build the type.
Definition: types.hpp:272
const std::string & image() const
Definition: types.hpp:176
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:141
int hitpoints() const
Definition: types.hpp:161
const unit_type & get_variation(const std::string &id) const
Definition: types.cpp:474
const std::vector< std::string > & advances_to() const
A vector of unit_type ids that this unit_type can advance to.
Definition: types.hpp:115
const variations_map & variation_types() const
Definition: types.hpp:256
bool has_gender_variation(const unit_race::GENDER gender) const
Definition: types.hpp:250
int movement() const
Definition: types.hpp:166
@ FULL
Definition: types.hpp:74
int cost() const
Definition: types.hpp:172
const unit_type & get_gender_unit_type(std::string gender) const
Returns a gendered variant of this unit_type.
Definition: types.cpp:453
const std::string & icon() const
Definition: types.hpp:177
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:577
const std::string & big_profile() const
Definition: types.hpp:179
std::vector< std::string > get_ability_list() const
Definition: types.cpp:604
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:138
config::const_child_itors possible_traits() const
Definition: types.hpp:231
int level() const
Definition: types.hpp:164
unit_alignments::type alignment() const
Definition: types.hpp:193
const std::string & small_profile() const
Definition: types.hpp:178
const config & get_cfg() const
Definition: types.hpp:281
int recall_cost() const
Definition: types.hpp:165
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:827
#define return_vector_string_attrib(name, accessor)
Definition: lua_common.hpp:319
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:256
#define return_cfgref_attrib(name, accessor)
Definition: lua_common.hpp:309
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:267
#define return_tstring_attrib(name, accessor)
Definition: lua_common.hpp:236
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.
static int impl_unit_type_next(lua_State *L)
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.
static int impl_unit_type_count(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[]
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:373
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
mock_party p
unit_type_data unit_types
Definition: types.cpp:1486