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