The Battle for Wesnoth  1.15.11+dev
game_lua_kernel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Provides a Lua interpreter, to be embedded in WML.
18  *
19  * @note Naming conventions:
20  * - intf_ functions are exported in the wesnoth domain,
21  * - impl_ functions are hidden inside metatables,
22  * - cfun_ functions are closures,
23  * - luaW_ functions are helpers in Lua style.
24  */
25 
27 
28 #include "actions/attack.hpp" // for battle_context_unit_stats, etc
29 #include "actions/advancement.hpp" // for advance_unit_at, etc
30 #include "actions/move.hpp" // for clear_shroud
31 #include "actions/vision.hpp" // for clear_shroud
32 #include "ai/composite/ai.hpp" // for ai_composite
33 #include "ai/composite/component.hpp" // for component, etc
34 #include "ai/composite/contexts.hpp" // for ai_context
35 #include "ai/lua/engine_lua.hpp" // for engine_lua
36 #include "ai/composite/rca.hpp" // for candidate_action
37 #include "ai/composite/stage.hpp" // for stage
38 #include "ai/configuration.hpp" // for configuration
39 #include "ai/lua/core.hpp" // for lua_ai_context, etc
40 #include "ai/manager.hpp" // for manager, holder
41 #include "attack_prediction.hpp" // for combatant
42 #include "chat_events.hpp" // for chat_handler, etc
43 #include "config.hpp" // for config, etc
44 #include "display_chat_manager.hpp" // for clear_chat_messages
45 #include "floating_label.hpp"
46 #include "formatter.hpp"
47 #include "game_board.hpp" // for game_board
48 #include "game_classification.hpp" // for game_classification, etc
49 #include "game_config.hpp" // for debug, base_income, etc
50 #include "game_config_manager.hpp" // for game_config_manager
51 #include "game_data.hpp" // for game_data, etc
52 #include "game_display.hpp" // for game_display
53 #include "game_errors.hpp" // for game_error
54 #include "game_events/conditional_wml.hpp" // for conditional_passed
56 #include "game_events/pump.hpp" // for queued_event
57 #include "preferences/game.hpp" // for encountered_units
58 #include "help/help.hpp"
59 #include "log.hpp" // for LOG_STREAM, logger, etc
60 #include "utils/make_enum.hpp" // for operator<<
61 #include "map/map.hpp" // for gamemap
62 #include "map/label.hpp"
63 #include "map/location.hpp" // for map_location
64 #include "mouse_events.hpp" // for mouse_handler
65 #include "mp_game_settings.hpp" // for mp_game_settings
66 #include "pathfind/pathfind.hpp" // for full_cost_map, plain_route, etc
67 #include "pathfind/teleport.hpp" // for get_teleport_locations, etc
68 #include "play_controller.hpp" // for play_controller
69 #include "recall_list_manager.hpp" // for recall_list_manager
70 #include "replay.hpp" // for get_user_choice, etc
71 #include "reports.hpp" // for register_generator, etc
72 #include "resources.hpp" // for whiteboard
73 #include "scripting/lua_audio.hpp"
74 #include "scripting/lua_unit.hpp"
76 #include "scripting/lua_common.hpp"
78 #include "scripting/lua_gui2.hpp" // for show_gamestate_inspector
80 #include "scripting/lua_race.hpp"
81 #include "scripting/lua_team.hpp"
84 #include "scripting/push_check.hpp"
85 #include "synced_commands.hpp"
86 #include "color.hpp" // for surface
87 #include "sdl/surface.hpp" // for surface
88 #include "side_filter.hpp" // for side_filter
89 #include "sound.hpp" // for commit_music_changes, etc
90 #include "soundsource.hpp"
91 #include "synced_context.hpp" // for synced_context, etc
92 #include "synced_user_choice.hpp"
93 #include "team.hpp" // for team, village_owner
94 #include "terrain/terrain.hpp" // for terrain_type
95 #include "terrain/filter.hpp" // for terrain_filter
96 #include "terrain/translation.hpp" // for read_terrain_code, etc
97 #include "time_of_day.hpp" // for time_of_day
98 #include "tod_manager.hpp" // for tod_manager
99 #include "tstring.hpp" // for t_string, operator+
100 #include "units/unit.hpp" // for unit
101 #include "units/animation_component.hpp" // for unit_animation_component
102 #include "units/udisplay.hpp"
103 #include "units/filter.hpp"
104 #include "units/map.hpp" // for unit_map, etc
105 #include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
106 #include "units/types.hpp" // for unit_type_data, unit_types, etc
107 #include "variable.hpp" // for vconfig, etc
108 #include "variable_info.hpp"
109 #include "whiteboard/manager.hpp" // for whiteboard
110 #include "wml_exception.hpp"
111 #include "deprecation.hpp"
112 
113 #include <functional> // for bind_t, bind
114 #include <array>
115 #include <cassert> // for assert
116 #include <cstring> // for strcmp
117 #include <iterator> // for distance, advance
118 #include <map> // for map, map<>::value_type, etc
119 #include <new> // for operator new
120 #include <set> // for set
121 #include <sstream> // for operator<<, basic_ostream, etc
122 #include <utility> // for pair
123 #include <algorithm>
124 #include <vector> // for vector, etc
125 #include <SDL2/SDL_timer.h> // for SDL_GetTicks
126 #include "lua/lauxlib.h" // for luaL_checkinteger, etc
127 #include "lua/lua.h" // for lua_setfield, etc
128 
129 class CVideo;
130 
131 #ifdef DEBUG_LUA
132 #include "scripting/debug_lua.hpp"
133 #endif
134 
135 static lg::log_domain log_scripting_lua("scripting/lua");
136 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
137 #define WRN_LUA LOG_STREAM(warn, log_scripting_lua)
138 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
139 
140 std::vector<config> game_lua_kernel::preload_scripts;
142 
143 // Template which allows to push member functions to the lua kernel base into lua as C functions, using a shim
145 
146 template <member_callback method>
148  return ((lua_kernel_base::get_lua_kernel<game_lua_kernel>(L)).*method)(L);
149 }
150 
151 // Pass a const bool also...
152 typedef int (game_lua_kernel::*member_callback2)(lua_State *, bool);
153 
154 template <member_callback2 method, bool b>
156  return ((lua_kernel_base::get_lua_kernel<game_lua_kernel>(L)).*method)(L, b);
157 }
158 
160 {
161  map_locker(game_lua_kernel* kernel) : kernel_(kernel)
162  {
163  ++kernel_->map_locked_;
164  }
166  {
167  --kernel_->map_locked_;
168  }
170 };
171 
172 
174 {
175  game_lua_kernel::preload_scripts.clear();
176  for (const config& cfg : game_config.child_range("lua")) {
177  game_lua_kernel::preload_scripts.push_back(cfg);
178  }
179  game_lua_kernel::preload_config = game_config.child("game_config");
180 }
181 
182 void game_lua_kernel::log_error(char const * msg, char const * context)
183 {
184  lua_kernel_base::log_error(msg, context);
185  lua_chat(context, msg);
186 }
187 
188 void game_lua_kernel::lua_chat(const std::string& caption, const std::string& msg)
189 {
190  if (game_display_) {
191  game_display_->get_chat_manager().add_chat_message(std::time(nullptr), caption, 0, msg,
193  }
194 }
195 
196 /**
197  * Gets a vector of sides from side= attribute in a given config node.
198  * Promotes consistent behavior.
199  */
200 std::vector<int> game_lua_kernel::get_sides_vector(const vconfig& cfg)
201 {
202  const config::attribute_value sides = cfg["side"];
203  const vconfig &ssf = cfg.child("filter_side");
204 
205  if (!ssf.null()) {
206  if(!sides.empty()) { WRN_LUA << "ignoring duplicate side filter information (inline side=)" << std::endl; }
207  side_filter filter(ssf, &game_state_);
208  return filter.get_teams();
209  }
210 
211  side_filter filter(sides.str(), &game_state_);
212  return filter.get_teams();
213 }
214 
215 namespace {
216  /**
217  * Temporary entry to a queued_event stack
218  */
219  struct queued_event_context
220  {
221  typedef game_events::queued_event qe;
222  std::stack<qe const *> & stack_;
223 
224  queued_event_context(qe const *new_qe, std::stack<qe const*> & stack)
225  : stack_(stack)
226  {
227  stack_.push(new_qe);
228  }
229 
230  ~queued_event_context()
231  {
232  stack_.pop();
233  }
234  };
235 }//unnamed namespace for queued_event_context
236 
237 /**
238  * Gets currently viewing side.
239  * - Ret 1: integer specifying the currently viewing side
240  * - Ret 2: Bool whether the vision is not limited to that team, this can for example be true during replays.
241  */
243 {
244  if(const display* disp = display::get_singleton()) {
245  lua_pushinteger(L, disp->viewing_side());
246  lua_pushboolean(L, disp->show_everything());
247  return 2;
248  }
249  else {
250  return 0;
251  }
252 }
253 
254 static const char animatorKey[] = "unit animator";
255 
257  unit_animator& anim = *static_cast<unit_animator*>(luaL_checkudata(L, 1, animatorKey));
258  anim.~unit_animator();
259  return 0;
260 }
261 
263 {
264  unit_animator& anim = *static_cast<unit_animator*>(luaL_checkudata(L, 1, animatorKey));
265  unit_ptr up = luaW_checkunit_ptr(L, 2, false);
266  unit& u = *up;
267  std::string which = luaL_checkstring(L, 3);
268 
269  using hit_type = unit_animation::hit_type;
270  std::string hits_str = luaL_checkstring(L, 4);
271  hit_type hits = hit_type::string_to_enum(hits_str, hit_type::INVALID);
272 
273  map_location dest;
274  int v1 = 0, v2 = 0;
275  bool bars = false;
276  t_string text;
277  color_t color{255, 255, 255};
278  const_attack_ptr primary, secondary;
279 
280  if(lua_istable(L, 5)) {
281  lua_getfield(L, 5, "target");
282  if(luaW_tolocation(L, -1, dest)) {
283  if(dest == u.get_location()) {
284  return luaL_argerror(L, 5, "target location must be different from animated unit's location");
285  } else if(!tiles_adjacent(dest, u.get_location())) {
286  return luaL_argerror(L, 5, "target location must be adjacent to the animated unit");
287  }
288  } else {
289  // luaW_tolocation may set the location to (0,0) if it fails
290  dest = map_location();
291  if(!lua_isnoneornil(L, -1)) {
292  return luaW_type_error(L, 5, "target", "location table");
293  }
294  }
295  lua_pop(L, 1);
296 
297  lua_getfield(L, 5, "value");
298  if(lua_isnumber(L, -1)) {
299  v1 = lua_tonumber(L, -1);
300  } else if(lua_istable(L, -1)) {
301  lua_rawgeti(L, -1, 1);
302  v1 = lua_tonumber(L, -1);
303  lua_pop(L, 1);
304  lua_rawgeti(L, -1, 2);
305  v2 = lua_tonumber(L, -1);
306  lua_pop(L, 1);
307  } else if(!lua_isnoneornil(L, -1)) {
308  return luaW_type_error(L, 5, "value", "number or array of two numbers");
309  }
310  lua_pop(L, 1);
311 
312  lua_getfield(L, 5, "with_bars");
313  if(lua_isboolean(L, -1)) {
314  bars = luaW_toboolean(L, -1);
315  } else if(!lua_isnoneornil(L, -1)) {
316  return luaW_type_error(L, 5, "with_bars", lua_typename(L, LUA_TBOOLEAN));
317  }
318  lua_pop(L, 1);
319 
320  lua_getfield(L, 5, "text");
321  if(lua_isstring(L, -1)) {
322  text = lua_tostring(L, -1);
323  } else if(luaW_totstring(L, -1, text)) {
324  // Do nothing; luaW_totstring already assigned the value
325  } else if(!lua_isnoneornil(L, -1)) {
326  return luaW_type_error(L, 5, "text", lua_typename(L, LUA_TSTRING));
327  }
328  lua_pop(L, 1);
329 
330  lua_getfield(L, 5, "color");
331  if(lua_istable(L, -1) && lua_rawlen(L, -1) == 3) {
332  int idx = lua_absindex(L, -1);
333  lua_rawgeti(L, idx, 1); // red @ -3
334  lua_rawgeti(L, idx, 2); // green @ -2
335  lua_rawgeti(L, idx, 3); // blue @ -1
336  color = color_t(lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1));
337  lua_pop(L, 3);
338  } else if(!lua_isnoneornil(L, -1)) {
339  return luaW_type_error(L, 5, "color", "array of three numbers");
340  }
341  lua_pop(L, 1);
342 
343  lua_getfield(L, 5, "primary");
344  primary = luaW_toweapon(L, -1);
345  if(!primary && !lua_isnoneornil(L, -1)) {
346  return luaW_type_error(L, 5, "primary", "weapon");
347  }
348  lua_pop(L, 1);
349 
350  lua_getfield(L, 5, "secondary");
351  secondary = luaW_toweapon(L, -1);
352  if(!secondary && !lua_isnoneornil(L, -1)) {
353  return luaW_type_error(L, 5, "secondary", "weapon");
354  }
355  lua_pop(L, 1);
356  } else if(!lua_isnoneornil(L, 5)) {
357  return luaW_type_error(L, 5, "table of options");
358  }
359 
360  anim.add_animation(up, which, u.get_location(), dest, v1, bars, text, color, hits, primary, secondary, v2);
361  return 0;
362 }
363 
365 {
367  if(v.update_locked() || v.faked()) {
368  return 0;
369  }
370  events::command_disabler command_disabler;
371  unit_animator& anim = *static_cast<unit_animator*>(luaL_checkudata(L, 1, animatorKey));
372  play_controller_.play_slice(false);
373  anim.start_animations();
374  anim.wait_for_end();
375  anim.set_all_standing();
376  anim.clear();
377  return 0;
378 }
379 
381 {
382  unit_animator& anim = *static_cast<unit_animator*>(luaL_checkudata(L, 1, animatorKey));
383  anim.clear();
384  return 0;
385 }
386 
388 {
389  const char* m = lua_tostring(L, 2);
390  return luaW_getmetafield(L, 1, m);
391 }
392 
394 {
395  new(L) unit_animator;
397  luaL_Reg metafuncs[] {
398  {"__gc", impl_animator_collect},
399  {"__index", impl_animator_get},
400  {"add", impl_add_animation},
401  {"run", &dispatch<&game_lua_kernel::impl_run_animation>},
402  {"clear", impl_clear_animation},
403  {nullptr, nullptr},
404  };
405  luaL_setfuncs(L, metafuncs, 0);
406  lua_pushstring(L, "__metatable");
407  lua_setfield(L, -2, animatorKey);
408  }
409  lua_setmetatable(L, -2);
410  return 1;
411 }
412 
414 {
415  if (game_display_) {
416  return lua_gui2::show_gamestate_inspector(luaW_checkvconfig(L, 1), gamedata(), game_state_);
417  }
418  return 0;
419 }
420 
421 /**
422  * Gets the unit at the given location or with the given id.
423  * - Arg 1: location
424  * OR
425  * - Arg 1: string ID
426  * - Ret 1: full userdata with __index pointing to impl_unit_get and
427  * __newindex pointing to impl_unit_set.
428  */
430 {
431  map_location loc;
432  if(lua_isstring(L, 1) && !lua_isnumber(L, 1)) {
433  std::string id = luaL_checkstring(L, 1);
434  for(const unit& u : units()) {
435  if(u.id() == id) {
436  luaW_pushunit(L, u.underlying_id());
437  return 1;
438  }
439  }
440  return 0;
441  }
442  if(!luaW_tolocation(L, 1, loc)) {
443  return luaL_argerror(L, 1, "expected string or location");
444  }
445  unit_map::const_iterator ui = units().find(loc);
446 
447  if (!ui.valid()) return 0;
448 
449  luaW_pushunit(L, ui->underlying_id());
450  return 1;
451 }
452 
453 /**
454  * Gets the unit displayed in the sidebar.
455  * - Ret 1: full userdata with __index pointing to impl_unit_get and
456  * __newindex pointing to impl_unit_set.
457  */
459 {
460  if (!game_display_) {
461  return 0;
462  }
463 
464  unit_map::const_iterator ui = board().find_visible_unit(
465  game_display_->displayed_unit_hex(),
466  teams()[game_display_->viewing_team()],
467  game_display_->show_everything());
468  if (!ui.valid()) return 0;
469 
470  luaW_pushunit(L, ui->underlying_id());
471  return 1;
472 }
473 
474 /**
475  * Gets all the units matching a given filter.
476  * - Arg 1: optional table containing a filter
477  * - Arg 2: optional location (to find all units that would match on that location)
478  OR unit (to find all units that would match adjacent to that unit)
479  * - Ret 1: table containing full userdata with __index pointing to
480  * impl_unit_get and __newindex pointing to impl_unit_set.
481  */
483 {
484  vconfig filter = luaW_checkvconfig(L, 1, true);
485  unit_filter filt(filter);
486  std::vector<const unit*> units;
487 
488  if(unit* u_adj = luaW_tounit(L, 2)) {
489  if(!u_adj) {
490  return luaL_argerror(L, 2, "unit not found");
491  }
492  units = filt.all_matches_with_unit(*u_adj);
493  } else if(!lua_isnoneornil(L, 2)) {
494  map_location loc;
495  luaW_tolocation(L, 2, loc);
496  if(!loc.valid()) {
497  return luaL_argerror(L, 2, "invalid location");
498  }
499  units = filt.all_matches_at(loc);
500  } else {
501  units = filt.all_matches_on_map();
502  }
503 
504  // Go through all the units while keeping the following stack:
505  // 1: return table, 2: userdata
506  lua_settop(L, 0);
507  lua_newtable(L);
508  int i = 1;
509 
510  for (const unit * ui : units) {
511  luaW_pushunit(L, ui->underlying_id());
512  lua_rawseti(L, 1, i);
513  ++i;
514  }
515  return 1;
516 }
517 
518 /**
519  * Matches a unit against the given filter.
520  * - Arg 1: full userdata.
521  * - Arg 2: table containing a filter
522  * - Arg 3: optional location OR optional "adjacent" unit
523  * - Ret 1: boolean.
524  */
526 {
527  lua_unit& u = *luaW_checkunit_ref(L, 1);
528 
529  vconfig filter = luaW_checkvconfig(L, 2, true);
530 
531  if (filter.null()) {
532  lua_pushboolean(L, true);
533  return 1;
534  }
535 
536  if(unit* u_adj = luaW_tounit(L, 3)) {
537  if(int side = u.on_recall_list()) {
538  WRN_LUA << "wesnoth.units.matches called with a secondary unit (3rd argument), ";
539  WRN_LUA << "but unit to match was on recall list. ";
540  WRN_LUA << "Thus the 3rd argument is ignored.\n";
541  team &t = board().get_team(side);
542  scoped_recall_unit auto_store("this_unit", t.save_id_or_number(), t.recall_list().find_index(u->id()));
543  lua_pushboolean(L, unit_filter(filter).matches(*u, map_location()));
544  return 1;
545  }
546  if (!u_adj) {
547  return luaL_argerror(L, 3, "unit not found");
548  }
549  lua_pushboolean(L, unit_filter(filter).matches(*u, *u_adj));
550  } else if(int side = u.on_recall_list()) {
551  map_location loc;
552  luaW_tolocation(L, 3, loc); // If argument 3 isn't a location, loc is unchanged
553  team &t = board().get_team(side);
554  scoped_recall_unit auto_store("this_unit", t.save_id_or_number(), t.recall_list().find_index(u->id()));
555  lua_pushboolean(L, unit_filter(filter).matches(*u, loc));
556  return 1;
557  } else {
558  map_location loc = u->get_location();
559  luaW_tolocation(L, 3, loc); // If argument 3 isn't a location, loc is unchanged
560  lua_pushboolean(L, unit_filter(filter).matches(*u, loc));
561  }
562  return 1;
563 }
564 
565 /**
566  * Gets the numeric ids of all the units matching a given filter on the recall lists.
567  * - Arg 1: optional table containing a filter
568  * - Ret 1: table containing full userdata with __index pointing to
569  * impl_unit_get and __newindex pointing to impl_unit_set.
570  */
572 {
573  vconfig filter = luaW_checkvconfig(L, 1, true);
574 
575  // Go through all the units while keeping the following stack:
576  // 1: return table, 2: userdata
577  lua_settop(L, 0);
578  lua_newtable(L);
579  int i = 1, s = 1;
580  const unit_filter ufilt(filter);
581  for (team &t : teams())
582  {
583  for (unit_ptr & u : t.recall_list())
584  {
585  if (!filter.null()) {
586  scoped_recall_unit auto_store("this_unit",
587  t.save_id_or_number(), t.recall_list().find_index(u->id()));
588  if (!ufilt( *u, map_location() ))
589  continue;
590  }
591  luaW_pushunit(L, s, u->underlying_id());
592  lua_rawseti(L, 1, i);
593  ++i;
594  }
595  ++s;
596  }
597  return 1;
598 }
599 
600 /**
601  * Fires an event.
602  * - Arg 1: string containing the event name or id.
603  * - Arg 2: optional first location.
604  * - Arg 3: optional second location.
605  * - Arg 4: optional WML table used as the [weapon] tag.
606  * - Arg 5: optional WML table used as the [second_weapon] tag.
607  * - Ret 1: boolean indicating whether the event was processed or not.
608  */
610 {
611  char const *m = luaL_checkstring(L, 1);
612 
613  int pos = 2;
614  map_location l1, l2;
615  config data;
616 
617  if (luaW_tolocation(L, 2, l1)) {
618  if (luaW_tolocation(L, 3, l2)) {
619  pos = 4;
620  } else {
621  pos = 3;
622  }
623  }
624 
625  if (!lua_isnoneornil(L, pos)) {
626  data.add_child("first", luaW_checkconfig(L, pos));
627  }
628  ++pos;
629  if (!lua_isnoneornil(L, pos)) {
630  data.add_child("second", luaW_checkconfig(L, pos));
631  }
632 
633  bool b = false;
634 
635  if (by_id) {
636  b = std::get<0>(play_controller_.pump().fire("", m, l1, l2, data));
637  }
638  else {
639  b = std::get<0>(play_controller_.pump().fire(m, l1, l2, data));
640  }
641  lua_pushboolean(L, b);
642  return 1;
643 }
644 
645 
646 /**
647  * Fires a wml menu item.
648  * - Arg 1: id of the item. it is not possible to fire items that don't have ids with this function.
649  * - Arg 2: optional first location.
650  * - Ret 1: boolean, true indicating that the event was fired successfully
651  *
652  * NOTE: This is not an "official" feature, it may currently cause assertion failures if used with
653  * menu items which have "needs_select". It is not supported right now to use it this way.
654  * The purpose of this function right now is to make it possible to have automated sanity tests for
655  * the wml menu items system.
656  */
658 {
659  char const *m = luaL_checkstring(L, 1);
660 
661  map_location l1 = luaW_checklocation(L, 2);
662 
663  bool b = game_state_.get_wml_menu_items().fire_item(m, l1, gamedata(), game_state_, units());
664  lua_pushboolean(L, b);
665  return 1;
666 }
667 
668 /**
669  * Gets a WML variable.
670  * - Arg 1: string containing the variable name.
671  * - Arg 2: optional bool indicating if tables for containers should be left empty.
672  * - Ret 1: value of the variable, if any.
673  */
675 {
676  char const *m = luaL_checkstring(L, 1);
677  variable_access_const v = gamedata().get_variable_access_read(m);
678  return luaW_pushvariable(L, v) ? 1 : 0;
679 }
680 
681 /**
682  * Sets a WML variable.
683  * - Arg 1: string containing the variable name.
684  * - Arg 2: boolean/integer/string/table containing the value.
685  */
687 {
688  const std::string m = luaL_checkstring(L, 1);
689  if(m.empty()) return luaL_argerror(L, 1, "empty variable name");
690  if (lua_isnoneornil(L, 2)) {
691  gamedata().clear_variable(m);
692  return 0;
693  }
694  variable_access_create v = gamedata().get_variable_access_write(m);
695  luaW_checkvariable(L, v, 2);
696  return 0;
697 }
698 
699 
701 {
702  config cfg = luaW_checkconfig(L, 1);
703  game_state_.add_side_wml(cfg);
704 
705  return 0;
706 }
707 
709 {
710  game_state_.get_wml_menu_items().set_item(luaL_checkstring(L, 1), luaW_checkvconfig(L,2));
711  return 0;
712 }
713 
715 {
716  std::string ids(luaL_checkstring(L, 1));
717  for(const std::string& id : utils::split(ids, ',', utils::STRIP_SPACES)) {
718  if(id.empty()) {
719  WRN_LUA << "[clear_menu_item] has been given an empty id=, ignoring" << std::endl;
720  continue;
721  }
722  game_state_.get_wml_menu_items().erase(id);
723  }
724  return 0;
725 }
726 
728 {
729  game_classification &classification = play_controller_.get_classification();
730  classification.end_credits = luaW_toboolean(L, 1);
731  return 0;
732 }
733 
735 {
736  game_classification &classification = play_controller_.get_classification();
737  classification.end_text = luaW_checktstring(L, 1);
738  if (lua_isnumber(L, 2)) {
739  classification.end_text_duration = static_cast<int> (lua_tonumber(L, 2));
740  }
741 
742  return 0;
743 }
744 
746 {
747  deprecated_message("wesnoth.set_next_scenario", DEP_LEVEL::INDEFINITE, "");
748  gamedata().set_next_scenario(luaL_checkstring(L, 1));
749  return 0;
750 }
751 
752 int game_lua_kernel::intf_shroud_op(lua_State *L, bool place_shroud)
753 {
754 
755  int side_num = luaL_checkinteger(L, 1);
756 
757  if(lua_isstring(L, 2)) {
758  std::string data = lua_tostring(L, 2);
759  // Special case - using a shroud_data string, or "all"
760  team& side = board().get_team(side_num);
761  if(place_shroud) {
762  side.reshroud();
763  }
764  if(data != "all") {
765  side.merge_shroud_map_data(data);
766  } else if(!place_shroud) {
767  bool was_shrouded = side.uses_shroud();
768  side.set_shroud(false);
769  actions::clear_shroud(side.side());
770  side.set_shroud(was_shrouded);
771  }
772  return 0;
773  } else if(lua_istable(L, 2)) {
774  std::vector<map_location> locs_v = lua_check<std::vector<map_location>>(L, 2);
775  std::set<map_location> locs(locs_v.begin(), locs_v.end());
776  team &t = board().get_team(side_num);
777 
778  for (const map_location& loc : locs)
779  {
780  if (place_shroud) {
781  t.place_shroud(loc);
782  } else {
783  t.clear_shroud(loc);
784  }
785  }
786  } else {
787  return luaL_argerror(L, 2, "expected list of locations or shroud data string");
788  }
789 
790  game_display_->labels().recalculate_shroud();
791  game_display_->recalculate_minimap();
792  game_display_->invalidate_all();
793 
794  return 0;
795 }
796 
797 
798 /**
799  * Highlights the given location on the map.
800  * - Arg 1: location.
801  */
803 {
804  if (!game_display_) {
805  return 0;
806  }
807 
808  const map_location loc = luaW_checklocation(L, 1);
809  if(!map().on_board(loc)) return luaL_argerror(L, 1, "not on board");
810  game_display_->highlight_hex(loc);
811  game_display_->display_unit_hex(loc);
812 
813  return 0;
814 }
815 
816 /**
817  * Returns whether the first side is an enemy of the second one.
818  * - Args 1,2: side numbers.
819  * - Ret 1: boolean.
820  */
822 {
823  unsigned side_1, side_2;
824  if(team* t = luaW_toteam(L, 1)) {
825  side_1 = t->side();
826  } else {
827  side_1 = luaL_checkinteger(L, 1);
828  }
829  if(team* t = luaW_toteam(L, 2)) {
830  side_2 = t->side();
831  } else {
832  side_2 = luaL_checkinteger(L, 2);
833  }
834  if (side_1 > teams().size() || side_2 > teams().size()) return 0;
835  lua_pushboolean(L, board().get_team(side_1).is_enemy(side_2));
836  return 1;
837 }
838 
839 /**
840  * Gets whether gamemap scrolling is disabled for the user.
841  * - Ret 1: boolean.
842  */
844 {
845  if (!game_display_) {
846  return 0;
847  }
848 
849  lua_pushboolean(L, game_display_->view_locked());
850  return 1;
851 }
852 
853 /**
854  * Sets whether gamemap scrolling is disabled for the user.
855  * - Arg 1: boolean, specifying the new locked/unlocked status.
856  */
858 {
859  bool lock = luaW_toboolean(L, 1);
860  if (game_display_) {
861  game_display_->set_view_locked(lock);
862  }
863  return 0;
864 }
865 
866 /**
867  * Gets details about a terrain.
868  * - Arg 1: terrain code string.
869  * - Ret 1: table.
870  */
872 {
873  char const *m = luaL_checkstring(L, 2);
875  if (t == t_translation::NONE_TERRAIN) return 0;
876  const terrain_type& info = board().map().tdata()->get_terrain_info(t);
877 
878  lua_newtable(L);
879  lua_pushstring(L, info.id().c_str());
880  lua_setfield(L, -2, "id");
881  luaW_pushtstring(L, info.name());
882  lua_setfield(L, -2, "name");
883  luaW_pushtstring(L, info.editor_name());
884  lua_setfield(L, -2, "editor_name");
885  luaW_pushtstring(L, info.description());
886  lua_setfield(L, -2, "description");
887  lua_push(L, info.icon_image());
888  lua_setfield(L, -2, "icon");
889  lua_push(L, info.editor_image());
890  lua_setfield(L, -2, "editor_image");
891  lua_pushinteger(L, info.light_bonus(0));
892  lua_setfield(L, -2, "light");
893  lua_pushboolean(L, info.is_village());
894  lua_setfield(L, -2, "village");
895  lua_pushboolean(L, info.is_castle());
896  lua_setfield(L, -2, "castle");
897  lua_pushboolean(L, info.is_keep());
898  lua_setfield(L, -2, "keep");
899  lua_pushinteger(L, info.gives_healing());
900  lua_setfield(L, -2, "healing");
901 
902  return 1;
903 }
904 
905 /**
906  * Gets time of day information.
907  * - Arg 1: optional turn number
908  * - Arg 2: optional location
909  * - Arg 3: optional boolean (consider_illuminates)
910  * - Ret 1: table.
911  */
913 {
914  unsigned arg = 1;
915 
916  int for_turn = tod_man().turn();
917  map_location loc = map_location();
918  bool consider_illuminates = false;
919 
920  if(lua_isnumber(L, arg)) {
921  ++arg;
922  for_turn = luaL_checkinteger(L, 1);
923  int number_of_turns = tod_man().number_of_turns();
924  if(for_turn < 1 || (number_of_turns != -1 && for_turn > number_of_turns)) {
925  return luaL_argerror(L, 1, "turn number out of range");
926  }
927  }
928  else if(lua_isnil(L, arg)) ++arg;
929 
930  if(luaW_tolocation(L, arg, loc)) {
931  if(!board().map().on_board(loc)) return luaL_argerror(L, arg, "coordinates are not on board");
932 
933  if(lua_istable(L, arg)) {
934  lua_rawgeti(L, arg, 3);
935  consider_illuminates = luaW_toboolean(L, -1);
936  lua_pop(L, 1);
937  } else if(lua_isboolean(L, arg + 1)) {
938  consider_illuminates = luaW_toboolean(L, arg + 1);
939  }
940  }
941 
942  const time_of_day& tod = consider_illuminates ?
943  tod_man().get_illuminated_time_of_day(board().units(), board().map(), loc, for_turn) :
944  tod_man().get_time_of_day(loc, for_turn);
945 
946  lua_newtable(L);
947  lua_pushstring(L, tod.id.c_str());
948  lua_setfield(L, -2, "id");
950  lua_setfield(L, -2, "lawful_bonus");
952  lua_setfield(L, -2, "bonus_modified");
953  lua_pushstring(L, tod.image.c_str());
954  lua_setfield(L, -2, "image");
955  luaW_pushtstring(L, tod.name);
956  lua_setfield(L, -2, "name");
957 
958  lua_pushinteger(L, tod.color.r);
959  lua_setfield(L, -2, "red");
960  lua_pushinteger(L, tod.color.g);
961  lua_setfield(L, -2, "green");
962  lua_pushinteger(L, tod.color.b);
963  lua_setfield(L, -2, "blue");
964 
965  return 1;
966 }
967 
968 /**
969  * Gets the max liminal bonus
970  * - Ret 1: integer.
971  */
973 {
974  int bonus = tod_man().get_max_liminal_bonus();
975  lua_pushinteger(L, bonus);
976 
977  return 1;
978 }
979 
980 /**
981  * Gets the side of a village owner.
982  * - Arg 1: map location.
983  * - Ret 1: integer.
984  */
986 {
987  map_location loc = luaW_checklocation(L, 1);
988  if (!board().map().is_village(loc))
989  return 0;
990 
991  int side = board().village_owner(loc);
992  if (!side) return 0;
993  lua_pushinteger(L, side);
994  return 1;
995 }
996 
997 /**
998  * Sets the owner of a village.
999  * - Arg 1: map location.
1000  * - Arg 2: integer for the side or empty to remove ownership.
1001  */
1003 {
1004  map_location loc = luaW_checklocation(L, 1);
1005  if(!board().map().is_village(loc)) {
1006  return 0;
1007  }
1008 
1009  const int old_side_num = board().village_owner(loc);
1010  const int new_side_num = lua_isnoneornil(L, 2) ? 0 : luaL_checkinteger(L, 2);
1011 
1012  team* old_side = nullptr;
1013  team* new_side = nullptr;
1014 
1015  if(old_side_num == new_side_num) {
1016  return 0;
1017  }
1018 
1019  try {
1020  old_side = &board().get_team(old_side_num);
1021  } catch(const std::out_of_range&) {
1022  // old_side_num is invalid, most likely because the village wasn't captured.
1023  old_side = nullptr;
1024  }
1025 
1026  try {
1027  new_side = &board().get_team(new_side_num);
1028  } catch(const std::out_of_range&) {
1029  // new_side_num is invalid.
1030  new_side = nullptr;
1031  }
1032 
1033  // The new side was valid, but already defeated. Do nothing.
1034  if(new_side && board().team_is_defeated(*new_side)) {
1035  return 0;
1036  }
1037 
1038  // Even if the new side is not valid, we still want to remove the village from the old side.
1039  // This covers the case where new_side_num equals 0. The behavior in that case is to simply
1040  // un-assign the village from the old side, which of course we also want to happen if the new
1041  // side IS valid. If the village in question hadn't been captured, this won't fire (old_side
1042  // will be a nullptr).
1043  if(old_side) {
1044  old_side->lose_village(loc);
1045  }
1046 
1047  // If the new side was valid, re-assign the village.
1048  if(new_side) {
1049  new_side->get_village(loc, old_side_num, (luaW_toboolean(L, 3) ? &gamedata() : nullptr));
1050  }
1051 
1052  return 0;
1053 }
1054 
1055 /**
1056  * Returns the currently overed tile.
1057  * - Ret 1: x.
1058  * - Ret 2: y.
1059  */
1061 {
1062  if (!game_display_) {
1063  return 0;
1064  }
1065 
1066  const map_location &loc = game_display_->mouseover_hex();
1067  if (!board().map().on_board(loc)) return 0;
1068  lua_pushinteger(L, loc.wml_x());
1069  lua_pushinteger(L, loc.wml_y());
1070  return 2;
1071 }
1072 
1073 /**
1074  * Returns the currently selected tile.
1075  * - Ret 1: x.
1076  * - Ret 2: y.
1077  */
1079 {
1080  if (!game_display_) {
1081  return 0;
1082  }
1083 
1084  const map_location &loc = game_display_->selected_hex();
1085  if (!board().map().on_board(loc)) return 0;
1086  lua_pushinteger(L, loc.wml_x());
1087  lua_pushinteger(L, loc.wml_y());
1088  return 2;
1089 }
1090 
1091 
1092 /**
1093  * Gets a table for an resource tag.
1094  * - Arg 1: userdata (ignored).
1095  * - Arg 2: string containing id of the desired resource
1096  * - Ret 1: config for the era
1097  */
1099 {
1100  std::string m = luaL_checkstring(L, 1);
1101  if(const config& res = game_config_manager::get()->game_config().find_child("resource","id",m)) {
1102  luaW_pushconfig(L, res);
1103  return 1;
1104  }
1105  else {
1106  return luaL_argerror(L, 1, ("Cannot find ressource with id '" + m + "'").c_str());
1107  }
1108 }
1109 
1110 /**
1111  * Gets a table for an era tag.
1112  * - Arg 1: userdata (ignored).
1113  * - Arg 2: string containing id of the desired era
1114  * - Ret 1: config for the era
1115  */
1116 static int intf_get_era(lua_State *L)
1117 {
1118  char const *m = luaL_checkstring(L, 1);
1119  luaW_pushconfig(L, game_config_manager::get()->game_config().find_child("era","id",m));
1120  return 1;
1121 }
1122 
1123 /**
1124  * Gets some game_config data (__index metamethod).
1125  * - Arg 1: userdata (ignored).
1126  * - Arg 2: string containing the name of the property.
1127  * - Ret 1: something containing the attribute.
1128  */
1130 {
1131  LOG_LUA << "impl_game_config_get\n";
1132  char const *m = luaL_checkstring(L, 2);
1133 
1134  // Find the corresponding attribute.
1135  return_int_attrib("last_turn", tod_man().number_of_turns());
1136  return_bool_attrib("do_healing", play_controller_.gamestate().do_healing_);
1137  return_string_attrib("next_scenario", gamedata().next_scenario());
1138  return_string_attrib("theme", gamedata().get_theme());
1139  return_string_attrib("scenario_id", gamedata().get_id());
1140  return_vector_string_attrib("defeat_music", gamedata().get_defeat_music());
1141  return_vector_string_attrib("victory_music", gamedata().get_victory_music());
1142  return_vector_string_attrib("active_resources", utils::split(play_controller_.get_loaded_resources()) );
1143 
1144  const mp_game_settings& mp_settings = play_controller_.get_mp_settings();
1145  const game_classification & classification = play_controller_.get_classification();
1146 
1147  return_string_attrib("campaign_type", classification.campaign_type.to_string());
1148  if(classification.campaign_type==game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
1149  return_cfgref_attrib("mp_settings", mp_settings.to_config());
1150  return_cfgref_attrib("era", game_config_manager::get()->game_config().find_child("era","id",classification.era_id));
1151  //^ finds the era with name matching mp_era, and creates a lua reference from the config of that era.
1152 
1153  //This code for SigurdFD, not the cleanest implementation but seems to work just fine.
1154  std::vector<std::string> eras_list;
1155  for (const config& era : game_config_manager::get()->game_config().child_range("era") ) {
1156  eras_list.push_back(era["id"].str());
1157  }
1158  return_string_attrib("eras", utils::join(eras_list));
1159  }
1161 }
1162 
1163 /**
1164  * Sets some game_config data (__newindex metamethod).
1165  * - Arg 1: userdata (ignored).
1166  * - Arg 2: string containing the name of the property.
1167  * - Arg 3: something containing the attribute.
1168  */
1170 {
1171  LOG_LUA << "impl_game_config_set\n";
1172  char const *m = luaL_checkstring(L, 2);
1173 
1174  // Find the corresponding attribute.
1175  modify_int_attrib("base_income", game_config::base_income = value);
1176  modify_int_attrib("village_income", game_config::village_income = value);
1177  modify_int_attrib("village_support", game_config::village_support = value);
1178  modify_int_attrib("poison_amount", game_config::poison_amount = value);
1179  modify_int_attrib("rest_heal_amount", game_config::rest_heal_amount = value);
1180  modify_int_attrib("recall_cost", game_config::recall_cost = value);
1181  modify_int_attrib("kill_experience", game_config::kill_experience = value);
1182  modify_int_attrib("combat_experience", game_config::combat_experience = value);
1183  modify_int_attrib("last_turn", tod_man().set_number_of_turns_by_wml(value));
1184  modify_bool_attrib("do_healing", play_controller_.gamestate().do_healing_ = value);
1185  modify_string_attrib("next_scenario", gamedata().set_next_scenario(value));
1186  modify_string_attrib("theme",
1187  gamedata().set_theme(value);
1189  game_display_->set_theme(play_controller_.get_theme(game_config, value));
1190  );
1191  modify_vector_string_attrib("defeat_music", gamedata().set_defeat_music(std::move(value)));
1192  modify_vector_string_attrib("victory_music", gamedata().set_victory_music(std::move(value)));
1194 }
1195 
1196 /**
1197  converts synced_context::get_synced_state() to a string.
1198 */
1200 {
1201  //maybe return "initial" for game_data::INITIAL?
1202  if(gamedata().phase() == game_data::PRELOAD || gamedata().phase() == game_data::INITIAL)
1203  {
1204  return "preload";
1205  }
1207  {
1209  return "local_choice";
1211  return "synced";
1213  return "unsynced";
1214  default:
1215  throw game::game_error("Found corrupt synced_context::synced_state");
1216  }
1217 }
1218 
1219 
1220 /**
1221  * Gets some data about current point of game (__index metamethod).
1222  * - Arg 1: userdata (ignored).
1223  * - Arg 2: string containing the name of the property.
1224  * - Ret 1: something containing the attribute.
1225  */
1227 {
1228  char const *m = luaL_checkstring(L, 2);
1229 
1230  // Find the corresponding attribute.
1231  return_int_attrib("side", play_controller_.current_side());
1232  return_int_attrib("turn", play_controller_.turn());
1233  return_string_attrib("synced_state", synced_state());
1234  return_bool_attrib("user_can_invoke_commands", !play_controller_.is_lingering() && play_controller_.gamestate().init_side_done() && !events::commands_disabled && gamedata().phase() == game_data::PLAY);
1235 
1236  if(strcmp(m, "map") == 0) {
1237  return intf_terrainmap_get(L);
1238  }
1239 
1240  if (strcmp(m, "event_context") == 0)
1241  {
1242  const game_events::queued_event &ev = get_event_info();
1243  config cfg;
1244  cfg["name"] = ev.name;
1245  cfg["id"] = ev.id;
1246  if (const config &weapon = ev.data.child("first")) {
1247  cfg.add_child("weapon", weapon);
1248  }
1249  if (const config &weapon = ev.data.child("second")) {
1250  cfg.add_child("second_weapon", weapon);
1251  }
1252 
1253  const config::attribute_value di = ev.data["damage_inflicted"];
1254  if(!di.empty()) {
1255  cfg["damage_inflicted"] = di;
1256  }
1257 
1258  if (ev.loc1.valid()) {
1259  cfg["x1"] = ev.loc1.filter_loc().wml_x();
1260  cfg["y1"] = ev.loc1.filter_loc().wml_y();
1261  // The position of the unit involved in this event, currently the only case where this is different from x1/y1 are enter/exit_hex events
1262  cfg["unit_x"] = ev.loc1.wml_x();
1263  cfg["unit_y"] = ev.loc1.wml_y();
1264  }
1265  if (ev.loc2.valid()) {
1266  cfg["x2"] = ev.loc2.filter_loc().wml_x();
1267  cfg["y2"] = ev.loc2.filter_loc().wml_y();
1268  }
1269  luaW_pushconfig(L, cfg);
1270  return 1;
1271  }
1272 
1273  return 0;
1274 }
1275 
1276 /**
1277  * Displays a message in the chat window and in the logs.
1278  * - Arg 1: optional message header.
1279  * - Arg 2 (or 1): message.
1280  */
1282 {
1283  t_string m = luaW_checktstring(L, 1);
1284  t_string h = m;
1285  if (lua_isnone(L, 2)) {
1286  h = "Lua";
1287  } else {
1288  m = luaW_checktstring(L, 2);
1289  }
1290  lua_chat(h, m);
1291  LOG_LUA << "Script says: \"" << m << "\"\n";
1292  return 0;
1293 }
1294 
1296 {
1297  if (game_display_) {
1299  }
1300  return 0;
1301 }
1302 
1304 {
1305  if(!game_display_) {
1306  return 0;
1307  }
1308  double factor = luaL_checknumber(L, 1);
1309  bool relative = luaW_toboolean(L, 2);
1310  if(relative) {
1311  factor *= game_display_->get_zoom_factor();
1312  }
1313  // Passing true explicitly to avoid casting to int.
1314  // Without doing one of the two, the call is ambiguous.
1315  game_display_->set_zoom(factor * game_config::tile_size, true);
1316  lua_pushnumber(L, game_display_->get_zoom_factor());
1317  return 1;
1318 }
1319 
1320 /**
1321  * Removes all messages from the chat window.
1322  */
1324 {
1325  if (game_display_) {
1326  game_display_->get_chat_manager().clear_chat_messages();
1327  }
1328  return 0;
1329 }
1330 
1332 {
1333  const end_level_data& data = *static_cast<end_level_data*>(lua_touserdata(L, 1));
1334  const char* m = luaL_checkstring(L, 2);
1335 
1336  return_bool_attrib("linger_mode", data.transient.linger_mode);
1337  return_bool_attrib("reveal_map", data.transient.reveal_map);
1338  return_bool_attrib("carryover_report", data.transient.carryover_report);
1339  return_bool_attrib("prescenario_save", data.prescenario_save);
1340  return_bool_attrib("replay_save", data.replay_save);
1341  return_bool_attrib("proceed_to_next_level", data.proceed_to_next_level);
1342  return_bool_attrib("is_victory", data.is_victory);
1343  return_bool_attrib("is_loss", !data.is_victory);
1344  return_cstring_attrib("result", data.is_victory ? "victory" : "loss"); // to match wesnoth.end_level()
1345  return_string_attrib("test_result", data.test_result);
1346  return_cfg_attrib("__cfg", data.to_config_full());
1347 
1348  return 0;
1349 }
1350 
1351 namespace {
1352  struct end_level_committer {
1353  end_level_committer(end_level_data& data, play_controller& pc) : data_(data), pc_(pc) {}
1354  ~end_level_committer() {
1355  pc_.set_end_level_data(data_);
1356  }
1357  private:
1358  end_level_data& data_;
1359  play_controller& pc_;
1360  };
1361 }
1362 
1364 {
1365  end_level_data& data = *static_cast<end_level_data*>(lua_touserdata(L, 1));
1366  const char* m = luaL_checkstring(L, 2);
1367  end_level_committer commit(data, play_controller_);
1368 
1369  modify_bool_attrib("linger_mode", data.transient.linger_mode = value);
1370  modify_bool_attrib("reveal_map", data.transient.reveal_map = value);
1371  modify_bool_attrib("carryover_report", data.transient.carryover_report = value);
1372  modify_bool_attrib("prescenario_save", data.prescenario_save = value);
1373  modify_bool_attrib("replay_save", data.replay_save = value);
1374  modify_string_attrib("test_result", data.test_result = value);
1375 
1376  return 0;
1377 }
1378 
1380 {
1381  end_level_data* data = static_cast<end_level_data*>(lua_touserdata(L, 1));
1382  data->~end_level_data();
1383  return 0;
1384 }
1385 
1387 {
1388  if (!play_controller_.is_regular_game_end()) {
1389  return 0;
1390  }
1391  auto data = play_controller_.get_end_level_data();
1392  new(L) end_level_data(data);
1393  if(luaL_newmetatable(L, "end level data")) {
1394  static luaL_Reg const callbacks[] {
1395  { "__index", &impl_end_level_data_get},
1396  { "__newindex", &dispatch<&game_lua_kernel::impl_end_level_data_set>},
1397  { "__gc", &impl_end_level_data_collect},
1398  { nullptr, nullptr }
1399  };
1400  luaL_setfuncs(L, callbacks, 0);
1401  }
1402  lua_setmetatable(L, -2);
1403  return 1;
1404 }
1405 
1407 {
1408  vconfig cfg(luaW_checkvconfig(L, 1));
1409  end_level_data data;
1410 
1411  data.proceed_to_next_level = cfg["proceed_to_next_level"].to_bool(true);
1412  data.transient.carryover_report = cfg["carryover_report"].to_bool(true);
1413  data.prescenario_save = cfg["save"].to_bool(true);
1414  data.replay_save = cfg["replay_save"].to_bool(true);
1415  data.transient.linger_mode = cfg["linger_mode"].to_bool(true) && !teams().empty();
1416  data.transient.reveal_map = cfg["reveal_map"].to_bool(true);
1417  data.is_victory = cfg["result"] == "victory";
1418  data.test_result = cfg["test_result"].str(LEVEL_RESULT::enum_to_string(LEVEL_RESULT::TEST_NOT_SET));
1419  play_controller_.set_end_level_data(data);
1420  return 0;
1421 }
1422 
1424 {
1425  //note that next_player_number = 1, next_player_number = nteams+1 both set the next team to be the first team
1426  //but the later will make the turn counter change aswell fire turn end events accoringly etc.
1427  if (!lua_isnoneornil(L, 1)) {
1428  int npn = luaL_checknumber(L, 1);
1429  if (npn <= 0 /*TODO: || npn > 2*nteams*/) {
1430  return luaL_argerror(L, 1, "side number out of range");
1431  }
1433  }
1434  play_controller_.force_end_turn();
1435  return 0;
1436 }
1437 
1438 /**
1439  * Evaluates a boolean WML conditional.
1440  * - Arg 1: WML table.
1441  * - Ret 1: boolean.
1442  */
1444 {
1445  vconfig cond = luaW_checkvconfig(L, 1);
1446  bool b = game_events::conditional_passed(cond);
1447  lua_pushboolean(L, b);
1448  return 1;
1449 }
1450 
1451 
1452 /**
1453  * Finds a path between two locations.
1454  * - Arg 1: source location. (Or Arg 1: unit.)
1455  * - Arg 2: destination.
1456  * - Arg 3: optional cost function or
1457  * table (optional fields: ignore_units, ignore_teleport, max_cost, viewing_side).
1458  * - Ret 1: array of pairs containing path steps.
1459  * - Ret 2: path cost.
1460  */
1462 {
1463  int arg = 1;
1464  map_location src, dst;
1465  const unit* u = nullptr;
1466  int viewing_side = 0;
1467 
1468  if (lua_isuserdata(L, arg))
1469  {
1470  u = &luaW_checkunit(L, arg);
1471  src = u->get_location();
1472  viewing_side = u->side();
1473  ++arg;
1474  }
1475  else
1476  {
1477  src = luaW_checklocation(L, arg);
1478  unit_map::const_unit_iterator ui = units().find(src);
1479  if (ui.valid()) {
1480  u = ui.get_shared_ptr().get();
1481  viewing_side = u->side();
1482  }
1483  ++arg;
1484  }
1485 
1486  dst = luaW_checklocation(L, arg);
1487  ++arg;
1488 
1489  if (!board().map().on_board(src))
1490  return luaL_argerror(L, 1, "invalid location");
1491  if (!board().map().on_board(dst))
1492  return luaL_argerror(L, arg - 2, "invalid location");
1493 
1494  const gamemap &map = board().map();
1495  bool ignore_units = false, see_all = false, ignore_teleport = false;
1496  double stop_at = 10000;
1497  std::unique_ptr<pathfind::cost_calculator> calc;
1498 
1499  if (lua_istable(L, arg))
1500  {
1501  ignore_units = luaW_table_get_def<bool>(L, arg, "ignore_units", false);
1502  see_all = luaW_table_get_def<bool>(L, arg, "ignore_visibility", false);
1503  ignore_teleport = luaW_table_get_def<bool>(L, arg, "ignore_teleport", false);
1504 
1505  stop_at = luaW_table_get_def<double>(L, arg, "max_cost", stop_at);
1506 
1507 
1508  lua_pushstring(L, "viewing_side");
1509  lua_rawget(L, arg);
1510  if (!lua_isnil(L, -1)) {
1511  int i = luaL_checkinteger(L, -1);
1512  if (i >= 1 && i <= static_cast<int>(teams().size())) viewing_side = i;
1513  else {
1514  // If there's a unit, we have a valid side, so fall back to legacy behaviour.
1515  // If we don't have a unit, legacy behaviour would be a crash, so let's not.
1516  if(u) see_all = true;
1517  deprecated_message("wesnoth.find_path with viewing_side=0 (or an invalid side)", DEP_LEVEL::FOR_REMOVAL, {1, 17, 0}, "To consider fogged and hidden units, use ignore_visibility=true instead.");
1518  }
1519  }
1520  lua_pop(L, 1);
1521 
1522  lua_pushstring(L, "calculate");
1523  lua_rawget(L, arg);
1524  if(lua_isfunction(L, -1)) {
1525  calc.reset(new lua_pathfind_cost_calculator(L, lua_gettop(L)));
1526  }
1527  // Don't pop, the lua_pathfind_cost_calculator requires it to stay on the stack.
1528  }
1529  else if (lua_isfunction(L, arg))
1530  {
1531  deprecated_message("wesnoth.find_path with cost_function as last argument", DEP_LEVEL::FOR_REMOVAL, {1, 17, 0}, "Use calculate=cost_function inside the path options table instead.");
1532  calc.reset(new lua_pathfind_cost_calculator(L, arg));
1533  }
1534 
1535  pathfind::teleport_map teleport_locations;
1536 
1537  if(!ignore_teleport) {
1538  if(viewing_side == 0) {
1539  return luaL_error(L, "wesnoth.find_path: ignore_teleport=false requires a valid viewing_side");
1540  } else {
1541  teleport_locations = pathfind::get_teleport_locations(*u, board().get_team(viewing_side), see_all, ignore_units);
1542  }
1543  }
1544 
1545  if (!calc) {
1546  if(!u) {
1547  return luaL_argerror(L, 1, "unit not found OR custom cost function not provided");
1548  }
1549 
1550  calc.reset(new pathfind::shortest_path_calculator(*u, board().get_team(viewing_side),
1551  teams(), map, ignore_units, false, see_all));
1552  }
1553 
1554  pathfind::plain_route res = pathfind::a_star_search(src, dst, stop_at, *calc, map.w(), map.h(),
1555  &teleport_locations);
1556 
1557  int nb = res.steps.size();
1558  lua_createtable(L, nb, 0);
1559  for (int i = 0; i < nb; ++i)
1560  {
1561  lua_createtable(L, 2, 0);
1562  lua_pushinteger(L, res.steps[i].wml_x());
1563  lua_rawseti(L, -2, 1);
1564  lua_pushinteger(L, res.steps[i].wml_y());
1565  lua_rawseti(L, -2, 2);
1566  lua_rawseti(L, -2, i + 1);
1567  }
1568  lua_pushinteger(L, res.move_cost);
1569 
1570  return 2;
1571 }
1572 
1573 /**
1574  * Finds all the locations reachable by a unit.
1575  * - Arg 1: source location OR unit.
1576  * - Arg 2: optional table (optional fields: ignore_units, ignore_teleport, additional_turns, viewing_side).
1577  * - Ret 1: array of triples (coordinates + remaining movement).
1578  */
1580 {
1581  int arg = 1;
1582  const unit* u = nullptr;
1583 
1584  if (lua_isuserdata(L, arg))
1585  {
1586  u = &luaW_checkunit(L, arg);
1587  ++arg;
1588  }
1589  else
1590  {
1591  map_location src = luaW_checklocation(L, arg);
1592  unit_map::const_unit_iterator ui = units().find(src);
1593  if (!ui.valid())
1594  return luaL_argerror(L, 1, "unit not found");
1595  u = ui.get_shared_ptr().get();
1596  ++arg;
1597  }
1598 
1599  int viewing_side = u->side();
1600  bool ignore_units = false, see_all = false, ignore_teleport = false;
1601  int additional_turns = 0;
1602 
1603  if (lua_istable(L, arg))
1604  {
1605  ignore_units = luaW_table_get_def<bool>(L, arg, "ignore_units", false);
1606  see_all = luaW_table_get_def<bool>(L, arg, "ignore_visibility", false);
1607  ignore_teleport = luaW_table_get_def<bool>(L, arg, "ignore_teleport", false);
1608  additional_turns = luaW_table_get_def<int>(L, arg, "max_cost", additional_turns);
1609 
1610  lua_pushstring(L, "viewing_side");
1611  lua_rawget(L, arg);
1612  if (!lua_isnil(L, -1)) {
1613  int i = luaL_checkinteger(L, -1);
1614  if (i >= 1 && i <= static_cast<int>(teams().size())) viewing_side = i;
1615  else {
1616  // If there's a unit, we have a valid side, so fall back to legacy behaviour.
1617  // If we don't have a unit, legacy behaviour would be a crash, so let's not.
1618  if(u) see_all = true;
1619  deprecated_message("wesnoth.find_reach with viewing_side=0 (or an invalid side)", DEP_LEVEL::FOR_REMOVAL, {1, 17, 0}, "To consider fogged and hidden units, use ignore_visibility=true instead.");
1620  }
1621  }
1622  lua_pop(L, 1);
1623  }
1624 
1625  const team& viewing_team = board().get_team(viewing_side);
1626 
1627  pathfind::paths res(*u, ignore_units, !ignore_teleport,
1628  viewing_team, additional_turns, see_all, ignore_units);
1629 
1630  int nb = res.destinations.size();
1631  lua_createtable(L, nb, 0);
1632  for (int i = 0; i < nb; ++i)
1633  {
1635  lua_createtable(L, 2, 0);
1636  lua_pushinteger(L, s.curr.wml_x());
1637  lua_rawseti(L, -2, 1);
1638  lua_pushinteger(L, s.curr.wml_y());
1639  lua_rawseti(L, -2, 2);
1640  lua_pushinteger(L, s.move_left);
1641  lua_rawseti(L, -2, 3);
1642  lua_rawseti(L, -2, i + 1);
1643  }
1644 
1645  return 1;
1646 }
1647 
1648 template<typename T> // This is only a template so I can avoid typing out the long typename. >_>
1649 static int load_fake_units(lua_State* L, int arg, T& fake_units)
1650 {
1651  for (int i = 1, i_end = lua_rawlen(L, arg); i <= i_end; ++i)
1652  {
1653  map_location src;
1654  lua_rawgeti(L, arg, i);
1655  int entry = lua_gettop(L);
1656  if (!lua_istable(L, entry)) {
1657  goto error;
1658  }
1659 
1660  if (!luaW_tolocation(L, entry, src)) {
1661  goto error;
1662  }
1663 
1664  lua_rawgeti(L, entry, 3);
1665  if (!lua_isnumber(L, -1)) {
1666  lua_getfield(L, entry, "side");
1667  if (!lua_isnumber(L, -1)) {
1668  goto error;
1669  }
1670  }
1671  int side = lua_tointeger(L, -1);
1672 
1673  lua_rawgeti(L, entry, 4);
1674  if (!lua_isstring(L, -1)) {
1675  lua_getfield(L, entry, "type");
1676  if (!lua_isstring(L, -1)) {
1677  goto error;
1678  }
1679  }
1680  std::string unit_type = lua_tostring(L, -1);
1681 
1682  fake_units.emplace_back(src, side, unit_type);
1683 
1684  lua_settop(L, entry - 1);
1685  }
1686  return 0;
1687 error:
1688  return luaL_argerror(L, arg, "unit type table malformed - each entry should be either array of 4 elements or table with keys x, y, side, type");
1689 }
1690 
1691 /**
1692  * Is called with one or more units and builds a cost map.
1693  * - Arg 1: source location. (Or Arg 1: unit. Or Arg 1: table containing a filter)
1694  * - Arg 2: optional array of tables with 4 elements (coordinates + side + unit type string)
1695  * - Arg 3: optional table (optional fields: ignore_units, ignore_teleport, viewing_side, debug).
1696  * - Arg 4: optional table: standard location filter.
1697  * - Ret 1: array of triples (coordinates + array of tuples(summed cost + reach counter)).
1698  */
1700 {
1701  int arg = 1;
1702  unit* unit = luaW_tounit(L, arg, true);
1704  luaW_tovconfig(L, arg, filter);
1705 
1706  std::vector<const ::unit*> real_units;
1707  typedef std::vector<std::tuple<map_location, int, std::string>> unit_type_vector;
1708  unit_type_vector fake_units;
1709 
1710 
1711  if (unit) // 1. arg - unit
1712  {
1713  real_units.push_back(unit);
1714  }
1715  else if (!filter.null()) // 1. arg - filter
1716  {
1717  for(const ::unit* match : unit_filter(filter).all_matches_on_map()) {
1718  if(match->get_location().valid()) {
1719  real_units.push_back(match);
1720  }
1721  }
1722  }
1723  else // 1. arg - coordinates
1724  {
1725  map_location src = luaW_checklocation(L, arg);
1726  unit_map::const_unit_iterator ui = units().find(src);
1727  if (ui.valid())
1728  {
1729  real_units.push_back(&(*ui));
1730  }
1731  }
1732  ++arg;
1733 
1734  if (lua_istable(L, arg)) // 2. arg - optional types
1735  {
1736  load_fake_units(L, arg, fake_units);
1737  ++arg;
1738  }
1739 
1740  if(real_units.empty() && fake_units.empty())
1741  {
1742  return luaL_argerror(L, 1, "unit(s) not found");
1743  }
1744 
1745  int viewing_side = 0;
1746  bool ignore_units = true, see_all = true, ignore_teleport = false, debug = false, use_max_moves = false;
1747 
1748  if (lua_istable(L, arg)) // 4. arg - options
1749  {
1750  lua_pushstring(L, "ignore_units");
1751  lua_rawget(L, arg);
1752  if (!lua_isnil(L, -1))
1753  {
1754  ignore_units = luaW_toboolean(L, -1);
1755  }
1756  lua_pop(L, 1);
1757 
1758  lua_pushstring(L, "ignore_teleport");
1759  lua_rawget(L, arg);
1760  if (!lua_isnil(L, -1))
1761  {
1762  ignore_teleport = luaW_toboolean(L, -1);
1763  }
1764  lua_pop(L, 1);
1765 
1766  lua_pushstring(L, "viewing_side");
1767  lua_rawget(L, arg);
1768  if (!lua_isnil(L, -1))
1769  {
1770  int i = luaL_checkinteger(L, -1);
1771  if (i >= 1 && i <= static_cast<int>(teams().size()))
1772  {
1773  viewing_side = i;
1774  see_all = false;
1775  }
1776  }
1777 
1778  lua_pushstring(L, "debug");
1779  lua_rawget(L, arg);
1780  if (!lua_isnil(L, -1))
1781  {
1782  debug = luaW_toboolean(L, -1);
1783  }
1784  lua_pop(L, 1);
1785 
1786  lua_pushstring(L, "use_max_moves");
1787  lua_rawget(L, arg);
1788  if (!lua_isnil(L, -1))
1789  {
1790  use_max_moves = luaW_toboolean(L, -1);
1791  }
1792  lua_pop(L, 1);
1793  ++arg;
1794  }
1795 
1796  // 5. arg - location filter
1797  filter = vconfig::unconstructed_vconfig();
1798  std::set<map_location> location_set;
1799  luaW_tovconfig(L, arg, filter);
1800  if (filter.null())
1801  {
1802  filter = vconfig(config(), true);
1803  }
1804  filter_context & fc = game_state_;
1805  const terrain_filter t_filter(filter, &fc, false);
1806  t_filter.get_locations(location_set, true);
1807  ++arg;
1808 
1809  // build cost_map
1810  const team& viewing_team = viewing_side
1811  ? board().get_team(viewing_side)
1812  : board().teams()[0];
1813 
1814  pathfind::full_cost_map cost_map(
1815  ignore_units, !ignore_teleport, viewing_team, see_all, ignore_units);
1816 
1817  for (const ::unit* const u : real_units)
1818  {
1819  cost_map.add_unit(*u, use_max_moves);
1820  }
1821  for (const unit_type_vector::value_type& fu : fake_units)
1822  {
1823  const unit_type* ut = unit_types.find(std::get<2>(fu));
1824  cost_map.add_unit(std::get<0>(fu), ut, std::get<1>(fu));
1825  }
1826 
1827  if (debug)
1828  {
1829  if (game_display_) {
1830  game_display_->labels().clear_all();
1831  for (const map_location& loc : location_set)
1832  {
1833  std::stringstream s;
1834  s << cost_map.get_pair_at(loc).first;
1835  s << " / ";
1836  s << cost_map.get_pair_at(loc).second;
1837  game_display_->labels().set_label(loc, s.str());
1838  }
1839  }
1840  }
1841 
1842  // create return value
1843  lua_createtable(L, location_set.size(), 0);
1844  int counter = 1;
1845  for (const map_location& loc : location_set)
1846  {
1847  lua_createtable(L, 4, 0);
1848 
1849  lua_pushinteger(L, loc.wml_x());
1850  lua_rawseti(L, -2, 1);
1851 
1852  lua_pushinteger(L, loc.wml_y());
1853  lua_rawseti(L, -2, 2);
1854 
1855  lua_pushinteger(L, cost_map.get_pair_at(loc).first);
1856  lua_rawseti(L, -2, 3);
1857 
1858  lua_pushinteger(L, cost_map.get_pair_at(loc).second);
1859  lua_rawseti(L, -2, 4);
1860 
1861  lua_rawseti(L, -2, counter);
1862  ++counter;
1863  }
1864  return 1;
1865 }
1866 
1868  vconfig cfg(luaW_checkvconfig(L, 1));
1869 
1870  // Remove any old message.
1871  static int floating_label = 0;
1872  if (floating_label)
1873  font::remove_floating_label(floating_label);
1874 
1875  // Display a message on-screen
1876  std::string text = cfg["text"];
1877  if(text.empty() || !game_display_)
1878  return 0;
1879 
1880  int size = cfg["size"].to_int(font::SIZE_SMALL);
1881  int lifetime = cfg["duration"].to_int(50);
1882 
1883  color_t color = font::LABEL_COLOR;
1884 
1885  if(!cfg["color"].empty()) {
1886  color = color_t::from_rgb_string(cfg["color"]);
1887  } else if(cfg.has_attribute("red") || cfg.has_attribute("green") || cfg.has_attribute("blue")) {
1888  color = color_t(cfg["red"], cfg["green"], cfg["blue"]);
1889  }
1890 
1891  const SDL_Rect& rect = game_display_->map_outside_area();
1892 
1893  font::floating_label flabel(text);
1894  flabel.set_font_size(size);
1895  flabel.set_color(color);
1896  flabel.set_position(rect.x + rect.w/2, rect.y + rect.h/2);
1897  flabel.set_lifetime(lifetime);
1898  flabel.set_clip_rect(rect);
1899 
1900  floating_label = font::add_floating_label(flabel);
1901 
1902  return 0;
1903 }
1904 
1906 {
1907  if(game_display_) {
1908  game_display_->invalidate(loc);
1909  }
1910 
1911  units().erase(loc);
1912  resources::whiteboard->on_kill_unit();
1913 }
1914 
1915 /**
1916  * Places a unit on the map.
1917  * - Arg 1: (optional) location.
1918  * - Arg 2: Unit (WML table or proxy), or nothing/nil to delete.
1919  * OR
1920  * - Arg 1: Unit (WML table or proxy)
1921  * - Arg 2: (optional) location
1922  * - Arg 3: (optional) boolean
1923  */
1925 {
1926  if(map_locked_) {
1927  return luaL_error(L, "Attempted to move a unit while the map is locked");
1928  }
1929 
1930  map_location loc;
1931  if (luaW_tolocation(L, 2, loc)) {
1932  if (!map().on_board(loc)) {
1933  return luaL_argerror(L, 2, "invalid location");
1934  }
1935  }
1936 
1937  if((luaW_isunit(L, 1))) {
1938  lua_unit& u = *luaW_checkunit_ref(L, 1);
1939  if(u.on_map() && u->get_location() == loc) {
1940  return 0;
1941  }
1942  if (!loc.valid()) {
1943  loc = u->get_location();
1944  if (!map().on_board(loc))
1945  return luaL_argerror(L, 1, "invalid location");
1946  }
1947 
1948  put_unit_helper(loc);
1949  u.put_map(loc);
1950  u.get_shared()->anim_comp().set_standing();
1951  } else if(!lua_isnoneornil(L, 1)) {
1952  const vconfig* vcfg = nullptr;
1953  config cfg = luaW_checkconfig(L, 1, vcfg);
1954  if (!map().on_board(loc)) {
1955  loc.set_wml_x(cfg["x"]);
1956  loc.set_wml_y(cfg["y"]);
1957  if (!map().on_board(loc))
1958  return luaL_argerror(L, 2, "invalid location");
1959  }
1960 
1961  unit_ptr u = unit::create(cfg, true, vcfg);
1962  put_unit_helper(loc);
1963  u->set_location(loc);
1964  units().insert(u);
1965  }
1966 
1967  // Fire event if using the deprecated version or if the final argument is not false
1968  // If the final boolean argument is omitted, the actual final argument (the unit or location) will always yield true.
1969  if(luaW_toboolean(L, -1)) {
1970  play_controller_.pump().fire("unit_placed", loc);
1971  }
1972  return 0;
1973 }
1974 
1975 /**
1976  * Erases a unit from the map
1977  * - Arg 1: Unit to erase OR Location to erase unit
1978  */
1980 {
1981  if(map_locked_) {
1982  return luaL_error(L, "Attempted to remove a unit while the map is locked");
1983  }
1984  map_location loc;
1985 
1986  if(luaW_isunit(L, 1)) {
1987  lua_unit& u = *luaW_checkunit_ref(L, 1);
1988  if (u.on_map()) {
1989  loc = u->get_location();
1990  if (!map().on_board(loc)) {
1991  return luaL_argerror(L, 1, "invalid location");
1992  }
1993  } else if (int side = u.on_recall_list()) {
1994  team &t = board().get_team(side);
1995  // Should it use underlying ID instead?
1997  } else {
1998  return luaL_argerror(L, 1, "can't erase private units");
1999  }
2000  } else if (luaW_tolocation(L, 1, loc)) {
2001  if (!map().on_board(loc)) {
2002  return luaL_argerror(L, 1, "invalid location");
2003  }
2004  } else {
2005  return luaL_argerror(L, 1, "expected unit or location");
2006  }
2007 
2008  units().erase(loc);
2009  resources::whiteboard->on_kill_unit();
2010  return 0;
2011 }
2012 
2013 /**
2014  * Puts a unit on a recall list.
2015  * - Arg 1: WML table or unit.
2016  * - Arg 2: (optional) side.
2017  */
2019 {
2020  if(map_locked_) {
2021  return luaL_error(L, "Attempted to move a unit while the map is locked");
2022  }
2023  lua_unit *lu = nullptr;
2024  unit_ptr u = unit_ptr();
2025  int side = lua_tointeger(L, 2);
2026  if (static_cast<unsigned>(side) > teams().size()) side = 0;
2027 
2028  if(luaW_isunit(L, 1)) {
2029  lu = luaW_checkunit_ref(L, 1);
2030  u = lu->get_shared();
2031  if(lu->on_recall_list() && lu->on_recall_list() == side) {
2032  return luaL_argerror(L, 1, "unit already on recall list");
2033  }
2034  } else {
2035  const vconfig* vcfg = nullptr;
2036  config cfg = luaW_checkconfig(L, 1, vcfg);
2037  u = unit::create(cfg, true, vcfg);
2038  }
2039 
2040  if (!side) {
2041  side = u->side();
2042  } else {
2043  u->set_side(side);
2044  }
2045  team &t = board().get_team(side);
2046  // Avoid duplicates in the recall list.
2047  std::size_t uid = u->underlying_id();
2049  t.recall_list().add(u);
2050  if (lu) {
2051  if (lu->on_map()) {
2052  units().erase(u->get_location());
2053  resources::whiteboard->on_kill_unit();
2054  u->anim_comp().clear_haloes();
2055  }
2056  lu->lua_unit::~lua_unit();
2057  new(lu) lua_unit(side, uid);
2058  }
2059 
2060  return 0;
2061 }
2062 
2063 /**
2064  * Extracts a unit from the map or a recall list and gives it to Lua.
2065  * - Arg 1: unit userdata.
2066  */
2068 {
2069  if(map_locked_) {
2070  return luaL_error(L, "Attempted to remove a unit while the map is locked");
2071  }
2072  lua_unit* lu = luaW_checkunit_ref(L, 1);
2073  unit_ptr u = lu->get_shared();
2074 
2075  if (lu->on_map()) {
2076  u = units().extract(u->get_location());
2077  assert(u);
2078  u->anim_comp().clear_haloes();
2079  } else if (int side = lu->on_recall_list()) {
2080  team &t = board().get_team(side);
2081  unit_ptr v = u->clone();
2082  t.recall_list().erase_if_matches_id(u->id());
2083  u = v;
2084  } else {
2085  return 0;
2086  }
2087 
2088  lu->lua_unit::~lua_unit();
2089  new(lu) lua_unit(u);
2090  return 0;
2091 }
2092 
2093 /**
2094  * Finds a vacant tile.
2095  * - Arg 1: location.
2096  * - Arg 2: optional unit for checking movement type.
2097  * - Rets 1,2: location.
2098  */
2100 {
2101  map_location loc = luaW_checklocation(L, 1);
2102 
2103  unit_ptr u;
2104  if (!lua_isnoneornil(L, 2)) {
2105  if(luaW_isunit(L, 2)) {
2106  u = luaW_checkunit_ptr(L, 2, false);
2107  } else {
2108  const vconfig* vcfg = nullptr;
2109  config cfg = luaW_checkconfig(L, 2, vcfg);
2110  u = unit::create(cfg, false, vcfg);
2111  }
2112  }
2113 
2114  map_location res = find_vacant_tile(loc, pathfind::VACANT_ANY, u.get());
2115 
2116  if (!res.valid()) return 0;
2117  lua_pushinteger(L, res.wml_x());
2118  lua_pushinteger(L, res.wml_y());
2119  return 2;
2120 }
2121 
2122 /**
2123  * Floats some text on the map.
2124  * - Arg 1: location.
2125  * - Arg 2: string.
2126  * - Arg 3: color.
2127  */
2129 {
2130  map_location loc = luaW_checklocation(L, 1);
2131  color_t color = font::LABEL_COLOR;
2132 
2133  t_string text = luaW_checktstring(L, 2);
2134  if (!lua_isnoneornil(L, 3)) {
2136  }
2137 
2138  if (game_display_) {
2139  game_display_->float_label(loc, text, color);
2140  }
2141  return 0;
2142 }
2143 
2144 /**
2145  * Creates a unit from its WML description.
2146  * - Arg 1: WML table.
2147  * - Ret 1: unit userdata.
2148  */
2150 {
2151  const vconfig* vcfg = nullptr;
2152  config cfg = luaW_checkconfig(L, 1, vcfg);
2153  unit_ptr u = unit::create(cfg, true, vcfg);
2154  luaW_pushunit(L, u);
2155  return 1;
2156 }
2157 
2158 /**
2159  * Copies a unit.
2160  * - Arg 1: unit userdata.
2161  * - Ret 1: unit userdata.
2162  */
2164 {
2165  unit& u = luaW_checkunit(L, 1);
2166  luaW_pushunit(L, u.clone());
2167  return 1;
2168 }
2169 
2170 /**
2171  * Returns unit resistance against a given attack type.
2172  * - Arg 1: unit userdata.
2173  * - Arg 2: string containing the attack type.
2174  * - Arg 3: boolean indicating if attacker.
2175  * - Arg 4: optional location.
2176  * - Ret 1: integer.
2177  */
2179 {
2180  const unit& u = luaW_checkunit(L, 1);
2181  char const *m = luaL_checkstring(L, 2);
2182  bool a = false;
2183  map_location loc = u.get_location();
2184 
2185  if(lua_isboolean(L, 3)) {
2186  a = luaW_toboolean(L, 3);
2187  if(!lua_isnoneornil(L, 4)) {
2188  loc = luaW_checklocation(L, 4);
2189  }
2190  } else if(!lua_isnoneornil(L, 3)) {
2191  loc = luaW_checklocation(L, 3);
2192  }
2193 
2194  lua_pushinteger(L, 100 - u.resistance_against(m, a, loc));
2195  return 1;
2196 }
2197 
2198 /**
2199  * Returns unit movement cost on a given terrain.
2200  * - Arg 1: unit userdata.
2201  * - Arg 2: string containing the terrain type.
2202  * - Ret 1: integer.
2203  */
2205 {
2206  const unit& u = luaW_checkunit(L, 1);
2208  map_location loc;
2209  if(luaW_tolocation(L, 2, loc)) {
2210  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2211  } else if(lua_isstring(L, 2)) {
2212  char const *m = luaL_checkstring(L, 2);
2214  } else return luaW_type_error(L, 2, "location or terrain string");
2215  lua_pushinteger(L, u.movement_cost(t));
2216  return 1;
2217 }
2218 
2219 /**
2220  * Returns unit vision cost on a given terrain.
2221  * - Arg 1: unit userdata.
2222  * - Arg 2: string containing the terrain type.
2223  * - Ret 1: integer.
2224  */
2226 {
2227  const unit& u = luaW_checkunit(L, 1);
2229  map_location loc;
2230  if(luaW_tolocation(L, 2, loc)) {
2231  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2232  } else if(lua_isstring(L, 2)) {
2233  char const *m = luaL_checkstring(L, 2);
2235  } else return luaW_type_error(L, 2, "location or terrain string");
2236  lua_pushinteger(L, u.vision_cost(t));
2237  return 1;
2238 }
2239 
2240 /**
2241  * Returns unit jamming cost on a given terrain.
2242  * - Arg 1: unit userdata.
2243  * - Arg 2: string containing the terrain type.
2244  * - Ret 1: integer.
2245  */
2247 {
2248  const unit& u = luaW_checkunit(L, 1);
2250  map_location loc;
2251  if(luaW_tolocation(L, 2, loc)) {
2252  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2253  } else if(lua_isstring(L, 2)) {
2254  char const *m = luaL_checkstring(L, 2);
2256  } else return luaW_type_error(L, 2, "location or terrain string");
2257  lua_pushinteger(L, u.jamming_cost(t));
2258  return 1;
2259 }
2260 
2261 /**
2262  * Returns unit defense on a given terrain.
2263  * - Arg 1: unit userdata.
2264  * - Arg 2: string containing the terrain type.
2265  * - Ret 1: integer.
2266  */
2268 {
2269  const unit& u = luaW_checkunit(L, 1);
2271  map_location loc;
2272  if(luaW_tolocation(L, 2, loc)) {
2273  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2274  } else if(lua_isstring(L, 2)) {
2275  char const *m = luaL_checkstring(L, 2);
2277  } else return luaW_type_error(L, 2, "location or terrain string");
2278  lua_pushinteger(L, 100 - u.defense_modifier(t));
2279  return 1;
2280 }
2281 
2282 /**
2283  * Returns true if the unit has the given ability enabled.
2284  * - Arg 1: unit userdata.
2285  * - Arg 2: string.
2286  * - Ret 1: boolean.
2287  */
2289 {
2290  const unit& u = luaW_checkunit(L, 1);
2291  char const *m = luaL_checkstring(L, 2);
2293  return 1;
2294 }
2295 
2296 /**
2297  * Changes a unit to the given unit type.
2298  * - Arg 1: unit userdata.
2299  * - Arg 2: unit type name
2300  * - Arg 3: (optional) unit variation name
2301  */
2303 {
2304  unit& u = luaW_checkunit(L, 1);
2305  char const *m = luaL_checkstring(L, 2);
2306  const unit_type *utp = unit_types.find(m);
2307  if (!utp) return luaL_argerror(L, 2, "unknown unit type");
2308  if(lua_isstring(L, 3)) {
2309  const std::string& m2 = lua_tostring(L, 3);
2310  if(!utp->has_variation(m2)) return luaL_argerror(L, 2, "unknown unit variation");
2311  utp = &utp->get_variation(m2);
2312  }
2313  u.advance_to(*utp);
2314 
2315  return 0;
2316 }
2317 
2318 /**
2319  * Puts a table at the top of the stack with some combat result.
2320  */
2321 static void luaW_pushsimdata(lua_State *L, const combatant &cmb)
2322 {
2323  int n = cmb.hp_dist.size();
2324  lua_createtable(L, 0, 4);
2325  lua_pushnumber(L, cmb.poisoned);
2326  lua_setfield(L, -2, "poisoned");
2327  lua_pushnumber(L, cmb.slowed);
2328  lua_setfield(L, -2, "slowed");
2329  lua_pushnumber(L, cmb.untouched);
2330  lua_setfield(L, -2, "untouched");
2331  lua_pushnumber(L, cmb.average_hp());
2332  lua_setfield(L, -2, "average_hp");
2333  lua_createtable(L, n, 0);
2334  for (int i = 0; i < n; ++i) {
2335  lua_pushnumber(L, cmb.hp_dist[i]);
2336  lua_rawseti(L, -2, i);
2337  }
2338  lua_setfield(L, -2, "hp_chance");
2339 }
2340 
2341 /**
2342  * Puts a table at the top of the stack with information about the combatants' weapons.
2343  */
2345 {
2346 
2347  lua_createtable(L, 0, 16);
2348 
2349  lua_pushnumber(L, bcustats.num_blows);
2350  lua_setfield(L, -2, "num_blows");
2351  lua_pushnumber(L, bcustats.damage);
2352  lua_setfield(L, -2, "damage");
2353  lua_pushnumber(L, bcustats.chance_to_hit);
2354  lua_setfield(L, -2, "chance_to_hit");
2355  lua_pushboolean(L, bcustats.poisons);
2356  lua_setfield(L, -2, "poisons");
2357  lua_pushboolean(L, bcustats.slows);
2358  lua_setfield(L, -2, "slows");
2359  lua_pushboolean(L, bcustats.petrifies);
2360  lua_setfield(L, -2, "petrifies");
2361  lua_pushboolean(L, bcustats.plagues);
2362  lua_setfield(L, -2, "plagues");
2363  lua_pushstring(L, bcustats.plague_type.c_str());
2364  lua_setfield(L, -2, "plague_type");
2365  lua_pushboolean(L, bcustats.backstab_pos);
2366  lua_setfield(L, -2, "backstabs");
2367  lua_pushnumber(L, bcustats.rounds);
2368  lua_setfield(L, -2, "rounds");
2369  lua_pushboolean(L, bcustats.firststrike);
2370  lua_setfield(L, -2, "firststrike");
2371  lua_pushboolean(L, bcustats.drains);
2372  lua_setfield(L, -2, "drains");
2373  lua_pushnumber(L, bcustats.drain_constant);
2374  lua_setfield(L, -2, "drain_constant");
2375  lua_pushnumber(L, bcustats.drain_percent);
2376  lua_setfield(L, -2, "drain_percent");
2377 
2378 
2379  //if we called simulate_combat without giving an explicit weapon this can be useful.
2380  lua_pushnumber(L, bcustats.attack_num);
2381  lua_setfield(L, -2, "attack_num"); // DEPRECATED
2382  lua_pushnumber(L, bcustats.attack_num + 1);
2383  lua_setfield(L, -2, "number");
2384  //this is nullptr when there is no counter weapon
2385  if(bcustats.weapon != nullptr)
2386  {
2387  lua_pushstring(L, bcustats.weapon->id().c_str());
2388  lua_setfield(L, -2, "name");
2389  luaW_pushweapon(L, bcustats.weapon);
2390  lua_setfield(L, -2, "weapon");
2391  }
2392 
2393 }
2394 
2395 /**
2396  * Simulates a combat between two units.
2397  * - Arg 1: attacker userdata.
2398  * - Arg 2: optional weapon index.
2399  * - Arg 3: defender userdata.
2400  * - Arg 4: optional weapon index.
2401  *
2402  * - Ret 1: attacker results.
2403  * - Ret 2: defender results.
2404  * - Ret 3: info about the attacker weapon.
2405  * - Ret 4: info about the defender weapon.
2406  */
2408 {
2409  int arg_num = 1, att_w = -1, def_w = -1;
2410 
2411  unit_const_ptr att = luaW_checkunit(L, arg_num).shared_from_this();
2412  ++arg_num;
2413  if (lua_isnumber(L, arg_num)) {
2414  att_w = lua_tointeger(L, arg_num) - 1;
2415  if (att_w < 0 || att_w >= static_cast<int>(att->attacks().size()))
2416  return luaL_argerror(L, arg_num, "weapon index out of bounds");
2417  ++arg_num;
2418  }
2419 
2420  unit_const_ptr def = luaW_checkunit(L, arg_num).shared_from_this();
2421  ++arg_num;
2422  if (lua_isnumber(L, arg_num)) {
2423  def_w = lua_tointeger(L, arg_num) - 1;
2424  if (def_w < 0 || def_w >= static_cast<int>(def->attacks().size()))
2425  return luaL_argerror(L, arg_num, "weapon index out of bounds");
2426  ++arg_num;
2427  }
2428 
2429  battle_context context(units(), att->get_location(),
2430  def->get_location(), att_w, def_w, 0.0, nullptr, att, def);
2431 
2432  luaW_pushsimdata(L, context.get_attacker_combatant());
2433  luaW_pushsimdata(L, context.get_defender_combatant());
2434  luaW_pushsimweapon(L, context.get_attacker_stats());
2435  luaW_pushsimweapon(L, context.get_defender_stats());
2436  return 4;
2437 }
2438 
2439 /**
2440  * Modifies the music playlist.
2441  * - Arg 1: WML table, or nil to force changes.
2442  */
2444 {
2445  deprecated_message("wesnoth.set_music", DEP_LEVEL::INDEFINITE, "", "Use the wesnoth.playlist table instead!");
2446  if (lua_isnoneornil(L, 1)) {
2448  return 0;
2449  }
2450 
2451  config cfg = luaW_checkconfig(L, 1);
2453  return 0;
2454 }
2455 
2456 /**
2457  * Plays a sound, possibly repeated.
2458  * - Arg 1: string.
2459  * - Arg 2: optional integer.
2460  */
2462 {
2463  char const *m = luaL_checkstring(L, 1);
2464  if (play_controller_.is_skipping_replay()) return 0;
2465  int repeats = lua_tointeger(L, 2);
2466  sound::play_sound(m, sound::SOUND_FX, repeats);
2467  return 0;
2468 }
2469 
2470 /**
2471  * Gets/sets the current sound volume
2472  * - Arg 1: (optional) New volume to set
2473  * - Return: Original volume
2474  */
2476 {
2477  int vol = preferences::sound_volume();
2478  lua_pushnumber(L, sound::get_sound_volume() * 100.0 / vol);
2479  if(lua_isnumber(L, 1)) {
2480  float rel = lua_tonumber(L, 1);
2481  if(rel < 0.0f || rel > 100.0f) {
2482  return luaL_argerror(L, 1, "volume must be in range 0..100");
2483  }
2484  vol = static_cast<int>(rel*vol / 100.0f);
2486  }
2487  return 1;
2488 }
2489 
2490 /**
2491  * Scrolls to given tile.
2492  * - Arg 1: location.
2493  * - Arg 2: boolean preventing scroll to fog.
2494  * - Arg 3: boolean specifying whether to warp instantly.
2495  * - Arg 4: boolean specifying whether to skip if already onscreen
2496  */
2498 {
2499  map_location loc = luaW_checklocation(L, 1);
2500  bool check_fogged = luaW_toboolean(L, 2);
2502  ? luaW_toboolean(L, 3)
2505  : luaW_toboolean(L, 3)
2508  ;
2509  if (game_display_) {
2510  game_display_->scroll_to_tile(loc, scroll, check_fogged);
2511  }
2512  return 0;
2513 }
2514 
2516 {
2517  events::command_disabler command_disabler;
2518  deprecated_message("wesnoth.select_hex", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Use wesnoth.units.select and/or wesnoth.interface.highlight_hex instead.");
2519 
2520  // Need this because check_location may change the stack
2521  // By doing this now, we ensure that it won't do so when
2522  // intf_select_unit and intf_highlight_hex call it.
2523  const map_location loc = luaW_checklocation(L, 1);
2524  luaW_pushlocation(L, loc);
2525  lua_replace(L, 1);
2526 
2527  intf_select_unit(L);
2528  if(!lua_isnoneornil(L, 2) && luaW_toboolean(L,2)) {
2529  intf_highlight_hex(L);
2530  }
2531  return 0;
2532 }
2533 
2534 /**
2535  * Selects and highlights the given location on the map.
2536  * - Arg 1: location.
2537  * - Args 2,3: booleans
2538  */
2540 {
2541  events::command_disabler command_disabler;
2542  if(lua_isnoneornil(L, 1)) {
2543  play_controller_.get_mouse_handler_base().select_hex(map_location::null_location(), false, false, false);
2544  return 0;
2545  }
2546  const map_location loc = luaW_checklocation(L, 1);
2547  if(!map().on_board(loc)) return luaL_argerror(L, 1, "not on board");
2548  bool highlight = true;
2549  if(!lua_isnoneornil(L, 2))
2550  highlight = luaW_toboolean(L, 2);
2551  const bool fire_event = luaW_toboolean(L, 3);
2552  play_controller_.get_mouse_handler_base().select_hex(
2553  loc, false, highlight, fire_event);
2554  return 0;
2555 }
2556 
2557 /**
2558  * Deselects any highlighted hex on the map.
2559  * No arguments or return values
2560  */
2562 {
2563  if(game_display_) {
2564  game_display_->highlight_hex(map_location::null_location());
2565  }
2566 
2567  return 0;
2568 }
2569 
2570 /**
2571  * Return true if a replay is in progress but the player has chosen to skip it
2572  */
2574 {
2575  bool skipping = play_controller_.is_skipping_replay() || play_controller_.is_skipping_story();
2576  if (!skipping) {
2577  skipping = game_state_.events_manager_->pump().context_skip_messages();
2578  }
2579  lua_pushboolean(L, skipping);
2580  return 1;
2581 }
2582 
2583 /**
2584  * Set whether to skip messages
2585  * Arg 1 (optional) - boolean
2586  */
2588 {
2589  bool skip = true;
2590  if (!lua_isnone(L, 1)) {
2591  skip = luaW_toboolean(L, 1);
2592  }
2593  game_state_.events_manager_->pump().context_skip_messages(skip);
2594  return 0;
2595 }
2596 
2597 namespace
2598 {
2599  struct lua_synchronize : mp_sync::user_choice
2600  {
2601  lua_State *L;
2602  int user_choice_index;
2603  int random_choice_index;
2604  int ai_choice_index;
2605  std::string desc;
2606  lua_synchronize(lua_State *l, const std::string& descr, int user_index, int random_index = 0, int ai_index = 0)
2607  : L(l)
2608  , user_choice_index(user_index)
2609  , random_choice_index(random_index)
2610  , ai_choice_index(ai_index != 0 ? ai_index : user_index)
2611  , desc(descr)
2612  {}
2613 
2614  virtual config query_user(int side) const override
2615  {
2616  bool is_local_ai = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).board().get_team(side).is_local_ai();
2617  config cfg;
2618  query_lua(side, is_local_ai ? ai_choice_index : user_choice_index, cfg);
2619  return cfg;
2620  }
2621 
2622  virtual config random_choice(int side) const override
2623  {
2624  config cfg;
2625  if(random_choice_index != 0 && lua_isfunction(L, random_choice_index)) {
2626  query_lua(side, random_choice_index, cfg);
2627  }
2628  return cfg;
2629  }
2630 
2631  virtual std::string description() const override
2632  {
2633  return desc;
2634  }
2635 
2636  void query_lua(int side, int function_index, config& cfg) const
2637  {
2638  assert(cfg.empty());
2639  lua_pushvalue(L, function_index);
2640  lua_pushnumber(L, side);
2641  if (luaW_pcall(L, 1, 1, false)) {
2642  if(!luaW_toconfig(L, -1, cfg)) {
2643  lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).log_error("function returned to wesnoth.synchronize_choice a table which was partially invalid");
2644  }
2645  }
2646  }
2647  //Although lua's sync_choice can show a dialog, (and will in most cases)
2648  //we return false to enable other possible things that do not contain UI things.
2649  //it's in the responsibility of the umc dev to not show dialogs during prestart events.
2650  virtual bool is_visible() const override { return false; }
2651  };
2652 }//unnamed namespace for lua_synchronize
2653 
2654 /**
2655  * Ensures a value is synchronized among all the clients.
2656  * - Arg 1: optional string specifying the type id of the choice.
2657  * - Arg 2: function to compute the value, called if the client is the master.
2658  * - Arg 3: optional function, called instead of the first function if the user is not human.
2659  * - Arg 4: optional integer specifying, on which side the function should be evaluated.
2660  * - Ret 1: WML table returned by the function.
2661  */
2663 {
2664  std::string tagname = "input";
2665  t_string desc = _("input");
2666  int human_func = 0;
2667  int ai_func = 0;
2668  int side_for;
2669 
2670  int nextarg = 1;
2671  if(!lua_isfunction(L, nextarg) && luaW_totstring(L, nextarg, desc) ) {
2672  ++nextarg;
2673  }
2674  if(lua_isfunction(L, nextarg)) {
2675  human_func = nextarg++;
2676  }
2677  else {
2678  return luaL_argerror(L, nextarg, "expected a function");
2679  }
2680  if(lua_isfunction(L, nextarg)) {
2681  ai_func = nextarg++;
2682  }
2683  side_for = lua_tointeger(L, nextarg);
2684 
2685  config cfg = mp_sync::get_user_choice(tagname, lua_synchronize(L, desc, human_func, 0, ai_func), side_for);
2686  luaW_pushconfig(L, cfg);
2687  return 1;
2688 }
2689 /**
2690  * Ensures a value is synchronized among all the clients.
2691  * - Arg 1: optional string the id of this type of user input, may only contain characters a-z and '_'
2692  * - Arg 2: function to compute the value, called if the client is the master.
2693  * - Arg 3: an optional function to compute the value, if the side was null/empty controlled.
2694  * - Arg 4: an array of integers specifying, on which side the function should be evaluated.
2695  * - Ret 1: a map int -> WML tabls.
2696  */
2698 {
2699  std::string tagname = "input";
2700  t_string desc = _("input");
2701  int human_func = 0;
2702  int null_func = 0;
2703  std::vector<int> sides_for;
2704 
2705  int nextarg = 1;
2706  if(!lua_isfunction(L, nextarg) && luaW_totstring(L, nextarg, desc) ) {
2707  ++nextarg;
2708  }
2709  if(lua_isfunction(L, nextarg)) {
2710  human_func = nextarg++;
2711  }
2712  else {
2713  return luaL_argerror(L, nextarg, "expected a function");
2714  }
2715  if(lua_isfunction(L, nextarg)) {
2716  null_func = nextarg++;
2717  };
2718  sides_for = lua_check<std::vector<int>>(L, nextarg++);
2719 
2720  lua_push(L, mp_sync::get_user_choice_multiple_sides(tagname, lua_synchronize(L, desc, human_func, null_func), std::set<int>(sides_for.begin(), sides_for.end())));
2721  return 1;
2722 }
2723 
2724 
2725 /**
2726  * Calls a function in an unsynced context (this specially means that all random calls used by that function will be unsynced).
2727  * This is usually used together with an unsynced if like 'if controller != network'
2728  * - Arg 1: function that will be called during the unsynced context.
2729  */
2731 {
2732  set_scontext_unsynced sync;
2733  lua_pushvalue(L, 1);
2734  luaW_pcall(L, 0, 0, false);
2735  return 0;
2736 }
2737 
2738 /**
2739  * Gets all the locations matching a given filter.
2740  * - Arg 1: WML table.
2741  * - Arg 2: Optional reference unit (teleport_unit)
2742  * - Ret 1: array of integer pairs.
2743  */
2745 {
2746  vconfig filter = luaW_checkvconfig(L, 1);
2747 
2748  std::set<map_location> res;
2749  filter_context & fc = game_state_;
2750  const terrain_filter t_filter(filter, &fc, false);
2751  if(luaW_isunit(L, 2)) {
2752  t_filter.get_locations(res, *luaW_tounit(L, 2), true);
2753  } else {
2754  t_filter.get_locations(res, true);
2755  }
2756 
2757  lua_createtable(L, res.size(), 0);
2758  int i = 1;
2759  for (const map_location& loc : res)
2760  {
2761  lua_createtable(L, 2, 0);
2762  lua_pushinteger(L, loc.wml_x());
2763  lua_rawseti(L, -2, 1);
2764  lua_pushinteger(L, loc.wml_y());
2765  lua_rawseti(L, -2, 2);
2766  lua_rawseti(L, -2, i);
2767  ++i;
2768  }
2769  return 1;
2770 }
2771 
2772 /**
2773  * Gets all the villages matching a given filter, or all the villages on the map if no filter is given.
2774  * - Arg 1: WML table (optional).
2775  * - Ret 1: array of integer pairs.
2776  */
2778 {
2779  std::vector<map_location> locs = map().villages();
2780  lua_newtable(L);
2781  int i = 1;
2782 
2783  vconfig filter = luaW_checkvconfig(L, 1);
2784 
2785  filter_context & fc = game_state_;
2786  for(std::vector<map_location>::const_iterator it = locs.begin(); it != locs.end(); ++it) {
2787  bool matches = terrain_filter(filter, &fc, false).match(*it);
2788  if (matches) {
2789  lua_createtable(L, 2, 0);
2790  lua_pushinteger(L, it->wml_x());
2791  lua_rawseti(L, -2, 1);
2792  lua_pushinteger(L, it->wml_y());
2793  lua_rawseti(L, -2, 2);
2794  lua_rawseti(L, -2, i);
2795  ++i;
2796  }
2797  }
2798  return 1;
2799 }
2800 
2801 /**
2802  * Matches a location against the given filter.
2803  * - Arg 1: location.
2804  * - Arg 2: WML table.
2805  * - Arg 3: Optional reference unit (teleport_unit)
2806  * - Ret 1: boolean.
2807  */
2809 {
2810  map_location loc = luaW_checklocation(L, 1);
2811  vconfig filter = luaW_checkvconfig(L, 2, true);
2812 
2813  if (filter.null()) {
2814  lua_pushboolean(L, true);
2815  return 1;
2816  }
2817 
2818  filter_context & fc = game_state_;
2819  const terrain_filter t_filter(filter, &fc, false);
2820  if(luaW_isunit(L, 3)) {
2821  lua_pushboolean(L, t_filter.match(loc, *luaW_tounit(L, 3)));
2822  } else {
2823  lua_pushboolean(L, t_filter.match(loc));
2824  }
2825  return 1;
2826 }
2827 
2828 
2829 
2830 /**
2831  * Matches a side against the given filter.
2832  * - Args 1: side number.
2833  * - Arg 2: WML table.
2834  * - Ret 1: boolean.
2835  */
2837 {
2838  vconfig filter = luaW_checkvconfig(L, 2, true);
2839 
2840  if (filter.null()) {
2841  lua_pushboolean(L, true);
2842  return 1;
2843  }
2844 
2845  filter_context & fc = game_state_;
2846  side_filter s_filter(filter, &fc);
2847 
2848  if(team* t = luaW_toteam(L, 1)) {
2849  lua_pushboolean(L, s_filter.match(*t));
2850  } else {
2851  unsigned side = luaL_checkinteger(L, 1) - 1;
2852  if (side >= teams().size()) return 0;
2853  lua_pushboolean(L, s_filter.match(side + 1));
2854  }
2855  return 1;
2856 }
2857 
2859 {
2860  int team_i;
2861  if(team* t = luaW_toteam(L, 1)) {
2862  team_i = t->side();
2863  } else {
2864  team_i = luaL_checkinteger(L, 1);
2865  }
2866  std::string flag = luaL_optlstring(L, 2, "", nullptr);
2867  std::string color = luaL_optlstring(L, 3, "", nullptr);
2868 
2869  if(flag.empty() && color.empty()) {
2870  return 0;
2871  }
2872  if(team_i < 1 || static_cast<std::size_t>(team_i) > teams().size()) {
2873  return luaL_error(L, "set_side_id: side number %d out of range", team_i);
2874  }
2875  team& side = board().get_team(team_i);
2876 
2877  if(!color.empty()) {
2878  side.set_color(color);
2879  }
2880  if(!flag.empty()) {
2881  side.set_flag(flag);
2882  }
2883 
2884  game_display_->reinit_flags_for_team(side);
2885  return 0;
2886 }
2887 
2888 static int intf_modify_ai(lua_State *L, const char* action)
2889 {
2890  int side_num;
2891  if(team* t = luaW_toteam(L, 1)) {
2892  side_num = t->side();
2893  } else {
2894  side_num = luaL_checkinteger(L, 1);
2895  }
2896  std::string path = luaL_checkstring(L, 2);
2897  config cfg {
2898  "action", action,
2899  "path", path
2900  };
2901  if(strcmp(action, "delete") == 0) {
2903  return 0;
2904  }
2905  config component = luaW_checkconfig(L, 3);
2906  std::size_t len = std::string::npos, open_brak = path.find_last_of('[');
2907  std::size_t dot = path.find_last_of('.');
2908  if(open_brak != len) {
2909  len = open_brak - dot - 1;
2910  }
2911  cfg.add_child(path.substr(dot + 1, len), component);
2913  return 0;
2914 }
2915 
2917 {
2918  int side_num;
2919  if(team* t = luaW_toteam(L, 1)) {
2920  side_num = t->side();
2921  } else {
2922  side_num = luaL_checkinteger(L, 1);
2923  }
2924  if(lua_isstring(L, 2)) {
2925  std::string file = luaL_checkstring(L, 2);
2926  if(!ai::manager::get_singleton().add_ai_for_side_from_file(side_num, file)) {
2927  std::string err = formatter() << "Could not load AI for side " << side_num << " from file " << file;
2928  lua_pushlstring(L, err.c_str(), err.length());
2929  return lua_error(L);
2930  }
2931  } else {
2933  }
2934  return 0;
2935 }
2936 
2938 {
2939  int side_num;
2940  if(team* t = luaW_toteam(L, 1)) {
2941  side_num = t->side();
2942  } else {
2943  side_num = luaL_checkinteger(L, 1);
2944  }
2945  config cfg = luaW_checkconfig(L, 2);
2946  if(!cfg.has_child("ai")) {
2947  cfg = config {"ai", cfg};
2948  }
2949  bool added_dummy_stage = false;
2950  if(!cfg.child("ai").has_child("stage")) {
2951  added_dummy_stage = true;
2952  cfg.child("ai").add_child("stage", config {"name", "empty"});
2953  }
2955  if(added_dummy_stage) {
2956  for(auto iter = cfg.ordered_begin(); iter != cfg.ordered_end(); iter++) {
2957  if(iter->key == "stage" && iter->cfg["name"] == "empty") {
2958  iter = cfg.erase(iter);
2959  }
2960  }
2961  }
2963  return 0;
2964 }
2965 
2967 {
2968  unsigned i = luaL_checkinteger(L, 1);
2969  if(i < 1 || i > teams().size()) return 0;
2970  luaW_pushteam(L, board().get_team(i));
2971  return 1;
2972 }
2973 
2974 /**
2975  * Returns a proxy table array for all sides matching the given SSF.
2976  * - Arg 1: SSF
2977  * - Ret 1: proxy table array
2978  */
2980 {
2981  LOG_LUA << "intf_get_sides called: this = " << std::hex << this << std::dec << " myname = " << my_name() << std::endl;
2982  std::vector<int> sides;
2983  const vconfig ssf = luaW_checkvconfig(L, 1, true);
2984  if(ssf.null()) {
2985  for (unsigned side_number = 1; side_number <= teams().size(); ++side_number) {
2986  sides.push_back(side_number);
2987  }
2988  } else {
2989  filter_context & fc = game_state_;
2990 
2991  side_filter filter(ssf, &fc);
2992  sides = filter.get_teams();
2993  }
2994 
2995  lua_settop(L, 0);
2996  lua_createtable(L, sides.size(), 0);
2997  unsigned index = 1;
2998  for(int side : sides) {
2999  luaW_pushteam(L, board().get_team(side));
3000  lua_rawseti(L, -2, index);
3001  ++index;
3002  }
3003 
3004  return 1;
3005 }
3006 
3007 /**
3008  * .Returns information about the global traits known to the engine.
3009  * - Ret 1: Table with named fields holding wml tables describing the traits.
3010  */
3012 {
3013  lua_newtable(L);
3014  for(const config& trait : unit_types.traits()) {
3015  const std::string& id = trait["id"];
3016  //It seems the engine does nowhere check the id field for emptyness or duplicates
3017  //(also not later on).
3018  //However, the worst thing to happen is that the trait read later overwrites the older one,
3019  //and this is not the right place for such checks.
3020  lua_pushstring(L, id.c_str());
3021  luaW_pushconfig(L, trait);
3022  lua_rawset(L, -3);
3023  }
3024  return 1;
3025 }
3026 
3027 /**
3028  * Adds a modification to a unit.
3029  * - Arg 1: unit.
3030  * - Arg 2: string.
3031  * - Arg 3: WML table.
3032  * - Arg 4: (optional) Whether to add to [modifications] - default true
3033  */
3035 {
3036  unit& u = luaW_checkunit(L, 1);
3037  char const *m = luaL_checkstring(L, 2);
3038  std::string sm = m;
3039  if (sm == "advance") { // Maintain backwards compatibility
3040  sm = "advancement";
3041  deprecated_message("\"advance\" modification type", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Use \"advancement\" instead.");
3042  }
3043  if (sm != "advancement" && sm != "object" && sm != "trait") {
3044  return luaL_argerror(L, 2, "unknown modification type");
3045  }
3046  bool write_to_mods = true;
3047  if (!lua_isnone(L, 4)) {
3048  write_to_mods = luaW_toboolean(L, 4);
3049  }
3050  if(sm.empty()) {
3051  write_to_mods = false;
3052  }
3053 
3054  config cfg = luaW_checkconfig(L, 3);
3055  u.add_modification(sm, cfg, !write_to_mods);
3056  return 0;
3057 }
3058 
3059 /**
3060  * Removes modifications from a unit
3061  * - Arg 1: unit
3062  * - Arg 2: table (filter as [filter_wml])
3063  * - Arg 3: type of modification (default "object")
3064  */
3066 {
3067  unit& u = luaW_checkunit(L, 1);
3068  config filter = luaW_checkconfig(L, 2);
3069  std::string tag = luaL_optstring(L, 3, "object");
3070  //TODO
3071  if(filter.attribute_count() == 1 && filter.all_children_count() == 0 && filter.attribute_range().front().first == "duration") {
3072  u.expire_modifications(filter["duration"]);
3073  } else {
3074  for(config& obj : u.get_modifications().child_range(tag)) {
3075  if(obj.matches(filter)) {
3076  obj["duration"] = "now";
3077  }
3078  }
3079  u.expire_modifications("now");
3080  }
3081  return 0;
3082 }
3083 
3084 /**
3085  * Advances a unit if the unit has enough xp.
3086  * - Arg 1: unit.
3087  * - Arg 2: optional boolean whether to animate the advancement.
3088  * - Arg 3: optional boolean whether to fire advancement events.
3089  */
3091 {
3092  events::command_disabler command_disabler;
3093  unit& u = luaW_checkunit(L, 1, true);
3095  if(lua_isboolean(L, 2)) {
3096  par.animate(luaW_toboolean(L, 2));
3097  }
3098  if(lua_isboolean(L, 3)) {
3099  par.fire_events(luaW_toboolean(L, 3));
3100  }
3101  advance_unit_at(par);
3102  return 0;
3103 }
3104 
3105 
3106 /**
3107  * Adds a new known unit type to the help system.
3108  * - Arg 1: string.
3109  */
3111 {
3112  char const *ty = luaL_checkstring(L, 1);
3113  if(!unit_types.find(ty))
3114  {
3115  std::stringstream ss;
3116  ss << "unknown unit type: '" << ty << "'";
3117  return luaL_argerror(L, 1, ss.str().c_str());
3118  }
3119  preferences::encountered_units().insert(ty);
3120  return 0;
3121 }
3122 
3123 /**
3124  * Adds an overlay on a tile.
3125  * - Arg 1: location.
3126  * - Arg 2: WML table.
3127  */
3129 {
3130  map_location loc = luaW_checklocation(L, 1);
3131  vconfig cfg = luaW_checkvconfig(L, 2);
3132  const vconfig &ssf = cfg.child("filter_team");
3133 
3134  std::string team_name;
3135  if (!ssf.null()) {
3136  const std::vector<int>& teams = side_filter(ssf, &game_state_).get_teams();
3137  std::vector<std::string> team_names;
3138  std::transform(teams.begin(), teams.end(), std::back_inserter(team_names),
3139  [&](int team) { return game_state_.get_disp_context().get_team(team).team_name(); });
3140  team_name = utils::join(team_names);
3141  } else {
3142  team_name = cfg["team_name"].str();
3143  }
3144 
3145  if (game_display_) {
3146  game_display_->add_overlay(loc, cfg["image"], cfg["halo"],
3147  team_name, cfg["name"], cfg["visible_in_fog"].to_bool(true), cfg["z_order"].to_double(0));
3148  }
3149  return 0;
3150 }
3151 
3152 /**
3153  * Removes an overlay from a tile.
3154  * - Arg 1: location.
3155  * - Arg 2: optional string.
3156  */
3158 {
3159  map_location loc = luaW_checklocation(L, 1);
3160  char const *m = lua_tostring(L, 2);
3161 
3162  if (m) {
3163  if (game_display_) {
3164  game_display_->remove_single_overlay(loc, m);
3165  }
3166  } else {
3167  if (game_display_) {
3168  game_display_->remove_overlay(loc);
3169  }
3170  }
3171  return 0;
3172 }
3173 
3175 {
3176  replay& recorder = play_controller_.get_replay();
3177  const int nargs = lua_gettop(L);
3178  if(nargs < 2 || nargs > 3) {
3179  return luaL_error(L, "Wrong number of arguments to ai.log_replay() - should be 2 or 3 arguments.");
3180  }
3181  const std::string key = nargs == 2 ? luaL_checkstring(L, 1) : luaL_checkstring(L, 2);
3182  config cfg;
3183  if(nargs == 2) {
3184  recorder.add_log_data(key, luaL_checkstring(L, 2));
3185  } else if(luaW_toconfig(L, 3, cfg)) {
3186  recorder.add_log_data(luaL_checkstring(L, 1), key, cfg);
3187  } else if(!lua_isstring(L, 3)) {
3188  return luaL_argerror(L, 3, "accepts only string or config");
3189  } else {
3190  recorder.add_log_data(luaL_checkstring(L, 1), key, luaL_checkstring(L, 3));
3191  }
3192  return 0;
3193 }
3194 
3195 /** Adding new events */
3197 {
3198  vconfig cfg(luaW_checkvconfig(L, 1));
3199  game_events::manager & man = *game_state_.events_manager_;
3200 
3201  if (!cfg["delayed_variable_substitution"].to_bool(true)) {
3203  } else {
3204  man.add_event_handler(cfg.get_config());
3205  }
3206  return 0;
3207 }
3208 
3210 {
3211  game_state_.events_manager_->remove_event_handler(luaL_checkstring(L, 1));
3212  return 0;
3213 }
3214 
3216 {
3217  if (game_display_) {
3218  vconfig cfg(luaW_checkvconfig(L, 1));
3219 
3220  game_display_->adjust_color_overlay(cfg["red"], cfg["green"], cfg["blue"]);
3221  game_display_->invalidate_all();
3222  game_display_->draw(true,true);
3223  }
3224  return 0;
3225 }
3226 
3227 /**
3228  * Delays engine for a while.
3229  * - Arg 1: integer.
3230  * - Arg 2: boolean (optional).
3231  */
3233 {
3234  if(gamedata().phase() == game_data::PRELOAD || gamedata().phase() == game_data::PRESTART || gamedata().phase() == game_data::INITIAL) {
3235  //don't call play_slice if the game ui is not active yet.
3236  return 0;
3237  }
3238  events::command_disabler command_disabler;
3239  lua_Integer delay = luaL_checkinteger(L, 1);
3240  if(delay == 0) {
3241  play_controller_.play_slice(false);
3242  return 0;
3243  }
3244  if(luaW_toboolean(L, 2) && game_display_ && game_display_->turbo_speed() > 0) {
3245  delay /= game_display_->turbo_speed();
3246  }
3247  const unsigned final = SDL_GetTicks() + delay;
3248  do {
3249  play_controller_.play_slice(false);
3250  CVideo::delay(10);
3251  } while (static_cast<int>(final - SDL_GetTicks()) > 0);
3252  return 0;
3253 }
3254 
3256 {
3257  if (game_display_) {
3258  vconfig cfg(luaW_checkvconfig(L, 1));
3259 
3260  game_display &screen = *game_display_;
3261 
3262  terrain_label label(screen.labels(), cfg.get_config());
3263 
3264  screen.labels().set_label(label.location(), add ? label.text() : "", label.creator(), label.team_name(), label.color(),
3265  label.visible_in_fog(), label.visible_in_shroud(), label.immutable(), label.category(), label.tooltip());
3266  }
3267  return 0;
3268 }
3269 
3271 {
3272  if(game_display_) {
3273  game_display &screen = *game_display_;
3274  auto loc = luaW_checklocation(L, 1);
3275  const terrain_label* label = nullptr;
3276  switch(lua_type(L, 2)) {
3277  // Missing 2nd argument - get global label
3278  case LUA_TNONE: case LUA_TNIL:
3279  label = screen.labels().get_label(loc, "");
3280  break;
3281  // Side number - get label belonging to that side's team
3282  case LUA_TNUMBER:
3283  if(size_t n = luaL_checkinteger(L, 2); n > 0 && n <= teams().size()) {
3284  label = screen.labels().get_label(loc, teams().at(n - 1).team_name());
3285  }
3286  break;
3287  // String - get label belonging to the team with that name
3288  case LUA_TSTRING:
3289  label = screen.labels().get_label(loc, luaL_checkstring(L, 2));
3290  break;
3291  // Side userdata - get label belonging to that side's team
3292  case LUA_TUSERDATA:
3293  label = screen.labels().get_label(loc, luaW_checkteam(L, 2).team_name());
3294  break;
3295  }
3296  if(label) {
3297  config cfg;
3298  label->write(cfg);
3299  luaW_pushconfig(L, cfg);
3300  return 1;
3301  }
3302  }
3303  return 0;
3304 }
3305 
3307 {
3308  if (game_display_) {
3309  game_display & screen = *game_display_;
3310 
3311  vconfig cfg(luaW_checkvconfig(L, 1));
3312  bool clear_shroud(luaW_toboolean(L, 2));
3313 
3314  // We do this twice so any applicable redraws happen both before and after
3315  // any events caused by redrawing shroud are fired
3316  bool result = screen.maybe_rebuild();
3317  if (!result) {
3318  screen.invalidate_all();
3319  }
3320 
3321  if (clear_shroud) {
3322  side_filter filter(cfg, &game_state_);
3323  for (const int side : filter.get_teams()){
3324  actions::clear_shroud(side);
3325  }
3326  screen.recalculate_minimap();
3327  }
3328 
3329  result = screen.maybe_rebuild();
3330  if (!result) {
3331  screen.invalidate_all();
3332  }
3333 
3334  screen.draw(true,true);
3335  }
3336  return 0;
3337 }
3338 
3339 /**
3340  * Lua frontend to the modify_ai functionality
3341  * - Arg 1: config.
3342  */
3344 {
3345  config cfg;
3346  luaW_toconfig(L, 1, cfg);
3347  int side = cfg["side"];
3348  deprecated_message("wesnoth.modify_ai", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Use wesnoth.sides.add_ai_component, wesnoth.sides.delete_ai_component, or wesnoth.sides.change_ai_component.");
3350  return 0;
3351 }
3352 
3354 {
3355  bool exec = luaW_toboolean(L, -1);
3356  lua_pop(L, 1);
3357 
3358  lua_getfield(L, -1, "ca_ptr");
3359 
3360  ai::candidate_action *ca = static_cast<ai::candidate_action*>(lua_touserdata(L, -1));
3361  lua_pop(L, 2);
3362  if (exec) {
3363  ca->execute();
3364  return 0;
3365  }
3366  lua_pushinteger(L, ca->evaluate());
3367  return 1;
3368 }
3369 
3371 {
3372  lua_getfield(L, -1, "stg_ptr");
3373  ai::stage *stg = static_cast<ai::stage*>(lua_touserdata(L, -1));
3374  lua_pop(L, 2);
3375  stg->play_stage();
3376  return 0;
3377 }
3378 
3379 static void push_component(lua_State *L, ai::component* c, const std::string &ct = "")
3380 {
3381  lua_createtable(L, 0, 0); // Table for a component
3382 
3383  lua_pushstring(L, "name");
3384  lua_pushstring(L, c->get_name().c_str());
3385  lua_rawset(L, -3);
3386 
3387  lua_pushstring(L, "engine");
3388  lua_pushstring(L, c->get_engine().c_str());
3389  lua_rawset(L, -3);
3390 
3391  lua_pushstring(L, "id");
3392  lua_pushstring(L, c->get_id().c_str());
3393  lua_rawset(L, -3);
3394 
3395  if (ct == "candidate_action") {
3396  lua_pushstring(L, "ca_ptr");
3397  lua_pushlightuserdata(L, c);
3398  lua_rawset(L, -3);
3399 
3400  lua_pushstring(L, "exec");
3402  lua_rawset(L, -3);
3403  }
3404 
3405  if (ct == "stage") {
3406  lua_pushstring(L, "stg_ptr");
3407  lua_pushlightuserdata(L, c);
3408  lua_rawset(L, -3);
3409 
3410  lua_pushstring(L, "exec");
3412  lua_rawset(L, -3);
3413  }
3414 
3415 
3416  std::vector<std::string> c_types = c->get_children_types();
3417 
3418  for (std::vector<std::string>::const_iterator t = c_types.begin(); t != c_types.end(); ++t)
3419  {
3420  std::vector<ai::component*> children = c->get_children(*t);
3421  std::string type = *t;
3422  if (type == "aspect" || type == "goal" || type == "engine")
3423  {
3424  continue;
3425  }
3426 
3427  lua_pushstring(L, type.c_str());
3428  lua_createtable(L, 0, 0); // this table will be on top of the stack during recursive calls
3429 
3430  for (std::vector<ai::component*>::const_iterator i = children.begin(); i != children.end(); ++i)
3431  {
3432  lua_pushstring(L, (*i)->get_name().c_str());
3433  push_component(L, *i, type);
3434  lua_rawset(L, -3);
3435 
3436  //if (type == "candidate_action")
3437  //{
3438  // ai::candidate_action *ca = dynamic_cast<ai::candidate_action*>(*i);
3439  // ca->execute();
3440  //}
3441  }
3442 
3443  lua_rawset(L, -3); // setting the child table
3444  }
3445 
3446 
3447 }
3448 
3449 /**
3450  * Debug access to the ai tables
3451  * - Arg 1: int
3452  * - Ret 1: ai table
3453  */
3454 static int intf_debug_ai(lua_State *L)
3455 {
3456  if (!game_config::debug) { // This function works in debug mode only
3457  return 0;
3458  }
3459  int side;
3460  if(team* t = luaW_toteam(L, 1)) {
3461  side = t->side();
3462  } else {
3463  side = luaL_checkinteger(L, 1);
3464  }
3465  lua_pop(L, 1);
3466 
3468 
3469  // Bad, but works
3470  std::vector<ai::component*> engines = c->get_children("engine");
3471  ai::engine_lua* lua_engine = nullptr;
3472  for (std::vector<ai::component*>::const_iterator i = engines.begin(); i != engines.end(); ++i)
3473  {
3474  if ((*i)->get_name() == "lua")
3475  {
3476  lua_engine = dynamic_cast<ai::engine_lua *>(*i);
3477  }
3478  }
3479 
3480  // Better way, but doesn't work
3481  //ai::component* e = ai::manager::get_singleton().get_active_ai_holder_for_side_dbg(side).get_component(c, "engine[lua]");
3482  //ai::engine_lua* lua_engine = dynamic_cast<ai::engine_lua *>(e);
3483 
3484  if (lua_engine == nullptr)
3485  {
3486  //no lua engine is defined for this side.
3487  //so set up a dummy engine
3488 
3489  ai::ai_composite * ai_ptr = dynamic_cast<ai::ai_composite *>(c);
3490 
3491  assert(ai_ptr);
3492 
3493  ai::ai_context& ai_context = ai_ptr->get_ai_context();
3495 
3496  lua_engine = new ai::engine_lua(ai_context, cfg);
3497  LOG_LUA << "Created new dummy lua-engine for debug_ai(). \n";
3498 
3499  //and add the dummy engine as a component
3500  //to the manager, so we could use it later
3501  cfg.add_child("engine", lua_engine->to_config());
3502  ai::component_manager::add_component(c, "engine[]", cfg);
3503  }
3504 
3505  lua_engine->push_ai_table(); // stack: [-1: ai_context]
3506 
3507  lua_pushstring(L, "components");
3508  push_component(L, c); // stack: [-1: component tree; -2: ai context]
3509  lua_rawset(L, -3);
3510 
3511  return 1;
3512 }
3513 
3514 /** Allow undo sets the flag saying whether the event has mutated the game to false. */
3516 {
3517  bool allow;
3518  t_string reason;
3519  // The extra iststring is required to prevent totstring from converting a bool value
3520  if(luaW_iststring(L, 1) && luaW_totstring(L, 1, reason)) {
3521  allow = false;
3522  } else {
3523  allow = luaW_toboolean(L, 1);
3524  luaW_totstring(L, 2, reason);
3525  }
3526  gamedata().set_allow_end_turn(allow, reason);
3527  return 0;
3528 }
3529 
3530 /** Allow undo sets the flag saying whether the event has mutated the game to false. */
3532 {
3533  if(lua_isboolean(L, 1)) {
3534  play_controller_.pump().set_undo_disabled(!luaW_toboolean(L, 1));
3535  }
3536  else {
3537  play_controller_.pump().set_undo_disabled(false);
3538  }
3539  return 0;
3540 }
3541 
3543 {
3544  play_controller_.pump().set_action_canceled();
3545  return 0;
3546 }
3547 
3548 /** Adding new time_areas dynamically with Standard Location Filters. */
3550 {
3551  log_scope("time_area");
3552 
3553  vconfig cfg(luaW_checkvconfig(L, 1));
3554  const std::string id = cfg["id"];
3555 
3556  std::set<map_location> locs;
3557  const terrain_filter filter(cfg, &game_state_, false);
3558  filter.get_locations(locs, true);
3559  config parsed_cfg = cfg.get_parsed_config();
3560  tod_man().add_time_area(id, locs, parsed_cfg);
3561  LOG_LUA << "Lua inserted time_area '" << id << "'\n";
3562  return 0;
3563 }
3564 
3565 /** Removing new time_areas dynamically with Standard Location Filters. */
3567 {
3568  log_scope("remove_time_area");
3569 
3570  const char * id = luaL_checkstring(L, 1);
3571  tod_man().remove_time_area(id);
3572  LOG_LUA << "Lua removed time_area '" << id << "'\n";
3573 
3574  return 0;
3575 }
3576 
3577 /** Replacing the current time of day schedule. */
3579 {
3580  vconfig cfg = luaW_checkvconfig(L, 1);
3581 
3582  if(cfg.get_children("time").empty()) {
3583  ERR_LUA << "attempted to to replace ToD schedule with empty schedule" << std::endl;
3584  } else {
3585  tod_man().replace_schedule(cfg.get_parsed_config());
3586  if (game_display_) {
3587  game_display_->new_turn();
3588  }
3589  LOG_LUA << "replaced ToD schedule\n";
3590  }
3591  return 0;
3592 }
3593 
3595 {
3596  if(!game_display_) {
3597  return 0;
3598  }
3599  std::string area_id;
3600  std::size_t area_i = 0;
3601  if (lua_isstring(L, 2)) {
3602  area_id = lua_tostring(L, 1);
3603  std::vector<std::string> area_ids = tod_man().get_area_ids();
3604  area_i = std::distance(area_ids.begin(), std::find(area_ids.begin(), area_ids.end(), area_id));
3605  if(area_i >= area_ids.size()) {
3606  return luaL_argerror(L, 1, "invalid time area ID");
3607  }
3608  }
3609  int is_num = false;
3610  int new_time = lua_tonumberx(L, 1, &is_num) - 1;
3611  const std::vector<time_of_day>& times = area_id.empty()
3612  ? tod_man().times()
3613  : tod_man().times(area_i);
3614  int num_times = times.size();
3615  if(!is_num) {
3616  std::string time_id = luaL_checkstring(L, 1);
3617  new_time = 0;
3618  for(const time_of_day& time : times) {
3619  if(time_id == time.id) {
3620  break;
3621  }
3622  new_time++;
3623  }
3624  if(new_time >= num_times) {
3625  return luaL_argerror(L, 1, "invalid time of day ID");
3626  }
3627  }
3628 
3629  if(new_time == 0 && num_times == 0) {
3630  //ignore this case, because we don't want code like set_current_time(get_current_time()) to fail if num_times is 0.
3631  return 0;
3632  }
3633  if(new_time < 0 || new_time >= num_times) {
3634  return luaL_argerror(L, 1, "invalid time of day index");
3635  }
3636 
3637  if(area_id.empty()) {
3638  tod_man().set_current_time(new_time);
3639  } else {
3640  tod_man().set_current_time(new_time, area_i);
3641  }
3642  return 0;
3643 }
3644 
3646 {
3647  int x = luaL_checkinteger(L, 1), y = luaL_checkinteger(L, 2);
3648 
3649  if (game_display_) {
3650  game_display_->scroll(x, y, true);
3651  game_display_->draw(true, true);
3652  }
3653 
3654  return 0;
3655 }
3656 
3657 namespace {
3658  struct lua_report_generator : reports::generator
3659  {
3660  lua_State *mState;
3661  std::string name;
3662  lua_report_generator(lua_State *L, const std::string &n)
3663  : mState(L), name(n) {}
3664  virtual config generate(reports::context & rc);
3665  };
3666 
3667  config lua_report_generator::generate(reports::context & /*rc*/)
3668  {
3669  lua_State *L = mState;
3670  config cfg;
3671  if (!luaW_getglobal(L, "wesnoth", "interface", "game_display", name))
3672  return cfg;
3673  if (!luaW_pcall(L, 0, 1)) return cfg;
3674  luaW_toconfig(L, -1, cfg);
3675  lua_pop(L, 1);
3676  return cfg;
3677  }
3678 }//unnamed namespace for lua_report_generator
3679 
3680 /**
3681  * Executes its upvalue as a theme item generator.
3682  */
3684 {
3685  reports::context temp_context = reports::context(board(), *game_display_, tod_man(), play_controller_.get_whiteboard(), play_controller_.get_mouse_handler_base());
3686  luaW_pushconfig(L, reports_.generate_report(m.c_str(), temp_context , true));
3687  return 1;
3688 }
3689 
3690 /**
3691  * Creates a field of the theme_items table and returns it (__index metamethod).
3692  */
3694 {
3695  char const *m = luaL_checkstring(L, 2);
3696  lua_cpp::push_closure(L, std::bind(&game_lua_kernel::impl_theme_item, this, std::placeholders::_1, std::string(m)), 0);
3697  lua_pushvalue(L, 2);
3698  lua_pushvalue(L, -2);
3699  lua_rawset(L, 1);
3700  reports_.register_generator(m, new lua_report_generator(L, m));
3701  return 1;
3702 }
3703 
3704 /**
3705  * Sets a field of the theme_items table (__newindex metamethod).
3706  */
3708 {
3709  char const *m = luaL_checkstring(L, 2);
3710  lua_pushvalue(L, 2);
3711  lua_pushvalue(L, 3);
3712  lua_rawset(L, 1);
3713  reports_.register_generator(m, new lua_report_generator(L, m));
3714  return 0;
3715 }
3716 
3717 /**
3718  * Gets all the WML variables currently set.
3719  * - Ret 1: WML table
3720  */
3722  luaW_pushconfig(L, gamedata().get_variables());
3723  return 1;
3724 }
3725 
3726 /**
3727  * Teeleports a unit to a location.
3728  * Arg 1: unit
3729  * Arg 2: target location
3730  * Arg 3: bool (ignore_passability)
3731  * Arg 4: bool (clear_shroud)
3732  * Arg 5: bool (animate)
3733  */
3735 {
3736  events::command_disabler command_disabler;
3737  unit_ptr u = luaW_checkunit_ptr(L, 1, true);
3738  map_location dst = luaW_checklocation(L, 2);
3739  bool check_passability = !luaW_toboolean(L, 3);
3740  bool clear_shroud = luaW_toboolean(L, 4);
3741  bool animate = luaW_toboolean(L, 5);
3742 
3743  if (dst == u->get_location() || !map().on_board(dst)) {
3744  return 0;
3745  }
3746  const map_location vacant_dst = find_vacant_tile(dst, pathfind::VACANT_ANY, check_passability ? u.get() : nullptr);
3747  if (!map().on_board(vacant_dst)) {
3748  return 0;
3749  }
3750  // Clear the destination hex before the move (so the animation can be seen).
3751  actions::shroud_clearer clearer;
3752  if ( clear_shroud ) {
3753  clearer.clear_dest(vacant_dst, *u);
3754  }
3755 
3756  map_location src_loc = u->get_location();
3757 
3758  std::vector<map_location> teleport_path;
3759  teleport_path.push_back(src_loc);
3760  teleport_path.push_back(vacant_dst);
3761  unit_display::move_unit(teleport_path, u, animate);
3762 
3763  units().move(src_loc, vacant_dst);
3765 
3766  u = units().find(vacant_dst).get_shared_ptr();
3767  u->anim_comp().set_standing();
3768 
3769  if ( clear_shroud ) {
3770  // Now that the unit is visibly in position, clear the shroud.
3771  clearer.clear_unit(vacant_dst, *u);
3772  }
3773 
3774  if (map().is_village(vacant_dst)) {
3775  actions::get_village(vacant_dst, u->side());
3776  }
3777 
3778  game_display_->invalidate_unit_after_move(src_loc, vacant_dst);
3779  game_display_->draw();
3780 
3781  // Sighted events.
3782  clearer.fire_events();
3783  return 0;
3784 }
3785 
3786 /**
3787  * Removes a sound source by its ID
3788  * Arg 1: sound source ID
3789  */
3791 {
3792  soundsource::manager* man = play_controller_.get_soundsource_man();
3793  std::string id = luaL_checkstring(L, 1);
3794  man->remove(id);
3795  return 0;
3796 }
3797 
3798 /**
3799  * Add a new sound source
3800  * Arg 1: Table containing keyword arguments
3801  */
3803 {
3804  soundsource::manager* man = play_controller_.get_soundsource_man();
3805  config cfg = luaW_checkconfig(L, 1);
3806  try {
3807  soundsource::sourcespec spec(cfg);
3808  man->add(spec);
3809  man->update();
3810  } catch (const bad_lexical_cast &) {
3811  ERR_LUA << "Error when parsing sound_source config: invalid parameter." << std::endl;
3812  ERR_LUA << "sound_source config was: " << cfg.debug() << std::endl;
3813  ERR_LUA << "Skipping this sound source..." << std::endl;
3814  }
3815  return 0;
3816 }
3817 
3818 /**
3819  * Get an existing sound source
3820  * Arg 1: The sound source ID
3821  * Return: Config of sound source info, or nil if it didn't exist
3822  * This is a copy of the sound source info, so you need to call
3823  * add_sound_source again after changing it.
3824  */
3826 {
3827  soundsource::manager* man = play_controller_.get_soundsource_man();
3828  std::string id = luaL_checkstring(L, 1);
3829  config cfg = man->get(id);
3830  if(cfg.empty()) {
3831  return 0;
3832  }
3833  // Sound sources do not know their own string ID
3834  // Thus, we need to add this manually
3835  cfg["id"] = id;
3836  luaW_pushconfig(L, cfg);
3837  return 1;
3838 }
3839 
3840 /**
3841  * Logs a message
3842  * Arg 1: (optional) Logger; "wml" for WML errors or deprecations
3843  * Arg 2: Message
3844  * Arg 3: Whether to print to chat (always true if arg 1 is "wml")
3845  */
3847 {
3848  const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) : "";
3849  const std::string& msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1);
3850 
3851  if(logger == "wml" || logger == "WML") {
3852  lg::wml_error() << msg << '\n';
3853  } else {
3854  bool in_chat = luaW_toboolean(L, -1);
3855  game_state_.events_manager_->pump().put_wml_message(logger,msg,in_chat);
3856  }
3857  return 0;
3858 }
3859 
3861 {
3862  int side = luaL_checknumber(L, 1);
3863  map_location loc = luaW_checklocation(L, 2);
3864  if(side < 1 || static_cast<std::size_t>(side) > teams().size()) {
3865  std::string error = "side " + std::to_string(side) + " does not exist";
3866  return luaL_argerror(L, 1, error.c_str());
3867  }
3868 
3869  team& t = board().get_team(side);
3870  lua_pushboolean(L, fog ? t.fogged(loc) : t.shrouded(loc));
3871  return 1;
3872 }
3873 
3874 /**
3875  * Implements the lifting and resetting of fog via WML.
3876  * Keeping affect_normal_fog as false causes only the fog override to be affected.
3877  * Otherwise, fog lifting will be implemented similar to normal sight (cannot be
3878  * individually reset and ends at the end of the turn), and fog resetting will, in
3879  * addition to removing overrides, extend the specified teams' normal fog to all
3880  * hexes.
3881  *
3882  * Arg 1: (optional) Side number, or list of side numbers
3883  * Arg 2: List of locations; each is a two-element array or a table with x and y keys
3884  * Arg 3: (optional) boolean
3885  */
3887 {
3888  bool affect_normal_fog = false;
3889  if(lua_isboolean(L, -1)) {
3890  affect_normal_fog = luaW_toboolean(L, -1);
3891  }
3892  std::set<int> sides;
3893  if(lua_isnumber(L, 1)) {
3894  sides.insert(lua_tonumber(L, 1));
3895  } else if(lua_istable(L, 1) && lua_istable(L, 2)) {
3896  const auto& v = lua_check<std::vector<int>>(L, 1);
3897  sides.insert(v.begin(), v.end());
3898  } else {
3899  for(const team& t : teams()) {
3900  sides.insert(t.side()+1);
3901  }
3902  }
3903  const auto& v_locs = lua_check<std::vector<map_location>>(L, lua_istable(L, 2) ? 2 : 1);
3904  std::set<map_location> locs(v_locs.begin(), v_locs.end());
3905 
3906  for(const int &side_num : sides) {
3907  if(side_num < 1 || static_cast<std::size_t>(side_num) > teams().size()) {
3908  continue;
3909  }
3910  team &t = board().get_team(side_num);
3911  if(!clear) {
3912  // Extend fog.
3913  t.remove_fog_override(locs);
3914  if(affect_normal_fog) {
3915  t.refog();
3916  }
3917  } else if(!affect_normal_fog) {
3918  // Force the locations clear of fog.
3919  t.add_fog_override(locs);
3920  } else {
3921  // Simply clear fog from the locations.
3922  for(const map_location &hex : locs) {
3923  t.clear_fog(hex);
3924  }
3925  }
3926  }
3927 
3928  // Flag a screen update.
3929  game_display_->recalculate_minimap();
3930  game_display_->invalidate_all();
3931  return 0;
3932 }
3933 
3934 // Invokes a synced command
3936 {
3937  const std::string name = luaL_checkstring(L, 1);
3938  auto it = synced_command::registry().find(name);
3939  config cmd;
3940  if(it == synced_command::registry().end()) {
3941  // Custom command
3942  if(!luaW_getglobal(L, "wesnoth", "custom_synced_commands", name)) {
3943  return luaL_argerror(L, 1, "Unknown synced command");
3944  }
3945  config& cmd_tag = cmd.child_or_add("custom_command");
3946  cmd_tag["name"] = name;
3947  if(!lua_isnoneornil(L, 2)) {
3948  cmd_tag.add_child("data", luaW_checkconfig(L, 2));
3949  }
3950  } else {
3951  // Built-in command
3952  cmd.add_child(name, luaW_checkconfig(L, 2));
3953  }
3954  // Now just forward to the WML action.
3955  luaW_getglobal(L, "wesnoth", "wml_actions", "do_command");
3956  luaW_pushconfig(L, cmd);
3957  luaW_pcall(L, 1, 0);
3958  return 0;
3959 }
3960 
3961 // END CALLBACK IMPLEMENTATION
3962 
3964  return game_state_.board_;
3965 }
3966 
3968  return game_state_.board_.units();
3969 }
3970 
3971 std::vector<team> & game_lua_kernel::teams() {
3972  return game_state_.board_.teams();
3973 }
3974 
3976  return game_state_.board_.map();
3977 }
3978 
3980  return game_state_.gamedata_;
3981 }
3982 
3984  return game_state_.tod_manager_;
3985 }
3986 
3988  return *queued_events_.top();
3989 }
3990 
3991 
3993  : lua_kernel_base()
3994  , game_display_(nullptr)
3995  , game_state_(gs)
3996  , play_controller_(pc)
3997  , reports_(reports_object)
3998  , level_lua_()
3999  , queued_events_()
4000  , map_locked_(0)
4001 {
4002  static game_events::queued_event default_queued_event("_from_lua", "", map_location(), map_location(), config());
4003  queued_events_.push(&default_queued_event);
4004 
4005  lua_State *L = mState;
4006 
4007  cmd_log_ << "Registering game-specific wesnoth lib functions...\n";
4008 
4009  // Put some callback functions in the scripting environment.
4010  static luaL_Reg const callbacks[] {
4011  { "add_known_unit", &intf_add_known_unit },
4012  { "create_animator", &dispatch<&game_lua_kernel::intf_create_animator> },
4013  { "eval_conditional", &intf_eval_conditional },
4014  { "get_era", &intf_get_era },
4015  { "get_resource", &intf_get_resource },
4016  { "get_traits", &intf_get_traits },
4017  { "get_viewing_side", &intf_get_viewing_side },
4018  { "invoke_synced_command", &intf_invoke_synced_command },
4019  { "modify_ai", &intf_modify_ai_old },
4020  { "set_music", &intf_set_music },
4021  { "sound_volume", &intf_sound_volume },
4022  { "unsynced", &intf_do_unsynced },
4023  { "add_event_handler", &dispatch<&game_lua_kernel::intf_add_event > },
4024  { "add_sound_source", &dispatch<&game_lua_kernel::intf_add_sound_source > },
4025  { "allow_end_turn", &dispatch<&game_lua_kernel::intf_allow_end_turn > },
4026  { "allow_undo", &dispatch<&game_lua_kernel::intf_allow_undo > },
4027  { "cancel_action", &dispatch<&game_lua_kernel::intf_cancel_action > },
4028  { "clear_messages", &dispatch<&game_lua_kernel::intf_clear_messages > },
4029  { "end_turn", &dispatch<&game_lua_kernel::intf_end_turn > },
4030  { "end_level", &dispatch<&game_lua_kernel::intf_end_level > },
4031  { "find_cost_map", &dispatch<&game_lua_kernel::intf_find_cost_map > },
4032  { "find_path", &dispatch<&game_lua_kernel::intf_find_path > },
4033  { "find_reach", &dispatch<&game_lua_kernel::intf_find_reach > },
4034  { "find_vacant_tile", &dispatch<&game_lua_kernel::intf_find_vacant_tile > },
4035  { "fire_event", &dispatch2<&game_lua_kernel::intf_fire_event, false > },
4036  { "fire_event_by_id", &dispatch2<&game_lua_kernel::intf_fire_event, true > },
4037  { "get_all_vars", &dispatch<&game_lua_kernel::intf_get_all_vars > },
4038  { "get_end_level_data", &dispatch<&game_lua_kernel::intf_get_end_level_data > },
4039  { "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > },
4040  { "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day > },
4041  { "get_max_liminal_bonus", &dispatch<&game_lua_kernel::intf_get_max_liminal_bonus > },
4042  { "get_variable", &dispatch<&game_lua_kernel::intf_get_variable > },
4043  { "log_replay", &dispatch<&game_lua_kernel::intf_log_replay > },
4044  { "log", &dispatch<&game_lua_kernel::intf_log > },
4045  { "message", &dispatch<&game_lua_kernel::intf_message > },
4046  { "open_help", &dispatch<&game_lua_kernel::intf_open_help > },
4047  { "play_sound", &dispatch<&game_lua_kernel::intf_play_sound > },
4048  { "print", &dispatch<&game_lua_kernel::intf_print > },
4049  { "redraw", &dispatch<&game_lua_kernel::intf_redraw > },
4050  { "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > },
4051  { "remove_sound_source", &dispatch<&game_lua_kernel::intf_remove_sound_source > },
4052  { "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > },
4053  { "select_hex", &dispatch<&game_lua_kernel::intf_select_hex > },
4054  { "set_time_of_day", &dispatch<&game_lua_kernel::intf_set_time_of_day > },
4055  { "set_end_campaign_credits", &dispatch<&game_lua_kernel::intf_set_end_campaign_credits > },
4056  { "set_end_campaign_text", &dispatch<&game_lua_kernel::intf_set_end_campaign_text > },
4057  { "create_side", &dispatch<&game_lua_kernel::intf_create_side > },
4058  { "set_next_scenario", &dispatch<&game_lua_kernel::intf_set_next_scenario > },
4059  { "set_variable", &dispatch<&game_lua_kernel::intf_set_variable > },
4060  { "simulate_combat", &dispatch<&game_lua_kernel::intf_simulate_combat > },
4061  { "synchronize_choice", &intf_synchronize_choice },
4062  { "synchronize_choices", &intf_synchronize_choices },
4063  { "teleport", &dispatch<&game_lua_kernel::intf_teleport > },
4064  { nullptr, nullptr }
4065  };lua_getglobal(L, "wesnoth");
4066  if (!lua_istable(L,-1)) {
4067  lua_newtable(L);
4068  }
4069  luaL_setfuncs(L, callbacks, 0);
4070 
4072  static luaL_Reg const test_callbacks[] {
4073  { "fire_wml_menu_item", &dispatch<&game_lua_kernel::intf_fire_wml_menu_item > },
4074  { nullptr, nullptr }
4075  };
4076  luaL_setfuncs(L, test_callbacks , 0);
4077  }
4078 
4079  lua_setglobal(L, "wesnoth");
4080 
4081  lua_getglobal(L, "gui");
4082  lua_pushcfunction(L, &dispatch<&game_lua_kernel::intf_gamestate_inspector>);
4083  lua_setfield(L, -2, "show_inspector");
4084  lua_pop(L, 1);
4085 
4086  // Create the getside metatable.
4088 
4089  // Create the gettype metatable.
4091 
4092  //Create the getrace metatable
4094 
4095  //Create the unit metatables
4098 
4099  // Create the vconfig metatable.
4101 
4102  // Create the unit_types table
4104 
4105  // Create the unit_types table
4107 
4108  // Create the unit_types table
4109  cmd_log_ << "Adding terrain_types table...\n";
4110  lua_getglobal(L, "wesnoth");
4111  lua_newuserdatauv(L, 0, 0);
4112  lua_createtable(L, 0, 2);
4113  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_get_terrain_info>);
4114  lua_setfield(L, -2, "__index");
4115  lua_pushstring(L, "terrain types");
4116  lua_setfield(L, -2, "__metatable");
4117  lua_setmetatable(L, -2);
4118  lua_setfield(L, -2, "terrain_types");
4119  lua_pop(L, 1);
4120 
4121  // Create the ai elements table.
4122  cmd_log_ << "Adding ai elements table...\n";
4123 
4125 
4126  // Create the current variable with its metatable.
4127  cmd_log_ << "Adding wesnoth current table...\n";
4128 
4129  lua_getglobal(L, "wesnoth");
4130  lua_newuserdatauv(L, 0, 0);
4131  lua_createtable(L, 0, 2);
4132  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_current_get>);
4133  lua_setfield(L, -2, "__index");
4134  lua_pushstring(L, "current config");
4135  lua_setfield(L, -2, "__metatable");
4136  lua_setmetatable(L, -2);
4137  lua_setfield(L, -2, "current");
4138  lua_pop(L, 1);
4139 
4140  // Add tovconfig to the WML module
4141  lua_getglobal(L, "wml");
4143  lua_setfield(L, -2, "tovconfig");
4144  lua_pop(L, 1);
4145 
4146  // Add functions to the map module
4147  luaW_getglobal(L, "wesnoth", "map");
4148  static luaL_Reg const map_callbacks[] {
4149  // Map methods
4150  {"terrain_mask", &intf_terrain_mask},
4151  {"on_board", &intf_on_board},
4152  {"on_border", &intf_on_border},
4153  {"iter", &intf_terrainmap_iter},
4154  // Shroud operations
4155  {"place_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, true>},
4156  {"remove_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, false>},
4157  {"is_shrouded", &dispatch2<&game_lua_kernel::intf_get_fog_or_shroud, false>},
4158  // Fog operations
4159  {"place_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, false>},
4160  {"remove_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, true>},
4161  {"is_fogged", &dispatch2<&game_lua_kernel::intf_get_fog_or_shroud, true>},
4162  // Village operations
4163  {"get_owner", &dispatch<&game_lua_kernel::intf_get_village_owner>},
4164  {"set_owner", &dispatch<&game_lua_kernel::intf_set_village_owner>},
4165  // Label operations
4166  {"add_label", &dispatch2<&game_lua_kernel::intf_label, true>},
4167  {"remove_label", &dispatch2<&game_lua_kernel::intf_label, false>},
4168  {"get_label", &dispatch<&game_lua_kernel::intf_get_label>},
4169  // Time area operations
4170  {"place_area", &dispatch<&game_lua_kernel::intf_add_time_area>},
4171  {"remove_area", &dispatch<&game_lua_kernel::intf_remove_time_area>},
4172  // Filters
4173  {"find", &dispatch<&game_lua_kernel::intf_get_locations>},
4174  {"matches", &dispatch<&game_lua_kernel::intf_match_location>},
4175  {"replace_if_failed", intf_replace_if_failed},
4176  { nullptr, nullptr }
4177  };
4178  luaL_setfuncs(L, map_callbacks, 0);
4179  lua_pop(L, 1);
4180 
4181  // Create the units module
4182  cmd_log_ << "Adding units module...\n";
4183  static luaL_Reg const unit_callbacks[] {
4184  {"advance", &intf_advance_unit},
4185  {"clone", &intf_copy_unit},
4186  {"erase", &dispatch<&game_lua_kernel::intf_erase_unit>},
4187  {"extract", &dispatch<&game_lua_kernel::intf_extract_unit>},
4188  {"matches", &dispatch<&game_lua_kernel::intf_match_unit>},
4189  {"select", &dispatch<&game_lua_kernel::intf_select_unit>},
4190  {"to_map", &dispatch<&game_lua_kernel::intf_put_unit>},
4191  {"to_recall", &dispatch<&game_lua_kernel::intf_put_recall_unit>},
4192  {"transform", &intf_transform_unit},
4193 
4194  {"ability", &dispatch<&game_lua_kernel::intf_unit_ability>},
4195  {"defense_on", &intf_unit_defense},
4196  {"jamming_on", &intf_unit_jamming_cost},
4197  {"movement_on", &intf_unit_movement_cost},
4198  {"resistance_against", intf_unit_resistance},
4199  {"vision_on", &intf_unit_vision_cost},
4200 
4201  {"add_modification", &intf_add_modification},
4202  {"remove_modifications", &intf_remove_modifications},
4203  // Static functions
4204  {"create", &intf_create_unit},
4205  {"find_on_map", &dispatch<&game_lua_kernel::intf_get_units>},
4206  {"find_on_recall", &dispatch<&game_lua_kernel::intf_get_recall_units>},
4207  {"get", &dispatch<&game_lua_kernel::intf_get_unit>},
4208  {"get_hovered", &dispatch<&game_lua_kernel::intf_get_displayed_unit>},
4209  { nullptr, nullptr }
4210  };
4211  lua_getglobal(L, "wesnoth");
4212  lua_newtable(L);
4213  luaL_setfuncs(L, unit_callbacks, 0);
4214  lua_setfield(L, -2, "units");
4215  lua_pop(L, 1);
4216 
4217  // Create sides module
4218  cmd_log_ << "Adding sides module...\n";
4219  static luaL_Reg const side_callbacks[] {
4220  { "is_enemy", &dispatch<&game_lua_kernel::intf_is_enemy> },
4221  { "matches", &dispatch<&game_lua_kernel::intf_match_side> },
4222  { "set_id", &dispatch<&game_lua_kernel::intf_set_side_id> },
4223  { "append_ai", &intf_append_ai },
4224  { "debug_ai", &intf_debug_ai },
4225  { "switch_ai", &intf_switch_ai },
4226  // Static functions
4227  { "find", &dispatch<&game_lua_kernel::intf_get_sides> },
4228  { "get", &dispatch<&game_lua_kernel::intf_get_side> },
4229  { nullptr, nullptr }
4230  };
4231  std::vector<lua_cpp::Reg> const cpp_side_callbacks {
4232  {"add_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "add")},
4233  {"delete_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "delete")},
4234  {"change_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "change")},
4235  {nullptr, nullptr}
4236  };
4237 
4238  lua_getglobal(L, "wesnoth");
4239  lua_newtable(L);
4240  luaL_setfuncs(L, side_callbacks, 0);
4241  lua_cpp::set_functions(L, cpp_side_callbacks);
4242  lua_setfield(L, -2, "sides");
4243  lua_pop(L, 1);
4244 
4245  // Create the interface module
4246  cmd_log_ << "Adding interface module...\n";
4247  static luaL_Reg const intf_callbacks[] {
4248  {"add_hex_overlay", &dispatch<&game_lua_kernel::intf_add_tile_overlay>},
4249  {"remove_hex_overlay", &dispatch<&game_lua_kernel::intf_remove_tile_overlay>},
4250  {"color_adjust", &dispatch<&game_lua_kernel::intf_color_adjust>},
4251  {"delay", &dispatch<&game_lua_kernel::intf_delay>},
4252  {"deselect_hex", &dispatch<&game_lua_kernel::intf_deselect_hex>},
4253  {"highlight_hex", &dispatch<&game_lua_kernel::intf_highlight_hex>},
4254  {"float_label", &dispatch<&game_lua_kernel::intf_float_label>},
4255  {"get_displayed_unit", &dispatch<&game_lua_kernel::intf_get_displayed_unit>},
4256  {"get_hovered_hex", &dispatch<&game_lua_kernel::intf_get_mouseover_tile>},
4257  {"get_selected_hex", &dispatch<&game_lua_kernel::intf_get_selected_tile>},
4258  {"lock", &dispatch<&game_lua_kernel::intf_lock_view>},
4259  {"is_locked", &dispatch<&game_lua_kernel::intf_view_locked>},
4260  {"scroll", &dispatch<&game_lua_kernel::intf_scroll>},
4261  {"scroll_to_hex", &dispatch<&game_lua_kernel::intf_scroll_to_tile>},
4262  {"skip_messages", &dispatch<&game_lua_kernel::intf_skip_messages>},
4263  {"is_skipping_messages", &dispatch<&game_lua_kernel::intf_is_skipping_messages>},
4264  {"zoom", &dispatch<&game_lua_kernel::intf_zoom>},
4265  {"clear_menu_item", &dispatch<&game_lua_kernel::intf_clear_menu_item>},
4266  {"set_menu_item", &dispatch<&game_lua_kernel::intf_set_menu_item>},
4267  { nullptr, nullptr }
4268  };
4269  lua_getglobal(L, "wesnoth");
4270  lua_newtable(L);
4271  luaL_setfuncs(L, intf_callbacks, 0);
4272  lua_setfield(L, -2, "interface");
4273  lua_pop(L, 1);
4274 
4275  // Create the playlist table with its metatable
4277 
4278  // Create the wml_actions table.
4279  cmd_log_ << "Adding wml_actions table...\n";
4280 
4281  lua_getglobal(L, "wesnoth");
4282  lua_newtable(L);
4283  lua_setfield(L, -2, "wml_actions");
4284  lua_pop(L, 1);
4285 
4286  // Create the wml_conditionals table.
4287  cmd_log_ << "Adding wml_conditionals table...\n";
4288 
4289  lua_getglobal(L, "wesnoth");
4290  lua_newtable(L);
4291  lua_setfield(L, -2, "wml_conditionals");
4292  lua_pop(L, 1);
4296 
4297  // Create the effects table.
4298  cmd_log_ << "Adding effects table...\n";
4299 
4300  lua_getglobal(L, "wesnoth");
4301  lua_newtable(L);
4302  lua_setfield(L, -2, "effects");
4303  lua_pop(L, 1);
4304 
4305  // Create the custom_synced_commands table.
4306  cmd_log_ << "Adding custom_synced_commands table...\n";
4307 
4308  lua_getglobal(L, "wesnoth");
4309  lua_newtable(L);
4310  lua_setfield(L, -2, "custom_synced_commands");
4311  lua_pop(L, 1);
4312 
4313  // Create the game_events table.
4314  cmd_log_ << "Adding game_events table...\n";
4315 
4316  lua_getglobal(L, "wesnoth");
4317  lua_newtable(L);
4318  lua_setfield(L, -2, "game_events");
4319  lua_pop(L, 1);
4320 
4321  // Create the theme_items table.
4322  cmd_log_ << "Adding game_display table...\n";
4323 
4324  luaW_getglobal(L, "wesnoth", "interface");
4325  lua_newtable(L);
4326  lua_createtable(L, 0, 2);
4327  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_theme_items_get>);
4328  lua_setfield(L, -2, "__index");
4329  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_theme_items_set>);
4330  lua_setfield(L, -2, "__newindex");
4331  lua_setmetatable(L, -2);
4332  lua_setfield(L, -2, "game_display");
4333  lua_pop(L, 1);
4334 
4335  lua_settop(L, 0);
4336 
4337  for(const auto& handler : game_events::wml_action::registry())
4338  {
4339  set_wml_action(handler.first, handler.second);
4340  }
4341  luaW_getglobal(L, "wesnoth", "effects");
4342  for(const std::string& effect : unit::builtin_effects) {
4343  lua_pushstring(L, effect.c_str());
4345  lua_rawset(L, -3);
4346  }
4347  lua_settop(L, 0);
4348 }
4349 
4351 {
4352  lua_State *L = mState;
4353  assert(level_lua_.empty());
4354  level_lua_.append_children(level, "lua");
4355 
4356  //Create the races table.
4357  cmd_log_ << "Adding races table...\n";
4358 
4359  lua_settop(L, 0);
4360  lua_getglobal(L, "wesnoth");
4361  luaW_pushracetable(L);
4362  lua_setfield(L, -2, "races");
4363  lua_pop(L, 1);
4364 
4365  // Execute the preload scripts.
4366  cmd_log_ << "Running preload scripts...\n";
4367 
4368  game_config::load_config(game_lua_kernel::preload_config);
4369  for (const config &cfg : game_lua_kernel::preload_scripts) {
4370  run_lua_tag(cfg);
4371  }
4372  for (const config &cfg : level_lua_.child_range("lua")) {
4373  run_lua_tag(cfg);
4374  }
4375 }
4376 
4378  game_display_ = gd;
4379 }
4380 
4381 /**
4382  * These are the child tags of [scenario] (and the like) that are handled
4383  * elsewhere (in the C++ code).
4384  * Any child tags not in this list will be passed to Lua's on_load event.
4385  */
4386 static const std::array<std::string, 24> handled_file_tags {{
4387  "color_palette",
4388  "color_range",
4389  "display",
4390  "end_level_data",
4391  "era",
4392  "event",
4393  "generator",
4394  "label",
4395  "lua",
4396  "map",
4397  "menu_item",
4398  "modification",
4399  "modify_unit_type",
4400  "music",
4401  "options",
4402  "side",
4403  "sound_source",
4404  "story",
4405  "terrain_graphics",
4406  "time",
4407  "time_area",
4408  "tunnel",
4409  "undo_stack",
4410  "variables"
4411 }};
4412 
4413 static bool is_handled_file_tag(const std::string& s)
4414 {
4415  for(const std::string& t : handled_file_tags) {
4416  if (s == t) return true;
4417  }
4418 
4419  return false;
4420 }
4421 
4422 /**
4423  * Executes the game_events.on_load function and passes to it all the
4424  * scenario tags not yet handled.
4425  */
4427 {
4428  lua_State *L = mState;
4429 
4430  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_load"))
4431  return;
4432 
4433  lua_newtable(L);
4434  int k = 1;
4435  for (const config::any_child &v : level.all_children_range())
4436  {
4437  if (is_handled_file_tag(v.key)) continue;
4438  lua_createtable(L, 2, 0);
4439  lua_pushstring(L, v.key.c_str());
4440  lua_rawseti(L, -2, 1);
4441  luaW_pushconfig(L, v.cfg);
4442  lua_rawseti(L, -2, 2);
4443  lua_rawseti(L, -2, k++);
4444  }
4445 
4446  luaW_pcall(L, 1, 0, true);
4447 }
4448 
4449 /**
4450  * Executes the game_events.on_save function and adds to @a cfg the
4451  * returned tags. Also flushes the [lua] tags.
4452  */
4454 {
4455  lua_State *L = mState;
4456 
4457  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_save"))
4458  return;
4459 
4460  if (!luaW_pcall(L, 0, 1, false))
4461  return;
4462 
4463  config v;
4464  luaW_toconfig(L, -1, v);
4465  lua_pop(L, 1);
4466 
4467  for (;;)
4468  {
4470  if (i == v.ordered_end()) break;
4471  if (is_handled_file_tag(i->key))
4472  {
4473  /*
4474  * It seems the only tags appearing in the config v variable here
4475  * are the core-lua-handled (currently [item] and [objectives])
4476  * and the extra UMC ones.
4477  */
4478  const std::string m = "Tag is already used: [" + i->key + "]";
4479  log_error(m.c_str());
4480  v.erase(i);
4481  continue;
4482  }
4483  cfg.splice_children(v, i->key);
4484  }
4485 }
4486 
4487 /**
4488  * Executes the game_events.on_event function.
4489  * Returns false if there was no lua handler for this event
4490  */
4492 {
4493  lua_State *L = mState;
4494 
4495  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_event"))
4496  return false;
4497 
4498  queued_event_context dummy(&ev, queued_events_);
4499  lua_pushstring(L, ev.name.c_str());
4500  luaW_pcall(L, 1, 0, false);
4501  return true;
4502 }
4503 
4504 void game_lua_kernel::custom_command(const std::string& name, const config& cfg)
4505 {
4506  lua_State *L = mState;
4507 
4508  if (!luaW_getglobal(L, "wesnoth", "custom_synced_commands", name)) {
4509  return;
4510  }
4511  luaW_pushconfig(L, cfg);
4512  luaW_pcall(L, 1, 0, false);
4513 }
4514 
4515 /**
4516  * Applies its upvalue as an effect
4517  * Arg 1: The unit to apply to
4518  * Arg 3: The [effect] tag contents
4519  * Arg 3: If false, only build description
4520  * Return: The description of the effect
4521  */
4523 {
4524  std::string which_effect = lua_tostring(L, lua_upvalueindex(1));
4525  bool need_apply = luaW_toboolean(L, lua_upvalueindex(2));
4526  // Argument 1 is the implicit "self" argument, which isn't needed here
4527  lua_unit u(luaW_checkunit(L, 2));
4528  config cfg = luaW_checkconfig(L, 3);
4529 
4530  // The times= key is supposed to be ignored by the effect function.
4531  // However, just in case someone doesn't realize this, we will set it to 1 here.
4532  cfg["times"] = 1;
4533 
4534  if(need_apply) {
4535  u->apply_builtin_effect(which_effect, cfg);
4536  return 0;
4537  } else {
4538  std::string description = u->describe_builtin_effect(which_effect, cfg);
4539  lua_pushstring(L, description.c_str());
4540  return 1;
4541  }
4542 }
4543 
4544 /**
4545 * Registers a function for use as an effect handler.
4546 */
4548 {
4549  lua_State *L = mState;
4550 
4551  // The effect name is at the top of the stack
4552  int str_i = lua_gettop(L);
4553  lua_newtable(L); // The functor table
4554  lua_newtable(L); // The functor metatable
4555  lua_pushstring(L, "__call");
4556  lua_pushvalue(L, str_i);
4557  lua_pushboolean(L, true);
4558  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_builtin_effect>, 2);
4559  lua_rawset(L, -3); // Set the call metafunction
4560  lua_pushstring(L, "__descr");
4561  lua_pushvalue(L, str_i);
4562  lua_pushboolean(L, false);
4563  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_builtin_effect>, 2);
4564  lua_rawset(L, -3); // Set the descr "metafunction"
4565  lua_setmetatable(L, -2); // Apply the metatable to the functor table
4566 }
4567 
4568 
4569 /**
4570  * Executes its upvalue as a wml action.
4571  */
4573 {
4576 
4577  vconfig vcfg = luaW_checkvconfig(L, 1);
4578  h(get_event_info(), vcfg);
4579  return 0;
4580 }
4581 
4582 /**
4583  * Registers a function for use as an action handler.
4584  */
4586 {
4587  lua_State *L = mState;
4588 
4589  lua_getglobal(L, "wesnoth");
4590  lua_pushstring(L, "wml_actions");
4591  lua_rawget(L, -2);
4592  lua_pushstring(L, cmd.c_str());
4593  lua_pushlightuserdata(L, reinterpret_cast<void *>(h));
4594  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_wml_action>, 1);
4595  lua_rawset(L, -3);
4596  lua_pop(L, 2);
4597 }
4598 
4599 using wml_conditional_handler = bool(*)(const vconfig&);
4600 
4601 /**
4602  * Executes its upvalue as a wml condition and returns the result.
4603  */
4605 {
4608 
4609  vconfig vcfg = luaW_checkvconfig(L, 1);
4610  lua_pushboolean(L, h(vcfg));
4611  return 1;
4612 }
4613 
4614 /**
4615  * Registers a function for use as a conditional handler.
4616  */
4618 {
4619  lua_State *L = mState;
4620 
4621  lua_getglobal(L, "wesnoth");
4622  lua_pushstring(L, "wml_conditionals");
4623  lua_rawget(L, -2);
4624  lua_pushstring(L, cmd.c_str());
4625  lua_pushlightuserdata(L, reinterpret_cast<void *>(h));
4627  lua_rawset(L, -3);
4628  lua_pop(L, 2);
4629 }
4630 
4631 /**
4632  * Runs a command from an event handler.
4633  * @return true if there is a handler for the command.
4634  * @note @a cfg should be either volatile or long-lived since the Lua
4635  * code may grab it for an arbitrary long time.
4636  */
4637 bool game_lua_kernel::run_wml_action(const std::string& cmd, const vconfig& cfg,
4638  const game_events::queued_event& ev)
4639 {
4640  lua_State *L = mState;
4641 
4642 
4643  if (!luaW_getglobal(L, "wesnoth", "wml_actions", cmd))
4644  return false;
4645 
4646  queued_event_context dummy(&ev, queued_events_);
4647  luaW_pushvconfig(L, cfg);
4648  luaW_pcall(L, 1, 0, true);
4649  return true;
4650 }
4651 
4652 
4653 /**
4654  * Evaluates a WML conidition.
4655  *
4656  * @returns Whether the condition passed.
4657  * @note @a cfg should be either volatile or long-lived since the Lua
4658  * code may grab it for an arbitrarily long time.
4659  */
4660 bool game_lua_kernel::run_wml_conditional(const std::string& cmd, const vconfig& cfg)
4661 {
4662  lua_State* L = mState;
4663 
4664  // If an invalid coniditional tag is used, consider it a pass.
4665  if(!luaW_getglobal(L, "wesnoth", "wml_conditionals", cmd)) {
4666  lg::wml_error() << "unknown conditional wml: [" << cmd << "]\n";
4667  return true;
4668  }
4669 
4670  luaW_pushvconfig(L, cfg);
4671 
4672  // Any runtime error is considered a fail.
4673  if(!luaW_pcall(L, 1, 1, true)) {
4674  return false;
4675  }
4676 
4677  bool b = luaW_toboolean(L, -1);
4678 
4679  lua_pop(L, 1);
4680  return b;
4681 }
4682 
4683 
4684 /**
4685 * Runs a script from a location filter.
4686 * The script is an already compiled function given by its name.
4687 */
4688 bool game_lua_kernel::run_filter(char const *name, const map_location& l)
4689 {
4692  return run_filter(name, 2);
4693 }
4694 
4695 /**
4696 * Runs a script from a location filter.
4697 * The script is an already compiled function given by its name.
4698 */
4699 bool game_lua_kernel::run_filter(char const *name, const team& t)
4700 {
4701  //TODO: instead of passing the lua team object we coudl also jsut pass its
4702  // number. then we wouldn't need this const cast.
4703  luaW_pushteam(mState, const_cast<team&>(t));
4704  return run_filter(name, 1);
4705 }
4706 /**
4707 * Runs a script from a unit filter.
4708 * The script is an already compiled function given by its name.
4709 */
4710 bool game_lua_kernel::run_filter(char const *name, const unit& u)
4711 {
4712  lua_State *L = mState;
4713  lua_unit* lu = luaW_pushlocalunit(L, const_cast<unit&>(u));
4714  // stack: unit
4715  // put the unit to the stack twice to prevent gc.
4716  lua_pushvalue(L, -1);
4717  // stack: unit, unit
4718  bool res = run_filter(name, 1);
4719  // stack: unit
4720  lu->clear_ref();
4721  lua_pop(L, 1);
4722  return res;
4723 }
4724 /**
4725 * Runs a script from a filter.
4726 * The script is an already compiled function given by its name.
4727 */
4728 bool game_lua_kernel::run_filter(char const *name, int nArgs)
4729 {
4730  map_locker(this);
4731  lua_State *L = mState;
4732  // Get the user filter by name.
4733  const std::vector<std::string>& path = utils::split(name, '.', utils::STRIP_SPACES);
4734  if (!luaW_getglobal(L, path))
4735  {
4736  std::string message = std::string() + "function " + name + " not found";
4737  log_error(message.c_str(), "Lua SUF Error");
4738  //we pushed nothing and can safeley return.
4739  return false;
4740  }
4741  lua_insert(L, -nArgs - 1);
4742 
4743  if (!luaW_pcall(L, nArgs, 1)) return false;
4744 
4745  bool b = luaW_toboolean(L, -1);
4746  lua_pop(L, 1);
4747  return b;
4748 }
4749 
4750 std::string game_lua_kernel::apply_effect(const std::string& name, unit& u, const config& cfg, bool need_apply)
4751 {
4752  lua_State *L = mState;
4753  int top = lua_gettop(L);
4754  std::string descr;
4755  // Stack: nothing
4756  lua_unit* lu = luaW_pushlocalunit(L, u);
4757  // Stack: unit
4758  // (Note: The unit needs to be on the stack twice to prevent untimely GC.)
4759  luaW_pushconfig(L, cfg);
4760  // Stack: unit, cfg
4761  if(luaW_getglobal(L, "wesnoth", "effects", name)) {
4762  map_locker(this);
4763  // Stack: unit, cfg, effect
4764  if(lua_istable(L, -1)) {
4765  // Effect is implemented by a table with __call and __descr
4766  if(need_apply) {
4767  lua_pushvalue(L, -1);
4768  // Stack: unit, cfg, effect, effect
4769  lua_pushvalue(L, top + 1);
4770  // Stack: unit, cfg, effect, effect, unit
4771  lua_pushvalue(L, top + 2);
4772  // Stack: unit, cfg, effect, effect, unit, cfg
4773  luaW_pcall(L, 2, 0);
4774  // Stack: unit, cfg, effect
4775  }
4776  if(luaL_getmetafield(L, -1, "__descr")) {
4777  // Stack: unit, cfg, effect, __descr
4778  if(lua_isstring(L, -1)) {
4779  // __descr was a static string
4780  descr = lua_tostring(L, -1);
4781  } else {
4782  lua_pushvalue(L, -2);
4783  // Stack: unit, cfg, effect, __descr, effect
4784  lua_pushvalue(L, top + 1);
4785  // Stack: unit, cfg, effect, __descr, effect, unit
4786  lua_pushvalue(L, top + 2);
4787  // Stack: unit, cfg, effect, __descr, effect, unit, cfg
4788  luaW_pcall(L, 3, 1);
4789  if(lua_isstring(L, -1) && !lua_isnumber(L, -1)) {
4790  descr = lua_tostring(L, -1);
4791  } else {
4792  ERR_LUA << "Effect __descr metafunction should have returned a string, but instead returned ";
4793  if(lua_isnone(L, -1)) {
4794  ERR_LUA << "nothing";
4795  } else {
4796  ERR_LUA << lua_typename(L, lua_type(L, -1));
4797  }
4798  }
4799  }
4800  }
4801  } else if(need_apply) {
4802  // Effect is assumed to be a simple function; no description is provided
4803  lua_pushvalue(L, top + 1);
4804  // Stack: unit, cfg, effect, unit
4805  lua_pushvalue(L, top + 2);
4806  // Stack: unit, cfg, effect, unit, cfg
4807  luaW_pcall(L, 2, 0);
4808  // Stack: unit, cfg
4809  }
4810  }
4811  lua_settop(L, top);
4812  lu->clear_ref();
4813  return descr;
4814 }
4815 
4817 {
4818  return ai::lua_ai_context::create(mState,code,engine);
4819 }
4820 
4822 {
4823  return ai::lua_ai_action_handler::create(mState,code,context);
4824 }
4825 
4827 {
4828  lua_State *L = mState;
4829 
4830  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_mouse_move")) {
4831  return;
4832  }
4833  lua_push(L, loc.wml_x());
4834  lua_push(L, loc.wml_y());
4835  luaW_pcall(L, 2, 0, false);
4836  return;
4837 }
4838 
4840 {
4841  lua_State *L = mState;
4842 
4843  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_mouse_action")) {
4844  return;
4845  }
4846  lua_push(L, loc.wml_x());
4847  lua_push(L, loc.wml_y());
4848  luaW_pcall(L, 2, 0, false);
4849  return;
4850 }
const_attack_ptr weapon
The weapon used by the unit to attack the opponent, or nullptr if there is none.
Definition: attack.hpp:52
void set_wml_y(int v)
Definition: location.hpp:156
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
Definition: lua_common.cpp:926
int dispatch(lua_State *L)
#define modify_bool_attrib(name, accessor)
Definition: lua_common.hpp:348
play_controller * controller
Definition: resources.cpp:21
static int intf_transform_unit(lua_State *L)
Changes a unit to the given unit type.
#define lua_isnoneornil(L, n)
Definition: lua.h:379
void wait_for_end() const
Definition: animation.cpp:1457
unsigned int end_text_duration
for how long the end-of-campaign text is shown
bool empty() const
Tests for an attribute that either was never set or was set to "".
LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
Definition: lapi.cpp:592
static int impl_end_level_data_get(lua_State *L)
LUALIB_API void * luaL_checkudata(lua_State *L, int ud, const char *tname)
Definition: lauxlib.cpp:345
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
std::stack< game_events::queued_event const *> queued_events_
Game board class.
Definition: game_board.hpp:50
static synced_state get_synced_state()
LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
Definition: lapi.cpp:728
#define lua_pushcfunction(L, f)
Definition: lua.h:370
static int intf_advance_unit(lua_State *L)
Advances a unit if the unit has enough xp.
static int intf_get_era(lua_State *L)
Gets a table for an era tag.
virtual std::string get_id() const =0
int map_locked_
A value != 0 means that the shouldn&#39;t remove any units from the map, usually because we are currently...
std::string apply_effect(const std::string &name, unit &u, const config &cfg, bool need_apply)
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:414
lua_unit * luaW_pushunit(lua_State *L, Args... args)
Definition: lua_unit.hpp:115
bool on_map() const
Definition: lua_unit.hpp:99
bool end_credits
whether to show the standard credits at the end
void set_shroud(bool shroud)
Definition: team.hpp:334
bool is_castle() const
Definition: terrain.hpp:141
double untouched
Resulting chance we were not hit by this opponent (important if it poisons)
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
bool update_locked() const
Whether the screen has been &#39;locked&#39; or not.
Definition: video.cpp:348
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:114
entity_location loc2
Definition: pump.hpp:65
LUA_API lua_Number lua_tonumberx(lua_State *L, int idx, int *pisnum)
Definition: lapi.cpp:355
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:90
int intf_remove_sound_source(lua_State *L)
Removes a sound source by its ID Arg 1: sound source ID.
int intf_allow_end_turn(lua_State *)
Allow undo sets the flag saying whether the event has mutated the game to false.
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:953
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1228
void remove_floating_label(int handle, int fadeout)
removes the floating label given by &#39;handle&#39; from the screen
void start_animations()
Definition: animation.cpp:1398
int intf_find_path(lua_State *L)
Finds a path between two locations.
const terrain_code NONE_TERRAIN
Definition: translation.hpp:58
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
Gets an optional vconfig from either a table or a userdata.
Definition: lua_common.cpp:839
std::string register_metatables(lua_State *L)
Definition: lua_unit.cpp:648
vconfig child(const std::string &key) const
Returns a child of *this whose key is key.
Definition: variable.cpp:288
int intf_set_end_campaign_credits(lua_State *L)
void reshroud()
Definition: team.hpp:332
const t_string & description() const
Definition: terrain.hpp:49
LUALIB_API lua_Number luaL_checknumber(lua_State *L, int arg)
Definition: lauxlib.cpp:420
game_display * game_display_
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:733
LUA_API void lua_settop(lua_State *L, int idx)
Definition: lapi.cpp:173
int intf_fire_event(lua_State *L, const bool by_id)
Fires an event.
#define lua_isnone(L, n)
Definition: lua.h:378
int intf_get_time_of_day(lua_State *L)
Gets time of day information.
team & luaW_checkteam(lua_State *L, int idx)
Test if the top stack element is a team, and if not, error.
Definition: lua_team.cpp:347
int intf_get_unit(lua_State *)
Gets the unit at the given location or with the given id.
LUA_API int lua_type(lua_State *L, int idx)
Definition: lapi.cpp:260
int village_support
Definition: game_config.cpp:54
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
void luaW_pushteam(lua_State *L, team &tm)
Create a full userdata containing a pointer to the team.
Definition: lua_team.cpp:340
std::string era()
Definition: game.cpp:689
std::string plague_type
The plague type used by the attack, if any.
Definition: attack.hpp:84
This class represents a single unit of a specific type.
Definition: unit.hpp:120
int dummy
Definition: lstrlib.cpp:1347
game_classification * classification
Definition: resources.cpp:34
int intf_get_variable(lua_State *L)
Gets a WML variable.
tod_color color
The color modifications that should be made to the game board to reflect the time of day...
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit&#39;s movement cost on a particular terrain.
Definition: unit.hpp:1431
#define LUA_TUSERDATA
Definition: lua.h:72
int intf_match_location(lua_State *L)
Matches a location against the given filter.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
void advance_to(const unit_type &t, bool use_traits=false)
Advances this unit to another type.
Definition: unit.cpp:850
std::vector< int > get_sides_vector(const vconfig &cfg)
Gets a vector of sides from side= attribute in a given config node.
Various functions implementing vision (through fog of war and shroud).
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool run_filter(char const *name, const unit &u)
Runs a script from a unit filter.
int impl_theme_items_get(lua_State *L)
Creates a field of the theme_items table and returns it (__index metamethod).
int intf_replace_schedule(lua_State *l)
Replacing the current time of day schedule.
bool play_stage()
Play the turn - strategy.
Definition: stage.cpp:56
void set_clip_rect(const SDL_Rect &r)
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 manager & get_singleton()
Definition: manager.hpp:143
int impl_get_terrain_info(lua_State *L)
Gets details about a terrain.
void write(config &res) const
Definition: label.cpp:431
config_array_view traits() const
Definition: types.hpp:391
LUA_API void lua_pushboolean(lua_State *L, int b)
Definition: lapi.cpp:581
LUA_API int lua_rawgeti(lua_State *L, int idx, lua_Integer n)
Definition: lapi.cpp:710
Various functions that implement attacks and attack calculations.
int impl_end_level_data_set(lua_State *)
Variant for storing WML attributes.
int intf_view_locked(lua_State *L)
Gets whether gamemap scrolling is disabled for the user.
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
bool luaW_isunit(lua_State *L, int index)
Test if a Lua value is a unit.
Definition: lua_unit.cpp:113
int intf_label(lua_State *L, bool add)
bool clear_fog(const map_location &loc)
Definition: team.hpp:331
void add_log_data(const std::string &key, const std::string &var)
Definition: replay.cpp:310
virtual std::vector< component * > get_children(const std::string &type)
Definition: component.cpp:105
std::vector< team > & teams()
static const char animatorKey[]
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
int intf_log(lua_State *L)
Logs a message Arg 1: (optional) Logger; "wml" for WML errors or deprecations Arg 2: Message Arg 3: W...
logger & info()
Definition: log.cpp:88
#define a
config_array_view child_range(config_key_type key) const
static map & registry()
using static function variable instead of static member variable to prevent static initialization fia...
int intf_clear_messages(lua_State *)
Removes all messages from the chat window.
Definition: video.hpp:31
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:406
void refog()
Definition: team.hpp:333
int intf_play_sound(lua_State *L)
Plays a sound, possibly repeated.
int next_player_number_
Definition: game_state.hpp:60
static int impl_animator_get(lua_State *L)
bool have_location(const vconfig &cfg)
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible, but which is unoccupied by any units.
Definition: pathfind.cpp:54
LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n)
Definition: lapi.cpp:889
LUALIB_API int luaL_getmetafield(lua_State *L, int obj, const char *event)
Definition: lauxlib.cpp:823
LUA_API int lua_gettop(lua_State *L)
Definition: lapi.cpp:168
child_itors child_range(config_key_type key)
Definition: config.cpp:356
std::string register_table(lua_State *L)
std::string id
Definition: time_of_day.hpp:89
int intf_extract_unit(lua_State *L)
Extracts a unit from the map or a recall list and gives it to Lua.
double average_hp(unsigned int healing=0) const
What&#39;s the average hp (weighted average of hp_dist).
const map_location & filter_loc() const
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
Definition: lua_common.cpp:898
static int intf_copy_unit(lua_State *L)
Copies a unit.
void set_lifetime(int lifetime, int fadeout=100)
std::string register_metatable(lua_State *L)
int intf_get_all_vars(lua_State *L)
Gets all the WML variables currently set.
LUA_API int lua_getglobal(lua_State *L, const char *name)
Definition: lapi.cpp:632
int intf_find_cost_map(lua_State *L)
Is called with one or more units and builds a cost map.
int intf_terrainmap_iter(lua_State *L)
void clear(const std::string &key)
Definition: general.cpp:203
int lawful_bonus
The % bonus lawful units receive.
Definition: time_of_day.hpp:82
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:226
dest_vect destinations
Definition: pathfind.hpp:100
unit_ptr clone() const
Definition: unit.hpp:209
#define lua_tointeger(L, i)
Definition: lua.h:362
int intf_set_time_of_day(lua_State *L)
const std::string & gamedata
int wml_x() const
Definition: location.hpp:152
virtual config to_config() const
Serialize to config.
Definition: engine_lua.cpp:384
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
static lua_ai_context * create(lua_State *L, char const *code, engine_lua *engine)
Definition: core.cpp:983
LUA_API int lua_rawget(lua_State *L, int idx)
Definition: lapi.cpp:698
Composite AI stages.
std::string image
The image to be displayed in the game status.
Definition: time_of_day.hpp:86
unit_type_data unit_types
Definition: types.cpp:1447
void set_wml_x(int v)
Definition: location.hpp:155
int intf_get_fog_or_shroud(lua_State *L, bool fog)
static int cfun_wml_condition(lua_State *L)
Executes its upvalue as a wml condition and returns the result.
bool prescenario_save
Should a prescenario be created the next game?
int intf_set_village_owner(lua_State *L)
Sets the owner of a village.
lua_unit * luaW_pushlocalunit(lua_State *L, unit &u)
Pushes a private unit on the stack.
Definition: lua_unit.cpp:212
const color_t LABEL_COLOR
int intf_unit_ability(lua_State *L)
Returns true if the unit has the given ability enabled.
int intf_match_unit(lua_State *L)
Matches a unit against the given filter.
int intf_set_next_scenario(lua_State *L)
void push_builtin_effect()
Registers a function for use as an effect handler.
static CVideo & get_singleton()
Definition: video.hpp:48
std::string name
Definition: pump.hpp:62
Replay control code.
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
#define lua_tonumber(L, i)
Definition: lua.h:361
config & child_or_add(config_key_type key)
Definition: config.cpp:490
advance_unit_params & fire_events(bool value)
Definition: advancement.hpp:46
bool replay_save
Should a replay save be made?
void remove(const std::string &id)
Definition: soundsource.cpp:65
std::string save_id_or_number() const
Definition: team.hpp:240
void custom_command(const std::string &, const config &)
Additional functionality for a non-const variable_info.
bool slows
Attack slows opponent when it hits.
Definition: attack.hpp:57
int intf_skip_messages(lua_State *L)
Set whether to skip messages Arg 1 (optional) - boolean.
void set_font_size(int font_size)
LUA_API int lua_isuserdata(lua_State *L, int idx)
Definition: lapi.cpp:298
const std::string & editor_image() const
Definition: terrain.hpp:46
LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n)
Definition: lapi.cpp:555
int intf_scroll(lua_State *L)
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2466
int impl_theme_items_set(lua_State *L)
Sets a field of the theme_items table (__newindex metamethod).
void append_children(const config &cfg)
Adds children from cfg.
Definition: config.cpp:235
#define return_vector_string_attrib(name, accessor)
Definition: lua_common.hpp:277
int intf_get_max_liminal_bonus(lua_State *L)
Gets the max liminal bonus.
static bool is_handled_file_tag(const std::string &s)
int intf_get_sides(lua_State *L)
Returns a proxy table array for all sides matching the given SSF.
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:384
void add_unit(const unit &u, bool use_max_moves=true)
Adds a units cost map to cost_map (increments the elements in cost_map)
Definition: pathfind.cpp:908
int drain_constant
Base HP drained regardless of damage dealt.
Definition: attack.hpp:79
An object to leave the synced context during draw or unsynced wml items when we don’t know whether w...
int(game_lua_kernel::* member_callback2)(lua_State *, bool)
int intf_gamestate_inspector(lua_State *)
static std::string _(const char *str)
Definition: gettext.hpp:92
int impl_game_config_set(lua_State *L) override
Sets some game_config data (__newindex metamethod).
void(* handler)(const queued_event &, const vconfig &)
Definition: action_wml.hpp:49
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:725
Definitions for the interface to Wesnoth Markup Language (WML).
bool empty() const
Definition: variable.hpp:100
const game_events::queued_event & get_event_info()
LUA_API int lua_absindex(lua_State *L, int idx)
Definition: lapi.cpp:161
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:25
void load_config(const config &v)
unsigned int chance_to_hit
Effective chance to hit as a percentage (all factors accounted for).
Definition: attack.hpp:75
int rest_heal_amount
Definition: game_config.cpp:60
std::map< int, config > get_user_choice_multiple_sides(const std::string &name, const user_choice &uch, std::set< int > sides)
Performs a choice for multiple sides for WML events.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:189
const_attr_itors attribute_range() const
Definition: config.cpp:833
A single unit type that the player may recruit.
Definition: types.hpp:44
int intf_get_locations(lua_State *L)
Gets all the locations matching a given filter.
int intf_log_replay(lua_State *L)
advance_unit_params & animate(bool value)
Definition: advancement.hpp:47
Unit and team statistics.
#define lua_pop(L, n)
Definition: lua.h:364
terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
Reads a single terrain from a string.
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:1020
void append_active_ai_for_side(ai::side_number side, const config &cfg)
Appends AI parameters to active AI of the given side.
Definition: manager.cpp:639
#define return_cfgref_attrib(name, accessor)
Definition: lua_common.hpp:269
bool clear_dest(const map_location &dest, const unit &viewer)
Clears shroud (and fog) at the provided location and its immediate neighbors.
Definition: vision.cpp:504
bool reveal_map
Should we reveal map when game is ended? (Multiplayer only)
bool have_unit(const vconfig &cfg)
#define b
bool is_village() const
Definition: terrain.hpp:140
bool clear_unit(const map_location &view_loc, team &view_team, std::size_t viewer_id, int sight_range, bool slowed, const movetype::terrain_costs &costs, const map_location &real_loc, const std::set< map_location > *known_units=nullptr, std::size_t *enemy_count=nullptr, std::size_t *friend_count=nullptr, move_unit_spectator *spectator=nullptr, bool instant=true)
Clears shroud (and fog) around the provided location for view_team based on sight_range, costs, and slowed.
Definition: vision.cpp:334
int intf_find_reach(lua_State *L)
Finds all the locations reachable by a unit.
config to_config() const
void set_game_display(game_display *gd)
bool poisons
Attack poisons opponent when it hits.
Definition: attack.hpp:61
int vision_cost(const t_translation::terrain_code &terrain) const
Get the unit&#39;s vision cost on a particular terrain.
Definition: unit.hpp:1441
int intf_set_variable(lua_State *L)
Sets a WML variable.
bool fog()
Definition: game.cpp:533
LUALIB_API const char * luaL_optlstring(lua_State *L, int arg, const char *def, size_t *len)
Definition: lauxlib.cpp:409
std::string register_metatable(lua_State *L)
Definition: lua_team.cpp:305
void set_flag(const std::string &flag)
Definition: team.hpp:313
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:26
int intf_delay(lua_State *L)
Delays engine for a while.
t_string name
Definition: time_of_day.hpp:87
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:55
void add_modification(const std::string &type, const config &modification, bool no_add=false)
Add a new modification to the unit.
Definition: unit.cpp:2215
#define lua_upvalueindex(i)
Definition: lua.h:45
bool backstab_pos
True if the attacker is in position to backstab the defender (this is used to determine whether to ap...
Definition: attack.hpp:62
int light_bonus(int base) const
Returns the light (lawful) bonus for this terrain when the time of day gives a base bonus...
Definition: terrain.hpp:131
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit&#39;s defense on a given terrain.
Definition: unit.cpp:1573
static void clear_status_caches()
Clear this unit status cache for all units.
Definition: unit.cpp:647
LUA_INTEGER lua_Integer
Definition: lua.h:94
unsigned attribute_count() const
Count the number of non-blank attributes.
Definition: config.cpp:401
const_all_children_iterator ordered_end() const
Definition: config.cpp:943
child_list get_children(const std::string &key) const
Definition: variable.cpp:226
std::vector< const unit * > all_matches_with_unit(const unit &u) const
Definition: filter.hpp:170
#define LUA_TSTRING
Definition: lua.h:69
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
static int intf_eval_conditional(lua_State *L)
Evaluates a boolean WML conditional.
static game_config_manager * get()
static std::string at(const std::string &file, int line)
void select_hex_callback(const map_location &loc)
int intf_get_label(lua_State *L)
int show_gamestate_inspector(const vconfig &cfg, const game_data &data, const game_state &state)
Definition: lua_gui2.cpp:246
const t_string & editor_name() const
Definition: terrain.hpp:48
int intf_create_side(lua_State *L)
LUALIB_API int luaL_argerror(lua_State *L, int arg, const char *extramsg)
Definition: lauxlib.cpp:175
int damage
Effective damage of the weapon (all factors accounted for).
Definition: attack.hpp:76
static int intf_get_viewing_side(lua_State *L)
Gets currently viewing side.
game_events::pump_result_t fire_events()
Fires the sighted events that were earlier recorded by fog/shroud clearing.
Definition: vision.cpp:555
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
virtual void log_error(char const *msg, char const *context="Lua error") override
Error reporting mechanisms, used by virtual methods protected_call and load_string.
std::string register_vconfig_metatable(lua_State *L)
Adds the vconfig metatable.
Definition: lua_common.cpp:462
static int impl_add_animation(lua_State *L)
Various functions that implement advancements of units.
#define modify_string_attrib(name, accessor)
Definition: lua_common.hpp:301
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:370
bool linger_mode
Should linger mode be invoked?
std::vector< map_location > steps
Definition: pathfind.hpp:134
int intf_simulate_combat(lua_State *L)
Simulates a combat between two units.
int intf_select_unit(lua_State *L)
Selects and highlights the given location on the map.
int intf_remove_tile_overlay(lua_State *L)
Removes an overlay from a tile.
void splice_children(config &src, const std::string &key)
Moves all the children with tag key from src to this.
Definition: config.cpp:650
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:235
int intf_remove_time_area(lua_State *)
Removing new time_areas dynamically with Standard Location Filters.
#define LUA_TNONE
Definition: lua.h:63
int intf_on_board(lua_State *L)
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil...
Definition: lua_common.cpp:874
void set_theme(const std::string &theme)
Definition: game.cpp:824
LUA_API int lua_isstring(lua_State *L, int idx)
Definition: lapi.cpp:292
tod_manager & tod_man()
int w() const
Effective map width.
Definition: map.hpp:49
bool luaW_toboolean(lua_State *L, int n)
Definition: lua_common.cpp:893
component * get_component(component *root, const std::string &path)
Definition: manager.cpp:281
bool uses_shroud() const
Definition: team.hpp:326
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
std::string test_result
result to use if this is a unit test
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
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
Definition: label.cpp:146
unsigned int rounds
Berserk special can force us to fight more than one round.
Definition: attack.hpp:72
std::ostringstream wrapper.
Definition: formatter.hpp:38
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
static int intf_switch_ai(lua_State *L)
#define LUA_TNIL
Definition: lua.h:65
int impl_game_config_get(lua_State *L) override
Gets some game_config data (__index metamethod).
map_location curr
Definition: pathfind.hpp:88
Proxy table for the AI context.
Definition: core.hpp:32
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:616
LUA_API void * lua_newuserdatauv(lua_State *L, size_t size, int nuvalue)
Definition: lapi.cpp:1311
int wml_y() const
Definition: location.hpp:153