37 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
38 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
56 if (!ui.
valid())
return nullptr;
81 uid = unit_it->underlying_id();
83 ERR_LUA <<
"Could not move unit " <<
ptr->underlying_id() <<
" onto map location " << loc;
93 ERR_LUA <<
"Could not find unit " <<
uid <<
" on recall list of side " <<
side;
106 ERR_LUA <<
"Could not find unit " <<
uid <<
" on the map";
133 if(only_on_map && !lu->on_map()) {
159 return lu->get_shared();
175 luaL_argerror(L,
index,
"unit not found");
178 luaL_argerror(L,
index,
"unit not found on map");
188 return lu->get_shared();
225 u->lua_unit::~lua_unit();
237 lua_pushboolean(L, equal);
247 unit &u = *lu->get();
248 std::ostringstream str;
251 if(!u.
id().empty()) {
252 str << u.
id() <<
" ";
256 if(
int side = lu->on_recall_list()) {
257 str <<
"at (side " << side <<
" recall list)";
263 lua_push(L, str.str());
273 static int impl_unit_get(lua_State *L)
275 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
276 char const *m = luaL_checkstring(L, 2);
277 const unit* pu = lu->get();
279 if(strcmp(m, "valid") == 0) {
284 lua_pushstring(L, "map");
285 } else if(lu->on_recall_list()) {
286 lua_pushstring(L, "recall");
288 lua_pushstring(L, "private");
294 return luaL_argerror(L, 1, "unknown unit");
299 // Find the corresponding attribute.
300 return_int_attrib("x", u.get_location().wml_x());
301 return_int_attrib("y", u.get_location().wml_y());
302 if(strcmp(m, "loc") == 0) {
303 luaW_pushlocation(L, u.get_location());
306 if(strcmp(m, "goto") == 0) {
307 luaW_pushlocation(L, u.get_goto());
310 return_int_attrib("side", u.side());
311 return_string_attrib("id", u.id());
312 return_string_attrib("type", u.type_id());
313 return_string_attrib("image_mods", u.effect_image_mods());
314 return_string_attrib("usage", u.usage());
315 return_string_attrib("ellipse", u.image_ellipse());
316 return_string_attrib("halo", u.image_halo());
317 return_int_attrib("hitpoints", u.hitpoints());
318 return_int_attrib("max_hitpoints", u.max_hitpoints());
319 return_int_attrib("experience", u.experience());
320 return_int_attrib("max_experience", u.max_experience());
321 return_int_attrib("recall_cost", u.recall_cost());
322 return_int_attrib("moves", u.movement_left());
323 return_int_attrib("max_moves", u.total_movement());
324 return_int_attrib("max_attacks", u.max_attacks());
325 return_int_attrib("attacks_left", u.attacks_left());
326 return_int_attrib("vision", u.vision());
327 return_int_attrib("jamming", u.jamming());
328 return_tstring_attrib("name", u.name());
329 return_tstring_attrib("description", u.unit_description());
330 return_bool_attrib("canrecruit", u.can_recruit());
331 return_bool_attrib("renamable", !u.unrenamable());
332 return_int_attrib("level", u.level());
333 return_int_attrib("cost", u.cost());
335 return_vector_string_attrib("extra_recruit", u.recruits());
336 return_vector_string_attrib("advances_to", u.advances_to());
338 if(strcmp(m, "alignment") == 0) {
339 lua_push(L, unit_alignments::get_string(u.alignment()));
343 if(strcmp(m, "upkeep") == 0) {
344 unit::upkeep_t upkeep = u.upkeep_raw();
346 // Need to keep these separate in order to ensure an int value is always used if applicable.
347 if(int* v = utils::get_if<int>(&upkeep)) {
350 const std::string type = utils::visit(unit::upkeep_type_visitor{}, upkeep);
356 if(strcmp(m, "advancements") == 0) {
357 lua_push(L, u.modification_advancements());
360 if(strcmp(m, "overlays") == 0) {
361 lua_push(L, u.overlays());
364 if(strcmp(m, "traits") == 0) {
365 lua_push(L, u.get_traits_list());
368 if(strcmp(m, "abilities") == 0) {
369 lua_push(L, u.get_ability_list());
372 if(strcmp(m, "status") == 0) {
373 lua_createtable(L, 1, 0);
375 lua_rawseti(L, -2, 1);
376 luaL_setmetatable(L, ustatusKey);
379 if(strcmp(m, "variables") == 0) {
380 lua_createtable(L, 1, 0);
382 lua_rawseti(L, -2, 1);
383 luaL_setmetatable(L, unitvarKey);
386 if(strcmp(m, "attacks") == 0) {
387 push_unit_attacks_table(L, 1);
390 if(strcmp(m, "petrified") == 0) {
391 deprecated_message("(unit).petrified", DEP_LEVEL::INDEFINITE, {1,17,0}, "use (unit).status.petrified instead");
392 lua_pushboolean(L, u.incapacitated());
395 return_vector_string_attrib("animations", u.anim_comp().get_flags());
396 return_cfg_attrib("recall_filter", cfg = u.recall_filter());
397 return_bool_attrib("hidden", u.get_hidden());
398 return_bool_attrib("resting", u.resting());
399 return_string_attrib("role", u.get_role());
400 return_string_attrib("race", u.race()->id());
401 return_string_attrib("gender", gender_string(u.gender()));
402 return_string_attrib("variation", u.variation());
403 return_string_attrib("undead_variation", u.undead_variation());
404 return_bool_attrib("zoc", u.get_emit_zoc());
405 return_string_attrib("facing", map_location::write_direction(u.facing()));
406 return_string_attrib("portrait", u.big_profile() == u.absolute_image()
407 ? u.absolute_image() + u.image_mods() + "~XBRZ(2)"
409 return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
411 if(luaW_getglobal(L, "wesnoth", "units", m)) {
423 static int impl_unit_set(lua_State *L)
425 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
426 char const *m = luaL_checkstring(L, 2);
427 unit* pu = lu->get();
428 if (!pu) return luaL_argerror(L, 1, "unknown unit");
431 // Find the corresponding attribute.
432 //modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(teams().size())); TODO: Figure out if this is a good idea, to refer to teams() and make this depend on having a gamestate
433 modify_int_attrib("side", u.set_side(value));
434 modify_int_attrib("moves", u.set_movement(value));
435 modify_int_attrib("max_moves", u.set_total_movement(value));
436 modify_int_attrib("max_attacks", u.set_max_attacks(value));
437 modify_int_attrib("hitpoints", u.set_hitpoints(value));
438 modify_int_attrib("max_hitpoints", u.set_max_hitpoints(value));
439 modify_int_attrib("experience", u.set_experience(value));
440 modify_int_attrib("max_experience", u.set_max_experience(value));
441 modify_int_attrib("recall_cost", u.set_recall_cost(value));
442 modify_int_attrib("attacks_left", u.set_attacks(value));
443 modify_int_attrib("level", u.set_level(value));
444 modify_bool_attrib("resting", u.set_resting(value));
445 modify_tstring_attrib("name", u.set_name(value));
446 modify_tstring_attrib("description", u.set_unit_description(value));
447 modify_string_attrib("portrait", u.set_big_profile(value));
448 modify_string_attrib("role", u.set_role(value));
449 modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
450 modify_string_attrib("usage", u.set_usage(value));
451 modify_string_attrib("undead_variation", u.set_undead_variation(value));
452 modify_string_attrib("ellipse", u.set_image_ellipse(value));
453 modify_string_attrib("halo", u.set_image_halo(value));
454 modify_bool_attrib("hidden", u.set_hidden(value));
455 modify_bool_attrib("zoc", u.set_emit_zoc(value));
456 modify_bool_attrib("canrecruit", u.set_can_recruit(value));
457 modify_bool_attrib("renamable", u.set_unrenamable(!value));
458 modify_cfg_attrib("recall_filter", u.set_recall_filter(cfg));
460 modify_vector_string_attrib("extra_recruit", u.set_recruits(value));
461 modify_vector_string_attrib("advances_to", u.set_advances_to(value));
462 if(strcmp(m, "alignment") == 0) {
463 u.set_alignment(lua_enum_check<unit_alignments>(L, 3));
467 if(strcmp(m, "advancements") == 0) {
468 u.set_advancements(lua_check<std::vector<config>>(L, 3));
472 if(strcmp(m, "upkeep") == 0) {
473 if(lua_isnumber(L, 3)) {
474 u.set_upkeep(static_cast<int>(luaL_checkinteger(L, 3)));
477 const char* v = luaL_checkstring(L, 3);
478 if((strcmp(v, "loyal") == 0) || (strcmp(v, "free") == 0)) {
479 u.set_upkeep(unit::upkeep_loyal());
480 } else if(strcmp(v, "full") == 0) {
481 u.set_upkeep(unit::upkeep_full());
483 std::string err_msg = "unknown upkeep value of unit: ";
485 return luaL_argerror(L, 2, err_msg.c_str());
491 map_location loc = u.get_location();
492 modify_int_attrib("x", loc.set_wml_x(value); u.set_location(loc));
493 modify_int_attrib("y", loc.set_wml_y(value); u.set_location(loc));
494 modify_string_attrib("id", u.set_id(value));
495 if(strcmp(m, "loc") == 0) {
496 luaW_tolocation(L, 3, loc);
501 const bool is_key_x = strcmp(m, "x") == 0;
502 const bool is_key_y = strcmp(m, "y") == 0;
503 const bool is_loc_key = strcmp(m, "loc") == 0;
505 // Handle moving an on-map unit
506 if(is_key_x || is_key_y || is_loc_key) {
507 game_board* gb = resources::gameboard;
513 map_location src = u.get_location();
514 map_location dst = src;
517 dst.set_wml_x(luaL_checkinteger(L, 3));
518 } else if(is_key_y) {
519 dst.set_wml_y(luaL_checkinteger(L, 3));
521 dst = luaW_checklocation(L, 3);
524 // TODO: could probably be relegated to a helper function.
526 // If the dst isn'
t on the map, the
unit will be clobbered. Guard against that.
527 if(!gb->map().on_board(dst)) {
528 std::string err_msg =
formatter() <<
"destination hex not on map (excluding border): " << dst;
529 return luaL_argerror(L, 2, err_msg.c_str());
532 auto [unit_iterator,
success] = gb->units().move(src, dst);
535 unit_iterator->anim_comp().set_standing();
543 if(strcmp(m,
"goto") == 0) {
548 std::string err_msg =
"unknown modifiable property of unit: ";
550 return luaL_argerror(L, 2, err_msg.c_str());
561 if(!lua_istable(L, 1)) {
564 lua_rawgeti(L, 1, 1);
567 return luaL_argerror(L, 1,
"unknown unit");
569 char const *m = luaL_checkstring(L, 2);
582 if(!lua_istable(L, 1)) {
585 lua_rawgeti(L, 1, 1);
588 return luaL_argerror(L, 1,
"unknown unit");
590 char const *m = luaL_checkstring(L, 2);
603 if(!lua_istable(L, 1)) {
606 lua_rawgeti(L, 1, 1);
609 return luaL_argerror(L, 2,
"unknown unit");
611 char const *m = luaL_checkstring(L, 2);
626 if(!lua_istable(L, 1)) {
629 lua_rawgeti(L, 1, 1);
632 return luaL_argerror(L, 2,
"unknown unit");
634 char const *m = luaL_checkstring(L, 2);
637 if(lua_isnoneornil(L, 3)) {
652 std::ostringstream cmd_out;
655 cmd_out <<
"Adding getunit metatable...\n";
659 lua_setfield(L, -2,
"__gc");
661 lua_setfield(L, -2,
"__eq");
663 lua_setfield(L, -2,
"__tostring");
665 lua_setfield(L, -2,
"__index");
667 lua_setfield(L, -2,
"__newindex");
668 lua_pushstring(L,
"unit");
669 lua_setfield(L, -2,
"__metatable");
672 cmd_out <<
"Adding unit status metatable...\n";
676 lua_setfield(L, -2,
"__index");
678 lua_setfield(L, -2,
"__newindex");
679 lua_pushstring(L,
"unit status");
680 lua_setfield(L, -2,
"__metatable");
683 cmd_out <<
"Adding unit variables metatable...\n";
687 lua_setfield(L, -2,
"__index");
689 lua_setfield(L, -2,
"__newindex");
690 lua_pushstring(L,
"unit variables");
691 lua_setfield(L, -2,
"__metatable");
693 return cmd_out.str();
A config object defines a single node in a WML file, with access to child nodes.
virtual const unit_map & units() const override
Storage for a unit, either owned by the Lua code (ptr != 0), a local variable unit (c_ptr !...
static void setmetatable(lua_State *L)
bool put_map(const map_location &loc)
unit_ptr get_shared() const
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()
umap_retval_pair_t replace(const map_location &l, unit_ptr p)
Works like unit_map::add; but l is emptied first, if needed.
unit_iterator find(std::size_t id)
std::size_t erase(const map_location &l)
Erases the unit at location l, if any.
umap_retval_pair_t move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
This class represents a single unit of a specific type.
Additional functionality for a non-const variable_info.
Information on a WML variable.
Interfaces for manipulating version numbers of engine, add-ons, etc.
void set_state(const std::string &state, bool value)
Set whether the unit is affected by a status effect.
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
const std::string & type_id() const
The id of this unit's type.
const std::string & id() const
Gets this unit's id.
config & variables()
Gets any user-defined variables this unit 'owns'.
std::size_t underlying_id() const
This unit's unique internal ID.
const map_location & get_location() const
The current map location this unit is at.
void set_goto(const map_location &new_goto)
Sets this unit's long term destination.
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)
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
#define return_cfgref_attrib(name, accessor)
#define modify_cfg_attrib(name, accessor)
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...
static int impl_unit_set(lua_State *L)
Sets some data on a unit (__newindex metamethod).
static int impl_unit_equality(lua_State *L)
Checks two lua proxy units for equality.
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.
static void unit_show_error(lua_State *L, int index, int error)
static int impl_unit_status_get(lua_State *L)
Gets the status of a unit (__index metamethod).
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...
static int impl_unit_collect(lua_State *L)
Destroys a unit object before it is collected (__gc metamethod).
static const char unitvarKey[]
static int impl_unit_variables_get(lua_State *L)
Gets the variable of a unit (__index metamethod).
static lua_unit * internal_get_unit(lua_State *L, int index, bool only_on_map, int &error)
static int impl_unit_get(lua_State *L)
Gets some data on a unit (__index metamethod).
static int impl_unit_variables_set(lua_State *L)
Sets the variable of a unit (__newindex metamethod).
bool luaW_isunit(lua_State *L, int index)
Test if a Lua value is a unit.
static const char getunitKey[]
static const char ustatusKey[]
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...
static int impl_unit_status_set(lua_State *L)
Sets the status of a unit (__newindex metamethod).
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...
static int impl_unit_tostring(lua_State *L)
Turns a lua proxy unit to string.
lua_unit * luaW_pushlocalunit(lua_State *L, unit &u)
Pushes a private unit on the stack.
unit * luaW_tounit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
std::string register_metatables(lua_State *L)
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.
std::shared_ptr< unit > unit_ptr
Encapsulates the map of the game.
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
variable_info_mutable< variable_info_implementation::vi_policy_throw > variable_access_throw
'Throw if nonexistent' access.