35 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
36 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
54 if (!ui.
valid())
return nullptr;
79 uid = unit_it->underlying_id();
81 ERR_LUA <<
"Could not move unit " <<
ptr->underlying_id() <<
" onto map location " << loc;
91 ERR_LUA <<
"Could not find unit " <<
uid <<
" on recall list of side " <<
side;
104 ERR_LUA <<
"Could not find unit " <<
uid <<
" on the map";
131 if(only_on_map && !lu->on_map()) {
157 return lu->get_shared();
173 luaL_argerror(L,
index,
"unit not found");
176 luaL_argerror(L,
index,
"unit not found on map");
186 return lu->get_shared();
223 u->lua_unit::~lua_unit();
235 lua_pushboolean(L, equal);
245 unit &u = *lu->get();
246 std::ostringstream str;
249 if(!u.
id().empty()) {
250 str << u.
id() <<
" ";
254 if(
int side = lu->on_recall_list()) {
255 str <<
"at (side " << side <<
" recall list)";
261 lua_push(L, str.str());
271 static int impl_unit_get(lua_State *L)
273 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
274 char const *m = luaL_checkstring(L, 2);
275 const unit* pu = lu->get();
277 if(strcmp(m, "valid") == 0) {
282 lua_pushstring(L, "map");
283 } else if(lu->on_recall_list()) {
284 lua_pushstring(L, "recall");
286 lua_pushstring(L, "private");
292 return luaL_argerror(L, 1, "unknown unit");
297 // Find the corresponding attribute.
298 return_int_attrib("x", u.get_location().wml_x());
299 return_int_attrib("y", u.get_location().wml_y());
300 if(strcmp(m, "loc") == 0) {
301 luaW_pushlocation(L, u.get_location());
304 if(strcmp(m, "goto") == 0) {
305 luaW_pushlocation(L, u.get_goto());
308 return_int_attrib("side", u.side());
309 return_string_attrib("id", u.id());
310 return_string_attrib("type", u.type_id());
311 return_string_attrib("image_mods", u.effect_image_mods());
312 return_string_attrib("usage", u.usage());
313 return_string_attrib("ellipse", u.image_ellipse());
314 return_string_attrib("halo", u.image_halo());
315 return_int_attrib("hitpoints", u.hitpoints());
316 return_int_attrib("max_hitpoints", u.max_hitpoints());
317 return_int_attrib("experience", u.experience());
318 return_int_attrib("max_experience", u.max_experience());
319 return_int_attrib("recall_cost", u.recall_cost());
320 return_int_attrib("moves", u.movement_left());
321 return_int_attrib("max_moves", u.total_movement());
322 return_int_attrib("max_attacks", u.max_attacks());
323 return_int_attrib("attacks_left", u.attacks_left());
324 return_int_attrib("vision", u.vision());
325 return_int_attrib("jamming", u.jamming());
326 return_tstring_attrib("name", u.name());
327 return_tstring_attrib("description", u.unit_description());
328 return_bool_attrib("canrecruit", u.can_recruit());
329 return_bool_attrib("renamable", !u.unrenamable());
330 return_int_attrib("level", u.level());
331 return_int_attrib("cost", u.cost());
333 return_vector_string_attrib("extra_recruit", u.recruits());
334 return_vector_string_attrib("advances_to", u.advances_to());
336 if(strcmp(m, "alignment") == 0) {
337 lua_push(L, unit_alignments::get_string(u.alignment()));
341 if(strcmp(m, "upkeep") == 0) {
342 unit::upkeep_t upkeep = u.upkeep_raw();
344 // Need to keep these separate in order to ensure an int value is always used if applicable.
345 if(int* v = utils::get_if<int>(&upkeep)) {
348 const std::string type = utils::visit(unit::upkeep_type_visitor{}, upkeep);
354 if(strcmp(m, "advancements") == 0) {
355 lua_push(L, u.modification_advancements());
358 if(strcmp(m, "overlays") == 0) {
359 lua_push(L, u.overlays());
362 if(strcmp(m, "traits") == 0) {
363 lua_push(L, u.get_traits_list());
366 if(strcmp(m, "abilities") == 0) {
367 lua_push(L, u.get_ability_list());
370 if(strcmp(m, "status") == 0) {
371 lua_createtable(L, 1, 0);
373 lua_rawseti(L, -2, 1);
374 luaL_setmetatable(L, ustatusKey);
377 if(strcmp(m, "variables") == 0) {
378 lua_createtable(L, 1, 0);
380 lua_rawseti(L, -2, 1);
381 luaL_setmetatable(L, unitvarKey);
384 if(strcmp(m, "attacks") == 0) {
385 push_unit_attacks_table(L, 1);
388 if(strcmp(m, "petrified") == 0) {
389 deprecated_message("(unit).petrified", DEP_LEVEL::INDEFINITE, {1,17,0}, "use (unit).status.petrified instead");
390 lua_pushboolean(L, u.incapacitated());
393 return_vector_string_attrib("animations", u.anim_comp().get_flags());
394 return_cfg_attrib("recall_filter", cfg = u.recall_filter());
395 return_bool_attrib("hidden", u.get_hidden());
396 return_bool_attrib("resting", u.resting());
397 return_string_attrib("role", u.get_role());
398 return_string_attrib("race", u.race()->id());
399 return_string_attrib("gender", gender_string(u.gender()));
400 return_string_attrib("variation", u.variation());
401 return_string_attrib("undead_variation", u.undead_variation());
402 return_bool_attrib("zoc", u.get_emit_zoc());
403 return_string_attrib("facing", map_location::write_direction(u.facing()));
404 return_string_attrib("portrait", u.big_profile() == u.absolute_image()
405 ? u.absolute_image() + u.image_mods() + "~SCALE_SHARP(144,144)"
407 return_cfg_attrib("__cfg", u.write(cfg); u.get_location().write(cfg));
409 if(luaW_getglobal(L, "wesnoth", "units", m)) {
421 static int impl_unit_set(lua_State *L)
423 lua_unit *lu = static_cast<lua_unit *>(lua_touserdata(L, 1));
424 char const *m = luaL_checkstring(L, 2);
425 unit* pu = lu->get();
426 if (!pu) return luaL_argerror(L, 1, "unknown unit");
429 // Find the corresponding attribute.
430 //modify_int_attrib_check_range("side", u.set_side(value), 1, static_cast<int>(teams().size())); TODO: Figure out if this is a good idea, to refer to teams() and make this depend on having a gamestate
431 modify_int_attrib("side", u.set_side(value));
432 modify_int_attrib("moves", u.set_movement(value));
433 modify_int_attrib("max_moves", u.set_total_movement(value));
434 modify_int_attrib("max_attacks", u.set_max_attacks(value));
435 modify_int_attrib("hitpoints", u.set_hitpoints(value));
436 modify_int_attrib("max_hitpoints", u.set_max_hitpoints(value));
437 modify_int_attrib("experience", u.set_experience(value));
438 modify_int_attrib("max_experience", u.set_max_experience(value));
439 modify_int_attrib("recall_cost", u.set_recall_cost(value));
440 modify_int_attrib("attacks_left", u.set_attacks(value));
441 modify_int_attrib("level", u.set_level(value));
442 modify_bool_attrib("resting", u.set_resting(value));
443 modify_tstring_attrib("name", u.set_name(value));
444 modify_tstring_attrib("description", u.set_unit_description(value));
445 modify_string_attrib("portrait", u.set_big_profile(value));
446 modify_string_attrib("role", u.set_role(value));
447 modify_string_attrib("facing", u.set_facing(map_location::parse_direction(value)));
448 modify_string_attrib("usage", u.set_usage(value));
449 modify_string_attrib("undead_variation", u.set_undead_variation(value));
450 modify_string_attrib("ellipse", u.set_image_ellipse(value));
451 modify_string_attrib("halo", u.set_image_halo(value));
452 modify_bool_attrib("hidden", u.set_hidden(value));
453 modify_bool_attrib("zoc", u.set_emit_zoc(value));
454 modify_bool_attrib("canrecruit", u.set_can_recruit(value));
455 modify_bool_attrib("renamable", u.set_unrenamable(!value));
456 modify_cfg_attrib("recall_filter", u.set_recall_filter(cfg));
458 modify_vector_string_attrib("extra_recruit", u.set_recruits(value));
459 modify_vector_string_attrib("advances_to", u.set_advances_to(value));
460 if(strcmp(m, "alignment") == 0) {
461 u.set_alignment(lua_enum_check<unit_alignments>(L, 3));
465 if(strcmp(m, "advancements") == 0) {
466 u.set_advancements(lua_check<std::vector<config>>(L, 3));
470 if(strcmp(m, "upkeep") == 0) {
471 if(lua_isnumber(L, 3)) {
472 u.set_upkeep(static_cast<int>(luaL_checkinteger(L, 3)));
475 const char* v = luaL_checkstring(L, 3);
476 if((strcmp(v, "loyal") == 0) || (strcmp(v, "free") == 0)) {
477 u.set_upkeep(unit::upkeep_loyal());
478 } else if(strcmp(v, "full") == 0) {
479 u.set_upkeep(unit::upkeep_full());
481 std::string err_msg = "unknown upkeep value of unit: ";
483 return luaL_argerror(L, 2, err_msg.c_str());
489 map_location loc = u.get_location();
490 modify_int_attrib("x", loc.set_wml_x(value); u.set_location(loc));
491 modify_int_attrib("y", loc.set_wml_y(value); u.set_location(loc));
492 modify_string_attrib("id", u.set_id(value));
493 if(strcmp(m, "loc") == 0) {
494 luaW_tolocation(L, 3, loc);
499 const bool is_key_x = strcmp(m, "x") == 0;
500 const bool is_key_y = strcmp(m, "y") == 0;
501 const bool is_loc_key = strcmp(m, "loc") == 0;
503 // Handle moving an on-map unit
504 if(is_key_x || is_key_y || is_loc_key) {
505 game_board* gb = resources::gameboard;
511 map_location src = u.get_location();
512 map_location dst = src;
515 dst.set_wml_x(luaL_checkinteger(L, 3));
516 } else if(is_key_y) {
517 dst.set_wml_y(luaL_checkinteger(L, 3));
519 dst = luaW_checklocation(L, 3);
522 // TODO: could probably be relegated to a helper function.
524 // If the dst isn'
t on the map, the
unit will be clobbered. Guard against that.
525 if(!gb->map().on_board(dst)) {
526 std::string err_msg =
formatter() <<
"destination hex not on map (excluding border): " << dst;
527 return luaL_argerror(L, 2, err_msg.c_str());
530 auto [unit_iterator,
success] = gb->units().move(src, dst);
533 unit_iterator->anim_comp().set_standing();
541 if(strcmp(m,
"goto") == 0) {
546 std::string err_msg =
"unknown modifiable property of unit: ";
548 return luaL_argerror(L, 2, err_msg.c_str());
559 if(!lua_istable(L, 1)) {
562 lua_rawgeti(L, 1, 1);
565 return luaL_argerror(L, 1,
"unknown unit");
567 char const *m = luaL_checkstring(L, 2);
580 if(!lua_istable(L, 1)) {
583 lua_rawgeti(L, 1, 1);
586 return luaL_argerror(L, 1,
"unknown unit");
588 char const *m = luaL_checkstring(L, 2);
601 if(!lua_istable(L, 1)) {
604 lua_rawgeti(L, 1, 1);
607 return luaL_argerror(L, 2,
"unknown unit");
609 char const *m = luaL_checkstring(L, 2);
624 if(!lua_istable(L, 1)) {
627 lua_rawgeti(L, 1, 1);
630 return luaL_argerror(L, 2,
"unknown unit");
632 char const *m = luaL_checkstring(L, 2);
635 if(lua_isnoneornil(L, 3)) {
650 std::ostringstream cmd_out;
653 cmd_out <<
"Adding getunit metatable...\n";
657 lua_setfield(L, -2,
"__gc");
659 lua_setfield(L, -2,
"__eq");
661 lua_setfield(L, -2,
"__tostring");
663 lua_setfield(L, -2,
"__index");
665 lua_setfield(L, -2,
"__newindex");
666 lua_pushstring(L,
"unit");
667 lua_setfield(L, -2,
"__metatable");
670 cmd_out <<
"Adding unit status metatable...\n";
674 lua_setfield(L, -2,
"__index");
676 lua_setfield(L, -2,
"__newindex");
677 lua_pushstring(L,
"unit status");
678 lua_setfield(L, -2,
"__metatable");
681 cmd_out <<
"Adding unit variables metatable...\n";
685 lua_setfield(L, -2,
"__index");
687 lua_setfield(L, -2,
"__newindex");
688 lua_pushstring(L,
"unit variables");
689 lua_setfield(L, -2,
"__metatable");
691 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.