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