The Battle for Wesnoth  1.15.2+dev
lua_unit_type.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "scripting/lua_common.hpp"
19 #include "scripting/push_check.hpp"
20 #include "units/types.hpp"
21 
22 #include <string>
23 #include <cstring>
24 
25 #include "lua/lua.h"
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  */
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());
50  return_string_attrib("alignment", ut.alignment().to_string());
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;
87  return 1;
88  }
89  return 0;
90 }
91 
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 
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 
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 
132 {
133  lua_pushnumber(L, unit_types.types().size());
134  return 1;
135 }
136 
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 
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  */
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  {
207 
209  lua_setfield(L, -2, "__index");
211  lua_setfield(L, -2, "__tostring");
213  lua_setfield(L, -2, "__eq");
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;
226  lua_setfield(L, -2, "__index");
228  lua_setfield(L, -2, "__newindex");
230  lua_setfield(L, -2, "__len");
232  lua_setfield(L, -2, "__pairs");
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 
244 {
245  *static_cast<const unit_type**>(lua_newuserdata(L, sizeof(unit_type*))) = &ut;
247 }
248 
250 {
251  if(void* p = luaL_testudata(L, idx, UnitType)) {
252  return *static_cast<const unit_type**>(p);
253  }
254  return nullptr;
255 }
256 
258 {
259  return **static_cast<const unit_type**>(luaL_checkudata(L, idx, UnitType));
260 }
#define lua_isnoneornil(L, n)
Definition: lua.h:359
LUALIB_API void * luaL_checkudata(lua_State *L, int ud, const char *tname)
Definition: lauxlib.cpp:333
#define lua_pushcfunction(L, f)
Definition: lua.h:350
unit_iterator end()
Definition: map.hpp:415
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:1271
#define return_tstring_attrib(name, accessor)
Definition: lua_common.hpp:201
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:730
static int impl_unit_type_pairs(lua_State *L)
LUA_API void lua_pushboolean(lua_State *L, int b)
Definition: lapi.cpp:557
const std::string & big_profile() const
Definition: types.hpp:168
This namespace contains bindings for lua to hold a reference to a unit type and access its stats...
const std::vector< std::string > & advances_to() const
A vector of unit_type ids that this unit_type can advance to.
Definition: types.hpp:112
std::string register_table(lua_State *L)
std::string register_metatable(lua_State *L)
LUA_API int lua_getglobal(lua_State *L, const char *name)
Definition: lapi.cpp:605
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:217
unit_iterator begin()
Definition: map.hpp:405
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:543
unit_type_data unit_types
Definition: types.cpp:1529
const config & get_cfg() const
Definition: types.hpp:272
#define return_vector_string_attrib(name, accessor)
Definition: lua_common.hpp:268
static int impl_unit_type_new(lua_State *L)
LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:312
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:371
const unit_type_map & types() const
Definition: types.hpp:366
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...
const std::vector< std::string > advances_from() const
A vector of unit_type ids that can advance to this unit_type.
Definition: types.cpp:679
static int impl_unit_type_equal(lua_State *L)
LUA_API void * lua_newuserdata(lua_State *L, size_t size)
Definition: lapi.cpp:1184
A single unit type that the player may recruit.
Definition: types.hpp:42
#define lua_pop(L, n)
Definition: lua.h:344
#define return_cfgref_attrib(name, accessor)
Definition: lua_common.hpp:260
static const char UnitType[]
Implementation for a lua reference to a unit_type.
int cost() const
Definition: types.hpp:161
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:226
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:135
static const char UnitTypeTable[]
static int impl_unit_type_next(lua_State *L)
LUA_API const char * lua_pushlstring(lua_State *L, const char *s, size_t len)
Definition: lapi.cpp:479
LUA_API int lua_setmetatable(lua_State *L, int objindex)
Definition: lapi.cpp:846
std::string race_id() const
Returns the ID of this type&#39;s race without the need to build the type.
Definition: types.hpp:265
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:138
static int impl_unit_type_count(lua_State *L)
LUALIB_API void * luaL_testudata(lua_State *L, int ud, const char *tname)
Definition: lauxlib.cpp:318
#define lua_newtable(L)
Definition: lua.h:346
LUA_API void lua_pushnil(lua_State *L)
Definition: lapi.cpp:450
LUA_API void lua_pushnumber(lua_State *L, lua_Number n)
Definition: lapi.cpp:458
const unit_type * luaW_tounittype(lua_State *L, int idx)
Test if a stack element is a unit type, and return it if so.
unit_iterator find(std::size_t id)
Definition: map.cpp:311
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
Definition: lauxlib.cpp:299
static int impl_unit_type_lookup(lua_State *L)
int recall_cost() const
Definition: types.hpp:154
static int impl_unit_type_tostring(lua_State *L)
Turns a lua proxy unit type to string.
LUA_API void lua_rawset(lua_State *L, int idx)
Definition: lapi.cpp:801
std::vector< std::string > get_ability_list() const
Definition: types.cpp:570
mock_party p
const std::string & icon() const
Definition: types.hpp:166
int level() const
Definition: types.hpp:153
LUA_API void lua_pushvalue(lua_State *L, int idx)
Definition: lapi.cpp:237
bool has_gender_variation(const unit_race::GENDER gender) const
Definition: types.hpp:243
const std::string & small_profile() const
Definition: types.hpp:167
int hitpoints() const
Definition: types.hpp:150
int movement() const
Definition: types.hpp:155
config::const_child_itors possible_traits() const
Definition: types.hpp:226
const std::string & image() const
Definition: types.hpp:165
LUA_API int lua_error(lua_State *L)
Definition: lapi.cpp:1114
const unit_type & get_variation(const std::string &id) const
Definition: types.cpp:472
const variations_map & variation_types() const
Definition: types.hpp:249
static int impl_unit_type_get(lua_State *L)
Gets some data on a unit type (__index metamethod).
const unit_type & get_gender_unit_type(std::string gender) const
Returns a gendered variant of this unit_type.
Definition: types.cpp:451
Container associating units to locations.
Definition: map.hpp:99
void push_unit_attacks_table(lua_State *L, int idx)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
LUA_API const char * lua_pushstring(lua_State *L, const char *s)
Definition: lapi.cpp:491
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
Definition: lapi.cpp:777
const unit_type & luaW_checkunittype(lua_State *L, int idx)
Test if a stack element is a unit type, and return it if so.
#define luaL_checkstring(L, n)
Definition: lauxlib.h:124