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