The Battle for Wesnoth  1.15.12+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 and create_jamming_map
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 /**
1649  * Finds all the locations for which a given unit would remove the fog (if there was fog on the map).
1650  *
1651  * - Arg 1: source location OR unit.
1652  * - Ret 1: array of triples (coordinates + remaining vision points).
1653  */
1655 {
1656  int arg = 1;
1657  const unit* u = nullptr;
1658 
1659  if (lua_isuserdata(L, arg))
1660  {
1661  u = &luaW_checkunit(L, arg);
1662  ++arg;
1663  }
1664  else
1665  {
1666  map_location src = luaW_checklocation(L, arg);
1667  unit_map::const_unit_iterator ui = units().find(src);
1668  if (!ui.valid())
1669  return luaL_argerror(L, 1, "unit not found");
1670  u = ui.get_shared_ptr().get();
1671  ++arg;
1672  }
1673 
1674  if(!u)
1675  {
1676  return luaL_error(L, "wesnoth.find_vision_range: requires a valid unit");
1677  }
1678 
1679  std::map<map_location, int> jamming_map;
1680  actions::create_jamming_map(jamming_map, resources::gameboard->get_team(u->side()));
1681  pathfind::vision_path res(*u, u->get_location(), jamming_map);
1682 
1683  auto vision_set = res.edges;
1684  for(auto d : res.destinations)
1685  {
1686  vision_set.insert(d.curr);
1687  }
1688 
1689  lua_createtable(L, vision_set.size(), 0);
1690  int i = 1;
1691  for (const map_location& loc : vision_set)
1692  {
1693  lua_createtable(L, 2, 0);
1694  lua_pushinteger(L, loc.wml_x());
1695  lua_rawseti(L, -2, 1);
1696  lua_pushinteger(L, loc.wml_y());
1697  lua_rawseti(L, -2, 2);
1698  lua_rawseti(L, -2, i);
1699  ++i;
1700  }
1701  return 1;
1702 }
1703 
1704 template<typename T> // This is only a template so I can avoid typing out the long typename. >_>
1705 static int load_fake_units(lua_State* L, int arg, T& fake_units)
1706 {
1707  for (int i = 1, i_end = lua_rawlen(L, arg); i <= i_end; ++i)
1708  {
1709  map_location src;
1710  lua_rawgeti(L, arg, i);
1711  int entry = lua_gettop(L);
1712  if (!lua_istable(L, entry)) {
1713  goto error;
1714  }
1715 
1716  if (!luaW_tolocation(L, entry, src)) {
1717  goto error;
1718  }
1719 
1720  lua_rawgeti(L, entry, 3);
1721  if (!lua_isnumber(L, -1)) {
1722  lua_getfield(L, entry, "side");
1723  if (!lua_isnumber(L, -1)) {
1724  goto error;
1725  }
1726  }
1727  int side = lua_tointeger(L, -1);
1728 
1729  lua_rawgeti(L, entry, 4);
1730  if (!lua_isstring(L, -1)) {
1731  lua_getfield(L, entry, "type");
1732  if (!lua_isstring(L, -1)) {
1733  goto error;
1734  }
1735  }
1736  std::string unit_type = lua_tostring(L, -1);
1737 
1738  fake_units.emplace_back(src, side, unit_type);
1739 
1740  lua_settop(L, entry - 1);
1741  }
1742  return 0;
1743 error:
1744  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");
1745 }
1746 
1747 /**
1748  * Is called with one or more units and builds a cost map.
1749  * - Arg 1: source location. (Or Arg 1: unit. Or Arg 1: table containing a filter)
1750  * - Arg 2: optional array of tables with 4 elements (coordinates + side + unit type string)
1751  * - Arg 3: optional table (optional fields: ignore_units, ignore_teleport, viewing_side, debug).
1752  * - Arg 4: optional table: standard location filter.
1753  * - Ret 1: array of triples (coordinates + array of tuples(summed cost + reach counter)).
1754  */
1756 {
1757  int arg = 1;
1758  unit* unit = luaW_tounit(L, arg, true);
1760  luaW_tovconfig(L, arg, filter);
1761 
1762  std::vector<const ::unit*> real_units;
1763  typedef std::vector<std::tuple<map_location, int, std::string>> unit_type_vector;
1764  unit_type_vector fake_units;
1765 
1766 
1767  if (unit) // 1. arg - unit
1768  {
1769  real_units.push_back(unit);
1770  }
1771  else if (!filter.null()) // 1. arg - filter
1772  {
1773  for(const ::unit* match : unit_filter(filter).all_matches_on_map()) {
1774  if(match->get_location().valid()) {
1775  real_units.push_back(match);
1776  }
1777  }
1778  }
1779  else // 1. arg - coordinates
1780  {
1781  map_location src = luaW_checklocation(L, arg);
1782  unit_map::const_unit_iterator ui = units().find(src);
1783  if (ui.valid())
1784  {
1785  real_units.push_back(&(*ui));
1786  }
1787  }
1788  ++arg;
1789 
1790  if (lua_istable(L, arg)) // 2. arg - optional types
1791  {
1792  load_fake_units(L, arg, fake_units);
1793  ++arg;
1794  }
1795 
1796  if(real_units.empty() && fake_units.empty())
1797  {
1798  return luaL_argerror(L, 1, "unit(s) not found");
1799  }
1800 
1801  int viewing_side = 0;
1802  bool ignore_units = true, see_all = true, ignore_teleport = false, debug = false, use_max_moves = false;
1803 
1804  if (lua_istable(L, arg)) // 4. arg - options
1805  {
1806  lua_pushstring(L, "ignore_units");
1807  lua_rawget(L, arg);
1808  if (!lua_isnil(L, -1))
1809  {
1810  ignore_units = luaW_toboolean(L, -1);
1811  }
1812  lua_pop(L, 1);
1813 
1814  lua_pushstring(L, "ignore_teleport");
1815  lua_rawget(L, arg);
1816  if (!lua_isnil(L, -1))
1817  {
1818  ignore_teleport = luaW_toboolean(L, -1);
1819  }
1820  lua_pop(L, 1);
1821 
1822  lua_pushstring(L, "viewing_side");
1823  lua_rawget(L, arg);
1824  if (!lua_isnil(L, -1))
1825  {
1826  int i = luaL_checkinteger(L, -1);
1827  if (i >= 1 && i <= static_cast<int>(teams().size()))
1828  {
1829  viewing_side = i;
1830  see_all = false;
1831  }
1832  }
1833 
1834  lua_pushstring(L, "debug");
1835  lua_rawget(L, arg);
1836  if (!lua_isnil(L, -1))
1837  {
1838  debug = luaW_toboolean(L, -1);
1839  }
1840  lua_pop(L, 1);
1841 
1842  lua_pushstring(L, "use_max_moves");
1843  lua_rawget(L, arg);
1844  if (!lua_isnil(L, -1))
1845  {
1846  use_max_moves = luaW_toboolean(L, -1);
1847  }
1848  lua_pop(L, 1);
1849  ++arg;
1850  }
1851 
1852  // 5. arg - location filter
1853  filter = vconfig::unconstructed_vconfig();
1854  std::set<map_location> location_set;
1855  luaW_tovconfig(L, arg, filter);
1856  if (filter.null())
1857  {
1858  filter = vconfig(config(), true);
1859  }
1860  filter_context & fc = game_state_;
1861  const terrain_filter t_filter(filter, &fc, false);
1862  t_filter.get_locations(location_set, true);
1863  ++arg;
1864 
1865  // build cost_map
1866  const team& viewing_team = viewing_side
1867  ? board().get_team(viewing_side)
1868  : board().teams()[0];
1869 
1870  pathfind::full_cost_map cost_map(
1871  ignore_units, !ignore_teleport, viewing_team, see_all, ignore_units);
1872 
1873  for (const ::unit* const u : real_units)
1874  {
1875  cost_map.add_unit(*u, use_max_moves);
1876  }
1877  for (const unit_type_vector::value_type& fu : fake_units)
1878  {
1879  const unit_type* ut = unit_types.find(std::get<2>(fu));
1880  cost_map.add_unit(std::get<0>(fu), ut, std::get<1>(fu));
1881  }
1882 
1883  if (debug)
1884  {
1885  if (game_display_) {
1886  game_display_->labels().clear_all();
1887  for (const map_location& loc : location_set)
1888  {
1889  std::stringstream s;
1890  s << cost_map.get_pair_at(loc).first;
1891  s << " / ";
1892  s << cost_map.get_pair_at(loc).second;
1893  game_display_->labels().set_label(loc, s.str());
1894  }
1895  }
1896  }
1897 
1898  // create return value
1899  lua_createtable(L, location_set.size(), 0);
1900  int counter = 1;
1901  for (const map_location& loc : location_set)
1902  {
1903  lua_createtable(L, 4, 0);
1904 
1905  lua_pushinteger(L, loc.wml_x());
1906  lua_rawseti(L, -2, 1);
1907 
1908  lua_pushinteger(L, loc.wml_y());
1909  lua_rawseti(L, -2, 2);
1910 
1911  lua_pushinteger(L, cost_map.get_pair_at(loc).first);
1912  lua_rawseti(L, -2, 3);
1913 
1914  lua_pushinteger(L, cost_map.get_pair_at(loc).second);
1915  lua_rawseti(L, -2, 4);
1916 
1917  lua_rawseti(L, -2, counter);
1918  ++counter;
1919  }
1920  return 1;
1921 }
1922 
1924  vconfig cfg(luaW_checkvconfig(L, 1));
1925 
1926  // Remove any old message.
1927  static int floating_label = 0;
1928  if (floating_label)
1929  font::remove_floating_label(floating_label);
1930 
1931  // Display a message on-screen
1932  std::string text = cfg["text"];
1933  if(text.empty() || !game_display_)
1934  return 0;
1935 
1936  int size = cfg["size"].to_int(font::SIZE_SMALL);
1937  int lifetime = cfg["duration"].to_int(50);
1938 
1939  color_t color = font::LABEL_COLOR;
1940 
1941  if(!cfg["color"].empty()) {
1942  color = color_t::from_rgb_string(cfg["color"]);
1943  } else if(cfg.has_attribute("red") || cfg.has_attribute("green") || cfg.has_attribute("blue")) {
1944  color = color_t(cfg["red"], cfg["green"], cfg["blue"]);
1945  }
1946 
1947  const SDL_Rect& rect = game_display_->map_outside_area();
1948 
1949  font::floating_label flabel(text);
1950  flabel.set_font_size(size);
1951  flabel.set_color(color);
1952  flabel.set_position(rect.x + rect.w/2, rect.y + rect.h/2);
1953  flabel.set_lifetime(lifetime);
1954  flabel.set_clip_rect(rect);
1955 
1956  floating_label = font::add_floating_label(flabel);
1957 
1958  return 0;
1959 }
1960 
1962 {
1963  if(game_display_) {
1964  game_display_->invalidate(loc);
1965  }
1966 
1967  units().erase(loc);
1968  resources::whiteboard->on_kill_unit();
1969 }
1970 
1971 /**
1972  * Places a unit on the map.
1973  * - Arg 1: (optional) location.
1974  * - Arg 2: Unit (WML table or proxy), or nothing/nil to delete.
1975  * OR
1976  * - Arg 1: Unit (WML table or proxy)
1977  * - Arg 2: (optional) location
1978  * - Arg 3: (optional) boolean
1979  */
1981 {
1982  if(map_locked_) {
1983  return luaL_error(L, "Attempted to move a unit while the map is locked");
1984  }
1985 
1986  map_location loc;
1987  if (luaW_tolocation(L, 2, loc)) {
1988  if (!map().on_board(loc)) {
1989  return luaL_argerror(L, 2, "invalid location");
1990  }
1991  }
1992 
1993  if((luaW_isunit(L, 1))) {
1994  lua_unit& u = *luaW_checkunit_ref(L, 1);
1995  if(u.on_map() && u->get_location() == loc) {
1996  return 0;
1997  }
1998  if (!loc.valid()) {
1999  loc = u->get_location();
2000  if (!map().on_board(loc))
2001  return luaL_argerror(L, 1, "invalid location");
2002  }
2003 
2004  put_unit_helper(loc);
2005  u.put_map(loc);
2006  u.get_shared()->anim_comp().set_standing();
2007  } else if(!lua_isnoneornil(L, 1)) {
2008  const vconfig* vcfg = nullptr;
2009  config cfg = luaW_checkconfig(L, 1, vcfg);
2010  if (!map().on_board(loc)) {
2011  loc.set_wml_x(cfg["x"]);
2012  loc.set_wml_y(cfg["y"]);
2013  if (!map().on_board(loc))
2014  return luaL_argerror(L, 2, "invalid location");
2015  }
2016 
2017  unit_ptr u = unit::create(cfg, true, vcfg);
2018  put_unit_helper(loc);
2019  u->set_location(loc);
2020  units().insert(u);
2021  }
2022 
2023  // Fire event if using the deprecated version or if the final argument is not false
2024  // If the final boolean argument is omitted, the actual final argument (the unit or location) will always yield true.
2025  if(luaW_toboolean(L, -1)) {
2026  play_controller_.pump().fire("unit_placed", loc);
2027  }
2028  return 0;
2029 }
2030 
2031 /**
2032  * Erases a unit from the map
2033  * - Arg 1: Unit to erase OR Location to erase unit
2034  */
2036 {
2037  if(map_locked_) {
2038  return luaL_error(L, "Attempted to remove a unit while the map is locked");
2039  }
2040  map_location loc;
2041 
2042  if(luaW_isunit(L, 1)) {
2043  lua_unit& u = *luaW_checkunit_ref(L, 1);
2044  if (u.on_map()) {
2045  loc = u->get_location();
2046  if (!map().on_board(loc)) {
2047  return luaL_argerror(L, 1, "invalid location");
2048  }
2049  } else if (int side = u.on_recall_list()) {
2050  team &t = board().get_team(side);
2051  // Should it use underlying ID instead?
2053  } else {
2054  return luaL_argerror(L, 1, "can't erase private units");
2055  }
2056  } else if (luaW_tolocation(L, 1, loc)) {
2057  if (!map().on_board(loc)) {
2058  return luaL_argerror(L, 1, "invalid location");
2059  }
2060  } else {
2061  return luaL_argerror(L, 1, "expected unit or location");
2062  }
2063 
2064  units().erase(loc);
2065  resources::whiteboard->on_kill_unit();
2066  return 0;
2067 }
2068 
2069 /**
2070  * Puts a unit on a recall list.
2071  * - Arg 1: WML table or unit.
2072  * - Arg 2: (optional) side.
2073  */
2075 {
2076  if(map_locked_) {
2077  return luaL_error(L, "Attempted to move a unit while the map is locked");
2078  }
2079  lua_unit *lu = nullptr;
2080  unit_ptr u = unit_ptr();
2081  int side = lua_tointeger(L, 2);
2082  if (static_cast<unsigned>(side) > teams().size()) side = 0;
2083 
2084  if(luaW_isunit(L, 1)) {
2085  lu = luaW_checkunit_ref(L, 1);
2086  u = lu->get_shared();
2087  if(lu->on_recall_list() && lu->on_recall_list() == side) {
2088  return luaL_argerror(L, 1, "unit already on recall list");
2089  }
2090  } else {
2091  const vconfig* vcfg = nullptr;
2092  config cfg = luaW_checkconfig(L, 1, vcfg);
2093  u = unit::create(cfg, true, vcfg);
2094  }
2095 
2096  if (!side) {
2097  side = u->side();
2098  } else {
2099  u->set_side(side);
2100  }
2101  team &t = board().get_team(side);
2102  // Avoid duplicates in the recall list.
2103  std::size_t uid = u->underlying_id();
2105  t.recall_list().add(u);
2106  if (lu) {
2107  if (lu->on_map()) {
2108  units().erase(u->get_location());
2109  resources::whiteboard->on_kill_unit();
2110  u->anim_comp().clear_haloes();
2111  }
2112  lu->lua_unit::~lua_unit();
2113  new(lu) lua_unit(side, uid);
2114  }
2115 
2116  return 0;
2117 }
2118 
2119 /**
2120  * Extracts a unit from the map or a recall list and gives it to Lua.
2121  * - Arg 1: unit userdata.
2122  */
2124 {
2125  if(map_locked_) {
2126  return luaL_error(L, "Attempted to remove a unit while the map is locked");
2127  }
2128  lua_unit* lu = luaW_checkunit_ref(L, 1);
2129  unit_ptr u = lu->get_shared();
2130 
2131  if (lu->on_map()) {
2132  u = units().extract(u->get_location());
2133  assert(u);
2134  u->anim_comp().clear_haloes();
2135  } else if (int side = lu->on_recall_list()) {
2136  team &t = board().get_team(side);
2137  unit_ptr v = u->clone();
2138  t.recall_list().erase_if_matches_id(u->id());
2139  u = v;
2140  } else {
2141  return 0;
2142  }
2143 
2144  lu->lua_unit::~lua_unit();
2145  new(lu) lua_unit(u);
2146  return 0;
2147 }
2148 
2149 /**
2150  * Finds a vacant tile.
2151  * - Arg 1: location.
2152  * - Arg 2: optional unit for checking movement type.
2153  * - Rets 1,2: location.
2154  */
2156 {
2157  map_location loc = luaW_checklocation(L, 1);
2158 
2159  unit_ptr u;
2160  if (!lua_isnoneornil(L, 2)) {
2161  if(luaW_isunit(L, 2)) {
2162  u = luaW_checkunit_ptr(L, 2, false);
2163  } else {
2164  const vconfig* vcfg = nullptr;
2165  config cfg = luaW_checkconfig(L, 2, vcfg);
2166  u = unit::create(cfg, false, vcfg);
2167  }
2168  }
2169 
2170  map_location res = find_vacant_tile(loc, pathfind::VACANT_ANY, u.get());
2171 
2172  if (!res.valid()) return 0;
2173  lua_pushinteger(L, res.wml_x());
2174  lua_pushinteger(L, res.wml_y());
2175  return 2;
2176 }
2177 
2178 /**
2179  * Floats some text on the map.
2180  * - Arg 1: location.
2181  * - Arg 2: string.
2182  * - Arg 3: color.
2183  */
2185 {
2186  map_location loc = luaW_checklocation(L, 1);
2187  color_t color = font::LABEL_COLOR;
2188 
2189  t_string text = luaW_checktstring(L, 2);
2190  if (!lua_isnoneornil(L, 3)) {
2192  }
2193 
2194  if (game_display_) {
2195  game_display_->float_label(loc, text, color);
2196  }
2197  return 0;
2198 }
2199 
2200 /**
2201  * Creates a unit from its WML description.
2202  * - Arg 1: WML table.
2203  * - Ret 1: unit userdata.
2204  */
2206 {
2207  const vconfig* vcfg = nullptr;
2208  config cfg = luaW_checkconfig(L, 1, vcfg);
2209  unit_ptr u = unit::create(cfg, true, vcfg);
2210  luaW_pushunit(L, u);
2211  return 1;
2212 }
2213 
2214 /**
2215  * Copies a unit.
2216  * - Arg 1: unit userdata.
2217  * - Ret 1: unit userdata.
2218  */
2220 {
2221  unit& u = luaW_checkunit(L, 1);
2222  luaW_pushunit(L, u.clone());
2223  return 1;
2224 }
2225 
2226 /**
2227  * Returns unit resistance against a given attack type.
2228  * - Arg 1: unit userdata.
2229  * - Arg 2: string containing the attack type.
2230  * - Arg 3: boolean indicating if attacker.
2231  * - Arg 4: optional location.
2232  * - Ret 1: integer.
2233  */
2235 {
2236  const unit& u = luaW_checkunit(L, 1);
2237  char const *m = luaL_checkstring(L, 2);
2238  bool a = false;
2239  map_location loc = u.get_location();
2240 
2241  if(lua_isboolean(L, 3)) {
2242  a = luaW_toboolean(L, 3);
2243  if(!lua_isnoneornil(L, 4)) {
2244  loc = luaW_checklocation(L, 4);
2245  }
2246  } else if(!lua_isnoneornil(L, 3)) {
2247  loc = luaW_checklocation(L, 3);
2248  }
2249 
2250  lua_pushinteger(L, 100 - u.resistance_against(m, a, loc));
2251  return 1;
2252 }
2253 
2254 /**
2255  * Returns unit movement cost on a given terrain.
2256  * - Arg 1: unit userdata.
2257  * - Arg 2: string containing the terrain type.
2258  * - Ret 1: integer.
2259  */
2261 {
2262  const unit& u = luaW_checkunit(L, 1);
2264  map_location loc;
2265  if(luaW_tolocation(L, 2, loc)) {
2266  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2267  } else if(lua_isstring(L, 2)) {
2268  char const *m = luaL_checkstring(L, 2);
2270  } else return luaW_type_error(L, 2, "location or terrain string");
2271  lua_pushinteger(L, u.movement_cost(t));
2272  return 1;
2273 }
2274 
2275 /**
2276  * Returns unit vision cost on a given terrain.
2277  * - Arg 1: unit userdata.
2278  * - Arg 2: string containing the terrain type.
2279  * - Ret 1: integer.
2280  */
2282 {
2283  const unit& u = luaW_checkunit(L, 1);
2285  map_location loc;
2286  if(luaW_tolocation(L, 2, loc)) {
2287  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2288  } else if(lua_isstring(L, 2)) {
2289  char const *m = luaL_checkstring(L, 2);
2291  } else return luaW_type_error(L, 2, "location or terrain string");
2292  lua_pushinteger(L, u.vision_cost(t));
2293  return 1;
2294 }
2295 
2296 /**
2297  * Returns unit jamming cost on a given terrain.
2298  * - Arg 1: unit userdata.
2299  * - Arg 2: string containing the terrain type.
2300  * - Ret 1: integer.
2301  */
2303 {
2304  const unit& u = luaW_checkunit(L, 1);
2306  map_location loc;
2307  if(luaW_tolocation(L, 2, loc)) {
2308  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2309  } else if(lua_isstring(L, 2)) {
2310  char const *m = luaL_checkstring(L, 2);
2312  } else return luaW_type_error(L, 2, "location or terrain string");
2313  lua_pushinteger(L, u.jamming_cost(t));
2314  return 1;
2315 }
2316 
2317 /**
2318  * Returns unit defense on a given terrain.
2319  * - Arg 1: unit userdata.
2320  * - Arg 2: string containing the terrain type.
2321  * - Ret 1: integer.
2322  */
2324 {
2325  const unit& u = luaW_checkunit(L, 1);
2327  map_location loc;
2328  if(luaW_tolocation(L, 2, loc)) {
2329  t = static_cast<const game_board*>(resources::gameboard)->map()[loc];
2330  } else if(lua_isstring(L, 2)) {
2331  char const *m = luaL_checkstring(L, 2);
2333  } else return luaW_type_error(L, 2, "location or terrain string");
2334  lua_pushinteger(L, 100 - u.defense_modifier(t));
2335  return 1;
2336 }
2337 
2338 /**
2339  * Returns true if the unit has the given ability enabled.
2340  * - Arg 1: unit userdata.
2341  * - Arg 2: string.
2342  * - Ret 1: boolean.
2343  */
2345 {
2346  const unit& u = luaW_checkunit(L, 1);
2347  char const *m = luaL_checkstring(L, 2);
2349  return 1;
2350 }
2351 
2352 /**
2353  * Changes a unit to the given unit type.
2354  * - Arg 1: unit userdata.
2355  * - Arg 2: unit type name
2356  * - Arg 3: (optional) unit variation name
2357  */
2359 {
2360  unit& u = luaW_checkunit(L, 1);
2361  char const *m = luaL_checkstring(L, 2);
2362  const unit_type *utp = unit_types.find(m);
2363  if (!utp) return luaL_argerror(L, 2, "unknown unit type");
2364  if(lua_isstring(L, 3)) {
2365  const std::string& m2 = lua_tostring(L, 3);
2366  if(!utp->has_variation(m2)) return luaL_argerror(L, 2, "unknown unit variation");
2367  utp = &utp->get_variation(m2);
2368  }
2369  u.advance_to(*utp);
2370 
2371  return 0;
2372 }
2373 
2374 /**
2375  * Puts a table at the top of the stack with some combat result.
2376  */
2377 static void luaW_pushsimdata(lua_State *L, const combatant &cmb)
2378 {
2379  int n = cmb.hp_dist.size();
2380  lua_createtable(L, 0, 4);
2381  lua_pushnumber(L, cmb.poisoned);
2382  lua_setfield(L, -2, "poisoned");
2383  lua_pushnumber(L, cmb.slowed);
2384  lua_setfield(L, -2, "slowed");
2385  lua_pushnumber(L, cmb.untouched);
2386  lua_setfield(L, -2, "untouched");
2387  lua_pushnumber(L, cmb.average_hp());
2388  lua_setfield(L, -2, "average_hp");
2389  lua_createtable(L, n, 0);
2390  for (int i = 0; i < n; ++i) {
2391  lua_pushnumber(L, cmb.hp_dist[i]);
2392  lua_rawseti(L, -2, i);
2393  }
2394  lua_setfield(L, -2, "hp_chance");
2395 }
2396 
2397 /**
2398  * Puts a table at the top of the stack with information about the combatants' weapons.
2399  */
2401 {
2402 
2403  lua_createtable(L, 0, 16);
2404 
2405  lua_pushnumber(L, bcustats.num_blows);
2406  lua_setfield(L, -2, "num_blows");
2407  lua_pushnumber(L, bcustats.damage);
2408  lua_setfield(L, -2, "damage");
2409  lua_pushnumber(L, bcustats.chance_to_hit);
2410  lua_setfield(L, -2, "chance_to_hit");
2411  lua_pushboolean(L, bcustats.poisons);
2412  lua_setfield(L, -2, "poisons");
2413  lua_pushboolean(L, bcustats.slows);
2414  lua_setfield(L, -2, "slows");
2415  lua_pushboolean(L, bcustats.petrifies);
2416  lua_setfield(L, -2, "petrifies");
2417  lua_pushboolean(L, bcustats.plagues);
2418  lua_setfield(L, -2, "plagues");
2419  lua_pushstring(L, bcustats.plague_type.c_str());
2420  lua_setfield(L, -2, "plague_type");
2421  lua_pushboolean(L, bcustats.backstab_pos);
2422  lua_setfield(L, -2, "backstabs");
2423  lua_pushnumber(L, bcustats.rounds);
2424  lua_setfield(L, -2, "rounds");
2425  lua_pushboolean(L, bcustats.firststrike);
2426  lua_setfield(L, -2, "firststrike");
2427  lua_pushboolean(L, bcustats.drains);
2428  lua_setfield(L, -2, "drains");
2429  lua_pushnumber(L, bcustats.drain_constant);
2430  lua_setfield(L, -2, "drain_constant");
2431  lua_pushnumber(L, bcustats.drain_percent);
2432  lua_setfield(L, -2, "drain_percent");
2433 
2434 
2435  //if we called simulate_combat without giving an explicit weapon this can be useful.
2436  lua_pushnumber(L, bcustats.attack_num);
2437  lua_setfield(L, -2, "attack_num"); // DEPRECATED
2438  lua_pushnumber(L, bcustats.attack_num + 1);
2439  lua_setfield(L, -2, "number");
2440  //this is nullptr when there is no counter weapon
2441  if(bcustats.weapon != nullptr)
2442  {
2443  lua_pushstring(L, bcustats.weapon->id().c_str());
2444  lua_setfield(L, -2, "name");
2445  luaW_pushweapon(L, bcustats.weapon);
2446  lua_setfield(L, -2, "weapon");
2447  }
2448 
2449 }
2450 
2451 /**
2452  * Simulates a combat between two units.
2453  * - Arg 1: attacker userdata.
2454  * - Arg 2: optional weapon index.
2455  * - Arg 3: defender userdata.
2456  * - Arg 4: optional weapon index.
2457  *
2458  * - Ret 1: attacker results.
2459  * - Ret 2: defender results.
2460  * - Ret 3: info about the attacker weapon.
2461  * - Ret 4: info about the defender weapon.
2462  */
2464 {
2465  int arg_num = 1, att_w = -1, def_w = -1;
2466 
2467  unit_const_ptr att = luaW_checkunit(L, arg_num).shared_from_this();
2468  ++arg_num;
2469  if (lua_isnumber(L, arg_num)) {
2470  att_w = lua_tointeger(L, arg_num) - 1;
2471  if (att_w < 0 || att_w >= static_cast<int>(att->attacks().size()))
2472  return luaL_argerror(L, arg_num, "weapon index out of bounds");
2473  ++arg_num;
2474  }
2475 
2476  unit_const_ptr def = luaW_checkunit(L, arg_num).shared_from_this();
2477  ++arg_num;
2478  if (lua_isnumber(L, arg_num)) {
2479  def_w = lua_tointeger(L, arg_num) - 1;
2480  if (def_w < 0 || def_w >= static_cast<int>(def->attacks().size()))
2481  return luaL_argerror(L, arg_num, "weapon index out of bounds");
2482  ++arg_num;
2483  }
2484 
2485  battle_context context(units(), att->get_location(),
2486  def->get_location(), att_w, def_w, 0.0, nullptr, att, def);
2487 
2488  luaW_pushsimdata(L, context.get_attacker_combatant());
2489  luaW_pushsimdata(L, context.get_defender_combatant());
2490  luaW_pushsimweapon(L, context.get_attacker_stats());
2491  luaW_pushsimweapon(L, context.get_defender_stats());
2492  return 4;
2493 }
2494 
2495 /**
2496  * Modifies the music playlist.
2497  * - Arg 1: WML table, or nil to force changes.
2498  */
2500 {
2501  deprecated_message("wesnoth.set_music", DEP_LEVEL::INDEFINITE, "", "Use the wesnoth.playlist table instead!");
2502  if (lua_isnoneornil(L, 1)) {
2504  return 0;
2505  }
2506 
2507  config cfg = luaW_checkconfig(L, 1);
2509  return 0;
2510 }
2511 
2512 /**
2513  * Plays a sound, possibly repeated.
2514  * - Arg 1: string.
2515  * - Arg 2: optional integer.
2516  */
2518 {
2519  char const *m = luaL_checkstring(L, 1);
2520  if (play_controller_.is_skipping_replay()) return 0;
2521  int repeats = lua_tointeger(L, 2);
2522  sound::play_sound(m, sound::SOUND_FX, repeats);
2523  return 0;
2524 }
2525 
2526 /**
2527  * Gets/sets the current sound volume
2528  * - Arg 1: (optional) New volume to set
2529  * - Return: Original volume
2530  */
2532 {
2533  int vol = preferences::sound_volume();
2534  lua_pushnumber(L, sound::get_sound_volume() * 100.0 / vol);
2535  if(lua_isnumber(L, 1)) {
2536  float rel = lua_tonumber(L, 1);
2537  if(rel < 0.0f || rel > 100.0f) {
2538  return luaL_argerror(L, 1, "volume must be in range 0..100");
2539  }
2540  vol = static_cast<int>(rel*vol / 100.0f);
2542  }
2543  return 1;
2544 }
2545 
2546 /**
2547  * Scrolls to given tile.
2548  * - Arg 1: location.
2549  * - Arg 2: boolean preventing scroll to fog.
2550  * - Arg 3: boolean specifying whether to warp instantly.
2551  * - Arg 4: boolean specifying whether to skip if already onscreen
2552  */
2554 {
2555  map_location loc = luaW_checklocation(L, 1);
2556  bool check_fogged = luaW_toboolean(L, 2);
2558  ? luaW_toboolean(L, 3)
2561  : luaW_toboolean(L, 3)
2564  ;
2565  if (game_display_) {
2566  game_display_->scroll_to_tile(loc, scroll, check_fogged);
2567  }
2568  return 0;
2569 }
2570 
2572 {
2573  events::command_disabler command_disabler;
2574  deprecated_message("wesnoth.select_hex", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Use wesnoth.units.select and/or wesnoth.interface.highlight_hex instead.");
2575 
2576  // Need this because check_location may change the stack
2577  // By doing this now, we ensure that it won't do so when
2578  // intf_select_unit and intf_highlight_hex call it.
2579  const map_location loc = luaW_checklocation(L, 1);
2580  luaW_pushlocation(L, loc);
2581  lua_replace(L, 1);
2582 
2583  intf_select_unit(L);
2584  if(!lua_isnoneornil(L, 2) && luaW_toboolean(L,2)) {
2585  intf_highlight_hex(L);
2586  }
2587  return 0;
2588 }
2589 
2590 /**
2591  * Selects and highlights the given location on the map.
2592  * - Arg 1: location.
2593  * - Args 2,3: booleans
2594  */
2596 {
2597  events::command_disabler command_disabler;
2598  if(lua_isnoneornil(L, 1)) {
2599  play_controller_.get_mouse_handler_base().select_hex(map_location::null_location(), false, false, false);
2600  return 0;
2601  }
2602  const map_location loc = luaW_checklocation(L, 1);
2603  if(!map().on_board(loc)) return luaL_argerror(L, 1, "not on board");
2604  bool highlight = true;
2605  if(!lua_isnoneornil(L, 2))
2606  highlight = luaW_toboolean(L, 2);
2607  const bool fire_event = luaW_toboolean(L, 3);
2608  play_controller_.get_mouse_handler_base().select_hex(
2609  loc, false, highlight, fire_event);
2610  return 0;
2611 }
2612 
2613 /**
2614  * Deselects any highlighted hex on the map.
2615  * No arguments or return values
2616  */
2618 {
2619  if(game_display_) {
2620  game_display_->highlight_hex(map_location::null_location());
2621  }
2622 
2623  return 0;
2624 }
2625 
2626 /**
2627  * Return true if a replay is in progress but the player has chosen to skip it
2628  */
2630 {
2631  bool skipping = play_controller_.is_skipping_replay() || play_controller_.is_skipping_story();
2632  if (!skipping) {
2633  skipping = game_state_.events_manager_->pump().context_skip_messages();
2634  }
2635  lua_pushboolean(L, skipping);
2636  return 1;
2637 }
2638 
2639 /**
2640  * Set whether to skip messages
2641  * Arg 1 (optional) - boolean
2642  */
2644 {
2645  bool skip = true;
2646  if (!lua_isnone(L, 1)) {
2647  skip = luaW_toboolean(L, 1);
2648  }
2649  game_state_.events_manager_->pump().context_skip_messages(skip);
2650  return 0;
2651 }
2652 
2653 namespace
2654 {
2655  struct lua_synchronize : mp_sync::user_choice
2656  {
2657  lua_State *L;
2658  int user_choice_index;
2659  int random_choice_index;
2660  int ai_choice_index;
2661  std::string desc;
2662  lua_synchronize(lua_State *l, const std::string& descr, int user_index, int random_index = 0, int ai_index = 0)
2663  : L(l)
2664  , user_choice_index(user_index)
2665  , random_choice_index(random_index)
2666  , ai_choice_index(ai_index != 0 ? ai_index : user_index)
2667  , desc(descr)
2668  {}
2669 
2670  virtual config query_user(int side) const override
2671  {
2672  bool is_local_ai = lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).board().get_team(side).is_local_ai();
2673  config cfg;
2674  query_lua(side, is_local_ai ? ai_choice_index : user_choice_index, cfg);
2675  return cfg;
2676  }
2677 
2678  virtual config random_choice(int side) const override
2679  {
2680  config cfg;
2681  if(random_choice_index != 0 && lua_isfunction(L, random_choice_index)) {
2682  query_lua(side, random_choice_index, cfg);
2683  }
2684  return cfg;
2685  }
2686 
2687  virtual std::string description() const override
2688  {
2689  return desc;
2690  }
2691 
2692  void query_lua(int side, int function_index, config& cfg) const
2693  {
2694  assert(cfg.empty());
2695  lua_pushvalue(L, function_index);
2696  lua_pushnumber(L, side);
2697  if (luaW_pcall(L, 1, 1, false)) {
2698  if(!luaW_toconfig(L, -1, cfg)) {
2699  lua_kernel_base::get_lua_kernel<game_lua_kernel>(L).log_error("function returned to wesnoth.synchronize_choice a table which was partially invalid");
2700  }
2701  }
2702  }
2703  //Although lua's sync_choice can show a dialog, (and will in most cases)
2704  //we return false to enable other possible things that do not contain UI things.
2705  //it's in the responsibility of the umc dev to not show dialogs during prestart events.
2706  virtual bool is_visible() const override { return false; }
2707  };
2708 }//unnamed namespace for lua_synchronize
2709 
2710 /**
2711  * Ensures a value is synchronized among all the clients.
2712  * - Arg 1: optional string specifying the type id of the choice.
2713  * - Arg 2: function to compute the value, called if the client is the master.
2714  * - Arg 3: optional function, called instead of the first function if the user is not human.
2715  * - Arg 4: optional integer specifying, on which side the function should be evaluated.
2716  * - Ret 1: WML table returned by the function.
2717  */
2719 {
2720  std::string tagname = "input";
2721  t_string desc = _("input");
2722  int human_func = 0;
2723  int ai_func = 0;
2724  int side_for;
2725 
2726  int nextarg = 1;
2727  if(!lua_isfunction(L, nextarg) && luaW_totstring(L, nextarg, desc) ) {
2728  ++nextarg;
2729  }
2730  if(lua_isfunction(L, nextarg)) {
2731  human_func = nextarg++;
2732  }
2733  else {
2734  return luaL_argerror(L, nextarg, "expected a function");
2735  }
2736  if(lua_isfunction(L, nextarg)) {
2737  ai_func = nextarg++;
2738  }
2739  side_for = lua_tointeger(L, nextarg);
2740 
2741  config cfg = mp_sync::get_user_choice(tagname, lua_synchronize(L, desc, human_func, 0, ai_func), side_for);
2742  luaW_pushconfig(L, cfg);
2743  return 1;
2744 }
2745 /**
2746  * Ensures a value is synchronized among all the clients.
2747  * - Arg 1: optional string the id of this type of user input, may only contain characters a-z and '_'
2748  * - Arg 2: function to compute the value, called if the client is the master.
2749  * - Arg 3: an optional function to compute the value, if the side was null/empty controlled.
2750  * - Arg 4: an array of integers specifying, on which side the function should be evaluated.
2751  * - Ret 1: a map int -> WML tabls.
2752  */
2754 {
2755  std::string tagname = "input";
2756  t_string desc = _("input");
2757  int human_func = 0;
2758  int null_func = 0;
2759  std::vector<int> sides_for;
2760 
2761  int nextarg = 1;
2762  if(!lua_isfunction(L, nextarg) && luaW_totstring(L, nextarg, desc) ) {
2763  ++nextarg;
2764  }
2765  if(lua_isfunction(L, nextarg)) {
2766  human_func = nextarg++;
2767  }
2768  else {
2769  return luaL_argerror(L, nextarg, "expected a function");
2770  }
2771  if(lua_isfunction(L, nextarg)) {
2772  null_func = nextarg++;
2773  };
2774  sides_for = lua_check<std::vector<int>>(L, nextarg++);
2775 
2776  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())));
2777  return 1;
2778 }
2779 
2780 
2781 /**
2782  * Calls a function in an unsynced context (this specially means that all random calls used by that function will be unsynced).
2783  * This is usually used together with an unsynced if like 'if controller != network'
2784  * - Arg 1: function that will be called during the unsynced context.
2785  */
2787 {
2788  set_scontext_unsynced sync;
2789  lua_pushvalue(L, 1);
2790  luaW_pcall(L, 0, 0, false);
2791  return 0;
2792 }
2793 
2794 /**
2795  * Gets all the locations matching a given filter.
2796  * - Arg 1: WML table.
2797  * - Arg 2: Optional reference unit (teleport_unit)
2798  * - Ret 1: array of integer pairs.
2799  */
2801 {
2802  vconfig filter = luaW_checkvconfig(L, 1);
2803 
2804  std::set<map_location> res;
2805  filter_context & fc = game_state_;
2806  const terrain_filter t_filter(filter, &fc, false);
2807  if(luaW_isunit(L, 2)) {
2808  t_filter.get_locations(res, *luaW_tounit(L, 2), true);
2809  } else {
2810  t_filter.get_locations(res, true);
2811  }
2812 
2813  lua_createtable(L, res.size(), 0);
2814  int i = 1;
2815  for (const map_location& loc : res)
2816  {
2817  lua_createtable(L, 2, 0);
2818  lua_pushinteger(L, loc.wml_x());
2819  lua_rawseti(L, -2, 1);
2820  lua_pushinteger(L, loc.wml_y());
2821  lua_rawseti(L, -2, 2);
2822  lua_rawseti(L, -2, i);
2823  ++i;
2824  }
2825  return 1;
2826 }
2827 
2828 /**
2829  * Gets all the villages matching a given filter, or all the villages on the map if no filter is given.
2830  * - Arg 1: WML table (optional).
2831  * - Ret 1: array of integer pairs.
2832  */
2834 {
2835  std::vector<map_location> locs = map().villages();
2836  lua_newtable(L);
2837  int i = 1;
2838 
2839  vconfig filter = luaW_checkvconfig(L, 1);
2840 
2841  filter_context & fc = game_state_;
2842  for(std::vector<map_location>::const_iterator it = locs.begin(); it != locs.end(); ++it) {
2843  bool matches = terrain_filter(filter, &fc, false).match(*it);
2844  if (matches) {
2845  lua_createtable(L, 2, 0);
2846  lua_pushinteger(L, it->wml_x());
2847  lua_rawseti(L, -2, 1);
2848  lua_pushinteger(L, it->wml_y());
2849  lua_rawseti(L, -2, 2);
2850  lua_rawseti(L, -2, i);
2851  ++i;
2852  }
2853  }
2854  return 1;
2855 }
2856 
2857 /**
2858  * Matches a location against the given filter.
2859  * - Arg 1: location.
2860  * - Arg 2: WML table.
2861  * - Arg 3: Optional reference unit (teleport_unit)
2862  * - Ret 1: boolean.
2863  */
2865 {
2866  map_location loc = luaW_checklocation(L, 1);
2867  vconfig filter = luaW_checkvconfig(L, 2, true);
2868 
2869  if (filter.null()) {
2870  lua_pushboolean(L, true);
2871  return 1;
2872  }
2873 
2874  filter_context & fc = game_state_;
2875  const terrain_filter t_filter(filter, &fc, false);
2876  if(luaW_isunit(L, 3)) {
2877  lua_pushboolean(L, t_filter.match(loc, *luaW_tounit(L, 3)));
2878  } else {
2879  lua_pushboolean(L, t_filter.match(loc));
2880  }
2881  return 1;
2882 }
2883 
2884 
2885 
2886 /**
2887  * Matches a side against the given filter.
2888  * - Args 1: side number.
2889  * - Arg 2: WML table.
2890  * - Ret 1: boolean.
2891  */
2893 {
2894  vconfig filter = luaW_checkvconfig(L, 2, true);
2895 
2896  if (filter.null()) {
2897  lua_pushboolean(L, true);
2898  return 1;
2899  }
2900 
2901  filter_context & fc = game_state_;
2902  side_filter s_filter(filter, &fc);
2903 
2904  if(team* t = luaW_toteam(L, 1)) {
2905  lua_pushboolean(L, s_filter.match(*t));
2906  } else {
2907  unsigned side = luaL_checkinteger(L, 1) - 1;
2908  if (side >= teams().size()) return 0;
2909  lua_pushboolean(L, s_filter.match(side + 1));
2910  }
2911  return 1;
2912 }
2913 
2915 {
2916  int team_i;
2917  if(team* t = luaW_toteam(L, 1)) {
2918  team_i = t->side();
2919  } else {
2920  team_i = luaL_checkinteger(L, 1);
2921  }
2922  std::string flag = luaL_optlstring(L, 2, "", nullptr);
2923  std::string color = luaL_optlstring(L, 3, "", nullptr);
2924 
2925  if(flag.empty() && color.empty()) {
2926  return 0;
2927  }
2928  if(team_i < 1 || static_cast<std::size_t>(team_i) > teams().size()) {
2929  return luaL_error(L, "set_side_id: side number %d out of range", team_i);
2930  }
2931  team& side = board().get_team(team_i);
2932 
2933  if(!color.empty()) {
2934  side.set_color(color);
2935  }
2936  if(!flag.empty()) {
2937  side.set_flag(flag);
2938  }
2939 
2940  game_display_->reinit_flags_for_team(side);
2941  return 0;
2942 }
2943 
2944 static int intf_modify_ai(lua_State *L, const char* action)
2945 {
2946  int side_num;
2947  if(team* t = luaW_toteam(L, 1)) {
2948  side_num = t->side();
2949  } else {
2950  side_num = luaL_checkinteger(L, 1);
2951  }
2952  std::string path = luaL_checkstring(L, 2);
2953  config cfg {
2954  "action", action,
2955  "path", path
2956  };
2957  if(strcmp(action, "delete") == 0) {
2959  return 0;
2960  }
2961  config component = luaW_checkconfig(L, 3);
2962  std::size_t len = std::string::npos, open_brak = path.find_last_of('[');
2963  std::size_t dot = path.find_last_of('.');
2964  if(open_brak != len) {
2965  len = open_brak - dot - 1;
2966  }
2967  cfg.add_child(path.substr(dot + 1, len), component);
2969  return 0;
2970 }
2971 
2973 {
2974  int side_num;
2975  if(team* t = luaW_toteam(L, 1)) {
2976  side_num = t->side();
2977  } else {
2978  side_num = luaL_checkinteger(L, 1);
2979  }
2980  if(lua_isstring(L, 2)) {
2981  std::string file = luaL_checkstring(L, 2);
2982  if(!ai::manager::get_singleton().add_ai_for_side_from_file(side_num, file)) {
2983  std::string err = formatter() << "Could not load AI for side " << side_num << " from file " << file;
2984  lua_pushlstring(L, err.c_str(), err.length());
2985  return lua_error(L);
2986  }
2987  } else {
2989  }
2990  return 0;
2991 }
2992 
2994 {
2995  int side_num;
2996  if(team* t = luaW_toteam(L, 1)) {
2997  side_num = t->side();
2998  } else {
2999  side_num = luaL_checkinteger(L, 1);
3000  }
3001  config cfg = luaW_checkconfig(L, 2);
3002  if(!cfg.has_child("ai")) {
3003  cfg = config {"ai", cfg};
3004  }
3005  bool added_dummy_stage = false;
3006  if(!cfg.child("ai").has_child("stage")) {
3007  added_dummy_stage = true;
3008  cfg.child("ai").add_child("stage", config {"name", "empty"});
3009  }
3011  if(added_dummy_stage) {
3012  for(auto iter = cfg.ordered_begin(); iter != cfg.ordered_end(); iter++) {
3013  if(iter->key == "stage" && iter->cfg["name"] == "empty") {
3014  iter = cfg.erase(iter);
3015  }
3016  }
3017  }
3019  return 0;
3020 }
3021 
3023 {
3024  unsigned i = luaL_checkinteger(L, 1);
3025  if(i < 1 || i > teams().size()) return 0;
3026  luaW_pushteam(L, board().get_team(i));
3027  return 1;
3028 }
3029 
3030 /**
3031  * Returns a proxy table array for all sides matching the given SSF.
3032  * - Arg 1: SSF
3033  * - Ret 1: proxy table array
3034  */
3036 {
3037  LOG_LUA << "intf_get_sides called: this = " << std::hex << this << std::dec << " myname = " << my_name() << std::endl;
3038  std::vector<int> sides;
3039  const vconfig ssf = luaW_checkvconfig(L, 1, true);
3040  if(ssf.null()) {
3041  for (unsigned side_number = 1; side_number <= teams().size(); ++side_number) {
3042  sides.push_back(side_number);
3043  }
3044  } else {
3045  filter_context & fc = game_state_;
3046 
3047  side_filter filter(ssf, &fc);
3048  sides = filter.get_teams();
3049  }
3050 
3051  lua_settop(L, 0);
3052  lua_createtable(L, sides.size(), 0);
3053  unsigned index = 1;
3054  for(int side : sides) {
3055  luaW_pushteam(L, board().get_team(side));
3056  lua_rawseti(L, -2, index);
3057  ++index;
3058  }
3059 
3060  return 1;
3061 }
3062 
3063 /**
3064  * .Returns information about the global traits known to the engine.
3065  * - Ret 1: Table with named fields holding wml tables describing the traits.
3066  */
3068 {
3069  lua_newtable(L);
3070  for(const config& trait : unit_types.traits()) {
3071  const std::string& id = trait["id"];
3072  //It seems the engine does nowhere check the id field for emptyness or duplicates
3073  //(also not later on).
3074  //However, the worst thing to happen is that the trait read later overwrites the older one,
3075  //and this is not the right place for such checks.
3076  lua_pushstring(L, id.c_str());
3077  luaW_pushconfig(L, trait);
3078  lua_rawset(L, -3);
3079  }
3080  return 1;
3081 }
3082 
3083 /**
3084  * Adds a modification to a unit.
3085  * - Arg 1: unit.
3086  * - Arg 2: string.
3087  * - Arg 3: WML table.
3088  * - Arg 4: (optional) Whether to add to [modifications] - default true
3089  */
3091 {
3092  unit& u = luaW_checkunit(L, 1);
3093  char const *m = luaL_checkstring(L, 2);
3094  std::string sm = m;
3095  if (sm == "advance") { // Maintain backwards compatibility
3096  sm = "advancement";
3097  deprecated_message("\"advance\" modification type", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Use \"advancement\" instead.");
3098  }
3099  if (sm != "advancement" && sm != "object" && sm != "trait") {
3100  return luaL_argerror(L, 2, "unknown modification type");
3101  }
3102  bool write_to_mods = true;
3103  if (!lua_isnone(L, 4)) {
3104  write_to_mods = luaW_toboolean(L, 4);
3105  }
3106  if(sm.empty()) {
3107  write_to_mods = false;
3108  }
3109 
3110  config cfg = luaW_checkconfig(L, 3);
3111  u.add_modification(sm, cfg, !write_to_mods);
3112  return 0;
3113 }
3114 
3115 /**
3116  * Removes modifications from a unit
3117  * - Arg 1: unit
3118  * - Arg 2: table (filter as [filter_wml])
3119  * - Arg 3: type of modification (default "object")
3120  */
3122 {
3123  unit& u = luaW_checkunit(L, 1);
3124  config filter = luaW_checkconfig(L, 2);
3125  std::string tag = luaL_optstring(L, 3, "object");
3126  //TODO
3127  if(filter.attribute_count() == 1 && filter.all_children_count() == 0 && filter.attribute_range().front().first == "duration") {
3128  u.expire_modifications(filter["duration"]);
3129  } else {
3130  for(config& obj : u.get_modifications().child_range(tag)) {
3131  if(obj.matches(filter)) {
3132  obj["duration"] = "now";
3133  }
3134  }
3135  u.expire_modifications("now");
3136  }
3137  return 0;
3138 }
3139 
3140 /**
3141  * Advances a unit if the unit has enough xp.
3142  * - Arg 1: unit.
3143  * - Arg 2: optional boolean whether to animate the advancement.
3144  * - Arg 3: optional boolean whether to fire advancement events.
3145  */
3147 {
3148  events::command_disabler command_disabler;
3149  unit& u = luaW_checkunit(L, 1, true);
3151  if(lua_isboolean(L, 2)) {
3152  par.animate(luaW_toboolean(L, 2));
3153  }
3154  if(lua_isboolean(L, 3)) {
3155  par.fire_events(luaW_toboolean(L, 3));
3156  }
3157  advance_unit_at(par);
3158  return 0;
3159 }
3160 
3161 
3162 /**
3163  * Adds a new known unit type to the help system.
3164  * - Arg 1: string.
3165  */
3167 {
3168  char const *ty = luaL_checkstring(L, 1);
3169  if(!unit_types.find(ty))
3170  {
3171  std::stringstream ss;
3172  ss << "unknown unit type: '" << ty << "'";
3173  return luaL_argerror(L, 1, ss.str().c_str());
3174  }
3175  preferences::encountered_units().insert(ty);
3176  return 0;
3177 }
3178 
3179 /**
3180  * Adds an overlay on a tile.
3181  * - Arg 1: location.
3182  * - Arg 2: WML table.
3183  */
3185 {
3186  map_location loc = luaW_checklocation(L, 1);
3187  vconfig cfg = luaW_checkvconfig(L, 2);
3188  const vconfig &ssf = cfg.child("filter_team");
3189 
3190  std::string team_name;
3191  if (!ssf.null()) {
3192  const std::vector<int>& teams = side_filter(ssf, &game_state_).get_teams();
3193  std::vector<std::string> team_names;
3194  std::transform(teams.begin(), teams.end(), std::back_inserter(team_names),
3195  [&](int team) { return game_state_.get_disp_context().get_team(team).team_name(); });
3196  team_name = utils::join(team_names);
3197  } else {
3198  team_name = cfg["team_name"].str();
3199  }
3200 
3201  if (game_display_) {
3202  game_display_->add_overlay(loc, cfg["image"], cfg["halo"],
3203  team_name, cfg["name"], cfg["visible_in_fog"].to_bool(true), cfg["z_order"].to_double(0));
3204  }
3205  return 0;
3206 }
3207 
3208 /**
3209  * Removes an overlay from a tile.
3210  * - Arg 1: location.
3211  * - Arg 2: optional string.
3212  */
3214 {
3215  map_location loc = luaW_checklocation(L, 1);
3216  char const *m = lua_tostring(L, 2);
3217 
3218  if (m) {
3219  if (game_display_) {
3220  game_display_->remove_single_overlay(loc, m);
3221  }
3222  } else {
3223  if (game_display_) {
3224  game_display_->remove_overlay(loc);
3225  }
3226  }
3227  return 0;
3228 }
3229 
3231 {
3232  replay& recorder = play_controller_.get_replay();
3233  const int nargs = lua_gettop(L);
3234  if(nargs < 2 || nargs > 3) {
3235  return luaL_error(L, "Wrong number of arguments to ai.log_replay() - should be 2 or 3 arguments.");
3236  }
3237  const std::string key = nargs == 2 ? luaL_checkstring(L, 1) : luaL_checkstring(L, 2);
3238  config cfg;
3239  if(nargs == 2) {
3240  recorder.add_log_data(key, luaL_checkstring(L, 2));
3241  } else if(luaW_toconfig(L, 3, cfg)) {
3242  recorder.add_log_data(luaL_checkstring(L, 1), key, cfg);
3243  } else if(!lua_isstring(L, 3)) {
3244  return luaL_argerror(L, 3, "accepts only string or config");
3245  } else {
3246  recorder.add_log_data(luaL_checkstring(L, 1), key, luaL_checkstring(L, 3));
3247  }
3248  return 0;
3249 }
3250 
3251 /** Adding new events */
3253 {
3254  vconfig cfg(luaW_checkvconfig(L, 1));
3255  game_events::manager & man = *game_state_.events_manager_;
3256 
3257  if (!cfg["delayed_variable_substitution"].to_bool(true)) {
3259  } else {
3260  man.add_event_handler(cfg.get_config());
3261  }
3262  return 0;
3263 }
3264 
3266 {
3267  game_state_.events_manager_->remove_event_handler(luaL_checkstring(L, 1));
3268  return 0;
3269 }
3270 
3272 {
3273  if (game_display_) {
3274  vconfig cfg(luaW_checkvconfig(L, 1));
3275 
3276  game_display_->adjust_color_overlay(cfg["red"], cfg["green"], cfg["blue"]);
3277  game_display_->invalidate_all();
3278  game_display_->draw(true,true);
3279  }
3280  return 0;
3281 }
3282 
3283 /**
3284  * Delays engine for a while.
3285  * - Arg 1: integer.
3286  * - Arg 2: boolean (optional).
3287  */
3289 {
3290  if(gamedata().phase() == game_data::PRELOAD || gamedata().phase() == game_data::PRESTART || gamedata().phase() == game_data::INITIAL) {
3291  //don't call play_slice if the game ui is not active yet.
3292  return 0;
3293  }
3294  events::command_disabler command_disabler;
3295  lua_Integer delay = luaL_checkinteger(L, 1);
3296  if(delay == 0) {
3297  play_controller_.play_slice(false);
3298  return 0;
3299  }
3300  if(luaW_toboolean(L, 2) && game_display_ && game_display_->turbo_speed() > 0) {
3301  delay /= game_display_->turbo_speed();
3302  }
3303  const unsigned final = SDL_GetTicks() + delay;
3304  do {
3305  play_controller_.play_slice(false);
3306  CVideo::delay(10);
3307  } while (static_cast<int>(final - SDL_GetTicks()) > 0);
3308  return 0;
3309 }
3310 
3312 {
3313  if (game_display_) {
3314  vconfig cfg(luaW_checkvconfig(L, 1));
3315 
3316  game_display &screen = *game_display_;
3317 
3318  terrain_label label(screen.labels(), cfg.get_config());
3319 
3320  screen.labels().set_label(label.location(), add ? label.text() : "", label.creator(), label.team_name(), label.color(),
3321  label.visible_in_fog(), label.visible_in_shroud(), label.immutable(), label.category(), label.tooltip());
3322  }
3323  return 0;
3324 }
3325 
3327 {
3328  if(game_display_) {
3329  game_display &screen = *game_display_;
3330  auto loc = luaW_checklocation(L, 1);
3331  const terrain_label* label = nullptr;
3332  switch(lua_type(L, 2)) {
3333  // Missing 2nd argument - get global label
3334  case LUA_TNONE: case LUA_TNIL:
3335  label = screen.labels().get_label(loc, "");
3336  break;
3337  // Side number - get label belonging to that side's team
3338  case LUA_TNUMBER:
3339  if(size_t n = luaL_checkinteger(L, 2); n > 0 && n <= teams().size()) {
3340  label = screen.labels().get_label(loc, teams().at(n - 1).team_name());
3341  }
3342  break;
3343  // String - get label belonging to the team with that name
3344  case LUA_TSTRING:
3345  label = screen.labels().get_label(loc, luaL_checkstring(L, 2));
3346  break;
3347  // Side userdata - get label belonging to that side's team
3348  case LUA_TUSERDATA:
3349  label = screen.labels().get_label(loc, luaW_checkteam(L, 2).team_name());
3350  break;
3351  }
3352  if(label) {
3353  config cfg;
3354  label->write(cfg);
3355  luaW_pushconfig(L, cfg);
3356  return 1;
3357  }
3358  }
3359  return 0;
3360 }
3361 
3363 {
3364  if (game_display_) {
3365  game_display & screen = *game_display_;
3366 
3367  vconfig cfg(luaW_checkvconfig(L, 1));
3368  bool clear_shroud(luaW_toboolean(L, 2));
3369 
3370  // We do this twice so any applicable redraws happen both before and after
3371  // any events caused by redrawing shroud are fired
3372  bool result = screen.maybe_rebuild();
3373  if (!result) {
3374  screen.invalidate_all();
3375  }
3376 
3377  if (clear_shroud) {
3378  side_filter filter(cfg, &game_state_);
3379  for (const int side : filter.get_teams()){
3380  actions::clear_shroud(side);
3381  }
3382  screen.recalculate_minimap();
3383  }
3384 
3385  result = screen.maybe_rebuild();
3386  if (!result) {
3387  screen.invalidate_all();
3388  }
3389 
3390  screen.draw(true,true);
3391  }
3392  return 0;
3393 }
3394 
3395 /**
3396  * Lua frontend to the modify_ai functionality
3397  * - Arg 1: config.
3398  */
3400 {
3401  config cfg;
3402  luaW_toconfig(L, 1, cfg);
3403  int side = cfg["side"];
3404  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.");
3406  return 0;
3407 }
3408 
3410 {
3411  bool exec = luaW_toboolean(L, -1);
3412  lua_pop(L, 1);
3413 
3414  lua_getfield(L, -1, "ca_ptr");
3415 
3416  ai::candidate_action *ca = static_cast<ai::candidate_action*>(lua_touserdata(L, -1));
3417  lua_pop(L, 2);
3418  if (exec) {
3419  ca->execute();
3420  return 0;
3421  }
3422  lua_pushinteger(L, ca->evaluate());
3423  return 1;
3424 }
3425 
3427 {
3428  lua_getfield(L, -1, "stg_ptr");
3429  ai::stage *stg = static_cast<ai::stage*>(lua_touserdata(L, -1));
3430  lua_pop(L, 2);
3431  stg->play_stage();
3432  return 0;
3433 }
3434 
3435 static void push_component(lua_State *L, ai::component* c, const std::string &ct = "")
3436 {
3437  lua_createtable(L, 0, 0); // Table for a component
3438 
3439  lua_pushstring(L, "name");
3440  lua_pushstring(L, c->get_name().c_str());
3441  lua_rawset(L, -3);
3442 
3443  lua_pushstring(L, "engine");
3444  lua_pushstring(L, c->get_engine().c_str());
3445  lua_rawset(L, -3);
3446 
3447  lua_pushstring(L, "id");
3448  lua_pushstring(L, c->get_id().c_str());
3449  lua_rawset(L, -3);
3450 
3451  if (ct == "candidate_action") {
3452  lua_pushstring(L, "ca_ptr");
3453  lua_pushlightuserdata(L, c);
3454  lua_rawset(L, -3);
3455 
3456  lua_pushstring(L, "exec");
3458  lua_rawset(L, -3);
3459  }
3460 
3461  if (ct == "stage") {
3462  lua_pushstring(L, "stg_ptr");
3463  lua_pushlightuserdata(L, c);
3464  lua_rawset(L, -3);
3465 
3466  lua_pushstring(L, "exec");
3468  lua_rawset(L, -3);
3469  }
3470 
3471 
3472  std::vector<std::string> c_types = c->get_children_types();
3473 
3474  for (std::vector<std::string>::const_iterator t = c_types.begin(); t != c_types.end(); ++t)
3475  {
3476  std::vector<ai::component*> children = c->get_children(*t);
3477  std::string type = *t;
3478  if (type == "aspect" || type == "goal" || type == "engine")
3479  {
3480  continue;
3481  }
3482 
3483  lua_pushstring(L, type.c_str());
3484  lua_createtable(L, 0, 0); // this table will be on top of the stack during recursive calls
3485 
3486  for (std::vector<ai::component*>::const_iterator i = children.begin(); i != children.end(); ++i)
3487  {
3488  lua_pushstring(L, (*i)->get_name().c_str());
3489  push_component(L, *i, type);
3490  lua_rawset(L, -3);
3491 
3492  //if (type == "candidate_action")
3493  //{
3494  // ai::candidate_action *ca = dynamic_cast<ai::candidate_action*>(*i);
3495  // ca->execute();
3496  //}
3497  }
3498 
3499  lua_rawset(L, -3); // setting the child table
3500  }
3501 
3502 
3503 }
3504 
3505 /**
3506  * Debug access to the ai tables
3507  * - Arg 1: int
3508  * - Ret 1: ai table
3509  */
3510 static int intf_debug_ai(lua_State *L)
3511 {
3512  if (!game_config::debug) { // This function works in debug mode only
3513  return 0;
3514  }
3515  int side;
3516  if(team* t = luaW_toteam(L, 1)) {
3517  side = t->side();
3518  } else {
3519  side = luaL_checkinteger(L, 1);
3520  }
3521  lua_pop(L, 1);
3522 
3524 
3525  // Bad, but works
3526  std::vector<ai::component*> engines = c->get_children("engine");
3527  ai::engine_lua* lua_engine = nullptr;
3528  for (std::vector<ai::component*>::const_iterator i = engines.begin(); i != engines.end(); ++i)
3529  {
3530  if ((*i)->get_name() == "lua")
3531  {
3532  lua_engine = dynamic_cast<ai::engine_lua *>(*i);
3533  }
3534  }
3535 
3536  // Better way, but doesn't work
3537  //ai::component* e = ai::manager::get_singleton().get_active_ai_holder_for_side_dbg(side).get_component(c, "engine[lua]");
3538  //ai::engine_lua* lua_engine = dynamic_cast<ai::engine_lua *>(e);
3539 
3540  if (lua_engine == nullptr)
3541  {
3542  //no lua engine is defined for this side.
3543  //so set up a dummy engine
3544 
3545  ai::ai_composite * ai_ptr = dynamic_cast<ai::ai_composite *>(c);
3546 
3547  assert(ai_ptr);
3548 
3549  ai::ai_context& ai_context = ai_ptr->get_ai_context();
3551 
3552  lua_engine = new ai::engine_lua(ai_context, cfg);
3553  LOG_LUA << "Created new dummy lua-engine for debug_ai(). \n";
3554 
3555  //and add the dummy engine as a component
3556  //to the manager, so we could use it later
3557  cfg.add_child("engine", lua_engine->to_config());
3558  ai::component_manager::add_component(c, "engine[]", cfg);
3559  }
3560 
3561  lua_engine->push_ai_table(); // stack: [-1: ai_context]
3562 
3563  lua_pushstring(L, "components");
3564  push_component(L, c); // stack: [-1: component tree; -2: ai context]
3565  lua_rawset(L, -3);
3566 
3567  return 1;
3568 }
3569 
3570 /** Allow undo sets the flag saying whether the event has mutated the game to false. */
3572 {
3573  bool allow;
3574  t_string reason;
3575  // The extra iststring is required to prevent totstring from converting a bool value
3576  if(luaW_iststring(L, 1) && luaW_totstring(L, 1, reason)) {
3577  allow = false;
3578  } else {
3579  allow = luaW_toboolean(L, 1);
3580  luaW_totstring(L, 2, reason);
3581  }
3582  gamedata().set_allow_end_turn(allow, reason);
3583  return 0;
3584 }
3585 
3586 /** Allow undo sets the flag saying whether the event has mutated the game to false. */
3588 {
3589  if(lua_isboolean(L, 1)) {
3590  play_controller_.pump().set_undo_disabled(!luaW_toboolean(L, 1));
3591  }
3592  else {
3593  play_controller_.pump().set_undo_disabled(false);
3594  }
3595  return 0;
3596 }
3597 
3599 {
3600  play_controller_.pump().set_action_canceled();
3601  return 0;
3602 }
3603 
3604 /** Adding new time_areas dynamically with Standard Location Filters. */
3606 {
3607  log_scope("time_area");
3608 
3609  vconfig cfg(luaW_checkvconfig(L, 1));
3610  const std::string id = cfg["id"];
3611 
3612  std::set<map_location> locs;
3613  const terrain_filter filter(cfg, &game_state_, false);
3614  filter.get_locations(locs, true);
3615  config parsed_cfg = cfg.get_parsed_config();
3616  tod_man().add_time_area(id, locs, parsed_cfg);
3617  LOG_LUA << "Lua inserted time_area '" << id << "'\n";
3618  return 0;
3619 }
3620 
3621 /** Removing new time_areas dynamically with Standard Location Filters. */
3623 {
3624  log_scope("remove_time_area");
3625 
3626  const char * id = luaL_checkstring(L, 1);
3627  tod_man().remove_time_area(id);
3628  LOG_LUA << "Lua removed time_area '" << id << "'\n";
3629 
3630  return 0;
3631 }
3632 
3633 /** Replacing the current time of day schedule. */
3635 {
3636  vconfig cfg = luaW_checkvconfig(L, 1);
3637 
3638  if(cfg.get_children("time").empty()) {
3639  ERR_LUA << "attempted to to replace ToD schedule with empty schedule" << std::endl;
3640  } else {
3641  tod_man().replace_schedule(cfg.get_parsed_config());
3642  if (game_display_) {
3643  game_display_->new_turn();
3644  }
3645  LOG_LUA << "replaced ToD schedule\n";
3646  }
3647  return 0;
3648 }
3649 
3651 {
3652  if(!game_display_) {
3653  return 0;
3654  }
3655  std::string area_id;
3656  std::size_t area_i = 0;
3657  if (lua_isstring(L, 2)) {
3658  area_id = lua_tostring(L, 1);
3659  std::vector<std::string> area_ids = tod_man().get_area_ids();
3660  area_i = std::distance(area_ids.begin(), std::find(area_ids.begin(), area_ids.end(), area_id));
3661  if(area_i >= area_ids.size()) {
3662  return luaL_argerror(L, 1, "invalid time area ID");
3663  }
3664  }
3665  int is_num = false;
3666  int new_time = lua_tonumberx(L, 1, &is_num) - 1;
3667  const std::vector<time_of_day>& times = area_id.empty()
3668  ? tod_man().times()
3669  : tod_man().times(area_i);
3670  int num_times = times.size();
3671  if(!is_num) {
3672  std::string time_id = luaL_checkstring(L, 1);
3673  new_time = 0;
3674  for(const time_of_day& time : times) {
3675  if(time_id == time.id) {
3676  break;
3677  }
3678  new_time++;
3679  }
3680  if(new_time >= num_times) {
3681  return luaL_argerror(L, 1, "invalid time of day ID");
3682  }
3683  }
3684 
3685  if(new_time == 0 && num_times == 0) {
3686  //ignore this case, because we don't want code like set_current_time(get_current_time()) to fail if num_times is 0.
3687  return 0;
3688  }
3689  if(new_time < 0 || new_time >= num_times) {
3690  return luaL_argerror(L, 1, "invalid time of day index");
3691  }
3692 
3693  if(area_id.empty()) {
3694  tod_man().set_current_time(new_time);
3695  } else {
3696  tod_man().set_current_time(new_time, area_i);
3697  }
3698  return 0;
3699 }
3700 
3702 {
3703  int x = luaL_checkinteger(L, 1), y = luaL_checkinteger(L, 2);
3704 
3705  if (game_display_) {
3706  game_display_->scroll(x, y, true);
3707  game_display_->draw(true, true);
3708  }
3709 
3710  return 0;
3711 }
3712 
3713 namespace {
3714  struct lua_report_generator : reports::generator
3715  {
3716  lua_State *mState;
3717  std::string name;
3718  lua_report_generator(lua_State *L, const std::string &n)
3719  : mState(L), name(n) {}
3720  virtual config generate(reports::context & rc);
3721  };
3722 
3723  config lua_report_generator::generate(reports::context & /*rc*/)
3724  {
3725  lua_State *L = mState;
3726  config cfg;
3727  if (!luaW_getglobal(L, "wesnoth", "interface", "game_display", name))
3728  return cfg;
3729  if (!luaW_pcall(L, 0, 1)) return cfg;
3730  luaW_toconfig(L, -1, cfg);
3731  lua_pop(L, 1);
3732  return cfg;
3733  }
3734 }//unnamed namespace for lua_report_generator
3735 
3736 /**
3737  * Executes its upvalue as a theme item generator.
3738  */
3740 {
3741  reports::context temp_context = reports::context(board(), *game_display_, tod_man(), play_controller_.get_whiteboard(), play_controller_.get_mouse_handler_base());
3742  luaW_pushconfig(L, reports_.generate_report(m.c_str(), temp_context , true));
3743  return 1;
3744 }
3745 
3746 /**
3747  * Creates a field of the theme_items table and returns it (__index metamethod).
3748  */
3750 {
3751  char const *m = luaL_checkstring(L, 2);
3752  lua_cpp::push_closure(L, std::bind(&game_lua_kernel::impl_theme_item, this, std::placeholders::_1, std::string(m)), 0);
3753  lua_pushvalue(L, 2);
3754  lua_pushvalue(L, -2);
3755  lua_rawset(L, 1);
3756  reports_.register_generator(m, new lua_report_generator(L, m));
3757  return 1;
3758 }
3759 
3760 /**
3761  * Sets a field of the theme_items table (__newindex metamethod).
3762  */
3764 {
3765  char const *m = luaL_checkstring(L, 2);
3766  lua_pushvalue(L, 2);
3767  lua_pushvalue(L, 3);
3768  lua_rawset(L, 1);
3769  reports_.register_generator(m, new lua_report_generator(L, m));
3770  return 0;
3771 }
3772 
3773 /**
3774  * Gets all the WML variables currently set.
3775  * - Ret 1: WML table
3776  */
3778  luaW_pushconfig(L, gamedata().get_variables());
3779  return 1;
3780 }
3781 
3782 /**
3783  * Teeleports a unit to a location.
3784  * Arg 1: unit
3785  * Arg 2: target location
3786  * Arg 3: bool (ignore_passability)
3787  * Arg 4: bool (clear_shroud)
3788  * Arg 5: bool (animate)
3789  */
3791 {
3792  events::command_disabler command_disabler;
3793  unit_ptr u = luaW_checkunit_ptr(L, 1, true);
3794  map_location dst = luaW_checklocation(L, 2);
3795  bool check_passability = !luaW_toboolean(L, 3);
3796  bool clear_shroud = luaW_toboolean(L, 4);
3797  bool animate = luaW_toboolean(L, 5);
3798 
3799  if (dst == u->get_location() || !map().on_board(dst)) {
3800  return 0;
3801  }
3802  const map_location vacant_dst = find_vacant_tile(dst, pathfind::VACANT_ANY, check_passability ? u.get() : nullptr);
3803  if (!map().on_board(vacant_dst)) {
3804  return 0;
3805  }
3806  // Clear the destination hex before the move (so the animation can be seen).
3807  actions::shroud_clearer clearer;
3808  if ( clear_shroud ) {
3809  clearer.clear_dest(vacant_dst, *u);
3810  }
3811 
3812  map_location src_loc = u->get_location();
3813 
3814  std::vector<map_location> teleport_path;
3815  teleport_path.push_back(src_loc);
3816  teleport_path.push_back(vacant_dst);
3817  unit_display::move_unit(teleport_path, u, animate);
3818 
3819  units().move(src_loc, vacant_dst);
3821 
3822  u = units().find(vacant_dst).get_shared_ptr();
3823  u->anim_comp().set_standing();
3824 
3825  if ( clear_shroud ) {
3826  // Now that the unit is visibly in position, clear the shroud.
3827  clearer.clear_unit(vacant_dst, *u);
3828  }
3829 
3830  if (map().is_village(vacant_dst)) {
3831  actions::get_village(vacant_dst, u->side());
3832  }
3833 
3834  game_display_->invalidate_unit_after_move(src_loc, vacant_dst);
3835  game_display_->draw();
3836 
3837  // Sighted events.
3838  clearer.fire_events();
3839  return 0;
3840 }
3841 
3842 /**
3843  * Removes a sound source by its ID
3844  * Arg 1: sound source ID
3845  */
3847 {
3848  soundsource::manager* man = play_controller_.get_soundsource_man();
3849  std::string id = luaL_checkstring(L, 1);
3850  man->remove(id);
3851  return 0;
3852 }
3853 
3854 /**
3855  * Add a new sound source
3856  * Arg 1: Table containing keyword arguments
3857  */
3859 {
3860  soundsource::manager* man = play_controller_.get_soundsource_man();
3861  config cfg = luaW_checkconfig(L, 1);
3862  try {
3863  soundsource::sourcespec spec(cfg);
3864  man->add(spec);
3865  man->update();
3866  } catch (const bad_lexical_cast &) {
3867  ERR_LUA << "Error when parsing sound_source config: invalid parameter." << std::endl;
3868  ERR_LUA << "sound_source config was: " << cfg.debug() << std::endl;
3869  ERR_LUA << "Skipping this sound source..." << std::endl;
3870  }
3871  return 0;
3872 }
3873 
3874 /**
3875  * Get an existing sound source
3876  * Arg 1: The sound source ID
3877  * Return: Config of sound source info, or nil if it didn't exist
3878  * This is a copy of the sound source info, so you need to call
3879  * add_sound_source again after changing it.
3880  */
3882 {
3883  soundsource::manager* man = play_controller_.get_soundsource_man();
3884  std::string id = luaL_checkstring(L, 1);
3885  config cfg = man->get(id);
3886  if(cfg.empty()) {
3887  return 0;
3888  }
3889  // Sound sources do not know their own string ID
3890  // Thus, we need to add this manually
3891  cfg["id"] = id;
3892  luaW_pushconfig(L, cfg);
3893  return 1;
3894 }
3895 
3896 /**
3897  * Logs a message
3898  * Arg 1: (optional) Logger; "wml" for WML errors or deprecations
3899  * Arg 2: Message
3900  * Arg 3: Whether to print to chat (always true if arg 1 is "wml")
3901  */
3903 {
3904  const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) : "";
3905  const std::string& msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1);
3906 
3907  if(logger == "wml" || logger == "WML") {
3908  lg::wml_error() << msg << '\n';
3909  } else {
3910  bool in_chat = luaW_toboolean(L, -1);
3911  game_state_.events_manager_->pump().put_wml_message(logger,msg,in_chat);
3912  }
3913  return 0;
3914 }
3915 
3917 {
3918  int side = luaL_checknumber(L, 1);
3919  map_location loc = luaW_checklocation(L, 2);
3920  if(side < 1 || static_cast<std::size_t>(side) > teams().size()) {
3921  std::string error = "side " + std::to_string(side) + " does not exist";
3922  return luaL_argerror(L, 1, error.c_str());
3923  }
3924 
3925  team& t = board().get_team(side);
3926  lua_pushboolean(L, fog ? t.fogged(loc) : t.shrouded(loc));
3927  return 1;
3928 }
3929 
3930 /**
3931  * Implements the lifting and resetting of fog via WML.
3932  * Keeping affect_normal_fog as false causes only the fog override to be affected.
3933  * Otherwise, fog lifting will be implemented similar to normal sight (cannot be
3934  * individually reset and ends at the end of the turn), and fog resetting will, in
3935  * addition to removing overrides, extend the specified teams' normal fog to all
3936  * hexes.
3937  *
3938  * Arg 1: (optional) Side number, or list of side numbers
3939  * Arg 2: List of locations; each is a two-element array or a table with x and y keys
3940  * Arg 3: (optional) boolean
3941  */
3943 {
3944  bool affect_normal_fog = false;
3945  if(lua_isboolean(L, -1)) {
3946  affect_normal_fog = luaW_toboolean(L, -1);
3947  }
3948  std::set<int> sides;
3949  if(lua_isnumber(L, 1)) {
3950  sides.insert(lua_tonumber(L, 1));
3951  } else if(lua_istable(L, 1) && lua_istable(L, 2)) {
3952  const auto& v = lua_check<std::vector<int>>(L, 1);
3953  sides.insert(v.begin(), v.end());
3954  } else {
3955  for(const team& t : teams()) {
3956  sides.insert(t.side()+1);
3957  }
3958  }
3959  const auto& v_locs = lua_check<std::vector<map_location>>(L, lua_istable(L, 2) ? 2 : 1);
3960  std::set<map_location> locs(v_locs.begin(), v_locs.end());
3961 
3962  for(const int &side_num : sides) {
3963  if(side_num < 1 || static_cast<std::size_t>(side_num) > teams().size()) {
3964  continue;
3965  }
3966  team &t = board().get_team(side_num);
3967  if(!clear) {
3968  // Extend fog.
3969  t.remove_fog_override(locs);
3970  if(affect_normal_fog) {
3971  t.refog();
3972  }
3973  } else if(!affect_normal_fog) {
3974  // Force the locations clear of fog.
3975  t.add_fog_override(locs);
3976  } else {
3977  // Simply clear fog from the locations.
3978  for(const map_location &hex : locs) {
3979  t.clear_fog(hex);
3980  }
3981  }
3982  }
3983 
3984  // Flag a screen update.
3985  game_display_->recalculate_minimap();
3986  game_display_->invalidate_all();
3987  return 0;
3988 }
3989 
3990 // Invokes a synced command
3992 {
3993  const std::string name = luaL_checkstring(L, 1);
3994  auto it = synced_command::registry().find(name);
3995  config cmd;
3996  if(it == synced_command::registry().end()) {
3997  // Custom command
3998  if(!luaW_getglobal(L, "wesnoth", "custom_synced_commands", name)) {
3999  return luaL_argerror(L, 1, "Unknown synced command");
4000  }
4001  config& cmd_tag = cmd.child_or_add("custom_command");
4002  cmd_tag["name"] = name;
4003  if(!lua_isnoneornil(L, 2)) {
4004  cmd_tag.add_child("data", luaW_checkconfig(L, 2));
4005  }
4006  } else {
4007  // Built-in command
4008  cmd.add_child(name, luaW_checkconfig(L, 2));
4009  }
4010  // Now just forward to the WML action.
4011  luaW_getglobal(L, "wesnoth", "wml_actions", "do_command");
4012  luaW_pushconfig(L, cmd);
4013  luaW_pcall(L, 1, 0);
4014  return 0;
4015 }
4016 
4017 // END CALLBACK IMPLEMENTATION
4018 
4020  return game_state_.board_;
4021 }
4022 
4024  return game_state_.board_.units();
4025 }
4026 
4027 std::vector<team> & game_lua_kernel::teams() {
4028  return game_state_.board_.teams();
4029 }
4030 
4032  return game_state_.board_.map();
4033 }
4034 
4036  return game_state_.gamedata_;
4037 }
4038 
4040  return game_state_.tod_manager_;
4041 }
4042 
4044  return *queued_events_.top();
4045 }
4046 
4047 
4049  : lua_kernel_base()
4050  , game_display_(nullptr)
4051  , game_state_(gs)
4052  , play_controller_(pc)
4053  , reports_(reports_object)
4054  , level_lua_()
4055  , queued_events_()
4056  , map_locked_(0)
4057 {
4058  static game_events::queued_event default_queued_event("_from_lua", "", map_location(), map_location(), config());
4059  queued_events_.push(&default_queued_event);
4060 
4061  lua_State *L = mState;
4062 
4063  cmd_log_ << "Registering game-specific wesnoth lib functions...\n";
4064 
4065  // Put some callback functions in the scripting environment.
4066  static luaL_Reg const callbacks[] {
4067  { "add_known_unit", &intf_add_known_unit },
4068  { "create_animator", &dispatch<&game_lua_kernel::intf_create_animator> },
4069  { "eval_conditional", &intf_eval_conditional },
4070  { "get_era", &intf_get_era },
4071  { "get_resource", &intf_get_resource },
4072  { "get_traits", &intf_get_traits },
4073  { "get_viewing_side", &intf_get_viewing_side },
4074  { "invoke_synced_command", &intf_invoke_synced_command },
4075  { "modify_ai", &intf_modify_ai_old },
4076  { "set_music", &intf_set_music },
4077  { "sound_volume", &intf_sound_volume },
4078  { "unsynced", &intf_do_unsynced },
4079  { "add_event_handler", &dispatch<&game_lua_kernel::intf_add_event > },
4080  { "add_sound_source", &dispatch<&game_lua_kernel::intf_add_sound_source > },
4081  { "allow_end_turn", &dispatch<&game_lua_kernel::intf_allow_end_turn > },
4082  { "allow_undo", &dispatch<&game_lua_kernel::intf_allow_undo > },
4083  { "cancel_action", &dispatch<&game_lua_kernel::intf_cancel_action > },
4084  { "clear_messages", &dispatch<&game_lua_kernel::intf_clear_messages > },
4085  { "end_turn", &dispatch<&game_lua_kernel::intf_end_turn > },
4086  { "end_level", &dispatch<&game_lua_kernel::intf_end_level > },
4087  { "find_cost_map", &dispatch<&game_lua_kernel::intf_find_cost_map > },
4088  { "find_path", &dispatch<&game_lua_kernel::intf_find_path > },
4089  { "find_reach", &dispatch<&game_lua_kernel::intf_find_reach > },
4090  { "find_vacant_tile", &dispatch<&game_lua_kernel::intf_find_vacant_tile > },
4091  { "find_vision_range", &dispatch<&game_lua_kernel::intf_find_vision_range > },
4092  { "fire_event", &dispatch2<&game_lua_kernel::intf_fire_event, false > },
4093  { "fire_event_by_id", &dispatch2<&game_lua_kernel::intf_fire_event, true > },
4094  { "get_all_vars", &dispatch<&game_lua_kernel::intf_get_all_vars > },
4095  { "get_end_level_data", &dispatch<&game_lua_kernel::intf_get_end_level_data > },
4096  { "get_sound_source", &dispatch<&game_lua_kernel::intf_get_sound_source > },
4097  { "get_time_of_day", &dispatch<&game_lua_kernel::intf_get_time_of_day > },
4098  { "get_max_liminal_bonus", &dispatch<&game_lua_kernel::intf_get_max_liminal_bonus > },
4099  { "get_variable", &dispatch<&game_lua_kernel::intf_get_variable > },
4100  { "log_replay", &dispatch<&game_lua_kernel::intf_log_replay > },
4101  { "log", &dispatch<&game_lua_kernel::intf_log > },
4102  { "message", &dispatch<&game_lua_kernel::intf_message > },
4103  { "open_help", &dispatch<&game_lua_kernel::intf_open_help > },
4104  { "play_sound", &dispatch<&game_lua_kernel::intf_play_sound > },
4105  { "print", &dispatch<&game_lua_kernel::intf_print > },
4106  { "redraw", &dispatch<&game_lua_kernel::intf_redraw > },
4107  { "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > },
4108  { "remove_sound_source", &dispatch<&game_lua_kernel::intf_remove_sound_source > },
4109  { "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > },
4110  { "select_hex", &dispatch<&game_lua_kernel::intf_select_hex > },
4111  { "set_time_of_day", &dispatch<&game_lua_kernel::intf_set_time_of_day > },
4112  { "set_end_campaign_credits", &dispatch<&game_lua_kernel::intf_set_end_campaign_credits > },
4113  { "set_end_campaign_text", &dispatch<&game_lua_kernel::intf_set_end_campaign_text > },
4114  { "create_side", &dispatch<&game_lua_kernel::intf_create_side > },
4115  { "set_next_scenario", &dispatch<&game_lua_kernel::intf_set_next_scenario > },
4116  { "set_variable", &dispatch<&game_lua_kernel::intf_set_variable > },
4117  { "simulate_combat", &dispatch<&game_lua_kernel::intf_simulate_combat > },
4118  { "synchronize_choice", &intf_synchronize_choice },
4119  { "synchronize_choices", &intf_synchronize_choices },
4120  { "teleport", &dispatch<&game_lua_kernel::intf_teleport > },
4121  { nullptr, nullptr }
4122  };lua_getglobal(L, "wesnoth");
4123  if (!lua_istable(L,-1)) {
4124  lua_newtable(L);
4125  }
4126  luaL_setfuncs(L, callbacks, 0);
4127 
4128  lua_setglobal(L, "wesnoth");
4129 
4130  lua_getglobal(L, "gui");
4131  lua_pushcfunction(L, &dispatch<&game_lua_kernel::intf_gamestate_inspector>);
4132  lua_setfield(L, -2, "show_inspector");
4133  lua_pop(L, 1);
4134 
4136  // Create the unit_test module
4137  lua_newtable(L);
4138  static luaL_Reg const test_callbacks[] {
4139  { "fire_wml_menu_item", &dispatch<&game_lua_kernel::intf_fire_wml_menu_item> },
4140  { nullptr, nullptr }
4141  };
4142  luaL_setfuncs(L, test_callbacks, 0);
4143  lua_setglobal(L, "unit_test");
4144  }
4145 
4146  // Create the getside metatable.
4148 
4149  // Create the gettype metatable.
4151 
4152  //Create the getrace metatable
4154 
4155  //Create the unit metatables
4158 
4159  // Create the vconfig metatable.
4161 
4162  // Create the unit_types table
4164 
4165  // Create the unit_types table
4167 
4168  // Create the unit_types table
4169  cmd_log_ << "Adding terrain_types table...\n";
4170  lua_getglobal(L, "wesnoth");
4171  lua_newuserdatauv(L, 0, 0);
4172  lua_createtable(L, 0, 2);
4173  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_get_terrain_info>);
4174  lua_setfield(L, -2, "__index");
4175  lua_pushstring(L, "terrain types");
4176  lua_setfield(L, -2, "__metatable");
4177  lua_setmetatable(L, -2);
4178  lua_setfield(L, -2, "terrain_types");
4179  lua_pop(L, 1);
4180 
4181  // Create the ai elements table.
4182  cmd_log_ << "Adding ai elements table...\n";
4183 
4185 
4186  // Create the current variable with its metatable.
4187  cmd_log_ << "Adding wesnoth current table...\n";
4188 
4189  lua_getglobal(L, "wesnoth");
4190  lua_newuserdatauv(L, 0, 0);
4191  lua_createtable(L, 0, 2);
4192  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_current_get>);
4193  lua_setfield(L, -2, "__index");
4194  lua_pushstring(L, "current config");
4195  lua_setfield(L, -2, "__metatable");
4196  lua_setmetatable(L, -2);
4197  lua_setfield(L, -2, "current");
4198  lua_pop(L, 1);
4199 
4200  // Add tovconfig to the WML module
4201  lua_getglobal(L, "wml");
4203  lua_setfield(L, -2, "tovconfig");
4204  lua_pop(L, 1);
4205 
4206  // Add functions to the map module
4207  luaW_getglobal(L, "wesnoth", "map");
4208  static luaL_Reg const map_callbacks[] {
4209  // Map methods
4210  {"terrain_mask", &intf_terrain_mask},
4211  {"on_board", &intf_on_board},
4212  {"on_border", &intf_on_border},
4213  {"iter", &intf_terrainmap_iter},
4214  // Shroud operations
4215  {"place_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, true>},
4216  {"remove_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, false>},
4217  {"is_shrouded", &dispatch2<&game_lua_kernel::intf_get_fog_or_shroud, false>},
4218  // Fog operations
4219  {"place_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, false>},
4220  {"remove_fog", &dispatch2<&game_lua_kernel::intf_toggle_fog, true>},
4221  {"is_fogged", &dispatch2<&game_lua_kernel::intf_get_fog_or_shroud, true>},
4222  // Village operations
4223  {"get_owner", &dispatch<&game_lua_kernel::intf_get_village_owner>},
4224  {"set_owner", &dispatch<&game_lua_kernel::intf_set_village_owner>},
4225  // Label operations
4226  {"add_label", &dispatch2<&game_lua_kernel::intf_label, true>},
4227  {"remove_label", &dispatch2<&game_lua_kernel::intf_label, false>},
4228  {"get_label", &dispatch<&game_lua_kernel::intf_get_label>},
4229  // Time area operations
4230  {"place_area", &dispatch<&game_lua_kernel::intf_add_time_area>},
4231  {"remove_area", &dispatch<&game_lua_kernel::intf_remove_time_area>},
4232  // Filters
4233  {"find", &dispatch<&game_lua_kernel::intf_get_locations>},
4234  {"matches", &dispatch<&game_lua_kernel::intf_match_location>},
4235  {"replace_if_failed", intf_replace_if_failed},
4236  { nullptr, nullptr }
4237  };
4238  luaL_setfuncs(L, map_callbacks, 0);
4239  lua_pop(L, 1);
4240 
4241  // Create the units module
4242  cmd_log_ << "Adding units module...\n";
4243  static luaL_Reg const unit_callbacks[] {
4244  {"advance", &intf_advance_unit},
4245  {"clone", &intf_copy_unit},
4246  {"erase", &dispatch<&game_lua_kernel::intf_erase_unit>},
4247  {"extract", &dispatch<&game_lua_kernel::intf_extract_unit>},
4248  {"matches", &dispatch<&game_lua_kernel::intf_match_unit>},
4249  {"select", &dispatch<&game_lua_kernel::intf_select_unit>},
4250  {"to_map", &dispatch<&game_lua_kernel::intf_put_unit>},
4251  {"to_recall", &dispatch<&game_lua_kernel::intf_put_recall_unit>},
4252  {"transform", &intf_transform_unit},
4253 
4254  {"ability", &dispatch<&game_lua_kernel::intf_unit_ability>},
4255  {"defense_on", &intf_unit_defense},
4256  {"jamming_on", &intf_unit_jamming_cost},
4257  {"movement_on", &intf_unit_movement_cost},
4258  {"resistance_against", intf_unit_resistance},
4259  {"vision_on", &intf_unit_vision_cost},
4260 
4261  {"add_modification", &intf_add_modification},
4262  {"remove_modifications", &intf_remove_modifications},
4263  // Static functions
4264  {"create", &intf_create_unit},
4265  {"find_on_map", &dispatch<&game_lua_kernel::intf_get_units>},
4266  {"find_on_recall", &dispatch<&game_lua_kernel::intf_get_recall_units>},
4267  {"get", &dispatch<&game_lua_kernel::intf_get_unit>},
4268  {"get_hovered", &dispatch<&game_lua_kernel::intf_get_displayed_unit>},
4269  { nullptr, nullptr }
4270  };
4271  lua_getglobal(L, "wesnoth");
4272  lua_newtable(L);
4273  luaL_setfuncs(L, unit_callbacks, 0);
4274  lua_setfield(L, -2, "units");
4275  lua_pop(L, 1);
4276 
4277  // Create sides module
4278  cmd_log_ << "Adding sides module...\n";
4279  static luaL_Reg const side_callbacks[] {
4280  { "is_enemy", &dispatch<&game_lua_kernel::intf_is_enemy> },
4281  { "matches", &dispatch<&game_lua_kernel::intf_match_side> },
4282  { "set_id", &dispatch<&game_lua_kernel::intf_set_side_id> },
4283  { "append_ai", &intf_append_ai },
4284  { "debug_ai", &intf_debug_ai },
4285  { "switch_ai", &intf_switch_ai },
4286  // Static functions
4287  { "find", &dispatch<&game_lua_kernel::intf_get_sides> },
4288  { "get", &dispatch<&game_lua_kernel::intf_get_side> },
4289  { nullptr, nullptr }
4290  };
4291  std::vector<lua_cpp::Reg> const cpp_side_callbacks {
4292  {"add_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "add")},
4293  {"delete_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "delete")},
4294  {"change_ai_component", std::bind(intf_modify_ai, std::placeholders::_1, "change")},
4295  {nullptr, nullptr}
4296  };
4297 
4298  lua_getglobal(L, "wesnoth");
4299  lua_newtable(L);
4300  luaL_setfuncs(L, side_callbacks, 0);
4301  lua_cpp::set_functions(L, cpp_side_callbacks);
4302  lua_setfield(L, -2, "sides");
4303  lua_pop(L, 1);
4304 
4305  // Create the interface module
4306  cmd_log_ << "Adding interface module...\n";
4307  static luaL_Reg const intf_callbacks[] {
4308  {"add_hex_overlay", &dispatch<&game_lua_kernel::intf_add_tile_overlay>},
4309  {"remove_hex_overlay", &dispatch<&game_lua_kernel::intf_remove_tile_overlay>},
4310  {"color_adjust", &dispatch<&game_lua_kernel::intf_color_adjust>},
4311  {"delay", &dispatch<&game_lua_kernel::intf_delay>},
4312  {"deselect_hex", &dispatch<&game_lua_kernel::intf_deselect_hex>},
4313  {"highlight_hex", &dispatch<&game_lua_kernel::intf_highlight_hex>},
4314  {"float_label", &dispatch<&game_lua_kernel::intf_float_label>},
4315  {"get_displayed_unit", &dispatch<&game_lua_kernel::intf_get_displayed_unit>},
4316  {"get_hovered_hex", &dispatch<&game_lua_kernel::intf_get_mouseover_tile>},
4317  {"get_selected_hex", &dispatch<&game_lua_kernel::intf_get_selected_tile>},
4318  {"lock", &dispatch<&game_lua_kernel::intf_lock_view>},
4319  {"is_locked", &dispatch<&game_lua_kernel::intf_view_locked>},
4320  {"scroll", &dispatch<&game_lua_kernel::intf_scroll>},
4321  {"scroll_to_hex", &dispatch<&game_lua_kernel::intf_scroll_to_tile>},
4322  {"skip_messages", &dispatch<&game_lua_kernel::intf_skip_messages>},
4323  {"is_skipping_messages", &dispatch<&game_lua_kernel::intf_is_skipping_messages>},
4324  {"zoom", &dispatch<&game_lua_kernel::intf_zoom>},
4325  {"clear_menu_item", &dispatch<&game_lua_kernel::intf_clear_menu_item>},
4326  {"set_menu_item", &dispatch<&game_lua_kernel::intf_set_menu_item>},
4327  { nullptr, nullptr }
4328  };
4329  lua_getglobal(L, "wesnoth");
4330  lua_newtable(L);
4331  luaL_setfuncs(L, intf_callbacks, 0);
4332  lua_setfield(L, -2, "interface");
4333  lua_pop(L, 1);
4334 
4335  // Create the playlist table with its metatable
4337 
4338  // Create the wml_actions table.
4339  cmd_log_ << "Adding wml_actions table...\n";
4340 
4341  lua_getglobal(L, "wesnoth");
4342  lua_newtable(L);
4343  lua_setfield(L, -2, "wml_actions");
4344  lua_pop(L, 1);
4345 
4346  // Create the wml_conditionals table.
4347  cmd_log_ << "Adding wml_conditionals table...\n";
4348 
4349  lua_getglobal(L, "wesnoth");
4350  lua_newtable(L);
4351  lua_setfield(L, -2, "wml_conditionals");
4352  lua_pop(L, 1);
4356 
4357  // Create the effects table.
4358  cmd_log_ << "Adding effects table...\n";
4359 
4360  lua_getglobal(L, "wesnoth");
4361  lua_newtable(L);
4362  lua_setfield(L, -2, "effects");
4363  lua_pop(L, 1);
4364 
4365  // Create the custom_synced_commands table.
4366  cmd_log_ << "Adding custom_synced_commands table...\n";
4367 
4368  lua_getglobal(L, "wesnoth");
4369  lua_newtable(L);
4370  lua_setfield(L, -2, "custom_synced_commands");
4371  lua_pop(L, 1);
4372 
4373  // Create the game_events table.
4374  cmd_log_ << "Adding game_events table...\n";
4375 
4376  lua_getglobal(L, "wesnoth");
4377  lua_newtable(L);
4378  lua_setfield(L, -2, "game_events");
4379  lua_pop(L, 1);
4380 
4381  // Create the theme_items table.
4382  cmd_log_ << "Adding game_display table...\n";
4383 
4384  luaW_getglobal(L, "wesnoth", "interface");
4385  lua_newtable(L);
4386  lua_createtable(L, 0, 2);
4387  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_theme_items_get>);
4388  lua_setfield(L, -2, "__index");
4389  lua_pushcfunction(L, &dispatch<&game_lua_kernel::impl_theme_items_set>);
4390  lua_setfield(L, -2, "__newindex");
4391  lua_setmetatable(L, -2);
4392  lua_setfield(L, -2, "game_display");
4393  lua_pop(L, 1);
4394 
4395  lua_settop(L, 0);
4396 
4397  for(const auto& handler : game_events::wml_action::registry())
4398  {
4399  set_wml_action(handler.first, handler.second);
4400  }
4401  luaW_getglobal(L, "wesnoth", "effects");
4402  for(const std::string& effect : unit::builtin_effects) {
4403  lua_pushstring(L, effect.c_str());
4405  lua_rawset(L, -3);
4406  }
4407  lua_settop(L, 0);
4408 }
4409 
4411 {
4412  lua_State *L = mState;
4413  assert(level_lua_.empty());
4414  level_lua_.append_children(level, "lua");
4415 
4416  //Create the races table.
4417  cmd_log_ << "Adding races table...\n";
4418 
4419  lua_settop(L, 0);
4420  lua_getglobal(L, "wesnoth");
4421  luaW_pushracetable(L);
4422  lua_setfield(L, -2, "races");
4423  lua_pop(L, 1);
4424 
4425  // Execute the preload scripts.
4426  cmd_log_ << "Running preload scripts...\n";
4427 
4428  game_config::load_config(game_lua_kernel::preload_config);
4429  for (const config &cfg : game_lua_kernel::preload_scripts) {
4430  run_lua_tag(cfg);
4431  }
4432  for (const config &cfg : level_lua_.child_range("lua")) {
4433  run_lua_tag(cfg);
4434  }
4435 }
4436 
4438  game_display_ = gd;
4439 }
4440 
4441 /**
4442  * These are the child tags of [scenario] (and the like) that are handled
4443  * elsewhere (in the C++ code).
4444  * Any child tags not in this list will be passed to Lua's on_load event.
4445  */
4446 static const std::array<std::string, 24> handled_file_tags {{
4447  "color_palette",
4448  "color_range",
4449  "display",
4450  "end_level_data",
4451  "era",
4452  "event",
4453  "generator",
4454  "label",
4455  "lua",
4456  "map",
4457  "menu_item",
4458  "modification",
4459  "modify_unit_type",
4460  "music",
4461  "options",
4462  "side",
4463  "sound_source",
4464  "story",
4465  "terrain_graphics",
4466  "time",
4467  "time_area",
4468  "tunnel",
4469  "undo_stack",
4470  "variables"
4471 }};
4472 
4473 static bool is_handled_file_tag(const std::string& s)
4474 {
4475  for(const std::string& t : handled_file_tags) {
4476  if (s == t) return true;
4477  }
4478 
4479  return false;
4480 }
4481 
4482 /**
4483  * Executes the game_events.on_load function and passes to it all the
4484  * scenario tags not yet handled.
4485  */
4487 {
4488  lua_State *L = mState;
4489 
4490  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_load"))
4491  return;
4492 
4493  lua_newtable(L);
4494  int k = 1;
4495  for (const config::any_child &v : level.all_children_range())
4496  {
4497  if (is_handled_file_tag(v.key)) continue;
4498  lua_createtable(L, 2, 0);
4499  lua_pushstring(L, v.key.c_str());
4500  lua_rawseti(L, -2, 1);
4501  luaW_pushconfig(L, v.cfg);
4502  lua_rawseti(L, -2, 2);
4503  lua_rawseti(L, -2, k++);
4504  }
4505 
4506  luaW_pcall(L, 1, 0, true);
4507 }
4508 
4509 /**
4510  * Executes the game_events.on_save function and adds to @a cfg the
4511  * returned tags. Also flushes the [lua] tags.
4512  */
4514 {
4515  lua_State *L = mState;
4516 
4517  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_save"))
4518  return;
4519 
4520  if (!luaW_pcall(L, 0, 1, false))
4521  return;
4522 
4523  config v;
4524  luaW_toconfig(L, -1, v);
4525  lua_pop(L, 1);
4526 
4527  for (;;)
4528  {
4530  if (i == v.ordered_end()) break;
4531  if (is_handled_file_tag(i->key))
4532  {
4533  /*
4534  * It seems the only tags appearing in the config v variable here
4535  * are the core-lua-handled (currently [item] and [objectives])
4536  * and the extra UMC ones.
4537  */
4538  const std::string m = "Tag is already used: [" + i->key + "]";
4539  log_error(m.c_str());
4540  v.erase(i);
4541  continue;
4542  }
4543  cfg.splice_children(v, i->key);
4544  }
4545 }
4546 
4547 /**
4548  * Executes the game_events.on_event function.
4549  * Returns false if there was no lua handler for this event
4550  */
4552 {
4553  lua_State *L = mState;
4554 
4555  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_event"))
4556  return false;
4557 
4558  queued_event_context dummy(&ev, queued_events_);
4559  lua_pushstring(L, ev.name.c_str());
4560  luaW_pcall(L, 1, 0, false);
4561  return true;
4562 }
4563 
4564 void game_lua_kernel::custom_command(const std::string& name, const config& cfg)
4565 {
4566  lua_State *L = mState;
4567 
4568  if (!luaW_getglobal(L, "wesnoth", "custom_synced_commands", name)) {
4569  return;
4570  }
4571  luaW_pushconfig(L, cfg);
4572  luaW_pcall(L, 1, 0, false);
4573 }
4574 
4575 /**
4576  * Applies its upvalue as an effect
4577  * Arg 1: The unit to apply to
4578  * Arg 3: The [effect] tag contents
4579  * Arg 3: If false, only build description
4580  * Return: The description of the effect
4581  */
4583 {
4584  std::string which_effect = lua_tostring(L, lua_upvalueindex(1));
4585  bool need_apply = luaW_toboolean(L, lua_upvalueindex(2));
4586  // Argument 1 is the implicit "self" argument, which isn't needed here
4587  lua_unit u(luaW_checkunit(L, 2));
4588  config cfg = luaW_checkconfig(L, 3);
4589 
4590  // The times= key is supposed to be ignored by the effect function.
4591  // However, just in case someone doesn't realize this, we will set it to 1 here.
4592  cfg["times"] = 1;
4593 
4594  if(need_apply) {
4595  u->apply_builtin_effect(which_effect, cfg);
4596  return 0;
4597  } else {
4598  std::string description = u->describe_builtin_effect(which_effect, cfg);
4599  lua_pushstring(L, description.c_str());
4600  return 1;
4601  }
4602 }
4603 
4604 /**
4605 * Registers a function for use as an effect handler.
4606 */
4608 {
4609  lua_State *L = mState;
4610 
4611  // The effect name is at the top of the stack
4612  int str_i = lua_gettop(L);
4613  lua_newtable(L); // The functor table
4614  lua_newtable(L); // The functor metatable
4615  lua_pushstring(L, "__call");
4616  lua_pushvalue(L, str_i);
4617  lua_pushboolean(L, true);
4618  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_builtin_effect>, 2);
4619  lua_rawset(L, -3); // Set the call metafunction
4620  lua_pushstring(L, "__descr");
4621  lua_pushvalue(L, str_i);
4622  lua_pushboolean(L, false);
4623  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_builtin_effect>, 2);
4624  lua_rawset(L, -3); // Set the descr "metafunction"
4625  lua_setmetatable(L, -2); // Apply the metatable to the functor table
4626 }
4627 
4628 
4629 /**
4630  * Executes its upvalue as a wml action.
4631  */
4633 {
4636 
4637  vconfig vcfg = luaW_checkvconfig(L, 1);
4638  h(get_event_info(), vcfg);
4639  return 0;
4640 }
4641 
4642 /**
4643  * Registers a function for use as an action handler.
4644  */
4646 {
4647  lua_State *L = mState;
4648 
4649  lua_getglobal(L, "wesnoth");
4650  lua_pushstring(L, "wml_actions");
4651  lua_rawget(L, -2);
4652  lua_pushstring(L, cmd.c_str());
4653  lua_pushlightuserdata(L, reinterpret_cast<void *>(h));
4654  lua_pushcclosure(L, &dispatch<&game_lua_kernel::cfun_wml_action>, 1);
4655  lua_rawset(L, -3);
4656  lua_pop(L, 2);
4657 }
4658 
4659 using wml_conditional_handler = bool(*)(const vconfig&);
4660 
4661 /**
4662  * Executes its upvalue as a wml condition and returns the result.
4663  */
4665 {
4668 
4669  vconfig vcfg = luaW_checkvconfig(L, 1);
4670  lua_pushboolean(L, h(vcfg));
4671  return 1;
4672 }
4673 
4674 /**
4675  * Registers a function for use as a conditional handler.
4676  */
4678 {
4679  lua_State *L = mState;
4680 
4681  lua_getglobal(L, "wesnoth");
4682  lua_pushstring(L, "wml_conditionals");
4683  lua_rawget(L, -2);
4684  lua_pushstring(L, cmd.c_str());
4685  lua_pushlightuserdata(L, reinterpret_cast<void *>(h));
4687  lua_rawset(L, -3);
4688  lua_pop(L, 2);
4689 }
4690 
4691 /**
4692  * Runs a command from an event handler.
4693  * @return true if there is a handler for the command.
4694  * @note @a cfg should be either volatile or long-lived since the Lua
4695  * code may grab it for an arbitrary long time.
4696  */
4697 bool game_lua_kernel::run_wml_action(const std::string& cmd, const vconfig& cfg,
4698  const game_events::queued_event& ev)
4699 {
4700  lua_State *L = mState;
4701 
4702 
4703  if (!luaW_getglobal(L, "wesnoth", "wml_actions", cmd))
4704  return false;
4705 
4706  queued_event_context dummy(&ev, queued_events_);
4707  luaW_pushvconfig(L, cfg);
4708  luaW_pcall(L, 1, 0, true);
4709  return true;
4710 }
4711 
4712 
4713 /**
4714  * Evaluates a WML conidition.
4715  *
4716  * @returns Whether the condition passed.
4717  * @note @a cfg should be either volatile or long-lived since the Lua
4718  * code may grab it for an arbitrarily long time.
4719  */
4720 bool game_lua_kernel::run_wml_conditional(const std::string& cmd, const vconfig& cfg)
4721 {
4722  lua_State* L = mState;
4723 
4724  // If an invalid coniditional tag is used, consider it a pass.
4725  if(!luaW_getglobal(L, "wesnoth", "wml_conditionals", cmd)) {
4726  lg::wml_error() << "unknown conditional wml: [" << cmd << "]\n";
4727  return true;
4728  }
4729 
4730  luaW_pushvconfig(L, cfg);
4731 
4732  // Any runtime error is considered a fail.
4733  if(!luaW_pcall(L, 1, 1, true)) {
4734  return false;
4735  }
4736 
4737  bool b = luaW_toboolean(L, -1);
4738 
4739  lua_pop(L, 1);
4740  return b;
4741 }
4742 
4743 
4744 /**
4745 * Runs a script from a location filter.
4746 * The script is an already compiled function given by its name.
4747 */
4748 bool game_lua_kernel::run_filter(char const *name, const map_location& l)
4749 {
4752  return run_filter(name, 2);
4753 }
4754 
4755 /**
4756 * Runs a script from a location filter.
4757 * The script is an already compiled function given by its name.
4758 */
4759 bool game_lua_kernel::run_filter(char const *name, const team& t)
4760 {
4761  //TODO: instead of passing the lua team object we coudl also jsut pass its
4762  // number. then we wouldn't need this const cast.
4763  luaW_pushteam(mState, const_cast<team&>(t));
4764  return run_filter(name, 1);
4765 }
4766 /**
4767 * Runs a script from a unit filter.
4768 * The script is an already compiled function given by its name.
4769 */
4770 bool game_lua_kernel::run_filter(char const *name, const unit& u)
4771 {
4772  lua_State *L = mState;
4773  lua_unit* lu = luaW_pushlocalunit(L, const_cast<unit&>(u));
4774  // stack: unit
4775  // put the unit to the stack twice to prevent gc.
4776  lua_pushvalue(L, -1);
4777  // stack: unit, unit
4778  bool res = run_filter(name, 1);
4779  // stack: unit
4780  lu->clear_ref();
4781  lua_pop(L, 1);
4782  return res;
4783 }
4784 /**
4785 * Runs a script from a filter.
4786 * The script is an already compiled function given by its name.
4787 */
4788 bool game_lua_kernel::run_filter(char const *name, int nArgs)
4789 {
4790  map_locker(this);
4791  lua_State *L = mState;
4792  // Get the user filter by name.
4793  const std::vector<std::string>& path = utils::split(name, '.', utils::STRIP_SPACES);
4794  if (!luaW_getglobal(L, path))
4795  {
4796  std::string message = std::string() + "function " + name + " not found";
4797  log_error(message.c_str(), "Lua SUF Error");
4798  //we pushed nothing and can safeley return.
4799  return false;
4800  }
4801  lua_insert(L, -nArgs - 1);
4802 
4803  if (!luaW_pcall(L, nArgs, 1)) return false;
4804 
4805  bool b = luaW_toboolean(L, -1);
4806  lua_pop(L, 1);
4807  return b;
4808 }
4809 
4810 std::string game_lua_kernel::apply_effect(const std::string& name, unit& u, const config& cfg, bool need_apply)
4811 {
4812  lua_State *L = mState;
4813  int top = lua_gettop(L);
4814  std::string descr;
4815  // Stack: nothing
4816  lua_unit* lu = luaW_pushlocalunit(L, u);
4817  // Stack: unit
4818  // (Note: The unit needs to be on the stack twice to prevent untimely GC.)
4819  luaW_pushconfig(L, cfg);
4820  // Stack: unit, cfg
4821  if(luaW_getglobal(L, "wesnoth", "effects", name)) {
4822  map_locker(this);
4823  // Stack: unit, cfg, effect
4824  if(lua_istable(L, -1)) {
4825  // Effect is implemented by a table with __call and __descr
4826  if(need_apply) {
4827  lua_pushvalue(L, -1);
4828  // Stack: unit, cfg, effect, effect
4829  lua_pushvalue(L, top + 1);
4830  // Stack: unit, cfg, effect, effect, unit
4831  lua_pushvalue(L, top + 2);
4832  // Stack: unit, cfg, effect, effect, unit, cfg
4833  luaW_pcall(L, 2, 0);
4834  // Stack: unit, cfg, effect
4835  }
4836  if(luaL_getmetafield(L, -1, "__descr")) {
4837  // Stack: unit, cfg, effect, __descr
4838  if(lua_isstring(L, -1)) {
4839  // __descr was a static string
4840  descr = lua_tostring(L, -1);
4841  } else {
4842  lua_pushvalue(L, -2);
4843  // Stack: unit, cfg, effect, __descr, effect
4844  lua_pushvalue(L, top + 1);
4845  // Stack: unit, cfg, effect, __descr, effect, unit
4846  lua_pushvalue(L, top + 2);
4847  // Stack: unit, cfg, effect, __descr, effect, unit, cfg
4848  luaW_pcall(L, 3, 1);
4849  if(lua_isstring(L, -1) && !lua_isnumber(L, -1)) {
4850  descr = lua_tostring(L, -1);
4851  } else {
4852  ERR_LUA << "Effect __descr metafunction should have returned a string, but instead returned ";
4853  if(lua_isnone(L, -1)) {
4854  ERR_LUA << "nothing";
4855  } else {
4856  ERR_LUA << lua_typename(L, lua_type(L, -1));
4857  }
4858  }
4859  }
4860  }
4861  } else if(need_apply) {
4862  // Effect is assumed to be a simple function; no description is provided
4863  lua_pushvalue(L, top + 1);
4864  // Stack: unit, cfg, effect, unit
4865  lua_pushvalue(L, top + 2);
4866  // Stack: unit, cfg, effect, unit, cfg
4867  luaW_pcall(L, 2, 0);
4868  // Stack: unit, cfg
4869  }
4870  }
4871  lua_settop(L, top);
4872  lu->clear_ref();
4873  return descr;
4874 }
4875 
4877 {
4878  return ai::lua_ai_context::create(mState,code,engine);
4879 }
4880 
4882 {
4883  return ai::lua_ai_action_handler::create(mState,code,context);
4884 }
4885 
4887 {
4888  lua_State *L = mState;
4889 
4890  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_mouse_move")) {
4891  return;
4892  }
4893  lua_push(L, loc.wml_x());
4894  lua_push(L, loc.wml_y());
4895  luaW_pcall(L, 2, 0, false);
4896  return;
4897 }
4898 
4900 {
4901  lua_State *L = mState;
4902 
4903  if (!luaW_getglobal(L, "wesnoth", "game_events", "on_mouse_action")) {
4904  return;
4905  }
4906  lua_push(L, loc.wml_x());
4907  lua_push(L, loc.wml_y());
4908  luaW_pcall(L, 2, 0, false);
4909  return;
4910 }
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:327
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:91
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:845
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
int intf_find_vision_range(lua_State *L)
Finds all the locations for which a given unit would remove the fog (if there was fog on the map)...
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
void create_jamming_map(std::map< map_location, int > &jamming, const team &view_team)
Helper function that creates the map of enemy anti-vision that&#39;s needed when creating a pathfinding::...
Definition: vision.cpp:48
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)
#define d
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2477
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:501
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:331
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:2210
#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:1568
static void clear_status_caches()
Clear this unit status cache for all units.
Definition: unit.cpp:642
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:552
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.