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