1 /*
2  * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "solarus/audio/Music.h"
18 #include "solarus/audio/Sound.h"
19 #include "solarus/core/CurrentQuest.h"
20 #include "solarus/core/Debug.h"
21 #include "solarus/core/Equipment.h"
22 #include "solarus/core/EquipmentItem.h"
23 #include "solarus/core/Game.h"
24 #include "solarus/core/MainLoop.h"
25 #include "solarus/core/Map.h"
26 #include "solarus/core/ResourceProvider.h"
27 #include "solarus/core/Timer.h"
28 #include "solarus/core/Treasure.h"
29 #include "solarus/entities/Block.h"
30 #include "solarus/entities/Bomb.h"
31 #include "solarus/entities/Chest.h"
32 #include "solarus/entities/Crystal.h"
33 #include "solarus/entities/CrystalBlock.h"
34 #include "solarus/entities/CustomEntity.h"
35 #include "solarus/entities/Destination.h"
36 #include "solarus/entities/Destructible.h"
37 #include "solarus/entities/Door.h"
38 #include "solarus/entities/DynamicTile.h"
39 #include "solarus/entities/Enemy.h"
40 #include "solarus/entities/Entities.h"
41 #include "solarus/entities/EntityTypeInfo.h"
42 #include "solarus/entities/Explosion.h"
43 #include "solarus/entities/Fire.h"
44 #include "solarus/entities/GroundInfo.h"
45 #include "solarus/entities/Hero.h"
46 #include "solarus/entities/Jumper.h"
47 #include "solarus/entities/Npc.h"
48 #include "solarus/entities/Pickable.h"
49 #include "solarus/entities/Sensor.h"
50 #include "solarus/entities/Separator.h"
51 #include "solarus/entities/ShopTreasure.h"
52 #include "solarus/entities/Stairs.h"
53 #include "solarus/entities/Stream.h"
54 #include "solarus/entities/Switch.h"
55 #include "solarus/entities/Teletransporter.h"
56 #include "solarus/entities/Tile.h"
57 #include "solarus/entities/TileInfo.h"
58 #include "solarus/entities/TilePattern.h"
59 #include "solarus/entities/Tileset.h"
60 #include "solarus/entities/Wall.h"
61 #include "solarus/lua/LuaContext.h"
62 #include "solarus/lua/LuaTools.h"
63 #include "solarus/movements/Movement.h"
64 #include <lua.hpp>
65 #include <sstream>
66 
67 namespace Solarus {
68 
69 namespace {
70 
71 /**
72  * \brief Lua equivalent of the deprecated map:move_camera() function.
73  */
74 const char* move_camera_code =
75 "local map, x, y, speed, callback, delay_before, delay_after = ...\n"
76 "local camera = map:get_camera()\n"
77 "local game = map:get_game()\n"
78 "local hero = map:get_hero()\n"
79 "delay_before = delay_before or 1000\n"
80 "delay_after = delay_after or 1000\n"
81 "local back_x, back_y = camera:get_position_to_track(hero)\n"
82 "game:set_suspended(true)\n"
83 "camera:start_manual()\n"
84 "local movement = sol.movement.create(\"target\")\n"
85 "movement:set_target(camera:get_position_to_track(x, y))\n"
86 "movement:set_ignore_obstacles(true)\n"
87 "movement:set_speed(speed)\n"
88 "movement:start(camera, function()\n"
89 "  local timer_1 = sol.timer.start(map, delay_before, function()\n"
90 "    callback()\n"
91 "    local timer_2 = sol.timer.start(map, delay_after, function()\n"
92 "      local movement = sol.movement.create(\"target\")\n"
93 "      movement:set_target(back_x, back_y)\n"
94 "      movement:set_ignore_obstacles(true)\n"
95 "      movement:set_speed(speed)\n"
96 "      movement:start(camera, function()\n"
97 "        game:set_suspended(false)\n"
98 "        camera:start_tracking(hero)\n"
99 "        if map.on_camera_back ~= nil then\n"
100 "          map:on_camera_back()\n"
101 "        end\n"
102 "      end)\n"
103 "    end)\n"
104 "    timer_2:set_suspended_with_map(false)\n"
105 "  end)\n"
106 "  timer_1:set_suspended_with_map(false)\n"
107 "end)\n";
108 
109 }  // Anonymous namespace.
110 
111 /**
112  * Name of the Lua table representing the map module.
113  */
114 const std::string LuaContext::map_module_name = "sol.map";
115 
116 /**
117  * \brief Initializes the map features provided to Lua.
118  */
register_map_module()119 void LuaContext::register_map_module() {
120 
121   const std::vector<luaL_Reg> methods = {
122       { "get_id", map_api_get_id },
123       { "get_game", map_api_get_game },
124       { "get_world", map_api_get_world },
125       { "set_world", map_api_set_world },
126       { "get_min_layer", map_api_get_min_layer },
127       { "get_max_layer", map_api_get_max_layer },
128       { "get_size", map_api_get_size },
129       { "get_location", map_api_get_location },
130       { "get_floor", map_api_get_floor },
131       { "set_floor", map_api_set_floor },
132       { "get_tileset", map_api_get_tileset },
133       { "set_tileset", map_api_set_tileset },
134       { "get_music", map_api_get_music },
135       { "get_camera", map_api_get_camera },
136       { "get_camera_position", map_api_get_camera_position },
137       { "move_camera", map_api_move_camera },
138       { "get_ground", map_api_get_ground },
139       { "draw_visual", map_api_draw_visual },
140       { "draw_sprite", map_api_draw_sprite },
141       { "get_crystal_state", map_api_get_crystal_state },
142       { "set_crystal_state", map_api_set_crystal_state },
143       { "change_crystal_state", map_api_change_crystal_state },
144       { "open_doors", map_api_open_doors },
145       { "close_doors", map_api_close_doors },
146       { "set_doors_open", map_api_set_doors_open },
147       { "get_entity", map_api_get_entity },
148       { "has_entity", map_api_has_entity },
149       { "get_entities", map_api_get_entities },
150       { "get_entities_count", map_api_get_entities_count },
151       { "has_entities", map_api_has_entities },
152       { "get_entities_by_type", map_api_get_entities_by_type },
153       { "get_entities_in_rectangle", map_api_get_entities_in_rectangle },
154       { "get_entities_in_region", map_api_get_entities_in_region },
155       { "get_hero", map_api_get_hero },
156       { "set_entities_enabled", map_api_set_entities_enabled },
157       { "remove_entities", map_api_remove_entities }
158   };
159 
160   const std::vector<luaL_Reg> metamethods = {
161       { "__gc", userdata_meta_gc },
162       { "__newindex", userdata_meta_newindex_as_table },
163       { "__index", userdata_meta_index_as_table },
164   };
165 
166   register_type(map_module_name, {}, methods, metamethods);
167 
168   // Add map:create_* functions as closures because we pass the entity type as upvalue.
169   luaL_getmetatable(current_l, map_module_name.c_str());
170   for (const auto& kvp : EnumInfoTraits<EntityType>::names) {
171     EntityType type = kvp.first;
172     const std::string& type_name = kvp.second;
173     if (!EntityTypeInfo::can_be_created_from_lua_api(type)) {
174       continue;
175     }
176     std::string function_name = "create_" + type_name;
177     push_string(current_l, type_name);
178     lua_pushcclosure(current_l, map_api_create_entity, 1);
179     lua_setfield(current_l, -2, function_name.c_str());
180   }
181 
182   // Add a Lua implementation of the deprecated map:move_camera() function.
183   int result = luaL_loadstring(current_l, move_camera_code);
184   if (result != 0) {
185     Debug::error(std::string("Failed to initialize map:move_camera(): ") + lua_tostring(current_l, -1));
186     lua_pop(current_l, 1);
187   }
188   else {
189     Debug::check_assertion(lua_isfunction(current_l, -1), "map:move_camera() is not a function");
190     lua_setfield(current_l, LUA_REGISTRYINDEX, "map.move_camera");
191   }
192 }
193 
194 /**
195  * \brief Returns whether a value is a userdata of type map.
196  * \param l A Lua context.
197  * \param index An index in the stack.
198  * \return true if the value at this index is a map.
199  */
is_map(lua_State * l,int index)200 bool LuaContext::is_map(lua_State* l, int index) {
201   return is_userdata(l, index, map_module_name);
202 }
203 
204 /**
205  * \brief Checks that the userdata at the specified index of the stack is a
206  * map that is currently loaded and returns it.
207  * \param l A Lua context.
208  * \param index An index in the stack.
209  * \return The map.
210  */
check_map(lua_State * l,int index)211 std::shared_ptr<Map> LuaContext::check_map(lua_State* l, int index) {
212 
213   return std::static_pointer_cast<Map>(check_userdata(
214       l, index, map_module_name
215   ));
216 }
217 
218 /**
219  * \brief Pushes a map userdata onto the stack.
220  * \param l A Lua context.
221  * \param game A game.
222  */
push_map(lua_State * l,Map & map)223 void LuaContext::push_map(lua_State* l, Map& map) {
224 
225   push_userdata(l, map);
226 }
227 
228 namespace {
229 
230 /**
231  * \brief Checks and returns the layer of an entity to be created.
232  *
233  * The layer is assumed to be specified in a field "layer".
234  * Throws a LuaException if the layer is invalid for the map.
235  *
236  * \param l A Lua state.
237  * \param index Index of the argument in the Lua stack.
238  * \param entity_data Description of the entity to create.
239  * \param map The map where to create the entity.
240  * \return The layer.
241  */
entity_creation_check_layer(lua_State * l,int index,const EntityData & entity_data,const Map & map)242 int entity_creation_check_layer(
243     lua_State* l,
244     int index,
245     const EntityData& entity_data,
246     const Map& map) {
247 
248   const int layer = entity_data.get_layer();
249 
250   if (!map.is_valid_layer(layer)) {
251     std::ostringstream oss;
252     oss << "Invalid layer: " << layer;
253     LuaTools::arg_error(l, index, oss.str());
254   }
255 
256   return layer;
257 }
258 
259 /**
260  * \brief Checks and returns the size of an entity to be created.
261  *
262  * The size is assumed to be specified in fields "width" and "height".
263  * Throws a LuaException if the size is invalid.
264  *
265  * \param l A Lua state.
266  * \param index Index of the argument in the Lua stack.
267  * \param entity_data Description of the entity to create.
268  * \return The size.
269  */
entity_creation_check_size(lua_State * l,int index,const EntityData & entity_data)270 Size entity_creation_check_size(
271     lua_State* l,
272     int index,
273     const EntityData& entity_data) {
274 
275   const Size size = {
276       entity_data.get_integer("width"),
277       entity_data.get_integer("height")
278   };
279 
280   if (size.width < 0 || size.width % 8 != 0) {
281     std::ostringstream oss;
282     oss << "Invalid width " << size.width << ": should be a positive multiple of 8";
283     LuaTools::arg_error(l, index, oss.str());
284   }
285   if (size.height < 0 || size.height % 8 != 0) {
286     std::ostringstream oss;
287     oss << "Invalid height " << size.height << ": should be a positive multiple of 8";
288     LuaTools::arg_error(l, index, oss.str());
289   }
290 
291   return size;
292 }
293 
294 /**
295  * \brief Checks and returns a mandatory savegame variable field for an
296  * entity to be created.
297  *
298  * Throws a LuaException if the savegame variable name is invalid or empty.
299  *
300  * \param l A Lua state.
301  * \param index Index of the argument in the Lua stack.
302  * \param entity_data Description of the entity to create.
303  * \param field_name Name of the savegame variable field to check.
304  * \return The savegame variable name.
305  */
entity_creation_check_savegame_variable_mandatory(lua_State * l,int index,const EntityData & entity_data,const std::string & field_name)306 std::string entity_creation_check_savegame_variable_mandatory(
307     lua_State* l,
308     int index,
309     const EntityData& entity_data,
310     const std::string& field_name
311 ) {
312 
313   const std::string& savegame_variable = entity_data.get_string(field_name);
314 
315   if (!LuaTools::is_valid_lua_identifier(savegame_variable)) {
316     LuaTools::arg_error(l, index,
317         "Bad field '" + field_name + "' (invalid savegame variable identifier: '"
318         + savegame_variable + "')"
319     );
320   }
321 
322   return savegame_variable;
323 }
324 
325 /**
326  * \brief Checks and returns an optional savegame variable field for an
327  * entity to be created.
328  *
329  * Throws a LuaException if the savegame variable name is invalid.
330  *
331  * \param l A Lua state.
332  * \param index Index of the argument in the Lua stack.
333  * \param entity_data Description of the entity to create.
334  * \param field_name Name of the savegame variable field to check.
335  * \return The savegame variable name.
336  * An empty string means no savegame variable.
337  */
entity_creation_check_savegame_variable_optional(lua_State * l,int index,const EntityData & entity_data,const std::string & field_name)338 std::string entity_creation_check_savegame_variable_optional(
339     lua_State* l,
340     int index,
341     const EntityData& entity_data,
342     const std::string& field_name
343 ) {
344   const std::string& savegame_variable = entity_data.get_string(field_name);
345 
346   if (savegame_variable.empty()) {
347     return savegame_variable;
348   }
349 
350   return entity_creation_check_savegame_variable_mandatory(l, index, entity_data, field_name);
351 }
352 
353 /**
354  * \brief Checks an enum field for an entity to be created.
355  *
356  * Throws a LuaException if the value is not a string or if the string is not
357  * a valid name for the enum.
358  * This is a useful function for mapping strings to C or C++ enums.
359  *
360  * \param l A Lua state.
361  * \param index Index of the argument in the Lua stack.
362  * \param entity_data Description of the entity to
363  * \param field_name Name of the field to check.
364  * \param names A mapping of enum values to strings to search in.
365  * \return The enumerated value corresponding to this string.
366  */
367 template<typename E>
entity_creation_check_enum(lua_State * l,int index,const EntityData & entity_data,const std::string & field_name,const std::map<E,std::string> & names)368 E entity_creation_check_enum(
369     lua_State* l,
370     int index,
371     const EntityData& entity_data,
372     const std::string& field_name,
373     const std::map<E, std::string>& names
374 ) {
375   const std::string& name = entity_data.get_string(field_name);
376   for (const auto& kvp: names) {
377     if (kvp.second == name) {
378       return kvp.first;
379     }
380   }
381 
382   // The value was not found. Build an error message with possible values.
383   std::string allowed_names;
384   for (const auto& kvp: names) {
385     allowed_names += "\"" + kvp.second + "\", ";
386   }
387   allowed_names = allowed_names.substr(0, allowed_names.size() - 2);
388 
389   LuaTools::arg_error(l, index,
390       std::string("Invalid name '") + name + "'. Allowed names are: "
391       + allowed_names
392   );
393   return E();  // Make sure the compiler is happy.
394 }
395 
396 template<typename E>
entity_creation_check_enum(lua_State * l,int index,const EntityData & entity_data,const std::string & field_name)397 E entity_creation_check_enum(
398     lua_State* l,
399     int index,
400     const EntityData& entity_data,
401     const std::string& field_name
402 ) {
403   return entity_creation_check_enum<E>(l, index, entity_data, field_name, EnumInfoTraits<E>::names);
404 }
405 
406 }
407 
408 /**
409  * \brief Creates a tile on the map.
410  * \param l The Lua context that is calling this function.
411  * \return Number of values to return to Lua.
412  */
l_create_tile(lua_State * l)413 int LuaContext::l_create_tile(lua_State* l) {
414 
415   return state_boundary_handle(l, [&] {
416     Map& map = *check_map(l, 1);
417     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
418     const int layer = entity_creation_check_layer(l, 1, data, map);
419     const int x = data.get_xy().x;
420     const int y = data.get_xy().y;
421     const Size size =  entity_creation_check_size(l, 1, data);
422     const std::string& tile_pattern_id = data.get_string("pattern");
423     std::string tileset_id = data.get_string("tileset");
424 
425     bool use_map_tileset = tileset_id.empty();
426     if (use_map_tileset) {
427       tileset_id = map.get_tileset_id();
428     }
429     ResourceProvider& resource_provider = map.get_game().get_resource_provider();
430     const Tileset& tileset = resource_provider.get_tileset(tileset_id);
431     std::shared_ptr<TilePattern> pattern = tileset.get_tile_pattern(tile_pattern_id);
432     if (pattern == nullptr) {
433       LuaTools::error(l, "No such pattern in tileset '" + tileset_id + "': '" + tile_pattern_id + "'");
434     }
435     const Size& pattern_size = pattern->get_size();
436     Entities& entities = map.get_entities();
437 
438     // If the tile is big, divide it in several smaller tiles so that
439     // most of them can still be optimized away.
440     // Otherwise, tiles expanded in big rectangles like a lake or a dungeon
441     // floor would be entirely redrawn at each frame when just one small
442     // animated tile overlaps them.
443 
444     TileInfo tile_info;
445     tile_info.layer = layer;
446     tile_info.box = { Point(), pattern_size };
447     tile_info.pattern_id = tile_pattern_id;
448     tile_info.pattern = pattern;
449 
450     if (!use_map_tileset) {
451       tile_info.tileset = &tileset;
452     }
453 
454     for (int current_y = y; current_y < y + size.height; current_y += pattern->get_height()) {
455       for (int current_x = x; current_x < x + size.width; current_x += pattern->get_width()) {
456         tile_info.box.set_xy(current_x, current_y);
457         // The tile will actually be created only if it cannot be optimized away.
458         entities.add_tile_info(
459             tile_info
460         );
461       }
462     }
463 
464     return 0;
465   });
466 }
467 
468 /**
469  * \brief Creates a destination on the map.
470  * \param l The Lua context that is calling this function.
471  * \return Number of values to return to Lua.
472  */
l_create_destination(lua_State * l)473 int LuaContext::l_create_destination(lua_State* l) {
474 
475   return state_boundary_handle(l, [&] {
476     Map& map = *check_map(l, 1);
477     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
478 
479     std::shared_ptr<Destination> entity = std::make_shared<Destination>(
480         data.get_name(),
481         entity_creation_check_layer(l, 1, data, map),
482         data.get_xy(),
483         data.get_integer("direction"),
484         data.get_string("sprite"),
485         data.get_boolean("default")
486     );
487     StartingLocationMode starting_location_mode =
488         entity_creation_check_enum<StartingLocationMode>(l, 1, data, "starting_location_mode");
489     entity->set_starting_location_mode(starting_location_mode);
490     entity->set_user_properties(data.get_user_properties());
491     entity->set_enabled(data.is_enabled_at_start());
492     map.get_entities().add_entity(entity);
493 
494     if (map.is_started()) {
495       push_entity(l, *entity);
496       return 1;
497     }
498     return 0;
499   });
500 }
501 
502 /**
503  * \brief Creates a teletransporter on the map.
504  * \param l The Lua context that is calling this function.
505  * \return Number of values to return to Lua.
506  */
l_create_teletransporter(lua_State * l)507 int LuaContext::l_create_teletransporter(lua_State* l) {
508 
509   return state_boundary_handle(l, [&] {
510     Map& map = *check_map(l, 1);
511     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
512 
513     EntityPtr entity = std::make_shared<Teletransporter>(
514         data.get_name(),
515         entity_creation_check_layer(l, 1, data, map),
516         data.get_xy(),
517         entity_creation_check_size(l, 1, data),
518         data.get_string("sprite"),
519         data.get_string("sound"),
520         entity_creation_check_enum<Transition::Style>(l, 1, data, "transition"),
521         data.get_string("destination_map"),
522         data.get_string("destination")
523     );
524     entity->set_user_properties(data.get_user_properties());
525     entity->set_enabled(data.is_enabled_at_start());
526     map.get_entities().add_entity(entity);
527 
528     if (map.is_started()) {
529       push_entity(l, *entity);
530       return 1;
531     }
532     return 0;
533   });
534 }
535 
536 /**
537  * \brief Creates a pickable treasure on the map.
538  * \param l The Lua context that is calling this function.
539  * \return Number of values to return to Lua.
540  */
l_create_pickable(lua_State * l)541 int LuaContext::l_create_pickable(lua_State* l) {
542 
543   return state_boundary_handle(l, [&] {
544     Map& map = *check_map(l, 1);
545     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
546 
547     Game& game = map.get_game();
548     bool force_persistent = false;
549     FallingHeight falling_height = FALLING_MEDIUM;
550     if (!map.is_loaded()) {
551       // Different behavior when the pickable is already placed on the map.
552       falling_height = FALLING_NONE;
553       force_persistent = true;
554     }
555 
556     const std::shared_ptr<Pickable>& entity = Pickable::create(
557         game,
558         data.get_name(),
559         entity_creation_check_layer(l, 1, data, map),
560         data.get_xy(),
561         Treasure(
562             game,
563             data.get_string("treasure_name"),
564             data.get_integer("treasure_variant"),
565             entity_creation_check_savegame_variable_optional(l, 1, data, "treasure_savegame_variable")
566         ),
567         falling_height,
568         force_persistent
569     );
570 
571     if (entity == nullptr) {
572       lua_pushnil(l);
573       return 1;
574     }
575 
576     entity->set_user_properties(data.get_user_properties());
577     entity->set_enabled(data.is_enabled_at_start());
578     map.get_entities().add_entity(entity);
579 
580     if (map.is_started()) {
581       push_entity(l, *entity);
582       return 1;
583     }
584     return 0;
585   });
586 }
587 
588 /**
589  * \brief Creates a destructible object on the map.
590  * \param l The Lua context that is calling this function.
591  * \return Number of values to return to Lua.
592  */
l_create_destructible(lua_State * l)593 int LuaContext::l_create_destructible(lua_State* l) {
594 
595   return state_boundary_handle(l, [&] {
596     Map& map = *check_map(l, 1);
597     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
598 
599     std::shared_ptr<Destructible> destructible = std::make_shared<Destructible>(
600         data.get_name(),
601         entity_creation_check_layer(l, 1, data, map),
602         data.get_xy(),
603         data.get_string("sprite"),
604         Treasure(
605             map.get_game(),
606             data.get_string("treasure_name"),
607             data.get_integer("treasure_variant"),
608             entity_creation_check_savegame_variable_optional(l, 1, data, "treasure_savegame_variable")
609         ),
610         entity_creation_check_enum<Ground>(l, 1, data, "ground")
611     );
612     destructible->set_destruction_sound(data.get_string("destruction_sound"));
613     destructible->set_weight(data.get_integer("weight"));
614     destructible->set_can_be_cut(data.get_boolean("can_be_cut"));
615     destructible->set_can_explode(data.get_boolean("can_explode"));
616     destructible->set_can_regenerate(data.get_boolean("can_regenerate"));
617     destructible->set_damage_on_enemies(data.get_integer("damage_on_enemies"));
618     destructible->set_user_properties(data.get_user_properties());
619     destructible->set_enabled(data.is_enabled_at_start());
620     map.get_entities().add_entity(destructible);
621     if (map.is_started()) {
622       push_entity(l, *destructible);
623       return 1;
624     }
625     return 0;
626   });
627 }
628 
629 /**
630  * \brief Creates a chest on the map.
631  * \param l The Lua context that is calling this function.
632  * \return Number of values to return to Lua.
633  */
l_create_chest(lua_State * l)634 int LuaContext::l_create_chest(lua_State* l) {
635 
636   return state_boundary_handle(l, [&] {
637     Map& map = *check_map(l, 1);
638     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
639 
640     Chest::OpeningMethod opening_method = entity_creation_check_enum<Chest::OpeningMethod>(
641         l,
642         1,
643         data,
644         "opening_method",
645         Chest::opening_method_names
646     );
647 
648     // Check the value of opening_condition depending on the opening method.
649     Game& game = map.get_game();
650     const std::string& opening_condition = data.get_string("opening_condition");
651     if (opening_method == Chest::OpeningMethod::BY_INTERACTION_IF_SAVEGAME_VARIABLE) {
652       entity_creation_check_savegame_variable_mandatory(l, 1, data, "opening_condition");
653     }
654     else if (opening_method == Chest::OpeningMethod::BY_INTERACTION_IF_ITEM) {
655       if (!game.get_equipment().item_exists(opening_condition)) {
656         LuaTools::arg_error(l, 1, "Bad field 'opening_condition' (no such equipment item: '"
657             + opening_condition + "')"
658         );
659       }
660       EquipmentItem& item = game.get_equipment().get_item(opening_condition);
661       if (!item.is_saved()) {
662         LuaTools::arg_error(l, 1, "Bad field 'opening_condition' (equipment item '"
663             + opening_condition + "' is not saved)"
664         );
665       }
666     }
667 
668     std::shared_ptr<Chest> chest = std::make_shared<Chest>(
669         data.get_name(),
670         entity_creation_check_layer(l, 1, data, map),
671         data.get_xy(),
672         data.get_string("sprite"),
673         Treasure(
674             game,
675             data.get_string("treasure_name"),
676             data.get_integer("treasure_variant"),
677             entity_creation_check_savegame_variable_optional(l, 1, data, "treasure_savegame_variable")
678         )
679     );
680     chest->set_opening_method(opening_method);
681     chest->set_opening_condition(opening_condition);
682     chest->set_opening_condition_consumed(data.get_boolean("opening_condition_consumed"));
683     chest->set_cannot_open_dialog_id(data.get_string("cannot_open_dialog"));
684     chest->set_user_properties(data.get_user_properties());
685     chest->set_enabled(data.is_enabled_at_start());
686     map.get_entities().add_entity(chest);
687     if (map.is_started()) {
688       push_entity(l, *chest);
689       return 1;
690     }
691     return 0;
692   });
693 }
694 
695 /**
696  * \brief Creates a jumper on the map.
697  * \param l The Lua context that is calling this function.
698  * \return Number of values to return to Lua.
699  */
l_create_jumper(lua_State * l)700 int LuaContext::l_create_jumper(lua_State* l) {
701 
702   return state_boundary_handle(l, [&] {
703     Map& map = *check_map(l, 1);
704     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
705 
706     EntityPtr entity = std::make_shared<Jumper>(
707         data.get_name(),
708         entity_creation_check_layer(l, 1, data, map),
709         data.get_xy(),
710         entity_creation_check_size(l, 1, data),
711         data.get_integer("direction"),
712         data.get_integer("jump_length")
713     );
714     entity->set_user_properties(data.get_user_properties());
715     entity->set_enabled(data.is_enabled_at_start());
716     map.get_entities().add_entity(entity);
717     if (map.is_started()) {
718       push_entity(l, *entity);
719       return 1;
720     }
721     return 0;
722   });
723 }
724 
725 /**
726  * \brief Creates an enemy on the map.
727  * \param l The Lua context that is calling this function.
728  * \return Number of values to return to Lua.
729  */
l_create_enemy(lua_State * l)730 int LuaContext::l_create_enemy(lua_State* l) {
731 
732   return state_boundary_handle(l, [&] {
733     Map& map = *check_map(l, 1);
734     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
735     Game& game = map.get_game();
736     EntityPtr entity = Enemy::create(
737         game,
738         data.get_string("breed"),
739         entity_creation_check_savegame_variable_optional(l, 1, data, "savegame_variable"),
740         data.get_name(),
741         entity_creation_check_layer(l, 1, data, map),
742         data.get_xy(),
743         data.get_integer("direction"),
744         Treasure(
745             game,
746             data.get_string("treasure_name"),
747             data.get_integer("treasure_variant"),
748             entity_creation_check_savegame_variable_optional(l, 1, data, "treasure_savegame_variable")
749         )
750     );
751     if (entity == nullptr) {
752       lua_pushnil(l);
753       return 1;
754     }
755     entity->set_user_properties(data.get_user_properties());
756     entity->set_enabled(data.is_enabled_at_start());
757     map.get_entities().add_entity(entity);
758     if (map.is_started()) {
759       push_entity(l, *entity);
760       return 1;
761     }
762     return 0;
763   });
764 }
765 
766 /**
767  * \brief Creates an NPC on the map.
768  * \param l The Lua context that is calling this function.
769  * \return Number of values to return to Lua.
770  */
l_create_npc(lua_State * l)771 int LuaContext::l_create_npc(lua_State* l) {
772 
773   return state_boundary_handle(l, [&] {
774     Map& map = *check_map(l, 1);
775     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
776 
777     Game& game = map.get_game();
778     EntityPtr entity = std::make_shared<Npc>(
779         game,
780         data.get_name(),
781         entity_creation_check_layer(l, 1, data, map),
782         data.get_xy(),
783         Npc::Subtype(data.get_integer("subtype")),
784         data.get_string("sprite"),
785         data.get_integer("direction"),
786         data.get_string("behavior")
787     );
788     entity->set_user_properties(data.get_user_properties());
789     entity->set_enabled(data.is_enabled_at_start());
790     map.get_entities().add_entity(entity);
791     if (map.is_started()) {
792       push_entity(l, *entity);
793       return 1;
794     }
795     return 0;
796   });
797 }
798 
799 /**
800  * \brief Creates a block on the map.
801  * \param l The Lua context that is calling this function.
802  * \return Number of values to return to Lua.
803  */
l_create_block(lua_State * l)804 int LuaContext::l_create_block(lua_State* l) {
805 
806   return state_boundary_handle(l, [&] {
807     Map& map = *check_map(l, 1);
808     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
809 
810     int max_moves = data.get_integer("max_moves");
811     if (max_moves < -1) {  // -1 means unset here.
812       std::ostringstream oss;
813       oss << "Invalid max_moves (should be 0, positive or nil): " << max_moves;
814       LuaTools::arg_error(l, 1, oss.str());
815     }
816 
817     // Deprecated version.
818     int maximum_moves = data.get_integer("maximum_moves");
819     if (maximum_moves != -1) {
820       if (maximum_moves < 0 || maximum_moves > 2) {
821         std::ostringstream oss;
822         oss << "Invalid maximum_moves (should be 0, 1 or 2): " << maximum_moves;
823         LuaTools::arg_error(l, 1, oss.str());
824       }
825       if (max_moves != -1) {
826         LuaTools::arg_error(l, 1, "Only one of max_moves and maximum_moves can be set");
827       }
828       if (maximum_moves == 2) {
829         // Replace the old special value 2 by the new proper value to mean unlimited.
830         maximum_moves = -1;
831       }
832       max_moves = maximum_moves;
833     }
834 
835     std::shared_ptr<Block> entity = std::make_shared<Block>(
836         data.get_name(),
837         entity_creation_check_layer(l, 1, data, map),
838         data.get_xy(),
839         data.get_integer("direction"),
840         data.get_string("sprite"),
841         data.get_boolean("pushable"),
842         data.get_boolean("pullable"),
843         max_moves
844     );
845     entity->set_user_properties(data.get_user_properties());
846     entity->set_enabled(data.is_enabled_at_start());
847     map.get_entities().add_entity(entity);
848     if (map.is_started()) {
849       push_entity(l, *entity);
850       return 1;
851     }
852     return 0;
853   });
854 }
855 
856 /**
857  * \brief Creates a dynamic tile on the map.
858  * \param l The Lua context that is calling this function.
859  * \return Number of values to return to Lua.
860  */
l_create_dynamic_tile(lua_State * l)861 int LuaContext::l_create_dynamic_tile(lua_State* l) {
862 
863   return state_boundary_handle(l, [&] {
864     Map& map = *check_map(l, 1);
865     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
866 
867     const std::string& pattern_id = data.get_string("pattern");
868     const std::string& tileset_id = data.get_string("tileset");
869     const Tileset* tileset = nullptr;
870     std::shared_ptr<TilePattern> pattern = nullptr;
871     if (!tileset_id.empty()) {
872       ResourceProvider& resource_provider = map.get_game().get_resource_provider();
873       tileset = &resource_provider.get_tileset(tileset_id);
874       pattern = tileset->get_tile_pattern(pattern_id);
875       if (pattern == nullptr) {
876         LuaTools::error(l, "No such pattern in tileset '" + tileset_id + "': '" + pattern_id + "'");
877       }
878     } else {
879       // Use the tileset of the map.
880       pattern = map.get_tileset().get_tile_pattern(pattern_id);
881       if (pattern == nullptr) {
882         LuaTools::error(l, "No such pattern in tileset '" + map.get_tileset_id() + "': '" + pattern_id + "'");
883       }
884     }
885 
886     EntityPtr entity = std::make_shared<DynamicTile>(
887         data.get_name(),
888         entity_creation_check_layer(l, 1, data, map),
889         data.get_xy(),
890         entity_creation_check_size(l, 1, data),
891         pattern_id,
892         pattern,
893         tileset
894     );
895     entity->set_user_properties(data.get_user_properties());
896     entity->set_enabled(data.is_enabled_at_start());
897     map.get_entities().add_entity(entity);
898     if (map.is_started()) {
899       push_entity(l, *entity);
900       return 1;
901     }
902     return 0;
903   });
904 }
905 
906 /**
907  * \brief Creates a switch on the map.
908  * \param l The Lua context that is calling this function.
909  * \return Number of values to return to Lua.
910  */
l_create_switch(lua_State * l)911 int LuaContext::l_create_switch(lua_State* l) {
912 
913   return state_boundary_handle(l, [&] {
914     Map& map = *check_map(l, 1);
915     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
916 
917     EntityPtr entity = std::make_shared<Switch>(
918         data.get_name(),
919         entity_creation_check_layer(l, 1, data, map),
920         data.get_xy(),
921         entity_creation_check_enum<Switch::Subtype>(l, 1, data, "subtype", Switch::subtype_names),
922         data.get_string("sprite"),
923         data.get_string("sound"),
924         data.get_boolean("needs_block"),
925         data.get_boolean("inactivate_when_leaving")
926     );
927     entity->set_user_properties(data.get_user_properties());
928     entity->set_enabled(data.is_enabled_at_start());
929     map.get_entities().add_entity(entity);
930     if (map.is_started()) {
931       push_entity(l, *entity);
932       return 1;
933     }
934     return 0;
935   });
936 }
937 
938 /**
939  * \brief Creates a wall on the map.
940  * \param l The Lua context that is calling this function.
941  * \return Number of values to return to Lua.
942  */
l_create_wall(lua_State * l)943 int LuaContext::l_create_wall(lua_State* l) {
944 
945   return state_boundary_handle(l, [&] {
946     Map& map = *check_map(l, 1);
947     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
948 
949     EntityPtr entity = std::make_shared<Wall>(
950         data.get_name(),
951         entity_creation_check_layer(l, 1, data, map),
952         data.get_xy(),
953         entity_creation_check_size(l, 1, data),
954         data.get_boolean("stops_hero"),
955         data.get_boolean("stops_enemies"),
956         data.get_boolean("stops_npcs"),
957         data.get_boolean("stops_blocks"),
958         data.get_boolean("stops_projectiles")
959     );
960     entity->set_user_properties(data.get_user_properties());
961     entity->set_enabled(data.is_enabled_at_start());
962     map.get_entities().add_entity(entity);
963     if (map.is_started()) {
964       push_entity(l, *entity);
965       return 1;
966     }
967     return 0;
968   });
969 }
970 
971 /**
972  * \brief Creates a sensor on the map.
973  * \param l The Lua context that is calling this function.
974  * \return Number of values to return to Lua.
975  */
l_create_sensor(lua_State * l)976 int LuaContext::l_create_sensor(lua_State* l) {
977 
978   return state_boundary_handle(l, [&] {
979     Map& map = *check_map(l, 1);
980     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
981 
982     EntityPtr entity = std::make_shared<Sensor>(
983         data.get_name(),
984         entity_creation_check_layer(l, 1, data, map),
985         data.get_xy(),
986         entity_creation_check_size(l, 1, data)
987     );
988     entity->set_user_properties(data.get_user_properties());
989     entity->set_enabled(data.is_enabled_at_start());
990     map.get_entities().add_entity(entity);
991     if (map.is_started()) {
992       push_entity(l, *entity);
993       return 1;
994     }
995     return 0;
996   });
997 }
998 
999 /**
1000  * \brief Creates a crystal on the map.
1001  * \param l The Lua context that is calling this function.
1002  * \return Number of values to return to Lua.
1003  */
l_create_crystal(lua_State * l)1004 int LuaContext::l_create_crystal(lua_State* l) {
1005 
1006   return state_boundary_handle(l, [&] {
1007     Map& map = *check_map(l, 1);
1008     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1009 
1010     EntityPtr entity = std::make_shared<Crystal>(
1011         data.get_name(),
1012         entity_creation_check_layer(l, 1, data, map),
1013         data.get_xy()
1014     );
1015     entity->set_user_properties(data.get_user_properties());
1016     entity->set_enabled(data.is_enabled_at_start());
1017     map.get_entities().add_entity(entity);
1018     if (map.is_started()) {
1019       push_entity(l, *entity);
1020       return 1;
1021     }
1022     return 0;
1023   });
1024 }
1025 
1026 /**
1027  * \brief Creates a crystal block on the map.
1028  * \param l The Lua context that is calling this function.
1029  * \return Number of values to return to Lua.
1030  */
l_create_crystal_block(lua_State * l)1031 int LuaContext::l_create_crystal_block(lua_State* l) {
1032 
1033   return state_boundary_handle(l, [&] {
1034     Map& map = *check_map(l, 1);
1035     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1036 
1037     Game& game = map.get_game();
1038     EntityPtr entity = std::make_shared<CrystalBlock>(
1039         game,
1040         data.get_name(),
1041         entity_creation_check_layer(l, 1, data, map),
1042         data.get_xy(),
1043         entity_creation_check_size(l, 1, data),
1044         CrystalBlock::Subtype(data.get_integer("subtype"))
1045     );
1046     entity->set_user_properties(data.get_user_properties());
1047     entity->set_enabled(data.is_enabled_at_start());
1048     map.get_entities().add_entity(entity);
1049     if (map.is_started()) {
1050       push_entity(l, *entity);
1051       return 1;
1052     }
1053     return 0;
1054   });
1055 }
1056 
1057 /**
1058  * \brief Creates a shop treasure on the map.
1059  * \param l The Lua context that is calling this function.
1060  * \return Number of values to return to Lua.
1061  */
l_create_shop_treasure(lua_State * l)1062 int LuaContext::l_create_shop_treasure(lua_State* l) {
1063 
1064   return state_boundary_handle(l, [&] {
1065     Map& map = *check_map(l, 1);
1066     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1067 
1068     Game& game = map.get_game();
1069     EntityPtr entity = ShopTreasure::create(
1070         game,
1071         data.get_name(),
1072         entity_creation_check_layer(l, 1, data, map),
1073         data.get_xy(),
1074         Treasure(
1075             game,
1076             data.get_string("treasure_name"),
1077             data.get_integer("treasure_variant"),
1078             entity_creation_check_savegame_variable_optional(l, 1, data, "treasure_savegame_variable")
1079         ),
1080         data.get_integer("price"),
1081         data.get_string("font"),
1082         data.get_string("dialog")
1083     );
1084     if (entity == nullptr) {
1085       lua_pushnil(l);
1086       return 1;
1087     }
1088 
1089     entity->set_user_properties(data.get_user_properties());
1090     entity->set_enabled(data.is_enabled_at_start());
1091     map.get_entities().add_entity(entity);
1092     if (map.is_started()) {
1093       push_entity(l, *entity);
1094       return 1;
1095     }
1096     return 0;
1097   });
1098 }
1099 
1100 /**
1101  * \brief Creates a stream on the map.
1102  * \param l The Lua context that is calling this function.
1103  * \return Number of values to return to Lua.
1104  */
l_create_stream(lua_State * l)1105 int LuaContext::l_create_stream(lua_State* l) {
1106 
1107   return state_boundary_handle(l, [&] {
1108     Map& map = *check_map(l, 1);
1109     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1110 
1111     std::shared_ptr<Stream> stream = std::make_shared<Stream>(
1112         data.get_name(),
1113         entity_creation_check_layer(l, 1, data, map),
1114         data.get_xy(),
1115         data.get_integer("direction"),
1116         data.get_string("sprite")
1117     );
1118     stream->set_speed(data.get_integer("speed"));
1119     stream->set_allow_movement(data.get_boolean("allow_movement"));
1120     stream->set_allow_attack(data.get_boolean("allow_attack"));
1121     stream->set_allow_item(data.get_boolean("allow_item"));
1122     stream->set_user_properties(data.get_user_properties());
1123     stream->set_enabled(data.is_enabled_at_start());
1124     map.get_entities().add_entity(stream);
1125     if (map.is_started()) {
1126       push_stream(l, *stream);
1127       return 1;
1128     }
1129     return 0;
1130   });
1131 }
1132 
1133 /**
1134  * \brief Creates a door on the map.
1135  * \param l The Lua context that is calling this function.
1136  * \return Number of values to return to Lua.
1137  */
l_create_door(lua_State * l)1138 int LuaContext::l_create_door(lua_State* l) {
1139 
1140   return state_boundary_handle(l, [&] {
1141     Map& map = *check_map(l, 1);
1142     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1143 
1144     Door::OpeningMethod opening_method = entity_creation_check_enum<Door::OpeningMethod>(
1145         l,
1146         1,
1147         data,
1148         "opening_method",
1149         Door::opening_method_names
1150     );
1151 
1152     // Check the value of opening_condition depending on the opening method.
1153     Game& game = map.get_game();
1154     const std::string& opening_condition = data.get_string("opening_condition");
1155     if (opening_method == Door::OpeningMethod::BY_INTERACTION_IF_SAVEGAME_VARIABLE) {
1156       entity_creation_check_savegame_variable_mandatory(l, 1, data, "opening_condition");
1157     }
1158     else if (opening_method == Door::OpeningMethod::BY_INTERACTION_IF_ITEM) {
1159       if (!game.get_equipment().item_exists(opening_condition)) {
1160         LuaTools::arg_error(l, 1, "Bad field 'opening_condition' (no such equipment item: '"
1161             + opening_condition + "')"
1162         );
1163       }
1164       EquipmentItem& item = game.get_equipment().get_item(opening_condition);
1165       if (!item.is_saved()) {
1166         LuaTools::arg_error(l, 1, "Bad field 'opening_condition' (equipment item '"
1167             + opening_condition + "' is not saved)"
1168         );
1169       }
1170     }
1171     std::shared_ptr<Door> door = std::make_shared<Door>(
1172         game,
1173         data.get_name(),
1174         entity_creation_check_layer(l, 1, data, map),
1175         data.get_xy(),
1176         data.get_integer("direction"),
1177         data.get_string("sprite"),
1178         entity_creation_check_savegame_variable_optional(l, 1, data, "savegame_variable")
1179     );
1180     door->set_opening_method(opening_method);
1181     door->set_opening_condition(opening_condition);
1182     door->set_opening_condition_consumed(data.get_boolean("opening_condition_consumed"));
1183     door->set_cannot_open_dialog_id(data.get_string("cannot_open_dialog"));
1184     door->set_user_properties(data.get_user_properties());
1185     door->set_enabled(data.is_enabled_at_start());
1186     map.get_entities().add_entity(door);
1187     if (map.is_started()) {
1188       push_entity(l, *door);
1189       return 1;
1190     }
1191     return 0;
1192   });
1193 }
1194 
1195 /**
1196  * \brief Creates stairs on the map.
1197  * \param l The Lua context that is calling this function.
1198  * \return Number of values to return to Lua.
1199  */
l_create_stairs(lua_State * l)1200 int LuaContext::l_create_stairs(lua_State* l) {
1201 
1202   return state_boundary_handle(l, [&] {
1203     Map& map = *check_map(l, 1);
1204     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1205 
1206     EntityPtr entity = std::make_shared<Stairs>(
1207         data.get_name(),
1208         entity_creation_check_layer(l, 1, data, map),
1209         data.get_xy(),
1210         data.get_integer("direction"),
1211         Stairs::Subtype(data.get_integer("subtype"))
1212     );
1213     entity->set_user_properties(data.get_user_properties());
1214     entity->set_enabled(data.is_enabled_at_start());
1215     map.get_entities().add_entity(entity);
1216     if (map.is_started()) {
1217       push_entity(l, *entity);
1218       return 1;
1219     }
1220     return 0;
1221   });
1222 }
1223 
1224 /**
1225  * \brief Creates a separator on the map.
1226  * \param l The Lua context that is calling this function.
1227  * \return Number of values to return to Lua.
1228  */
l_create_separator(lua_State * l)1229 int LuaContext::l_create_separator(lua_State* l) {
1230 
1231   return state_boundary_handle(l, [&] {
1232     Map& map = *check_map(l, 1);
1233     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1234 
1235     EntityPtr entity = std::make_shared<Separator>(
1236         data.get_name(),
1237         entity_creation_check_layer(l, 1, data, map),
1238         data.get_xy(),
1239         entity_creation_check_size(l, 1, data)
1240     );
1241     entity->set_user_properties(data.get_user_properties());
1242     entity->set_enabled(data.is_enabled_at_start());
1243     map.get_entities().add_entity(entity);
1244     if (map.is_started()) {
1245       push_entity(l, *entity);
1246       return 1;
1247     }
1248     return 0;
1249   });
1250 }
1251 
1252 /**
1253  * \brief Creates a custom entity on the map.
1254  * \param l The Lua context that is calling this function.
1255  * \return Number of values to return to Lua.
1256  */
l_create_custom_entity(lua_State * l)1257 int LuaContext::l_create_custom_entity(lua_State* l) {
1258 
1259   return state_boundary_handle(l, [&] {
1260     Map& map = *check_map(l, 1);
1261     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1262 
1263     Game& game = map.get_game();
1264     EntityPtr entity = std::make_shared<CustomEntity>(
1265         game,
1266         data.get_name(),
1267         data.get_integer("direction"),
1268         entity_creation_check_layer(l, 1, data, map),
1269         data.get_xy(),
1270         entity_creation_check_size(l, 1, data),
1271         Point(data.get_integer("origin_x"), data.get_integer("origin_y")),
1272         data.get_string("sprite"),
1273         data.get_string("model")
1274     );
1275     entity->set_tiled(data.get_boolean("tiled"));
1276     entity->set_user_properties(data.get_user_properties());
1277     entity->set_enabled(data.is_enabled_at_start());
1278     map.get_entities().add_entity(entity);
1279     if (map.is_started()) {
1280       push_entity(l, *entity);
1281       return 1;
1282     }
1283     return 0;
1284   });
1285 }
1286 
1287 /**
1288  * \brief Creates a bomb on the map.
1289  * \param l The Lua context that is calling this function.
1290  * \return Number of values to return to Lua.
1291  */
l_create_bomb(lua_State * l)1292 int LuaContext::l_create_bomb(lua_State* l) {
1293 
1294   return state_boundary_handle(l, [&] {
1295     Map& map = *check_map(l, 1);
1296     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1297 
1298     EntityPtr entity = std::make_shared<Bomb>(
1299         data.get_name(),
1300         entity_creation_check_layer(l, 1, data, map),
1301         data.get_xy()
1302     );
1303     entity->set_user_properties(data.get_user_properties());
1304     entity->set_enabled(data.is_enabled_at_start());
1305     map.get_entities().add_entity(entity);
1306     if (map.is_started()) {
1307       push_entity(l, *entity);
1308       return 1;
1309     }
1310     return 0;
1311   });
1312 }
1313 
1314 /**
1315  * \brief Creates an explosion on the map.
1316  * \param l The Lua context that is calling this function.
1317  * \return Number of values to return to Lua.
1318  */
l_create_explosion(lua_State * l)1319 int LuaContext::l_create_explosion(lua_State* l) {
1320 
1321   return state_boundary_handle(l, [&] {
1322     Map& map = *check_map(l, 1);
1323     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1324 
1325     const bool with_damage = true;
1326     EntityPtr entity = std::make_shared<Explosion>(
1327         data.get_name(),
1328         entity_creation_check_layer(l, 1, data, map),
1329         data.get_xy(),
1330         with_damage
1331     );
1332     entity->set_user_properties(data.get_user_properties());
1333     entity->set_enabled(data.is_enabled_at_start());
1334     map.get_entities().add_entity(entity);
1335     if (map.is_started()) {
1336       push_entity(l, *entity);
1337       return 1;
1338     }
1339     return 0;
1340   });
1341 }
1342 
1343 /**
1344  * \brief Creates a fire entity on the map.
1345  * \param l The Lua context that is calling this function.
1346  * \return Number of values to return to Lua.
1347  */
l_create_fire(lua_State * l)1348 int LuaContext::l_create_fire(lua_State* l) {
1349 
1350   return state_boundary_handle(l, [&] {
1351     Map& map = *check_map(l, 1);
1352     EntityData& data = *(static_cast<EntityData*>(lua_touserdata(l, 2)));
1353 
1354     EntityPtr entity = std::make_shared<Fire>(
1355         data.get_name(),
1356         entity_creation_check_layer(l, 1, data, map),
1357         data.get_xy()
1358     );
1359     entity->set_user_properties(data.get_user_properties());
1360     entity->set_enabled(data.is_enabled_at_start());
1361     map.get_entities().add_entity(entity);
1362     if (map.is_started()) {
1363       push_entity(l, *entity);
1364       return 1;
1365     }
1366     return 0;
1367   });
1368 }
1369 
1370 const std::map<EntityType, lua_CFunction> LuaContext::entity_creation_functions = {
1371     { EntityType::TILE, LuaContext::l_create_tile },
1372     { EntityType::DESTINATION, LuaContext::l_create_destination },
1373     { EntityType::TELETRANSPORTER, LuaContext::l_create_teletransporter },
1374     { EntityType::PICKABLE, LuaContext::l_create_pickable },
1375     { EntityType::DESTRUCTIBLE, LuaContext::l_create_destructible },
1376     { EntityType::CHEST, LuaContext::l_create_chest },
1377     { EntityType::JUMPER, LuaContext::l_create_jumper },
1378     { EntityType::ENEMY, LuaContext::l_create_enemy },
1379     { EntityType::NPC, LuaContext::l_create_npc },
1380     { EntityType::BLOCK, LuaContext::l_create_block },
1381     { EntityType::DYNAMIC_TILE, LuaContext::l_create_dynamic_tile },
1382     { EntityType::SWITCH, LuaContext::l_create_switch },
1383     { EntityType::WALL, LuaContext::l_create_wall },
1384     { EntityType::SENSOR, LuaContext::l_create_sensor },
1385     { EntityType::CRYSTAL, LuaContext::l_create_crystal },
1386     { EntityType::CRYSTAL_BLOCK, LuaContext::l_create_crystal_block },
1387     { EntityType::SHOP_TREASURE, LuaContext::l_create_shop_treasure },
1388     { EntityType::STREAM, LuaContext::l_create_stream },
1389     { EntityType::DOOR, LuaContext::l_create_door },
1390     { EntityType::STAIRS, LuaContext::l_create_stairs },
1391     { EntityType::SEPARATOR, LuaContext::l_create_separator },
1392     { EntityType::CUSTOM, LuaContext::l_create_custom_entity },
1393     { EntityType::EXPLOSION, LuaContext::l_create_explosion },
1394     { EntityType::BOMB, LuaContext::l_create_bomb },
1395     { EntityType::FIRE, LuaContext::l_create_fire },
1396 };
1397 
1398 /**
1399  * \brief Creates on the current map an entity from the specified data.
1400  *
1401  * Pushes onto the Lua stack the created entity.
1402  * In case of error, pushes nothing and returns \c false.
1403  *
1404  * \param map The map where to create an entity.
1405  * \param entity_data Description of the entity to create.
1406  * \return \c true if the entity was successfully created.
1407  */
create_map_entity_from_data(Map & map,const EntityData & entity_data)1408 bool LuaContext::create_map_entity_from_data(Map& map, const EntityData& entity_data) {
1409 
1410   const std::string& type_name = enum_to_name(entity_data.get_type());
1411   std::string function_name = "create_" + type_name;
1412   const auto& it = entity_creation_functions.find(entity_data.get_type());
1413   Debug::check_assertion(it != entity_creation_functions.end(),
1414       "Missing entity creation function for type '" + type_name + "'"
1415   );
1416   lua_CFunction function = it->second;
1417 
1418   lua_pushcfunction(current_l, function);
1419   push_map(current_l, map);
1420   lua_pushlightuserdata(current_l, const_cast<EntityData*>(&entity_data));
1421   return call_function(2, 1, function_name.c_str());
1422 }
1423 
1424 /**
1425  * \brief __index function of the environment of the map's code.
1426  *
1427  * This special __index function allows the map's Lua code to get a map
1428  * entity like a global value.
1429  * If an entity exists with the specified name, this entity is returned.
1430  * Otherwise, we fall back to the usual behavior of global values:
1431  * a global value with this name (or \c nil) is returned.
1432  *
1433  * \param l The Lua context that is calling this function.
1434  * \return Number of values to return to Lua.
1435  */
l_get_map_entity_or_global(lua_State * l)1436 int LuaContext::l_get_map_entity_or_global(lua_State* l) {
1437 
1438   return state_boundary_handle(l, [&] {
1439     lua_pushvalue(l, lua_upvalueindex(1));  // Because check_map does not like pseudo-indexes.
1440     Map& map = *check_map(l, -1);
1441     const std::string& name = LuaTools::check_string(l, 2);
1442 
1443     EntityPtr entity = nullptr;
1444     if (map.is_started()) {
1445       entity = map.get_entities().find_entity(name);
1446     }
1447 
1448     if (entity != nullptr && !entity->is_being_removed()) {
1449       push_entity(l, *entity);
1450     }
1451     else {
1452       lua_getglobal(l, name.c_str());
1453     }
1454     return 1;
1455   });
1456 }
1457 
1458 /**
1459  * \brief __index function of the easy environment for the console.
1460  *
1461  * See do_string_with_easy_env() for more details.
1462  *
1463  * \param l The Lua context that is calling this function.
1464  * \return Number of values to return to Lua.
1465  */
l_easy_index(lua_State * l)1466 int LuaContext::l_easy_index(lua_State* l) {
1467 
1468   return state_boundary_handle(l, [&] {
1469 
1470     const std::string& name = LuaTools::check_string(l, 2);
1471 
1472     LuaContext& lua_context = get();
1473     Game* game = lua_context.get_main_loop().get_game();
1474 
1475     if (game != nullptr) {
1476       // A game is running.
1477       if (name == "game") {
1478         push_game(l, game->get_savegame());
1479         return 1;
1480       }
1481 
1482       if (game->has_current_map()) {
1483         Map& map = game->get_current_map();
1484         if (name == "map") {
1485           push_map(l, map);
1486           return 1;
1487         }
1488 
1489         if (name == "tp") {
1490           push_hero(l, *game->get_hero());
1491           lua_pushcclosure(l, l_hero_teleport, 1);
1492           return 1;
1493         }
1494 
1495         EntityPtr entity = map.get_entities().find_entity(name);
1496         if (entity != nullptr && !entity->is_being_removed()) {
1497           push_entity(l, *entity);
1498           return 1;
1499         }
1500       }
1501     }
1502 
1503     lua_getglobal(l, name.c_str());
1504     return 1;
1505   });
1506 }
1507 
1508 /**
1509  * \brief Like hero:teleport(), but the hero is passed as an upvalue.
1510  * \param l The Lua context that is calling this function.
1511  * \return Number of values to return to Lua.
1512  */
l_hero_teleport(lua_State * l)1513 int LuaContext::l_hero_teleport(lua_State* l) {
1514 
1515   return state_boundary_handle(l, [&] {
1516     lua_pushvalue(l, lua_upvalueindex(1));
1517     Hero& hero = *check_hero(l, -1);
1518     lua_pop(l, 1);
1519     Game& game = hero.get_game();
1520     const std::string& map_id = LuaTools::check_string(l, 1);
1521     const std::string& destination_name = LuaTools::opt_string(l, 2, "");
1522     Transition::Style transition_style = LuaTools::opt_enum<Transition::Style>(
1523         l, 3, game.get_default_transition_style());
1524 
1525     if (!CurrentQuest::resource_exists(ResourceType::MAP, map_id)) {
1526       LuaTools::arg_error(l, 2, std::string("No such map: '") + map_id + "'");
1527     }
1528 
1529     game.set_current_map(map_id, destination_name, transition_style);
1530 
1531     return 0;
1532   });
1533 }
1534 
1535 /**
1536  * \brief Closure of an iterator over a list of entities.
1537  *
1538  * This closure expects 3 upvalues in this order:
1539  * - The array of entities.
1540  * - The size of the array (for performance).
1541  * - The current index in the array.
1542  *
1543  * \param l The Lua context that is calling this function.
1544  * \return Number of values to return to Lua.
1545  */
l_entity_iterator_next(lua_State * l)1546 int LuaContext::l_entity_iterator_next(lua_State* l) {
1547 
1548   return state_boundary_handle(l, [&] {
1549 
1550     // Get upvalues.
1551     const int table_index = lua_upvalueindex(1);
1552     const int size = lua_tointeger(l, lua_upvalueindex(2));
1553     int index = lua_tointeger(l, lua_upvalueindex(3));
1554 
1555     if (index > size) {
1556       // Finished.
1557       return 0;
1558     }
1559 
1560     // Get the next value.
1561     lua_rawgeti(l, table_index, index);
1562 
1563     // Increment index.
1564     ++index;
1565     lua_pushinteger(l, index);
1566     lua_replace(l, lua_upvalueindex(3));
1567 
1568     return 1;
1569   });
1570 }
1571 
1572 /**
1573  * \brief Generates a Lua error if a map is not in an existing game.
1574  * \param l A Lua context.
1575  * \param map The map to check.
1576  */
check_map_has_game(lua_State * l,const Map & map)1577 void LuaContext::check_map_has_game(lua_State* l, const Map& map) {
1578 
1579   if (!map.is_game_running()) {
1580     // Return nil if the game is already destroyed.
1581     LuaTools::error(l, "The game of this map is no longer running");
1582   }
1583 }
1584 
1585 /**
1586  * \brief Implementation of map:get_game().
1587  * \param l The Lua context that is calling this function.
1588  * \return Number of values to return to Lua.
1589  */
map_api_get_game(lua_State * l)1590 int LuaContext::map_api_get_game(lua_State* l) {
1591 
1592   return state_boundary_handle(l, [&] {
1593     Map& map = *check_map(l, 1);
1594 
1595     push_game(l, *map.get_savegame());
1596     return 1;
1597   });
1598 }
1599 
1600 /**
1601  * \brief Implementation of map:get_id().
1602  * \param l The Lua context that is calling this function.
1603  * \return Number of values to return to Lua.
1604  */
map_api_get_id(lua_State * l)1605 int LuaContext::map_api_get_id(lua_State* l) {
1606 
1607   return state_boundary_handle(l, [&] {
1608     const Map& map = *check_map(l, 1);
1609 
1610     push_string(l, map.get_id());
1611     return 1;
1612   });
1613 }
1614 
1615 /**
1616  * \brief Implementation of map:get_world().
1617  * \param l The Lua context that is calling this function.
1618  * \return Number of values to return to Lua.
1619  */
map_api_get_world(lua_State * l)1620 int LuaContext::map_api_get_world(lua_State* l) {
1621 
1622   return state_boundary_handle(l, [&] {
1623     const Map& map = *check_map(l, 1);
1624 
1625     const std::string& world = map.get_world();
1626 
1627     if (world.empty()) {
1628       lua_pushnil(l);
1629     }
1630     else {
1631       push_string(l, world);
1632     }
1633     return 1;
1634   });
1635 }
1636 
1637 /**
1638  * \brief Implementation of map:set_world().
1639  * \param l The Lua context that is calling this function.
1640  * \return Number of values to return to Lua.
1641  */
map_api_set_world(lua_State * l)1642 int LuaContext::map_api_set_world(lua_State* l) {
1643 
1644   return state_boundary_handle(l, [&] {
1645     Map& map = *check_map(l, 1);
1646     std::string world;
1647     if (lua_type(l, 2) != LUA_TSTRING && lua_type(l, 2) != LUA_TNIL) {
1648       LuaTools::type_error(l, 2, "string or nil");
1649     }
1650     if (!lua_isnil(l, 2)) {
1651       world = LuaTools::check_string(l, 2);
1652     }
1653 
1654     map.set_world(world);
1655 
1656     return 0;
1657   });
1658 }
1659 
1660 /**
1661  * \brief Implementation of map:get_min_layer().
1662  * \param l The Lua context that is calling this function.
1663  * \return Number of values to return to Lua.
1664  */
map_api_get_min_layer(lua_State * l)1665 int LuaContext::map_api_get_min_layer(lua_State* l) {
1666 
1667   return state_boundary_handle(l, [&] {
1668     const Map& map = *check_map(l, 1);
1669 
1670     lua_pushinteger(l, map.get_min_layer());
1671     return 1;
1672   });
1673 }
1674 
1675 /**
1676  * \brief Implementation of map:get_max_layer().
1677  * \param l The Lua context that is calling this function.
1678  * \return Number of values to return to Lua.
1679  */
map_api_get_max_layer(lua_State * l)1680 int LuaContext::map_api_get_max_layer(lua_State* l) {
1681 
1682   return state_boundary_handle(l, [&] {
1683     const Map& map = *check_map(l, 1);
1684 
1685     lua_pushinteger(l, map.get_max_layer());
1686     return 1;
1687   });
1688 }
1689 
1690 /**
1691  * \brief Implementation of map:get_floor().
1692  * \param l The Lua context that is calling this function.
1693  * \return Number of values to return to Lua.
1694  */
map_api_get_floor(lua_State * l)1695 int LuaContext::map_api_get_floor(lua_State* l) {
1696 
1697   return state_boundary_handle(l, [&] {
1698     const Map& map = *check_map(l, 1);
1699 
1700     if (!map.has_floor()) {
1701       lua_pushnil(l);
1702     }
1703     else {
1704       lua_pushinteger(l, map.get_floor());
1705     }
1706     return 1;
1707   });
1708 }
1709 
1710 /**
1711  * \brief Implementation of map:set_floor().
1712  * \param l The Lua context that is calling this function.
1713  * \return Number of values to return to Lua.
1714  */
map_api_set_floor(lua_State * l)1715 int LuaContext::map_api_set_floor(lua_State* l) {
1716 
1717   return state_boundary_handle(l, [&] {
1718     Map& map = *check_map(l, 1);
1719     int floor = MapData::NO_FLOOR;
1720     if (lua_type(l, 2) != LUA_TNUMBER && lua_type(l, 2) != LUA_TNIL) {
1721       LuaTools::type_error(l, 2, "number or nil");
1722     }
1723     if (!lua_isnil(l, 2)) {
1724       floor = LuaTools::check_int(l, 2);
1725     }
1726 
1727     map.set_floor(floor);
1728 
1729     return 0;
1730   });
1731 }
1732 
1733 /**
1734  * \brief Implementation of map:get_size().
1735  * \param l the Lua context that is calling this function
1736  * \return number of values to return to Lua
1737  */
map_api_get_size(lua_State * l)1738 int LuaContext::map_api_get_size(lua_State* l) {
1739 
1740   return state_boundary_handle(l, [&] {
1741     const Map& map = *check_map(l, 1);
1742 
1743     lua_pushinteger(l, map.get_width());
1744     lua_pushinteger(l, map.get_height());
1745 
1746     return 2;
1747   });
1748 }
1749 
1750 /**
1751  * \brief Implementation of map:get_location().
1752  * \param l the Lua context that is calling this function
1753  * \return number of values to return to Lua
1754  */
map_api_get_location(lua_State * l)1755 int LuaContext::map_api_get_location(lua_State* l) {
1756 
1757   return state_boundary_handle(l, [&] {
1758     const Map& map = *check_map(l, 1);
1759 
1760     lua_pushinteger(l, map.get_location().get_x());
1761     lua_pushinteger(l, map.get_location().get_y());
1762 
1763     return 2;
1764   });
1765 }
1766 
1767 /**
1768  * \brief Implementation of map:get_tileset().
1769  * \param l The Lua context that is calling this function.
1770  * \return Number of values to return to Lua.
1771  */
map_api_get_tileset(lua_State * l)1772 int LuaContext::map_api_get_tileset(lua_State* l) {
1773 
1774   return state_boundary_handle(l, [&] {
1775     const Map& map = *check_map(l, 1);
1776 
1777     push_string(l, map.get_tileset_id());
1778     return 1;
1779   });
1780 }
1781 
1782 /**
1783  * \brief Implementation of map:get_music().
1784  * \param l The Lua context that is calling this function.
1785  * \return Number of values to return to Lua.
1786  */
map_api_get_music(lua_State * l)1787 int LuaContext::map_api_get_music(lua_State* l) {
1788 
1789   return state_boundary_handle(l, [&] {
1790     const Map& map = *check_map(l, 1);
1791 
1792     const std::string& music_id = map.get_music_id();
1793     if (music_id == Music::none) {
1794       // Special id to stop any music.
1795       lua_pushnil(l);
1796     }
1797     else if (music_id == Music::unchanged) {
1798       // Special id to keep the music unchanged.
1799       push_string(l, "same");
1800     }
1801     else {
1802       push_string(l, music_id);
1803     }
1804     return 1;
1805   });
1806 }
1807 
1808 /**
1809  * \brief Implementation of map:set_tileset().
1810  * \param l The Lua context that is calling this function.
1811  * \return Number of values to return to Lua.
1812  */
map_api_set_tileset(lua_State * l)1813 int LuaContext::map_api_set_tileset(lua_State* l) {
1814 
1815   return state_boundary_handle(l, [&] {
1816     Map& map = *check_map(l, 1);
1817     const std::string& tileset_id = LuaTools::check_string(l, 2);
1818 
1819     map.set_tileset(tileset_id);
1820 
1821     return 0;
1822   });
1823 }
1824 
1825 /**
1826  * \brief Implementation of map:get_camera().
1827  * \param l The Lua context that is calling this function.
1828  * \return Number of values to return to Lua.
1829  */
map_api_get_camera(lua_State * l)1830 int LuaContext::map_api_get_camera(lua_State* l) {
1831 
1832   return state_boundary_handle(l, [&] {
1833     Map& map = *check_map(l, 1);
1834 
1835     const CameraPtr& camera = map.get_camera();
1836     if (camera == nullptr) {
1837       lua_pushnil(l);
1838       return 1;
1839     }
1840 
1841     push_camera(l, *camera);
1842     return 1;
1843   });
1844 }
1845 
1846 /**
1847  * \brief Implementation of map:get_camera_position().
1848  * \param l The Lua context that is calling this function.
1849  * \return Number of values to return to Lua.
1850  */
map_api_get_camera_position(lua_State * l)1851 int LuaContext::map_api_get_camera_position(lua_State* l) {
1852 
1853   return state_boundary_handle(l, [&] {
1854 
1855     get().warning_deprecated(
1856         { 1, 5 },
1857         "map:get_camera_position()",
1858         "Use map:get_camera():get_bounding_box() instead.");
1859 
1860     const Map& map = *check_map(l, 1);
1861 
1862     const CameraPtr& camera = map.get_camera();
1863     if (camera == nullptr) {
1864       lua_pushnil(l);
1865       return 1;
1866     }
1867 
1868     const Rectangle& camera_position = camera->get_bounding_box();
1869 
1870     lua_pushinteger(l, camera_position.get_x());
1871     lua_pushinteger(l, camera_position.get_y());
1872     lua_pushinteger(l, camera_position.get_width());
1873     lua_pushinteger(l, camera_position.get_height());
1874     return 4;
1875   });
1876 }
1877 
1878 /**
1879  * \brief Implementation of map:move_camera().
1880  * \param l The Lua context that is calling this function.
1881  * \return Number of values to return to Lua.
1882  */
map_api_move_camera(lua_State * l)1883 int LuaContext::map_api_move_camera(lua_State* l) {
1884 
1885   return state_boundary_handle(l, [&] {
1886 
1887     LuaContext& lua_context = get();
1888     lua_context.warning_deprecated(
1889         { 1, 5 },
1890         "map:move_camera()",
1891         "Make a target movement on map:get_camera() instead.");
1892 
1893     check_map(l, 1);
1894     LuaTools::check_int(l, 2);
1895     LuaTools::check_int(l, 3);
1896     LuaTools::check_int(l, 4);
1897     LuaTools::check_type(l, 5, LUA_TFUNCTION);
1898     if (lua_gettop(l) >= 6) {
1899       LuaTools::check_int(l, 6);
1900     }
1901     if (lua_gettop(l) >= 7) {
1902       LuaTools::check_int(l, 7);
1903     }
1904     lua_settop(l, 7); // Make sure that we always have 7 arguments.
1905 
1906     lua_getfield(l, LUA_REGISTRYINDEX, "map.move_camera");
1907     if (!lua_isnil(l, -1)) {
1908       Debug::check_assertion(lua_isfunction(l, -1), "map:move_camera() is not a function");
1909       lua_insert(l, 1);
1910       lua_context.call_function(7, 0, "move_camera");
1911     }
1912 
1913     return 0;
1914   });
1915 }
1916 
1917 /**
1918  * \brief Implementation of map:get_ground().
1919  * \param l The Lua context that is calling this function.
1920  * \return Number of values to return to Lua.
1921  */
map_api_get_ground(lua_State * l)1922 int LuaContext::map_api_get_ground(lua_State* l) {
1923 
1924   return state_boundary_handle(l, [&] {
1925     Map& map = *check_map(l, 1);
1926     int x = LuaTools::check_int(l, 2);
1927     int y = LuaTools::check_int(l, 3);
1928     int layer = LuaTools::check_layer(l, 4, map);
1929 
1930     Ground ground = map.get_ground(layer, x, y, nullptr);
1931 
1932     push_string(l, enum_to_name(ground));
1933     return 1;
1934   });
1935 }
1936 
1937 /**
1938  * \brief Implementation of map:draw_visual().
1939  * \param l The Lua context that is calling this function.
1940  * \return Number of values to return to Lua.
1941  */
map_api_draw_visual(lua_State * l)1942 int LuaContext::map_api_draw_visual(lua_State* l) {
1943 
1944   return state_boundary_handle(l, [&] {
1945 
1946     Map& map = *check_map(l, 1);
1947     Drawable& drawable = *check_drawable(l, 2);
1948     int x = LuaTools::check_int(l, 3);
1949     int y = LuaTools::check_int(l, 4);
1950 
1951     map.draw_visual(drawable, x, y);
1952 
1953     return 0;
1954   });
1955 }
1956 
1957 /**
1958  * \brief Implementation of map:draw_sprite().
1959  * \param l The Lua context that is calling this function.
1960  * \return Number of values to return to Lua.
1961  */
map_api_draw_sprite(lua_State * l)1962 int LuaContext::map_api_draw_sprite(lua_State* l) {
1963 
1964   return state_boundary_handle(l, [&] {
1965 
1966     get().warning_deprecated(
1967         { 1, 5 },
1968         "map:draw_sprite()",
1969         "Use map:draw_visual() instead.");
1970 
1971     Map& map = *check_map(l, 1);
1972     Sprite& sprite = *check_sprite(l, 2);
1973     int x = LuaTools::check_int(l, 3);
1974     int y = LuaTools::check_int(l, 4);
1975 
1976     map.draw_visual(sprite, x, y);
1977 
1978     return 0;
1979   });
1980 }
1981 
1982 /**
1983  * \brief Implementation of map:get_crystal_state().
1984  * \param l The Lua context that is calling this function.
1985  * \return Number of values to return to Lua.
1986  */
map_api_get_crystal_state(lua_State * l)1987 int LuaContext::map_api_get_crystal_state(lua_State* l) {
1988 
1989   return state_boundary_handle(l, [&] {
1990     Map& map = *check_map(l, 1);
1991 
1992     lua_pushboolean(l, map.get_game().get_crystal_state());
1993     return 1;
1994   });
1995 }
1996 
1997 /**
1998  * \brief Implementation of map:set_crystal_state().
1999  * \param l The Lua context that is calling this function.
2000  * \return Number of values to return to Lua.
2001  */
map_api_set_crystal_state(lua_State * l)2002 int LuaContext::map_api_set_crystal_state(lua_State* l) {
2003 
2004   return state_boundary_handle(l, [&] {
2005     Map& map = *check_map(l, 1);
2006     bool state = LuaTools::check_boolean(l, 2);
2007 
2008     Game& game = map.get_game();
2009     if (game.get_crystal_state() != state) {
2010       game.change_crystal_state();
2011     }
2012 
2013     return 0;
2014   });
2015 }
2016 
2017 /**
2018  * \brief Implementation of map:change_crystal_state().
2019  * \param l The Lua context that is calling this function.
2020  * \return Number of values to return to Lua.
2021  */
map_api_change_crystal_state(lua_State * l)2022 int LuaContext::map_api_change_crystal_state(lua_State* l) {
2023 
2024   return state_boundary_handle(l, [&] {
2025     Map& map = *check_map(l, 1);
2026 
2027     map.get_game().change_crystal_state();
2028 
2029     return 0;
2030   });
2031 }
2032 
2033 /**
2034  * \brief Implementation of map:open_doors().
2035  * \param l The Lua context that is calling this function.
2036  * \return Number of values to return to Lua.
2037  */
map_api_open_doors(lua_State * l)2038 int LuaContext::map_api_open_doors(lua_State* l) {
2039 
2040   return state_boundary_handle(l, [&] {
2041     Map& map = *check_map(l, 1);
2042     const std::string& prefix = LuaTools::check_string(l, 2);
2043 
2044     bool done = false;
2045     Entities& entities = map.get_entities();
2046     const std::vector<EntityPtr>& doors = entities.get_entities_with_prefix(EntityType::DOOR, prefix);
2047     for (const EntityPtr& entity: doors) {
2048       Door& door = *std::static_pointer_cast<Door>(entity);
2049       if (!door.is_open() && !door.is_opening()) {
2050         door.open();
2051         done = true;
2052       }
2053     }
2054 
2055     // make sure the sound is played only once even if the script calls
2056     // this function repeatedly while the door is still changing
2057     if (done) {
2058       Sound::play("door_open");
2059     }
2060 
2061     return 0;
2062   });
2063 }
2064 
2065 /**
2066  * \brief Implementation of map:close_doors().
2067  * \param l The Lua context that is calling this function.
2068  * \return Number of values to return to Lua.
2069  */
map_api_close_doors(lua_State * l)2070 int LuaContext::map_api_close_doors(lua_State* l) {
2071 
2072   return state_boundary_handle(l, [&] {
2073     Map& map = *check_map(l, 1);
2074     const std::string& prefix = LuaTools::check_string(l, 2);
2075 
2076     bool done = false;
2077     Entities& entities = map.get_entities();
2078     const std::vector<EntityPtr>& doors = entities.get_entities_with_prefix(EntityType::DOOR, prefix);
2079     for (const EntityPtr& entity: doors) {
2080       Door& door = *std::static_pointer_cast<Door>(entity);
2081       if (!door.is_closed() && !door.is_closing()) {
2082         door.close();
2083         done = true;
2084       }
2085     }
2086 
2087     // make sure the sound is played only once even if the script calls
2088     // this function repeatedly while the door is still changing
2089     if (done) {
2090       Sound::play("door_closed");
2091     }
2092 
2093     return 0;
2094   });
2095 }
2096 
2097 /**
2098  * \brief Implementation of map:set_doors_open().
2099  * \param l The Lua context that is calling this function.
2100  * \return Number of values to return to Lua.
2101  */
map_api_set_doors_open(lua_State * l)2102 int LuaContext::map_api_set_doors_open(lua_State* l) {
2103 
2104   return state_boundary_handle(l, [&] {
2105     Map& map = *check_map(l, 1);
2106     const std::string& prefix = LuaTools::check_string(l, 2);
2107     bool open = LuaTools::opt_boolean(l, 3, true);
2108 
2109     Entities& entities = map.get_entities();
2110     const std::vector<EntityPtr>& doors = entities.get_entities_with_prefix(EntityType::DOOR, prefix);
2111     for (const EntityPtr& entity: doors) {
2112       Door& door = *std::static_pointer_cast<Door>(entity);
2113       door.set_open(open);
2114     }
2115 
2116     return 0;
2117   });
2118 }
2119 
2120 /**
2121  * \brief Implementation of map:get_entity().
2122  * \param l The Lua context that is calling this function.
2123  * \return Number of values to return to Lua.
2124  */
map_api_get_entity(lua_State * l)2125 int LuaContext::map_api_get_entity(lua_State* l) {
2126 
2127   return state_boundary_handle(l, [&] {
2128     Map& map = *check_map(l, 1);
2129     const std::string& name = LuaTools::check_string(l, 2);
2130 
2131     const EntityPtr& entity = map.get_entities().find_entity(name);
2132 
2133     if (entity != nullptr && !entity->is_being_removed()) {
2134       push_entity(l, *entity);
2135     }
2136     else {
2137       lua_pushnil(l);
2138     }
2139     return 1;
2140   });
2141 }
2142 
2143 /**
2144  * \brief Implementation of map:has_entity().
2145  * \param l The Lua context that is calling this function.
2146  * \return Number of values to return to Lua.
2147  */
map_api_has_entity(lua_State * l)2148 int LuaContext::map_api_has_entity(lua_State* l) {
2149 
2150   return state_boundary_handle(l, [&] {
2151     Map& map = *check_map(l, 1);
2152     const std::string& name = LuaTools::check_string(l, 2);
2153 
2154     const EntityPtr& entity = map.get_entities().find_entity(name);
2155 
2156     lua_pushboolean(l, entity != nullptr);
2157     return 1;
2158   });
2159 }
2160 
2161 /**
2162  * \brief Implementation of map:get_entities().
2163  * \param l The Lua context that is calling this function.
2164  * \return Number of values to return to Lua.
2165  */
map_api_get_entities(lua_State * l)2166 int LuaContext::map_api_get_entities(lua_State* l) {
2167 
2168   return state_boundary_handle(l, [&] {
2169     Map& map = *check_map(l, 1);
2170     const std::string& prefix = LuaTools::opt_string(l, 2, "");
2171 
2172     const EntityVector& entities =
2173         map.get_entities().get_entities_with_prefix_z_sorted(prefix);
2174 
2175     push_entity_iterator(l, entities);
2176     return 1;
2177   });
2178 }
2179 
2180 /**
2181  * \brief Implementation of map:get_entities_count().
2182  * \param l The Lua context that is calling this function.
2183  * \return Number of values to return to Lua.
2184  */
map_api_get_entities_count(lua_State * l)2185 int LuaContext::map_api_get_entities_count(lua_State* l) {
2186 
2187   return state_boundary_handle(l, [&] {
2188     Map& map = *check_map(l, 1);
2189     const std::string& prefix = LuaTools::check_string(l, 2);
2190 
2191     const EntityVector& entities =
2192         map.get_entities().get_entities_with_prefix(prefix);
2193 
2194     lua_pushinteger(l, entities.size());
2195     return 1;
2196   });
2197 }
2198 
2199 /**
2200  * \brief Implementation of map:has_entities().
2201  * \param l The Lua context that is calling this function.
2202  * \return Number of values to return to Lua.
2203  */
map_api_has_entities(lua_State * l)2204 int LuaContext::map_api_has_entities(lua_State* l) {
2205 
2206   return state_boundary_handle(l, [&] {
2207     const Map& map = *check_map(l, 1);
2208     const std::string& prefix = LuaTools::check_string(l, 2);
2209 
2210     lua_pushboolean(l, map.get_entities().has_entity_with_prefix(prefix));
2211     return 1;
2212   });
2213 }
2214 
2215 /**
2216  * \brief Implementation of map:get_entities_by_type().
2217  * \param l The Lua context that is calling this function.
2218  * \return Number of values to return to Lua.
2219  */
map_api_get_entities_by_type(lua_State * l)2220 int LuaContext::map_api_get_entities_by_type(lua_State* l) {
2221 
2222   return state_boundary_handle(l, [&] {
2223     Map& map = *check_map(l, 1);
2224     EntityType type = LuaTools::check_enum<EntityType>(l, 2);
2225 
2226     const EntityVector& entities =
2227         map.get_entities().get_entities_by_type_z_sorted(type);
2228 
2229     push_entity_iterator(l, entities);
2230     return 1;
2231   });
2232 }
2233 
2234 /**
2235  * \brief Implementation of map:get_entities_in_rectangle().
2236  * \param l The Lua context that is calling this function.
2237  * \return Number of values to return to Lua.
2238  */
map_api_get_entities_in_rectangle(lua_State * l)2239 int LuaContext::map_api_get_entities_in_rectangle(lua_State* l) {
2240 
2241   return state_boundary_handle(l, [&] {
2242     Map& map = *check_map(l, 1);
2243     const int x = LuaTools::check_int(l, 2);
2244     const int y = LuaTools::check_int(l, 3);
2245     const int width = LuaTools::check_int(l, 4);
2246     const int height = LuaTools::check_int(l, 5);
2247 
2248     EntityVector entities;
2249     map.get_entities().get_entities_in_rectangle_z_sorted(
2250         Rectangle(x, y, width, height), entities
2251     );
2252 
2253     push_entity_iterator(l, entities);
2254     return 1;
2255   });
2256 }
2257 
2258 /**
2259  * \brief Implementation of map:get_entities_in_region().
2260  * \param l The Lua context that is calling this function.
2261  * \return Number of values to return to Lua.
2262  */
map_api_get_entities_in_region(lua_State * l)2263 int LuaContext::map_api_get_entities_in_region(lua_State* l) {
2264 
2265   return state_boundary_handle(l, [&] {
2266     Map& map = *check_map(l, 1);
2267     Point xy;
2268     EntityPtr entity;
2269     if (lua_isnumber(l, 2)) {
2270       int x = LuaTools::check_int(l, 2);
2271       int y = LuaTools::check_int(l, 3);
2272       xy = Point(x, y);
2273     }
2274     else if (is_entity(l, 2)) {
2275       entity = check_entity(l, 2);
2276       xy = entity->get_xy();
2277     }
2278     else {
2279       LuaTools::type_error(l, 2, "entity or number");
2280     }
2281 
2282     EntityVector entities;
2283     map.get_entities().get_entities_in_region_z_sorted(
2284         xy, entities
2285     );
2286 
2287     if (entity != nullptr) {
2288       // Entity variant: remove the entity itself.
2289       const auto& it = std::find(entities.begin(), entities.end(), entity);
2290       if (it != entities.end()) {
2291         entities.erase(it);
2292       }
2293     }
2294 
2295     push_entity_iterator(l, entities);
2296     return 1;
2297   });
2298 }
2299 
2300 /**
2301  * \brief Implementation of map:get_hero().
2302  * \param l The Lua context that is calling this function.
2303  * \return Number of values to return to Lua.
2304  */
map_api_get_hero(lua_State * l)2305 int LuaContext::map_api_get_hero(lua_State* l) {
2306 
2307   return state_boundary_handle(l, [&] {
2308     Map& map = *check_map(l, 1);
2309 
2310     check_map_has_game(l, map);
2311 
2312     // Return the hero even if he is no longer on this map.
2313     push_hero(l, *map.get_game().get_hero());
2314     return 1;
2315   });
2316 }
2317 
2318 /**
2319  * \brief Implementation of map:set_entities_enabled().
2320  * \param l The Lua context that is calling this function.
2321  * \return Number of values to return to Lua.
2322  */
map_api_set_entities_enabled(lua_State * l)2323 int LuaContext::map_api_set_entities_enabled(lua_State* l) {
2324 
2325   return state_boundary_handle(l, [&] {
2326     Map& map = *check_map(l, 1);
2327     const std::string& prefix = LuaTools::check_string(l, 2);
2328     bool enabled = LuaTools::opt_boolean(l, 3, true);
2329 
2330     std::vector<EntityPtr> entities =
2331         map.get_entities().get_entities_with_prefix(prefix);
2332     for (const EntityPtr& entity: entities) {
2333       entity->set_enabled(enabled);
2334     }
2335 
2336     return 0;
2337   });
2338 }
2339 
2340 /**
2341  * \brief Implementation of map:remove_entities().
2342  * \param l The Lua context that is calling this function.
2343  * \return Number of values to return to Lua.
2344  */
map_api_remove_entities(lua_State * l)2345 int LuaContext::map_api_remove_entities(lua_State* l) {
2346 
2347   return state_boundary_handle(l, [&] {
2348     Map& map = *check_map(l, 1);
2349     const std::string& prefix = LuaTools::check_string(l, 2);
2350 
2351     map.get_entities().remove_entities_with_prefix(prefix);
2352     return 0;
2353   });
2354 }
2355 
2356 /**
2357  * \brief Implementation of all entity creation functions: map_api_create_*.
2358  * \param l The Lua context that is calling this function.
2359  * \return Number of values to return to Lua.
2360  */
map_api_create_entity(lua_State * l)2361 int LuaContext::map_api_create_entity(lua_State* l) {
2362 
2363   return state_boundary_handle(l, [&] {
2364 
2365     EntityType type = LuaTools::check_enum<EntityType>(
2366         l, lua_upvalueindex(1)
2367     );
2368     Map& map = *check_map(l, 1);
2369     const EntityData& data = EntityData::check_entity_data(l, 2, type);
2370 
2371     get().create_map_entity_from_data(map, data);
2372 
2373     return 1;
2374   });
2375 }
2376 
2377 /**
2378  * \brief Calls the on_started() method of a Lua map.
2379  *
2380  * Does nothing if the method is not defined.
2381  *
2382  * \param map A map.
2383  * \param destination The destination point used (nullptr if it is a special one).
2384  */
map_on_started(Map & map,const std::shared_ptr<Destination> & destination)2385 void LuaContext::map_on_started(Map& map, const std::shared_ptr<Destination>& destination) {
2386 
2387   if (!userdata_has_field(map, "on_started")) {
2388     return;
2389   }
2390 
2391   push_map(current_l, map);
2392   on_started(destination);
2393   lua_pop(current_l, 1);
2394 }
2395 
2396 /**
2397  * \brief Calls the on_finished() method of a Lua map if it is defined.
2398  *
2399  * Also stops timers and menus associated to the map.
2400  *
2401  * \param map A map.
2402  */
map_on_finished(Map & map)2403 void LuaContext::map_on_finished(Map& map) {
2404 
2405   push_map(current_l, map);
2406   if (userdata_has_field(map, "on_finished")) {
2407     on_finished();
2408   }
2409   remove_timers(-1);  // Stop timers and menus associated to this map.
2410   remove_menus(-1);
2411   lua_pop(current_l, 1);
2412 }
2413 
2414 /**
2415  * \brief Calls the on_update() method of a Lua map.
2416  *
2417  * Also calls the method on its menus.
2418  *
2419  * \param map A map.
2420  */
map_on_update(Map & map)2421 void LuaContext::map_on_update(Map& map) {
2422 
2423   push_map(current_l, map);
2424   // This particular method is tried so often that we want to save optimize
2425   // the std::string construction.
2426   static const std::string method_name = "on_update";
2427   if (userdata_has_field(map, method_name)) {
2428     on_update();
2429   }
2430   menus_on_update(-1);
2431   lua_pop(current_l, 1);
2432 }
2433 
2434 /**
2435  * \brief Calls the on_draw() method of a Lua map if it is defined.
2436  *
2437  * Also calls the method on its menus.
2438  *
2439  * \param map A map.
2440  * \param dst_surface The destination surface.
2441  */
map_on_draw(Map & map,const SurfacePtr & dst_surface)2442 void LuaContext::map_on_draw(Map& map, const SurfacePtr& dst_surface) {
2443 
2444   push_map(current_l, map);
2445   if (userdata_has_field(map, "on_draw")) {
2446     on_draw(dst_surface);
2447   }
2448   menus_on_draw(-1, dst_surface);
2449   lua_pop(current_l, 1);
2450 }
2451 
2452 /**
2453  * \brief Notifies a Lua map that an input event has just occurred.
2454  *
2455  * The appropriate callback in the map is triggered if it exists.
2456  * Also notifies the menus of the game if the game itself does not handle the
2457  * event.
2458  *
2459  * \param event The input event to handle.
2460  * \param map A map.
2461  * \return \c true if the event was handled and should stop being propagated.
2462  */
map_on_input(Map & map,const InputEvent & event)2463 bool LuaContext::map_on_input(Map& map, const InputEvent& event) {
2464 
2465   push_map(current_l, map);
2466   bool handled = on_input(event);
2467   if (!handled) {
2468     handled = menus_on_input(-1, event);
2469   }
2470   lua_pop(current_l, 1);
2471   return handled;
2472 }
2473 
2474 /**
2475  * \brief Calls the on_command_pressed() method of a Lua map.
2476  *
2477  * Also notifies the menus of the game if the game itself does not handle the
2478  * event.
2479  *
2480  * \param map A map.
2481  * \param command The command pressed.
2482  * \return \c true if the event was handled and should stop being propagated.
2483  */
map_on_command_pressed(Map & map,GameCommand command)2484 bool LuaContext::map_on_command_pressed(Map& map, GameCommand command) {
2485 
2486   bool handled = false;
2487   push_map(current_l, map);
2488   if (userdata_has_field(map, "on_command_pressed")) {
2489     handled = on_command_pressed(command);
2490   }
2491   if (!handled) {
2492     handled = menus_on_command_pressed(-1, command);
2493   }
2494   lua_pop(current_l, 1);
2495   return handled;
2496 }
2497 
2498 /**
2499  * \brief Calls the on_command_released() method of a Lua map.
2500  *
2501  * Also notifies the menus of the game if the game itself does not handle the
2502  * event.
2503  *
2504  * \param map A map.
2505  * \param command The command released.
2506  * \return \c true if the event was handled and should stop being propagated.
2507  */
map_on_command_released(Map & map,GameCommand command)2508 bool LuaContext::map_on_command_released(Map& map, GameCommand command) {
2509 
2510   bool handled = false;
2511   push_map(current_l, map);
2512   if (userdata_has_field(map, "on_command_released")) {
2513     handled = on_command_released(command);
2514   }
2515   if (!handled) {
2516     handled = menus_on_command_released(-1, command);
2517   }
2518   lua_pop(current_l, 1);
2519   return handled;
2520 }
2521 
2522 /**
2523  * \brief Calls the on_suspended() method of a Lua map.
2524  *
2525  * Does nothing if the method is not defined.
2526  *
2527  * \param map A map.
2528  * \param suspended true if the map is suspended.
2529  */
map_on_suspended(Map & map,bool suspended)2530 void LuaContext::map_on_suspended(Map& map, bool suspended) {
2531 
2532   if (!userdata_has_field(map, "on_suspended")) {
2533     return;
2534   }
2535 
2536   push_map(current_l, map);
2537   on_suspended(suspended);
2538   lua_pop(current_l, 1);
2539 }
2540 
2541 /**
2542  * \brief Calls the on_opening_transition_finished() method of a Lua map.
2543  *
2544  * Does nothing if the method is not defined.
2545  *
2546  * \param map A map.
2547  * \param destination The destination point used (nullptr if it is a special one).
2548  */
map_on_opening_transition_finished(Map & map,const std::shared_ptr<Destination> & destination)2549 void LuaContext::map_on_opening_transition_finished(Map& map,
2550     const std::shared_ptr<Destination>& destination) {
2551 
2552   if (!userdata_has_field(map, "on_opening_transition_finished")) {
2553     //return;
2554   }
2555 
2556   push_map(current_l, map);
2557   on_opening_transition_finished(destination);
2558   lua_pop(current_l, 1);
2559 }
2560 
2561 /**
2562  * \brief Calls the on_obtaining_treasure() method of a Lua map.
2563  *
2564  * Does nothing if the method is not defined.
2565  *
2566  * \param map A map.
2567  * \param treasure A treasure the hero is about to obtain on that map.
2568  */
map_on_obtaining_treasure(Map & map,const Treasure & treasure)2569 void LuaContext::map_on_obtaining_treasure(Map& map, const Treasure& treasure) {
2570 
2571   if (!userdata_has_field(map, "on_obtaining_treasure")) {
2572     return;
2573   }
2574 
2575   push_map(current_l, map);
2576   on_obtaining_treasure(treasure);
2577   lua_pop(current_l, 1);
2578 }
2579 
2580 /**
2581  * \brief Calls the on_obtained_treasure() method of a Lua map.
2582  *
2583  * Does nothing if the method is not defined.
2584  *
2585  * \param map A map.
2586  * \param treasure The treasure just obtained.
2587  */
map_on_obtained_treasure(Map & map,const Treasure & treasure)2588 void LuaContext::map_on_obtained_treasure(Map& map, const Treasure& treasure) {
2589 
2590   if (!userdata_has_field(map, "on_obtained_treasure")) {
2591     return;
2592   }
2593 
2594   push_map(current_l, map);
2595   on_obtained_treasure(treasure);
2596   lua_pop(current_l, 1);
2597 }
2598 
2599 }
2600 
2601