The Battle for Wesnoth  1.19.5+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"
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
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) {
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::vector<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  return u.get_ability_list();
628 }
629 
631  (void)u;
632  lua_createtable(L, 1, 0);
633  lua_pushvalue(L, 1);
634  lua_rawseti(L, -2, 1);
635  luaL_setmetatable(L, ustatusKey);
636  return lua_index_raw(L);
637 }
638 
639 UNIT_GETTER("variables", lua_index_raw) {
640  (void)u;
641  lua_createtable(L, 1, 0);
642  lua_pushvalue(L, 1);
643  lua_rawseti(L, -2, 1);
644  luaL_setmetatable(L, unitvarKey);
645  return lua_index_raw(L);
646 }
647 
649  (void)u;
651  return lua_index_raw(L);
652 }
653 
654 UNIT_GETTER("petrified", bool) {
655  deprecated_message("(unit).petrified", DEP_LEVEL::INDEFINITE, {1,17,0}, "use (unit).status.petrified instead");
656  return u.incapacitated();
657 }
658 
659 UNIT_GETTER("animations", std::vector<std::string>) {
660  return u.anim_comp().get_flags();
661 }
662 
663 UNIT_GETTER("recall_filter", config) {
664  return u.recall_filter();
665 }
666 
667 UNIT_SETTER("recall_filter", config) {
668  u.set_recall_filter(value);
669 }
670 
671 UNIT_GETTER("hidden", bool) {
672  return u.get_hidden();
673 }
674 
675 UNIT_SETTER("hidden", bool) {
676  u.set_hidden(value);
677 }
678 
679 UNIT_GETTER("resting", bool) {
680  return u.resting();
681 }
682 
683 UNIT_SETTER("resting", bool) {
684  u.set_resting(value);
685 }
686 
687 UNIT_GETTER("flying", bool) {
688  return u.is_flying();
689 }
690 
691 UNIT_GETTER("fearless", bool) {
692  return u.is_fearless();
693 }
694 
695 UNIT_GETTER("healthy", bool) {
696  return u.is_healthy();
697 }
698 
699 UNIT_GETTER("zoc", bool) {
700  return u.get_emit_zoc();
701 }
702 
703 UNIT_SETTER("zoc", bool) {
704  u.set_emit_zoc(value);
705 }
706 
707 UNIT_GETTER("role", std::string) {
708  return u.get_role();
709 }
710 
711 UNIT_SETTER("role", std::string) {
712  u.set_role(value);
713 }
714 
715 UNIT_GETTER("race", std::string) {
716  return u.race()->id();
717 }
718 
719 UNIT_GETTER("gender", std::string) {
720  return gender_string(u.gender());
721 }
722 
723 UNIT_GETTER("variation", std::string) {
724  return u.variation();
725 }
726 
727 UNIT_GETTER("undead_variation", std::string) {
728  return u.undead_variation();
729 }
730 
731 UNIT_SETTER("undead_variation", std::string) {
732  u.set_undead_variation(value);
733 }
734 
735 UNIT_GETTER("facing", std::string) {
737 }
738 
739 UNIT_SETTER("facing", std::string) {
741 }
742 
743 UNIT_GETTER("portrait", std::string) {
744  return u.big_profile() == u.absolute_image()
745  ? u.absolute_image() + u.image_mods() + "~SCALE_SHARP(144,144)"
746  : u.big_profile();
747 }
748 
749 UNIT_SETTER("portrait", std::string) {
750  u.set_big_profile(value);
751 }
752 
753 UNIT_GETTER("__cfg", config) {
754  config cfg;
755  u.write(cfg);
756  u.get_location().write(cfg);
757  return cfg;
758 }
759 
760 /**
761  * Gets some data on a unit (__index metamethod).
762  * - Arg 1: full userdata containing the unit id.
763  * - Arg 2: string containing the name of the property.
764  * - Ret 1: something containing the attribute.
765  */
766 static int impl_unit_get(lua_State *L)
767 {
768  return unitReg.get(L);
769 }
770 
771 /**
772  * Sets some data on a unit (__newindex metamethod).
773  * - Arg 1: full userdata containing the unit id.
774  * - Arg 2: string containing the name of the property.
775  * - Arg 3: something containing the attribute.
776  */
777 static int impl_unit_set(lua_State *L)
778 {
779  return unitReg.set(L);
780 }
781 
782 /**
783  * Prints valid attributes on a unit (__dir metamethod).
784  * - Arg 1: full userdata containing the unit id.
785  * - Arg 2: string containing the name of the property.
786  * - Ret 1: a list of attributes.
787  */
788 static int impl_unit_dir(lua_State *L)
789 {
790  return unitReg.dir(L);
791 }
792 
793 /**
794  * Gets the status of a unit (__index metamethod).
795  * - Arg 1: table containing the userdata containing the unit id.
796  * - Arg 2: string containing the name of the status.
797  * - Ret 1: boolean.
798  */
799 static int impl_unit_status_get(lua_State *L)
800 {
801  if(!lua_istable(L, 1)) {
802  return luaW_type_error(L, 1, "unit status");
803  }
804  lua_rawgeti(L, 1, 1);
805  const unit* u = luaW_tounit(L, -1);
806  if(!u) {
807  return luaL_argerror(L, 1, "unknown unit");
808  }
809  char const *m = luaL_checkstring(L, 2);
810  lua_pushboolean(L, u->get_state(m));
811  return 1;
812 }
813 
814 /**
815  * Sets the status of a unit (__newindex metamethod).
816  * - Arg 1: table containing the userdata containing the unit id.
817  * - Arg 2: string containing the name of the status.
818  * - Arg 3: boolean.
819  */
820 static int impl_unit_status_set(lua_State *L)
821 {
822  if(!lua_istable(L, 1)) {
823  return luaW_type_error(L, 1, "unit status");
824  }
825  lua_rawgeti(L, 1, 1);
826  unit* u = luaW_tounit(L, -1);
827  if(!u) {
828  return luaL_argerror(L, 1, "unknown unit");
829  }
830  char const *m = luaL_checkstring(L, 2);
831  u->set_state(m, luaW_toboolean(L, 3));
832  return 0;
833 }
834 
835 /**
836  * List statuses on a unit (__dir metamethod)
837  * This returns all known statuses (regardless of state) plus any currently set to true.
838  */
839 static int impl_unit_status_dir(lua_State *L)
840 {
841  if(!lua_istable(L, 1)) {
842  return luaW_type_error(L, 1, "unit status");
843  }
844  lua_rawgeti(L, 1, 1);
845  unit* u = luaW_tounit(L, -1);
846  if(!u) {
847  return luaL_argerror(L, 1, "unknown unit");
848  }
849  std::vector<std::string> states;
850  states.reserve(unit::NUMBER_OF_STATES);
852  states.push_back(unit::get_known_boolean_state_name(s));
853  }
854  for(auto s : u->get_states()) {
855  states.push_back(s);
856  }
857  lua_push(L, states);
858  return 1;
859 }
860 
861 /**
862  * Gets the variable of a unit (__index metamethod).
863  * - Arg 1: table containing the userdata containing the unit id.
864  * - Arg 2: string containing the name of the status.
865  * - Ret 1: boolean.
866  */
867 static int impl_unit_variables_get(lua_State *L)
868 {
869  if(!lua_istable(L, 1)) {
870  return luaW_type_error(L, 1, "unit variables");
871  }
872  lua_rawgeti(L, 1, 1);
873  const unit* u = luaW_tounit(L, -1);
874  if(!u) {
875  return luaL_argerror(L, 2, "unknown unit");
876  }
877  char const *m = luaL_checkstring(L, 2);
878  return_cfgref_attrib("__cfg", u->variables());
879 
880  variable_access_const v(m, u->variables());
881  return luaW_pushvariable(L, v) ? 1 : 0;
882 }
883 
884 /**
885  * Sets the variable of a unit (__newindex metamethod).
886  * - Arg 1: table containing the userdata containing the unit id.
887  * - Arg 2: string containing the name of the status.
888  * - Arg 3: scalar.
889  */
890 static int impl_unit_variables_set(lua_State *L)
891 {
892  if(!lua_istable(L, 1)) {
893  return luaW_type_error(L, 1, "unit variables");
894  }
895  lua_rawgeti(L, 1, 1);
896  unit* u = luaW_tounit(L, -1);
897  if(!u) {
898  return luaL_argerror(L, 2, "unknown unit");
899  }
900  char const *m = luaL_checkstring(L, 2);
901  modify_cfg_attrib("__cfg", u->variables() = cfg);
902  config& vars = u->variables();
903  if(lua_isnoneornil(L, 3)) {
904  try {
905  variable_access_throw(m, vars).clear(false);
906  } catch(const invalid_variablename_exception&) {
907  }
908  return 0;
909  }
910  variable_access_create v(m, vars);
911  luaW_checkvariable(L, v, 3);
912  return 0;
913 }
914 
915 /**
916  * List variables on a unit (__dir metamethod)
917  */
918 static int impl_unit_variables_dir(lua_State *L)
919 {
920  if(!lua_istable(L, 1)) {
921  return luaW_type_error(L, 1, "unit variables");
922  }
923  lua_rawgeti(L, 1, 1);
924  unit* u = luaW_tounit(L, -1);
925  if(!u) {
926  return luaL_argerror(L, 2, "unknown unit");
927  }
928  config& vars = u->variables();
929  std::vector<std::string> variables;
930  variables.reserve(vars.attribute_count() + vars.all_children_count());
931  for(const auto& attr : vars.attribute_range()) {
932  variables.push_back(attr.first);
933  }
934  for(auto [key, cfg] : vars.all_children_view()) {
935  variables.push_back(key);
936  }
937  lua_push(L, variables);
938  return 1;
939 }
940 
941 namespace lua_units {
942  std::string register_metatables(lua_State* L)
943  {
944  std::ostringstream cmd_out;
945 
946  // Create the getunit metatable.
947  cmd_out << "Adding getunit metatable...\n";
948 
949  luaL_newmetatable(L, getunitKey);
950  lua_pushcfunction(L, impl_unit_collect);
951  lua_setfield(L, -2, "__gc");
952  lua_pushcfunction(L, impl_unit_equality);
953  lua_setfield(L, -2, "__eq");
954  lua_pushcfunction(L, impl_unit_tostring);
955  lua_setfield(L, -2, "__tostring");
956  lua_pushcfunction(L, impl_unit_get);
957  lua_setfield(L, -2, "__index");
958  lua_pushcfunction(L, impl_unit_set);
959  lua_setfield(L, -2, "__newindex");
960  lua_pushcfunction(L, impl_unit_dir);
961  lua_setfield(L, -2, "__dir");
962  lua_pushstring(L, "unit");
963  lua_setfield(L, -2, "__metatable");
964 
965  // Create the unit status metatable.
966  cmd_out << "Adding unit status metatable...\n";
967 
968  luaL_newmetatable(L, ustatusKey);
969  lua_pushcfunction(L, impl_unit_status_get);
970  lua_setfield(L, -2, "__index");
971  lua_pushcfunction(L, impl_unit_status_set);
972  lua_setfield(L, -2, "__newindex");
973  lua_pushcfunction(L, impl_unit_status_dir);
974  lua_setfield(L, -2, "__dir");
975  lua_pushstring(L, "unit status");
976  lua_setfield(L, -2, "__metatable");
977 
978  // Create the unit variables metatable.
979  cmd_out << "Adding unit variables metatable...\n";
980 
981  luaL_newmetatable(L, unitvarKey);
982  lua_pushcfunction(L, impl_unit_variables_get);
983  lua_setfield(L, -2, "__index");
984  lua_pushcfunction(L, impl_unit_variables_set);
985  lua_setfield(L, -2, "__newindex");
986  lua_pushcfunction(L, impl_unit_variables_dir);
987  lua_setfield(L, -2, "__dir");
988  lua_pushstring(L, "unit variables");
989  lua_setfield(L, -2, "__metatable");
990 
991  return cmd_out.str();
992  }
993 }
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:172
std::size_t attribute_count() const
Count the number of non-blank attributes.
Definition: config.cpp:311
const_attr_itors attribute_range() const
Definition: config.cpp:760
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:810
std::size_t all_children_count() const
Definition: config.cpp:306
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:201
std::vector< std::string > get_flags()
Get the flags of all registered animations.
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
const std::string & id() const
Definition: race.hpp:36
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.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
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:1516
std::vector< std::string > get_ability_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:262
void set_big_profile(const std::string &value)
Definition: unit.cpp:1937
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:505
void set_role(const std::string &role)
Sets a unit's role.
Definition: unit.hpp:675
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:475
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:911
void set_state(const std::string &state, bool value)
Set whether the unit is affected by a status effect.
Definition: unit.cpp:1445
int level() const
The current level of this unit.
Definition: unit.hpp:559
std::string usage() const
Gets this unit's usage.
Definition: unit.hpp:686
const std::string & get_role() const
Gets this unit's role.
Definition: unit.hpp:669
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:624
void set_max_experience(int value)
Definition: unit.hpp:534
void set_max_hitpoints(int value)
Definition: unit.hpp:510
void set_hitpoints(int hp)
Sets the current hitpoint amount.
Definition: unit.hpp:517
bool unrenamable() const
Whether this unit can be renamed.
Definition: unit.hpp:436
const config & recall_filter() const
Gets the filter constraints upon which units this unit may recall, if able.
Definition: unit.hpp:652
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:640
std::string big_profile() const
An optional profile image displays when this unit is 'speaking' via [message].
Definition: unit.cpp:1118
void set_level(int level)
Sets the current level of this unit.
Definition: unit.hpp:565
void set_hidden(bool state) const
Sets whether the unit is hidden on the map.
Definition: unit.cpp:2776
void set_recall_filter(const config &filter)
Sets the filter constraints upon which units this unit may recall, if able.
Definition: unit.hpp:658
const std::string & variation() const
The ID of the variation of this unit's type.
Definition: unit.hpp:572
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:499
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:633
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:1424
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1386
void set_undead_variation(const std::string &value)
The ID of the undead variation (ie, dwarf, swimmer) of this unit.
Definition: unit.hpp:578
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1932
void set_alignment(unit_alignments::type alignment)
Sets the alignment of this unit.
Definition: unit.hpp:481
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:720
void set_name(const t_string &name)
Sets this unit's translatable display name.
Definition: unit.hpp:413
void set_can_recruit(bool canrecruit)
Sets whether this unit can recruit other units.
Definition: unit.hpp:618
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition: unit.cpp:1369
void set_side(unsigned int new_side)
Sets the side this unit belongs to.
Definition: unit.hpp:349
const std::string & undead_variation() const
Definition: unit.hpp:583
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:493
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:523
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:612
void set_experience(int xp)
Sets the current experience point amount.
Definition: unit.hpp:553
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:380
int side() const
The side this unit belongs to.
Definition: unit.hpp:343
state_t
Built-in status effects known to the engine.
Definition: unit.hpp:859
void set_unit_description(const t_string &new_desc)
A detailed description of this unit.
Definition: unit.hpp:456
void set_unrenamable(bool unrenamable)
Sets the 'unrenamable' flag.
Definition: unit.hpp:444
void set_recruits(const std::vector< std::string > &recruits)
Sets the recruit list.
Definition: unit.cpp:1227
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition: unit.hpp:703
void set_recall_cost(int recall_cost)
Sets the cost of recalling this unit.
Definition: unit.hpp:646
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:392
void set_usage(const std::string &usage)
Sets this unit's usage.
Definition: unit.hpp:692
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:529
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:465
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:403
t_string unit_description() const
A detailed description of this unit.
Definition: unit.hpp:450
@ STATE_SLOWED
Definition: unit.hpp:860
@ NUMBER_OF_STATES
The unit is invulnerable - it cannot be hit by any attack.
Definition: unit.hpp:868
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:244
void set_advancements(std::vector< config > advancements)
Sets the raw modification advancement option data.
Definition: unit.cpp:1926
void set_advances_to(const std::vector< std::string > &advances_to)
Sets this unit's advancement options.
Definition: unit.cpp:1248
const std::vector< config > & modification_advancements() const
The raw, unparsed data for modification advancements.
Definition: unit.hpp:323
void set_max_attacks(int value)
Definition: unit.hpp:989
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:984
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:1000
void set_attacks(int left)
Sets the number of attacks this unit has left this turn.
Definition: unit.hpp:1021
unit_animation_component & anim_comp() const
Definition: unit.hpp:1614
const std::string & effect_image_mods() const
Gets any IPF image mods applied by effects.
Definition: unit.hpp:1664
std::string image_ellipse() const
Get the unit's ellipse image.
Definition: unit.hpp:1643
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2737
std::string image_halo() const
Get the unit's halo image.
Definition: unit.hpp:1626
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
Definition: unit.hpp:1677
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2556
void set_image_ellipse(const std::string &ellipse)
Set the unit's ellipse image.
Definition: unit.hpp:1649
void set_image_halo(const std::string &halo)
Set the unit's halo image.
Definition: unit.cpp:2789
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1391
int jamming() const
Gets the unit's jamming points.
Definition: unit.hpp:1453
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1404
void set_movement(int moves, bool unit_action=false)
Set this unit's remaining movement to moves.
Definition: unit.cpp:1255
void set_resting(bool rest)
Sets this unit's resting status.
Definition: unit.hpp:1379
void set_facing(map_location::direction dir) const
The this unit's facing.
Definition: unit.cpp:1681
void set_total_movement(int value)
Definition: unit.hpp:1318
void set_emit_zoc(bool val)
Sets the raw zone-of-control flag.
Definition: unit.hpp:1397
void set_goto(const map_location &new_goto)
Sets this unit's long term destination.
Definition: unit.hpp:1441
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1329
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1313
int vision() const
Gets the unit's vision points.
Definition: unit.hpp:1447
const map_location & get_goto() const
The map location to which this unit is moving over multiple turns, if any.
Definition: unit.hpp:1435
map_location::direction facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1420
bool resting() const
Checks whether this unit is 'resting'.
Definition: unit.hpp:1373
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1513
bool is_healthy() const
Gets whether this unit is healthy - ie, always rest heals.
Definition: unit.hpp:1300
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1294
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
Definition: unit.hpp:1182
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
Definition: unit.hpp:1135
upkeep_t upkeep_raw() const
Gets the raw variant controlling the upkeep value.
Definition: unit.hpp:1277
void set_upkeep(upkeep_t v)
Sets the upkeep value to a specific value value.
Definition: unit.hpp:1283
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)
Definition: lua_common.cpp:998
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:309
#define modify_cfg_attrib(name, accessor)
Definition: lua_common.hpp:415
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:777
static int impl_unit_variables_dir(lua_State *L)
List variables on a unit (__dir metamethod)
Definition: lua_unit.cpp:918
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:839
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:799
#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:867
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:766
#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:890
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:820
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:788
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:942
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
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:139
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:45
static std::string write_direction(direction dir)
Definition: location.cpp:154
void set_wml_y(int v)
Definition: location.hpp:187
int wml_y() const
Definition: location.hpp:184
void set_wml_x(int v)
Definition: location.hpp:186
int wml_x() const
Definition: location.hpp:183
static direction parse_direction(const std::string &str)
Definition: location.cpp:79
void write(config &cfg) const
Definition: location.cpp:225
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:1219
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.