The Battle for Wesnoth  1.17.23+dev
lua_unit.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2023
3  by Guillaume Melquiond <guillaume.melquiond@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 
16 #include "scripting/lua_unit.hpp"
17 
18 #include "formatter.hpp"
19 #include "game_board.hpp"
20 #include "log.hpp"
21 #include "map/location.hpp" // for map_location
22 #include "map/map.hpp"
23 #include "resources.hpp"
24 #include "scripting/lua_common.hpp"
26 #include "scripting/push_check.hpp"
28 #include "units/unit.hpp"
29 #include "units/map.hpp"
31 #include "game_version.hpp"
32 #include "deprecation.hpp"
33 
34 #include "lua/lauxlib.h"
35 
36 static lg::log_domain log_scripting_lua("scripting/lua");
37 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
38 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
39 
40 static const char getunitKey[] = "unit";
41 static const char ustatusKey[] = "unit status";
42 static const char unitvarKey[] = "unit variables";
43 
45 {
46 }
47 
49 {
50  if (ptr) return ptr.get();
51  if (c_ptr) return c_ptr;
52  if (side) {
54  }
56  if (!ui.valid()) return nullptr;
57  return ui.get_shared_ptr().get(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
58 }
60 {
61  if (ptr) return ptr;
62  if (side) {
64  }
66  if (!ui.valid()) return unit_ptr();
67  return ui.get_shared_ptr(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer.
68 }
69 
70 // Having this function here not only simplifies other code, it allows us to move
71 // pointers around from one structure to another.
72 // This makes bare pointer->map in particular about 2 orders of magnitude faster,
73 // as benchmarked from Lua code.
75 {
76  if (ptr) {
77  auto [unit_it, success] = resources::gameboard->units().replace(loc, ptr);
78 
79  if(success) {
80  ptr.reset();
81  uid = unit_it->underlying_id();
82  } else {
83  ERR_LUA << "Could not move unit " << ptr->underlying_id() << " onto map location " << loc;
84  return false;
85  }
86  } else if (side) { // recall list
88  if (it) {
89  side = 0;
90  // uid may be changed by unit_map on insertion
91  uid = resources::gameboard->units().replace(loc, it).first->underlying_id();
92  } else {
93  ERR_LUA << "Could not find unit " << uid << " on recall list of side " << side;
94  return false;
95  }
96  } else { // on map
98  if (ui != resources::gameboard->units().end()) {
99  map_location from = ui->get_location();
100  if (from != loc) { // This check is redundant in current usage
102  resources::gameboard->units().move(from, loc);
103  }
104  // No need to change our contents
105  } else {
106  ERR_LUA << "Could not find unit " << uid << " on the map";
107  return false;
108  }
109  }
110  return true;
111 }
112 
113 bool luaW_isunit(lua_State* L, int index)
114 {
115  return luaL_testudata(L, index,getunitKey) != nullptr;
116 }
117 
118 enum {
123 };
124 
125 static lua_unit* internal_get_unit(lua_State *L, int index, bool only_on_map, int& error)
126 {
127  error = LU_OK;
128  if(!luaW_isunit(L, index)) {
129  error = LU_NOT_UNIT;
130  return nullptr;
131  }
132  lua_unit* lu = static_cast<lua_unit*>(lua_touserdata(L, index));
133  if(only_on_map && !lu->on_map()) {
134  error = LU_NOT_ON_MAP;
135  }
136  if(!lu->get()) {
137  error = LU_NOT_VALID;
138  }
139  return lu;
140 }
141 
142 unit* luaW_tounit(lua_State *L, int index, bool only_on_map)
143 {
144  int error;
145  lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
146  if(error != LU_OK) {
147  return nullptr;
148  }
149  return lu->get();
150 }
151 
152 unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map)
153 {
154  int error;
155  lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
156  if(error != LU_OK) {
157  return nullptr;
158  }
159  return lu->get_shared();
160 }
161 
162 lua_unit* luaW_tounit_ref(lua_State *L, int index)
163 {
164  int error;
165  return internal_get_unit(L, index, false, error);
166 }
167 
168 static void unit_show_error(lua_State *L, int index, int error)
169 {
170  switch(error) {
171  case LU_NOT_UNIT:
172  luaW_type_error(L, index, "unit");
173  break;
174  case LU_NOT_VALID:
175  luaL_argerror(L, index, "unit not found");
176  break;
177  case LU_NOT_ON_MAP:
178  luaL_argerror(L, index, "unit not found on map");
179  break;
180  }
181 }
182 
183 unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map)
184 {
185  int error;
186  lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
187  unit_show_error(L, index, error);
188  return lu->get_shared();
189 }
190 
191 unit& luaW_checkunit(lua_State *L, int index, bool only_on_map)
192 {
193  int error;
194  lua_unit* lu = internal_get_unit(L, index, only_on_map, error);
195  unit_show_error(L, index, error);
196  return *lu->get();
197 }
198 
199 lua_unit* luaW_checkunit_ref(lua_State *L, int index)
200 {
201  int error;
202  lua_unit* lu = internal_get_unit(L, index, false, error);
203  unit_show_error(L, index, error);
204  return lu;
205 }
206 
207 void lua_unit::setmetatable(lua_State *L)
208 {
209  luaL_setmetatable(L, getunitKey);
210 }
211 
212 lua_unit* luaW_pushlocalunit(lua_State *L, unit& u)
213 {
214  lua_unit* res = new(L) lua_unit(u);
216  return res;
217 }
218 
219 /**
220  * Destroys a unit object before it is collected (__gc metamethod).
221  */
222 static int impl_unit_collect(lua_State *L)
223 {
224  lua_unit *u = static_cast<lua_unit *>(lua_touserdata(L, 1));
225  u->lua_unit::~lua_unit();
226  return 0;
227 }
228 
229 /**
230  * Checks two lua proxy units for equality. (__eq metamethod)
231  */
232 static int impl_unit_equality(lua_State* L)
233 {
234  unit& left = luaW_checkunit(L, 1);
235  unit& right = luaW_checkunit(L, 2);
236  const bool equal = left.underlying_id() == right.underlying_id();
237  lua_pushboolean(L, equal);
238  return 1;
239 }
240 
241 /**
242  * Turns a lua proxy unit to string. (__tostring metamethod)
243  */
244 static int impl_unit_tostring(lua_State* L)
245 {
246  const lua_unit* lu = luaW_tounit_ref(L, 1);
247  unit &u = *lu->get();
248  std::ostringstream str;
249 
250  str << "unit: <";
251  if(!u.id().empty()) {
252  str << u.id() << " ";
253  } else {
254  str << u.type_id() << " ";
255  }
256  if(int side = lu->on_recall_list()) {
257  str << "at (side " << side << " recall list)";
258  } else {
259  str << "at (" << u.get_location() << ")";
260  }
261  str << '>';
262 
263  lua_push(L, str.str());
264  return 1;
265 }
266 
267 /**
268  * Gets some data on a unit (__index metamethod).
269  * - Arg 1: full userdata containing the unit id.
270  * - Arg 2: string containing the name of the property.
271  * - Ret 1: something containing the attribute.
272  */
273 static int impl_unit_get(lua_State *L)
274 {
275  lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
276  char const *m = luaL_checkstring(L, 2);
277  const unit* pu = lu->get();
278 
279  if(strcmp(m, "valid") == 0) {
280  if(!pu) {
281  return 0;
282  }
283  if(lu->on_map()) {
284  lua_pushstring(L, "map");
285  } else if(lu->on_recall_list()) {
286  lua_pushstring(L, "recall");
287  } else {
288  lua_pushstring(L, "private");
289  }
290  return 1;
291  }
292 
293  if(!pu) {
294  return luaL_argerror(L, 1, "unknown unit");
295  }
296 
297  const unit& u = *pu;
298 
299  // Find the corresponding attribute.
300  return_int_attrib("x", u.get_location().wml_x());
301  return_int_attrib("y", u.get_location().wml_y());
302  if(strcmp(m, "loc") == 0) {
303  luaW_pushlocation(L, u.get_location());
304  return 1;
305  }
306  if(strcmp(m, "goto") == 0) {
307  luaW_pushlocation(L, u.get_goto());
308  return 1;
309  }
310  return_int_attrib("side", u.side());
311  return_string_attrib("id", u.id());
312  return_string_attrib("type", u.type_id());
313  return_string_attrib("image_mods", u.effect_image_mods());
314  return_string_attrib("usage", u.usage());
315  return_string_attrib("ellipse", u.image_ellipse());
316  return_string_attrib("halo", u.image_halo());
317  return_int_attrib("hitpoints", u.hitpoints());
318  return_int_attrib("max_hitpoints", u.max_hitpoints());
319  return_int_attrib("experience", u.experience());
320  return_int_attrib("max_experience", u.max_experience());
321  return_int_attrib("recall_cost", u.recall_cost());
322  return_int_attrib("moves", u.movement_left());
323  return_int_attrib("max_moves", u.total_movement());
324  return_int_attrib("max_attacks", u.max_attacks());
325  return_int_attrib("attacks_left", u.attacks_left());
326  return_int_attrib("vision", u.vision());
327  return_int_attrib("jamming", u.jamming());
328  return_tstring_attrib("name", u.name());
329  return_tstring_attrib("description", u.unit_description());
330  return_bool_attrib("canrecruit", u.can_recruit());
331  return_bool_attrib("renamable", !u.unrenamable());
332  return_int_attrib("level", u.level());
333  return_int_attrib("cost", u.cost());
334 
335  return_vector_string_attrib("extra_recruit", u.recruits());
336  return_vector_string_attrib("advances_to", u.advances_to());
337 
338  if(strcmp(m, "alignment") == 0) {
339  lua_push(L, unit_alignments::get_string(u.alignment()));
340  return 1;
341  }
342 
343  if(strcmp(m, "upkeep") == 0) {
344  unit::upkeep_t upkeep = u.upkeep_raw();
345 
346  // Need to keep these separate in order to ensure an int value is always used if applicable.
347  if(int* v = utils::get_if<int>(&upkeep)) {
348  lua_push(L, *v);
349  } else {
350  const std::string type = utils::visit(unit::upkeep_type_visitor{}, upkeep);
351  lua_push(L, type);
352  }
353 
354  return 1;
355  }
356  if(strcmp(m, "advancements") == 0) {
357  lua_push(L, u.modification_advancements());
358  return 1;
359  }
360  if(strcmp(m, "overlays") == 0) {
361  lua_push(L, u.overlays());
362  return 1;
363  }
364  if(strcmp(m, "traits") == 0) {
365  lua_push(L, u.get_traits_list());
366  return 1;
367  }
368  if(strcmp(m, "abilities") == 0) {
369  lua_push(L, u.get_ability_list());
370  return 1;
371  }
372  if(strcmp(m, "status") == 0) {
373  lua_createtable(L, 1, 0);
374  lua_pushvalue(L, 1);
375  lua_rawseti(L, -2, 1);
376  luaL_setmetatable(L, ustatusKey);
377  return 1;
378  }
379  if(strcmp(m, "variables") == 0) {
380  lua_createtable(L, 1, 0);
381  lua_pushvalue(L, 1);
382  lua_rawseti(L, -2, 1);
383  luaL_setmetatable(L, unitvarKey);
384  return 1;
385  }
386  if(strcmp(m, "attacks") == 0) {
387  push_unit_attacks_table(L, 1);
388  return 1;
389  }
390  if(strcmp(m, "petrified") == 0) {
391  deprecated_message("(unit).petrified", DEP_LEVEL::INDEFINITE, {1,17,0}, "use (unit).status.petrified instead");
392  lua_pushboolean(L, u.incapacitated());
393  return 1;
394  }
395  return_vector_string_attrib("animations", u.anim_comp().get_flags());
396  return_cfg_attrib("recall_filter", cfg = u.recall_filter());
397  return_bool_attrib("hidden", u.get_hidden());
398  return_bool_attrib("resting", u.resting());
399  return_string_attrib("role", u.get_role());
400  return_string_attrib("race", u.race()->id());
401  return_string_attrib("gender", gender_string(u.gender()));
402  return_string_attrib("variation", u.variation());
403  return_string_attrib("undead_variation", u.undead_variation());
404  return_bool_attrib("zoc", u.get_emit_zoc());
405  return_string_attrib("facing", map_location::write_direction(u.facing()));
406  return_string_attrib("portrait", u.big_profile() == u.absolute_image()
407  ? u.absolute_image() + u.image_mods() + "~XBRZ(2)"
408  : u.big_profile());
409  return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
410 
411  if(luaW_getglobal(L, "wesnoth", "units", m)) {
412  return 1;
413  }
414  return 0;
415 }
416 
417 /**
418  * Sets some data on a unit (__newindex metamethod).
419  * - Arg 1: full userdata containing the unit id.
420  * - Arg 2: string containing the name of the property.
421  * - Arg 3: something containing the attribute.
422  */
423 static int impl_unit_set(lua_State *L)
424 {
425  lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
426  char const *m = luaL_checkstring(L, 2);
427  unit* pu = lu->get();
428  if (!pu) return luaL_argerror(L, 1, "unknown unit");
429  unit &u = *pu;
430 
431  // Find the corresponding attribute.
432  //modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(teams().size())); TODO: Figure out if this is a good idea, to refer to teams() and make this depend on having a gamestate
433  modify_int_attrib("side", u.set_side(value));
434  modify_int_attrib("moves", u.set_movement(value));
435  modify_int_attrib("max_moves", u.set_total_movement(value));
436  modify_int_attrib("max_attacks", u.set_max_attacks(value));
437  modify_int_attrib("hitpoints", u.set_hitpoints(value));
438  modify_int_attrib("max_hitpoints", u.set_max_hitpoints(value));
439  modify_int_attrib("experience", u.set_experience(value));
440  modify_int_attrib("max_experience", u.set_max_experience(value));
441  modify_int_attrib("recall_cost", u.set_recall_cost(value));
442  modify_int_attrib("attacks_left", u.set_attacks(value));
443  modify_int_attrib("level", u.set_level(value));
444  modify_bool_attrib("resting", u.set_resting(value));
445  modify_tstring_attrib("name", u.set_name(value));
446  modify_tstring_attrib("description", u.set_unit_description(value));
447  modify_string_attrib("portrait", u.set_big_profile(value));
448  modify_string_attrib("role", u.set_role(value));
449  modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
450  modify_string_attrib("usage", u.set_usage(value));
451  modify_string_attrib("undead_variation", u.set_undead_variation(value));
452  modify_string_attrib("ellipse", u.set_image_ellipse(value));
453  modify_string_attrib("halo", u.set_image_halo(value));
454  modify_bool_attrib("hidden", u.set_hidden(value));
455  modify_bool_attrib("zoc", u.set_emit_zoc(value));
456  modify_bool_attrib("canrecruit", u.set_can_recruit(value));
457  modify_bool_attrib("renamable", u.set_unrenamable(!value));
458  modify_cfg_attrib("recall_filter", u.set_recall_filter(cfg));
459 
460  modify_vector_string_attrib("extra_recruit", u.set_recruits(value));
461  modify_vector_string_attrib("advances_to", u.set_advances_to(value));
462  if(strcmp(m, "alignment") == 0) {
463  u.set_alignment(lua_enum_check<unit_alignments>(L, 3));
464  return 0;
465  }
466 
467  if(strcmp(m, "advancements") == 0) {
468  u.set_advancements(lua_check<std::vector<config>>(L, 3));
469  return 0;
470  }
471 
472  if(strcmp(m, "upkeep") == 0) {
473  if(lua_isnumber(L, 3)) {
474  u.set_upkeep(static_cast<int>(luaL_checkinteger(L, 3)));
475  return 0;
476  }
477  const char* v = luaL_checkstring(L, 3);
478  if((strcmp(v, "loyal") == 0) || (strcmp(v, "free") == 0)) {
479  u.set_upkeep(unit::upkeep_loyal());
480  } else if(strcmp(v, "full") == 0) {
481  u.set_upkeep(unit::upkeep_full());
482  } else {
483  std::string err_msg = "unknown upkeep value of unit: ";
484  err_msg += v;
485  return luaL_argerror(L, 2, err_msg.c_str());
486  }
487  return 0;
488  }
489 
490  if(!lu->on_map()) {
491  map_location loc = u.get_location();
492  modify_int_attrib("x", loc.set_wml_x(value); u.set_location(loc));
493  modify_int_attrib("y", loc.set_wml_y(value); u.set_location(loc));
494  modify_string_attrib("id", u.set_id(value));
495  if(strcmp(m, "loc") == 0) {
496  luaW_tolocation(L, 3, loc);
497  u.set_location(loc);
498  return 0;
499  }
500  } else {
501  const bool is_key_x = strcmp(m, "x") == 0;
502  const bool is_key_y = strcmp(m, "y") == 0;
503  const bool is_loc_key = strcmp(m, "loc") == 0;
504 
505  // Handle moving an on-map unit
506  if(is_key_x || is_key_y || is_loc_key) {
507  game_board* gb = resources::gameboard;
508 
509  if(!gb) {
510  return 0;
511  }
512 
513  map_location src = u.get_location();
514  map_location dst = src;
515 
516  if(is_key_x) {
517  dst.set_wml_x(luaL_checkinteger(L, 3));
518  } else if(is_key_y) {
519  dst.set_wml_y(luaL_checkinteger(L, 3));
520  } else {
521  dst = luaW_checklocation(L, 3);
522  }
523 
524  // TODO: could probably be relegated to a helper function.
525  if(src != dst) {
526  // If the dst isn't on the map, the unit will be clobbered. Guard against that.
527  if(!gb->map().on_board(dst)) {
528  std::string err_msg = formatter() << "destination hex not on map (excluding border): " << dst;
529  return luaL_argerror(L, 2, err_msg.c_str());
530  }
531 
532  auto [unit_iterator, success] = gb->units().move(src, dst);
533 
534  if(success) {
535  unit_iterator->anim_comp().set_standing();
536  }
537  }
538 
539  return 0;
540  }
541  }
542 
543  if(strcmp(m, "goto") == 0) {
544  u.set_goto(luaW_checklocation(L, 3));
545  return 0;
546  }
547 
548  std::string err_msg = "unknown modifiable property of unit: ";
549  err_msg += m;
550  return luaL_argerror(L, 2, err_msg.c_str());
551 }
552 
553 /**
554  * Gets the status of a unit (__index metamethod).
555  * - Arg 1: table containing the userdata containing the unit id.
556  * - Arg 2: string containing the name of the status.
557  * - Ret 1: boolean.
558  */
559 static int impl_unit_status_get(lua_State *L)
560 {
561  if(!lua_istable(L, 1)) {
562  return luaW_type_error(L, 1, "unit status");
563  }
564  lua_rawgeti(L, 1, 1);
565  const unit* u = luaW_tounit(L, -1);
566  if(!u) {
567  return luaL_argerror(L, 1, "unknown unit");
568  }
569  char const *m = luaL_checkstring(L, 2);
570  lua_pushboolean(L, u->get_state(m));
571  return 1;
572 }
573 
574 /**
575  * Sets the status of a unit (__newindex metamethod).
576  * - Arg 1: table containing the userdata containing the unit id.
577  * - Arg 2: string containing the name of the status.
578  * - Arg 3: boolean.
579  */
580 static int impl_unit_status_set(lua_State *L)
581 {
582  if(!lua_istable(L, 1)) {
583  return luaW_type_error(L, 1, "unit status");
584  }
585  lua_rawgeti(L, 1, 1);
586  unit* u = luaW_tounit(L, -1);
587  if(!u) {
588  return luaL_argerror(L, 1, "unknown unit");
589  }
590  char const *m = luaL_checkstring(L, 2);
591  u->set_state(m, luaW_toboolean(L, 3));
592  return 0;
593 }
594 
595 /**
596  * Gets the variable of a unit (__index metamethod).
597  * - Arg 1: table containing the userdata containing the unit id.
598  * - Arg 2: string containing the name of the status.
599  * - Ret 1: boolean.
600  */
601 static int impl_unit_variables_get(lua_State *L)
602 {
603  if(!lua_istable(L, 1)) {
604  return luaW_type_error(L, 1, "unit variables");
605  }
606  lua_rawgeti(L, 1, 1);
607  const unit* u = luaW_tounit(L, -1);
608  if(!u) {
609  return luaL_argerror(L, 2, "unknown unit");
610  }
611  char const *m = luaL_checkstring(L, 2);
612  return_cfgref_attrib("__cfg", u->variables());
613 
614  variable_access_const v(m, u->variables());
615  return luaW_pushvariable(L, v) ? 1 : 0;
616 }
617 
618 /**
619  * Sets the variable of a unit (__newindex metamethod).
620  * - Arg 1: table containing the userdata containing the unit id.
621  * - Arg 2: string containing the name of the status.
622  * - Arg 3: scalar.
623  */
624 static int impl_unit_variables_set(lua_State *L)
625 {
626  if(!lua_istable(L, 1)) {
627  return luaW_type_error(L, 1, "unit variables");
628  }
629  lua_rawgeti(L, 1, 1);
630  unit* u = luaW_tounit(L, -1);
631  if(!u) {
632  return luaL_argerror(L, 2, "unknown unit");
633  }
634  char const *m = luaL_checkstring(L, 2);
635  modify_cfg_attrib("__cfg", u->variables() = cfg);
636  config& vars = u->variables();
637  if(lua_isnoneornil(L, 3)) {
638  try {
639  variable_access_throw(m, vars).clear(false);
640  } catch(const invalid_variablename_exception&) {
641  }
642  return 0;
643  }
644  variable_access_create v(m, vars);
645  luaW_checkvariable(L, v, 3);
646  return 0;
647 }
648 
649 namespace lua_units {
650  std::string register_metatables(lua_State* L)
651  {
652  std::ostringstream cmd_out;
653 
654  // Create the getunit metatable.
655  cmd_out << "Adding getunit metatable...\n";
656 
657  luaL_newmetatable(L, getunitKey);
658  lua_pushcfunction(L, impl_unit_collect);
659  lua_setfield(L, -2, "__gc");
660  lua_pushcfunction(L, impl_unit_equality);
661  lua_setfield(L, -2, "__eq");
662  lua_pushcfunction(L, impl_unit_tostring);
663  lua_setfield(L, -2, "__tostring");
664  lua_pushcfunction(L, impl_unit_get);
665  lua_setfield(L, -2, "__index");
666  lua_pushcfunction(L, impl_unit_set);
667  lua_setfield(L, -2, "__newindex");
668  lua_pushstring(L, "unit");
669  lua_setfield(L, -2, "__metatable");
670 
671  // Create the unit status metatable.
672  cmd_out << "Adding unit status metatable...\n";
673 
674  luaL_newmetatable(L, ustatusKey);
675  lua_pushcfunction(L, impl_unit_status_get);
676  lua_setfield(L, -2, "__index");
677  lua_pushcfunction(L, impl_unit_status_set);
678  lua_setfield(L, -2, "__newindex");
679  lua_pushstring(L, "unit status");
680  lua_setfield(L, -2, "__metatable");
681 
682  // Create the unit variables metatable.
683  cmd_out << "Adding unit variables metatable...\n";
684 
685  luaL_newmetatable(L, unitvarKey);
686  lua_pushcfunction(L, impl_unit_variables_get);
687  lua_setfield(L, -2, "__index");
688  lua_pushcfunction(L, impl_unit_variables_set);
689  lua_setfield(L, -2, "__newindex");
690  lua_pushstring(L, "unit variables");
691  lua_setfield(L, -2, "__metatable");
692 
693  return cmd_out.str();
694  }
695 }
double t
Definition: astarsearch.cpp:65
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
std::ostringstream wrapper.
Definition: formatter.hpp:40
team & get_team(int i)
Definition: game_board.hpp:98
virtual const unit_map & units() const override
Definition: game_board.hpp:113
Storage for a unit, either owned by the Lua code (ptr != 0), a local variable unit (c_ptr !...
Definition: lua_unit.hpp:81
unit_ptr ptr
Definition: lua_unit.hpp:83
int side
Definition: lua_unit.hpp:84
unit * c_ptr
Definition: lua_unit.hpp:85
static void setmetatable(lua_State *L)
Definition: lua_unit.cpp:207
std::size_t uid
Definition: lua_unit.hpp:82
~lua_unit()
Definition: lua_unit.cpp:44
bool put_map(const map_location &loc)
Definition: lua_unit.cpp:74
unit_ptr get_shared() const
Definition: lua_unit.cpp:59
unit * get() const
Definition: lua_unit.cpp:48
unit_ptr find_if_matches_underlying_id(std::size_t uid)
Find a unit by underlying id.
unit_ptr extract_if_matches_underlying_id(std::size_t uid)
Find a unit by underlying id, and extract if found.
recall_list_manager & recall_list()
Definition: team.hpp:203
umap_retval_pair_t replace(const map_location &l, unit_ptr p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:215
unit_iterator find(std::size_t id)
Definition: map.cpp:301
std::size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:288
umap_retval_pair_t move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:93
This class represents a single unit of a specific type.
Definition: unit.hpp:135
Additional functionality for a non-const variable_info.
Information on a WML variable.
Interfaces for manipulating version numbers of engine, add-ons, etc.
void set_state(const std::string &state, bool value)
Set whether the unit is affected by a status effect.
Definition: unit.cpp:1377
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1328
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1938
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:382
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition: unit.hpp:705
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:394
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1359
void set_goto(const map_location &new_goto)
Sets this unit's long term destination.
Definition: unit.hpp:1396
T end(const std::pair< T, T > &p)
Standard logging facilities (interface).
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
Definition: lua_common.cpp:996
bool luaW_toboolean(lua_State *L, int n)
Definition: lua_common.cpp:991
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:793
#define return_cfgref_attrib(name, accessor)
Definition: lua_common.hpp:309
#define modify_cfg_attrib(name, accessor)
Definition: lua_common.hpp:415
lua_unit * luaW_checkunit_ref(lua_State *L, int index)
Similar to luaW_checkunit but returns a lua_unit; use this if you need to handle map and recall units...
Definition: lua_unit.cpp:199
static int impl_unit_set(lua_State *L)
Sets some data on a unit (__newindex metamethod).
Definition: lua_unit.cpp:423
static int impl_unit_equality(lua_State *L)
Checks two lua proxy units for equality.
Definition: lua_unit.cpp:232
#define ERR_LUA
Definition: lua_unit.cpp:38
static lg::log_domain log_scripting_lua("scripting/lua")
unit & luaW_checkunit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
Definition: lua_unit.cpp:191
static void unit_show_error(lua_State *L, int index, int error)
Definition: lua_unit.cpp:168
static int impl_unit_status_get(lua_State *L)
Gets the status of a unit (__index metamethod).
Definition: lua_unit.cpp:559
lua_unit * luaW_tounit_ref(lua_State *L, int index)
Similar to luaW_tounit but returns a lua_unit; use this if you need to handle map and recall units di...
Definition: lua_unit.cpp:162
static int impl_unit_collect(lua_State *L)
Destroys a unit object before it is collected (__gc metamethod).
Definition: lua_unit.cpp:222
static const char unitvarKey[]
Definition: lua_unit.cpp:42
static int impl_unit_variables_get(lua_State *L)
Gets the variable of a unit (__index metamethod).
Definition: lua_unit.cpp:601
static lua_unit * internal_get_unit(lua_State *L, int index, bool only_on_map, int &error)
Definition: lua_unit.cpp:125
static int impl_unit_get(lua_State *L)
Gets some data on a unit (__index metamethod).
Definition: lua_unit.cpp:273
static int impl_unit_variables_set(lua_State *L)
Sets the variable of a unit (__newindex metamethod).
Definition: lua_unit.cpp:624
bool luaW_isunit(lua_State *L, int index)
Test if a Lua value is a unit.
Definition: lua_unit.cpp:113
static const char getunitKey[]
Definition: lua_unit.cpp:40
static const char ustatusKey[]
Definition: lua_unit.cpp:41
@ LU_NOT_ON_MAP
Definition: lua_unit.cpp:121
@ LU_NOT_VALID
Definition: lua_unit.cpp:122
@ LU_OK
Definition: lua_unit.cpp:119
@ LU_NOT_UNIT
Definition: lua_unit.cpp:120
unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map)
Similar to luaW_checkunit but returns a unit_ptr; use this instead of luaW_checkunit when using an ap...
Definition: lua_unit.cpp:183
static int impl_unit_status_set(lua_State *L)
Sets the status of a unit (__newindex metamethod).
Definition: lua_unit.cpp:580
unit_ptr luaW_tounit_ptr(lua_State *L, int index, bool only_on_map)
Similar to luaW_tounit but returns a unit_ptr; use this instead of luaW_tounit when using an api that...
Definition: lua_unit.cpp:152
static int impl_unit_tostring(lua_State *L)
Turns a lua proxy unit to string.
Definition: lua_unit.cpp:244
lua_unit * luaW_pushlocalunit(lua_State *L, unit &u)
Pushes a private unit on the stack.
Definition: lua_unit.cpp:212
unit * luaW_tounit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
Definition: lua_unit.cpp:142
std::string register_metatables(lua_State *L)
Definition: lua_unit.cpp:650
game_board * gameboard
Definition: resources.cpp:21
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
Encapsulates the map of the game.
Definition: location.hpp:38
bool valid() const
Definition: map.hpp:274
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:218
variable_info_mutable< variable_info_implementation::vi_policy_throw > variable_access_throw
'Throw if nonexistent' access.