The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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
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"
28#include "units/unit.hpp"
29#include "units/map.hpp"
32#include "game_version.hpp"
33#include "deprecation.hpp"
34#include <vector>
35
36static 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
40static const char getunitKey[] = "unit";
41static const char ustatusKey[] = "unit status";
42static const char unitvarKey[] = "unit variables";
43
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
113bool luaW_isunit(lua_State* L, int index)
114{
115 return luaL_testudata(L, index,getunitKey) != nullptr;
116}
117
118enum {
123};
124
125static 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*>(luaL_checkudata(L, index, getunitKey));
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
142unit* 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
152unit_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
162lua_unit* luaW_tounit_ref(lua_State *L, int index)
163{
164 int error;
165 return internal_get_unit(L, index, false, error);
166}
167
168static 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
183unit_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
191unit& 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
199lua_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
207void lua_unit::setmetatable(lua_State *L)
208{
209 luaL_setmetatable(L, getunitKey);
210}
211
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 */
222static int impl_unit_collect(lua_State *L)
223{
224 lua_unit *u = static_cast<lua_unit *>(luaL_checkudata(L, 1, getunitKey));
225 u->lua_unit::~lua_unit();
226 return 0;
227}
228
229/**
230 * Checks two lua proxy units for equality. (__eq metamethod)
231 */
232static 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 */
244static 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)
276luaW_Registry unitReg{"wesnoth", "units", getunitKey};
277
278template<> 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
287template<> 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
294static 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
302
303 if(!gb) {
304 return;
305 }
306
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
326LATTR_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
340UNIT_GETTER("x", int) {
341 return u.get_location().wml_x();
342}
343
344LATTR_SETTER("x", int, lua_unit*, lu) {
345 if(!lu->get()) return;
346 map_location loc = (*lu)->get_location();
348 handle_unit_move(L, lu, loc);
349}
350
351UNIT_GETTER("y", int) {
352 return u.get_location().wml_y();
353}
354
355LATTR_SETTER("y", int, lua_unit*, lu) {
356 if(!lu->get()) return;
357 map_location loc = (*lu)->get_location();
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
379UNIT_GETTER("side", int) {
380 return u.side();
381}
382
383UNIT_SETTER("side", int) {
384 u.set_side(value);
385}
386
387UNIT_GETTER("id", std::string) {
388 return u.id();
389}
390
391LATTR_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
397UNIT_GETTER("type", std::string) {
398 return u.type_id();
399}
400
401UNIT_GETTER("image_mods", std::string) {
402 return u.effect_image_mods();
403}
404
405UNIT_GETTER("usage", std::string) {
406 return u.usage();
407}
408
409UNIT_SETTER("usage", std::string) {
410 u.set_usage(value);
411}
412
413UNIT_GETTER("ellipse", std::string) {
414 return u.image_ellipse();
415}
416
417UNIT_SETTER("ellipse", std::string) {
418 u.set_image_ellipse(value);
419}
420
421UNIT_GETTER("halo", std::string) {
422 return u.image_halo();
423}
424
425UNIT_SETTER("halo", std::string) {
426 u.set_image_halo(value);
427}
428
429UNIT_GETTER("hitpoints", int) {
430 return u.hitpoints();
431}
432
433UNIT_SETTER("hitpoints", int) {
434 u.set_hitpoints(value);
435}
436
437UNIT_GETTER("max_hitpoints", int) {
438 return u.max_hitpoints();
439}
440
441UNIT_SETTER("max_hitpoints", int) {
442 u.set_max_hitpoints(value);
443}
444
445UNIT_GETTER("experience", int) {
446 return u.experience();
447}
448
449UNIT_SETTER("experience", int) {
450 u.set_experience(value);
451}
452
453UNIT_GETTER("max_experience", int) {
454 return u.max_experience();
455}
456
457UNIT_SETTER("max_experience", int) {
458 u.set_max_experience(value);
459}
460
461UNIT_GETTER("recall_cost", int) {
462 return u.recall_cost();
463}
464
465UNIT_SETTER("recall_cost", int) {
466 u.set_recall_cost(value);
467}
468
469UNIT_GETTER("moves", int) {
470 return u.movement_left();
471}
472
473UNIT_SETTER("moves", int) {
474 u.set_movement(value);
475}
476
477UNIT_GETTER("max_moves", int) {
478 return u.total_movement();
479}
480
481UNIT_SETTER("max_moves", int) {
482 u.set_total_movement(value);
483}
484
485UNIT_GETTER("max_attacks", int) {
486 return u.max_attacks();
487}
488
489UNIT_SETTER("max_attacks", int) {
490 u.set_max_attacks(value);
491}
492
493UNIT_GETTER("attacks_left", int) {
494 return u.attacks_left();
495}
496
497UNIT_SETTER("attacks_left", int) {
498 u.set_attacks(value);
499}
500
501UNIT_GETTER("vision", int) {
502 return u.vision();
503}
504
505UNIT_GETTER("jamming", int) {
506 return u.jamming();
507}
508
510 return u.name();
511}
512
514 u.set_name(value);
515}
516
517UNIT_GETTER("description", t_string) {
518 return u.unit_description();
519}
520
521UNIT_SETTER("description", t_string) {
522 u.set_unit_description(value);
523}
524
525UNIT_GETTER("canrecruit", bool) {
526 return u.can_recruit();
527}
528
529UNIT_SETTER("canrecruit", bool) {
530 u.set_can_recruit(value);
531}
532
533UNIT_GETTER("renamable", bool) {
534 return !u.unrenamable();
535}
536
537UNIT_SETTER("renamable", bool) {
538 u.set_unrenamable(!value);
539}
540
541UNIT_GETTER("level", int) {
542 return u.level();
543}
544
545UNIT_SETTER("level", int) {
546 u.set_level(value);
547}
548
549UNIT_GETTER("cost", int) {
550 return u.cost();
551}
552
553UNIT_GETTER("extra_recruit", std::set<std::string>) {
554 return u.recruits();
555}
556
557UNIT_SETTER("extra_recruit", std::vector<std::string>) {
558 u.set_recruits(value);
559}
560
561UNIT_GETTER("advances_to", std::vector<std::string>) {
562 return u.advances_to();
563}
564
565UNIT_SETTER("advances_to", std::vector<std::string>) {
566 u.set_advances_to(value);
567}
568
569UNIT_GETTER("alignment", std::string) {
570 return unit_alignments::get_string(u.alignment());
571}
572
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") {
599 u.set_upkeep(unit::upkeep_loyal());
600 } else if(v == "full") {
601 u.set_upkeep(unit::upkeep_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
610UNIT_GETTER("advancements", std::vector<config>) {
611 return u.modification_advancements();
612}
613
614UNIT_SETTER("advancements", std::vector<config>) {
615 u.set_advancements(value);
616}
617
618UNIT_GETTER("overlays", std::vector<std::string>) {
619 return u.overlays();
620}
621
622UNIT_GETTER("traits", std::vector<std::string>) {
623 return u.get_traits_list();
624}
625
626UNIT_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
631UNIT_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
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
659UNIT_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
664UNIT_GETTER("animations", std::vector<std::string>) {
665 return u.anim_comp().get_flags();
666}
667
668UNIT_GETTER("recall_filter", config) {
669 return u.recall_filter();
670}
671
672UNIT_SETTER("recall_filter", config) {
673 u.set_recall_filter(value);
674}
675
676UNIT_GETTER("hidden", bool) {
677 return u.get_hidden();
678}
679
680UNIT_SETTER("hidden", bool) {
681 u.set_hidden(value);
682}
683
684UNIT_GETTER("resting", bool) {
685 return u.resting();
686}
687
688UNIT_SETTER("resting", bool) {
689 u.set_resting(value);
690}
691
692UNIT_GETTER("flying", bool) {
693 return u.is_flying();
694}
695
696UNIT_GETTER("fearless", bool) {
697 return u.is_fearless();
698}
699
700UNIT_GETTER("healthy", bool) {
701 return u.is_healthy();
702}
703
704UNIT_GETTER("zoc", bool) {
705 return u.get_emit_zoc();
706}
707
708UNIT_SETTER("zoc", bool) {
709 u.set_emit_zoc(value);
710}
711
712UNIT_GETTER("role", std::string) {
713 return u.get_role();
714}
715
716UNIT_SETTER("role", std::string) {
717 u.set_role(value);
718}
719
720UNIT_GETTER("race", std::string) {
721 return u.race()->id();
722}
723
724UNIT_GETTER("gender", std::string) {
725 return gender_string(u.gender());
726}
727
728UNIT_GETTER("variation", std::string) {
729 return u.variation();
730}
731
732UNIT_GETTER("undead_variation", std::string) {
733 return u.undead_variation();
734}
735
736UNIT_SETTER("undead_variation", std::string) {
737 u.set_undead_variation(value);
738}
739
740UNIT_GETTER("facing", std::string) {
741 return map_location::write_direction(u.facing());
742}
743
744UNIT_SETTER("facing", std::string) {
746}
747
748UNIT_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
754UNIT_SETTER("portrait", std::string) {
755 u.set_big_profile(value);
756}
757
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 */
771static 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 */
782static 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 */
793static 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 */
804static 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 */
825static 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 */
844static 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 */
872static 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
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 */
895static 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 */
923static 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
946namespace 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
#define ERR_LUA
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
void clear()
Definition config.cpp:802
std::ostringstream wrapper.
Definition formatter.hpp:40
Game board class.
virtual const gamemap & map() const override
team & get_team(int i)
virtual const unit_map & units() const override
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition map.cpp:347
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
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
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:242
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
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)
const config * cfg
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:1505
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:1484
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition unit.cpp:1446
const std::string & type_id() const
The id of this unit's type.
Definition unit.cpp:1964
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition unit.cpp:1429
const std::string & id() const
Gets this unit's id.
Definition unit.hpp:286
state_t
Built-in status effects known to the engine.
Definition unit.hpp:774
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition unit.hpp:625
std::size_t underlying_id() const
This unit's unique internal ID.
Definition unit.hpp:298
@ 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 map_location & get_location() const
The current map location this unit is at.
Definition unit.hpp:1327
utils::variant< upkeep_full, upkeep_loyal, int > upkeep_t
Definition unit.hpp:1074
Standard logging facilities (interface).
#define LATTR_SETTER(name, value_type, obj_type, obj_name)
#define LATTR_GETTER(name, value_type, obj_type, obj_name)
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)
#define modify_cfg_attrib(name, accessor)
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
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")
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
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 int impl_unit_get(lua_State *L)
Gets some data on a unit (__index metamethod).
Definition lua_unit.cpp:771
lua_unit * luaW_pushlocalunit(lua_State *L, unit &u)
Pushes a private unit on the stack.
Definition lua_unit.cpp:212
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 lua_unit * internal_get_unit(lua_State *L, int index, bool only_on_map, int &error)
Definition lua_unit.cpp:125
#define UNIT_SETTER(name, type)
Definition lua_unit.cpp:275
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_variables_set(lua_State *L)
Sets the variable of a unit (__newindex metamethod).
Definition lua_unit.cpp:895
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
bool luaW_isunit(lua_State *L, int index)
Test if a Lua value is a unit.
Definition lua_unit.cpp:113
static const char getunitKey[]
Definition lua_unit.cpp:40
static const char ustatusKey[]
Definition lua_unit.cpp:41
@ LU_NOT_ON_MAP
Definition lua_unit.cpp:121
@ LU_NOT_VALID
Definition lua_unit.cpp:122
@ LU_OK
Definition lua_unit.cpp:119
@ LU_NOT_UNIT
Definition lua_unit.cpp:120
unit_ptr luaW_checkunit_ptr(lua_State *L, int index, bool only_on_map)
Similar to luaW_checkunit but returns a unit_ptr; use this instead of luaW_checkunit when using an ap...
Definition lua_unit.cpp:183
static 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
static int impl_unit_dir(lua_State *L)
Prints valid attributes on a unit (__dir metamethod).
Definition lua_unit.cpp:793
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
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
T end(const std::pair< T, T > &p)
std::shared_ptr< unit > unit_ptr
Definition ptr.hpp:26
void lua_push(lua_State *L, const T &val)
const std::string & gender_string(unit_race::GENDER gender)
Definition race.cpp:140
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
static lua_unit * get(lua_State *L, int n)
Definition lua_unit.cpp:280
static unit & get(lua_State *L, int n)
Definition lua_unit.cpp:289
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
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
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 n
static map_location::direction s
variable_info_mutable< variable_info_implementation::vi_policy_throw > variable_access_throw
'Throw if nonexistent' access.