The Battle for Wesnoth  1.17.23+dev
lua_unit_type.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2023
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 #include "lua/lauxlib.h"
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 /**
37  * Gets some data on a unit type (__index metamethod).
38  * - Arg 1: table containing an "id" field.
39  * - Arg 2: string containing the name of the property.
40  * - Ret 1: something containing the attribute.
41  */
42 static int impl_unit_type_get(lua_State *L)
43 {
44  const unit_type& ut = luaW_checkunittype(L, 1);
45  char const *m = luaL_checkstring(L, 2);
46 
47  // Find the corresponding attribute.
48  return_tstring_attrib("name", ut.type_name());
49  return_string_attrib("id", ut.id());
51  return_string_attrib("race", ut.race_id());
52  return_string_attrib("image", ut.image());
53  return_string_attrib("icon", ut.icon());
54  return_string_attrib("profile", ut.big_profile());
55  return_string_attrib("small_profile", ut.small_profile());
56  return_int_attrib("max_hitpoints", ut.hitpoints());
57  return_int_attrib("max_moves", ut.movement());
58  return_int_attrib("max_experience", ut.experience_needed());
59  return_int_attrib("cost", ut.cost());
60  return_int_attrib("level", ut.level());
61  return_int_attrib("recall_cost", ut.recall_cost());
62  return_vector_string_attrib("advances_to", ut.advances_to());
63  return_vector_string_attrib("advances_from", ut.advances_from());
64  return_cfgref_attrib("__cfg", ut.get_cfg());
65  if (strcmp(m, "traits") == 0) {
66  lua_newtable(L);
67  for (const config& trait : ut.possible_traits()) {
68  const std::string& id = trait["id"];
69  lua_pushlstring(L, id.c_str(), id.length());
70  luaW_pushconfig(L, trait);
71  lua_rawset(L, -3);
72  }
73  return 1;
74  }
75  if (strcmp(m, "abilities") == 0) {
76  lua_push(L, ut.get_ability_list());
77  return 1;
78  }
79  if (strcmp(m, "attacks") == 0) {
81  return 1;
82  }
83  // TODO: Should this only exist for base units?
84  if(strcmp(m, "variations") == 0) {
85  *new(L) const unit_type* = &ut;
86  luaL_setmetatable(L, UnitTypeTable);
87  return 1;
88  }
89  return 0;
90 }
91 
92 static int impl_unit_type_equal(lua_State* L)
93 {
94  const unit_type& ut1 = luaW_checkunittype(L, 1);
95  if(const unit_type* ut2 = luaW_tounittype(L, 2)) {
96  lua_pushboolean(L, &ut1 == ut2);
97  } else {
98  lua_pushboolean(L, false);
99  }
100  return 1;
101 }
102 
103 static int impl_unit_type_lookup(lua_State* L)
104 {
105  std::string id = luaL_checkstring(L, 2);
106  const unit_type* ut;
107  if(const unit_type* base = *static_cast<const unit_type**>(luaL_testudata(L, 1, UnitTypeTable))) {
108  if(id == "male" || id == "female") {
109  ut = &base->get_gender_unit_type(id);
110  } else {
111  ut = &base->get_variation(id);
112  }
113  } else {
114  ut = unit_types.find(id);
115  }
116  if(ut) {
117  luaW_pushunittype(L, *ut);
118  return 1;
119  }
120  return 0;
121 }
122 
123 static int impl_unit_type_new(lua_State* L)
124 {
125  // This could someday become a hook to construct new unit types on the fly?
126  // For now though, it's just an error
127  lua_pushstring(L, "unit_types table is read-only");
128  return lua_error(L);
129 }
130 
131 static int impl_unit_type_count(lua_State* L)
132 {
133  lua_pushnumber(L, unit_types.types().size());
134  return 1;
135 }
136 
137 static int impl_unit_type_next(lua_State* L)
138 {
139  const unit_type* base = *static_cast<const unit_type**>(luaL_checkudata(L, 1, UnitTypeTable));
140  const auto& unit_map = base ? base->variation_types() : unit_types.types();
141  auto it = unit_map.end();
142  if(lua_isnoneornil(L, 2)) {
143  if(base) {
145  lua_pushstring(L, "male");
147  return 2;
148  } else if(base->has_gender_variation(unit_race::FEMALE)) {
149  lua_pushstring(L, "female");
151  return 2;
152  }
153  }
154  it = unit_map.begin();
155  } else {
156  const std::string id = luaL_checkstring(L, 2);
157  if(base) {
158  if(id == "male" && base->has_gender_variation(unit_race::FEMALE)) {
159  lua_pushstring(L, "female");
161  return 2;
162  } else if(id == "male" || id == "female") {
163  it = unit_map.begin();
164  }
165  }
166  if(it == unit_map.end()) {
167  it = unit_map.find(id);
168  }
169  if(it == unit_map.end()) {
170  return 0;
171  }
172  ++it;
173  }
174  if (it == unit_map.end()) {
175  return 0;
176  }
177  lua_pushlstring(L, it->first.c_str(), it->first.size());
178  luaW_pushunittype(L, it->second);
179  return 2;
180 }
181 
182 static int impl_unit_type_pairs(lua_State* L) {
183  lua_pushcfunction(L, &impl_unit_type_next);
184  lua_pushvalue(L, -2);
185  lua_pushnil(L);
186  return 3;
187 }
188 
189 /**
190  * Turns a lua proxy unit type to string. (__tostring metamethod)
191  */
192 static int impl_unit_type_tostring(lua_State* L)
193 {
194  const unit_type& ut = luaW_checkunittype(L, 1);
195  std::ostringstream str;
196 
197  str << "unit type: <" << ut.id() << '>';
198 
199  lua_push(L, str.str());
200  return 1;
201 }
202 
203 namespace lua_unit_type {
204  std::string register_metatable(lua_State * L)
205  {
206  luaL_newmetatable(L, UnitType);
207 
208  lua_pushcfunction(L, impl_unit_type_get);
209  lua_setfield(L, -2, "__index");
210  lua_pushcfunction(L, impl_unit_type_tostring);
211  lua_setfield(L, -2, "__tostring");
212  lua_pushcfunction(L, impl_unit_type_equal);
213  lua_setfield(L, -2, "__eq");
214  lua_pushstring(L, UnitType);
215  lua_setfield(L, -2, "__metatable");
216 
217  return "Adding unit type metatable...\n";
218  }
219 
220  std::string register_table(lua_State* L)
221  {
222  lua_getglobal(L, "wesnoth");
223  *new(L) unit_type* = nullptr;
224  luaL_newmetatable(L, UnitTypeTable);
225  lua_pushcfunction(L, impl_unit_type_lookup);
226  lua_setfield(L, -2, "__index");
227  lua_pushcfunction(L, impl_unit_type_new);
228  lua_setfield(L, -2, "__newindex");
229  lua_pushcfunction(L, impl_unit_type_count);
230  lua_setfield(L, -2, "__len");
231  lua_pushcfunction(L, impl_unit_type_pairs);
232  lua_setfield(L, -2, "__pairs");
233  lua_pushstring(L, UnitTypeTable);
234  lua_setfield(L, -2, "__metatable");
235  lua_setmetatable(L, -2);
236  lua_setfield(L, -2, "unit_types");
237  lua_pop(L, 1);
238 
239  return "Adding unit_types table...\n";
240  }
241 }
242 
243 void luaW_pushunittype(lua_State *L, const unit_type& ut)
244 {
245  *static_cast<const unit_type**>(lua_newuserdatauv(L, sizeof(unit_type*), 0)) = &ut;
246  luaL_setmetatable(L, UnitType);
247 }
248 
249 const unit_type* luaW_tounittype(lua_State* L, int idx)
250 {
251  if(void* p = luaL_testudata(L, idx, UnitType)) {
252  return *static_cast<const unit_type**>(p);
253  }
254  return nullptr;
255 }
256 
257 const unit_type& luaW_checkunittype(lua_State* L, int idx)
258 {
259  return **static_cast<const unit_type**>(luaL_checkudata(L, idx, UnitType));
260 }
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
Container associating units to locations.
Definition: map.hpp:99
unit_iterator end()
Definition: map.hpp:429
unit_iterator find(std::size_t id)
Definition: map.cpp:301
unit_iterator begin()
Definition: map.hpp:419
@ 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:1246
const unit_type_map & types() const
Definition: types.hpp:396
A single unit type that the player may recruit.
Definition: types.hpp:46
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:274
const std::string & image() const
Definition: types.hpp:179
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:144
int hitpoints() const
Definition: types.hpp:164
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:118
const variations_map & variation_types() const
Definition: types.hpp:258
bool has_gender_variation(const unit_race::GENDER gender) const
Definition: types.hpp:252
int movement() const
Definition: types.hpp:169
int cost() const
Definition: types.hpp:175
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:180
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:577
const std::string & big_profile() const
Definition: types.hpp:182
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:141
config::const_child_itors possible_traits() const
Definition: types.hpp:233
int level() const
Definition: types.hpp:167
unit_alignments::type alignment() const
Definition: types.hpp:195
const std::string & small_profile() const
Definition: types.hpp:181
const config & get_cfg() const
Definition: types.hpp:283
int recall_cost() const
Definition: types.hpp:168
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:830
#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:1465