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/Sound.h"
18 #include "solarus/core/CurrentQuest.h"
19 #include "solarus/core/Debug.h"
20 #include "solarus/core/Geometry.h"
21 #include "solarus/core/Equipment.h"
22 #include "solarus/core/EquipmentItem.h"
23 #include "solarus/core/Game.h"
24 #include "solarus/core/Map.h"
25 #include "solarus/core/Savegame.h"
26 #include "solarus/core/Timer.h"
27 #include "solarus/entities/Block.h"
28 #include "solarus/entities/CarriedObject.h"
29 #include "solarus/entities/Chest.h"
30 #include "solarus/entities/CustomEntity.h"
31 #include "solarus/entities/Destination.h"
32 #include "solarus/entities/Destructible.h"
33 #include "solarus/entities/DynamicTile.h"
34 #include "solarus/entities/Door.h"
35 #include "solarus/entities/Enemy.h"
36 #include "solarus/entities/Entities.h"
37 #include "solarus/entities/EntityTypeInfo.h"
38 #include "solarus/entities/GroundInfo.h"
39 #include "solarus/entities/Hero.h"
40 #include "solarus/entities/Npc.h"
41 #include "solarus/entities/Pickable.h"
42 #include "solarus/entities/Sensor.h"
43 #include "solarus/entities/Separator.h"
44 #include "solarus/entities/ShopTreasure.h"
45 #include "solarus/entities/Stairs.h"
46 #include "solarus/entities/Stream.h"
47 #include "solarus/entities/StreamAction.h"
48 #include "solarus/entities/Switch.h"
49 #include "solarus/entities/Teletransporter.h"
50 #include "solarus/entities/Tileset.h"
51 #include "solarus/graphics/Sprite.h"
52 #include "solarus/hero/CustomState.h"
53 #include "solarus/hero/HeroSprites.h"
54 #include "solarus/lua/ExportableToLuaPtr.h"
55 #include "solarus/lua/LuaContext.h"
56 #include "solarus/lua/LuaTools.h"
57 #include "solarus/movements/Movement.h"
58 #include <sstream>
59
60 namespace Solarus {
61
62 namespace {
63
64 /**
65 * \brief Returns the Lua metatable names of each entity type.
66 * \return The Lua metatable name of each entity type.
67 */
get_entity_internal_type_names()68 const std::map<EntityType, std::string>& get_entity_internal_type_names() {
69
70 static std::map<EntityType, std::string> result;
71 if (result.empty()) {
72 for (const auto& kvp : EnumInfoTraits<EntityType>::names) {
73 std::string internal_type_name = std::string("sol.") + kvp.second;
74 result.emplace(kvp.first, internal_type_name);
75 }
76 }
77
78 return result;
79 }
80 /**
81 * \brief Returns a set of the Lua metatable names of all entity types.
82 * \return The Lua metatable name of all entity types.
83 */
get_entity_internal_type_names_set()84 const std::set<std::string>& get_entity_internal_type_names_set() {
85
86 static std::set<std::string> result;
87 if (result.empty()) {
88 for (const auto& kvp : EnumInfoTraits<EntityType>::names) {
89 result.insert(LuaContext::get_entity_internal_type_name(kvp.first));
90 }
91 }
92
93 return result;
94 }
95
96 }
97
98 /**
99 * \brief Initializes the map entity features provided to Lua.
100 */
register_entity_module()101 void LuaContext::register_entity_module() {
102
103 // Methods common to all entity types.
104 std::vector<luaL_Reg> common_methods = {
105 { "get_type", entity_api_get_type },
106 { "get_map", entity_api_get_map },
107 { "get_game", entity_api_get_game },
108 { "get_name", entity_api_get_name },
109 { "exists", entity_api_exists },
110 { "remove", entity_api_remove },
111 { "is_enabled", entity_api_is_enabled },
112 { "set_enabled", entity_api_set_enabled },
113 { "get_size", entity_api_get_size },
114 { "get_origin", entity_api_get_origin },
115 { "get_position", entity_api_get_position },
116 { "set_position", entity_api_set_position },
117 { "get_center_position", entity_api_get_center_position },
118 { "get_facing_position", entity_api_get_facing_position },
119 { "get_facing_entity", entity_api_get_facing_entity },
120 { "get_ground_position", entity_api_get_ground_position },
121 { "get_ground_below", entity_api_get_ground_below },
122 { "get_bounding_box", entity_api_get_bounding_box },
123 { "get_max_bounding_box", entity_api_get_max_bounding_box },
124 { "overlaps", entity_api_overlaps },
125 { "get_distance", entity_api_get_distance },
126 { "get_angle", entity_api_get_angle },
127 { "get_direction4_to", entity_api_get_direction4_to },
128 { "get_direction8_to", entity_api_get_direction8_to },
129 { "snap_to_grid", entity_api_snap_to_grid },
130 { "bring_to_front", entity_api_bring_to_front },
131 { "bring_to_back", entity_api_bring_to_back },
132 { "is_drawn_in_y_order", entity_api_is_drawn_in_y_order },
133 { "set_drawn_in_y_order", entity_api_set_drawn_in_y_order },
134 { "get_optimization_distance", entity_api_get_optimization_distance },
135 { "set_optimization_distance", entity_api_set_optimization_distance },
136 { "is_in_same_region", entity_api_is_in_same_region },
137 { "test_obstacles", entity_api_test_obstacles },
138 { "get_sprite", entity_api_get_sprite },
139 { "get_sprites", entity_api_get_sprites },
140 { "create_sprite", entity_api_create_sprite },
141 { "remove_sprite", entity_api_remove_sprite },
142 { "bring_sprite_to_front", entity_api_bring_sprite_to_front },
143 { "bring_sprite_to_back", entity_api_bring_sprite_to_back },
144 { "is_visible", entity_api_is_visible },
145 { "set_visible", entity_api_set_visible },
146 { "get_movement", entity_api_get_movement },
147 { "stop_movement", entity_api_stop_movement },
148 };
149 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
150 common_methods.insert(common_methods.end(), {
151 { "get_layer", entity_api_get_layer },
152 { "set_layer", entity_api_set_layer },
153 { "set_size", entity_api_set_size },
154 { "set_origin", entity_api_set_origin },
155 { "get_draw_override", entity_api_get_draw_override },
156 { "set_draw_override", entity_api_set_draw_override },
157 { "get_weight", entity_api_get_weight },
158 { "set_weight", entity_api_set_weight },
159 { "get_controlling_stream", entity_api_get_controlling_stream },
160 { "get_property", entity_api_get_property },
161 { "set_property", entity_api_set_property },
162 { "get_properties", entity_api_get_properties },
163 { "set_properties", entity_api_set_properties },
164 });
165 }
166
167 // Metamethods of all entity types.
168 std::vector<luaL_Reg> metamethods = {
169 { "__gc", userdata_meta_gc },
170 { "__newindex", userdata_meta_newindex_as_table },
171 { "__index", userdata_meta_index_as_table },
172 };
173
174 // Hero.
175 std::vector<luaL_Reg> hero_methods = {
176 { "teleport", hero_api_teleport },
177 { "get_direction", hero_api_get_direction },
178 { "set_direction", hero_api_set_direction },
179 { "get_walking_speed", hero_api_get_walking_speed },
180 { "set_walking_speed", hero_api_set_walking_speed },
181 { "save_solid_ground", hero_api_save_solid_ground },
182 { "reset_solid_ground", hero_api_reset_solid_ground },
183 { "get_solid_ground_position", hero_api_get_solid_ground_position },
184 { "get_animation", hero_api_get_animation },
185 { "set_animation", hero_api_set_animation },
186 { "get_tunic_sprite_id", hero_api_get_tunic_sprite_id },
187 { "set_tunic_sprite_id", hero_api_set_tunic_sprite_id },
188 { "get_sword_sprite_id", hero_api_get_sword_sprite_id },
189 { "set_sword_sprite_id", hero_api_set_sword_sprite_id },
190 { "get_sword_sound_id", hero_api_get_sword_sound_id },
191 { "set_sword_sound_id", hero_api_set_sword_sound_id },
192 { "get_shield_sprite_id", hero_api_get_shield_sprite_id },
193 { "set_shield_sprite_id", hero_api_set_shield_sprite_id },
194 { "is_blinking", hero_api_is_blinking },
195 { "set_blinking", hero_api_set_blinking },
196 { "is_invincible", hero_api_is_invincible },
197 { "set_invincible", hero_api_set_invincible },
198 { "freeze", hero_api_freeze },
199 { "unfreeze", hero_api_unfreeze },
200 { "walk", hero_api_walk }, // TODO use the more general movement:start
201 { "start_attack", hero_api_start_attack },
202 { "start_attack_loading", hero_api_start_attack_loading },
203 { "start_item", hero_api_start_item },
204 { "start_grabbing", hero_api_start_grabbing },
205 { "start_jumping", hero_api_start_jumping },
206 { "start_treasure", hero_api_start_treasure },
207 { "start_victory", hero_api_start_victory},
208 { "start_boomerang", hero_api_start_boomerang },
209 { "start_bow", hero_api_start_bow },
210 { "start_hookshot", hero_api_start_hookshot },
211 { "start_running", hero_api_start_running },
212 { "start_hurt", hero_api_start_hurt },
213 { "get_state", entity_api_get_state },
214 { "get_state_object", hero_api_get_state_object },
215 };
216 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
217 hero_methods.insert(hero_methods.end(), {
218 { "get_carried_object", hero_api_get_carried_object },
219 { "start_state", hero_api_start_state },
220 });
221 }
222
223 hero_methods.insert(hero_methods.end(), common_methods.begin(), common_methods.end());
224 register_type(
225 get_entity_internal_type_name(EntityType::HERO),
226 {},
227 hero_methods,
228 metamethods
229 );
230
231 // Camera.
232 std::vector<luaL_Reg> camera_methods = {
233 { "get_position_on_screen", camera_api_get_position_on_screen },
234 { "set_position_on_screen", camera_api_set_position_on_screen },
235 { "get_state", entity_api_get_state },
236 { "start_tracking", camera_api_start_tracking },
237 { "start_manual", camera_api_start_manual },
238 { "get_position_to_track", camera_api_get_position_to_track },
239 { "get_tracked_entity", camera_api_get_tracked_entity },
240 };
241 if (CurrentQuest::is_format_at_most({ 1, 5 })) {
242 camera_methods.insert(camera_methods.end(), {
243 // Available to all entities since 1.6.
244 { "set_size", entity_api_set_size },
245 });
246 }
247 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
248 common_methods.insert(common_methods.end(), {
249 { "get_surface", camera_api_get_surface },
250 });
251 }
252
253 camera_methods.insert(camera_methods.end(), common_methods.begin(), common_methods.end());
254 register_type(
255 get_entity_internal_type_name(EntityType::CAMERA),
256 {},
257 camera_methods,
258 metamethods
259 );
260
261 // Destination.
262 std::vector<luaL_Reg> destination_methods = {
263 { "get_starting_location_mode", destination_api_get_starting_location_mode },
264 { "set_starting_location_mode", destination_api_set_starting_location_mode },
265 };
266
267 destination_methods.insert(destination_methods.end(), common_methods.begin(), common_methods.end());
268 register_type(
269 get_entity_internal_type_name(EntityType::DESTINATION),
270 {},
271 destination_methods,
272 metamethods
273 );
274
275 // Teletransporter.
276 std::vector<luaL_Reg> teletransporter_methods = {
277 { "get_sound", teletransporter_api_get_sound },
278 { "set_sound", teletransporter_api_set_sound },
279 { "get_transition", teletransporter_api_get_transition },
280 { "set_transition", teletransporter_api_set_transition },
281 { "get_destination_map", teletransporter_api_get_destination_map },
282 { "set_destination_map", teletransporter_api_set_destination_map},
283 { "get_destination_name", teletransporter_api_get_destination_name },
284 { "set_destination_name", teletransporter_api_set_destination_name },
285 };
286
287 teletransporter_methods.insert(teletransporter_methods.end(), common_methods.begin(), common_methods.end());
288 register_type(
289 get_entity_internal_type_name(EntityType::TELETRANSPORTER),
290 {},
291 teletransporter_methods,
292 metamethods
293 );
294
295 // NPC.
296 std::vector<luaL_Reg> npc_methods = {
297 { "is_traversable", npc_api_is_traversable },
298 { "set_traversable", npc_api_set_traversable },
299 };
300
301 npc_methods.insert(npc_methods.end(), common_methods.begin(), common_methods.end());
302 register_type(
303 get_entity_internal_type_name(EntityType::NPC),
304 {},
305 npc_methods,
306 metamethods
307 );
308
309 // Chest.
310 std::vector<luaL_Reg> chest_methods = {
311 { "is_open", chest_api_is_open },
312 { "set_open", chest_api_set_open },
313 { "get_treasure", chest_api_get_treasure },
314 { "set_treasure", chest_api_set_treasure },
315 };
316
317 chest_methods.insert(chest_methods.end(), common_methods.begin(), common_methods.end());
318 register_type(
319 get_entity_internal_type_name(EntityType::CHEST),
320 {},
321 chest_methods,
322 metamethods
323 );
324
325 // Block.
326 std::vector<luaL_Reg> block_methods = {
327 { "reset", block_api_reset },
328 { "is_pushable", block_api_is_pushable },
329 { "set_pushable", block_api_set_pushable },
330 { "is_pullable", block_api_is_pullable },
331 { "set_pullable", block_api_set_pullable },
332 { "get_maximum_moves", block_api_get_maximum_moves },
333 { "set_maximum_moves", block_api_set_maximum_moves },
334 };
335 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
336 block_methods.insert(block_methods.end(), {
337 { "get_max_moves", block_api_get_max_moves },
338 { "set_max_moves", block_api_set_max_moves },
339 });
340 }
341
342 block_methods.insert(block_methods.end(), common_methods.begin(), common_methods.end());
343 register_type(
344 get_entity_internal_type_name(EntityType::BLOCK),
345 {},
346 block_methods,
347 metamethods
348 );
349
350 // Switch.
351 std::vector<luaL_Reg> switch_methods = {
352 { "is_activated", switch_api_is_activated },
353 { "set_activated", switch_api_set_activated },
354 { "is_locked", switch_api_is_locked },
355 { "set_locked", switch_api_set_locked },
356 { "is_walkable", switch_api_is_walkable },
357 };
358
359 switch_methods.insert(switch_methods.end(), common_methods.begin(), common_methods.end());
360 register_type(
361 get_entity_internal_type_name(EntityType::SWITCH),
362 {},
363 switch_methods,
364 metamethods
365 );
366
367 // Stream.
368 std::vector<luaL_Reg> stream_methods = {
369 { "get_direction", stream_api_get_direction },
370 { "set_direction", stream_api_set_direction },
371 { "get_speed", stream_api_get_speed },
372 { "set_speed", stream_api_set_speed },
373 { "get_allow_movement", stream_api_get_allow_movement },
374 { "set_allow_movement", stream_api_set_allow_movement },
375 { "get_allow_attack", stream_api_get_allow_attack },
376 { "set_allow_attack", stream_api_set_allow_attack },
377 { "get_allow_item", stream_api_get_allow_item },
378 { "set_allow_item", stream_api_set_allow_item },
379 };
380
381 stream_methods.insert(stream_methods.end(), common_methods.begin(), common_methods.end());
382 register_type(
383 get_entity_internal_type_name(EntityType::STREAM),
384 {},
385 stream_methods,
386 metamethods
387 );
388
389 // Door.
390 std::vector<luaL_Reg> door_methods = {
391 { "is_open", door_api_is_open },
392 { "is_opening", door_api_is_opening },
393 { "is_closed", door_api_is_closed },
394 { "is_closing", door_api_is_closing },
395 };
396 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
397 door_methods.insert(door_methods.end(), {
398 { "open", door_api_open },
399 { "close", door_api_close },
400 { "set_open", door_api_set_open },
401 });
402 }
403
404 door_methods.insert(door_methods.end(), common_methods.begin(), common_methods.end());
405 register_type(
406 get_entity_internal_type_name(EntityType::DOOR),
407 {},
408 door_methods,
409 metamethods
410 );
411
412
413 // Stairs.
414 std::vector<luaL_Reg> stairs_methods = {
415 };
416 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
417 stairs_methods.insert(stairs_methods.end(), {
418 { "get_direction", stairs_api_get_direction },
419 { "is_inner", stairs_api_is_inner },
420 });
421 }
422
423 stairs_methods.insert(stairs_methods.end(), common_methods.begin(), common_methods.end());
424 register_type(
425 get_entity_internal_type_name(EntityType::STAIRS),
426 {},
427 stairs_methods,
428 metamethods
429 );
430
431 // Pickable.
432 std::vector<luaL_Reg> pickable_methods = {
433 { "has_layer_independent_collisions", entity_api_has_layer_independent_collisions },
434 { "set_layer_independent_collisions", entity_api_set_layer_independent_collisions },
435 { "get_followed_entity", pickable_api_get_followed_entity },
436 { "get_falling_height", pickable_api_get_falling_height },
437 { "get_treasure", pickable_api_get_treasure },
438 };
439
440 pickable_methods.insert(pickable_methods.end(), common_methods.begin(), common_methods.end());
441 register_type(
442 get_entity_internal_type_name(EntityType::PICKABLE),
443 {},
444 pickable_methods,
445 metamethods
446 );
447
448 // Destructible.
449 std::vector<luaL_Reg> destructible_methods = {
450 { "get_treasure", destructible_api_get_treasure },
451 { "set_treasure", destructible_api_set_treasure },
452 { "get_destruction_sound", destructible_api_get_destruction_sound },
453 { "set_destruction_sound", destructible_api_set_destruction_sound },
454 { "get_can_be_cut", destructible_api_get_can_be_cut },
455 { "set_can_be_cut", destructible_api_set_can_be_cut },
456 { "get_can_explode", destructible_api_get_can_explode },
457 { "set_can_explode", destructible_api_set_can_explode },
458 { "get_can_regenerate", destructible_api_get_can_regenerate },
459 { "set_can_regenerate", destructible_api_set_can_regenerate },
460 { "get_damage_on_enemies", destructible_api_get_damage_on_enemies },
461 { "set_damage_on_enemies", destructible_api_set_damage_on_enemies },
462 { "get_modified_ground", destructible_api_get_modified_ground },
463 };
464 if (CurrentQuest::is_format_at_most({ 1, 5 })) {
465 destructible_methods.insert(destructible_methods.end(), {
466 // Available to all entities since 1.6.
467 { "get_weight", entity_api_get_weight },
468 { "set_weight", entity_api_set_weight },
469 });
470 }
471
472 destructible_methods.insert(destructible_methods.end(), common_methods.begin(), common_methods.end());
473 register_type(
474 get_entity_internal_type_name(EntityType::DESTRUCTIBLE),
475 {},
476 destructible_methods,
477 metamethods
478 );
479
480 // Carried object.
481 std::vector<luaL_Reg> carried_object_methods = {
482 };
483 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
484 carried_object_methods.insert(carried_object_methods.end(), {
485 { "get_carrier", carried_object_api_get_carrier },
486 { "get_destruction_sound", carried_object_api_get_destruction_sound },
487 { "set_destruction_sound", carried_object_api_set_destruction_sound },
488 { "get_damage_on_enemies", carried_object_api_get_damage_on_enemies },
489 { "set_damage_on_enemies", carried_object_api_set_damage_on_enemies },
490 });
491 }
492
493 carried_object_methods.insert(carried_object_methods.end(), common_methods.begin(), common_methods.end());
494 register_type(
495 get_entity_internal_type_name(EntityType::CARRIED_OBJECT),
496 {},
497 carried_object_methods,
498 metamethods
499 );
500
501 // Dynamic tile.
502 std::vector<luaL_Reg> dynamic_tile_methods = {
503 { "get_pattern_id", dynamic_tile_api_get_pattern_id },
504 { "get_modified_ground", dynamic_tile_api_get_modified_ground },
505 { "get_tileset", dynamic_tile_api_get_tileset },
506 { "set_tileset", dynamic_tile_api_set_tileset },
507 };
508
509 dynamic_tile_methods.insert(dynamic_tile_methods.end(), common_methods.begin(), common_methods.end());
510 register_type(
511 get_entity_internal_type_name(EntityType::DYNAMIC_TILE),
512 {},
513 dynamic_tile_methods,
514 metamethods
515 );
516
517 // Enemy.
518 std::vector<luaL_Reg> enemy_methods = {
519 { "get_breed", enemy_api_get_breed },
520 { "get_life", enemy_api_get_life },
521 { "set_life", enemy_api_set_life },
522 { "add_life", enemy_api_add_life },
523 { "remove_life", enemy_api_remove_life },
524 { "get_damage", enemy_api_get_damage },
525 { "set_damage", enemy_api_set_damage },
526 { "is_pushed_back_when_hurt", enemy_api_is_pushed_back_when_hurt },
527 { "set_pushed_back_when_hurt", enemy_api_set_pushed_back_when_hurt },
528 { "get_push_hero_on_sword", enemy_api_get_push_hero_on_sword },
529 { "set_push_hero_on_sword", enemy_api_set_push_hero_on_sword },
530 { "get_can_hurt_hero_running", enemy_api_get_can_hurt_hero_running },
531 { "set_can_hurt_hero_running", enemy_api_set_can_hurt_hero_running },
532 { "get_hurt_style", enemy_api_get_hurt_style },
533 { "set_hurt_style", enemy_api_set_hurt_style },
534 { "get_can_attack", enemy_api_get_can_attack },
535 { "set_can_attack", enemy_api_set_can_attack },
536 { "get_minimum_shield_needed", enemy_api_get_minimum_shield_needed },
537 { "set_minimum_shield_needed", enemy_api_set_minimum_shield_needed },
538 { "get_attack_consequence", enemy_api_get_attack_consequence },
539 { "set_attack_consequence", enemy_api_set_attack_consequence },
540 { "get_attack_consequence_sprite", enemy_api_get_attack_consequence_sprite },
541 { "set_attack_consequence_sprite", enemy_api_set_attack_consequence_sprite },
542 { "set_default_attack_consequences", enemy_api_set_default_attack_consequences },
543 { "set_default_attack_consequences_sprite", enemy_api_set_default_attack_consequences_sprite },
544 { "set_invincible", enemy_api_set_invincible },
545 { "set_invincible_sprite", enemy_api_set_invincible_sprite },
546 { "has_layer_independent_collisions", entity_api_has_layer_independent_collisions },
547 { "set_layer_independent_collisions", entity_api_set_layer_independent_collisions },
548 { "get_treasure", enemy_api_get_treasure },
549 { "set_treasure", enemy_api_set_treasure },
550 { "is_traversable", enemy_api_is_traversable },
551 { "set_traversable", enemy_api_set_traversable },
552 { "get_obstacle_behavior", enemy_api_get_obstacle_behavior },
553 { "set_obstacle_behavior", enemy_api_set_obstacle_behavior },
554 { "restart", enemy_api_restart },
555 { "hurt", enemy_api_hurt },
556 { "immobilize", enemy_api_immobilize },
557 { "create_enemy", enemy_api_create_enemy },
558 };
559 if (CurrentQuest::is_format_at_most({ 1, 5 })) {
560 enemy_methods.insert(enemy_methods.end(), {
561 // Available to all entities since 1.6.
562 { "set_size", entity_api_set_size },
563 { "set_origin", entity_api_set_origin },
564 { "create_sprite", entity_api_create_sprite },
565 { "remove_sprite", entity_api_remove_sprite },
566 });
567 }
568 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
569 enemy_methods.insert(enemy_methods.end(), {
570 { "get_dying_sprite_id", enemy_api_get_dying_sprite_id },
571 { "set_dying_sprite_id", enemy_api_set_dying_sprite_id },
572 { "is_immobilized", enemy_api_is_immobilized },
573 { "get_attacking_collision_mode", enemy_api_get_attacking_collision_mode },
574 { "set_attacking_collision_mode", enemy_api_set_attacking_collision_mode },
575 });
576 }
577
578 enemy_methods.insert(enemy_methods.end(), common_methods.begin(), common_methods.end());
579 register_type(
580 get_entity_internal_type_name(EntityType::ENEMY),
581 {},
582 enemy_methods,
583 metamethods
584 );
585
586 // Custom entity.
587 std::vector<luaL_Reg> custom_entity_methods = {
588 { "get_model", custom_entity_api_get_model },
589 { "set_size", entity_api_set_size },
590 { "set_origin", entity_api_set_origin },
591 { "get_direction", custom_entity_api_get_direction },
592 { "set_direction", custom_entity_api_set_direction },
593 { "set_traversable_by", custom_entity_api_set_traversable_by },
594 { "set_can_traverse", custom_entity_api_set_can_traverse },
595 { "can_traverse_ground", custom_entity_api_can_traverse_ground },
596 { "set_can_traverse_ground", custom_entity_api_set_can_traverse_ground },
597 { "add_collision_test", custom_entity_api_add_collision_test },
598 { "clear_collision_tests", custom_entity_api_clear_collision_tests },
599 { "has_layer_independent_collisions", entity_api_has_layer_independent_collisions },
600 { "set_layer_independent_collisions", entity_api_set_layer_independent_collisions },
601 { "get_modified_ground", custom_entity_api_get_modified_ground },
602 { "set_modified_ground", custom_entity_api_set_modified_ground },
603 };
604 if (CurrentQuest::is_format_at_most({ 1, 5 })) {
605 // Available to all entities since 1.6.
606 custom_entity_methods.insert(custom_entity_methods.end(), {
607 { "set_size", entity_api_set_size },
608 { "set_origin", entity_api_set_origin },
609 { "is_drawn_in_y_order", entity_api_is_drawn_in_y_order },
610 { "set_drawn_in_y_order", entity_api_set_drawn_in_y_order },
611 { "create_sprite", entity_api_create_sprite },
612 { "remove_sprite", entity_api_remove_sprite },
613 });
614 }
615 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
616 custom_entity_methods.insert(custom_entity_methods.end(), {
617 { "is_tiled", custom_entity_api_is_tiled },
618 { "set_tiled", custom_entity_api_set_tiled },
619 { "get_follow_streams", custom_entity_api_get_follow_streams },
620 { "set_follow_streams", custom_entity_api_set_follow_streams },
621 });
622 }
623
624 custom_entity_methods.insert(custom_entity_methods.end(), common_methods.begin(), common_methods.end());
625 register_type(
626 get_entity_internal_type_name(EntityType::CUSTOM),
627 {},
628 custom_entity_methods,
629 metamethods
630 );
631
632 // Also register all other types of entities that have no specific methods.
633 register_type(get_entity_internal_type_name(EntityType::TILE), {}, common_methods, metamethods);
634 register_type(get_entity_internal_type_name(EntityType::JUMPER), {}, common_methods, metamethods);
635 register_type(get_entity_internal_type_name(EntityType::SENSOR), {}, common_methods, metamethods);
636 register_type(get_entity_internal_type_name(EntityType::SEPARATOR), {}, common_methods, metamethods);
637 register_type(get_entity_internal_type_name(EntityType::WALL), {}, common_methods, metamethods);
638 register_type(get_entity_internal_type_name(EntityType::CRYSTAL), {}, common_methods, metamethods);
639 register_type(get_entity_internal_type_name(EntityType::CRYSTAL_BLOCK), {}, common_methods, metamethods);
640 register_type(get_entity_internal_type_name(EntityType::SHOP_TREASURE), {}, common_methods, metamethods);
641 register_type(get_entity_internal_type_name(EntityType::BOMB), {}, common_methods, metamethods);
642 register_type(get_entity_internal_type_name(EntityType::EXPLOSION), {}, common_methods, metamethods);
643 register_type(get_entity_internal_type_name(EntityType::FIRE), {}, common_methods, metamethods);
644 register_type(get_entity_internal_type_name(EntityType::ARROW), {}, common_methods, metamethods);
645 register_type(get_entity_internal_type_name(EntityType::HOOKSHOT), {}, common_methods, metamethods);
646 register_type(get_entity_internal_type_name(EntityType::BOOMERANG), {}, common_methods, metamethods);
647 }
648
649 /**
650 * \brief Returns whether a value is a userdata of type entity.
651 * \param l A Lua context.
652 * \param index An index in the stack.
653 * \return true if the value at this index is a entity.
654 */
is_entity(lua_State * l,int index)655 bool LuaContext::is_entity(lua_State* l, int index) {
656
657 // We could return is_hero() || is_tile() || is_dynamic_tile() || ...
658 // but this would be tedious, costly and error prone.
659
660 void* udata = lua_touserdata(l, index);
661 if (udata == nullptr) {
662 // This is not a userdata.
663 return false;
664 }
665
666 if (!lua_getmetatable(l, index)) {
667 // The userdata has no metatable.
668 return false;
669 }
670
671 // Get the name of the Solarus type from this userdata.
672 lua_pushstring(l, "__solarus_type");
673 lua_rawget(l, -2);
674 if (!lua_isstring(l, -1)) {
675 // This is probably a userdata from some library other than Solarus.
676 lua_pop(l, 2);
677 return false;
678 }
679
680 // Check if the type name is one of the entity type names.
681 const std::string& type_name = lua_tostring(l, -1);
682 lua_pop(l, 2);
683
684 return get_entity_internal_type_names_set().find(type_name) != get_entity_internal_type_names_set().end();
685 }
686
687 /**
688 * \brief Checks that the userdata at the specified index of the stack is an
689 * entity and returns it.
690 * \param l A Lua context.
691 * \param index An index in the stack.
692 * \return The entity.
693 */
check_entity(lua_State * l,int index)694 EntityPtr LuaContext::check_entity(lua_State* l, int index) {
695
696 if (is_entity(l, index)) {
697 const ExportableToLuaPtr& userdata = *(static_cast<ExportableToLuaPtr*>(
698 lua_touserdata(l, index)
699 ));
700 return std::static_pointer_cast<Entity>(userdata);
701 }
702 else {
703 LuaTools::type_error(l, index, "entity");
704 }
705 }
706
707 /**
708 * \brief Pushes an entity userdata onto the stack.
709 *
710 * If the entity or its map does not exist anymore, pushes nil.
711 *
712 * \param l A Lua context.
713 * \param entity An entity.
714 */
push_entity(lua_State * l,Entity & entity)715 void LuaContext::push_entity(lua_State* l, Entity& entity) {
716
717 push_userdata(l, entity);
718 }
719
720 /**
721 * \brief Pushes a list of entities as an iterator onto the stack.
722 *
723 * The iterator is pushed onto the stack as one value of type function.
724 *
725 * \param l A Lua context.
726 * \param entity A list of entities. The iterator preserves their order.
727 */
push_entity_iterator(lua_State * l,const EntityVector & entities)728 void LuaContext::push_entity_iterator(lua_State* l, const EntityVector& entities) {
729
730 // Create a Lua table with the list of entities, preserving their order.
731 int i = 0;
732 lua_newtable(l);
733 for (const EntityPtr& entity: entities) {
734 ++i;
735 lua_pushinteger(l, i);
736 push_entity(l, *entity);
737 lua_rawset(l, -3);
738 }
739
740 lua_pushinteger(l, entities.size());
741 lua_pushinteger(l, 1);
742 // 3 upvalues: entities table, size, current index.
743
744 lua_pushcclosure(l, l_entity_iterator_next, 3);
745 }
746
747 /**
748 * \brief Returns the Lua metatable name corresponding to a type of map entity.
749 * \param entity_type A type of map entity.
750 * \return The corresponding Lua metatable name, e.g. "sol.enemy".
751 */
get_entity_internal_type_name(EntityType entity_type)752 const std::string& LuaContext::get_entity_internal_type_name(
753 EntityType entity_type) {
754
755 const std::map<EntityType, std::string>& names = get_entity_internal_type_names();
756 const auto& it = names.find(entity_type);
757 SOLARUS_ASSERT(it != names.end(), "Missing entity internal type name");
758
759 return it->second;
760 }
761
762 /**
763 * \brief Closure of an iterator over a list of sprites and their names.
764 *
765 * This closure expects 3 upvalues in this order:
766 * - An array of { name, sprite } pairs.
767 * - The size of the array (for performance).
768 * - The current index in the array.
769 *
770 * \param l The Lua context that is calling this function.
771 * \return Number of values to return to Lua.
772 */
l_named_sprite_iterator_next(lua_State * l)773 int LuaContext::l_named_sprite_iterator_next(lua_State* l) {
774
775 return state_boundary_handle(l, [&] {
776
777 // Get upvalues.
778 const int table_index = lua_upvalueindex(1);
779 const int size = lua_tointeger(l, lua_upvalueindex(2));
780 int index = lua_tointeger(l, lua_upvalueindex(3));
781
782 if (index > size) {
783 // Finished.
784 return 0;
785 }
786
787 // Get the next value.
788 lua_rawgeti(l, table_index, index); // pair
789 lua_rawgeti(l, -1, 1); // pair name
790 lua_rawgeti(l, -2, 2); // pair name sprite
791
792 // Increment index.
793 ++index;
794 lua_pushinteger(l, index);
795 lua_replace(l, lua_upvalueindex(3));
796
797 return 2;
798 });
799 }
800
801 /**
802 * \brief Pushes a list of sprites and their names as an iterator onto the stack.
803 *
804 * The iterator is pushed onto the stack as one value of type function.
805 *
806 * \param l A Lua context.
807 * \param sprites A list of sprites and their names. The iterator preserves their order.
808 */
push_named_sprite_iterator(lua_State * l,const std::vector<Entity::NamedSprite> & sprites)809 void LuaContext::push_named_sprite_iterator(
810 lua_State* l,
811 const std::vector<Entity::NamedSprite>& sprites
812 ) {
813 // Create a Lua table with the list of name-sprite pairs, preserving their order.
814 int i = 0;
815 lua_newtable(l);
816 // sprites
817 for (const Entity::NamedSprite& named_sprite: sprites) {
818 if (named_sprite.removed) {
819 continue;
820 }
821 ++i;
822 lua_newtable(l); // sprites pair
823 push_string(l, named_sprite.name); // sprites pair name
824 lua_rawseti(l, -2, 1); // sprites pair
825 push_sprite(l, *named_sprite.sprite); // sprites pair sprite
826 lua_rawseti(l, -2, 2); // sprites pair
827
828 lua_rawseti(l, -2, i); // sprites
829 }
830
831 lua_pushinteger(l, i);
832 lua_pushinteger(l, 1);
833 // 3 upvalues: sprites table, size, current index.
834
835 lua_pushcclosure(l, l_named_sprite_iterator_next, 3);
836 }
837
838 /**
839 * \brief Calls the draw override function of an entity.
840 * \param draw_override The draw override function.
841 * \param entity The entity to draw.
842 * \param camera The camera where to draw the entity.
843 */
do_entity_draw_override_function(const ScopedLuaRef & draw_override,Entity & entity,Camera & camera)844 void LuaContext::do_entity_draw_override_function(
845 const ScopedLuaRef& draw_override,
846 Entity& entity,
847 Camera& camera
848 ) {
849 push_ref(current_l, draw_override);
850 push_entity(current_l, entity);
851 push_camera(current_l, camera);
852 call_function(2, 0, "entity draw override");
853 }
854
855 /**
856 * \brief Implementation of entity:get_type().
857 * \param l The Lua context that is calling this function.
858 * \return Number of values to return to Lua.
859 */
entity_api_get_type(lua_State * l)860 int LuaContext::entity_api_get_type(lua_State* l) {
861
862 return state_boundary_handle(l, [&] {
863 const Entity& entity = *check_entity(l, 1);
864
865 const std::string& type_name = enum_to_name(entity.get_type());
866 push_string(l, type_name);
867 return 1;
868 });
869 }
870
871 /**
872 * \brief Implementation of entity:get_map().
873 * \param l The Lua context that is calling this function.
874 * \return Number of values to return to Lua.
875 */
entity_api_get_map(lua_State * l)876 int LuaContext::entity_api_get_map(lua_State* l) {
877
878 return state_boundary_handle(l, [&] {
879 Entity& entity = *check_entity(l, 1);
880
881 push_map(l, entity.get_map());
882 return 1;
883 });
884 }
885
886 /**
887 * \brief Implementation of entity:get_game().
888 * \param l The Lua context that is calling this function.
889 * \return Number of values to return to Lua.
890 */
entity_api_get_game(lua_State * l)891 int LuaContext::entity_api_get_game(lua_State* l) {
892
893 return state_boundary_handle(l, [&] {
894 Entity& entity = *check_entity(l, 1);
895
896 push_game(l, entity.get_game().get_savegame());
897 return 1;
898 });
899 }
900
901 /**
902 * \brief Implementation of entity:get_name().
903 * \param l The Lua context that is calling this function.
904 * \return Number of values to return to Lua.
905 */
entity_api_get_name(lua_State * l)906 int LuaContext::entity_api_get_name(lua_State* l) {
907
908 return state_boundary_handle(l, [&] {
909 const Entity& entity = *check_entity(l, 1);
910
911 const std::string& name = entity.get_name();
912 if (name.empty()) {
913 lua_pushnil(l);
914 }
915 else {
916 push_string(l, name);
917 }
918 return 1;
919 });
920 }
921
922 /**
923 * \brief Implementation of entity:exists().
924 * \param l The Lua context that is calling this function.
925 * \return Number of values to return to Lua.
926 */
entity_api_exists(lua_State * l)927 int LuaContext::entity_api_exists(lua_State* l) {
928
929 return state_boundary_handle(l, [&] {
930 const Entity& entity = *check_entity(l, 1);
931
932 lua_pushboolean(l, !entity.is_being_removed());
933 return 1;
934 });
935 }
936
937 /**
938 * \brief Implementation of entity:remove().
939 * \param l The Lua context that is calling this function.
940 * \return Number of values to return to Lua.
941 */
entity_api_remove(lua_State * l)942 int LuaContext::entity_api_remove(lua_State* l) {
943
944 return state_boundary_handle(l, [&] {
945 Entity& entity = *check_entity(l, 1);
946
947 entity.remove_from_map();
948
949 return 0;
950 });
951 }
952
953 /**
954 * \brief Implementation of entity:is_enabled().
955 * \param l The Lua context that is calling this function.
956 * \return Number of values to return to Lua.
957 */
entity_api_is_enabled(lua_State * l)958 int LuaContext::entity_api_is_enabled(lua_State* l) {
959
960 return state_boundary_handle(l, [&] {
961 const Entity& entity = *check_entity(l, 1);
962
963 lua_pushboolean(l, entity.is_enabled());
964 return 1;
965 });
966 }
967
968 /**
969 * \brief Implementation of entity:set_enabled().
970 * \param l The Lua context that is calling this function.
971 * \return Number of values to return to Lua.
972 */
entity_api_set_enabled(lua_State * l)973 int LuaContext::entity_api_set_enabled(lua_State* l) {
974
975 return state_boundary_handle(l, [&] {
976 Entity& entity = *check_entity(l, 1);
977 bool enabled = LuaTools::opt_boolean(l, 2, true);
978
979 entity.set_enabled(enabled);
980
981 return 0;
982 });
983 }
984
985 /**
986 * \brief Implementation of entity:get_size().
987 * \param l The Lua context that is calling this function.
988 * \return Number of values to return to Lua.
989 */
entity_api_get_size(lua_State * l)990 int LuaContext::entity_api_get_size(lua_State* l) {
991
992 return state_boundary_handle(l, [&] {
993 const Entity& entity = *check_entity(l, 1);
994
995 lua_pushinteger(l, entity.get_width());
996 lua_pushinteger(l, entity.get_height());
997 return 2;
998 });
999 }
1000
1001 /**
1002 * \brief Implementation of entity:set_size().
1003 * \param l The Lua context that is calling this function.
1004 * \return Number of values to return to Lua.
1005 */
entity_api_set_size(lua_State * l)1006 int LuaContext::entity_api_set_size(lua_State* l) {
1007
1008 return state_boundary_handle(l, [&] {
1009 Entity& entity = *check_entity(l, 1);
1010 int width = LuaTools::check_int(l, 2);
1011 int height = LuaTools::check_int(l, 3);
1012
1013 if (width <= 0) {
1014 std::ostringstream oss;
1015 oss << "Invalid width: " << width << ": should be positive";
1016 LuaTools::arg_error(l, 2, oss.str());
1017 }
1018 if (height <= 0) {
1019 std::ostringstream oss;
1020 oss << "Invalid height: " << height << ": should be positive";
1021 LuaTools::arg_error(l, 3, oss.str());
1022 }
1023
1024 entity.set_size(width, height);
1025 entity.notify_position_changed();
1026
1027 return 0;
1028 });
1029 }
1030
1031 /**
1032 * \brief Implementation of entity:get_origin().
1033 * \param l The Lua context that is calling this function.
1034 * \return Number of values to return to Lua.
1035 */
entity_api_get_origin(lua_State * l)1036 int LuaContext::entity_api_get_origin(lua_State* l) {
1037
1038 return state_boundary_handle(l, [&] {
1039 const Entity& entity = *check_entity(l, 1);
1040
1041 const Point& origin = entity.get_origin();
1042
1043 lua_pushinteger(l, origin.x);
1044 lua_pushinteger(l, origin.y);
1045 return 2;
1046 });
1047 }
1048
1049 /**
1050 * \brief Implementation of enemy:set_origin().
1051 * \param l The Lua context that is calling this function.
1052 * \return Number of values to return to Lua.
1053 */
entity_api_set_origin(lua_State * l)1054 int LuaContext::entity_api_set_origin(lua_State* l) {
1055
1056 return state_boundary_handle(l, [&] {
1057 Entity& entity = *check_entity(l, 1);
1058 int x = LuaTools::check_int(l, 2);
1059 int y = LuaTools::check_int(l, 3);
1060
1061 entity.set_origin(x, y);
1062 entity.notify_position_changed();
1063
1064 return 0;
1065 });
1066 }
1067
1068 /**
1069 * \brief Implementation of entity:get_position().
1070 * \param l The Lua context that is calling this function.
1071 * \return Number of values to return to Lua.
1072 */
entity_api_get_position(lua_State * l)1073 int LuaContext::entity_api_get_position(lua_State* l) {
1074 return state_boundary_handle(l, [&] {
1075 const Entity& entity = *check_entity(l, 1);
1076
1077 lua_pushinteger(l, entity.get_x());
1078 lua_pushinteger(l, entity.get_y());
1079 lua_pushinteger(l, entity.get_layer());
1080 return 3;
1081 });
1082 }
1083
1084 /**
1085 * \brief Implementation of entity:set_position().
1086 * \param l The Lua context that is calling this function.
1087 * \return Number of values to return to Lua.
1088 */
entity_api_set_position(lua_State * l)1089 int LuaContext::entity_api_set_position(lua_State* l) {
1090
1091 return state_boundary_handle(l, [&] {
1092 Entity& entity = *check_entity(l, 1);
1093 int x = LuaTools::check_int(l, 2);
1094 int y = LuaTools::check_int(l, 3);
1095 int layer = LuaTools::opt_layer(l, 4, entity.get_map(), entity.get_layer());
1096
1097 Entities& entities = entity.get_map().get_entities();
1098 entity.set_xy(x, y);
1099 entities.set_entity_layer(entity, layer);
1100 entity.notify_position_changed();
1101
1102 return 0;
1103 });
1104 }
1105
1106 /**
1107 * \brief Implementation of entity:get_center_position().
1108 * \param l The Lua context that is calling this function.
1109 * \return Number of values to return to Lua.
1110 */
entity_api_get_center_position(lua_State * l)1111 int LuaContext::entity_api_get_center_position(lua_State* l) {
1112
1113 return state_boundary_handle(l, [&] {
1114 const Entity& entity = *check_entity(l, 1);
1115
1116 const Point& center_point = entity.get_center_point();
1117 lua_pushinteger(l, center_point.x);
1118 lua_pushinteger(l, center_point.y);
1119 lua_pushinteger(l, entity.get_layer());
1120 return 3;
1121 });
1122 }
1123
1124 /**
1125 * \brief Implementation of entity:get_facing_position().
1126 * \param l The Lua context that is calling this function.
1127 * \return Number of values to return to Lua.
1128 */
entity_api_get_facing_position(lua_State * l)1129 int LuaContext::entity_api_get_facing_position(lua_State* l) {
1130
1131 return state_boundary_handle(l, [&] {
1132 const Entity& entity = *check_entity(l, 1);
1133
1134 const Point& facing_point = entity.get_facing_point();
1135 lua_pushinteger(l, facing_point.x);
1136 lua_pushinteger(l, facing_point.y);
1137 lua_pushinteger(l, entity.get_layer());
1138 return 3;
1139 });
1140 }
1141
1142 /**
1143 * \brief Implementation of entity:get_facing_entity().
1144 * \param l The Lua context that is calling this function.
1145 * \return Number of values to return to Lua.
1146 */
entity_api_get_facing_entity(lua_State * l)1147 int LuaContext::entity_api_get_facing_entity(lua_State* l) {
1148
1149 return state_boundary_handle(l, [&] {
1150 Entity& entity = *check_entity(l, 1);
1151
1152 Entity* facing_entity = entity.get_facing_entity();
1153 if (facing_entity == nullptr) {
1154 lua_pushnil(l);
1155 }
1156 else {
1157 push_entity(l, *facing_entity);
1158 }
1159 return 1;
1160 });
1161 }
1162
1163 /**
1164 * \brief Implementation of entity:get_ground_position().
1165 * \param l The Lua context that is calling this function.
1166 * \return Number of values to return to Lua.
1167 */
entity_api_get_ground_position(lua_State * l)1168 int LuaContext::entity_api_get_ground_position(lua_State* l) {
1169
1170 return state_boundary_handle(l, [&] {
1171 const Entity& entity = *check_entity(l, 1);
1172
1173 const Point& ground_point = entity.get_ground_point();
1174 lua_pushinteger(l, ground_point.x);
1175 lua_pushinteger(l, ground_point.y);
1176 lua_pushinteger(l, entity.get_layer());
1177 return 3;
1178 });
1179 }
1180
1181 /**
1182 * \brief Implementation of entity:get_ground_below().
1183 * \param l The Lua context that is calling this function.
1184 * \return Number of values to return to Lua.
1185 */
entity_api_get_ground_below(lua_State * l)1186 int LuaContext::entity_api_get_ground_below(lua_State* l) {
1187
1188 return state_boundary_handle(l, [&] {
1189 const Entity& entity = *check_entity(l, 1);
1190
1191 Ground ground = entity.get_ground_below();
1192
1193 push_string(l, enum_to_name(ground));
1194 return 1;
1195 });
1196 }
1197
1198 /**
1199 * \brief Implementation of entity:get_bounding_box().
1200 * \param l The Lua context that is calling this function.
1201 * \return Number of values to return to Lua.
1202 */
entity_api_get_bounding_box(lua_State * l)1203 int LuaContext::entity_api_get_bounding_box(lua_State* l) {
1204
1205 return state_boundary_handle(l, [&] {
1206 const Entity& entity = *check_entity(l, 1);
1207
1208 const Rectangle& bounding_box = entity.get_bounding_box();
1209 lua_pushinteger(l, bounding_box.get_x());
1210 lua_pushinteger(l, bounding_box.get_y());
1211 lua_pushinteger(l, bounding_box.get_width());
1212 lua_pushinteger(l, bounding_box.get_height());
1213 return 4;
1214 });
1215 }
1216
1217 /**
1218 * \brief Implementation of entity:get_max_bounding_box().
1219 * \param l The Lua context that is calling this function.
1220 * \return Number of values to return to Lua.
1221 */
entity_api_get_max_bounding_box(lua_State * l)1222 int LuaContext::entity_api_get_max_bounding_box(lua_State* l) {
1223
1224 return state_boundary_handle(l, [&] {
1225 const Entity& entity = *check_entity(l, 1);
1226
1227 const Rectangle& max_bounding_box = entity.get_max_bounding_box();
1228 lua_pushinteger(l, max_bounding_box.get_x());
1229 lua_pushinteger(l, max_bounding_box.get_y());
1230 lua_pushinteger(l, max_bounding_box.get_width());
1231 lua_pushinteger(l, max_bounding_box.get_height());
1232 return 4;
1233 });
1234 }
1235
1236 /**
1237 * \brief Implementation of entity:get_layer().
1238 * \param l The Lua context that is calling this function.
1239 * \return Number of values to return to Lua.
1240 */
entity_api_get_layer(lua_State * l)1241 int LuaContext::entity_api_get_layer(lua_State* l) {
1242
1243 return state_boundary_handle(l, [&] {
1244 const Entity& entity = *check_entity(l, 1);
1245
1246 lua_pushinteger(l, entity.get_layer());
1247 return 1;
1248 });
1249 }
1250
1251 /**
1252 * \brief Implementation of entity:set_layer().
1253 * \param l The Lua context that is calling this function.
1254 * \return Number of values to return to Lua.
1255 */
entity_api_set_layer(lua_State * l)1256 int LuaContext::entity_api_set_layer(lua_State* l) {
1257
1258 return state_boundary_handle(l, [&] {
1259 Entity& entity = *check_entity(l, 1);
1260 int layer = LuaTools::check_layer(l, 2, entity.get_map());
1261
1262 Entities& entities = entity.get_map().get_entities();
1263 entities.set_entity_layer(entity, layer);
1264 entity.notify_position_changed();
1265
1266 return 0;
1267 });
1268 }
1269
1270 /**
1271 * \brief Implementation of entity:overlaps().
1272 * \param l The Lua context that is calling this function.
1273 * \return Number of values to return to Lua.
1274 */
entity_api_overlaps(lua_State * l)1275 int LuaContext::entity_api_overlaps(lua_State* l) {
1276
1277 return state_boundary_handle(l, [&] {
1278 Entity& entity = *check_entity(l, 1);
1279
1280 bool overlaps = false;
1281 if (is_entity(l, 2)) {
1282 Entity& other_entity = *check_entity(l, 2);
1283 std::string collision_mode_name = LuaTools::opt_string(l, 3, "overlapping");
1284 SpritePtr entity_sprite;
1285 SpritePtr other_entity_sprite;
1286
1287 CollisionMode collision_mode = CollisionMode::COLLISION_NONE;
1288 if (collision_mode_name == "overlapping") {
1289 collision_mode = CollisionMode::COLLISION_OVERLAPPING;
1290 }
1291 else if (collision_mode_name == "containing") {
1292 collision_mode = CollisionMode::COLLISION_CONTAINING;
1293 }
1294 else if (collision_mode_name == "origin") {
1295 collision_mode = CollisionMode::COLLISION_ORIGIN;
1296 }
1297 else if (collision_mode_name == "facing") {
1298 collision_mode = CollisionMode::COLLISION_FACING;
1299 }
1300 else if (collision_mode_name == "touching") {
1301 collision_mode = CollisionMode::COLLISION_TOUCHING;
1302 }
1303 else if (collision_mode_name == "center") {
1304 collision_mode = CollisionMode::COLLISION_CENTER;
1305 }
1306 else if (collision_mode_name == "sprite") {
1307 collision_mode = CollisionMode::COLLISION_SPRITE;
1308 if (!lua_isnoneornil(l, 4)) {
1309 entity_sprite = check_sprite(l, 4);
1310 }
1311 if (!lua_isnoneornil(l, 5)) {
1312 other_entity_sprite = check_sprite(l, 5);
1313 }
1314 }
1315 else {
1316 LuaTools::arg_error(l, 3,
1317 std::string("Invalid name '") + collision_mode_name + "'"
1318 );
1319 }
1320
1321 overlaps = entity.test_collision(other_entity, collision_mode, entity_sprite, other_entity_sprite);
1322 }
1323 else if (lua_isnumber(l, 2)) {
1324 int x = LuaTools::check_int(l, 2);
1325 int y = LuaTools::check_int(l, 3);
1326 int width = LuaTools::opt_int(l, 4, 1);
1327 int height = LuaTools::opt_int(l, 5, 1);
1328 overlaps = entity.overlaps(Rectangle(x, y, width, height));
1329 }
1330 else {
1331 LuaTools::type_error(l, 2, "entity or integer");
1332 }
1333
1334 lua_pushboolean(l, overlaps);
1335 return 1;
1336 });
1337 }
1338
1339 /**
1340 * \brief Implementation of entity:snap_to_grid().
1341 * \param l The Lua context that is calling this function.
1342 * \return Number of values to return to Lua.
1343 */
entity_api_snap_to_grid(lua_State * l)1344 int LuaContext::entity_api_snap_to_grid(lua_State* l) {
1345
1346 return state_boundary_handle(l, [&] {
1347 Entity& entity = *check_entity(l, 1);
1348
1349 entity.set_aligned_to_grid();
1350
1351 return 0;
1352 });
1353 }
1354
1355 /**
1356 * \brief Implementation of entity:get_distance().
1357 * \param l The Lua context that is calling this function.
1358 * \return Number of values to return to Lua.
1359 */
entity_api_get_distance(lua_State * l)1360 int LuaContext::entity_api_get_distance(lua_State* l) {
1361
1362 return state_boundary_handle(l, [&] {
1363 const Entity& entity = *check_entity(l, 1);
1364 int distance;
1365 if (lua_gettop(l) >= 3) {
1366 int x = LuaTools::check_number(l, 2);
1367 int y = LuaTools::check_number(l, 3);
1368 distance = entity.get_distance(x, y);
1369 }
1370 else {
1371 const Entity& other_entity = *check_entity(l, 2);
1372 distance = entity.get_distance(other_entity);
1373 }
1374
1375 lua_pushinteger(l, distance);
1376 return 1;
1377 });
1378 }
1379
1380 /**
1381 * \brief Implementation of entity:get_angle().
1382 * \param l The Lua context that is calling this function.
1383 * \return Number of values to return to Lua.
1384 */
entity_api_get_angle(lua_State * l)1385 int LuaContext::entity_api_get_angle(lua_State* l) {
1386
1387 return state_boundary_handle(l, [&] {
1388 const Entity& entity = *check_entity(l, 1);
1389 double angle;
1390 if (lua_gettop(l) >= 3) {
1391 int x = LuaTools::check_number(l, 2);
1392 int y = LuaTools::check_number(l, 3);
1393 angle = entity.get_angle(x, y);
1394 }
1395 else {
1396 const Entity& other_entity = *check_entity(l, 2);
1397 angle = entity.get_angle(other_entity);
1398 }
1399
1400 lua_pushnumber(l, angle);
1401 return 1;
1402 });
1403 }
1404
1405 /**
1406 * \brief Implementation of entity:get_direction4_to().
1407 * \param l The Lua context that is calling this function.
1408 * \return Number of values to return to Lua.
1409 */
entity_api_get_direction4_to(lua_State * l)1410 int LuaContext::entity_api_get_direction4_to(lua_State* l) {
1411
1412 return state_boundary_handle(l, [&] {
1413 const Entity& entity = *check_entity(l, 1);
1414 double angle;
1415 if (lua_gettop(l) >= 3) {
1416 int x = LuaTools::check_number(l, 2);
1417 int y = LuaTools::check_number(l, 3);
1418 angle = entity.get_angle(x, y);
1419 }
1420 else {
1421 const Entity& other_entity = *check_entity(l, 2);
1422 angle = entity.get_angle(other_entity);
1423 }
1424
1425 // Convert from radians.
1426 int direction4 = (angle + Geometry::PI_OVER_4) / Geometry::PI_OVER_2;
1427
1428 // Normalize.
1429 direction4 = (direction4 + 4) % 4;
1430
1431 lua_pushnumber(l, direction4);
1432 return 1;
1433 });
1434 }
1435
1436 /**
1437 * \brief Implementation of entity:get_direction8_to().
1438 * \param l The Lua context that is calling this function.
1439 * \return Number of values to return to Lua.
1440 */
entity_api_get_direction8_to(lua_State * l)1441 int LuaContext::entity_api_get_direction8_to(lua_State* l) {
1442
1443 return state_boundary_handle(l, [&] {
1444 const Entity& entity = *check_entity(l, 1);
1445 double angle;
1446 if (lua_gettop(l) >= 3) {
1447 int x = LuaTools::check_number(l, 2);
1448 int y = LuaTools::check_number(l, 3);
1449 angle = entity.get_angle(x, y);
1450 }
1451 else {
1452 const Entity& other_entity = *check_entity(l, 2);
1453 angle = entity.get_angle(other_entity);
1454 }
1455
1456 // Convert from radians.
1457 int direction8 = (angle + Geometry::PI_OVER_4 / 2) / Geometry::PI_OVER_4;
1458
1459 // Normalize.
1460 direction8 = (direction8 + 8) % 8;
1461
1462 lua_pushnumber(l, direction8);
1463 return 1;
1464 });
1465 }
1466
1467 /**
1468 * \brief Implementation of entity:bring_to_front().
1469 * \param l The Lua context that is calling this function.
1470 * \return Number of values to return to Lua.
1471 */
entity_api_bring_to_front(lua_State * l)1472 int LuaContext::entity_api_bring_to_front(lua_State* l) {
1473
1474 return state_boundary_handle(l, [&] {
1475 Entity& entity = *check_entity(l, 1);
1476
1477 entity.get_map().get_entities().bring_to_front(entity);
1478
1479 return 0;
1480 });
1481 }
1482
1483 /**
1484 * \brief Implementation of entity:bring_to_back().
1485 * \param l The Lua context that is calling this function.
1486 * \return Number of values to return to Lua.
1487 */
entity_api_bring_to_back(lua_State * l)1488 int LuaContext::entity_api_bring_to_back(lua_State* l) {
1489
1490 return state_boundary_handle(l, [&] {
1491 Entity& entity = *check_entity(l, 1);
1492
1493 entity.get_map().get_entities().bring_to_back(entity);
1494
1495 return 0;
1496 });
1497 }
1498
1499 /**
1500 * \brief Implementation of entity:is_drawn_in_y_order().
1501 * \param l The Lua context that is calling this function.
1502 * \return Number of values to return to Lua.
1503 */
entity_api_is_drawn_in_y_order(lua_State * l)1504 int LuaContext::entity_api_is_drawn_in_y_order(lua_State* l) {
1505
1506 return state_boundary_handle(l, [&] {
1507 const Entity& entity = *check_entity(l, 1);
1508
1509 lua_pushboolean(l, entity.is_drawn_in_y_order());
1510 return 1;
1511 });
1512 }
1513
1514 /**
1515 * \brief Implementation of entity:set_drawn_in_y_order().
1516 * \param l The Lua context that is calling this function.
1517 * \return Number of values to return to Lua.
1518 */
entity_api_set_drawn_in_y_order(lua_State * l)1519 int LuaContext::entity_api_set_drawn_in_y_order(lua_State* l) {
1520
1521 return state_boundary_handle(l, [&] {
1522 Entity& entity = *check_entity(l, 1);
1523 bool y_order = LuaTools::opt_boolean(l, 2, true);
1524
1525 entity.set_drawn_in_y_order(y_order);
1526
1527 return 0;
1528 });
1529 }
1530
1531 /**
1532 * \brief Implementation of entity:get_sprite().
1533 * \param l The Lua context that is calling this function.
1534 * \return Number of values to return to Lua.
1535 */
entity_api_get_sprite(lua_State * l)1536 int LuaContext::entity_api_get_sprite(lua_State* l) {
1537
1538 return state_boundary_handle(l, [&] {
1539 Entity& entity = *check_entity(l, 1);
1540 std::string sprite_name = LuaTools::opt_string(l, 2 ,"");
1541
1542 const SpritePtr& sprite = entity.get_sprite(sprite_name);
1543 if (sprite != nullptr) {
1544 push_sprite(l, *sprite);
1545 }
1546 else {
1547 lua_pushnil(l);
1548 }
1549 return 1;
1550 });
1551 }
1552
1553 /**
1554 * \brief Implementation of entity:get_sprites().
1555 * \param l The Lua context that is calling this function.
1556 * \return Number of values to return to Lua.
1557 */
entity_api_get_sprites(lua_State * l)1558 int LuaContext::entity_api_get_sprites(lua_State* l) {
1559
1560 return state_boundary_handle(l, [&] {
1561 Entity& entity = *check_entity(l, 1);
1562
1563 const std::vector<Entity::NamedSprite> named_sprites = entity.get_named_sprites();
1564 push_named_sprite_iterator(l, named_sprites);
1565 return 1;
1566 });
1567 }
1568
1569 /**
1570 * \brief Implementation of entity:create_sprite().
1571 * \param l The Lua context that is calling this function.
1572 * \return Number of values to return to Lua.
1573 */
entity_api_create_sprite(lua_State * l)1574 int LuaContext::entity_api_create_sprite(lua_State* l) {
1575
1576 return state_boundary_handle(l, [&] {
1577 Entity& entity = *check_entity(l, 1);
1578 const std::string& animation_set_id = LuaTools::check_string(l, 2);
1579 const std::string& sprite_name = LuaTools::opt_string(l, 3, "");
1580
1581 if (!sprite_name.empty() &&
1582 entity.get_sprite(sprite_name) != nullptr) {
1583 LuaTools::arg_error(l, 3, "This entity already has a sprite named '" + sprite_name + "'");
1584 }
1585
1586 const SpritePtr& sprite = entity.create_sprite(animation_set_id, sprite_name);
1587 sprite->enable_pixel_collisions();
1588
1589 //if entity is already on a map, notify the sprite that tileset is there
1590 if(entity.is_on_map()){
1591 const Map& map = entity.get_map();
1592 sprite->set_tileset(map.get_tileset());
1593 }
1594
1595 if (entity.is_suspended()) {
1596 sprite->set_suspended(true);
1597 }
1598
1599 push_sprite(l, *sprite);
1600 return 1;
1601 });
1602 }
1603
1604 /**
1605 * \brief Implementation of entity:remove_sprite().
1606 * \param l The Lua context that is calling this function.
1607 * \return Number of values to return to Lua.
1608 */
entity_api_remove_sprite(lua_State * l)1609 int LuaContext::entity_api_remove_sprite(lua_State* l) {
1610
1611 return state_boundary_handle(l, [&] {
1612 Entity& entity = *check_entity(l, 1);
1613
1614 if (lua_gettop(l) >= 2) {
1615 Sprite& sprite = *check_sprite(l, 2);
1616 bool success = entity.remove_sprite(sprite);
1617 if (!success) {
1618 LuaTools::arg_error(l, 2, "This sprite does not belong to this entity");
1619 }
1620 }
1621 else {
1622 const SpritePtr& sprite = entity.get_sprite();
1623 if (sprite == nullptr) {
1624 LuaTools::error(l, "This entity has no sprite");
1625 }
1626 entity.remove_sprite(*sprite);
1627 }
1628
1629 return 0;
1630 });
1631 }
1632
1633 /**
1634 * \brief Implementation of entity:bring_sprite_to_front().
1635 * \param l The Lua context that is calling this function.
1636 * \return Number of values to return to Lua.
1637 */
entity_api_bring_sprite_to_front(lua_State * l)1638 int LuaContext::entity_api_bring_sprite_to_front(lua_State* l) {
1639
1640 return state_boundary_handle(l, [&] {
1641 Entity& entity = *check_entity(l, 1);
1642 Sprite& sprite = *check_sprite(l, 2);
1643 bool success = entity.bring_sprite_to_front(sprite);
1644 if (!success) {
1645 LuaTools::arg_error(l, 2, "This sprite does not belong to this entity");
1646 }
1647
1648 return 0;
1649 });
1650 }
1651
1652 /**
1653 * \brief Implementation of entity:bring_sprite_to_back().
1654 * \param l The Lua context that is calling this function.
1655 * \return Number of values to return to Lua.
1656 */
entity_api_bring_sprite_to_back(lua_State * l)1657 int LuaContext::entity_api_bring_sprite_to_back(lua_State* l) {
1658
1659 return state_boundary_handle(l, [&] {
1660 Entity& entity = *check_entity(l, 1);
1661 Sprite& sprite = *check_sprite(l, 2);
1662 bool success = entity.bring_sprite_to_back(sprite);
1663 if (!success) {
1664 LuaTools::arg_error(l, 2, "This sprite does not belong to this entity");
1665 }
1666
1667 return 0;
1668 });
1669 }
1670
1671 /**
1672 * \brief Implementation of entity:is_visible().
1673 * \param l The Lua context that is calling this function.
1674 * \return Number of values to return to Lua.
1675 */
entity_api_is_visible(lua_State * l)1676 int LuaContext::entity_api_is_visible(lua_State* l) {
1677
1678 return state_boundary_handle(l, [&] {
1679 const Entity& entity = *check_entity(l, 1);
1680
1681 lua_pushboolean(l, entity.is_visible());
1682 return 1;
1683 });
1684 }
1685
1686 /**
1687 * \brief Implementation of entity:set_visible().
1688 * \param l The Lua context that is calling this function.
1689 * \return Number of values to return to Lua.
1690 */
entity_api_set_visible(lua_State * l)1691 int LuaContext::entity_api_set_visible(lua_State* l) {
1692
1693 return state_boundary_handle(l, [&] {
1694 Entity& entity = *check_entity(l, 1);
1695 bool visible = LuaTools::opt_boolean(l, 2, true);
1696
1697 entity.set_visible(visible);
1698
1699 return 0;
1700 });
1701 }
1702
1703 /**
1704 * \brief Implementation of entity:get_draw_override().
1705 * \param l The Lua context that is calling this function.
1706 * \return Number of values to return to Lua.
1707 */
entity_api_get_draw_override(lua_State * l)1708 int LuaContext::entity_api_get_draw_override(lua_State* l) {
1709
1710 return state_boundary_handle(l, [&] {
1711 const Entity& entity = *check_entity(l, 1);
1712
1713 ScopedLuaRef draw_override = entity.get_draw_override();
1714 if (draw_override.is_empty()) {
1715 lua_pushnil(l);
1716 }
1717 else {
1718 push_ref(l, draw_override);
1719 }
1720 return 1;
1721 });
1722 }
1723
1724 /**
1725 * \brief Implementation of entity:set_draw_override().
1726 * \param l The Lua context that is calling this function.
1727 * \return Number of values to return to Lua.
1728 */
entity_api_set_draw_override(lua_State * l)1729 int LuaContext::entity_api_set_draw_override(lua_State* l) {
1730
1731 return state_boundary_handle(l, [&] {
1732 Entity& entity = *check_entity(l, 1);
1733 ScopedLuaRef draw_override;
1734 if (lua_gettop(l) >= 2) {
1735 if (lua_isfunction(l, 2)) {
1736 draw_override = LuaTools::check_function(l, 2);
1737 }
1738 else if (!lua_isnil(l, 2)) {
1739 LuaTools::type_error(l, 2, "function or nil");
1740 }
1741 }
1742
1743 entity.set_draw_override(draw_override);
1744
1745 return 0;
1746 });
1747 }
1748
1749 /**
1750 * \brief Implementation of entity:get_weight().
1751 * \param l The Lua context that is calling this function.
1752 * \return Number of values to return to Lua.
1753 */
entity_api_get_weight(lua_State * l)1754 int LuaContext::entity_api_get_weight(lua_State* l) {
1755
1756 return state_boundary_handle(l, [&] {
1757 const Entity& entity = *check_entity(l, 1);
1758
1759 int weight = entity.get_weight();
1760
1761 lua_pushinteger(l, weight);
1762 return 1;
1763 });
1764 }
1765
1766 /**
1767 * \brief Implementation of entity:set_weight().
1768 * \param l The Lua context that is calling this function.
1769 * \return Number of values to return to Lua.
1770 */
entity_api_set_weight(lua_State * l)1771 int LuaContext::entity_api_set_weight(lua_State* l) {
1772
1773 return state_boundary_handle(l, [&] {
1774 Entity& entity = *check_entity(l, 1);
1775 int weight = LuaTools::check_int(l, 2);
1776
1777 entity.set_weight(weight);
1778
1779 return 0;
1780 });
1781 }
1782
1783 /**
1784 * \brief Implementation of entity:entity_api_get_controlling_stream().
1785 * \param l The Lua context that is calling this function.
1786 * \return Number of values to return to Lua.
1787 */
entity_api_get_controlling_stream(lua_State * l)1788 int LuaContext::entity_api_get_controlling_stream(lua_State* l) {
1789
1790 return state_boundary_handle(l, [&] {
1791 Entity& entity = *check_entity(l, 1);
1792
1793 StreamAction* stream_action = entity.get_stream_action();
1794 if (stream_action == nullptr) {
1795 lua_pushnil(l);
1796 }
1797 else {
1798 push_stream(l, stream_action->get_stream());
1799 }
1800 return 1;
1801 });
1802 }
1803
1804 /**
1805 * \brief Implementation of entity:get_movement().
1806 * \param l The Lua context that is calling this function.
1807 * \return Number of values to return to Lua.
1808 */
entity_api_get_movement(lua_State * l)1809 int LuaContext::entity_api_get_movement(lua_State* l) {
1810
1811 return state_boundary_handle(l, [&] {
1812 Entity& entity = *check_entity(l, 1);
1813
1814 const std::shared_ptr<Movement>& movement = entity.get_movement();
1815 if (movement == nullptr) {
1816 lua_pushnil(l);
1817 }
1818 else {
1819 push_userdata(l, *movement);
1820 }
1821
1822 return 1;
1823 });
1824 }
1825
1826 /**
1827 * \brief Implementation of entity:stop_movement().
1828 * \param l The Lua context that is calling this function.
1829 * \return Number of values to return to Lua.
1830 */
entity_api_stop_movement(lua_State * l)1831 int LuaContext::entity_api_stop_movement(lua_State* l) {
1832
1833 Entity& entity = *check_entity(l, 1);
1834
1835 entity.clear_movement();
1836
1837 return 0;
1838 }
1839
1840 /**
1841 * \brief Implementation of
1842 * pickable:has_layer_independent_collisions() and
1843 * enemy:has_layer_independent_collisions().
1844 * \param l The Lua context that is calling this function.
1845 * \return Number of values to return to Lua.
1846 */
entity_api_has_layer_independent_collisions(lua_State * l)1847 int LuaContext::entity_api_has_layer_independent_collisions(lua_State* l) {
1848
1849 return state_boundary_handle(l, [&] {
1850 const Entity& entity = *check_entity(l, 1);
1851
1852 bool independent = entity.has_layer_independent_collisions();
1853
1854 lua_pushboolean(l, independent);
1855 return 1;
1856 });
1857 }
1858
1859 /**
1860 * \brief Implementation of
1861 * pickable:set_layer_independent_collisions() and
1862 * enemy:set_layer_independent_collisions().
1863 * \param l The Lua context that is calling this function.
1864 * \return Number of values to return to Lua.
1865 */
entity_api_set_layer_independent_collisions(lua_State * l)1866 int LuaContext::entity_api_set_layer_independent_collisions(lua_State* l) {
1867
1868 return state_boundary_handle(l, [&] {
1869 Entity& entity = *check_entity(l, 1);
1870 bool independent = LuaTools::opt_boolean(l, 2, true);
1871
1872 entity.set_layer_independent_collisions(independent);
1873
1874 return 0;
1875 });
1876 }
1877
1878 /**
1879 * \brief Implementation of entity:test_obstacles().
1880 * \param l The Lua context that is calling this function.
1881 * \return Number of values to return to Lua.
1882 */
entity_api_test_obstacles(lua_State * l)1883 int LuaContext::entity_api_test_obstacles(lua_State* l) {
1884
1885 return state_boundary_handle(l, [&] {
1886 Entity& entity = *check_entity(l, 1);
1887 int dx = LuaTools::opt_int(l, 2, 0);
1888 int dy = LuaTools::opt_int(l, 3, 0);
1889 int layer = entity.get_layer();
1890 if (lua_gettop(l) >= 4) {
1891 layer = LuaTools::check_layer(l, 4, entity.get_map());
1892 }
1893
1894 Rectangle bounding_box = entity.get_bounding_box();
1895 bounding_box.add_xy(dx, dy);
1896
1897 lua_pushboolean(l, entity.get_map().test_collision_with_obstacles(
1898 layer, bounding_box, entity));
1899 return 1;
1900 });
1901 }
1902
1903 /**
1904 * \brief Implementation of entity:get_optimization_distance().
1905 * \param l The Lua context that is calling this function.
1906 * \return Number of values to return to Lua.
1907 */
entity_api_get_optimization_distance(lua_State * l)1908 int LuaContext::entity_api_get_optimization_distance(lua_State* l) {
1909
1910 return state_boundary_handle(l, [&] {
1911 const Entity& entity = *check_entity(l, 1);
1912
1913 lua_pushinteger(l, entity.get_optimization_distance());
1914 return 1;
1915 });
1916 }
1917
1918 /**
1919 * \brief Implementation of entity:set_optimization_distance().
1920 * \param l The Lua context that is calling this function.
1921 * \return Number of values to return to Lua.
1922 */
entity_api_set_optimization_distance(lua_State * l)1923 int LuaContext::entity_api_set_optimization_distance(lua_State* l) {
1924
1925 return state_boundary_handle(l, [&] {
1926 Entity& entity = *check_entity(l, 1);
1927 int distance = LuaTools::check_int(l, 2);
1928
1929 entity.set_optimization_distance(distance);
1930
1931 return 0;
1932 });
1933 }
1934
1935 /**
1936 * \brief Implementation of entity:is_in_same_region().
1937 * \param l The Lua context that is calling this function.
1938 * \return Number of values to return to Lua.
1939 */
entity_api_is_in_same_region(lua_State * l)1940 int LuaContext::entity_api_is_in_same_region(lua_State* l) {
1941
1942 return state_boundary_handle(l, [&] {
1943 const Entity& entity = *check_entity(l, 1);
1944 const Entity& other_entity = *check_entity(l, 2);
1945
1946 lua_pushboolean(l, entity.is_in_same_region(other_entity));
1947 return 1;
1948 });
1949 }
1950
1951 /**
1952 * \brief Implementation of hero:get_state() and camera:get_state().
1953 * \param l The Lua context that is calling this function.
1954 * \return Number of values to return to Lua.
1955 */
entity_api_get_state(lua_State * l)1956 int LuaContext::entity_api_get_state(lua_State* l) {
1957
1958 return state_boundary_handle(l, [&] {
1959 const Entity& entity = *check_entity(l, 1);
1960
1961 std::string state_name = entity.get_state_name();
1962 if (state_name.empty()) {
1963 lua_pushnil(l);
1964 return 1;
1965 }
1966
1967 push_string(l, state_name);
1968 if (state_name == "custom") {
1969 CustomState& state = *std::static_pointer_cast<CustomState>(entity.get_state());
1970 push_state(l, state);
1971 return 2;
1972 }
1973 return 1;
1974 });
1975 }
1976
1977 /**
1978 * \brief Implementation of entity:get_property().
1979 * \param l The Lua context that is calling this function.
1980 * \return Number of values to return to Lua.
1981 */
entity_api_get_property(lua_State * l)1982 int LuaContext::entity_api_get_property(lua_State* l) {
1983
1984 return state_boundary_handle(l, [&] {
1985 const Entity& entity = *check_entity(l, 1);
1986 const std::string& key = LuaTools::check_string(l, 2);
1987
1988 if (!entity.has_user_property(key)) {
1989 lua_pushnil(l);
1990 }
1991 else {
1992 const std::string& value = entity.get_user_property_value(key);
1993 push_string(l, value);
1994 }
1995 return 1;
1996 });
1997 }
1998
1999 /**
2000 * \brief Implementation of entity:set_property().
2001 * \param l The Lua context that is calling this function.
2002 * \return Number of values to return to Lua.
2003 */
entity_api_set_property(lua_State * l)2004 int LuaContext::entity_api_set_property(lua_State* l) {
2005
2006 return state_boundary_handle(l, [&] {
2007 Entity& entity = *check_entity(l, 1);
2008 const std::string& key = LuaTools::check_string(l, 2);
2009
2010 if (lua_isnil(l, 3)) {
2011 entity.remove_user_property(key);
2012 }
2013 else {
2014 const std::string& value = LuaTools::check_string(l, 3);
2015
2016 if (!EntityData::is_user_property_key_valid(key)) {
2017 LuaTools::arg_error(l, 2, "Invalid property key: '" + key + "'");
2018 }
2019 entity.set_user_property_value(key, value);
2020 }
2021
2022 return 0;
2023 });
2024 }
2025
2026 /**
2027 * \brief Implementation of entity:get_properties().
2028 * \param l The Lua context that is calling this function.
2029 * \return Number of values to return to Lua.
2030 */
entity_api_get_properties(lua_State * l)2031 int LuaContext::entity_api_get_properties(lua_State* l) {
2032
2033 return state_boundary_handle(l, [&] {
2034 const Entity& entity = *check_entity(l, 1);
2035
2036 const std::vector<Entity::UserProperty>& properties = entity.get_user_properties();
2037 lua_createtable(l, properties.size(), 0);
2038 int i = 1;
2039 for (const Entity::UserProperty& property : properties) {
2040 lua_createtable(l, 0, 2);
2041 push_string(l, property.first);
2042 lua_setfield(l, -2, "key");
2043 push_string(l, property.second);
2044 lua_setfield(l, -2, "value");
2045 lua_rawseti(l, -2, i);
2046 ++i;
2047 }
2048
2049 return 1;
2050 });
2051 }
2052
2053 /**
2054 * \brief Implementation of entity:set_properties().
2055 * \param l The Lua context that is calling this function.
2056 * \return Number of values to return to Lua.
2057 */
entity_api_set_properties(lua_State * l)2058 int LuaContext::entity_api_set_properties(lua_State* l) {
2059
2060 return state_boundary_handle(l, [&] {
2061 Entity& entity = *check_entity(l, 1);
2062 LuaTools::check_type(l, 2, LUA_TTABLE);
2063
2064 entity.set_user_properties({});
2065 lua_pushnil(l);
2066 while (lua_next(l, 2) != 0) {
2067 LuaTools::check_type(l, -1, LUA_TTABLE);
2068 const std::string& key = LuaTools::check_string_field(l, -1, "key");
2069 const std::string& value = LuaTools::check_string_field(l, -1, "value");
2070 if (entity.has_user_property(key)) {
2071 LuaTools::error(l, "Duplicate property '" + key + "'");
2072 }
2073 if (!EntityData::is_user_property_key_valid(key)) {
2074 LuaTools::error(l, "Invalid property key: '" + key + "'");
2075 }
2076 entity.set_user_property_value(key, value);
2077 lua_pop(l, 1);
2078 }
2079
2080 return 1;
2081 });
2082 }
2083
2084 /**
2085 * \brief Returns whether a value is a userdata of type hero.
2086 * \param l A Lua context.
2087 * \param index An index in the stack.
2088 * \return \c true if the value at this index is a hero.
2089 */
is_hero(lua_State * l,int index)2090 bool LuaContext::is_hero(lua_State* l, int index) {
2091 return is_userdata(l, index, get_entity_internal_type_name(EntityType::HERO));
2092 }
2093
2094 /**
2095 * \brief Checks that the userdata at the specified index of the stack is a
2096 * hero and returns it.
2097 * \param l A Lua context.
2098 * \param index An index in the stack.
2099 * \return The hero.
2100 */
check_hero(lua_State * l,int index)2101 std::shared_ptr<Hero> LuaContext::check_hero(lua_State* l, int index) {
2102 return std::static_pointer_cast<Hero>(check_userdata(
2103 l, index, get_entity_internal_type_name(EntityType::HERO)
2104 ));
2105 }
2106
2107 /**
2108 * \brief Pushes a hero userdata onto the stack.
2109 * \param l A Lua context.
2110 * \param hero A hero.
2111 */
push_hero(lua_State * l,Hero & hero)2112 void LuaContext::push_hero(lua_State* l, Hero& hero) {
2113 push_userdata(l, hero);
2114 }
2115
2116 /**
2117 * \brief Implementation of hero:teleport().
2118 * \param l The Lua context that is calling this function.
2119 * \return Number of values to return to Lua.
2120 */
hero_api_teleport(lua_State * l)2121 int LuaContext::hero_api_teleport(lua_State* l) {
2122
2123 return state_boundary_handle(l, [&] {
2124 Hero& hero = *check_hero(l, 1);
2125 Game& game = hero.get_game();
2126 const std::string& map_id = LuaTools::check_string(l, 2);
2127 const std::string& destination_name = LuaTools::opt_string(l, 3, "");
2128 Transition::Style transition_style = LuaTools::opt_enum<Transition::Style>(
2129 l, 4, game.get_default_transition_style());
2130
2131 if (!CurrentQuest::resource_exists(ResourceType::MAP, map_id)) {
2132 LuaTools::arg_error(l, 2, std::string("No such map: '") + map_id + "'");
2133 }
2134
2135 game.set_current_map(map_id, destination_name, transition_style);
2136
2137 return 0;
2138 });
2139 }
2140
2141 /**
2142 * \brief Implementation of hero:get_direction().
2143 * \param l The Lua context that is calling this function.
2144 * \return Number of values to return to Lua.
2145 */
hero_api_get_direction(lua_State * l)2146 int LuaContext::hero_api_get_direction(lua_State* l) {
2147
2148 return state_boundary_handle(l, [&] {
2149 const Hero& hero = *check_hero(l, 1);
2150
2151 lua_pushinteger(l, hero.get_animation_direction());
2152 return 1;
2153 });
2154 }
2155
2156 /**
2157 * \brief Implementation of hero:set_direction().
2158 * \param l The Lua context that is calling this function.
2159 * \return Number of values to return to Lua.
2160 */
hero_api_set_direction(lua_State * l)2161 int LuaContext::hero_api_set_direction(lua_State* l) {
2162
2163 return state_boundary_handle(l, [&] {
2164 Hero& hero = *check_hero(l, 1);
2165 int direction = LuaTools::check_int(l, 2);
2166
2167 hero.set_animation_direction(direction);
2168
2169 return 0;
2170 });
2171 }
2172
2173 /**
2174 * \brief Implementation of hero:get_walking_speed().
2175 * \param l The Lua context that is calling this function.
2176 * \return Number of values to return to Lua.
2177 */
hero_api_get_walking_speed(lua_State * l)2178 int LuaContext::hero_api_get_walking_speed(lua_State* l) {
2179
2180 return state_boundary_handle(l, [&] {
2181 const Hero& hero = *check_hero(l, 1);
2182
2183 lua_pushinteger(l, hero.get_normal_walking_speed());
2184 return 1;
2185 });
2186 }
2187
2188 /**
2189 * \brief Implementation of hero:set_walking_speed().
2190 * \param l The Lua context that is calling this function.
2191 * \return Number of values to return to Lua.
2192 */
hero_api_set_walking_speed(lua_State * l)2193 int LuaContext::hero_api_set_walking_speed(lua_State* l) {
2194
2195 return state_boundary_handle(l, [&] {
2196 Hero& hero = *check_hero(l, 1);
2197 int normal_walking_speed = LuaTools::check_int(l, 2);
2198
2199 hero.set_normal_walking_speed(normal_walking_speed);
2200
2201 return 0;
2202 });
2203 }
2204
2205 /**
2206 * \brief Implementation of hero:save_solid_ground().
2207 * \param l The Lua context that is calling this function.
2208 * \return Number of values to return to Lua.
2209 */
hero_api_save_solid_ground(lua_State * l)2210 int LuaContext::hero_api_save_solid_ground(lua_State* l) {
2211
2212 return state_boundary_handle(l, [&] {
2213 Hero& hero = *check_hero(l, 1);
2214
2215 ScopedLuaRef callback;
2216 if (lua_gettop(l) == 2) {
2217 // Function parameter.
2218 if (lua_isnil(l, 2)) {
2219 hero.reset_target_solid_ground_callback();
2220 return 0;
2221 }
2222 else {
2223 callback = LuaTools::check_function(l, 2);
2224 }
2225 }
2226 else {
2227 // Coordinates and layer.
2228 int x = 0;
2229 int y = 0;
2230 int layer = 0;
2231 if (lua_gettop(l) >= 2) {
2232 x = LuaTools::check_int(l, 2);
2233 y = LuaTools::check_int(l, 3);
2234 layer = LuaTools::check_layer(l, 4, hero.get_map());
2235 }
2236 else {
2237 x = hero.get_x();
2238 y = hero.get_y();
2239 layer = hero.get_layer();
2240 }
2241 callback = hero.make_solid_ground_callback(Point(x, y), layer);
2242 }
2243 hero.set_target_solid_ground_callback(callback);
2244
2245 return 0;
2246 });
2247 }
2248
2249 /**
2250 * \brief Implementation of hero:reset_solid_ground().
2251 * \param l The Lua context that is calling this function.
2252 * \return Number of values to return to Lua.
2253 */
hero_api_reset_solid_ground(lua_State * l)2254 int LuaContext::hero_api_reset_solid_ground(lua_State* l) {
2255
2256 return state_boundary_handle(l, [&] {
2257 Hero& hero = *check_hero(l, 1);
2258
2259 hero.reset_target_solid_ground_callback();
2260
2261 return 0;
2262 });
2263 }
2264
2265 /**
2266 * \brief Implementation of hero:get_solid_ground().
2267 * \param l The Lua context that is calling this function.
2268 * \return Number of values to return to Lua.
2269 */
hero_api_get_solid_ground_position(lua_State * l)2270 int LuaContext::hero_api_get_solid_ground_position(lua_State* l) {
2271
2272 return state_boundary_handle(l, [&] {
2273 const Hero& hero = *check_hero(l, 1);
2274
2275 Point xy;
2276 int layer = 0;
2277
2278 const ScopedLuaRef& solid_ground_callback = hero.get_target_solid_ground_callback();
2279 if (!solid_ground_callback.is_empty()) {
2280 // Coordinates memorized by hero:save_solid_ground().
2281 //TODO verify if this call is coroutine friendly
2282 solid_ground_callback.push(l);
2283 bool success = LuaTools::call_function(l,0,3,"Solid ground callback");
2284 if (!success) {
2285 // Fallback: use the last solid ground position.
2286 xy = hero.get_last_solid_ground_coords();
2287 layer = hero.get_last_solid_ground_layer();
2288 lua_pushinteger(l, xy.x);
2289 lua_pushinteger(l, xy.y);
2290 lua_pushinteger(l, layer);
2291 return 3;
2292 }
2293 else {
2294 // Normal case: use the result of the function.
2295 return 3;
2296 }
2297 }
2298 else if (hero.get_last_solid_ground_coords().x != -1) {
2299 xy = hero.get_last_solid_ground_coords();
2300 layer = hero.get_last_solid_ground_layer();
2301 // Last solid ground coordinates.
2302 lua_pushinteger(l, xy.x);
2303 lua_pushinteger(l, xy.y);
2304 lua_pushinteger(l, layer);
2305 return 3;
2306 }
2307 else {
2308 // No solid ground coordinates.
2309 // Maybe the map started in water.
2310 lua_pushnil(l);
2311 return 1;
2312 }
2313 });
2314 }
2315
2316 /**
2317 * \brief Implementation of hero:get_animation().
2318 * \param l The Lua context that is calling this function.
2319 * \return Number of values to return to Lua.
2320 */
hero_api_get_animation(lua_State * l)2321 int LuaContext::hero_api_get_animation(lua_State* l) {
2322
2323 return state_boundary_handle(l, [&] {
2324 Hero& hero = *check_hero(l, 1);
2325
2326 const std::string& animation = hero.get_hero_sprites().get_tunic_animation();
2327
2328 push_string(l, animation);
2329 return 1;
2330 });
2331 }
2332
2333 /**
2334 * \brief Implementation of hero:set_animation().
2335 * \param l The Lua context that is calling this function.
2336 * \return Number of values to return to Lua.
2337 */
hero_api_set_animation(lua_State * l)2338 int LuaContext::hero_api_set_animation(lua_State* l) {
2339
2340 return state_boundary_handle(l, [&] {
2341 Hero& hero = *check_hero(l, 1);
2342 const std::string& animation = LuaTools::check_string(l, 2);
2343 const ScopedLuaRef& callback_ref = LuaTools::opt_function(l, 3);
2344
2345 HeroSprites& sprites = hero.get_hero_sprites();
2346 if (!sprites.has_tunic_animation(animation)) {
2347 LuaTools::arg_error(l, 2,
2348 std::string("No such animation in tunic sprite: '") + animation + "'"
2349 );
2350 }
2351
2352 sprites.set_animation(animation, callback_ref);
2353
2354 return 0;
2355 });
2356 }
2357
2358 /**
2359 * \brief Implementation of hero:get_tunic_sprite_id().
2360 * \param l The Lua context that is calling this function.
2361 * \return Number of values to return to Lua.
2362 */
hero_api_get_tunic_sprite_id(lua_State * l)2363 int LuaContext::hero_api_get_tunic_sprite_id(lua_State* l) {
2364
2365 return state_boundary_handle(l, [&] {
2366 Hero& hero = *check_hero(l, 1);
2367
2368 const std::string& sprite_id = hero.get_hero_sprites().get_tunic_sprite_id();
2369
2370 push_string(l, sprite_id);
2371 return 1;
2372 });
2373 }
2374
2375 /**
2376 * \brief Implementation of hero:set_tunic_sprite_id().
2377 * \param l The Lua context that is calling this function.
2378 * \return Number of values to return to Lua.
2379 */
hero_api_set_tunic_sprite_id(lua_State * l)2380 int LuaContext::hero_api_set_tunic_sprite_id(lua_State* l) {
2381
2382 return state_boundary_handle(l, [&] {
2383 Hero& hero = *check_hero(l, 1);
2384 const std::string& sprite_id = LuaTools::check_string(l, 2);
2385
2386 // TODO check the existence of the sprite animation set
2387 // (see also sol.sprite.create()).
2388 hero.get_hero_sprites().set_tunic_sprite_id(sprite_id);
2389
2390 return 0;
2391 });
2392 }
2393
2394 /**
2395 * \brief Implementation of hero:get_sword_sprite_id().
2396 * \param l The Lua context that is calling this function.
2397 * \return Number of values to return to Lua.
2398 */
hero_api_get_sword_sprite_id(lua_State * l)2399 int LuaContext::hero_api_get_sword_sprite_id(lua_State* l) {
2400
2401 return state_boundary_handle(l, [&] {
2402 Hero& hero = *check_hero(l, 1);
2403
2404 const std::string& sprite_id = hero.get_hero_sprites().get_sword_sprite_id();
2405
2406 push_string(l, sprite_id);
2407 return 1;
2408 });
2409 }
2410
2411 /**
2412 * \brief Implementation of hero:set_sword_sprite_id().
2413 * \param l The Lua context that is calling this function.
2414 * \return Number of values to return to Lua.
2415 */
hero_api_set_sword_sprite_id(lua_State * l)2416 int LuaContext::hero_api_set_sword_sprite_id(lua_State* l) {
2417
2418 return state_boundary_handle(l, [&] {
2419 Hero& hero = *check_hero(l, 1);
2420 const std::string& sprite_id = LuaTools::check_string(l, 2);
2421
2422 hero.get_hero_sprites().set_sword_sprite_id(sprite_id);
2423
2424 return 0;
2425 });
2426 }
2427
2428 /**
2429 * \brief Implementation of hero:get_sword_sound_id().
2430 * \param l The Lua context that is calling this function.
2431 * \return Number of values to return to Lua.
2432 */
hero_api_get_sword_sound_id(lua_State * l)2433 int LuaContext::hero_api_get_sword_sound_id(lua_State* l) {
2434
2435 return state_boundary_handle(l, [&] {
2436 Hero& hero = *check_hero(l, 1);
2437
2438 const std::string& sound_id = hero.get_hero_sprites().get_sword_sound_id();
2439
2440 push_string(l, sound_id);
2441 return 1;
2442 });
2443 }
2444
2445 /**
2446 * \brief Implementation of hero:set_sword_sound_id().
2447 * \param l The Lua context that is calling this function.
2448 * \return Number of values to return to Lua.
2449 */
hero_api_set_sword_sound_id(lua_State * l)2450 int LuaContext::hero_api_set_sword_sound_id(lua_State* l) {
2451
2452 return state_boundary_handle(l, [&] {
2453 Hero& hero = *check_hero(l, 1);
2454 const std::string& sound_id = LuaTools::check_string(l, 2);
2455
2456 hero.get_hero_sprites().set_sword_sound_id(sound_id);
2457
2458 return 0;
2459 });
2460 }
2461
2462 /**
2463 * \brief Implementation of hero:get_shield_sprite_id().
2464 * \param l The Lua context that is calling this function.
2465 * \return Number of values to return to Lua.
2466 */
hero_api_get_shield_sprite_id(lua_State * l)2467 int LuaContext::hero_api_get_shield_sprite_id(lua_State* l) {
2468
2469 return state_boundary_handle(l, [&] {
2470 Hero& hero = *check_hero(l, 1);
2471
2472 const std::string& sprite_id = hero.get_hero_sprites().get_shield_sprite_id();
2473
2474 push_string(l, sprite_id);
2475 return 1;
2476 });
2477 }
2478
2479 /**
2480 * \brief Implementation of hero:set_shield_sprite_id().
2481 * \param l The Lua context that is calling this function.
2482 * \return Number of values to return to Lua.
2483 */
hero_api_set_shield_sprite_id(lua_State * l)2484 int LuaContext::hero_api_set_shield_sprite_id(lua_State* l) {
2485
2486 return state_boundary_handle(l, [&] {
2487 Hero& hero = *check_hero(l, 1);
2488 const std::string& sprite_id = LuaTools::check_string(l, 2);
2489
2490 hero.get_hero_sprites().set_shield_sprite_id(sprite_id);
2491
2492 return 0;
2493 });
2494 }
2495
2496 /**
2497 * \brief Implementation of hero:is_blinking().
2498 * \param l The Lua context that is calling this function.
2499 * \return Number of values to return to Lua.
2500 */
hero_api_is_blinking(lua_State * l)2501 int LuaContext::hero_api_is_blinking(lua_State* l) {
2502
2503 return state_boundary_handle(l, [&] {
2504 Hero& hero = *check_hero(l, 1);
2505
2506 lua_pushboolean(l, hero.get_hero_sprites().is_blinking());
2507 return 1;
2508 });
2509 }
2510
2511 /**
2512 * \brief Implementation of hero:set_blinking().
2513 * \param l The Lua context that is calling this function.
2514 * \return Number of values to return to Lua.
2515 */
hero_api_set_blinking(lua_State * l)2516 int LuaContext::hero_api_set_blinking(lua_State* l) {
2517
2518 return state_boundary_handle(l, [&] {
2519 Hero& hero = *check_hero(l, 1);
2520 bool blinking = LuaTools::opt_boolean(l, 2, true);
2521 uint32_t duration = LuaTools::opt_int(l, 3, 0);
2522
2523 if (blinking) {
2524 hero.get_hero_sprites().blink(duration);
2525 }
2526 else {
2527 hero.get_hero_sprites().stop_blinking();
2528 }
2529
2530 return 0;
2531 });
2532 }
2533
2534 /**
2535 * \brief Implementation of hero:is_invincible().
2536 * \param l The Lua context that is calling this function.
2537 * \return Number of values to return to Lua.
2538 */
hero_api_is_invincible(lua_State * l)2539 int LuaContext::hero_api_is_invincible(lua_State* l) {
2540
2541 return state_boundary_handle(l, [&] {
2542 const Hero& hero = *check_hero(l, 1);
2543
2544 lua_pushboolean(l, hero.is_invincible());
2545 return 1;
2546 });
2547 }
2548
2549 /**
2550 * \brief Implementation of hero:set_invincible().
2551 * \param l The Lua context that is calling this function.
2552 * \return Number of values to return to Lua.
2553 */
hero_api_set_invincible(lua_State * l)2554 int LuaContext::hero_api_set_invincible(lua_State* l) {
2555
2556 return state_boundary_handle(l, [&] {
2557 Hero& hero = *check_hero(l, 1);
2558 bool invincible = LuaTools::opt_boolean(l, 2, true);
2559 uint32_t duration = LuaTools::opt_int(l, 3, 0);
2560
2561 hero.set_invincible(invincible, duration);
2562
2563 return 0;
2564 });
2565 }
2566
2567 /**
2568 * \brief Implementation of hero:get_carried_object().
2569 * \param l The Lua context that is calling this function.
2570 * \return Number of values to return to Lua.
2571 */
hero_api_get_carried_object(lua_State * l)2572 int LuaContext::hero_api_get_carried_object(lua_State* l) {
2573
2574 return state_boundary_handle(l, [&] {
2575 Hero& hero = *check_hero(l, 1);
2576
2577 const std::shared_ptr<CarriedObject>& carried_object = hero.get_carried_object();
2578 if (carried_object == nullptr) {
2579 lua_pushnil(l);
2580 }
2581 else {
2582 push_carried_object(l, *carried_object);
2583 }
2584 return 1;
2585 });
2586 }
2587
2588 /**
2589 * \brief Implementation of hero:freeze().
2590 * \param l The Lua context that is calling this function.
2591 * \return Number of values to return to Lua.
2592 */
hero_api_freeze(lua_State * l)2593 int LuaContext::hero_api_freeze(lua_State* l) {
2594
2595 return state_boundary_handle(l, [&] {
2596 Hero& hero = *check_hero(l, 1);
2597
2598 hero.start_frozen();
2599
2600 return 0;
2601 });
2602 }
2603
2604 /**
2605 * \brief Implementation of hero:unfreeze().
2606 * \param l The Lua context that is calling this function.
2607 * \return Number of values to return to Lua.
2608 */
hero_api_unfreeze(lua_State * l)2609 int LuaContext::hero_api_unfreeze(lua_State* l) {
2610
2611 return state_boundary_handle(l, [&] {
2612 Hero& hero = *check_hero(l, 1);
2613
2614 hero.start_state_from_ground();
2615
2616 return 0;
2617 });
2618 }
2619
2620 /**
2621 * \brief Implementation of hero:walk().
2622 * \param l The Lua context that is calling this function.
2623 * \return Number of values to return to Lua.
2624 */
hero_api_walk(lua_State * l)2625 int LuaContext::hero_api_walk(lua_State* l) {
2626
2627 return state_boundary_handle(l, [&] {
2628 Hero& hero = *check_hero(l, 1);
2629 const std::string& path = LuaTools::check_string(l, 2);
2630 bool loop = LuaTools::opt_boolean(l, 3, false);
2631 bool ignore_obstacles = LuaTools::opt_boolean(l, 4, false);
2632
2633 hero.start_forced_walking(path, loop, ignore_obstacles);
2634
2635 return 0;
2636 });
2637 }
2638
2639 /**
2640 * \brief Implementation of hero:start_attack().
2641 * \param l The Lua context that is calling this function.
2642 * \return Number of values to return to Lua.
2643 */
hero_api_start_attack(lua_State * l)2644 int LuaContext::hero_api_start_attack(lua_State* l) {
2645
2646 return state_boundary_handle(l, [&] {
2647 Hero& hero = *check_hero(l, 1);
2648
2649 if (hero.can_start_sword()) {
2650 hero.start_sword();
2651 }
2652
2653 return 0;
2654 });
2655 }
2656
2657 /**
2658 * \brief Implementation of hero:start_attack_loading().
2659 * \param l The Lua context that is calling this function.
2660 * \return Number of values to return to Lua.
2661 */
hero_api_start_attack_loading(lua_State * l)2662 int LuaContext::hero_api_start_attack_loading(lua_State* l) {
2663
2664 return state_boundary_handle(l, [&] {
2665 Hero& hero = *check_hero(l, 1);
2666 int spin_attack_delay = LuaTools::opt_int(l, 2, 1000);
2667
2668 if (hero.can_start_sword()) {
2669 hero.start_sword_loading(spin_attack_delay);
2670 }
2671
2672 return 0;
2673 });
2674 }
2675
2676 /**
2677 * \brief Implementation of hero:start_item().
2678 * \param l The Lua context that is calling this function.
2679 * \return Number of values to return to Lua.
2680 */
hero_api_start_item(lua_State * l)2681 int LuaContext::hero_api_start_item(lua_State* l) {
2682
2683 return state_boundary_handle(l, [&] {
2684 Hero& hero = *check_hero(l, 1);
2685 EquipmentItem& item = *check_item(l, 2);
2686
2687 if (!item.is_saved()) {
2688 LuaTools::arg_error(l, 2,
2689 std::string("Cannot use item '" + item.get_name() + "': this item is not saved"));
2690 }
2691 if (hero.can_start_item(item)) {
2692 hero.start_item(item);
2693 }
2694
2695 return 0;
2696 });
2697 }
2698
2699 /**
2700 * \brief Implementation of hero:start_grabbing().
2701 * \param l The Lua context that is calling this function.
2702 * \return Number of values to return to Lua.
2703 */
hero_api_start_grabbing(lua_State * l)2704 int LuaContext::hero_api_start_grabbing(lua_State* l) {
2705
2706 return state_boundary_handle(l, [&] {
2707 Hero& hero = *check_hero(l, 1);
2708
2709 if (hero.get_equipment().has_ability(Ability::GRAB)) {
2710 hero.start_grabbing();
2711 }
2712
2713 return 0;
2714 });
2715 }
2716
2717 /**
2718 * \brief Implementation of hero:start_jumping().
2719 * \param l The Lua context that is calling this function.
2720 * \return Number of values to return to Lua.
2721 */
hero_api_start_jumping(lua_State * l)2722 int LuaContext::hero_api_start_jumping(lua_State* l) {
2723
2724 return state_boundary_handle(l, [&] {
2725 Hero& hero = *check_hero(l, 1);
2726 int direction = LuaTools::check_int(l, 2);
2727 int length = LuaTools::check_int(l, 3);
2728 bool ignore_obstacles = LuaTools::opt_boolean(l, 4, false);
2729
2730 hero.start_jumping(direction, length, ignore_obstacles, false);
2731
2732 return 0;
2733 });
2734 }
2735
2736 /**
2737 * \brief Implementation of hero:start_treasure().
2738 * \param l The Lua context that is calling this function.
2739 * \return Number of values to return to Lua.
2740 */
hero_api_start_treasure(lua_State * l)2741 int LuaContext::hero_api_start_treasure(lua_State* l) {
2742
2743 return state_boundary_handle(l, [&] {
2744 Hero& hero = *check_hero(l, 1);
2745 const std::string& item_name = LuaTools::check_string(l, 2);
2746 int variant = LuaTools::opt_int(l, 3, 1);
2747 const std::string& savegame_variable = LuaTools::opt_string(l, 4, "");
2748
2749 if (!savegame_variable.empty()
2750 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
2751 LuaTools::arg_error(l, 4, std::string(
2752 "savegame variable identifier expected, got '") +
2753 savegame_variable + "'");
2754 }
2755
2756 if (!hero.get_game().get_equipment().item_exists(item_name)) {
2757 LuaTools::arg_error(l, 2, std::string("No such item: '") + item_name + "'");
2758 }
2759
2760 Treasure treasure(hero.get_game(), item_name, variant, savegame_variable);
2761 if (treasure.is_found()) {
2762 LuaTools::arg_error(l, 4, "This treasure is already found");
2763 }
2764 if (!treasure.is_obtainable()) {
2765 LuaTools::arg_error(l, 4, "This treasure is not obtainable");
2766 }
2767
2768 const ScopedLuaRef& callback_ref = LuaTools::opt_function(l, 5);
2769
2770 hero.start_treasure(treasure, callback_ref);
2771
2772 return 0;
2773 });
2774 }
2775
2776 /**
2777 * \brief Implementation of hero:start_victory().
2778 * \param l The Lua context that is calling this function.
2779 * \return Number of values to return to Lua.
2780 */
hero_api_start_victory(lua_State * l)2781 int LuaContext::hero_api_start_victory(lua_State* l) {
2782
2783 return state_boundary_handle(l, [&] {
2784 Hero& hero = *check_hero(l, 1);
2785 ScopedLuaRef callback_ref = LuaTools::opt_function(l, 2);
2786
2787 hero.start_victory(callback_ref);
2788
2789 return 0;
2790 });
2791 }
2792
2793 /**
2794 * \brief Implementation of hero:start_boomerang().
2795 * \param l The Lua context that is calling this function.
2796 * \return Number of values to return to Lua.
2797 */
hero_api_start_boomerang(lua_State * l)2798 int LuaContext::hero_api_start_boomerang(lua_State* l) {
2799
2800 return state_boundary_handle(l, [&] {
2801 Hero& hero = *check_hero(l, 1);
2802 int max_distance = LuaTools::check_int(l, 2);
2803 int speed = LuaTools::check_int(l, 3);
2804 const std::string& tunic_preparing_animation = LuaTools::check_string(l, 4);
2805 const std::string& sprite_name = LuaTools::check_string(l, 5);
2806
2807 hero.start_boomerang(max_distance, speed,
2808 tunic_preparing_animation, sprite_name);
2809
2810 return 0;
2811 });
2812 }
2813
2814 /**
2815 * \brief Implementation of hero:start_bow().
2816 * \param l The Lua context that is calling this function.
2817 * \return Number of values to return to Lua.
2818 */
hero_api_start_bow(lua_State * l)2819 int LuaContext::hero_api_start_bow(lua_State* l) {
2820
2821 return state_boundary_handle(l, [&] {
2822 Hero& hero = *check_hero(l, 1);
2823
2824 hero.start_bow();
2825
2826 return 0;
2827 });
2828 }
2829
2830 /**
2831 * \brief Implementation of hero:start_hookshot().
2832 * \param l The Lua context that is calling this function.
2833 * \return Number of values to return to Lua.
2834 */
hero_api_start_hookshot(lua_State * l)2835 int LuaContext::hero_api_start_hookshot(lua_State* l) {
2836
2837 return state_boundary_handle(l, [&] {
2838 Hero& hero = *check_hero(l, 1);
2839
2840 hero.start_hookshot();
2841
2842 return 0;
2843 });
2844 }
2845
2846 /**
2847 * \brief Implementation of hero:start_running().
2848 * \param l The Lua context that is calling this function.
2849 * \return Number of values to return to Lua.
2850 */
hero_api_start_running(lua_State * l)2851 int LuaContext::hero_api_start_running(lua_State* l) {
2852
2853 return state_boundary_handle(l, [&] {
2854 Hero& hero = *check_hero(l, 1);
2855
2856 hero.start_running();
2857
2858 return 0;
2859 });
2860 }
2861
2862 /**
2863 * \brief Implementation of hero:start_hurt().
2864 * \param l The Lua context that is calling this function.
2865 * \return Number of values to return to Lua.
2866 */
hero_api_start_hurt(lua_State * l)2867 int LuaContext::hero_api_start_hurt(lua_State* l) {
2868
2869 return state_boundary_handle(l, [&] {
2870 // There are three possible prototypes:
2871 // - hero:start_hurt(damage)
2872 // - hero:start_hurt(source_x, source_y, damage)
2873 // - hero:start_hurt(source_entity, [source_sprite], damage)
2874 Hero& hero = *check_hero(l, 1);
2875
2876 if (lua_gettop(l) <= 2) {
2877 // hero:start_hurt(damage)
2878 int damage = LuaTools::check_int(l, 2);
2879 hero.hurt(damage);
2880 }
2881 else if (lua_isnumber(l, 2)) {
2882 // hero:start_hurt(source_x, source_y, damage)
2883 int source_x = LuaTools::check_int(l, 2);
2884 int source_y = LuaTools::check_int(l, 3);
2885 int damage = LuaTools::check_int(l, 4);
2886 hero.hurt(Point(source_x, source_y), damage);
2887 }
2888 else {
2889 // hero:start_hurt(source_entity, [source_sprite], damage)
2890 Entity& source_entity = *check_entity(l, 2);
2891 SpritePtr source_sprite;
2892 int index = 3;
2893 if (is_sprite(l, 3)) {
2894 source_sprite = check_sprite(l, 3);
2895 index = 4;
2896 }
2897 int damage = LuaTools::check_int(l, index);
2898 hero.hurt(source_entity, source_sprite.get(), damage);
2899 }
2900
2901 return 0;
2902 });
2903 }
2904
2905 /**
2906 * \brief Implementation of hero:start_state().
2907 * \param l The Lua context that is calling this function.
2908 * \return Number of values to return to Lua.
2909 */
hero_api_start_state(lua_State * l)2910 int LuaContext::hero_api_start_state(lua_State* l) {
2911
2912 return state_boundary_handle(l, [&] {
2913 Hero& hero = *check_hero(l, 1);
2914 std::shared_ptr<CustomState> state = check_state(l, 2);
2915
2916 if (state->is_current_state()) {
2917 LuaTools::arg_error(l, 1, "This state is already active");
2918 }
2919 hero.start_custom_state(state);
2920
2921 return 0;
2922 });
2923 }
2924
2925 /**
2926 * \brief Implementation of hero:get_state_object().
2927 * \param l The Lua context that is calling this function.
2928 * \return Number of values to return to Lua.
2929 */
hero_api_get_state_object(lua_State * l)2930 int LuaContext::hero_api_get_state_object(lua_State* l) {
2931
2932 return state_boundary_handle(l, [&] {
2933 const Hero& hero = *check_hero(l, 1);
2934
2935 if (hero.get_state_name() != "custom") {
2936 lua_pushnil(l);
2937 }
2938 else {
2939 push_state(l, *std::static_pointer_cast<CustomState>(hero.get_state()));
2940 }
2941 return 1;
2942 });
2943 }
2944
2945 /**
2946 * \brief Notifies Lua that the hero is brandishing a treasure.
2947 *
2948 * Lua then manages the treasure's dialog if any.
2949 *
2950 * \param treasure The treasure being brandished.
2951 * \param callback_ref Lua ref to a function to call when the
2952 * treasure's dialog finishes (possibly an empty ref).
2953 */
notify_hero_brandish_treasure(const Treasure & treasure,const ScopedLuaRef & callback_ref)2954 void LuaContext::notify_hero_brandish_treasure(
2955 const Treasure& treasure,
2956 const ScopedLuaRef& callback_ref
2957 ) {
2958 // This is getting tricky. We will define our own dialog callback
2959 // that will do some work and call callback_ref.
2960 std::ostringstream oss;
2961 oss << "_treasure." << treasure.get_item_name() << "." << treasure.get_variant();
2962 const std::string& dialog_id = oss.str();
2963 Game& game = treasure.get_game();
2964
2965 push_item(current_l, treasure.get_item());
2966 lua_pushinteger(current_l, treasure.get_variant());
2967 push_string(current_l, treasure.get_savegame_variable());
2968 push_ref(current_l, callback_ref);
2969 lua_pushcclosure(current_l, l_treasure_brandish_finished, 4);
2970 const ScopedLuaRef& treasure_callback_ref = create_ref();
2971
2972 if (!CurrentQuest::dialog_exists(dialog_id)) {
2973 // No treasure dialog: keep brandishing the treasure for some delay
2974 // and then execute the callback.
2975 TimerPtr timer = std::make_shared<Timer>(3000);
2976 push_map(current_l, game.get_current_map());
2977 add_timer(timer, -1, treasure_callback_ref);
2978 lua_pop(current_l, 1);
2979 }
2980 else {
2981 // A treasure dialog exists. Show it and then execute the callback.
2982 game.start_dialog(dialog_id, ScopedLuaRef(), treasure_callback_ref);
2983 }
2984 }
2985
2986 /**
2987 * \brief Callback function executed after the animation of brandishing
2988 * a treasure.
2989 *
2990 * Upvalues: item, variant, savegame variable, callback/nil.
2991 *
2992 * \param l The Lua context that is calling this function.
2993 * \return Number of values to return to Lua.
2994 */
l_treasure_brandish_finished(lua_State * l)2995 int LuaContext::l_treasure_brandish_finished(lua_State* l) {
2996
2997 return state_boundary_handle(l, [&] {
2998 LuaContext& lua_context = get();
2999
3000 // The treasure's dialog is over.
3001 EquipmentItem& item = *check_item(l, lua_upvalueindex(1));
3002 int treasure_variant = LuaTools::check_int(l, lua_upvalueindex(2));
3003 const std::string& treasure_savegame_variable =
3004 LuaTools::check_string(l, lua_upvalueindex(3));
3005 lua_pushvalue(l, lua_upvalueindex(4));
3006
3007 // Check upvalues. Any error here would be the fault of the C++ side
3008 // because the user cannot call this function.
3009 Debug::check_assertion(item.get_game() != nullptr,
3010 "Equipment item without game");
3011
3012 Debug::check_assertion(lua_isnil(l, -1) || lua_isfunction(l, -1),
3013 "Expected function or nil for treasure callback");
3014
3015 Game& game = *item.get_game();
3016 Hero& hero = *game.get_hero();
3017 const Treasure treasure(game, item.get_name(), treasure_variant, treasure_savegame_variable);
3018
3019 // Notify the Lua item and the Lua map.
3020 if (!lua_isnil(l, -1)) {
3021 // There is a user callback for this treasure.
3022 lua_context.call_function(0, 0, "treasure callback");
3023 }
3024 lua_context.item_on_obtained(item, treasure);
3025 lua_context.map_on_obtained_treasure(game.get_current_map(), treasure);
3026
3027 if (hero.is_brandishing_treasure()) {
3028 // The script may have changed the hero's state.
3029 // If not, stop the treasure state.
3030 hero.start_free();
3031 }
3032
3033 return 0;
3034 });
3035 }
3036
3037 /**
3038 * \brief Returns whether a value is a userdata of type camera.
3039 * \param l A Lua context.
3040 * \param index An index in the stack.
3041 * \return \c true if the value at this index is a camera.
3042 */
is_camera(lua_State * l,int index)3043 bool LuaContext::is_camera(lua_State* l, int index) {
3044 return is_userdata(l, index, get_entity_internal_type_name(EntityType::CAMERA));
3045 }
3046
3047 /**
3048 * \brief Checks that the userdata at the specified index of the stack is a
3049 * camera and returns it.
3050 * \param l A Lua context.
3051 * \param index An index in the stack.
3052 * \return The camera.
3053 */
check_camera(lua_State * l,int index)3054 std::shared_ptr<Camera> LuaContext::check_camera(lua_State* l, int index) {
3055 return std::static_pointer_cast<Camera>(check_userdata(
3056 l, index, get_entity_internal_type_name(EntityType::CAMERA)
3057 ));
3058 }
3059
3060 /**
3061 * \brief Pushes a camera userdata onto the stack.
3062 * \param l A Lua context.
3063 * \param camera A camera.
3064 */
push_camera(lua_State * l,Camera & camera)3065 void LuaContext::push_camera(lua_State* l, Camera& camera) {
3066 push_userdata(l, camera);
3067 }
3068
3069 /**
3070 * \brief Implementation of camera:get_position_on_screen().
3071 * \param l The Lua context that is calling this function.
3072 * \return Number of values to return to Lua.
3073 */
camera_api_get_position_on_screen(lua_State * l)3074 int LuaContext::camera_api_get_position_on_screen(lua_State* l) {
3075
3076 return state_boundary_handle(l, [&] {
3077 const Camera& camera = *check_camera(l, 1);
3078
3079 const Point& position_on_screen = camera.get_position_on_screen();
3080
3081 lua_pushinteger(l, position_on_screen.x);
3082 lua_pushinteger(l, position_on_screen.y);
3083
3084 return 2;
3085 });
3086 }
3087
3088 /**
3089 * \brief Implementation of camera:set_position_on_screen().
3090 * \param l The Lua context that is calling this function.
3091 * \return Number of values to return to Lua.
3092 */
camera_api_set_position_on_screen(lua_State * l)3093 int LuaContext::camera_api_set_position_on_screen(lua_State* l) {
3094
3095 return state_boundary_handle(l, [&] {
3096 Camera& camera = *check_camera(l, 1);
3097 int x = LuaTools::check_int(l, 2);
3098 int y = LuaTools::check_int(l, 3);
3099
3100 camera.set_position_on_screen({ x, y });
3101
3102 return 0;
3103 });
3104 }
3105
3106 /**
3107 * \brief Implementation of camera:start_tracking().
3108 * \param l The Lua context that is calling this function.
3109 * \return Number of values to return to Lua.
3110 */
camera_api_start_tracking(lua_State * l)3111 int LuaContext::camera_api_start_tracking(lua_State* l) {
3112
3113 return state_boundary_handle(l, [&] {
3114 Camera& camera = *check_camera(l, 1);
3115 EntityPtr entity = check_entity(l, 2);
3116
3117 camera.start_tracking(entity);
3118
3119 return 0;
3120 });
3121 }
3122
3123 /**
3124 * \brief Implementation of camera:start_manual().
3125 * \param l The Lua context that is calling this function.
3126 * \return Number of values to return to Lua.
3127 */
camera_api_start_manual(lua_State * l)3128 int LuaContext::camera_api_start_manual(lua_State* l) {
3129
3130 return state_boundary_handle(l, [&] {
3131 Camera& camera = *check_camera(l, 1);
3132
3133 camera.start_manual();
3134
3135 return 0;
3136 });
3137 }
3138
3139 /**
3140 * \brief Implementation of camera:get_position_to_track().
3141 * \param l The Lua context that is calling this function.
3142 * \return Number of values to return to Lua.
3143 */
camera_api_get_position_to_track(lua_State * l)3144 int LuaContext::camera_api_get_position_to_track(lua_State* l) {
3145
3146 return state_boundary_handle(l, [&] {
3147 const Camera& camera = *check_camera(l, 1);
3148
3149 Point xy;
3150 if (lua_isnumber(l, 2)) {
3151 xy.x = LuaTools::check_int(l, 2);
3152 xy.y = LuaTools::check_int(l, 3);
3153 }
3154 else if (is_entity(l, 2)) {
3155 const Entity& entity = *check_entity(l, 2);
3156 xy = entity.get_center_point();
3157 }
3158 else {
3159 LuaTools::type_error(l, 2, "number or entity");
3160 }
3161 const Point& position_to_track = camera.get_position_to_track(xy);
3162
3163 lua_pushinteger(l, position_to_track.x);
3164 lua_pushinteger(l, position_to_track.y);
3165
3166 return 2;
3167 });
3168 }
3169
3170 /**
3171 * \brief Implementation of camera:get_tracked_entity().
3172 * \param l The Lua context that is calling this function.
3173 * \return Number of values to return to Lua.
3174 */
camera_api_get_tracked_entity(lua_State * l)3175 int LuaContext::camera_api_get_tracked_entity(lua_State* l) {
3176
3177 return state_boundary_handle(l, [&] {
3178 const Camera& camera = *check_camera(l, 1);
3179
3180 EntityPtr entity = camera.get_tracked_entity();
3181 if (entity == nullptr) {
3182 lua_pushnil(l);
3183 }
3184 else {
3185 push_entity(l, *entity);
3186 }
3187 return 1;
3188 });
3189 }
3190
3191 /**
3192 * \brief Implementation of camera:get_surface().
3193 * \param l The Lua context that is calling this function.
3194 * \return Number of values to return to Lua.
3195 */
camera_api_get_surface(lua_State * l)3196 int LuaContext::camera_api_get_surface(lua_State* l) {
3197
3198 return state_boundary_handle(l, [&] {
3199 const Camera& camera = *check_camera(l, 1);
3200
3201 SurfacePtr surface = camera.get_surface();
3202 if (surface == nullptr) {
3203 lua_pushnil(l);
3204 }
3205 else {
3206 push_surface(l, *surface);
3207 }
3208 return 1;
3209 });
3210 }
3211
3212 /**
3213 * \brief Returns whether a value is a userdata of type destination.
3214 * \param l A Lua context.
3215 * \param index An index in the stack.
3216 * \return \c true if the value at this index is an destination.
3217 */
is_destination(lua_State * l,int index)3218 bool LuaContext::is_destination(lua_State* l, int index) {
3219 return is_userdata(l, index, get_entity_internal_type_name(EntityType::DESTINATION));
3220 }
3221
3222 /**
3223 * \brief Checks that the userdata at the specified index of the stack is a
3224 * destination and returns it.
3225 * \param l A Lua context.
3226 * \param index An index in the stack.
3227 * \return The destination.
3228 */
check_destination(lua_State * l,int index)3229 std::shared_ptr<Destination> LuaContext::check_destination(lua_State* l, int index) {
3230 return std::static_pointer_cast<Destination>(check_userdata(
3231 l, index, get_entity_internal_type_name(EntityType::DESTINATION)
3232 ));
3233 }
3234
3235 /**
3236 * \brief Pushes an destination userdata onto the stack.
3237 * \param l A Lua context.
3238 * \param destination A destination.
3239 */
push_destination(lua_State * l,Destination & destination)3240 void LuaContext::push_destination(lua_State* l, Destination& destination) {
3241 push_userdata(l, destination);
3242 }
3243
3244 /**
3245 * \brief Implementation of destination:get_starting_location_mode().
3246 * \param l The Lua context that is calling this function.
3247 * \return Number of values to return to Lua.
3248 */
destination_api_get_starting_location_mode(lua_State * l)3249 int LuaContext::destination_api_get_starting_location_mode(lua_State* l) {
3250
3251 return state_boundary_handle(l, [&] {
3252 const Destination& destination = *check_destination(l, 1);
3253
3254 StartingLocationMode mode = destination.get_starting_location_mode();
3255
3256 push_string(l, enum_to_name(mode));
3257 return 1;
3258 });
3259 }
3260
3261 /**
3262 * \brief Implementation of destination:set_starting_location_mode().
3263 * \param l The Lua context that is calling this function.
3264 * \return Number of values to return to Lua.
3265 */
destination_api_set_starting_location_mode(lua_State * l)3266 int LuaContext::destination_api_set_starting_location_mode(lua_State* l) {
3267
3268 return state_boundary_handle(l, [&] {
3269 Destination& destination = *check_destination(l, 1);
3270 StartingLocationMode mode = StartingLocationMode::WHEN_WORLD_CHANGES;
3271
3272 if (lua_gettop(l) == 1) {
3273 LuaTools::type_error(l, 2, "string or nil");
3274 }
3275 if (!lua_isnil(l, 2)) {
3276 mode = LuaTools::check_enum<StartingLocationMode>(l, 2);
3277 }
3278
3279 destination.set_starting_location_mode(mode);
3280 return 0;
3281 });
3282 }
3283
3284 /**
3285 * \brief Returns whether a value is a userdata of type teletransporter.
3286 * \param l A Lua context.
3287 * \param index An index in the stack.
3288 * \return \c true if the value at this index is an teletransporter.
3289 */
is_teletransporter(lua_State * l,int index)3290 bool LuaContext::is_teletransporter(lua_State* l, int index) {
3291 return is_userdata(l, index, get_entity_internal_type_name(EntityType::TELETRANSPORTER));
3292 }
3293
3294 /**
3295 * \brief Checks that the userdata at the specified index of the stack is a
3296 * teletransporter and returns it.
3297 * \param l A Lua context.
3298 * \param index An index in the stack.
3299 * \return The teletransporter.
3300 */
check_teletransporter(lua_State * l,int index)3301 std::shared_ptr<Teletransporter> LuaContext::check_teletransporter(lua_State* l, int index) {
3302 return std::static_pointer_cast<Teletransporter>(check_userdata(
3303 l, index, get_entity_internal_type_name(EntityType::TELETRANSPORTER)
3304 ));
3305 }
3306
3307 /**
3308 * \brief Pushes an teletransporter userdata onto the stack.
3309 * \param l A Lua context.
3310 * \param teletransporter A teletransporter.
3311 */
push_teletransporter(lua_State * l,Teletransporter & teletransporter)3312 void LuaContext::push_teletransporter(lua_State* l, Teletransporter& teletransporter) {
3313 push_userdata(l, teletransporter);
3314 }
3315
3316 /**
3317 * \brief Implementation of teletransporter:get_sound().
3318 * \param l The Lua context that is calling this function.
3319 * \return Number of values to return to Lua.
3320 */
teletransporter_api_get_sound(lua_State * l)3321 int LuaContext::teletransporter_api_get_sound(lua_State* l) {
3322
3323 return state_boundary_handle(l, [&] {
3324 const Teletransporter& teletransporter = *check_teletransporter(l, 1);
3325
3326 const std::string& sound_id = teletransporter.get_sound_id();
3327
3328 if (sound_id.empty()) {
3329 lua_pushnil(l);
3330 }
3331 else {
3332 push_string(l, sound_id);
3333 }
3334 return 1;
3335 });
3336 }
3337
3338 /**
3339 * \brief Implementation of teletransporter:set_sound().
3340 * \param l The Lua context that is calling this function.
3341 * \return Number of values to return to Lua.
3342 */
teletransporter_api_set_sound(lua_State * l)3343 int LuaContext::teletransporter_api_set_sound(lua_State* l) {
3344
3345 return state_boundary_handle(l, [&] {
3346 Teletransporter& teletransporter = *check_teletransporter(l, 1);
3347
3348 std::string sound_id;
3349 if (lua_gettop(l) > 1) {
3350 sound_id = LuaTools::check_string(l, 2);
3351 }
3352
3353 teletransporter.set_sound_id(sound_id);
3354 return 0;
3355 });
3356 }
3357
3358 /**
3359 * \brief Implementation of teletransporter:get_transition().
3360 * \param l The Lua context that is calling this function.
3361 * \return Number of values to return to Lua.
3362 */
teletransporter_api_get_transition(lua_State * l)3363 int LuaContext::teletransporter_api_get_transition(lua_State* l) {
3364
3365 return state_boundary_handle(l, [&] {
3366 const Teletransporter& teletransporter = *check_teletransporter(l, 1);
3367
3368 push_string(l, enum_to_name(teletransporter.get_transition_style()));
3369 return 1;
3370 });
3371 }
3372
3373 /**
3374 * \brief Implementation of teletransporter:set_transition().
3375 * \param l The Lua context that is calling this function.
3376 * \return Number of values to return to Lua.
3377 */
teletransporter_api_set_transition(lua_State * l)3378 int LuaContext::teletransporter_api_set_transition(lua_State* l) {
3379
3380 return state_boundary_handle(l, [&] {
3381 Teletransporter& teletransporter = *check_teletransporter(l, 1);
3382 Transition::Style transition_style = LuaTools::check_enum<Transition::Style>(
3383 l, 2
3384 );
3385
3386 teletransporter.set_transition_style(transition_style);
3387
3388 return 0;
3389 });
3390 }
3391
3392 /**
3393 * \brief Implementation of teletransporter:get_destination_map().
3394 * \param l The Lua context that is calling this function.
3395 * \return Number of values to return to Lua.
3396 */
teletransporter_api_get_destination_map(lua_State * l)3397 int LuaContext::teletransporter_api_get_destination_map(lua_State* l) {
3398
3399 return state_boundary_handle(l, [&] {
3400 const Teletransporter& teletransporter = *check_teletransporter(l, 1);
3401
3402 const std::string& map_id = teletransporter.get_destination_map_id();
3403
3404 push_string(l, map_id);
3405 return 1;
3406 });
3407 }
3408
3409 /**
3410 * \brief Implementation of teletransporter:set_destination_map().
3411 * \param l The Lua context that is calling this function.
3412 * \return Number of values to return to Lua.
3413 */
teletransporter_api_set_destination_map(lua_State * l)3414 int LuaContext::teletransporter_api_set_destination_map(lua_State* l) {
3415
3416 return state_boundary_handle(l, [&] {
3417 Teletransporter& teletransporter = *check_teletransporter(l, 1);
3418 const std::string& map_id = LuaTools::check_string(l, 2);
3419
3420 teletransporter.set_destination_map_id(map_id);
3421
3422 return 0;
3423 });
3424 }
3425
3426 /**
3427 * \brief Implementation of teletransporter:get_destination_name().
3428 * \param l The Lua context that is calling this function.
3429 * \return Number of values to return to Lua.
3430 */
teletransporter_api_get_destination_name(lua_State * l)3431 int LuaContext::teletransporter_api_get_destination_name(lua_State* l) {
3432
3433 return state_boundary_handle(l, [&] {
3434 const Teletransporter& teletransporter = *check_teletransporter(l, 1);
3435
3436 const std::string& destination_name = teletransporter.get_destination_name();
3437
3438 push_string(l, destination_name);
3439 return 1;
3440 });
3441 }
3442
3443 /**
3444 * \brief Implementation of teletransporter:set_destination_name().
3445 * \param l The Lua context that is calling this function.
3446 * \return Number of values to return to Lua.
3447 */
teletransporter_api_set_destination_name(lua_State * l)3448 int LuaContext::teletransporter_api_set_destination_name(lua_State* l) {
3449
3450 return state_boundary_handle(l, [&] {
3451 Teletransporter& teletransporter = *check_teletransporter(l, 1);
3452 const std::string& destination_name = LuaTools::check_string(l, 2);
3453
3454 teletransporter.set_destination_name(destination_name);
3455
3456 return 0;
3457 });
3458 }
3459
3460 /**
3461 * \brief Returns whether a value is a userdata of type NPC.
3462 * \param l A Lua context.
3463 * \param index An index in the stack.
3464 * \return \c true if the value at this index is an NPC.
3465 */
is_npc(lua_State * l,int index)3466 bool LuaContext::is_npc(lua_State* l, int index) {
3467 return is_userdata(l, index, get_entity_internal_type_name(EntityType::NPC));
3468 }
3469
3470 /**
3471 * \brief Checks that the userdata at the specified index of the stack is an
3472 * NPC and returns it.
3473 * \param l A Lua context.
3474 * \param index An index in the stack.
3475 * \return The NPC.
3476 */
check_npc(lua_State * l,int index)3477 std::shared_ptr<Npc> LuaContext::check_npc(lua_State* l, int index) {
3478 return std::static_pointer_cast<Npc>(check_userdata(
3479 l, index, get_entity_internal_type_name(EntityType::NPC))
3480 );
3481 }
3482
3483 /**
3484 * \brief Pushes an NPC userdata onto the stack.
3485 * \param l A Lua context.
3486 * \param npc An NPC.
3487 */
push_npc(lua_State * l,Npc & npc)3488 void LuaContext::push_npc(lua_State* l, Npc& npc) {
3489 push_userdata(l, npc);
3490 }
3491
3492 /**
3493 * \brief Implementation of npc:is_traversable().
3494 * \param l The Lua context that is calling this function.
3495 * \return Number of values to return to Lua.
3496 */
npc_api_is_traversable(lua_State * l)3497 int LuaContext::npc_api_is_traversable(lua_State* l) {
3498
3499 return state_boundary_handle(l, [&] {
3500 const Npc& npc = *check_npc(l, 1);
3501
3502 lua_pushboolean(l, npc.is_traversable());
3503 return 1;
3504 });
3505 }
3506
3507 /**
3508 * \brief Implementation of npc:set_traversable().
3509 * \param l The Lua context that is calling this function.
3510 * \return Number of values to return to Lua.
3511 */
npc_api_set_traversable(lua_State * l)3512 int LuaContext::npc_api_set_traversable(lua_State* l) {
3513
3514 return state_boundary_handle(l, [&] {
3515 Npc& npc = *check_npc(l, 1);
3516
3517 bool traversable = LuaTools::opt_boolean(l, 2, true);
3518
3519 npc.set_traversable(traversable);
3520
3521 return 0;
3522 });
3523 }
3524
3525 /**
3526 * \brief Returns whether a value is a userdata of type chest.
3527 * \param l A Lua context.
3528 * \param index An index in the stack.
3529 * \return \c true if the value at this index is a chest.
3530 */
is_chest(lua_State * l,int index)3531 bool LuaContext::is_chest(lua_State* l, int index) {
3532 return is_userdata(l, index, get_entity_internal_type_name(EntityType::CHEST));
3533 }
3534
3535 /**
3536 * \brief Checks that the userdata at the specified index of the stack is a
3537 * chest and returns it.
3538 * \param l A Lua context.
3539 * \param index An index in the stack.
3540 * \return The chest.
3541 */
check_chest(lua_State * l,int index)3542 std::shared_ptr<Chest> LuaContext::check_chest(lua_State* l, int index) {
3543 return std::static_pointer_cast<Chest>(check_userdata(
3544 l, index, get_entity_internal_type_name(EntityType::CHEST)
3545 ));
3546 }
3547
3548 /**
3549 * \brief Pushes a chest userdata onto the stack.
3550 * \param l A Lua context.
3551 * \param chest A chest.
3552 */
push_chest(lua_State * l,Chest & chest)3553 void LuaContext::push_chest(lua_State* l, Chest& chest) {
3554 push_userdata(l, chest);
3555 }
3556
3557 /**
3558 * \brief Implementation of chest:is_open().
3559 * \param l The Lua context that is calling this function.
3560 * \return Number of values to return to Lua.
3561 */
chest_api_is_open(lua_State * l)3562 int LuaContext::chest_api_is_open(lua_State* l) {
3563
3564 return state_boundary_handle(l, [&] {
3565 const Chest& chest = *check_chest(l, 1);
3566
3567 lua_pushboolean(l, chest.is_open());
3568 return 1;
3569 });
3570 }
3571
3572 /**
3573 * \brief Implementation of chest:set_open().
3574 * \param l The Lua context that is calling this function.
3575 * \return Number of values to return to Lua.
3576 */
chest_api_set_open(lua_State * l)3577 int LuaContext::chest_api_set_open(lua_State* l) {
3578
3579 return state_boundary_handle(l, [&] {
3580 Chest& chest = *check_chest(l, 1);
3581 bool open = LuaTools::opt_boolean(l, 2, true);
3582
3583 chest.set_open(open);
3584
3585 return 0;
3586 });
3587 }
3588
3589 /**
3590 * \brief Implementation of chest:get_treasure().
3591 * \param l The Lua context that is calling this function.
3592 * \return Number of values to return to Lua.
3593 */
chest_api_get_treasure(lua_State * l)3594 int LuaContext::chest_api_get_treasure(lua_State* l) {
3595
3596 return state_boundary_handle(l, [&] {
3597 const Chest& chest = *check_chest(l, 1);
3598 const Treasure& treasure = chest.get_treasure();
3599
3600 if (treasure.is_empty()) {
3601 // No treasure.
3602 lua_pushnil(l);
3603 lua_pushnil(l);
3604 }
3605 else {
3606 push_string(l, treasure.get_item_name());
3607 lua_pushinteger(l, treasure.get_variant());
3608 }
3609 if (!treasure.is_saved()) {
3610 lua_pushnil(l);
3611 }
3612 else {
3613 push_string(l, treasure.get_savegame_variable());
3614 }
3615 return 3;
3616 });
3617 }
3618
3619 /**
3620 * \brief Implementation of chest:set_treasure().
3621 * \param l The Lua context that is calling this function.
3622 * \return Number of values to return to Lua.
3623 */
chest_api_set_treasure(lua_State * l)3624 int LuaContext::chest_api_set_treasure(lua_State* l) {
3625
3626 return state_boundary_handle(l, [&] {
3627 Chest& chest = *check_chest(l, 1);
3628 std::string item_name;
3629 int variant = 1;
3630 std::string savegame_variable;
3631
3632 if (lua_gettop(l) >= 2 && !lua_isnil(l, 2)) {
3633 item_name = LuaTools::check_string(l, 2);
3634 }
3635 if (lua_gettop(l) >= 3 && !lua_isnil(l, 3)) {
3636 variant = LuaTools::check_int(l, 3);
3637 }
3638 if (lua_gettop(l) >= 4 && !lua_isnil(l, 4)) {
3639 savegame_variable = LuaTools::check_string(l, 4);
3640 }
3641
3642 if (!savegame_variable.empty()
3643 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
3644 LuaTools::arg_error(l, 4,
3645 std::string("savegame variable identifier expected, got '")
3646 + savegame_variable + "'");
3647 }
3648
3649 Treasure treasure(chest.get_game(), item_name, variant, savegame_variable);
3650 chest.set_treasure(treasure);
3651
3652 return 0;
3653 });
3654 }
3655
3656 /**
3657 * \brief Returns whether a value is a userdata of type block.
3658 * \param l A Lua context.
3659 * \param index An index in the stack.
3660 * \return \c true if the value at this index is a block.
3661 */
is_block(lua_State * l,int index)3662 bool LuaContext::is_block(lua_State* l, int index) {
3663 return is_userdata(l, index, get_entity_internal_type_name(EntityType::BLOCK));
3664 }
3665
3666 /**
3667 * \brief Checks that the userdata at the specified index of the stack is a
3668 * block and returns it.
3669 * \param l A Lua context.
3670 * \param index An index in the stack.
3671 * \return The block.
3672 */
check_block(lua_State * l,int index)3673 std::shared_ptr<Block> LuaContext::check_block(lua_State* l, int index) {
3674 return std::static_pointer_cast<Block>(check_userdata(
3675 l, index, get_entity_internal_type_name(EntityType::BLOCK)
3676 ));
3677 }
3678
3679 /**
3680 * \brief Pushes a block userdata onto the stack.
3681 * \param l A Lua context.
3682 * \param block A block.
3683 */
push_block(lua_State * l,Block & block)3684 void LuaContext::push_block(lua_State* l, Block& block) {
3685 push_userdata(l, block);
3686 }
3687
3688 /**
3689 * \brief Implementation of block:reset().
3690 * \param l The Lua context that is calling this function.
3691 * \return Number of values to return to Lua.
3692 */
block_api_reset(lua_State * l)3693 int LuaContext::block_api_reset(lua_State* l) {
3694
3695 return state_boundary_handle(l, [&] {
3696 Block& block = *check_block(l, 1);
3697
3698 block.reset();
3699
3700 return 0;
3701 });
3702 }
3703
3704 /**
3705 * \brief Implementation of block:is_pushable().
3706 * \param l The Lua context that is calling this function.
3707 * \return Number of values to return to Lua.
3708 */
block_api_is_pushable(lua_State * l)3709 int LuaContext::block_api_is_pushable(lua_State* l) {
3710
3711 return state_boundary_handle(l, [&] {
3712 const Block& block = *check_block(l, 1);
3713
3714 lua_pushboolean(l, block.is_pushable());
3715 return 1;
3716 });
3717 }
3718
3719 /**
3720 * \brief Implementation of block:set_pushable().
3721 * \param l The Lua context that is calling this function.
3722 * \return Number of values to return to Lua.
3723 */
block_api_set_pushable(lua_State * l)3724 int LuaContext::block_api_set_pushable(lua_State* l) {
3725
3726 return state_boundary_handle(l, [&] {
3727 Block& block = *check_block(l, 1);
3728 bool pushable = LuaTools::opt_boolean(l, 2, true);
3729
3730 block.set_pushable(pushable);
3731
3732 return 0;
3733 });
3734 }
3735
3736 /**
3737 * \brief Implementation of block:is_pullable().
3738 * \param l The Lua context that is calling this function.
3739 * \return Number of values to return to Lua.
3740 */
block_api_is_pullable(lua_State * l)3741 int LuaContext::block_api_is_pullable(lua_State* l) {
3742
3743 return state_boundary_handle(l, [&] {
3744 const Block& block = *check_block(l, 1);
3745
3746 lua_pushboolean(l, block.is_pullable());
3747 return 1;
3748 });
3749 }
3750
3751 /**
3752 * \brief Implementation of block:set_pullable().
3753 * \param l The Lua context that is calling this function.
3754 * \return Number of values to return to Lua.
3755 */
block_api_set_pullable(lua_State * l)3756 int LuaContext::block_api_set_pullable(lua_State* l) {
3757
3758 return state_boundary_handle(l, [&] {
3759 Block& block = *check_block(l, 1);
3760 bool pullable = LuaTools::opt_boolean(l, 2, true);
3761
3762 block.set_pullable(pullable);
3763
3764 return 0;
3765 });
3766 }
3767
3768 /**
3769 * \brief Implementation of block:get_max_moves().
3770 * \param l The Lua context that is calling this function.
3771 * \return Number of values to return to Lua.
3772 */
block_api_get_max_moves(lua_State * l)3773 int LuaContext::block_api_get_max_moves(lua_State* l) {
3774
3775 return state_boundary_handle(l, [&] {
3776 const Block& block = *check_block(l, 1);
3777
3778 const int max_moves = block.get_max_moves();
3779
3780 if (max_moves == -1) {
3781 // -1 means no maximum.
3782 lua_pushnil(l);
3783 }
3784 else {
3785 lua_pushinteger(l, max_moves);
3786 }
3787 return 1;
3788 });
3789 }
3790
3791 /**
3792 * \brief Implementation of block:set_max_moves().
3793 * \param l The Lua context that is calling this function.
3794 * \return Number of values to return to Lua.
3795 */
block_api_set_max_moves(lua_State * l)3796 int LuaContext::block_api_set_max_moves(lua_State* l) {
3797
3798 return state_boundary_handle(l, [&] {
3799 Block& block = *check_block(l, 1);
3800 if (lua_type(l, 2) != LUA_TNUMBER && lua_type(l, 2) != LUA_TNIL) {
3801 LuaTools::type_error(l, 2, "number or nil");
3802 }
3803
3804 if (lua_isnumber(l, 2)) {
3805 const int max_moves = LuaTools::check_int(l, 2);
3806 if (max_moves < 0) {
3807 LuaTools::arg_error(l, 2, "max_moves should be 0, positive or nil");
3808 }
3809 block.set_max_moves(max_moves);
3810 }
3811 else if (lua_isnil(l, 2)) {
3812 // -1 means no maximum in C++.
3813 block.set_max_moves(-1);
3814 }
3815
3816 return 0;
3817 });
3818 }
3819
3820 /**
3821 * \brief Implementation of block:get_maximum_moves().
3822 * \param l The Lua context that is calling this function.
3823 * \return Number of values to return to Lua.
3824 */
block_api_get_maximum_moves(lua_State * l)3825 int LuaContext::block_api_get_maximum_moves(lua_State* l) {
3826
3827 get().warning_deprecated(
3828 { 1, 5 },
3829 "block:get_maximum_moves()",
3830 "Use block:get_max_moves() instead.");
3831 return block_api_get_max_moves(l);
3832 }
3833
3834 /**
3835 * \brief Implementation of block:set_maximum_moves().
3836 * \param l The Lua context that is calling this function.
3837 * \return Number of values to return to Lua.
3838 */
block_api_set_maximum_moves(lua_State * l)3839 int LuaContext::block_api_set_maximum_moves(lua_State* l) {
3840
3841 get().warning_deprecated(
3842 { 1, 5 },
3843 "block:set_maximum_moves()",
3844 "Use block:set_max_moves() instead.");
3845 return block_api_set_max_moves(l);
3846 }
3847
3848 /**
3849 * \brief Returns whether a value is a userdata of type switch.
3850 * \param l A Lua context.
3851 * \param index An index in the stack.
3852 * \return \c true if the value at this index is a switch.
3853 */
is_switch(lua_State * l,int index)3854 bool LuaContext::is_switch(lua_State* l, int index) {
3855 return is_userdata(l, index, get_entity_internal_type_name(EntityType::SWITCH));
3856 }
3857
3858 /**
3859 * \brief Checks that the userdata at the specified index of the stack is a
3860 * switch and returns it.
3861 * \param l A Lua context.
3862 * \param index An index in the stack.
3863 * \return The switch.
3864 */
check_switch(lua_State * l,int index)3865 std::shared_ptr<Switch> LuaContext::check_switch(lua_State* l, int index) {
3866 return std::static_pointer_cast<Switch>(check_userdata(
3867 l, index, get_entity_internal_type_name(EntityType::SWITCH)
3868 ));
3869 }
3870
3871 /**
3872 * \brief Pushes a switch userdata onto the stack.
3873 * \param l A Lua context.
3874 * \param sw A switch.
3875 */
push_switch(lua_State * l,Switch & sw)3876 void LuaContext::push_switch(lua_State* l, Switch& sw) {
3877 push_userdata(l, sw);
3878 }
3879
3880 /**
3881 * \brief Implementation of switch:is_activated().
3882 * \param l The Lua context that is calling this function.
3883 * \return Number of values to return to Lua.
3884 */
switch_api_is_activated(lua_State * l)3885 int LuaContext::switch_api_is_activated(lua_State* l) {
3886
3887 return state_boundary_handle(l, [&] {
3888 const Switch& sw = *check_switch(l, 1);
3889
3890 lua_pushboolean(l, sw.is_activated());
3891 return 1;
3892 });
3893 }
3894
3895 /**
3896 * \brief Implementation of switch:set_activated().
3897 * \param l The Lua context that is calling this function.
3898 * \return Number of values to return to Lua.
3899 */
switch_api_set_activated(lua_State * l)3900 int LuaContext::switch_api_set_activated(lua_State* l) {
3901
3902 return state_boundary_handle(l, [&] {
3903 Switch& sw = *check_switch(l, 1);
3904 bool activated = LuaTools::opt_boolean(l, 2, true);
3905
3906 sw.set_activated(activated);
3907
3908 return 0;
3909 });
3910 }
3911
3912 /**
3913 * \brief Implementation of switch:is_locked().
3914 * \param l The Lua context that is calling this function.
3915 * \return Number of values to return to Lua.
3916 */
switch_api_is_locked(lua_State * l)3917 int LuaContext::switch_api_is_locked(lua_State* l) {
3918
3919 return state_boundary_handle(l, [&] {
3920 const Switch& sw = *check_switch(l, 1);
3921
3922 lua_pushboolean(l, sw.is_locked());
3923 return 1;
3924 });
3925 }
3926
3927 /**
3928 * \brief Implementation of switch:set_locked().
3929 * \param l The Lua context that is calling this function.
3930 * \return Number of values to return to Lua.
3931 */
switch_api_set_locked(lua_State * l)3932 int LuaContext::switch_api_set_locked(lua_State* l) {
3933
3934 return state_boundary_handle(l, [&] {
3935 Switch& sw = *check_switch(l, 1);
3936 bool locked = LuaTools::opt_boolean(l, 2, true);
3937
3938 sw.set_locked(locked);
3939
3940 return 0;
3941 });
3942 }
3943
3944 /**
3945 * \brief Implementation of switch:is_walkable().
3946 * \param l The Lua context that is calling this function.
3947 * \return Number of values to return to Lua.
3948 */
switch_api_is_walkable(lua_State * l)3949 int LuaContext::switch_api_is_walkable(lua_State* l) {
3950
3951 return state_boundary_handle(l, [&] {
3952 const Switch& sw = *check_switch(l, 1);
3953
3954 lua_pushboolean(l, sw.is_walkable());
3955 return 1;
3956 });
3957 }
3958
3959 /**
3960 * \brief Returns whether a value is a userdata of type stream.
3961 * \param l A Lua context.
3962 * \param index An index in the stack.
3963 * \return \c true if the value at this index is a stream.
3964 */
is_stream(lua_State * l,int index)3965 bool LuaContext::is_stream(lua_State* l, int index) {
3966 return is_userdata(l, index, get_entity_internal_type_name(EntityType::STREAM));
3967 }
3968
3969 /**
3970 * \brief Checks that the userdata at the specified index of the stack is a
3971 * stream and returns it.
3972 * \param l A Lua context.
3973 * \param index An index in the stack.
3974 * \return The stream.
3975 */
check_stream(lua_State * l,int index)3976 std::shared_ptr<Stream> LuaContext::check_stream(lua_State* l, int index) {
3977 return std::static_pointer_cast<Stream>(check_userdata(
3978 l, index, get_entity_internal_type_name(EntityType::STREAM)
3979 ));
3980 }
3981
3982 /**
3983 * \brief Pushes a stream userdata onto the stack.
3984 * \param l A Lua context.
3985 * \param stream A stream.
3986 */
push_stream(lua_State * l,Stream & stream)3987 void LuaContext::push_stream(lua_State* l, Stream& stream) {
3988 push_userdata(l, stream);
3989 }
3990
3991 /**
3992 * \brief Implementation of stream:get_direction().
3993 * \param l The Lua context that is calling this function.
3994 * \return Number of values to return to Lua.
3995 */
stream_api_get_direction(lua_State * l)3996 int LuaContext::stream_api_get_direction(lua_State* l) {
3997
3998 return state_boundary_handle(l, [&] {
3999 const Stream& stream = *check_stream(l, 1);
4000
4001 lua_pushinteger(l, stream.get_direction());
4002 return 1;
4003 });
4004 }
4005
4006 /**
4007 * \brief Implementation of stream:set_direction().
4008 * \param l The Lua context that is calling this function.
4009 * \return Number of values to return to Lua.
4010 */
stream_api_set_direction(lua_State * l)4011 int LuaContext::stream_api_set_direction(lua_State* l) {
4012
4013 return state_boundary_handle(l, [&] {
4014 Stream& stream = *check_stream(l, 1);
4015 int direction = LuaTools::check_int(l, 2);
4016
4017 if (direction < 0 || direction >= 8) {
4018 LuaTools::arg_error(l, 2, "Invalid stream direction: must be between 0 and 7");
4019 }
4020
4021 stream.set_direction(direction);
4022
4023 return 0;
4024 });
4025 }
4026
4027 /**
4028 * \brief Implementation of stream:get_speed().
4029 * \param l The Lua context that is calling this function.
4030 * \return Number of values to return to Lua.
4031 */
stream_api_get_speed(lua_State * l)4032 int LuaContext::stream_api_get_speed(lua_State* l) {
4033
4034 return state_boundary_handle(l, [&] {
4035 const Stream& stream = *check_stream(l, 1);
4036
4037 lua_pushinteger(l, stream.get_speed());
4038 return 1;
4039 });
4040 }
4041
4042 /**
4043 * \brief Implementation of stream:set_speed().
4044 * \param l The Lua context that is calling this function.
4045 * \return Number of values to return to Lua.
4046 */
stream_api_set_speed(lua_State * l)4047 int LuaContext::stream_api_set_speed(lua_State* l) {
4048
4049 return state_boundary_handle(l, [&] {
4050 Stream& stream = *check_stream(l, 1);
4051 int speed = LuaTools::check_int(l, 2);
4052
4053 stream.set_speed(speed);
4054
4055 return 0;
4056 });
4057 }
4058
4059 /**
4060 * \brief Implementation of stream:get_allow_movement().
4061 * \param l The Lua context that is calling this function.
4062 * \return Number of values to return to Lua.
4063 */
stream_api_get_allow_movement(lua_State * l)4064 int LuaContext::stream_api_get_allow_movement(lua_State* l) {
4065
4066 return state_boundary_handle(l, [&] {
4067 const Stream& stream = *check_stream(l, 1);
4068
4069 lua_pushboolean(l, stream.get_allow_movement());
4070 return 1;
4071 });
4072 }
4073
4074 /**
4075 * \brief Implementation of stream:set_allow_movement().
4076 * \param l The Lua context that is calling this function.
4077 * \return Number of values to return to Lua.
4078 */
stream_api_set_allow_movement(lua_State * l)4079 int LuaContext::stream_api_set_allow_movement(lua_State* l) {
4080
4081 return state_boundary_handle(l, [&] {
4082 Stream& stream = *check_stream(l, 1);
4083 bool allow_movement = LuaTools::opt_boolean(l, 2, true);
4084
4085 stream.set_allow_movement(allow_movement);
4086
4087 return 0;
4088 });
4089 }
4090
4091 /**
4092 * \brief Implementation of stream:get_allow_attack().
4093 * \param l The Lua context that is calling this function.
4094 * \return Number of values to return to Lua.
4095 */
stream_api_get_allow_attack(lua_State * l)4096 int LuaContext::stream_api_get_allow_attack(lua_State* l) {
4097
4098 return state_boundary_handle(l, [&] {
4099 const Stream& stream = *check_stream(l, 1);
4100
4101 lua_pushboolean(l, stream.get_allow_attack());
4102 return 1;
4103 });
4104 }
4105
4106 /**
4107 * \brief Implementation of stream:set_allow_attack().
4108 * \param l The Lua context that is calling this function.
4109 * \return Number of values to return to Lua.
4110 */
stream_api_set_allow_attack(lua_State * l)4111 int LuaContext::stream_api_set_allow_attack(lua_State* l) {
4112
4113 return state_boundary_handle(l, [&] {
4114 Stream& stream = *check_stream(l, 1);
4115 bool allow_attack = LuaTools::opt_boolean(l, 2, true);
4116
4117 stream.set_allow_attack(allow_attack);
4118
4119 return 0;
4120 });
4121 }
4122
4123 /**
4124 * \brief Implementation of stream:get_allow_item().
4125 * \param l The Lua context that is calling this function.
4126 * \return Number of values to return to Lua.
4127 */
stream_api_get_allow_item(lua_State * l)4128 int LuaContext::stream_api_get_allow_item(lua_State* l) {
4129
4130 return state_boundary_handle(l, [&] {
4131 const Stream& stream = *check_stream(l, 1);
4132
4133 lua_pushboolean(l, stream.get_allow_item());
4134 return 1;
4135 });
4136 }
4137
4138 /**
4139 * \brief Implementation of stream:set_allow_item().
4140 * \param l The Lua context that is calling this function.
4141 * \return Number of values to return to Lua.
4142 */
stream_api_set_allow_item(lua_State * l)4143 int LuaContext::stream_api_set_allow_item(lua_State* l) {
4144
4145 return state_boundary_handle(l, [&] {
4146 Stream& stream = *check_stream(l, 1);
4147 bool allow_item = LuaTools::opt_boolean(l, 2, true);
4148
4149 stream.set_allow_item(allow_item);
4150
4151 return 0;
4152 });
4153 }
4154
4155 /**
4156 * \brief Returns whether a value is a userdata of type door.
4157 * \param l A Lua context.
4158 * \param index An index in the stack.
4159 * \return \c true if the value at this index is a door.
4160 */
is_door(lua_State * l,int index)4161 bool LuaContext::is_door(lua_State* l, int index) {
4162 return is_userdata(l, index, get_entity_internal_type_name(EntityType::DOOR));
4163 }
4164
4165 /**
4166 * \brief Checks that the userdata at the specified index of the stack is a
4167 * door and returns it.
4168 * \param l A Lua context.
4169 * \param index An index in the stack.
4170 * \return The door.
4171 */
check_door(lua_State * l,int index)4172 std::shared_ptr<Door> LuaContext::check_door(lua_State* l, int index) {
4173 return std::static_pointer_cast<Door>(check_userdata(
4174 l, index, get_entity_internal_type_name(EntityType::DOOR))
4175 );
4176 }
4177
4178 /**
4179 * \brief Pushes a door userdata onto the stack.
4180 * \param l A Lua context.
4181 * \param door A door.
4182 */
push_door(lua_State * l,Door & door)4183 void LuaContext::push_door(lua_State* l, Door& door) {
4184 push_userdata(l, door);
4185 }
4186
4187 /**
4188 * \brief Implementation of door:is_open().
4189 * \param l The Lua context that is calling this function.
4190 * \return Number of values to return to Lua.
4191 */
door_api_is_open(lua_State * l)4192 int LuaContext::door_api_is_open(lua_State* l) {
4193
4194 return state_boundary_handle(l, [&] {
4195 const Door& door = *check_door(l, 1);
4196
4197 lua_pushboolean(l, door.is_open());
4198 return 1;
4199 });
4200 }
4201
4202 /**
4203 * \brief Implementation of door:is_opening().
4204 * \param l The Lua context that is calling this function.
4205 * \return Number of values to return to Lua.
4206 */
door_api_is_opening(lua_State * l)4207 int LuaContext::door_api_is_opening(lua_State* l) {
4208
4209 return state_boundary_handle(l, [&] {
4210 const Door& door = *check_door(l, 1);
4211
4212 lua_pushboolean(l, door.is_opening());
4213 return 1;
4214 });
4215 }
4216
4217 /**
4218 * \brief Implementation of door:is_closed().
4219 * \param l The Lua context that is calling this function.
4220 * \return Number of values to return to Lua.
4221 */
door_api_is_closed(lua_State * l)4222 int LuaContext::door_api_is_closed(lua_State* l) {
4223
4224 return state_boundary_handle(l, [&] {
4225 const Door& door = *check_door(l, 1);
4226
4227 lua_pushboolean(l, door.is_closed());
4228 return 1;
4229 });
4230 }
4231
4232 /**
4233 * \brief Implementation of door:is_closing().
4234 * \param l The Lua context that is calling this function.
4235 * \return Number of values to return to Lua.
4236 */
door_api_is_closing(lua_State * l)4237 int LuaContext::door_api_is_closing(lua_State* l) {
4238
4239 return state_boundary_handle(l, [&] {
4240 const Door& door = *check_door(l, 1);
4241
4242 lua_pushboolean(l, door.is_closing());
4243 return 1;
4244 });
4245 }
4246
4247 /**
4248 * \brief Implementation of door:open().
4249 * \param l The Lua context that is calling this function.
4250 * \return Number of values to return to Lua.
4251 */
door_api_open(lua_State * l)4252 int LuaContext::door_api_open(lua_State* l) {
4253
4254 return state_boundary_handle(l, [&] {
4255 Door& door = *check_door(l, 1);
4256
4257 if (!door.is_open() && !door.is_opening()) {
4258 door.open();
4259 Sound::play("door_open");
4260 }
4261
4262 return 0;
4263 });
4264 }
4265
4266 /**
4267 * \brief Implementation of door:close().
4268 * \param l The Lua context that is calling this function.
4269 * \return Number of values to return to Lua.
4270 */
door_api_close(lua_State * l)4271 int LuaContext::door_api_close(lua_State* l) {
4272
4273 return state_boundary_handle(l, [&] {
4274 Door& door = *check_door(l, 1);
4275
4276 if (!door.is_closed() && !door.is_closing()) {
4277 door.close();
4278 Sound::play("door_closed");
4279 }
4280
4281 return 0;
4282 });
4283 }
4284
4285 /**
4286 * \brief Implementation of door:set_open().
4287 * \param l The Lua context that is calling this function.
4288 * \return Number of values to return to Lua.
4289 */
door_api_set_open(lua_State * l)4290 int LuaContext::door_api_set_open(lua_State* l) {
4291
4292 return state_boundary_handle(l, [&] {
4293 Door& door = *check_door(l, 1);
4294 bool open = LuaTools::opt_boolean(l, 2, true);
4295
4296 door.set_open(open);
4297
4298 return 0;
4299 });
4300 }
4301
4302 /**
4303 * \brief Returns whether a value is a userdata of type stairs.
4304 * \param l A Lua context.
4305 * \param index An index in the stack.
4306 * \return \c true if the value at this index is a stairs entity.
4307 */
is_stairs(lua_State * l,int index)4308 bool LuaContext::is_stairs(lua_State* l, int index) {
4309 return is_userdata(l, index, get_entity_internal_type_name(EntityType::STAIRS));
4310 }
4311
4312 /**
4313 * \brief Checks that the userdata at the specified index of the stack is a
4314 * stairs entity and returns it.
4315 * \param l A Lua context.
4316 * \param index An index in the stack.
4317 * \return The stairs.
4318 */
check_stairs(lua_State * l,int index)4319 std::shared_ptr<Stairs> LuaContext::check_stairs(lua_State* l, int index) {
4320 return std::static_pointer_cast<Stairs>(check_userdata(
4321 l, index, get_entity_internal_type_name(EntityType::STAIRS))
4322 );
4323 }
4324
4325 /**
4326 * \brief Pushes a stairs userdata onto the stack.
4327 * \param l A Lua context.
4328 * \param stairs A stairs entity.
4329 */
push_stairs(lua_State * l,Stairs & stairs)4330 void LuaContext::push_stairs(lua_State* l, Stairs& stairs) {
4331 push_userdata(l, stairs);
4332 }
4333
4334 /**
4335 * \brief Implementation of stairs:get_direction().
4336 * \param l The Lua context that is calling this function.
4337 * \return Number of values to return to Lua.
4338 */
stairs_api_get_direction(lua_State * l)4339 int LuaContext::stairs_api_get_direction(lua_State* l) {
4340
4341 return state_boundary_handle(l, [&] {
4342 const Stairs& stairs = *check_stairs(l, 1);
4343
4344 lua_pushinteger(l, stairs.get_direction());
4345 return 1;
4346 });
4347 }
4348
4349 /**
4350 * \brief Implementation of stairs:is_inner().
4351 * \param l The Lua context that is calling this function.
4352 * \return Number of values to return to Lua.
4353 */
stairs_api_is_inner(lua_State * l)4354 int LuaContext::stairs_api_is_inner(lua_State* l) {
4355
4356 return state_boundary_handle(l, [&] {
4357 const Stairs& stairs = *check_stairs(l, 1);
4358
4359 lua_pushboolean(l, stairs.is_inside_floor());
4360 return 1;
4361 });
4362 }
4363
4364 /**
4365 * \brief Returns whether a value is a userdata of type shop treasure.
4366 * \param l A Lua context.
4367 * \param index An index in the stack.
4368 * \return \c true if the value at this index is a shop treasure.
4369 */
is_shop_treasure(lua_State * l,int index)4370 bool LuaContext::is_shop_treasure(lua_State* l, int index) {
4371 return is_userdata(l, index, get_entity_internal_type_name(EntityType::SHOP_TREASURE));
4372 }
4373
4374 /**
4375 * \brief Checks that the userdata at the specified index of the stack is a
4376 * shop treasure and returns it.
4377 * \param l A Lua context.
4378 * \param index An index in the stack.
4379 * \return The shop treasure.
4380 */
check_shop_treasure(lua_State * l,int index)4381 std::shared_ptr<ShopTreasure> LuaContext::check_shop_treasure(lua_State* l, int index) {
4382 return std::static_pointer_cast<ShopTreasure>(check_userdata(
4383 l, index, get_entity_internal_type_name(EntityType::SHOP_TREASURE)
4384 ));
4385 }
4386
4387 /**
4388 * \brief Pushes a shop treasure userdata onto the stack.
4389 * \param l A Lua context.
4390 * \param shop_treasure A shop treasure.
4391 */
push_shop_treasure(lua_State * l,ShopTreasure & shop_treasure)4392 void LuaContext::push_shop_treasure(lua_State* l, ShopTreasure& shop_treasure) {
4393 push_userdata(l, shop_treasure);
4394 }
4395
4396 /**
4397 * \brief Notifies Lua that the hero interacts with a shop treasure.
4398 *
4399 * Lua then manages the dialogs shown to the player.
4400 *
4401 * \param shop_treasure A shop treasure.
4402 */
notify_shop_treasure_interaction(ShopTreasure & shop_treasure)4403 void LuaContext::notify_shop_treasure_interaction(ShopTreasure& shop_treasure) {
4404
4405 push_shop_treasure(current_l, shop_treasure);
4406 lua_pushcclosure(current_l, l_shop_treasure_description_dialog_finished, 1);
4407 const ScopedLuaRef& callback_ref = create_ref();
4408
4409 shop_treasure.get_game().start_dialog(
4410 shop_treasure.get_dialog_id(),
4411 ScopedLuaRef(),
4412 callback_ref
4413 );
4414 }
4415
4416 /**
4417 * \brief Callback function executed after the description dialog of
4418 * a shop treasure.
4419 * \param l The Lua context that is calling this function.
4420 * \return Number of values to return to Lua.
4421 */
l_shop_treasure_description_dialog_finished(lua_State * l)4422 int LuaContext::l_shop_treasure_description_dialog_finished(lua_State* l) {
4423
4424 return state_boundary_handle(l, [&] {
4425
4426 // The description message has just finished.
4427 // The shop treasure is the first upvalue.
4428 ShopTreasure& shop_treasure = *check_shop_treasure(l, lua_upvalueindex(1));
4429 Game& game = shop_treasure.get_game();
4430
4431 if (shop_treasure.is_being_removed()) {
4432 // The shop treasure was removed during the dialog.
4433 return 0;
4434 }
4435
4436 lua_pushinteger(l, shop_treasure.get_price());
4437 const ScopedLuaRef& price_ref = LuaTools::create_ref(l);
4438
4439 push_shop_treasure(l, shop_treasure);
4440 lua_pushcclosure(l, l_shop_treasure_question_dialog_finished, 1);
4441 ScopedLuaRef callback_ref = LuaTools::create_ref(l);
4442
4443 game.start_dialog("_shop.question", price_ref, callback_ref);
4444
4445 return 0;
4446 });
4447 }
4448
4449 /**
4450 * \brief Callback function executed after the question dialog of
4451 * a shop treasure.
4452 * \param l The Lua context that is calling this function.
4453 * \return Number of values to return to Lua.
4454 */
l_shop_treasure_question_dialog_finished(lua_State * l)4455 int LuaContext::l_shop_treasure_question_dialog_finished(lua_State* l) {
4456
4457 return state_boundary_handle(l, [&] {
4458 LuaContext& lua_context = get();
4459
4460 // The "do you want to buy?" question has just been displayed.
4461 // The shop treasure is the first upvalue.
4462 ShopTreasure& shop_treasure = *check_shop_treasure(l, lua_upvalueindex(1));
4463
4464 if (shop_treasure.is_being_removed()) {
4465 // The shop treasure was removed during the dialog.
4466 return 0;
4467 }
4468
4469 // The first parameter is the answer.
4470 bool wants_to_buy = lua_isboolean(l, 1) && lua_toboolean(l, 1);
4471
4472 Game& game = shop_treasure.get_game();
4473 if (wants_to_buy) {
4474
4475 // The player wants to buy the item.
4476 Equipment& equipment = game.get_equipment();
4477 const Treasure& treasure = shop_treasure.get_treasure();
4478 EquipmentItem& item = treasure.get_item();
4479
4480 if (!treasure.is_obtainable()) {
4481 // This treasure is not allowed.
4482 Sound::play("wrong");
4483 }
4484 else if (equipment.get_money() < shop_treasure.get_price()) {
4485 // Not enough money.
4486 Sound::play("wrong");
4487 game.start_dialog("_shop.not_enough_money", ScopedLuaRef(), ScopedLuaRef());
4488 }
4489 else if (item.has_amount() && item.get_amount() >= item.get_max_amount()) {
4490 // The player already has the maximum amount of this item.
4491 Sound::play("wrong");
4492 game.start_dialog("_shop.amount_full", ScopedLuaRef(), ScopedLuaRef());
4493 }
4494 else {
4495
4496 bool can_buy = lua_context.shop_treasure_on_buying(shop_treasure);
4497 if (can_buy) {
4498
4499 // Give the treasure.
4500 equipment.remove_money(shop_treasure.get_price());
4501
4502 game.get_hero()->start_treasure(treasure, ScopedLuaRef());
4503 if (treasure.is_saved()) {
4504 shop_treasure.remove_from_map();
4505 game.get_savegame().set_boolean(treasure.get_savegame_variable(), true);
4506 }
4507 lua_context.shop_treasure_on_bought(shop_treasure);
4508 }
4509 }
4510 }
4511 return 0;
4512 });
4513 }
4514
4515 /**
4516 * \brief Returns whether a value is a userdata of type pickable.
4517 * \param l A Lua context.
4518 * \param index An index in the stack.
4519 * \return \c true if the value at this index is a pickable.
4520 */
is_pickable(lua_State * l,int index)4521 bool LuaContext::is_pickable(lua_State* l, int index) {
4522 return is_userdata(l, index, get_entity_internal_type_name(EntityType::PICKABLE));
4523 }
4524
4525 /**
4526 * \brief Checks that the userdata at the specified index of the stack is an
4527 * pickable and returns it.
4528 * \param l A Lua context.
4529 * \param index An index in the stack.
4530 * \return The pickable.
4531 */
check_pickable(lua_State * l,int index)4532 std::shared_ptr<Pickable> LuaContext::check_pickable(lua_State* l, int index) {
4533 return std::static_pointer_cast<Pickable>(check_userdata(
4534 l, index, get_entity_internal_type_name(EntityType::PICKABLE)
4535 ));
4536 }
4537
4538 /**
4539 * \brief Pushes an pickable userdata onto the stack.
4540 * \param l A Lua context.
4541 * \param pickable A pickable treasure.
4542 */
push_pickable(lua_State * l,Pickable & pickable)4543 void LuaContext::push_pickable(lua_State* l, Pickable& pickable) {
4544 push_userdata(l, pickable);
4545 }
4546
4547 /**
4548 * \brief Implementation of pickable:get_followed_entity().
4549 * \param l The Lua context that is calling this function.
4550 * \return Number of values to return to Lua.
4551 */
pickable_api_get_followed_entity(lua_State * l)4552 int LuaContext::pickable_api_get_followed_entity(lua_State* l) {
4553
4554 return state_boundary_handle(l, [&] {
4555 Pickable& pickable = *check_pickable(l, 1);
4556
4557 EntityPtr followed_entity = pickable.get_entity_followed();
4558
4559 if (followed_entity != nullptr) {
4560 push_entity(l, *followed_entity);
4561 }
4562 else {
4563 lua_pushnil(l);
4564 }
4565 return 1;
4566 });
4567 }
4568
4569 /**
4570 * \brief Implementation of pickable:get_falling_height().
4571 * \param l The Lua context that is calling this function.
4572 * \return Number of values to return to Lua.
4573 */
pickable_api_get_falling_height(lua_State * l)4574 int LuaContext::pickable_api_get_falling_height(lua_State* l) {
4575
4576 return state_boundary_handle(l, [&] {
4577 const Pickable& pickable = *check_pickable(l, 1);
4578
4579 lua_pushinteger(l, pickable.get_falling_height());
4580 return 1;
4581 });
4582 }
4583
4584 /**
4585 * \brief Implementation of pickable:get_treasure().
4586 * \param l The Lua context that is calling this function.
4587 * \return Number of values to return to Lua.
4588 */
pickable_api_get_treasure(lua_State * l)4589 int LuaContext::pickable_api_get_treasure(lua_State* l) {
4590
4591 return state_boundary_handle(l, [&] {
4592 const Pickable& pickable = *check_pickable(l, 1);
4593 const Treasure& treasure = pickable.get_treasure();
4594
4595 push_item(l, treasure.get_item());
4596 lua_pushinteger(l, treasure.get_variant());
4597 if (!treasure.is_saved()) {
4598 lua_pushnil(l);
4599 }
4600 else {
4601 push_string(l, treasure.get_savegame_variable());
4602 }
4603 return 3;
4604 });
4605 }
4606
4607 /**
4608 * \brief Returns whether a value is a userdata of type destructible object.
4609 * \param l A Lua context.
4610 * \param index An index in the stack.
4611 * \return \c true if the value at this index is a destructible object.
4612 */
is_destructible(lua_State * l,int index)4613 bool LuaContext::is_destructible(lua_State* l, int index) {
4614 return is_userdata(l, index, get_entity_internal_type_name(EntityType::DESTRUCTIBLE));
4615 }
4616
4617 /**
4618 * \brief Checks that the userdata at the specified index of the stack is a
4619 * destructible object and returns it.
4620 * \param l A Lua context.
4621 * \param index An index in the stack.
4622 * \return The destructible object.
4623 */
check_destructible(lua_State * l,int index)4624 std::shared_ptr<Destructible> LuaContext::check_destructible(lua_State* l, int index) {
4625 return std::static_pointer_cast<Destructible>(check_userdata(
4626 l, index, get_entity_internal_type_name(EntityType::DESTRUCTIBLE)
4627 ));
4628 }
4629
4630 /**
4631 * \brief Pushes a destructible userdata onto the stack.
4632 * \param l A Lua context.
4633 * \param destructible A destructible object.
4634 */
push_destructible(lua_State * l,Destructible & destructible)4635 void LuaContext::push_destructible(lua_State* l, Destructible& destructible) {
4636 push_userdata(l, destructible);
4637 }
4638
4639 /**
4640 * \brief Implementation of destructible:get_treasure().
4641 * \param l The Lua context that is calling this function.
4642 * \return Number of values to return to Lua.
4643 */
destructible_api_get_treasure(lua_State * l)4644 int LuaContext::destructible_api_get_treasure(lua_State* l) {
4645
4646 return state_boundary_handle(l, [&] {
4647 const Destructible& destructible = *check_destructible(l, 1);
4648 const Treasure& treasure = destructible.get_treasure();
4649
4650 if (treasure.get_item_name().empty()) {
4651 // No treasure: return nil.
4652 lua_pushnil(l);
4653 return 1;
4654 }
4655
4656 push_string(l, treasure.get_item_name());
4657 lua_pushinteger(l, treasure.get_variant());
4658 if (!treasure.is_saved()) {
4659 lua_pushnil(l);
4660 }
4661 else {
4662 push_string(l, treasure.get_savegame_variable());
4663 }
4664 return 3;
4665 });
4666 }
4667
4668 /**
4669 * \brief Implementation of destructible:set_treasure().
4670 * \param l The Lua context that is calling this function.
4671 * \return Number of values to return to Lua.
4672 */
destructible_api_set_treasure(lua_State * l)4673 int LuaContext::destructible_api_set_treasure(lua_State* l) {
4674
4675 return state_boundary_handle(l, [&] {
4676 Destructible& destructible = *check_destructible(l, 1);
4677 std::string item_name, savegame_variable;
4678 int variant = 1;
4679
4680 if (lua_gettop(l) >= 2 && !lua_isnil(l, 2)) {
4681 item_name = LuaTools::check_string(l, 2);
4682 }
4683 if (lua_gettop(l) >= 3 && !lua_isnil(l, 3)) {
4684 variant = LuaTools::check_int(l, 3);
4685 }
4686 if (lua_gettop(l) >= 4 && !lua_isnil(l, 4)) {
4687 savegame_variable = LuaTools::check_string(l, 4);
4688 }
4689
4690 if (!savegame_variable.empty()
4691 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
4692 LuaTools::arg_error(l, 4,
4693 std::string("savegame variable identifier expected, got '")
4694 + savegame_variable + "'");
4695 }
4696
4697 Treasure treasure(destructible.get_game(), item_name, variant, savegame_variable);
4698 destructible.set_treasure(treasure);
4699
4700 return 0;
4701 });
4702 }
4703
4704 /**
4705 * \brief Implementation of destructible:get_destruction_sound().
4706 * \param l The Lua context that is calling this function.
4707 * \return Number of values to return to Lua.
4708 */
destructible_api_get_destruction_sound(lua_State * l)4709 int LuaContext::destructible_api_get_destruction_sound(lua_State* l) {
4710
4711 return state_boundary_handle(l, [&] {
4712 const Destructible& destructible = *check_destructible(l, 1);
4713
4714 const std::string& destruction_sound_id = destructible.get_destruction_sound();
4715
4716 if (destruction_sound_id.empty()) {
4717 lua_pushnil(l);
4718 }
4719 else {
4720 push_string(l, destruction_sound_id);
4721 }
4722 return 1;
4723 });
4724 }
4725
4726 /**
4727 * \brief Implementation of destructible:set_destruction_sound().
4728 * \param l The Lua context that is calling this function.
4729 * \return Number of values to return to Lua.
4730 */
destructible_api_set_destruction_sound(lua_State * l)4731 int LuaContext::destructible_api_set_destruction_sound(lua_State* l) {
4732
4733 return state_boundary_handle(l, [&] {
4734 Destructible& destructible = *check_destructible(l, 1);
4735 std::string destruction_sound_id;
4736 if (!lua_isnil(l, 2)) {
4737 destruction_sound_id = LuaTools::check_string(l, 2);
4738 }
4739
4740 destructible.set_destruction_sound(destruction_sound_id);
4741 return 0;
4742 });
4743 }
4744
4745 /**
4746 * \brief Implementation of destructible:get_can_be_cut().
4747 * \param l The Lua context that is calling this function.
4748 * \return Number of values to return to Lua.
4749 */
destructible_api_get_can_be_cut(lua_State * l)4750 int LuaContext::destructible_api_get_can_be_cut(lua_State* l) {
4751
4752 return state_boundary_handle(l, [&] {
4753 const Destructible& destructible = *check_destructible(l, 1);
4754
4755 bool can_be_cut = destructible.get_can_be_cut();
4756
4757 lua_pushboolean(l, can_be_cut);
4758 return 1;
4759 });
4760 }
4761
4762 /**
4763 * \brief Implementation of destructible:set_can_be_cut().
4764 * \param l The Lua context that is calling this function.
4765 * \return Number of values to return to Lua.
4766 */
destructible_api_set_can_be_cut(lua_State * l)4767 int LuaContext::destructible_api_set_can_be_cut(lua_State* l) {
4768
4769 return state_boundary_handle(l, [&] {
4770 Destructible& destructible = *check_destructible(l, 1);
4771 bool can_be_cut = LuaTools::opt_boolean(l, 2, true);
4772
4773 destructible.set_can_be_cut(can_be_cut);
4774
4775 return 0;
4776 });
4777 }
4778
4779 /**
4780 * \brief Implementation of destructible:get_can_explode().
4781 * \param l The Lua context that is calling this function.
4782 * \return Number of values to return to Lua.
4783 */
destructible_api_get_can_explode(lua_State * l)4784 int LuaContext::destructible_api_get_can_explode(lua_State* l) {
4785
4786 return state_boundary_handle(l, [&] {
4787 const Destructible& destructible = *check_destructible(l, 1);
4788
4789 bool can_explode = destructible.get_can_explode();
4790
4791 lua_pushboolean(l, can_explode);
4792 return 1;
4793 });
4794 }
4795
4796 /**
4797 * \brief Implementation of destructible:set_can_explode().
4798 * \param l The Lua context that is calling this function.
4799 * \return Number of values to return to Lua.
4800 */
destructible_api_set_can_explode(lua_State * l)4801 int LuaContext::destructible_api_set_can_explode(lua_State* l) {
4802
4803 return state_boundary_handle(l, [&] {
4804 Destructible& destructible = *check_destructible(l, 1);
4805 bool can_explode = LuaTools::opt_boolean(l, 2, true);
4806
4807 destructible.set_can_explode(can_explode);
4808
4809 return 0;
4810 });
4811 }
4812
4813 /**
4814 * \brief Implementation of destructible:get_can_regenerate().
4815 * \param l The Lua context that is calling this function.
4816 * \return Number of values to return to Lua.
4817 */
destructible_api_get_can_regenerate(lua_State * l)4818 int LuaContext::destructible_api_get_can_regenerate(lua_State* l) {
4819
4820 return state_boundary_handle(l, [&] {
4821 const Destructible& destructible = *check_destructible(l, 1);
4822
4823 bool can_regenerate = destructible.get_can_regenerate();
4824
4825 lua_pushboolean(l, can_regenerate);
4826 return 1;
4827 });
4828 }
4829
4830 /**
4831 * \brief Implementation of destructible:set_can_regenerate().
4832 * \param l The Lua context that is calling this function.
4833 * \return Number of values to return to Lua.
4834 */
destructible_api_set_can_regenerate(lua_State * l)4835 int LuaContext::destructible_api_set_can_regenerate(lua_State* l) {
4836
4837 return state_boundary_handle(l, [&] {
4838 Destructible& destructible = *check_destructible(l, 1);
4839 bool can_regenerate = LuaTools::opt_boolean(l, 2, true);
4840
4841 destructible.set_can_regenerate(can_regenerate);
4842
4843 return 0;
4844 });
4845 }
4846
4847 /**
4848 * \brief Implementation of destructible:get_damage_on_enemies().
4849 * \param l The Lua context that is calling this function.
4850 * \return Number of values to return to Lua.
4851 */
destructible_api_get_damage_on_enemies(lua_State * l)4852 int LuaContext::destructible_api_get_damage_on_enemies(lua_State* l) {
4853
4854 return state_boundary_handle(l, [&] {
4855 const Destructible& destructible = *check_destructible(l, 1);
4856
4857 int damage_on_enemies = destructible.get_damage_on_enemies();
4858
4859 lua_pushinteger(l, damage_on_enemies);
4860 return 1;
4861 });
4862 }
4863
4864 /**
4865 * \brief Implementation of destructible:set_damage_on_enemies().
4866 * \param l The Lua context that is calling this function.
4867 * \return Number of values to return to Lua.
4868 */
destructible_api_set_damage_on_enemies(lua_State * l)4869 int LuaContext::destructible_api_set_damage_on_enemies(lua_State* l) {
4870
4871 return state_boundary_handle(l, [&] {
4872 Destructible& destructible = *check_destructible(l, 1);
4873 int damage_on_enemies = LuaTools::check_int(l, 2);
4874
4875 destructible.set_damage_on_enemies(damage_on_enemies);
4876
4877 return 0;
4878 });
4879 }
4880
4881 /**
4882 * \brief Implementation of destructible:get_modified_ground().
4883 * \param l The Lua context that is calling this function.
4884 * \return Number of values to return to Lua.
4885 */
destructible_api_get_modified_ground(lua_State * l)4886 int LuaContext::destructible_api_get_modified_ground(lua_State* l) {
4887
4888 return state_boundary_handle(l, [&] {
4889 const Destructible& destructible = *check_destructible(l, 1);
4890
4891 Ground modified_ground = destructible.get_modified_ground();
4892
4893 push_string(l, enum_to_name(modified_ground));
4894 return 1;
4895 });
4896 }
4897
4898 /**
4899 * \brief Returns whether a value is a userdata of type carried object.
4900 * \param l A Lua context.
4901 * \param index An index in the stack.
4902 * \return \c true if the value at this index is a carried object.
4903 */
is_carried_object(lua_State * l,int index)4904 bool LuaContext::is_carried_object(lua_State* l, int index) {
4905 return is_userdata(l, index, get_entity_internal_type_name(EntityType::CARRIED_OBJECT));
4906 }
4907
4908 /**
4909 * \brief Checks that the userdata at the specified index of the stack is a
4910 * carried object and returns it.
4911 * \param l A Lua context.
4912 * \param index An index in the stack.
4913 * \return The carried object.
4914 */
check_carried_object(lua_State * l,int index)4915 std::shared_ptr<CarriedObject> LuaContext::check_carried_object(lua_State* l, int index) {
4916 return std::static_pointer_cast<CarriedObject>(check_userdata(
4917 l, index, get_entity_internal_type_name(EntityType::CARRIED_OBJECT)
4918 ));
4919 }
4920
4921 /**
4922 * \brief Pushes a carried object userdata onto the stack.
4923 * \param l A Lua context.
4924 * \param carried_object A carried object.
4925 */
push_carried_object(lua_State * l,CarriedObject & carried_object)4926 void LuaContext::push_carried_object(lua_State* l, CarriedObject& carried_object) {
4927 push_userdata(l, carried_object);
4928 }
4929
4930 /**
4931 * \brief Implementation of carried_object:get_carrier().
4932 * \param l The Lua context that is calling this function.
4933 * \return Number of values to return to Lua.
4934 */
carried_object_api_get_carrier(lua_State * l)4935 int LuaContext::carried_object_api_get_carrier(lua_State* l) {
4936
4937 return state_boundary_handle(l, [&] {
4938 const CarriedObject& carried_object = *check_carried_object(l, 1);
4939
4940 const EntityPtr& carrier = carried_object.get_carrier();
4941 if (carrier == nullptr) {
4942 lua_pushnil(l);
4943 }
4944 else {
4945 push_entity(l, *carrier);
4946 }
4947 return 1;
4948 });
4949 }
4950
4951 /**
4952 * \brief Implementation of carried_object:get_destruction_sound().
4953 * \param l The Lua context that is calling this function.
4954 * \return Number of values to return to Lua.
4955 */
carried_object_api_get_destruction_sound(lua_State * l)4956 int LuaContext::carried_object_api_get_destruction_sound(lua_State* l) {
4957
4958 return state_boundary_handle(l, [&] {
4959 const CarriedObject& carried_object = *check_carried_object(l, 1);
4960
4961 const std::string& destruction_sound_id = carried_object.get_destruction_sound();
4962
4963 if (destruction_sound_id.empty()) {
4964 lua_pushnil(l);
4965 }
4966 else {
4967 push_string(l, destruction_sound_id);
4968 }
4969 return 1;
4970 });
4971 }
4972
4973 /**
4974 * \brief Implementation of carried_object:set_destruction_sound().
4975 * \param l The Lua context that is calling this function.
4976 * \return Number of values to return to Lua.
4977 */
carried_object_api_set_destruction_sound(lua_State * l)4978 int LuaContext::carried_object_api_set_destruction_sound(lua_State* l) {
4979
4980 return state_boundary_handle(l, [&] {
4981 CarriedObject& carried_object = *check_carried_object(l, 1);
4982 std::string destruction_sound_id;
4983 if (!lua_isnil(l, 2)) {
4984 destruction_sound_id = LuaTools::check_string(l, 2);
4985 }
4986
4987 carried_object.set_destruction_sound(destruction_sound_id);
4988 return 0;
4989 });
4990 }
4991
4992 /**
4993 * \brief Implementation of carried_object:get_damage_on_enemies().
4994 * \param l The Lua context that is calling this function.
4995 * \return Number of values to return to Lua.
4996 */
carried_object_api_get_damage_on_enemies(lua_State * l)4997 int LuaContext::carried_object_api_get_damage_on_enemies(lua_State* l) {
4998
4999 return state_boundary_handle(l, [&] {
5000 const CarriedObject& carried_object = *check_carried_object(l, 1);
5001
5002 int damage_on_enemies = carried_object.get_damage_on_enemies();
5003
5004 lua_pushinteger(l, damage_on_enemies);
5005 return 1;
5006 });
5007 }
5008
5009 /**
5010 * \brief Implementation of carried_object:set_damage_on_enemies().
5011 * \param l The Lua context that is calling this function.
5012 * \return Number of values to return to Lua.
5013 */
carried_object_api_set_damage_on_enemies(lua_State * l)5014 int LuaContext::carried_object_api_set_damage_on_enemies(lua_State* l) {
5015
5016 return state_boundary_handle(l, [&] {
5017 CarriedObject& carried_object = *check_carried_object(l, 1);
5018 int damage_on_enemies = LuaTools::check_int(l, 2);
5019
5020 carried_object.set_damage_on_enemies(damage_on_enemies);
5021
5022 return 0;
5023 });
5024 }
5025
5026 /**
5027 * \brief Returns whether a value is a userdata of type dynamic tile.
5028 * \param l A Lua context.
5029 * \param index An index in the stack.
5030 * \return \c true if the value at this index is a dynamic tile.
5031 */
is_dynamic_tile(lua_State * l,int index)5032 bool LuaContext::is_dynamic_tile(lua_State* l, int index) {
5033 return is_userdata(l, index, get_entity_internal_type_name(EntityType::DYNAMIC_TILE));
5034 }
5035
5036 /**
5037 * \brief Checks that the userdata at the specified index of the stack is a
5038 * dynamic tile and returns it.
5039 * \param l A Lua context.
5040 * \param index An index in the stack.
5041 * \return The dynamic tile.
5042 */
check_dynamic_tile(lua_State * l,int index)5043 std::shared_ptr<DynamicTile> LuaContext::check_dynamic_tile(lua_State* l, int index) {
5044 return std::static_pointer_cast<DynamicTile>(check_userdata(
5045 l, index, get_entity_internal_type_name(EntityType::DYNAMIC_TILE)
5046 ));
5047 }
5048
5049 /**
5050 * \brief Pushes a dynamic tile userdata onto the stack.
5051 * \param l A Lua context.
5052 * \param dynamic_tile A dynamic tile.
5053 */
push_dynamic_tile(lua_State * l,DynamicTile & dynamic_tile)5054 void LuaContext::push_dynamic_tile(lua_State* l, DynamicTile& dynamic_tile) {
5055 push_userdata(l, dynamic_tile);
5056 }
5057
5058 /**
5059 * \brief Implementation of dynamic_tile:get_pattern_id().
5060 * \param l The Lua context that is calling this function.
5061 * \return Number of values to return to Lua.
5062 */
dynamic_tile_api_get_pattern_id(lua_State * l)5063 int LuaContext::dynamic_tile_api_get_pattern_id(lua_State* l) {
5064
5065 return state_boundary_handle(l, [&] {
5066 const DynamicTile& dynamic_tile = *check_dynamic_tile(l, 1);
5067
5068 const std::string& pattern_id = dynamic_tile.get_tile_pattern_id();
5069
5070 push_string(l, pattern_id);
5071 return 1;
5072 });
5073 }
5074
5075 /**
5076 * \brief Implementation of dynamic_tile:get_modified_ground().
5077 * \param l The Lua context that is calling this function.
5078 * \return Number of values to return to Lua.
5079 */
dynamic_tile_api_get_modified_ground(lua_State * l)5080 int LuaContext::dynamic_tile_api_get_modified_ground(lua_State* l) {
5081
5082 return state_boundary_handle(l, [&] {
5083 const DynamicTile& dynamic_tile = *check_dynamic_tile(l, 1);
5084
5085 Ground modified_ground = dynamic_tile.get_modified_ground();
5086
5087 push_string(l, enum_to_name(modified_ground));
5088 return 1;
5089 });
5090 }
5091
5092 /**
5093 * \brief Implementation of dynamic_tile:get_tileset().
5094 * \param l The Lua context that is calling this function.
5095 * \return Number of values to return to Lua.
5096 */
dynamic_tile_api_get_tileset(lua_State * l)5097 int LuaContext::dynamic_tile_api_get_tileset(lua_State* l) {
5098
5099 return state_boundary_handle(l, [&] {
5100 const DynamicTile& dynamic_tile = *check_dynamic_tile(l, 1);
5101
5102 const Tileset* tileset = dynamic_tile.get_tileset();
5103 if (tileset) {
5104 push_string(l, tileset->get_id());
5105 }
5106 else {
5107 lua_pushnil(l);
5108 }
5109
5110 return 1;
5111 });
5112 }
5113
5114 /**
5115 * \brief Implementation of dynamic_tile:set_tileset().
5116 * \param l The Lua context that is calling this function.
5117 * \return Number of values to return to Lua.
5118 */
dynamic_tile_api_set_tileset(lua_State * l)5119 int LuaContext::dynamic_tile_api_set_tileset(lua_State* l) {
5120
5121 return state_boundary_handle(l, [&] {
5122 DynamicTile& dynamic_tile = *check_dynamic_tile(l, 1);
5123
5124 if (lua_isstring(l, 2)) {
5125 const std::string& tileset_id = LuaTools::check_string(l, 2);
5126 dynamic_tile.set_tileset(tileset_id);
5127 }
5128 else if (lua_isnil(l, 2)) {
5129 dynamic_tile.set_tileset(nullptr);
5130 }
5131 else {
5132 LuaTools::type_error(l, 2, "string or nil");
5133 }
5134
5135 return 0;
5136 });
5137 }
5138
5139 /**
5140 * \brief Returns whether a value is a userdata of type enemy.
5141 * \param l A Lua context.
5142 * \param index An index in the stack.
5143 * \return \c true if the value at this index is an enemy.
5144 */
is_enemy(lua_State * l,int index)5145 bool LuaContext::is_enemy(lua_State* l, int index) {
5146 return is_userdata(l, index, get_entity_internal_type_name(EntityType::ENEMY));
5147 }
5148
5149 /**
5150 * \brief Checks that the userdata at the specified index of the stack is an
5151 * enemy and returns it.
5152 * \param l A Lua context.
5153 * \param index An index in the stack.
5154 * \return The enemy.
5155 */
check_enemy(lua_State * l,int index)5156 std::shared_ptr<Enemy> LuaContext::check_enemy(lua_State* l, int index) {
5157 return std::static_pointer_cast<Enemy>(check_userdata(
5158 l, index, get_entity_internal_type_name(EntityType::ENEMY)
5159 ));
5160 }
5161
5162 /**
5163 * \brief Pushes an enemy userdata onto the stack.
5164 * \param l A Lua context.
5165 * \param enemy An enemy.
5166 */
push_enemy(lua_State * l,Enemy & enemy)5167 void LuaContext::push_enemy(lua_State* l, Enemy& enemy) {
5168 push_userdata(l, enemy);
5169 }
5170
5171 /**
5172 * \brief Implementation of enemy:get_breed().
5173 * \param l The Lua context that is calling this function.
5174 * \return Number of values to return to Lua.
5175 */
enemy_api_get_breed(lua_State * l)5176 int LuaContext::enemy_api_get_breed(lua_State* l) {
5177
5178 return state_boundary_handle(l, [&] {
5179 const Enemy& enemy = *check_enemy(l, 1);
5180
5181 push_string(l, enemy.get_breed());
5182 return 1;
5183 });
5184 }
5185
5186 /**
5187 * \brief Implementation of enemy:get_life().
5188 * \param l The Lua context that is calling this function.
5189 * \return Number of values to return to Lua.
5190 */
enemy_api_get_life(lua_State * l)5191 int LuaContext::enemy_api_get_life(lua_State* l) {
5192
5193 return state_boundary_handle(l, [&] {
5194 const Enemy& enemy = *check_enemy(l, 1);
5195
5196 lua_pushinteger(l, enemy.get_life());
5197 return 1;
5198 });
5199 }
5200
5201 /**
5202 * \brief Implementation of enemy:set_life().
5203 * \param l The Lua context that is calling this function.
5204 * \return Number of values to return to Lua.
5205 */
enemy_api_set_life(lua_State * l)5206 int LuaContext::enemy_api_set_life(lua_State* l) {
5207
5208 return state_boundary_handle(l, [&] {
5209 Enemy& enemy = *check_enemy(l, 1);
5210 int life = LuaTools::check_int(l, 2);
5211
5212 enemy.set_life(life);
5213
5214 return 0;
5215 });
5216 }
5217
5218 /**
5219 * \brief Implementation of enemy:add_life().
5220 * \param l The Lua context that is calling this function.
5221 * \return Number of values to return to Lua.
5222 */
enemy_api_add_life(lua_State * l)5223 int LuaContext::enemy_api_add_life(lua_State* l) {
5224
5225 return state_boundary_handle(l, [&] {
5226 Enemy& enemy = *check_enemy(l, 1);
5227 int points = LuaTools::check_int(l, 2);
5228
5229 enemy.set_life(enemy.get_life() + points);
5230
5231 return 0;
5232 });
5233 }
5234
5235 /**
5236 * \brief Implementation of enemy:remove_life().
5237 * \param l The Lua context that is calling this function.
5238 * \return Number of values to return to Lua.
5239 */
enemy_api_remove_life(lua_State * l)5240 int LuaContext::enemy_api_remove_life(lua_State* l) {
5241
5242 return state_boundary_handle(l, [&] {
5243 Enemy& enemy = *check_enemy(l, 1);
5244 int points = LuaTools::check_int(l, 2);
5245
5246 enemy.set_life(enemy.get_life() - points);
5247
5248 return 0;
5249 });
5250 }
5251
5252 /**
5253 * \brief Implementation of enemy:get_damage().
5254 * \param l The Lua context that is calling this function.
5255 * \return Number of values to return to Lua.
5256 */
enemy_api_get_damage(lua_State * l)5257 int LuaContext::enemy_api_get_damage(lua_State* l) {
5258
5259 return state_boundary_handle(l, [&] {
5260 const Enemy& enemy = *check_enemy(l, 1);
5261
5262 lua_pushinteger(l, enemy.get_damage());
5263 return 1;
5264 });
5265 }
5266
5267 /**
5268 * \brief Implementation of enemy:set_damage().
5269 * \param l The Lua context that is calling this function.
5270 * \return Number of values to return to Lua.
5271 */
enemy_api_set_damage(lua_State * l)5272 int LuaContext::enemy_api_set_damage(lua_State* l) {
5273
5274 return state_boundary_handle(l, [&] {
5275 Enemy& enemy = *check_enemy(l, 1);
5276 int damage = LuaTools::check_int(l, 2);
5277
5278 enemy.set_damage(damage);
5279
5280 return 0;
5281 });
5282 }
5283
5284 /**
5285 * \brief Implementation of enemy:is_pushed_back_when_hurt().
5286 * \param l The Lua context that is calling this function.
5287 * \return Number of values to return to Lua.
5288 */
enemy_api_is_pushed_back_when_hurt(lua_State * l)5289 int LuaContext::enemy_api_is_pushed_back_when_hurt(lua_State* l) {
5290
5291 return state_boundary_handle(l, [&] {
5292 const Enemy& enemy = *check_enemy(l, 1);
5293
5294 lua_pushboolean(l, enemy.get_pushed_back_when_hurt());
5295 return 1;
5296 });
5297 }
5298
5299 /**
5300 * \brief Implementation of enemy:set_pushed_back_when_hurt().
5301 * \param l The Lua context that is calling this function.
5302 * \return Number of values to return to Lua.
5303 */
enemy_api_set_pushed_back_when_hurt(lua_State * l)5304 int LuaContext::enemy_api_set_pushed_back_when_hurt(lua_State* l) {
5305
5306 return state_boundary_handle(l, [&] {
5307 Enemy& enemy = *check_enemy(l, 1);
5308 bool push_back = LuaTools::opt_boolean(l, 2, true);
5309
5310 enemy.set_pushed_back_when_hurt(push_back);
5311
5312 return 0;
5313 });
5314 }
5315
5316 /**
5317 * \brief Implementation of enemy:get_push_hero_on_sword().
5318 * \param l The Lua context that is calling this function.
5319 * \return Number of values to return to Lua.
5320 */
enemy_api_get_push_hero_on_sword(lua_State * l)5321 int LuaContext::enemy_api_get_push_hero_on_sword(lua_State* l) {
5322
5323 return state_boundary_handle(l, [&] {
5324 const Enemy& enemy = *check_enemy(l, 1);
5325
5326 lua_pushboolean(l, enemy.get_push_hero_on_sword());
5327 return 1;
5328 });
5329 }
5330
5331 /**
5332 * \brief Implementation of enemy:set_push_hero_on_sword().
5333 * \param l The Lua context that is calling this function.
5334 * \return Number of values to return to Lua.
5335 */
enemy_api_set_push_hero_on_sword(lua_State * l)5336 int LuaContext::enemy_api_set_push_hero_on_sword(lua_State* l) {
5337
5338 return state_boundary_handle(l, [&] {
5339 Enemy& enemy = *check_enemy(l, 1);
5340 bool push = LuaTools::opt_boolean(l, 2, true);
5341
5342 enemy.set_push_hero_on_sword(push);
5343
5344 return 0;
5345 });
5346 }
5347
5348 /**
5349 * \brief Implementation of enemy:get_can_hurt_hero_running().
5350 * \param l The Lua context that is calling this function.
5351 * \return Number of values to return to Lua.
5352 */
enemy_api_get_can_hurt_hero_running(lua_State * l)5353 int LuaContext::enemy_api_get_can_hurt_hero_running(lua_State* l) {
5354
5355 return state_boundary_handle(l, [&] {
5356 const Enemy& enemy = *check_enemy(l, 1);
5357
5358 lua_pushboolean(l, enemy.get_can_hurt_hero_running());
5359 return 1;
5360 });
5361 }
5362
5363 /**
5364 * \brief Implementation of enemy:set_can_hurt_hero_running().
5365 * \param l The Lua context that is calling this function.
5366 * \return Number of values to return to Lua.
5367 */
enemy_api_set_can_hurt_hero_running(lua_State * l)5368 int LuaContext::enemy_api_set_can_hurt_hero_running(lua_State* l) {
5369
5370 return state_boundary_handle(l, [&] {
5371 Enemy& enemy = *check_enemy(l, 1);
5372 bool can_hurt_hero_running = LuaTools::opt_boolean(l, 2, true);
5373
5374 enemy.set_can_hurt_hero_running(can_hurt_hero_running);
5375
5376 return 0;
5377 });
5378 }
5379
5380 /**
5381 * \brief Implementation of enemy:get_hurt_style().
5382 * \param l The Lua context that is calling this function.
5383 * \return Number of values to return to Lua.
5384 */
enemy_api_get_hurt_style(lua_State * l)5385 int LuaContext::enemy_api_get_hurt_style(lua_State* l) {
5386
5387 return state_boundary_handle(l, [&] {
5388 const Enemy& enemy = *check_enemy(l, 1);
5389
5390 Enemy::HurtStyle hurt_style = enemy.get_hurt_style();
5391
5392 push_string(l, Enemy::hurt_style_names.find(hurt_style)->second);
5393 return 1;
5394 });
5395 }
5396
5397 /**
5398 * \brief Implementation of enemy:set_hurt_style().
5399 * \param l The Lua context that is calling this function.
5400 * \return Number of values to return to Lua.
5401 */
enemy_api_set_hurt_style(lua_State * l)5402 int LuaContext::enemy_api_set_hurt_style(lua_State* l) {
5403
5404 return state_boundary_handle(l, [&] {
5405 Enemy& enemy = *check_enemy(l, 1);
5406 Enemy::HurtStyle hurt_style = LuaTools::check_enum<Enemy::HurtStyle>(
5407 l, 2, Enemy::hurt_style_names);
5408
5409 enemy.set_hurt_style(hurt_style);
5410
5411 return 0;
5412 });
5413 }
5414
5415 /**
5416 * \brief Implementation of enemy:get_dying_sprite_id().
5417 * \param l The Lua context that is calling this function.
5418 * \return Number of values to return to Lua.
5419 */
enemy_api_get_dying_sprite_id(lua_State * l)5420 int LuaContext::enemy_api_get_dying_sprite_id(lua_State* l) {
5421
5422 return state_boundary_handle(l, [&] {
5423 const Enemy& enemy = *check_enemy(l, 1);
5424
5425 const std::string& dying_sprite_id = enemy.get_dying_sprite_id();
5426
5427 if (dying_sprite_id.empty()) {
5428 lua_pushnil(l);
5429 }
5430 else {
5431 push_string(l, dying_sprite_id);
5432 }
5433 return 1;
5434 });
5435 }
5436
5437 /**
5438 * \brief Implementation of enemy:set_dying_sprite_id().
5439 * \param l The Lua context that is calling this function.
5440 * \return Number of values to return to Lua.
5441 */
enemy_api_set_dying_sprite_id(lua_State * l)5442 int LuaContext::enemy_api_set_dying_sprite_id(lua_State* l) {
5443
5444 return state_boundary_handle(l, [&] {
5445 Enemy& enemy = *check_enemy(l, 1);
5446 std::string dying_sprite_id;
5447
5448 if (lua_isstring(l, 2)) {
5449 dying_sprite_id = LuaTools::check_string(l, 2);
5450 }
5451 else if (!lua_isnil(l, 2)) {
5452 LuaTools::type_error(l, 2, "string or nil");
5453 }
5454
5455 enemy.set_dying_sprite_id(dying_sprite_id);
5456
5457 return 0;
5458 });
5459 }
5460
5461 /**
5462 * \brief Implementation of enemy:get_can_attack().
5463 * \param l The Lua context that is calling this function.
5464 * \return Number of values to return to Lua.
5465 */
enemy_api_get_can_attack(lua_State * l)5466 int LuaContext::enemy_api_get_can_attack(lua_State* l) {
5467
5468 return state_boundary_handle(l, [&] {
5469 const Enemy& enemy = *check_enemy(l, 1);
5470
5471 lua_pushboolean(l, enemy.get_can_attack());
5472 return 1;
5473 });
5474 }
5475
5476 /**
5477 * \brief Implementation of enemy:set_can_attack().
5478 * \param l The Lua context that is calling this function.
5479 * \return Number of values to return to Lua.
5480 */
enemy_api_set_can_attack(lua_State * l)5481 int LuaContext::enemy_api_set_can_attack(lua_State* l) {
5482
5483 return state_boundary_handle(l, [&] {
5484 Enemy& enemy = *check_enemy(l, 1);
5485 bool can_attack = LuaTools::opt_boolean(l, 2, true);
5486
5487 enemy.set_can_attack(can_attack);
5488
5489 return 0;
5490 });
5491 }
5492
5493 /**
5494 * \brief Implementation of enemy:get_minimum_shield_needed().
5495 * \param l The Lua context that is calling this function.
5496 * \return Number of values to return to Lua.
5497 */
enemy_api_get_minimum_shield_needed(lua_State * l)5498 int LuaContext::enemy_api_get_minimum_shield_needed(lua_State* l) {
5499
5500 return state_boundary_handle(l, [&] {
5501 const Enemy& enemy = *check_enemy(l, 1);
5502
5503 int shield_level = enemy.get_minimum_shield_needed();
5504
5505 lua_pushinteger(l, shield_level);
5506 return 1;
5507 });
5508 }
5509
5510 /**
5511 * \brief Implementation of enemy:set_minimum_shield_needed().
5512 * \param l The Lua context that is calling this function.
5513 * \return Number of values to return to Lua.
5514 */
enemy_api_set_minimum_shield_needed(lua_State * l)5515 int LuaContext::enemy_api_set_minimum_shield_needed(lua_State* l) {
5516
5517 return state_boundary_handle(l, [&] {
5518 Enemy& enemy = *check_enemy(l, 1);
5519 int shield_level = LuaTools::check_int(l, 2);
5520
5521 enemy.set_minimum_shield_needed(shield_level);
5522
5523 return 0;
5524 });
5525 }
5526
5527 /**
5528 * \brief Implementation of enemy:get_attack_consequence().
5529 * \param l The Lua context that is calling this function.
5530 * \return Number of values to return to Lua.
5531 */
enemy_api_get_attack_consequence(lua_State * l)5532 int LuaContext::enemy_api_get_attack_consequence(lua_State* l) {
5533
5534 return state_boundary_handle(l, [&] {
5535 const Enemy& enemy = *check_enemy(l, 1);
5536 EnemyAttack attack = LuaTools::check_enum<EnemyAttack>(l, 2, Enemy::attack_names);
5537
5538 const EnemyReaction::Reaction& reaction = enemy.get_attack_consequence(attack, nullptr);
5539 if (reaction.type == EnemyReaction::ReactionType::HURT) {
5540 // Return the life damage.
5541 lua_pushinteger(l, reaction.life_lost);
5542 } else if (reaction.type == EnemyReaction::ReactionType::LUA_CALLBACK) {
5543 // Return the callback.
5544 reaction.callback.push(l);
5545 } else {
5546 // Return a string.
5547 push_string(l, enum_to_name(reaction.type));
5548 }
5549 return 1;
5550 });
5551 }
5552
5553 /**
5554 * \brief Implementation of enemy:set_attack_consequence().
5555 * \param l The Lua context that is calling this function.
5556 * \return Number of values to return to Lua.
5557 */
enemy_api_set_attack_consequence(lua_State * l)5558 int LuaContext::enemy_api_set_attack_consequence(lua_State* l) {
5559
5560 return state_boundary_handle(l, [&] {
5561 Enemy& enemy = *check_enemy(l, 1);
5562 EnemyAttack attack = LuaTools::check_enum<EnemyAttack>(l, 2, Enemy::attack_names);
5563
5564 if (lua_isnumber(l, 3)) {
5565 int life_points = LuaTools::check_int(l, 3);
5566 if (life_points < 0) {
5567 std::ostringstream oss;
5568 oss << "Invalid life points number for attack consequence: '"
5569 << life_points << "'";
5570 LuaTools::arg_error(l, 3, oss.str());
5571 }
5572 enemy.set_attack_consequence(attack, EnemyReaction::ReactionType::HURT, life_points);
5573 }
5574 else if (lua_isstring(l, 3)) {
5575 EnemyReaction::ReactionType reaction = LuaTools::check_enum<EnemyReaction::ReactionType>(
5576 l, 3);
5577 enemy.set_attack_consequence(attack, reaction);
5578 }
5579 else if (lua_isfunction(l, 3)) {
5580 ScopedLuaRef callback = LuaTools::check_function(l, 3);
5581 enemy.set_attack_consequence(attack, EnemyReaction::ReactionType::LUA_CALLBACK, 0, callback);
5582 }
5583 else {
5584 LuaTools::type_error(l, 3, "number, string or function");
5585 }
5586
5587 return 0;
5588 });
5589 }
5590
5591 /**
5592 * \brief Implementation of enemy:get_attack_consequence_sprite().
5593 * \param l The Lua context that is calling this function.
5594 * \return Number of values to return to Lua.
5595 */
enemy_api_get_attack_consequence_sprite(lua_State * l)5596 int LuaContext::enemy_api_get_attack_consequence_sprite(lua_State* l) {
5597
5598 return state_boundary_handle(l, [&] {
5599 const Enemy& enemy = *check_enemy(l, 1);
5600 Sprite& sprite = *check_sprite(l, 2);
5601 EnemyAttack attack = LuaTools::check_enum<EnemyAttack>(l, 3, Enemy::attack_names);
5602
5603 const EnemyReaction::Reaction& reaction = enemy.get_attack_consequence(attack, &sprite);
5604 if (reaction.type == EnemyReaction::ReactionType::HURT) {
5605 // Return the life damage.
5606 lua_pushinteger(l, reaction.life_lost);
5607 }
5608 else if (reaction.type == EnemyReaction::ReactionType::LUA_CALLBACK) {
5609 // Return the callback.
5610 reaction.callback.push(l);
5611 }
5612 else {
5613 // Return a string.
5614 push_string(l, enum_to_name(reaction.type));
5615 }
5616 return 1;
5617 });
5618 }
5619
5620 /**
5621 * \brief Implementation of enemy:set_attack_consequence_sprite().
5622 * \param l The Lua context that is calling this function.
5623 * \return Number of values to return to Lua.
5624 */
enemy_api_set_attack_consequence_sprite(lua_State * l)5625 int LuaContext::enemy_api_set_attack_consequence_sprite(lua_State* l) {
5626
5627 return state_boundary_handle(l, [&] {
5628 Enemy& enemy = *check_enemy(l, 1);
5629 Sprite& sprite = *check_sprite(l, 2);
5630 EnemyAttack attack = LuaTools::check_enum<EnemyAttack>(l, 3, Enemy::attack_names);
5631
5632 if (lua_isnumber(l, 4)) {
5633 int life_points = LuaTools::check_int(l, 4);
5634 if (life_points < 0) {
5635 std::ostringstream oss;
5636 oss << "Invalid life points number for attack consequence: '"
5637 << life_points << "'";
5638 LuaTools::arg_error(l, 4, oss.str());
5639 }
5640 enemy.set_attack_consequence_sprite(sprite, attack, EnemyReaction::ReactionType::HURT, life_points);
5641 }
5642 else if (lua_isstring(l, 4)) {
5643 EnemyReaction::ReactionType reaction = LuaTools::check_enum<EnemyReaction::ReactionType>(
5644 l, 4);
5645 enemy.set_attack_consequence_sprite(sprite, attack, reaction);
5646 }
5647 else if (lua_isfunction(l, 4)) {
5648 ScopedLuaRef callback = LuaTools::check_function(l, 4);
5649 enemy.set_attack_consequence_sprite(sprite, attack, EnemyReaction::ReactionType::LUA_CALLBACK, 0, callback);
5650 }
5651 else {
5652 LuaTools::type_error(l, 3, "number, string or function");
5653 }
5654
5655 return 0;
5656 });
5657 }
5658
5659 /**
5660 * \brief Implementation of enemy:set_default_attack_consequences().
5661 * \param l The Lua context that is calling this function.
5662 * \return Number of values to return to Lua.
5663 */
enemy_api_set_default_attack_consequences(lua_State * l)5664 int LuaContext::enemy_api_set_default_attack_consequences(lua_State* l) {
5665
5666 return state_boundary_handle(l, [&] {
5667 Enemy& enemy = *check_enemy(l, 1);
5668
5669 enemy.set_default_attack_consequences();
5670
5671 return 0;
5672 });
5673 }
5674
5675 /**
5676 * \brief Implementation of enemy:set_default_attack_consequences_sprite().
5677 * \param l The Lua context that is calling this function.
5678 * \return Number of values to return to Lua.
5679 */
enemy_api_set_default_attack_consequences_sprite(lua_State * l)5680 int LuaContext::enemy_api_set_default_attack_consequences_sprite(lua_State* l) {
5681
5682 return state_boundary_handle(l, [&] {
5683 Enemy& enemy = *check_enemy(l, 1);
5684 Sprite& sprite = *check_sprite(l, 2);
5685
5686 enemy.set_default_attack_consequences_sprite(sprite);
5687
5688 return 0;
5689 });
5690 }
5691
5692 /**
5693 * \brief Implementation of enemy:set_invincible().
5694 * \param l The Lua context that is calling this function.
5695 * \return Number of values to return to Lua.
5696 */
enemy_api_set_invincible(lua_State * l)5697 int LuaContext::enemy_api_set_invincible(lua_State* l) {
5698
5699 return state_boundary_handle(l, [&] {
5700 Enemy& enemy = *check_enemy(l, 1);
5701
5702 enemy.set_no_attack_consequences();
5703
5704 return 0;
5705 });
5706 }
5707
5708 /**
5709 * \brief Implementation of enemy:set_invincible_sprite().
5710 * \param l The Lua context that is calling this function.
5711 * \return Number of values to return to Lua.
5712 */
enemy_api_set_invincible_sprite(lua_State * l)5713 int LuaContext::enemy_api_set_invincible_sprite(lua_State* l) {
5714
5715 return state_boundary_handle(l, [&] {
5716 Enemy& enemy = *check_enemy(l, 1);
5717 Sprite& sprite = *check_sprite(l, 2);
5718
5719 enemy.set_no_attack_consequences_sprite(sprite);
5720
5721 return 0;
5722 });
5723 }
5724
5725 /**
5726 * \brief Implementation of enemy:get_treasure().
5727 * \param l The Lua context that is calling this function.
5728 * \return Number of values to return to Lua.
5729 */
enemy_api_get_treasure(lua_State * l)5730 int LuaContext::enemy_api_get_treasure(lua_State* l) {
5731
5732 return state_boundary_handle(l, [&] {
5733 const Enemy& enemy = *check_enemy(l, 1);
5734 const Treasure& treasure = enemy.get_treasure();
5735
5736 if (treasure.get_item_name().empty()) {
5737 // No treasure: return nil.
5738 lua_pushnil(l);
5739 return 1;
5740 }
5741
5742 push_string(l, treasure.get_item_name());
5743 lua_pushinteger(l, treasure.get_variant());
5744 if (!treasure.is_saved()) {
5745 lua_pushnil(l);
5746 }
5747 else {
5748 push_string(l, treasure.get_savegame_variable());
5749 }
5750 return 3;
5751 });
5752 }
5753
5754
5755 /**
5756 * \brief Implementation of enemy:set_treasure().
5757 * \param l The Lua context that is calling this function.
5758 * \return Number of values to return to Lua.
5759 */
enemy_api_set_treasure(lua_State * l)5760 int LuaContext::enemy_api_set_treasure(lua_State* l) {
5761
5762 return state_boundary_handle(l, [&] {
5763 Enemy& enemy = *check_enemy(l, 1);
5764 std::string item_name, savegame_variable;
5765 int variant = 1;
5766
5767 if (lua_gettop(l) >= 2 && !lua_isnil(l, 2)) {
5768 item_name = LuaTools::check_string(l, 2);
5769 }
5770 if (lua_gettop(l) >= 3 && !lua_isnil(l, 3)) {
5771 variant = LuaTools::check_int(l, 3);
5772 }
5773 if (lua_gettop(l) >= 4 && !lua_isnil(l, 4)) {
5774 savegame_variable = LuaTools::check_string(l, 4);
5775 }
5776
5777 if (!savegame_variable.empty()
5778 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
5779 LuaTools::arg_error(l, 4,
5780 std::string("savegame variable identifier expected, got '")
5781 + savegame_variable + "'");
5782 }
5783
5784 Treasure treasure(enemy.get_game(), item_name, variant, savegame_variable);
5785 enemy.set_treasure(treasure);
5786
5787 return 0;
5788 });
5789 }
5790
5791 /**
5792 * \brief Implementation of enemy:is_traversable().
5793 * \param l The Lua context that is calling this function.
5794 * \return Number of values to return to Lua.
5795 */
enemy_api_is_traversable(lua_State * l)5796 int LuaContext::enemy_api_is_traversable(lua_State* l) {
5797
5798 return state_boundary_handle(l, [&] {
5799 const Enemy& enemy = *check_enemy(l, 1);
5800
5801 lua_pushboolean(l, enemy.is_traversable());
5802 return 1;
5803 });
5804 }
5805
5806 /**
5807 * \brief Implementation of enemy:set_traversable().
5808 * \param l The Lua context that is calling this function.
5809 * \return Number of values to return to Lua.
5810 */
enemy_api_set_traversable(lua_State * l)5811 int LuaContext::enemy_api_set_traversable(lua_State* l) {
5812
5813 return state_boundary_handle(l, [&] {
5814 Enemy& enemy = *check_enemy(l, 1);
5815
5816 bool traversable = LuaTools::opt_boolean(l, 2, true);
5817
5818 enemy.set_traversable(traversable);
5819
5820 return 0;
5821 });
5822 }
5823
5824 /**
5825 * \brief Implementation of enemy:get_attacking_collision_mode().
5826 * \param l The Lua context that is calling this function.
5827 * \return Number of values to return to Lua.
5828 */
enemy_api_get_attacking_collision_mode(lua_State * l)5829 int LuaContext::enemy_api_get_attacking_collision_mode(lua_State* l) {
5830
5831 return state_boundary_handle(l, [&] {
5832 const Enemy& enemy = *check_enemy(l, 1);
5833
5834 push_string(l, enum_to_name(enemy.get_attacking_collision_mode()));
5835 return 1;
5836 });
5837 }
5838
5839 /**
5840 * \brief Implementation of enemy:set_attacking_collision_mode().
5841 * \param l The Lua context that is calling this function.
5842 * \return Number of values to return to Lua.
5843 */
enemy_api_set_attacking_collision_mode(lua_State * l)5844 int LuaContext::enemy_api_set_attacking_collision_mode(lua_State* l) {
5845
5846 return state_boundary_handle(l, [&] {
5847 Enemy& enemy = *check_enemy(l, 1);
5848 CollisionMode attacking_collision_mode = LuaTools::check_enum<CollisionMode>(l, 2,
5849 EnumInfoTraits<CollisionMode>::names_no_none_no_custom
5850 );
5851 enemy.set_attacking_collision_mode(attacking_collision_mode);
5852
5853 return 0;
5854 });
5855 }
5856
5857 /**
5858 * \brief Implementation of enemy:get_obstacle_behavior().
5859 * \param l The Lua context that is calling this function.
5860 * \return Number of values to return to Lua.
5861 */
enemy_api_get_obstacle_behavior(lua_State * l)5862 int LuaContext::enemy_api_get_obstacle_behavior(lua_State* l) {
5863
5864 return state_boundary_handle(l, [&] {
5865 const Enemy& enemy = *check_enemy(l, 1);
5866
5867 Enemy::ObstacleBehavior behavior = enemy.get_obstacle_behavior();
5868
5869 push_string(l, Enemy::obstacle_behavior_names.find(behavior)->second);
5870 return 1;
5871 });
5872 }
5873
5874 /**
5875 * \brief Implementation of enemy:set_obstacle_behavior().
5876 * \param l The Lua context that is calling this function.
5877 * \return Number of values to return to Lua.
5878 */
enemy_api_set_obstacle_behavior(lua_State * l)5879 int LuaContext::enemy_api_set_obstacle_behavior(lua_State* l) {
5880
5881 return state_boundary_handle(l, [&] {
5882 Enemy& enemy = *check_enemy(l, 1);
5883 Enemy::ObstacleBehavior behavior = LuaTools::check_enum<Enemy::ObstacleBehavior>(
5884 l, 2, Enemy::obstacle_behavior_names);
5885
5886 enemy.set_obstacle_behavior(behavior);
5887
5888 return 0;
5889 });
5890 }
5891
5892 /**
5893 * \brief Implementation of enemy:restart().
5894 * \param l The Lua context that is calling this function.
5895 * \return Number of values to return to Lua.
5896 */
enemy_api_restart(lua_State * l)5897 int LuaContext::enemy_api_restart(lua_State* l) {
5898
5899 return state_boundary_handle(l, [&] {
5900 Enemy& enemy = *check_enemy(l, 1);
5901
5902 enemy.restart();
5903
5904 return 0;
5905 });
5906 }
5907
5908 /**
5909 * \brief Implementation of enemy:hurt().
5910 * \param l The Lua context that is calling this function.
5911 * \return Number of values to return to Lua.
5912 */
enemy_api_hurt(lua_State * l)5913 int LuaContext::enemy_api_hurt(lua_State* l) {
5914
5915 return state_boundary_handle(l, [&] {
5916 Enemy& enemy = *check_enemy(l, 1);
5917 int life_points = LuaTools::check_int(l, 2);
5918
5919 if (enemy.is_in_normal_state() && !enemy.is_invulnerable()) {
5920 Hero& hero = enemy.get_map().get_entities().get_hero();
5921 enemy.set_attack_consequence(EnemyAttack::SCRIPT, EnemyReaction::ReactionType::HURT, life_points);
5922 enemy.try_hurt(EnemyAttack::SCRIPT, hero, nullptr);
5923 }
5924
5925 return 0;
5926 });
5927 }
5928
5929 /**
5930 * \brief Implementation of enemy:is_immobilized().
5931 * \param l The Lua context that is calling this function.
5932 * \return Number of values to return to Lua.
5933 */
enemy_api_is_immobilized(lua_State * l)5934 int LuaContext::enemy_api_is_immobilized(lua_State* l) {
5935
5936 return state_boundary_handle(l, [&] {
5937 const Enemy& enemy = *check_enemy(l, 1);
5938
5939 lua_pushboolean(l, enemy.is_immobilized());
5940 return 1;
5941 });
5942 }
5943
5944 /**
5945 * \brief Implementation of enemy:immobilize().
5946 * \param l The Lua context that is calling this function.
5947 * \return Number of values to return to Lua.
5948 */
enemy_api_immobilize(lua_State * l)5949 int LuaContext::enemy_api_immobilize(lua_State* l) {
5950
5951 return state_boundary_handle(l, [&] {
5952 Enemy& enemy = *check_enemy(l, 1);
5953
5954 if (enemy.is_invulnerable()) {
5955 return 0;
5956 }
5957
5958 if (enemy.is_in_normal_state() || enemy.is_immobilized()) {
5959 Hero& hero = enemy.get_map().get_entities().get_hero();
5960 enemy.set_attack_consequence(EnemyAttack::SCRIPT, EnemyReaction::ReactionType::IMMOBILIZED, 0);
5961 enemy.try_hurt(EnemyAttack::SCRIPT, hero, nullptr);
5962 }
5963
5964 return 0;
5965 });
5966 }
5967
5968 /**
5969 * \brief Implementation of enemy:create_enemy().
5970 * \param l The Lua context that is calling this function.
5971 * \return Number of values to return to Lua.
5972 */
enemy_api_create_enemy(lua_State * l)5973 int LuaContext::enemy_api_create_enemy(lua_State* l) {
5974
5975 return state_boundary_handle(l, [&] {
5976 Enemy& enemy = *check_enemy(l, 1);
5977 LuaTools::check_type(l, 2, LUA_TTABLE);
5978 const std::string& name = LuaTools::opt_string_field(l, 2, "name", "");
5979 int layer = LuaTools::opt_layer_field(l, 2, "layer", enemy.get_map(), enemy.get_layer());
5980 int x = LuaTools::opt_int_field(l, 2, "x", 0);
5981 int y = LuaTools::opt_int_field(l, 2, "y", 0);
5982 int direction = LuaTools::opt_int_field(l, 2, "direction", 3);
5983 const std::string& breed = LuaTools::check_string_field(l, 2, "breed");
5984 const std::string& savegame_variable = LuaTools::opt_string_field(l, 2, "savegame_variable", "");
5985 const std::string& treasure_name = LuaTools::opt_string_field(l, 2, "treasure_name", "");
5986 int treasure_variant = LuaTools::opt_int_field(l, 2, "treasure_variant", 1);
5987 const std::string& treasure_savegame_variable = LuaTools::opt_string_field(l, 2, "treasure_savegame_variable", "");
5988
5989 if (!savegame_variable.empty()
5990 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
5991 LuaTools::arg_error(l, 2, std::string(
5992 "Bad field 'savegame_variable' (invalid savegame variable identifier '")
5993 + savegame_variable + "'");
5994 }
5995
5996 if (!treasure_savegame_variable.empty()
5997 && !LuaTools::is_valid_lua_identifier(treasure_savegame_variable)) {
5998 LuaTools::arg_error(l, 2, std::string(
5999 "Bad field 'treasure_savegame_variable' (invalid savegame variable identifier '")
6000 + treasure_savegame_variable + "'");
6001 }
6002
6003 // Make x and y relative to the existing enemy.
6004 x += enemy.get_x();
6005 y += enemy.get_y();
6006
6007 // Create the new enemy.
6008 Map& map = enemy.get_map();
6009
6010 if (!map.is_loaded()) {
6011 LuaTools::error(l, "Cannot create enemy: this map is not running");
6012 }
6013
6014 Game& game = map.get_game();
6015 const EntityPtr& entity = Enemy::create(
6016 game,
6017 breed,
6018 savegame_variable,
6019 name,
6020 layer,
6021 { x, y },
6022 direction,
6023 Treasure(game, treasure_name, treasure_variant, treasure_savegame_variable)
6024 );
6025
6026 if (entity == nullptr) {
6027 // The enemy is saved as already dead.
6028 lua_pushnil(l);
6029 return 1;
6030 }
6031
6032 map.get_entities().add_entity(entity);
6033
6034 push_entity(l, *entity);
6035 return 1;
6036 });
6037 }
6038
6039 /**
6040 * \brief Returns whether a value is a userdata of type custom entity.
6041 * \param l A Lua context.
6042 * \param index An index in the stack.
6043 * \return \c true if the value at this index is a custom entity.
6044 */
is_custom_entity(lua_State * l,int index)6045 bool LuaContext::is_custom_entity(lua_State* l, int index) {
6046 return is_userdata(l, index, get_entity_internal_type_name(EntityType::CUSTOM));
6047 }
6048
6049 /**
6050 * \brief Checks that the userdata at the specified index of the stack is a
6051 * custom entity and returns it.
6052 * \param l A Lua context.
6053 * \param index An index in the stack.
6054 * \return The custom entity.
6055 */
check_custom_entity(lua_State * l,int index)6056 std::shared_ptr<CustomEntity> LuaContext::check_custom_entity(lua_State* l, int index) {
6057 return std::static_pointer_cast<CustomEntity>(check_userdata(
6058 l, index, get_entity_internal_type_name(EntityType::CUSTOM)
6059 ));
6060 }
6061
6062 /**
6063 * \brief Pushes a custom entity userdata onto the stack.
6064 * \param l A Lua context.
6065 * \param custom_entity A custom entity.
6066 */
push_custom_entity(lua_State * l,CustomEntity & entity)6067 void LuaContext::push_custom_entity(lua_State* l, CustomEntity& entity) {
6068 push_userdata(l, entity);
6069 }
6070
6071 /**
6072 * \brief Calls the specified a Lua traversable test function.
6073 * \param traversable_test_ref Lua ref to a traversable test function.
6074 * \param userdata The object that is testing if it can traverse
6075 * or be traversed by another entity.
6076 * \param other_entity The other entity.
6077 * \return \c true if the traversable test function returned \c true.
6078 */
do_traversable_test_function(const ScopedLuaRef & traversable_test_ref,ExportableToLua & userdata,Entity & other_entity)6079 bool LuaContext::do_traversable_test_function(
6080 const ScopedLuaRef& traversable_test_ref,
6081 ExportableToLua& userdata,
6082 Entity& other_entity) {
6083
6084 Debug::check_assertion(!traversable_test_ref.is_empty(),
6085 "Missing traversable test function ref"
6086 );
6087
6088 // Call the test function.
6089 push_ref(current_l, traversable_test_ref);
6090 Debug::check_assertion(lua_isfunction(current_l, -1),
6091 "Traversable test is not a function"
6092 );
6093 push_userdata(current_l, userdata);
6094 push_entity(current_l, other_entity);
6095 if (!LuaTools::call_function(current_l, 2, 1, "traversable test function")) {
6096 // Error in the traversable test function.
6097 return false;
6098 }
6099
6100 // See its result.
6101 bool traversable = lua_toboolean(current_l, -1);
6102 lua_pop(current_l, 1);
6103
6104 return traversable;
6105 }
6106
6107 /**
6108 * \brief Calls the specified a Lua collision test function.
6109 * \param collision_test_ref Lua ref to a collision test function.
6110 * \param custom_entity The custom entity that is testing the collision.
6111 * \param other_entity The entity to test a collision with.
6112 * \return \c true if the collision test function returned \c true.
6113 */
do_custom_entity_collision_test_function(const ScopedLuaRef & collision_test_ref,CustomEntity & custom_entity,Entity & other_entity)6114 bool LuaContext::do_custom_entity_collision_test_function(
6115 const ScopedLuaRef& collision_test_ref,
6116 CustomEntity& custom_entity,
6117 Entity& other_entity
6118 ) {
6119 Debug::check_assertion(!collision_test_ref.is_empty(),
6120 "Missing collision test function"
6121 );
6122
6123 // Call the test function.
6124 push_ref(current_l, collision_test_ref);
6125 Debug::check_assertion(lua_isfunction(current_l, -1),
6126 "Collision test is not a function"
6127 );
6128 push_custom_entity(current_l, custom_entity);
6129 push_entity(current_l, other_entity);
6130 if (!LuaTools::call_function(current_l, 2, 1, "collision test function")) {
6131 // Error in the collision test function.
6132 return false;
6133 }
6134
6135 // See its result.
6136 bool collision = lua_toboolean(current_l, -1);
6137 lua_pop(current_l, 1);
6138
6139 return collision;
6140 }
6141
6142 /**
6143 * \brief Executes a callback after a custom entity detected a collision.
6144 * \param callback_ref Ref of the function to call.
6145 * \param custom_entity A custom entity that detected a collision.
6146 * \param other_entity The entity that was detected.
6147 */
do_custom_entity_collision_callback(const ScopedLuaRef & callback_ref,CustomEntity & custom_entity,Entity & other_entity)6148 void LuaContext::do_custom_entity_collision_callback(
6149 const ScopedLuaRef& callback_ref,
6150 CustomEntity& custom_entity,
6151 Entity& other_entity
6152 ) {
6153 Debug::check_assertion(!callback_ref.is_empty(),
6154 "Missing collision callback");
6155
6156 push_ref(current_l, callback_ref);
6157 Debug::check_assertion(lua_isfunction(current_l, -1),
6158 "Collision callback is not a function");
6159 push_custom_entity(current_l, custom_entity);
6160 push_entity(current_l, other_entity);
6161 LuaTools::call_function(current_l, 2, 0, "collision callback");
6162 }
6163
6164 /**
6165 * \brief Executes a callback after a custom entity detected a pixel-precise
6166 * collision.
6167 * \param callback_ref Ref of the function to call.
6168 * \param custom_entity A custom entity that detected a collision.
6169 * \param other_entity The entity that was detected.
6170 * \param custom_entity_sprite Sprite of the custom entity involved in the
6171 * collision.
6172 * \param other_entity_sprite Sprite of the detected entity involved in the
6173 * collision.
6174 */
do_custom_entity_collision_callback(const ScopedLuaRef & callback_ref,CustomEntity & custom_entity,Entity & other_entity,Sprite & custom_entity_sprite,Sprite & other_entity_sprite)6175 void LuaContext::do_custom_entity_collision_callback(
6176 const ScopedLuaRef& callback_ref,
6177 CustomEntity& custom_entity,
6178 Entity& other_entity,
6179 Sprite& custom_entity_sprite,
6180 Sprite& other_entity_sprite) {
6181
6182 Debug::check_assertion(!callback_ref.is_empty(),
6183 "Missing sprite collision callback"
6184 );
6185
6186 push_ref(current_l, callback_ref);
6187 Debug::check_assertion(lua_isfunction(current_l, -1),
6188 "Sprite collision callback is not a function");
6189 push_custom_entity(current_l, custom_entity);
6190 push_entity(current_l, other_entity);
6191 push_sprite(current_l, custom_entity_sprite);
6192 push_sprite(current_l, other_entity_sprite);
6193 LuaTools::call_function(current_l, 4, 0, "collision callback");
6194 }
6195
6196 /**
6197 * \brief Implementation of custom_entity:get_model().
6198 * \param l The Lua context that is calling this function.
6199 * \return Number of values to return to Lua.
6200 */
custom_entity_api_get_model(lua_State * l)6201 int LuaContext::custom_entity_api_get_model(lua_State* l) {
6202
6203 return state_boundary_handle(l, [&] {
6204 const CustomEntity& entity = *check_custom_entity(l, 1);
6205
6206 push_string(l, entity.get_model());
6207 return 1;
6208 });
6209 }
6210
6211 /**
6212 * \brief Implementation of custom_entity:get_direction().
6213 * \param l The Lua context that is calling this function.
6214 * \return Number of values to return to Lua.
6215 */
custom_entity_api_get_direction(lua_State * l)6216 int LuaContext::custom_entity_api_get_direction(lua_State* l) {
6217
6218 return state_boundary_handle(l, [&] {
6219 const CustomEntity& entity = *check_custom_entity(l, 1);
6220
6221 lua_pushinteger(l, entity.get_sprites_direction());
6222 return 1;
6223 });
6224 }
6225
6226 /**
6227 * \brief Implementation of custom_entity:set_direction().
6228 * \param l The Lua context that is calling this function.
6229 * \return Number of values to return to Lua.
6230 */
custom_entity_api_set_direction(lua_State * l)6231 int LuaContext::custom_entity_api_set_direction(lua_State* l) {
6232
6233 return state_boundary_handle(l, [&] {
6234 CustomEntity& entity = *check_custom_entity(l, 1);
6235 int direction = LuaTools::check_int(l, 2);
6236
6237 entity.set_sprites_direction(direction);
6238
6239 return 0;
6240 });
6241 }
6242
6243 /**
6244 * \brief Implementation of custom_entity:set_traversable_by().
6245 * \param l The Lua context that is calling this function.
6246 * \return Number of values to return to Lua.
6247 */
custom_entity_api_set_traversable_by(lua_State * l)6248 int LuaContext::custom_entity_api_set_traversable_by(lua_State* l) {
6249
6250 return state_boundary_handle(l, [&] {
6251 CustomEntity& entity = *check_custom_entity(l, 1);
6252
6253 bool type_specific = false;
6254 EntityType type = EntityType::TILE;
6255 int index = 2;
6256 if (lua_isstring(l, index)) {
6257 ++index;
6258 type_specific = true;
6259 type = LuaTools::check_enum<EntityType>(
6260 l, 2
6261 );
6262 }
6263
6264 if (lua_isnil(l, index)) {
6265 // Reset the setting.
6266 if (!type_specific) {
6267 entity.reset_traversable_by_entities();
6268 }
6269 else {
6270 entity.reset_traversable_by_entities(type);
6271 }
6272 }
6273 else if (lua_isboolean(l, index)) {
6274 // Boolean value.
6275 bool traversable = lua_toboolean(l, index);
6276 if (!type_specific) {
6277 entity.set_traversable_by_entities(traversable);
6278 }
6279 else {
6280 entity.set_traversable_by_entities(type, traversable);
6281 }
6282 }
6283 else if (lua_isfunction(l, index)) {
6284 // Custom boolean function.
6285
6286 const ScopedLuaRef& traversable_test_ref = LuaTools::check_function(l, index);
6287 if (!type_specific) {
6288 entity.set_traversable_by_entities(traversable_test_ref);
6289 }
6290 else {
6291 entity.set_traversable_by_entities(type, traversable_test_ref);
6292 }
6293 }
6294 else {
6295 LuaTools::type_error(l, index, "boolean, function or nil");
6296 }
6297
6298 return 0;
6299 });
6300 }
6301
6302 /**
6303 * \brief Implementation of custom_entity:set_can_traverse().
6304 * \param l The Lua context that is calling this function.
6305 * \return Number of values to return to Lua.
6306 */
custom_entity_api_set_can_traverse(lua_State * l)6307 int LuaContext::custom_entity_api_set_can_traverse(lua_State* l) {
6308
6309 return state_boundary_handle(l, [&] {
6310 CustomEntity& entity = *check_custom_entity(l, 1);
6311
6312 bool type_specific = false;
6313 EntityType type = EntityType::TILE;
6314 int index = 2;
6315 if (lua_isstring(l, index)) {
6316 ++index;
6317 type_specific = true;
6318 type = LuaTools::check_enum<EntityType>(
6319 l, 2
6320 );
6321 }
6322
6323 if (lua_isnil(l, index)) {
6324 // Reset the setting.
6325 if (!type_specific) {
6326 entity.reset_can_traverse_entities();
6327 }
6328 else {
6329 entity.reset_can_traverse_entities(type);
6330 }
6331 }
6332 else if (lua_isboolean(l, index)) {
6333 // Boolean value.
6334 bool traversable = lua_toboolean(l, index);
6335 if (!type_specific) {
6336 entity.set_can_traverse_entities(traversable);
6337 }
6338 else {
6339 entity.set_can_traverse_entities(type, traversable);
6340 }
6341 }
6342 else if (lua_isfunction(l, index)) {
6343 // Custom boolean function.
6344 const ScopedLuaRef& traversable_test_ref = LuaTools::check_function(l, index);
6345 if (!type_specific) {
6346 entity.set_can_traverse_entities(traversable_test_ref);
6347 }
6348 else {
6349 entity.set_can_traverse_entities(type, traversable_test_ref);
6350 }
6351 }
6352 else {
6353 LuaTools::type_error(l, index, "boolean, function or nil");
6354 }
6355
6356 return 0;
6357 });
6358 }
6359
6360 /**
6361 * \brief Implementation of custom_entity:can_traverse_ground().
6362 * \param l The Lua context that is calling this function.
6363 * \return Number of values to return to Lua.
6364 */
custom_entity_api_can_traverse_ground(lua_State * l)6365 int LuaContext::custom_entity_api_can_traverse_ground(lua_State* l) {
6366
6367 return state_boundary_handle(l, [&] {
6368 const CustomEntity& entity = *check_custom_entity(l, 1);
6369 Ground ground = LuaTools::check_enum<Ground>(l, 2);
6370
6371 bool traversable = entity.can_traverse_ground(ground);
6372
6373 lua_pushboolean(l, traversable);
6374 return 1;
6375 });
6376 }
6377
6378 /**
6379 * \brief Implementation of custom_entity:set_can_traverse_ground().
6380 * \param l The Lua context that is calling this function.
6381 * \return Number of values to return to Lua.
6382 */
custom_entity_api_set_can_traverse_ground(lua_State * l)6383 int LuaContext::custom_entity_api_set_can_traverse_ground(lua_State* l) {
6384
6385 return state_boundary_handle(l, [&] {
6386 CustomEntity& entity = *check_custom_entity(l, 1);
6387 Ground ground = LuaTools::check_enum<Ground>(l, 2);
6388 if (lua_isnil(l, 3)) {
6389 entity.reset_can_traverse_ground(ground);
6390 }
6391 else {
6392 if (!lua_isboolean(l, 3)) {
6393 LuaTools::type_error(l, 3, "boolean or nil");
6394 }
6395 bool traversable = lua_toboolean(l, 3);
6396
6397 entity.set_can_traverse_ground(ground, traversable);
6398 }
6399
6400 return 0;
6401 });
6402 }
6403
6404 /**
6405 * \brief Implementation of custom_entity:add_collision_test().
6406 * \param l The Lua context that is calling this function.
6407 * \return Number of values to return to Lua.
6408 */
custom_entity_api_add_collision_test(lua_State * l)6409 int LuaContext::custom_entity_api_add_collision_test(lua_State* l) {
6410
6411 return state_boundary_handle(l, [&] {
6412 CustomEntity& entity = *check_custom_entity(l, 1);
6413
6414 const ScopedLuaRef& callback_ref = LuaTools::check_function(l, 3);
6415
6416 if (lua_isstring(l, 2)) {
6417 // Built-in collision test.
6418 CollisionMode collision_mode = LuaTools::check_enum<CollisionMode>(l, 2,
6419 EnumInfoTraits<CollisionMode>::names_no_none_no_custom
6420 );
6421 entity.add_collision_test(collision_mode, callback_ref);
6422 }
6423 else if (lua_isfunction(l, 2)) {
6424 // Custom collision test.
6425 const ScopedLuaRef& collision_test_ref = LuaTools::check_function(l, 2);
6426 entity.add_collision_test(collision_test_ref, callback_ref);
6427 }
6428 else {
6429 LuaTools::type_error(l, 2, "string or function");
6430 }
6431
6432 return 0;
6433 });
6434 }
6435
6436 /**
6437 * \brief Implementation of custom_entity:clear_collision_tests().
6438 * \param l The Lua context that is calling this function.
6439 * \return Number of values to return to Lua.
6440 */
custom_entity_api_clear_collision_tests(lua_State * l)6441 int LuaContext::custom_entity_api_clear_collision_tests(lua_State* l) {
6442
6443 return state_boundary_handle(l, [&] {
6444 CustomEntity& entity = *check_custom_entity(l, 1);
6445
6446 entity.clear_collision_tests();
6447
6448 return 0;
6449 });
6450 }
6451
6452 /**
6453 * \brief Implementation of custom_entity:get_modified_ground().
6454 * \param l The Lua context that is calling this function.
6455 * \return Number of values to return to Lua.
6456 */
custom_entity_api_get_modified_ground(lua_State * l)6457 int LuaContext::custom_entity_api_get_modified_ground(lua_State* l) {
6458
6459 return state_boundary_handle(l, [&] {
6460 const CustomEntity& entity = *check_custom_entity(l, 1);
6461
6462 const Ground modified_ground = entity.get_modified_ground();
6463
6464 if (modified_ground == Ground::EMPTY) {
6465 lua_pushnil(l);
6466 }
6467 else {
6468 push_string(l, enum_to_name(modified_ground));
6469 }
6470 return 1;
6471 });
6472 }
6473
6474 /**
6475 * \brief Implementation of custom_entity:set_modified_ground().
6476 * \param l The Lua context that is calling this function.
6477 * \return Number of values to return to Lua.
6478 */
custom_entity_api_set_modified_ground(lua_State * l)6479 int LuaContext::custom_entity_api_set_modified_ground(lua_State* l) {
6480
6481 return state_boundary_handle(l, [&] {
6482 CustomEntity& entity = *check_custom_entity(l, 1);
6483 Ground modified_ground = Ground::EMPTY;
6484
6485 if (lua_gettop(l) == 1) {
6486 LuaTools::type_error(l, 2, "string or nil");
6487 }
6488 if (!lua_isnil(l, 2)) {
6489 modified_ground = LuaTools::check_enum<Ground>(l, 2);
6490 }
6491
6492 entity.set_modified_ground(modified_ground);
6493 return 0;
6494 });
6495 }
6496
6497 /**
6498 * \brief Implementation of custom_entity:get_tiled().
6499 * \param l The Lua context that is calling this function.
6500 * \return Number of values to return to Lua.
6501 */
custom_entity_api_is_tiled(lua_State * l)6502 int LuaContext::custom_entity_api_is_tiled(lua_State* l) {
6503
6504 return state_boundary_handle(l, [&] {
6505 const CustomEntity& entity = *check_custom_entity(l, 1);
6506
6507 lua_pushboolean(l, entity.is_tiled());
6508 return 1;
6509 });
6510 }
6511
6512 /**
6513 * \brief Implementation of custom_entity:set_tiled().
6514 * \param l The Lua context that is calling this function.
6515 * \return Number of values to return to Lua.
6516 */
custom_entity_api_set_tiled(lua_State * l)6517 int LuaContext::custom_entity_api_set_tiled(lua_State* l) {
6518
6519 return state_boundary_handle(l, [&] {
6520 CustomEntity& entity = *check_custom_entity(l, 1);
6521 bool tiled = LuaTools::opt_boolean(l, 2, true);
6522
6523 entity.set_tiled(tiled);
6524
6525 return 0;
6526 });
6527 }
6528
6529 /**
6530 * \brief Implementation of custom_entity:get_follow_streams().
6531 * \param l The Lua context that is calling this function.
6532 * \return Number of values to return to Lua.
6533 */
custom_entity_api_get_follow_streams(lua_State * l)6534 int LuaContext::custom_entity_api_get_follow_streams(lua_State* l) {
6535
6536 return state_boundary_handle(l, [&] {
6537 const CustomEntity& entity = *check_custom_entity(l, 1);
6538
6539 lua_pushboolean(l, entity.get_follow_streams());
6540 return 1;
6541 });
6542 }
6543
6544 /**
6545 * \brief Implementation of custom_entity:set_follow_streams().
6546 * \param l The Lua context that is calling this function.
6547 * \return Number of values to return to Lua.
6548 */
custom_entity_api_set_follow_streams(lua_State * l)6549 int LuaContext::custom_entity_api_set_follow_streams(lua_State* l) {
6550
6551 return state_boundary_handle(l, [&] {
6552 CustomEntity& entity = *check_custom_entity(l, 1);
6553 bool follow_streams = LuaTools::opt_boolean(l, 2, true);
6554
6555 entity.set_follow_streams(follow_streams);
6556
6557 return 0;
6558 });
6559 }
6560
6561 /**
6562 * \brief Calls the on_update() method of a Lua map entity.
6563 *
6564 * Does nothing if the method is not defined.
6565 *
6566 * \param entity A map entity.
6567 */
entity_on_update(Entity & entity)6568 void LuaContext::entity_on_update(Entity& entity) {
6569
6570 // This particular method is tried so often that we want to optimize
6571 // the std::string construction.
6572 static const std::string method_name = "on_update";
6573 if (!userdata_has_field(entity, method_name)) {
6574 return;
6575 }
6576
6577 push_entity(current_l, entity);
6578 on_update();
6579 lua_pop(current_l, 1);
6580 }
6581
6582 /**
6583 * \brief Calls the on_suspended() method of a Lua map entity.
6584 *
6585 * Does nothing if the method is not defined.
6586 *
6587 * \param entity A map entity.
6588 * \param suspended \c true if the entity is suspended.
6589 */
entity_on_suspended(Entity & entity,bool suspended)6590 void LuaContext::entity_on_suspended(Entity& entity, bool suspended) {
6591
6592 if (!userdata_has_field(entity, "on_suspended")) {
6593 return;
6594 }
6595 run_on_main([this, &entity, suspended](lua_State* l){
6596 push_entity(l, entity);
6597 on_suspended(suspended);
6598 lua_pop(l, 1);
6599 });
6600 }
6601
6602 /**
6603 * \brief Calls the on_created() method of a Lua map entity.
6604 *
6605 * Does nothing if the method is not defined.
6606 *
6607 * \param entity A map entity.
6608 */
entity_on_created(Entity & entity)6609 void LuaContext::entity_on_created(Entity& entity) {
6610
6611 if (!userdata_has_field(entity, "on_created")) {
6612 return;
6613 }
6614 run_on_main([this, &entity](lua_State* l){
6615 push_entity(l, entity);
6616 on_created();
6617 lua_pop(l, 1);
6618 });
6619 }
6620
6621 /**
6622 * \brief Calls the on_removed() method of a Lua map entity if it is defined.
6623 *
6624 * Also stops timers associated to the entity.
6625 *
6626 * \param entity A map entity.
6627 */
entity_on_removed(Entity & entity)6628 void LuaContext::entity_on_removed(Entity& entity) {
6629 run_on_main([this, &entity](lua_State* l){
6630 push_entity(l, entity);
6631 if (userdata_has_field(entity, "on_removed")) {
6632 on_removed();
6633 }
6634 remove_timers(-1); // Stop timers associated to this entity.
6635 lua_pop(l, 1);
6636 });
6637 }
6638
6639 /**
6640 * \brief Calls the on_enabled() method of a Lua map entity.
6641 *
6642 * Does nothing if the method is not defined.
6643 *
6644 * \param entity A map entity.
6645 */
entity_on_enabled(Entity & entity)6646 void LuaContext::entity_on_enabled(Entity& entity) {
6647
6648 if (!userdata_has_field(entity, "on_enabled")) {
6649 return;
6650 }
6651 run_on_main([this, &entity](lua_State* l){
6652 push_entity(l, entity);
6653 on_enabled();
6654 lua_pop(l, 1);
6655 });
6656 }
6657
6658 /**
6659 * \brief Calls the on_disabled() method of a Lua map entity.
6660 *
6661 * Does nothing if the method is not defined.
6662 *
6663 * \param entity A map entity.
6664 */
entity_on_disabled(Entity & entity)6665 void LuaContext::entity_on_disabled(Entity& entity) {
6666
6667 if (!userdata_has_field(entity, "on_disabled")) {
6668 return;
6669 }
6670 run_on_main([this, &entity](lua_State* l){
6671 push_entity(l, entity);
6672 on_disabled();
6673 lua_pop(l, 1);
6674 });
6675 }
6676
6677 /**
6678 * \brief Calls the on_pre_draw() method of a Lua map entity.
6679 *
6680 * Does nothing if the method is not defined.
6681 *
6682 * \param entity A map entity.
6683 * \param camera The camera where to draw the entity.
6684 */
entity_on_pre_draw(Entity & entity,Camera & camera)6685 void LuaContext::entity_on_pre_draw(Entity& entity, Camera& camera) {
6686
6687 if (!userdata_has_field(entity, "on_pre_draw")) {
6688 return;
6689 }
6690 run_on_main([this, &entity, &camera](lua_State* l){
6691 push_entity(l, entity);
6692 on_pre_draw(camera);
6693 lua_pop(l, 1);
6694 });
6695 }
6696
6697 /**
6698 * \brief Calls the on_post_draw() method of a Lua map entity.
6699 *
6700 * Does nothing if the method is not defined.
6701 *
6702 * \param entity A map entity.
6703 * \param camera The camera where to draw the entity.
6704 */
entity_on_post_draw(Entity & entity,Camera & camera)6705 void LuaContext::entity_on_post_draw(Entity& entity, Camera& camera) {
6706
6707 if (!userdata_has_field(entity, "on_post_draw")) {
6708 return;
6709 }
6710 run_on_main([this, &entity, &camera](lua_State* l){
6711 push_entity(l, entity);
6712 on_post_draw(camera);
6713 lua_pop(l, 1);
6714 });
6715 }
6716
6717 /**
6718 * \brief Calls the on_position_changed() method of a Lua map entity.
6719 *
6720 * Does nothing if the method is not defined.
6721 *
6722 * \param entity A map entity.
6723 * \param xy The new coordinates.
6724 * \param layer The new layer.
6725 */
entity_on_position_changed(Entity & entity,const Point & xy,int layer)6726 void LuaContext::entity_on_position_changed(
6727 Entity& entity, const Point& xy, int layer) {
6728
6729 if (!userdata_has_field(entity, "on_position_changed")) {
6730 return;
6731 }
6732 run_on_main([this, &entity, xy, layer](lua_State* l){
6733 push_entity(l, entity);
6734 on_position_changed(xy, layer);
6735 lua_pop(l, 1);
6736 });
6737 }
6738
6739 /**
6740 * \brief Calls the on_obstacle_reached() method of a Lua map entity.
6741 *
6742 * Does nothing if the method is not defined.
6743 *
6744 * \param entity A map entity.
6745 * \param movement The movement that reached an obstacle.
6746 */
entity_on_obstacle_reached(Entity & entity,Movement & movement)6747 void LuaContext::entity_on_obstacle_reached(
6748 Entity& entity, Movement& movement) {
6749
6750 if (!userdata_has_field(entity, "on_obstacle_reached")) {
6751 return;
6752 }
6753 run_on_main([this, &entity, &movement](lua_State* l) {
6754 push_entity(l, entity);
6755 on_obstacle_reached(movement);
6756 lua_pop(l, 1);
6757 });
6758 }
6759
6760 /**
6761 * \brief Calls the on_movement_started() method of a Lua map entity.
6762 *
6763 * Does nothing if the method is not defined.
6764 *
6765 * \param entity A map entity.
6766 * \param movement The movement that has just started.
6767 */
entity_on_movement_started(Entity & entity,Movement & movement)6768 void LuaContext::entity_on_movement_started(
6769 Entity& entity, Movement& movement) {
6770
6771 if (!userdata_has_field(entity, "on_movement_started")) {
6772 return;
6773 }
6774
6775 run_on_main([this, &entity, &movement](lua_State* l) {
6776 push_entity(l, entity);
6777 on_movement_started(movement);
6778 lua_pop(l, 1);
6779 });
6780 }
6781
6782 /**
6783 * \brief Calls the on_movement_changed() method of a Lua map entity.
6784 *
6785 * Does nothing if the method is not defined.
6786 *
6787 * \param entity A map entity.
6788 * \param movement Its movement.
6789 */
entity_on_movement_changed(Entity & entity,Movement & movement)6790 void LuaContext::entity_on_movement_changed(
6791 Entity& entity, Movement& movement) {
6792
6793 if (!userdata_has_field(entity, "on_movement_changed")) {
6794 return;
6795 }
6796
6797 run_on_main([this, &entity, &movement](lua_State* l) {
6798 push_entity(l, entity);
6799 on_movement_changed(movement);
6800 lua_pop(l, 1);
6801 });
6802 }
6803
6804 /**
6805 * \brief Calls the on_movement_finished() method of a Lua map entity.
6806 *
6807 * Does nothing if the method is not defined.
6808 *
6809 * \param entity A map entity.
6810 */
entity_on_movement_finished(Entity & entity)6811 void LuaContext::entity_on_movement_finished(Entity& entity) {
6812
6813 if (!userdata_has_field(entity, "on_movement_finished")) {
6814 return;
6815 }
6816
6817 run_on_main([this, &entity](lua_State* l) {
6818 push_entity(l, entity);
6819 on_movement_finished();
6820 lua_pop(l, 1);
6821 });
6822 }
6823
6824 /**
6825 * \brief Calls the on_interaction() method of a Lua map entity.
6826 *
6827 * Does nothing if the method is not defined.
6828 *
6829 * \param entity A map entity.
6830 * \return \c true if an interaction occurred.
6831 */
entity_on_interaction(Entity & entity)6832 bool LuaContext::entity_on_interaction(Entity& entity) {
6833
6834 if (!userdata_has_field(entity, "on_interaction")) {
6835 return false;
6836 }
6837
6838 //TODO make this on main
6839 check_callback_thread();
6840
6841 push_entity(current_l, entity);
6842 bool exists = on_interaction();
6843 lua_pop(current_l, 1);
6844
6845
6846 return exists;
6847 }
6848
6849 /**
6850 * \brief Calls the on_interaction_item() method of a Lua map entity.
6851 *
6852 * Does nothing if the method is not defined.
6853 *
6854 * \param entity A map entity.
6855 * \param item_used The equipment item used.
6856 * \return \c true if an interaction occurred.
6857 */
entity_on_interaction_item(Entity & entity,EquipmentItem & item_used)6858 bool LuaContext::entity_on_interaction_item(
6859 Entity& entity, EquipmentItem& item_used) {
6860
6861 if (!userdata_has_field(entity, "on_interaction_item")) {
6862 return false;
6863 }
6864
6865 //TODO make this on main
6866 check_callback_thread();
6867
6868 push_entity(current_l, entity);
6869 bool result = on_interaction_item(item_used);
6870 lua_pop(current_l, 1);
6871 return result;
6872 }
6873
6874 /**
6875 * \brief Calls the on_state_changing() method of a Lua entity.
6876 *
6877 * Does nothing if the method is not defined.
6878 *
6879 * \param entity A map entity.
6880 * \param state_state Name of the current state.
6881 * \param next_state_name Name of the state about to start.
6882 */
entity_on_state_changing(Entity & entity,const std::string & state_name,const std::string & next_state_name)6883 void LuaContext::entity_on_state_changing(
6884 Entity& entity, const std::string& state_name, const std::string& next_state_name) {
6885
6886 if (!userdata_has_field(entity, "on_state_changing")) {
6887 return;
6888 }
6889 run_on_main([this, &entity, state_name, next_state_name](lua_State* l){
6890 push_entity(l, entity);
6891 on_state_changing(state_name, next_state_name);
6892 lua_pop(l, 1);
6893 });
6894 }
6895
6896 /**
6897 * \brief Calls the on_state_changed() method of a Lua entity.
6898 *
6899 * Does nothing if the method is not defined.
6900 *
6901 * \param entity A map entity.
6902 * \param new_state_name A name describing the new state.
6903 */
entity_on_state_changed(Entity & entity,const std::string & new_state_name)6904 void LuaContext::entity_on_state_changed(
6905 Entity& entity, const std::string& new_state_name) {
6906
6907 if (!userdata_has_field(entity, "on_state_changed")) {
6908 return;
6909 }
6910 run_on_main([this, &entity, new_state_name](lua_State* l){
6911 push_entity(l, entity);
6912 on_state_changed(new_state_name);
6913 lua_pop(l, 1);
6914 });
6915 }
6916
6917 /**
6918 * \brief Calls the on_lifting() method of a Lua entity.
6919 *
6920 * Does nothing if the method is not defined.
6921 *
6922 * \param entity The entity being lifted.
6923 * \param carrier Entity that is lifting the first one.
6924 * \param carried_object Carried object created to replace
6925 * the entity being lifted.
6926 */
entity_on_lifting(Entity & entity,Entity & carrier,CarriedObject & carried_object)6927 void LuaContext::entity_on_lifting(
6928 Entity& entity,
6929 Entity& carrier,
6930 CarriedObject& carried_object
6931 ) {
6932
6933 if (!userdata_has_field(entity, "on_lifting")) {
6934 return;
6935 }
6936 run_on_main([this, &entity, &carrier, &carried_object](lua_State* l){
6937 push_entity(l, entity);
6938 on_lifting(carrier, carried_object);
6939 lua_pop(l, 1);
6940 });
6941 }
6942
6943 /**
6944 * \brief Calls the on_taking_damage() method of a Lua hero.
6945 *
6946 * Does nothing if the method is not defined.
6947 *
6948 * \param hero The hero.
6949 * \param damage The damage to take.
6950 * \return \c true if the event is defined.
6951 */
hero_on_taking_damage(Hero & hero,int damage)6952 bool LuaContext::hero_on_taking_damage(Hero& hero, int damage) {
6953
6954 if (!userdata_has_field(hero, "on_taking_damage")) {
6955 return false;
6956 }
6957 //TODO make in main
6958 check_callback_thread();
6959
6960 push_hero(current_l, hero);
6961 bool exists = on_taking_damage(damage);
6962 lua_pop(current_l, 1);
6963 return exists;
6964 }
6965
6966 /**
6967 * \brief Calls the on_activated() method of a Lua destination.
6968 *
6969 * Does nothing if the method is not defined.
6970 *
6971 * \param destination A destination.
6972 */
destination_on_activated(Destination & destination)6973 void LuaContext::destination_on_activated(Destination& destination) {
6974
6975 if (!userdata_has_field(destination, "on_activated")) {
6976 return;
6977 }
6978 run_on_main([this, &destination](lua_State* l){
6979 push_entity(l, destination);
6980 on_activated();
6981 lua_pop(l, 1);
6982 });
6983 }
6984
6985 /**
6986 * \brief Calls the on_activated() method of a Lua teletransporter.
6987 *
6988 * Does nothing if the method is not defined.
6989 *
6990 * \param teletransporter A teletransporter.
6991 */
teletransporter_on_activated(Teletransporter & teletransporter)6992 void LuaContext::teletransporter_on_activated(Teletransporter& teletransporter) {
6993
6994 if (!userdata_has_field(teletransporter, "on_activated")) {
6995 return;
6996 }
6997 run_on_main([this, &teletransporter](lua_State* l){
6998 push_teletransporter(l, teletransporter);
6999 on_activated();
7000 lua_pop(l, 1);
7001 });
7002 }
7003
7004 /**
7005 * \brief Calls the on_collision_fire() method of a Lua NPC.
7006 *
7007 * Does nothing if the method is not defined.
7008 *
7009 * \param npc An NPC.
7010 */
npc_on_collision_fire(Npc & npc)7011 void LuaContext::npc_on_collision_fire(Npc& npc) {
7012
7013 if (!userdata_has_field(npc, "on_collision_fire")) {
7014 return;
7015 }
7016 run_on_main([this, &npc](lua_State* l){
7017 push_npc(l, npc);
7018 on_collision_fire();
7019 lua_pop(l, 1);
7020 });
7021 }
7022
7023 /**
7024 * \brief Calls the on_lifted() method of a Lua carried object.
7025 *
7026 * Does nothing if the method is not defined.
7027 *
7028 * \param carried_object A carried object.
7029 */
carried_object_on_lifted(CarriedObject & carried_object)7030 void LuaContext::carried_object_on_lifted(CarriedObject& carried_object) {
7031
7032 if (!userdata_has_field(carried_object, "on_lifted")) {
7033 return;
7034 }
7035 run_on_main([this, &carried_object](lua_State* l){
7036 push_carried_object(l, carried_object);
7037 on_lifted();
7038 lua_pop(l, 1);
7039 });
7040 }
7041
7042
7043 /**
7044 * \brief Calls the on_thrown() method of a Lua carried object.
7045 *
7046 * Does nothing if the method is not defined.
7047 *
7048 * \param carried_object A carried object.
7049 */
carried_object_on_thrown(CarriedObject & carried_object)7050 void LuaContext::carried_object_on_thrown(CarriedObject& carried_object) {
7051
7052 if (!userdata_has_field(carried_object, "on_thrown")) {
7053 return;
7054 }
7055 run_on_main([this, &carried_object](lua_State* l){
7056 push_carried_object(l, carried_object);
7057 on_thrown();
7058 lua_pop(l, 1);
7059 });
7060 }
7061
7062
7063 /**
7064 * \brief Calls the on_breaking() method of a Lua carried object.
7065 *
7066 * Does nothing if the method is not defined.
7067 *
7068 * \param carried_object A carried object.
7069 */
carried_object_on_breaking(CarriedObject & carried_object)7070 void LuaContext::carried_object_on_breaking(CarriedObject& carried_object) {
7071
7072 if (!userdata_has_field(carried_object, "on_breaking")) {
7073 return;
7074 }
7075 run_on_main([this, &carried_object](lua_State* l){
7076 push_carried_object(l, carried_object);
7077 on_breaking();
7078 lua_pop(l, 1);
7079 });
7080 }
7081
7082 /**
7083 * \brief Calls the on_moving() method of a Lua block.
7084 *
7085 * Does nothing if the method is not defined.
7086 *
7087 * \param block a block.
7088 */
block_on_moving(Block & block)7089 void LuaContext::block_on_moving(Block& block) {
7090
7091 if (!userdata_has_field(block, "on_moving")) {
7092 return;
7093 }
7094 run_on_main([this, &block](lua_State* l){
7095 push_block(l, block);
7096 on_moving();
7097 lua_pop(l, 1);
7098 });
7099 }
7100
7101 /**
7102 * \brief Calls the on_moved() method of a Lua block.
7103 *
7104 * Does nothing if the method is not defined.
7105 *
7106 * \param block a block.
7107 */
block_on_moved(Block & block)7108 void LuaContext::block_on_moved(Block& block) {
7109
7110 if (!userdata_has_field(block, "on_moved")) {
7111 return;
7112 }
7113 run_on_main([this, &block](lua_State* l){
7114 push_block(l, block);
7115 on_moved();
7116 lua_pop(l, 1);
7117 });
7118 }
7119
7120 /**
7121 * \brief Calls the on_opened() method of a Lua chest.
7122 *
7123 * Does nothing if the method is not defined.
7124 *
7125 * \param chest A chest.
7126 * \param treasure The treasure obtained.
7127 * \return \c true if the on_opened() method is defined.
7128 */
chest_on_opened(Chest & chest,const Treasure & treasure)7129 bool LuaContext::chest_on_opened(Chest& chest, const Treasure& treasure) {
7130
7131 if (!userdata_has_field(chest, "on_opened")) {
7132 return false;
7133 }
7134
7135 //TODO make this on main
7136 check_callback_thread();
7137
7138 push_chest(current_l, chest);
7139 bool exists = on_opened(treasure);
7140 lua_pop(current_l, 1);
7141 return exists;
7142 }
7143
7144 /**
7145 * \brief Calls the on_activated() method of a Lua switch.
7146 *
7147 * Does nothing if the method is not defined.
7148 *
7149 * \param sw A switch.
7150 */
switch_on_activated(Switch & sw)7151 void LuaContext::switch_on_activated(Switch& sw) {
7152
7153 if (!userdata_has_field(sw, "on_activated")) {
7154 return;
7155 }
7156
7157 run_on_main([this, &sw](lua_State* l){
7158 push_switch(l, sw);
7159 on_activated();
7160 lua_pop(l, 1);
7161 });
7162 }
7163
7164 /**
7165 * \brief Calls the on_inactivated() method of a Lua switch.
7166 *
7167 * Does nothing if the method is not defined.
7168 *
7169 * \param sw A switch.
7170 */
switch_on_inactivated(Switch & sw)7171 void LuaContext::switch_on_inactivated(Switch& sw) {
7172
7173 if (!userdata_has_field(sw, "on_inactivated")) {
7174 return;
7175 }
7176
7177 run_on_main([this, &sw](lua_State* l){
7178 push_switch(l, sw);
7179 on_inactivated();
7180 lua_pop(l, 1);
7181 });
7182 }
7183
7184 /**
7185 * \brief Calls the on_left() method of a Lua switch.
7186 *
7187 * Does nothing if the method is not defined.
7188 *
7189 * \param sw A switch.
7190 */
switch_on_left(Switch & sw)7191 void LuaContext::switch_on_left(Switch& sw) {
7192
7193 if (!userdata_has_field(sw, "on_left")) {
7194 return;
7195 }
7196
7197 run_on_main([this, &sw](lua_State* l){
7198 push_switch(l, sw);
7199 on_left();
7200 lua_pop(l, 1);
7201 });
7202 }
7203
7204 /**
7205 * \brief Calls the on_activated() method of a Lua sensor.
7206 *
7207 * Does nothing if the method is not defined.
7208 *
7209 * \param sensor A sensor.
7210 */
sensor_on_activated(Sensor & sensor)7211 void LuaContext::sensor_on_activated(Sensor& sensor) {
7212
7213 if (!userdata_has_field(sensor, "on_activated")) {
7214 return;
7215 }
7216
7217 run_on_main([this, &sensor](lua_State* l){
7218 push_entity(l, sensor);
7219 on_activated();
7220 lua_pop(l, 1);
7221 });
7222 }
7223
7224 /**
7225 * \brief Calls the on_activated_repeat() method of a Lua sensor.
7226 *
7227 * Does nothing if the method is not defined.
7228 *
7229 * \param sensor A sensor.
7230 */
sensor_on_activated_repeat(Sensor & sensor)7231 void LuaContext::sensor_on_activated_repeat(Sensor& sensor) {
7232
7233 if (!userdata_has_field(sensor, "on_activated_repeat")) {
7234 return;
7235 }
7236 run_on_main([this, &sensor](lua_State* l){
7237 push_entity(l, sensor);
7238 on_activated_repeat();
7239 lua_pop(l, 1);
7240 });
7241 }
7242
7243 /**
7244 * \brief Calls the on_left() method of a Lua sensor.
7245 * \param sensor A sensor.
7246 */
sensor_on_left(Sensor & sensor)7247 void LuaContext::sensor_on_left(Sensor& sensor) {
7248
7249 if (!userdata_has_field(sensor, "on_left")) {
7250 return;
7251 }
7252 run_on_main([this, &sensor](lua_State* l){
7253 push_entity(l, sensor);
7254 on_left();
7255 lua_pop(l, 1);
7256 });
7257 }
7258
7259 /**
7260 * \brief Calls the on_collision_explosion() method of a Lua sensor.
7261 *
7262 * Does nothing if the method is not defined.
7263 *
7264 * \param sensor A sensor.
7265 */
sensor_on_collision_explosion(Sensor & sensor)7266 void LuaContext::sensor_on_collision_explosion(Sensor& sensor) {
7267
7268 if (!userdata_has_field(sensor, "on_collision_explosion")) {
7269 return;
7270 }
7271 run_on_main([this, &sensor](lua_State* l){
7272 push_entity(l, sensor);
7273 on_collision_explosion();
7274 lua_pop(l, 1);
7275 });
7276 }
7277
7278 /**
7279 * \brief Calls the on_activating() method of a Lua separator.
7280 *
7281 * Does nothing if the method is not defined.
7282 *
7283 * \param separator A separator.
7284 * \param direction4 Direction of the traversal.
7285 */
separator_on_activating(Separator & separator,int direction4)7286 void LuaContext::separator_on_activating(Separator& separator, int direction4) {
7287
7288 if (!userdata_has_field(separator, "on_activating")) {
7289 return;
7290 }
7291 run_on_main([this, &separator, direction4](lua_State* l){
7292 push_entity(l, separator);
7293 on_activating(direction4);
7294 lua_pop(l, 1);
7295 });
7296 }
7297
7298 /**
7299 * \brief Calls the on_activated() method of a Lua separator.
7300 *
7301 * Does nothing if the method is not defined.
7302 *
7303 * \param separator A separator.
7304 * \param direction4 Direction of the traversal.
7305 */
separator_on_activated(Separator & separator,int direction4)7306 void LuaContext::separator_on_activated(Separator& separator, int direction4) {
7307
7308 if (!userdata_has_field(separator, "on_activated")) {
7309 return;
7310 }
7311 run_on_main([this, &separator, direction4](lua_State* l){
7312 push_entity(l, separator);
7313 on_activated(direction4);
7314 lua_pop(l, 1);
7315 });
7316 }
7317
7318 /**
7319 * \brief Calls the on_opened() method of a Lua door.
7320 *
7321 * Does nothing if the method is not defined.
7322 *
7323 * \param door A door.
7324 */
door_on_opened(Door & door)7325 void LuaContext::door_on_opened(Door& door) {
7326
7327 if (!userdata_has_field(door, "on_opened")) {
7328 return;
7329 }
7330 run_on_main([this, &door](lua_State* l){
7331 push_door(l, door);
7332 on_opened();
7333 lua_pop(l, 1);
7334 });
7335 }
7336
7337 /**
7338 * \brief Calls the on_closed() method of a Lua door.
7339 *
7340 * Does nothing if the method is not defined.
7341 *
7342 * \param door A door.
7343 */
door_on_closed(Door & door)7344 void LuaContext::door_on_closed(Door& door) {
7345
7346 if (!userdata_has_field(door, "on_closed")) {
7347 return;
7348 }
7349 run_on_main([this, &door](lua_State* l){
7350 push_door(l, door);
7351 on_closed();
7352 lua_pop(l, 1);
7353 });
7354 }
7355
7356 /**
7357 * \brief Calls the on_buying() method of a Lua shop treasure.
7358 *
7359 * Does nothing if the method is not defined.
7360 *
7361 * \param shop_treasure A shop treasure.
7362 * \return \c true if the player is allowed to buy the treasure.
7363 */
shop_treasure_on_buying(ShopTreasure & shop_treasure)7364 bool LuaContext::shop_treasure_on_buying(ShopTreasure& shop_treasure) {
7365
7366 if (!userdata_has_field(shop_treasure, "on_buying")) {
7367 return true;
7368 }
7369
7370 //TODO make this on main
7371 check_callback_thread();
7372
7373 push_shop_treasure(current_l, shop_treasure);
7374 bool result = on_buying();
7375 lua_pop(current_l, 1);
7376 return result;
7377 }
7378
7379 /**
7380 * \brief Calls the on_bought() method of a Lua shop treasure.
7381 *
7382 * Does nothing if the method is not defined.
7383 *
7384 * \param shop_treasure A shop treasure.
7385 */
shop_treasure_on_bought(ShopTreasure & shop_treasure)7386 void LuaContext::shop_treasure_on_bought(ShopTreasure& shop_treasure) {
7387
7388 if (!userdata_has_field(shop_treasure, "on_bought")) {
7389 return;
7390 }
7391
7392 run_on_main([this, &shop_treasure](lua_State* l){
7393 push_shop_treasure(l, shop_treasure);
7394 on_bought();
7395 lua_pop(l, 1);
7396 });
7397 }
7398
7399 /**
7400 * \brief Calls the on_looked() method of a Lua destructible.
7401 *
7402 * Does nothing if the method is not defined.
7403 *
7404 * \param destructible A destructible object.
7405 */
destructible_on_looked(Destructible & destructible)7406 void LuaContext::destructible_on_looked(Destructible& destructible) {
7407
7408 if (!userdata_has_field(destructible, "on_looked")) {
7409 return;
7410 }
7411 run_on_main([this, &destructible](lua_State* l){
7412 push_destructible(l, destructible);
7413 on_looked();
7414 lua_pop(l, 1);
7415 });
7416 }
7417
7418 /**
7419 * \brief Calls the on_cut() method of a Lua destructible.
7420 *
7421 * Does nothing if the method is not defined.
7422 *
7423 * \param destructible A destructible object.
7424 */
destructible_on_cut(Destructible & destructible)7425 void LuaContext::destructible_on_cut(Destructible& destructible) {
7426
7427 if (!userdata_has_field(destructible, "on_cut")) {
7428 return;
7429 }
7430 run_on_main([this, &destructible](lua_State* l){
7431 push_destructible(l, destructible);
7432 on_cut();
7433 lua_pop(l, 1);
7434 });
7435 }
7436
7437 /**
7438 * \brief Calls the on_exploded() method of a Lua destructible.
7439 *
7440 * Does nothing if the method is not defined.
7441 *
7442 * \param destructible A destructible object.
7443 */
destructible_on_exploded(Destructible & destructible)7444 void LuaContext::destructible_on_exploded(Destructible& destructible) {
7445
7446 if (!userdata_has_field(destructible, "on_exploded")) {
7447 return;
7448 }
7449 run_on_main([this, &destructible](lua_State* l){
7450 push_destructible(l, destructible);
7451 on_exploded();
7452 lua_pop(l, 1);
7453 });
7454 }
7455
7456 /**
7457 * \brief Calls the on_regenerating() method of a Lua destructible.
7458 *
7459 * Does nothing if the method is not defined.
7460 *
7461 * \param destructible A destructible object.
7462 */
destructible_on_regenerating(Destructible & destructible)7463 void LuaContext::destructible_on_regenerating(Destructible& destructible) {
7464
7465 if (!userdata_has_field(destructible, "on_regenerating")) {
7466 return;
7467 }
7468
7469 run_on_main([this, &destructible](lua_State* l){
7470 push_destructible(l, destructible);
7471 on_regenerating();
7472 lua_pop(l, 1);
7473 });
7474 }
7475
7476 /**
7477 * \brief Calls the on_restarted() method of a Lua enemy if it is defined.
7478 *
7479 * Also stops timers associated to the entity.
7480 *
7481 * \param enemy An enemy.
7482 */
enemy_on_restarted(Enemy & enemy)7483 void LuaContext::enemy_on_restarted(Enemy& enemy) {
7484 run_on_main([this, &enemy](lua_State* l){
7485 push_enemy(l, enemy);
7486 remove_timers(-1); // Stop timers associated to this enemy.
7487 if (userdata_has_field(enemy, "on_restarted")) {
7488 on_restarted();
7489 }
7490 lua_pop(l, 1);
7491 });
7492 }
7493
7494 /**
7495 * \brief Calls the on_collision_enemy() method of a Lua enemy.
7496 *
7497 * Does nothing if the method is not defined.
7498 *
7499 * \param enemy An enemy.
7500 * \param other_enemy Another enemy colliding with the first one.
7501 * \param other_sprite Colliding sprite of the other enemy.
7502 * \param this_sprite Colliding sprite of the first enemy.
7503 */
enemy_on_collision_enemy(Enemy & enemy,Enemy & other_enemy,Sprite & other_sprite,Sprite & this_sprite)7504 void LuaContext::enemy_on_collision_enemy(Enemy& enemy,
7505 Enemy& other_enemy, Sprite& other_sprite, Sprite& this_sprite) {
7506
7507 if (!userdata_has_field(enemy, "on_collision_enemy")) {
7508 return;
7509 }
7510 run_on_main([&](lua_State* l){
7511 push_enemy(l, enemy);
7512 on_collision_enemy(other_enemy, other_sprite, this_sprite);
7513 lua_pop(l, 1);
7514 });
7515 }
7516
7517 /**
7518 * \brief Calls the on_custom_attack_received() method of a Lua enemy.
7519 *
7520 * Does nothing if the method is not defined.
7521 *
7522 * \param enemy An enemy.
7523 * \param attack The attack received.
7524 * \param sprite The sprite that receives the attack if any.
7525 */
enemy_on_custom_attack_received(Enemy & enemy,EnemyAttack attack,Sprite * sprite)7526 void LuaContext::enemy_on_custom_attack_received(Enemy& enemy,
7527 EnemyAttack attack, Sprite* sprite) {
7528
7529 if (!userdata_has_field(enemy, "on_custom_attack_received")) {
7530 return;
7531 }
7532 run_on_main([&, attack, sprite](lua_State* l){
7533 push_enemy(l, enemy);
7534 on_custom_attack_received(attack, sprite);
7535 lua_pop(l, 1);
7536 });
7537 }
7538
7539 /**
7540 * \brief Calls the on_hurt_by_sword() method of a Lua enemy if it is defined.
7541 * \param enemy An enemy.
7542 * \param hero The hero whose sword is hitting the enemy.
7543 * \param enemy_sprite Sprite of the enemy that gets hits.
7544 * \return \c true if the method is defined.
7545 */
enemy_on_hurt_by_sword(Enemy & enemy,Hero & hero,Sprite & enemy_sprite)7546 bool LuaContext::enemy_on_hurt_by_sword(
7547 Enemy& enemy, Hero& hero, Sprite& enemy_sprite) {
7548
7549 if (!userdata_has_field(enemy, "on_hurt_by_sword")) {
7550 return false;
7551 }
7552
7553 //TODO make this on main
7554 check_callback_thread();
7555
7556 push_enemy(current_l, enemy);
7557 bool exists = on_hurt_by_sword(hero, enemy_sprite);
7558 lua_pop(current_l, 1);
7559 return exists;
7560 }
7561
7562 /**
7563 * \brief Calls the on_hurt() method of a Lua enemy if it is defined.
7564 *
7565 * Also stops timers associated to the enemy.
7566 *
7567 * \param enemy An enemy.
7568 * \param attack The attack received.
7569 */
enemy_on_hurt(Enemy & enemy,EnemyAttack attack)7570 void LuaContext::enemy_on_hurt(Enemy& enemy, EnemyAttack attack) {
7571
7572 run_on_main([this, &enemy, attack](lua_State* l){
7573 push_enemy(l, enemy);
7574 remove_timers(-1); // Stop timers associated to this enemy.
7575 if (userdata_has_field(enemy, "on_hurt")) {
7576 on_hurt(attack);
7577 }
7578 lua_pop(l, 1);
7579 });
7580 }
7581
7582 /**
7583 * \brief Calls the on_dying() method of a Lua enemy if it is defined.
7584 *
7585 * Also stops timers associated to the enemy.
7586 *
7587 * \param enemy An enemy.
7588 */
enemy_on_dying(Enemy & enemy)7589 void LuaContext::enemy_on_dying(Enemy& enemy) {
7590 run_on_main([this, &enemy](lua_State* l){
7591 push_enemy(l, enemy);
7592 remove_timers(-1); // Stop timers associated to this enemy.
7593 if (userdata_has_field(enemy, "on_dying")) {
7594 on_dying();
7595 }
7596 lua_pop(l, 1);
7597 });
7598 }
7599
7600 /**
7601 * \brief Calls the on_dead() method of a Lua enemy.
7602 *
7603 * Does nothing if the method is not defined.
7604 *
7605 * \param enemy An enemy.
7606 */
enemy_on_dead(Enemy & enemy)7607 void LuaContext::enemy_on_dead(Enemy& enemy) {
7608
7609 if (!userdata_has_field(enemy, "on_dead")) {
7610 return;
7611 }
7612 run_on_main([this, &enemy](lua_State* l){
7613 push_enemy(l, enemy);
7614 on_dead();
7615 lua_pop(l, 1);
7616 });
7617 }
7618
7619 /**
7620 * \brief Calls the on_immobilized() method of a Lua enemy if it is defined.
7621 *
7622 * Also stops timers associated to the enemy.
7623 *
7624 * \param enemy An enemy.
7625 */
enemy_on_immobilized(Enemy & enemy)7626 void LuaContext::enemy_on_immobilized(Enemy& enemy) {
7627 run_on_main([this, &enemy](lua_State* l){
7628 push_enemy(l, enemy);
7629 remove_timers(-1); // Stop timers associated to this enemy.
7630 if (userdata_has_field(enemy, "on_immobilized")) {
7631 on_immobilized();
7632 }
7633 lua_pop(l, 1);
7634 });
7635 }
7636
7637 /**
7638 * \brief Calls the on_attacking_hero() method of a Lua enemy.
7639 *
7640 * Does nothing if the method is not defined.
7641 *
7642 * \param enemy An enemy.
7643 * \param hero The hero attacked.
7644 * \param attacker_sprite Enemy's sprite that caused the collision or nullptr.
7645 * \return \c true if the method is defined.
7646 */
enemy_on_attacking_hero(Enemy & enemy,Hero & hero,Sprite * attacker_sprite)7647 bool LuaContext::enemy_on_attacking_hero(Enemy& enemy, Hero& hero, Sprite* attacker_sprite) {
7648
7649 if (!userdata_has_field(enemy, "on_attacking_hero")) {
7650 return false;
7651 }
7652
7653 // TODO make this on main
7654 check_callback_thread();
7655
7656 push_enemy(current_l, enemy);
7657 bool exists = on_attacking_hero(hero, attacker_sprite);
7658 lua_pop(current_l, 1);
7659 return exists;
7660 }
7661
7662 /**
7663 * \brief Calls the on_ground_below_changed() method of a Lua custom entity.
7664 *
7665 * Does nothing if the method is not defined.
7666 *
7667 * \param custom_entity A custom entity.
7668 * \param ground_below The new ground below this entity.
7669 */
custom_entity_on_ground_below_changed(CustomEntity & custom_entity,Ground ground_below)7670 void LuaContext::custom_entity_on_ground_below_changed(
7671 CustomEntity& custom_entity, Ground ground_below) {
7672
7673 if (!userdata_has_field(custom_entity, "on_ground_below_changed")) {
7674 return;
7675 }
7676
7677 run_on_main([this, &custom_entity, ground_below](lua_State* l) {
7678 push_custom_entity(l, custom_entity);
7679 on_ground_below_changed(ground_below);
7680 lua_pop(l, 1);
7681 });
7682 }
7683
7684 }
7685
7686