The Battle for Wesnoth  1.19.26+dev
lua_unit.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2025
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"
25 #include "scripting/lua_common.hpp"
27 #include "scripting/push_check.hpp"
28 #include "units/unit.hpp"
29 #include "units/map.hpp"
31 #include "utils/optional_fwd.hpp"
32 #include "game_version.hpp"
33 #include "deprecation.hpp"
34 #include <vector>
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
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) {
252  str << "invalid";
253  } else if(!u->id().empty()) {
254  str << u->id() << " ";
255  } else {
256  str << u->type_id() << " ";
257  }
258  if(u) {
259  if(int side = lu->on_recall_list()) {
260  str << "at (side " << side << " recall list)";
261  } else {
262  if(!lu->on_map()) {
263  str << "private ";
264  }
265  str << "at (" << u->get_location() << ")";
266  }
267  }
268  str << '>';
269 
270  lua_push(L, str.str());
271  return 1;
272 }
273 
274 #define UNIT_GETTER(name, type) LATTR_GETTER(name, type, unit, u)
275 #define UNIT_SETTER(name, type) LATTR_SETTER(name, type, unit, u)
276 luaW_Registry unitReg{"wesnoth", "units", getunitKey};
277 
278 template<> struct lua_object_traits<lua_unit*> {
279  inline static auto metatable = getunitKey;
280  inline static lua_unit* get(lua_State* L, int n) {
281  auto lu = luaW_tounit_ref(L, n);
282  if(!lu) unit_show_error(L, n, LU_NOT_UNIT);
283  return lu;
284  }
285 };
286 
287 template<> struct lua_object_traits<unit> {
288  inline static auto metatable = getunitKey;
289  inline static unit& get(lua_State* L, int n) {
290  return luaW_checkunit(L, n);
291  }
292 };
293 
294 static void handle_unit_move(lua_State* L, lua_unit* lu, map_location dst) {
295  if(!lu->on_map()) {
296  (*lu)->set_location(dst);
297  } else {
298  unit& u = *lu->get();
299 
300  // Handle moving an on-map unit
301  game_board* gb = resources::gameboard;
302 
303  if(!gb) {
304  return;
305  }
306 
307  map_location src = u.get_location();
308 
309  // TODO: could probably be relegated to a helper function.
310  if(src != dst) {
311  // If the dst isn't on the map, the unit will be clobbered. Guard against that.
312  if(!gb->map().on_board(dst)) {
313  std::string err_msg = formatter() << "destination hex not on map (excluding border): " << dst;
314  return void(luaL_argerror(L, 2, err_msg.c_str()));
315  }
316 
317  auto [unit_iterator, success] = gb->units().move(src, dst);
318 
319  if(success) {
320  unit_iterator->anim_comp().set_standing();
321  }
322  }
323  }
324 }
325 
326 LATTR_GETTER("valid", utils::optional<std::string>, lua_unit*, lu) {
327  const unit* pu = lu->get();
328  if(!pu) {
329  return utils::nullopt;
330  }
331  using namespace std::literals;
332  if(lu->on_map()) {
333  return "map"s;
334  } else if(lu->on_recall_list()) {
335  return "recall"s;
336  }
337  return "private"s;
338 }
339 
340 UNIT_GETTER("x", int) {
341  return u.get_location().wml_x();
342 }
343 
344 LATTR_SETTER("x", int, lua_unit*, lu) {
345  if(!lu->get()) return;
346  map_location loc = (*lu)->get_location();
347  loc.set_wml_x(value);
348  handle_unit_move(L, lu, loc);
349 }
350 
351 UNIT_GETTER("y", int) {
352  return u.get_location().wml_y();
353 }
354 
355 LATTR_SETTER("y", int, lua_unit*, lu) {
356  if(!lu->get()) return;
357  map_location loc = (*lu)->get_location();
358  loc.set_wml_y(value);
359  handle_unit_move(L, lu, loc);
360 }
361 
363  return u.get_location();
364 }
365 
367  if(!lu->get()) return;
368  handle_unit_move(L, lu, value);
369 }
370 
372  return u.get_goto();
373 }
374 
376  u.set_goto(value);
377 }
378 
379 UNIT_GETTER("side", int) {
380  return u.side();
381 }
382 
383 UNIT_SETTER("side", int) {
384  u.set_side(value);
385 }
386 
387 UNIT_GETTER("id", std::string) {
388  return u.id();
389 }
390 
391 LATTR_SETTER("id", std::string, lua_unit*, lu) {
392  if(!lu->get()) return;
393  if(lu->on_map()) luaL_argerror(L, 3, "can't modify id of on-map unit");
394  (*lu)->set_id(value);
395 }
396 
397 UNIT_GETTER("type", std::string) {
398  return u.type_id();
399 }
400 
401 UNIT_GETTER("image_mods", std::string) {
402  return u.effect_image_mods();
403 }
404 
405 UNIT_GETTER("usage", std::string) {
406  return u.usage();
407 }
408 
409 UNIT_SETTER("usage", std::string) {
410  u.set_usage(value);
411 }
412 
413 UNIT_GETTER("ellipse", std::string) {
414  return u.image_ellipse();
415 }
416 
417 UNIT_SETTER("ellipse", std::string) {
418  u.set_image_ellipse(value);
419 }
420 
421 UNIT_GETTER("halo", std::string) {
422  return u.image_halo();
423 }
424 
425 UNIT_SETTER("halo", std::string) {
426  u.set_image_halo(value);
427 }
428 
429 UNIT_GETTER("hitpoints", int) {
430  return u.hitpoints();
431 }
432 
433 UNIT_SETTER("hitpoints", int) {
434  u.set_hitpoints(value);
435 }
436 
437 UNIT_GETTER("max_hitpoints", int) {
438  return u.max_hitpoints();
439 }
440 
441 UNIT_SETTER("max_hitpoints", int) {
442  u.set_max_hitpoints(value);
443 }
444 
445 UNIT_GETTER("experience", int) {
446  return u.experience();
447 }
448 
449 UNIT_SETTER("experience", int) {
450  u.set_experience(value);
451 }
452 
453 UNIT_GETTER("max_experience", int) {
454  return u.max_experience();
455 }
456 
457 UNIT_SETTER("max_experience", int) {
458  u.set_max_experience(value);
459 }
460 
461 UNIT_GETTER("recall_cost", int) {
462  return u.recall_cost();
463 }
464 
465 UNIT_SETTER("recall_cost", int) {
466  u.set_recall_cost(value);
467 }
468 
469 UNIT_GETTER("moves", int) {
470  return u.movement_left();
471 }
472 
473 UNIT_SETTER("moves", int) {
474  u.set_movement(value);
475 }
476 
477 UNIT_GETTER("max_moves", int) {
478  return u.total_movement();
479 }
480 
481 UNIT_SETTER("max_moves", int) {
482  u.set_total_movement(value);
483 }
484 
485 UNIT_GETTER("max_attacks", int) {
486  return u.max_attacks();
487 }
488 
489 UNIT_SETTER("max_attacks", int) {
490  u.set_max_attacks(value);
491 }
492 
493 UNIT_GETTER("attacks_left", int) {
494  return u.attacks_left();
495 }
496 
497 UNIT_SETTER("attacks_left", int) {
498  u.set_attacks(value);
499 }
500 
501 UNIT_GETTER("vision", int) {
502  return u.vision();
503 }
504 
505 UNIT_GETTER("jamming", int) {
506  return u.jamming();
507 }
508 
510  return u.name();
511 }
512 
514  u.set_name(value);
515 }
516 
517 UNIT_GETTER("description", t_string) {
518  return u.unit_description();
519 }
520 
521 UNIT_SETTER("description", t_string) {
522  u.set_unit_description(value);
523 }
524 
525 UNIT_GETTER("canrecruit", bool) {
526  return u.can_recruit();
527 }
528 
529 UNIT_SETTER("canrecruit", bool) {
530  u.set_can_recruit(value);
531 }
532 
533 UNIT_GETTER("renamable", bool) {
534  return !u.unrenamable();
535 }
536 
537 UNIT_SETTER("renamable", bool) {
538  u.set_unrenamable(!value);
539 }
540 
541 UNIT_GETTER("level", int) {
542  return u.level();
543 }
544 
545 UNIT_SETTER("level", int) {
546  u.set_level(value);
547 }
548 
549 UNIT_GETTER("cost", int) {
550  return u.cost();
551 }
552 
553 UNIT_GETTER("extra_recruit", std::set<std::string>) {
554  return u.recruits();
555 }
556 
557 UNIT_SETTER("extra_recruit", std::vector<std::string>) {
558  u.set_recruits(value);
559 }
560 
561 UNIT_GETTER("advances_to", std::vector<std::string>) {
562  return u.advances_to();
563 }
564 
565 UNIT_SETTER("advances_to", std::vector<std::string>) {
566  u.set_advances_to(value);
567 }
568 
569 UNIT_GETTER("alignment", std::string) {
571 }
572 
573 UNIT_SETTER("alignment", lua_index_raw) {
574  auto alignment = unit_alignments::get_enum(lua_check<std::string_view>(L, value.index));
575  if(!alignment) luaL_argerror(L, value.index, "invalid unit alignment");
576  u.set_alignment(*alignment);
577 }
578 
580  unit::upkeep_t upkeep = u.upkeep_raw();
581 
582  // Need to keep these separate in order to ensure an int value is always used if applicable.
583  if(int* v = utils::get_if<int>(&upkeep)) {
584  lua_push(L, *v);
585  } else {
586  const std::string type = utils::visit(unit::upkeep_type_visitor(), upkeep);
587  lua_push(L, type);
588  }
589  return lua_index_raw(L);
590 }
591 
593  if(lua_isnumber(L, value.index)) {
594  u.set_upkeep(static_cast<int>(luaL_checkinteger(L, 3)));
595  return;
596  }
597  auto v = lua_check<std::string_view>(L, value.index);
598  if(v == "loyal" || v == "free") {
600  } else if(v == "full") {
602  } else {
603  std::string err_msg = "unknown upkeep value of unit: ";
604  err_msg += v;
605  luaL_argerror(L, 2, err_msg.c_str());
606  }
607  return;
608 }
609 
610 UNIT_GETTER("advancements", std::vector<config>) {
611  return u.modification_advancements();
612 }
613 
614 UNIT_SETTER("advancements", std::vector<config>) {
615  u.set_advancements(value);
616 }
617 
618 UNIT_GETTER("overlays", std::vector<std::string>) {
619  return u.overlays();
620 }
621 
622 UNIT_GETTER("traits", std::vector<std::string>) {
623  return u.get_traits_list();
624 }
625 
626 UNIT_GETTER("abilities", std::vector<std::string>) {
627  deprecated_message("unit.abilities", DEP_LEVEL::FOR_REMOVAL, version_info("1.21"), "Use unit.ability_ids instead.");
628  return u.get_ability_id_list();
629 }
630 
631 UNIT_GETTER("ability_ids", std::vector<std::string>) {
632  return u.get_ability_id_list();
633 }
634 
636  (void)u;
637  lua_createtable(L, 1, 0);
638  lua_pushvalue(L, 1);
639  lua_rawseti(L, -2, 1);
640  luaL_setmetatable(L, ustatusKey);
641  return lua_index_raw(L);
642 }
643 
644 UNIT_GETTER("variables", lua_index_raw) {
645  (void)u;
646  lua_createtable(L, 1, 0);
647  lua_pushvalue(L, 1);
648  lua_rawseti(L, -2, 1);
649  luaL_setmetatable(L, unitvarKey);
650  return lua_index_raw(L);
651 }
652 
654  (void)u;
656  return lua_index_raw(L);
657 }
658 
659 UNIT_GETTER("petrified", bool) {
660  deprecated_message("(unit).petrified", DEP_LEVEL::INDEFINITE, {1,17,0}, "use (unit).status.petrified instead");
661  return u.incapacitated();
662 }
663 
664 UNIT_GETTER("animations", std::vector<std::string>) {
665  return u.anim_comp().get_flags();
666 }
667 
668 UNIT_GETTER("recall_filter", config) {
669  return u.recall_filter();
670 }
671 
672 UNIT_SETTER("recall_filter", config) {
673  u.set_recall_filter(value);
674 }
675 
676 UNIT_GETTER("hidden", bool) {
677  return u.get_hidden();
678 }
679 
680 UNIT_SETTER("hidden", bool) {
681  u.set_hidden(value);
682 }
683 
684 UNIT_GETTER("resting", bool) {
685  return u.resting();
686 }
687 
688 UNIT_SETTER("resting", bool) {
689  u.set_resting(value);
690 }
691 
692 UNIT_GETTER("flying", bool) {
693  return u.is_flying();
694 }
695 
696 UNIT_GETTER("fearless", bool) {
697  return u.is_fearless();
698 }
699 
700 UNIT_GETTER("healthy", bool) {
701  return u.is_healthy();
702 }
703 
704 UNIT_GETTER("zoc", bool) {
705  return u.get_emit_zoc();
706 }
707 
708 UNIT_SETTER("zoc", bool) {
709  u.set_emit_zoc(value);
710 }
711 
712 UNIT_GETTER("role", std::string) {
713  return u.get_role();
714 }
715 
716 UNIT_SETTER("role", std::string) {
717  u.set_role(value);
718 }
719 
720 UNIT_GETTER("race", std::string) {
721  return u.race()->id();
722 }
723 
724 UNIT_GETTER("gender", std::string) {
725  return gender_string(u.gender());
726 }
727 
728 UNIT_GETTER("variation", std::string) {
729  return u.variation();
730 }
731 
732 UNIT_GETTER("undead_variation", std::string) {
733  return u.undead_variation();
734 }
735 
736 UNIT_SETTER("undead_variation", std::string) {
737  u.set_undead_variation(value);
738 }
739 
740 UNIT_GETTER("facing", std::string) {
742 }
743 
744 UNIT_SETTER("facing", std::string) {
746 }
747 
748 UNIT_GETTER("portrait", std::string) {
749  return u.big_profile() == u.absolute_image()
750  ? u.absolute_image() + u.image_mods() + "~SCALE_SHARP(144,144)"
751  : u.big_profile();
752 }
753 
754 UNIT_SETTER("portrait", std::string) {
755  u.set_big_profile(value);
756 }
757 
758 UNIT_GETTER("__cfg", config) {
759  config cfg;
760  u.write(cfg);
761  u.get_location().write(cfg);
762  return cfg;
763 }
764 
765 /**
766  * Gets some data on a unit (__index metamethod).
767  * - Arg 1: full userdata containing the unit id.
768  * - Arg 2: string containing the name of the property.
769  * - Ret 1: something containing the attribute.
770  */
771 static int impl_unit_get(lua_State *L)
772 {
773  return unitReg.get(L);
774 }
775 
776 /**
777  * Sets some data on a unit (__newindex metamethod).
778  * - Arg 1: full userdata containing the unit id.
779  * - Arg 2: string containing the name of the property.
780  * - Arg 3: something containing the attribute.
781  */
782 static int impl_unit_set(lua_State *L)
783 {
784  return unitReg.set(L);
785 }
786 
787 /**
788  * Prints valid attributes on a unit (__dir metamethod).
789  * - Arg 1: full userdata containing the unit id.
790  * - Arg 2: string containing the name of the property.
791  * - Ret 1: a list of attributes.
792  */
793 static int impl_unit_dir(lua_State *L)
794 {
795  return unitReg.dir(L);
796 }
797 
798 /**
799  * Gets the status of a unit (__index metamethod).
800  * - Arg 1: table containing the userdata containing the unit id.
801  * - Arg 2: string containing the name of the status.
802  * - Ret 1: boolean.
803  */
804 static int impl_unit_status_get(lua_State *L)
805 {
806  if(!lua_istable(L, 1)) {
807  return luaW_type_error(L, 1, "unit status");
808  }
809  lua_rawgeti(L, 1, 1);
810  const unit* u = luaW_tounit(L, -1);
811  if(!u) {
812  return luaL_argerror(L, 1, "unknown unit");
813  }
814  char const *m = luaL_checkstring(L, 2);
815  lua_pushboolean(L, u->get_state(m));
816  return 1;
817 }
818 
819 /**
820  * Sets the status of a unit (__newindex metamethod).
821  * - Arg 1: table containing the userdata containing the unit id.
822  * - Arg 2: string containing the name of the status.
823  * - Arg 3: boolean.
824  */
825 static int impl_unit_status_set(lua_State *L)
826 {
827  if(!lua_istable(L, 1)) {
828  return luaW_type_error(L, 1, "unit status");
829  }
830  lua_rawgeti(L, 1, 1);
831  unit* u = luaW_tounit(L, -1);
832  if(!u) {
833  return luaL_argerror(L, 1, "unknown unit");
834  }
835  char const *m = luaL_checkstring(L, 2);
836  u->set_state(m, luaW_toboolean(L, 3));
837  return 0;
838 }
839 
840 /**
841  * List statuses on a unit (__dir metamethod)
842  * This returns all known statuses (regardless of state) plus any currently set to true.
843  */
844 static int impl_unit_status_dir(lua_State *L)
845 {
846  if(!lua_istable(L, 1)) {
847  return luaW_type_error(L, 1, "unit status");
848  }
849  lua_rawgeti(L, 1, 1);
850  unit* u = luaW_tounit(L, -1);
851  if(!u) {
852  return luaL_argerror(L, 1, "unknown unit");
853  }
854  std::vector<std::string> states;
855  states.reserve(unit::NUMBER_OF_STATES);
857  states.push_back(unit::get_known_boolean_state_name(s));
858  }
859  for(auto s : u->get_states()) {
860  states.push_back(s);
861  }
862  lua_push(L, states);
863  return 1;
864 }
865 
866 /**
867  * Gets the variable of a unit (__index metamethod).
868  * - Arg 1: table containing the userdata containing the unit id.
869  * - Arg 2: string containing the name of the status.
870  * - Ret 1: boolean.
871  */
872 static int impl_unit_variables_get(lua_State *L)
873 {
874  if(!lua_istable(L, 1)) {
875  return luaW_type_error(L, 1, "unit variables");
876  }
877  lua_rawgeti(L, 1, 1);
878  const unit* u = luaW_tounit(L, -1);
879  if(!u) {
880  return luaL_argerror(L, 2, "unknown unit");
881  }
882  char const *m = luaL_checkstring(L, 2);
883  return_cfgref_attrib("__cfg", u->variables());
884 
885  variable_access_const v(m, u->variables());
886  return luaW_pushvariable(L, v) ? 1 : 0;
887 }
888 
889 /**
890  * Sets the variable of a unit (__newindex metamethod).
891  * - Arg 1: table containing the userdata containing the unit id.
892  * - Arg 2: string containing the name of the status.
893  * - Arg 3: scalar.
894  */
895 static int impl_unit_variables_set(lua_State *L)
896 {
897  if(!lua_istable(L, 1)) {
898  return luaW_type_error(L, 1, "unit variables");
899  }
900  lua_rawgeti(L, 1, 1);
901  unit* u = luaW_tounit(L, -1);
902  if(!u) {
903  return luaL_argerror(L, 2, "unknown unit");
904  }
905  char const *m = luaL_checkstring(L, 2);
906  modify_cfg_attrib("__cfg", u->variables() = cfg);
907  config& vars = u->variables();
908  if(lua_isnoneornil(L, 3)) {
909  try {
910  variable_access_throw(m, vars).clear(false);
911  } catch(const invalid_variablename_exception&) {
912  }
913  return 0;
914  }
915  variable_access_create v(m, vars);
916  luaW_checkvariable(L, v, 3);
917  return 0;
918 }
919 
920 /**
921  * List variables on a unit (__dir metamethod)
922  */
923 static int impl_unit_variables_dir(lua_State *L)
924 {
925  if(!lua_istable(L, 1)) {
926  return luaW_type_error(L, 1, "unit variables");
927  }
928  lua_rawgeti(L, 1, 1);
929  unit* u = luaW_tounit(L, -1);
930  if(!u) {
931  return luaL_argerror(L, 2, "unknown unit");
932  }
933  config& vars = u->variables();
934  std::vector<std::string> variables;
935  variables.reserve(vars.attribute_count() + vars.all_children_count());
936  for(const auto& attr : vars.attribute_range()) {
937  variables.push_back(attr.first);
938  }
939  for(auto [key, cfg] : vars.all_children_view()) {
940  variables.push_back(key);
941  }
942  lua_push(L, variables);
943  return 1;
944 }
945 
946 namespace lua_units {
947  std::string register_metatables(lua_State* L)
948  {
949  std::ostringstream cmd_out;
950 
951  // Create the getunit metatable.
952  cmd_out << "Adding getunit metatable...\n";
953 
954  luaL_newmetatable(L, getunitKey);
955  lua_pushcfunction(L, impl_unit_collect);
956  lua_setfield(L, -2, "__gc");
957  lua_pushcfunction(L, impl_unit_equality);
958  lua_setfield(L, -2, "__eq");
959  lua_pushcfunction(L, impl_unit_tostring);
960  lua_setfield(L, -2, "__tostring");
961  lua_pushcfunction(L, impl_unit_get);
962  lua_setfield(L, -2, "__index");
963  lua_pushcfunction(L, impl_unit_set);
964  lua_setfield(L, -2, "__newindex");
965  lua_pushcfunction(L, impl_unit_dir);
966  lua_setfield(L, -2, "__dir");
967  lua_pushstring(L, "unit");
968  lua_setfield(L, -2, "__metatable");
969 
970  // Create the unit status metatable.
971  cmd_out << "Adding unit status metatable...\n";
972 
973  luaL_newmetatable(L, ustatusKey);
974  lua_pushcfunction(L, impl_unit_status_get);
975  lua_setfield(L, -2, "__index");
976  lua_pushcfunction(L, impl_unit_status_set);
977  lua_setfield(L, -2, "__newindex");
978  lua_pushcfunction(L, impl_unit_status_dir);
979  lua_setfield(L, -2, "__dir");
980  lua_pushstring(L, "unit status");
981  lua_setfield(L, -2, "__metatable");
982 
983  // Create the unit variables metatable.
984  cmd_out << "Adding unit variables metatable...\n";
985 
986  luaL_newmetatable(L, unitvarKey);
987  lua_pushcfunction(L, impl_unit_variables_get);
988  lua_setfield(L, -2, "__index");
989  lua_pushcfunction(L, impl_unit_variables_set);
990  lua_setfield(L, -2, "__newindex");
991  lua_pushcfunction(L, impl_unit_variables_dir);
992  lua_setfield(L, -2, "__dir");
993  lua_pushstring(L, "unit variables");
994  lua_setfield(L, -2, "__metatable");
995 
996  return cmd_out.str();
997  }
998 }
map_location loc
Definition: move.cpp:172
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:157
std::size_t attribute_count() const
Count the number of non-blank attributes.
Definition: config.cpp:307
const_attr_itors attribute_range() const
Definition: config.cpp:740
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:795
std::size_t all_children_count() const
Definition: config.cpp:302
std::ostringstream wrapper.
Definition: formatter.hpp:40
team & get_team(int i)
Definition: game_board.hpp:92
virtual const unit_map & units() const override
Definition: game_board.hpp:107
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:239
std::vector< std::string > get_flags()
Get the flags of all registered animations.
unit_iterator find(std::size_t id)
Definition: map.cpp:302
umap_retval_pair_t replace(const map_location &l, const unit_ptr &p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:216
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
const std::string & id() const
Definition: race.hpp:35
This class represents a single unit of a specific type.
Definition: unit.hpp:39
Additional functionality for a non-const variable_info.
Information on a WML variable.
Represents version numbers.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
const config * cfg
Interfaces for manipulating version numbers of engine, add-ons, etc.
void write(config &cfg, bool write_all=true) const
Serializes the current unit metadata values.
Definition: unit.cpp:1566
std::vector< std::string > get_ability_id_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:719
void set_big_profile(const std::string &value)
Definition: unit.cpp:1959
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:427
void set_role(const std::string &role)
Sets a unit's role.
Definition: unit.hpp:597
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:397
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:826
void set_state(const std::string &state, bool value)
Set whether the unit is affected by a status effect.
Definition: unit.cpp:1495
int level() const
The current level of this unit.
Definition: unit.hpp:481
std::string usage() const
Gets this unit's usage.
Definition: unit.hpp:608
const std::string & get_role() const
Gets this unit's role.
Definition: unit.hpp:591
const std::set< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:546
void set_max_experience(int value)
Definition: unit.hpp:456
void set_max_hitpoints(int value)
Definition: unit.hpp:432
void set_hitpoints(int hp)
Sets the current hitpoint amount.
Definition: unit.hpp:439
bool unrenamable() const
Whether this unit can be renamed.
Definition: unit.hpp:342
const config & recall_filter() const
Gets the filter constraints upon which units this unit may recall, if able.
Definition: unit.hpp:574
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
Definition: unit.hpp:562
std::string big_profile() const
An optional profile image displays when this unit is 'speaking' via [message].
Definition: unit.cpp:1159
void set_level(int level)
Sets the current level of this unit.
Definition: unit.hpp:487
void set_hidden(bool state) const
Sets whether the unit is hidden on the map.
Definition: unit.cpp:2827
void set_recall_filter(const config &filter)
Sets the filter constraints upon which units this unit may recall, if able.
Definition: unit.hpp:580
const std::string & variation() const
The ID of the variation of this unit's type.
Definition: unit.hpp:494
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:421
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:555
static std::string get_known_boolean_state_name(state_t state)
Convert a built-in status effect ID to a string status effect ID.
Definition: unit.cpp:1474
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1436
void set_undead_variation(const std::string &value)
The ID of the undead variation (ie, dwarf, swimmer) of this unit.
Definition: unit.hpp:500
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1954
void set_alignment(unit_alignments::type alignment)
Sets the alignment of this unit.
Definition: unit.hpp:403
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:642
void set_name(const t_string &name)
Sets this unit's translatable display name.
Definition: unit.hpp:319
void set_can_recruit(bool canrecruit)
Sets whether this unit can recruit other units.
Definition: unit.hpp:540
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition: unit.cpp:1419
void set_side(unsigned int new_side)
Sets the side this unit belongs to.
Definition: unit.hpp:255
const std::string & undead_variation() const
Definition: unit.hpp:505
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:415
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:445
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:534
void set_experience(int xp)
Sets the current experience point amount.
Definition: unit.hpp:475
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:286
int side() const
The side this unit belongs to.
Definition: unit.hpp:249
state_t
Built-in status effects known to the engine.
Definition: unit.hpp:774
void set_unit_description(const t_string &new_desc)
A detailed description of this unit.
Definition: unit.hpp:378
void set_unrenamable(bool unrenamable)
Sets the 'unrenamable' flag.
Definition: unit.hpp:350
void set_recruits(const std::vector< std::string > &recruits)
Sets the recruit list.
Definition: unit.cpp:1268
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition: unit.hpp:625
void set_recall_cost(int recall_cost)
Sets the cost of recalling this unit.
Definition: unit.hpp:568
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:298
void set_usage(const std::string &usage)
Sets this unit's usage.
Definition: unit.hpp:614
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:451
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:387
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:309
t_string unit_description() const
A detailed description of this unit.
Definition: unit.hpp:372
@ STATE_SLOWED
Definition: unit.hpp:775
@ NUMBER_OF_STATES
The unit is invulnerable - it cannot be hit by any attack.
Definition: unit.hpp:783
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:150
void set_advancements(std::vector< config > advancements)
Sets the raw modification advancement option data.
Definition: unit.cpp:1948
void set_advances_to(const std::vector< std::string > &advances_to)
Sets this unit's advancement options.
Definition: unit.cpp:1298
const std::vector< config > & modification_advancements() const
The raw, unparsed data for modification advancements.
Definition: unit.hpp:229
void set_max_attacks(int value)
Definition: unit.hpp:889
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:884
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:900
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
Definition: unit.hpp:921
unit_animation_component & anim_comp() const
Definition: unit.hpp:1537
const std::string & effect_image_mods() const
Gets any IPF image mods applied by effects.
Definition: unit.hpp:1587
std::string image_ellipse() const
Get the unit's ellipse image.
Definition: unit.hpp:1566
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2788
std::string image_halo() const
Get the unit's halo image.
Definition: unit.hpp:1549
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
Definition: unit.hpp:1600
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2607
void set_image_ellipse(const std::string &ellipse)
Set the unit's ellipse image.
Definition: unit.hpp:1572
void set_image_halo(const std::string &halo)
Set the unit's halo image.
Definition: unit.cpp:2849
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1314
int jamming() const
Gets the unit's jamming points.
Definition: unit.hpp:1376
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1327
void set_movement(int moves, bool unit_action=false)
Set this unit's remaining movement to moves.
Definition: unit.cpp:1305
void set_resting(bool rest)
Sets this unit's resting status.
Definition: unit.hpp:1302
void set_facing(map_location::direction dir) const
The this unit's facing.
Definition: unit.cpp:1732
void set_total_movement(int value)
Definition: unit.hpp:1241
void set_emit_zoc(bool val)
Sets the raw zone-of-control flag.
Definition: unit.hpp:1320
void set_goto(const map_location &new_goto)
Sets this unit's long term destination.
Definition: unit.hpp:1364
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1252
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1236
int vision() const
Gets the unit's vision points.
Definition: unit.hpp:1370
const map_location & get_goto() const
The map location to which this unit is moving over multiple turns, if any.
Definition: unit.hpp:1358
map_location::direction facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1343
bool resting() const
Checks whether this unit is 'resting'.
Definition: unit.hpp:1296
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1436
bool is_healthy() const
Gets whether this unit is healthy - ie, always rest heals.
Definition: unit.hpp:1192
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1186
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
Definition: unit.hpp:1074
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
Definition: unit.hpp:1027
upkeep_t upkeep_raw() const
Gets the raw variant controlling the upkeep value.
Definition: unit.hpp:1169
void set_upkeep(upkeep_t v)
Sets the upkeep value to a specific value value.
Definition: unit.hpp:1175
T end(const std::pair< T, T > &p)
Standard logging facilities (interface).
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
#define return_cfgref_attrib(name, accessor)
Definition: lua_common.hpp:377
#define modify_cfg_attrib(name, accessor)
Definition: lua_common.hpp:483
LATTR_SETTER("x", int, lua_unit *, lu)
Definition: lua_unit.cpp:344
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:782
static int impl_unit_variables_dir(lua_State *L)
List variables on a unit (__dir metamethod)
Definition: lua_unit.cpp:923
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 int impl_unit_status_dir(lua_State *L)
List statuses on a unit (__dir metamethod) This returns all known statuses (regardless of state) plus...
Definition: lua_unit.cpp:844
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:804
#define UNIT_GETTER(name, type)
Definition: lua_unit.cpp:274
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:872
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:771
#define UNIT_SETTER(name, type)
Definition: lua_unit.cpp:275
static int impl_unit_variables_set(lua_State *L)
Sets the variable of a unit (__newindex metamethod).
Definition: lua_unit.cpp:895
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
LATTR_GETTER("valid", utils::optional< std::string >, lua_unit *, lu)
Definition: lua_unit.cpp:326
static void handle_unit_move(lua_State *L, lua_unit *lu, map_location dst)
Definition: lua_unit.cpp:294
static int impl_unit_status_set(lua_State *L)
Sets the status of a unit (__newindex metamethod).
Definition: lua_unit.cpp:825
luaW_Registry unitReg
Definition: lua_unit.cpp:276
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
static int impl_unit_dir(lua_State *L)
Prints valid attributes on a unit (__dir metamethod).
Definition: lua_unit.cpp:793
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
void push_unit_attacks_table(lua_State *L, int idx)
std::string register_metatables(lua_State *L)
Definition: lua_unit.cpp:947
game_board * gameboard
Definition: resources.cpp:20
std::size_t index(std::string_view 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
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
const std::string & gender_string(unit_race::GENDER gender)
Definition: race.cpp:140
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
int dir(lua_State *L)
Implement __dir metamethod.
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
Encapsulates the map of the game.
Definition: location.hpp:46
static std::string write_direction(direction dir)
Definition: location.cpp:154
void set_wml_y(int v)
Definition: location.hpp:190
int wml_y() const
Definition: location.hpp:187
void set_wml_x(int v)
Definition: location.hpp:189
int wml_x() const
Definition: location.hpp:186
static direction parse_direction(const std::string &str)
Definition: location.cpp:79
void write(config &cfg) const
Definition: location.cpp:223
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition: enum_base.hpp:57
Visitor helper struct to fetch the upkeep type flag if applicable, or the the value otherwise.
Definition: unit.hpp:1111
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
static map_location::direction s
variable_info_mutable< variable_info_implementation::vi_policy_throw > variable_access_throw
'Throw if nonexistent' access.