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/core/CurrentQuest.h"
18 #include "solarus/core/Game.h"
19 #include "solarus/core/Map.h"
20 #include "solarus/entities/EntityTypeInfo.h"
21 #include "solarus/entities/GroundInfo.h"
22 #include "solarus/lua/LuaContext.h"
23 #include "solarus/lua/LuaTools.h"
24 #include "solarus/hero/CustomState.h"
25
26 namespace Solarus {
27
28 /**
29 * Name of the Lua table representing the state module.
30 */
31 const std::string LuaContext::state_module_name = "sol.state";
32
33 /**
34 * \brief Initializes the state features provided to Lua.
35 */
register_state_module()36 void LuaContext::register_state_module() {
37
38 if (!CurrentQuest::is_format_at_least({ 1, 6 })) {
39 return;
40 }
41
42 // Functions of sol.state.
43 const std::vector<luaL_Reg> functions = {
44 { "create", state_api_create },
45 };
46
47 // Methods of the state type.
48 const std::vector<luaL_Reg> methods = {
49 { "get_description", state_api_get_description },
50 { "set_description", state_api_set_description },
51 { "get_entity", state_api_get_entity },
52 { "get_map", state_api_get_map },
53 { "get_game", state_api_get_game },
54 { "is_started", state_api_is_started },
55 { "is_visible", state_api_is_visible },
56 { "set_visible", state_api_set_visible },
57 { "get_draw_override", state_api_get_draw_override },
58 { "set_draw_override", state_api_set_draw_override },
59 { "get_can_control_direction", state_api_get_can_control_direction },
60 { "set_can_control_direction", state_api_set_can_control_direction },
61 { "get_can_control_movement", state_api_get_can_control_movement },
62 { "set_can_control_movement", state_api_set_can_control_movement },
63 { "set_can_traverse", state_api_set_can_traverse },
64 { "get_can_traverse_ground", state_api_get_can_traverse_ground },
65 { "set_can_traverse_ground", state_api_set_can_traverse_ground },
66 { "is_gravity_enabled", state_api_is_gravity_enabled },
67 { "set_gravity_enabled", state_api_set_gravity_enabled },
68 { "is_affected_by_ground", state_api_is_affected_by_ground },
69 { "set_affected_by_ground", state_api_set_affected_by_ground },
70 { "get_can_come_from_bad_ground", state_api_get_can_come_from_bad_ground },
71 { "set_can_come_from_bad_ground", state_api_set_can_come_from_bad_ground },
72 { "get_can_be_hurt", state_api_get_can_be_hurt },
73 { "set_can_be_hurt", state_api_set_can_be_hurt },
74 { "get_can_use_sword", state_api_get_can_use_sword },
75 { "set_can_use_sword", state_api_set_can_use_sword },
76 { "get_can_cut", state_api_get_can_cut },
77 { "set_can_cut", state_api_set_can_cut },
78 { "get_can_use_shield", state_api_get_can_use_shield },
79 { "set_can_use_shield", state_api_set_can_use_shield },
80 { "get_can_use_item", state_api_get_can_use_item },
81 { "set_can_use_item", state_api_set_can_use_item },
82 { "get_can_interact", state_api_get_can_interact },
83 { "set_can_interact", state_api_set_can_interact },
84 { "get_can_grab", state_api_get_can_grab },
85 { "set_can_grab", state_api_set_can_grab },
86 { "get_can_push", state_api_get_can_push },
87 { "set_can_push", state_api_set_can_push },
88 { "get_pushing_delay", state_api_get_pushing_delay },
89 { "set_pushing_delay", state_api_set_pushing_delay },
90 { "get_can_pick_treasure", state_api_get_can_pick_treasure },
91 { "set_can_pick_treasure", state_api_set_can_pick_treasure },
92 { "get_can_use_teletransporter", state_api_get_can_use_teletransporter },
93 { "set_can_use_teletransporter", state_api_set_can_use_teletransporter },
94 { "get_can_use_switch", state_api_get_can_use_switch },
95 { "set_can_use_switch", state_api_set_can_use_switch },
96 { "get_can_use_stream", state_api_get_can_use_stream },
97 { "set_can_use_stream", state_api_set_can_use_stream },
98 { "get_can_use_stairs", state_api_get_can_use_stairs },
99 { "set_can_use_stairs", state_api_set_can_use_stairs },
100 { "get_can_use_jumper", state_api_get_can_use_jumper },
101 { "set_can_use_jumper", state_api_set_can_use_jumper },
102 { "get_jumper_delay", state_api_get_jumper_delay },
103 { "set_jumper_delay", state_api_set_jumper_delay },
104 { "get_carried_object_action", state_api_get_carried_object_action },
105 { "set_carried_object_action", state_api_set_carried_object_action },
106 };
107
108 const std::vector<luaL_Reg> metamethods = {
109 { "__gc", userdata_meta_gc },
110 { "__newindex", userdata_meta_newindex_as_table },
111 { "__index", userdata_meta_index_as_table }
112 };
113
114 register_type(state_module_name, functions, methods, metamethods);
115 }
116
117 /**
118 * \brief Returns whether a value is a userdata of type state.
119 * \param l A Lua context.
120 * \param index An index in the stack.
121 * \return \c true if the value at this index is a state.
122 */
is_state(lua_State * l,int index)123 bool LuaContext::is_state(lua_State* l, int index) {
124 return is_userdata(l, index, state_module_name);
125 }
126
127 /**
128 * \brief Checks that the userdata at the specified index of the stack is a
129 * state and returns it.
130 * \param l a Lua context
131 * \param index An index in the stack.
132 * \return The state.
133 */
check_state(lua_State * l,int index)134 std::shared_ptr<CustomState> LuaContext::check_state(lua_State* l, int index) {
135 return std::static_pointer_cast<CustomState>(check_userdata(
136 l, index, state_module_name
137 ));
138 }
139
140 /**
141 * \brief Pushes a state userdata onto the stack.
142 * \param l A Lua context.
143 * \param state A state.
144 */
push_state(lua_State * l,CustomState & state)145 void LuaContext::push_state(lua_State* l, CustomState& state) {
146 push_userdata(l, state);
147 }
148
149 /**
150 * \brief Calls the draw override function of a custom state.
151 * \param draw_override The draw override function.
152 * \param state The state to draw.
153 * \param camera The camera where to draw the entity.
154 */
do_state_draw_override_function(const ScopedLuaRef & draw_override,CustomState & state,Camera & camera)155 void LuaContext::do_state_draw_override_function(
156 const ScopedLuaRef& draw_override,
157 CustomState& state,
158 Camera& camera
159 ) {
160 push_ref(current_l, draw_override);
161 push_state(current_l, state);
162 push_camera(current_l, camera);
163 call_function(2, 0, "state draw override");
164 }
165
166 /**
167 * \brief Calls the can-be-hurt function of a custom state.
168 * \param can_be_hurt The function to call.
169 * \param state The state to test.
170 * \param attacker Source of the attack or nullptr.
171 */
do_state_can_be_hurt_function(const ScopedLuaRef & can_be_hurt,CustomState & state,Entity * attacker)172 bool LuaContext::do_state_can_be_hurt_function(
173 const ScopedLuaRef& can_be_hurt,
174 CustomState& state,
175 Entity* attacker) {
176 push_ref(current_l, can_be_hurt);
177 push_state(current_l, state);
178 if (attacker == nullptr) {
179 lua_pushnil(current_l);
180 } else {
181 push_entity(current_l, *attacker);
182 }
183 if (!call_function(2, 1, "state can_be_hurt callback")) {
184 return true;
185 }
186 return LuaTools::opt_boolean(current_l, -1, "true");
187 }
188
189 /**
190 * \brief Calls the can-cut function of a custom state.
191 * \param can_cut The function to call.
192 * \param state The state to test.
193 * \param entity The entity to test or nullptr.
194 */
do_state_can_cut_function(const ScopedLuaRef & can_cut,CustomState & state,Entity * entity)195 bool LuaContext::do_state_can_cut_function(
196 const ScopedLuaRef& can_cut,
197 CustomState& state,
198 Entity* entity) {
199 push_ref(current_l, can_cut);
200 push_state(current_l, state);
201 if (entity == nullptr) {
202 lua_pushnil(current_l);
203 } else {
204 push_entity(current_l, *entity);
205 }
206 if (!call_function(2, 1, "state can_cut callback")) {
207 return true;
208 }
209 return LuaTools::opt_boolean(current_l, -1, "true");
210 }
211
212 /**
213 * \brief Implementation of sol.state.create().
214 * \param l The Lua context that is calling this function.
215 * \return Number of values to return to Lua.
216 */
state_api_create(lua_State * l)217 int LuaContext::state_api_create(lua_State* l) {
218
219 return state_boundary_handle(l, [&] {
220 const std::string& description = LuaTools::opt_string(l, 1, "");
221
222 std::shared_ptr<CustomState> state = std::make_shared<CustomState>(get(), description);
223
224 push_state(l, *state);
225 return 1;
226 });
227 }
228
229 /**
230 * \brief Implementation of state:get_description().
231 * \param l The Lua context that is calling this function.
232 * \return Number of values to return to Lua.
233 */
state_api_get_description(lua_State * l)234 int LuaContext::state_api_get_description(lua_State* l) {
235
236 return state_boundary_handle(l, [&] {
237 const CustomState& state = *check_state(l, 1);
238
239 const std::string& description = state.get_description();
240 if (description.empty()) {
241 lua_pushnil(l);
242 }
243 else {
244 push_string(l, description);
245 }
246 return 1;
247 });
248 }
249
250 /**
251 * \brief Implementation of state:set_description().
252 * \param l The Lua context that is calling this function.
253 * \return Number of values to return to Lua.
254 */
state_api_set_description(lua_State * l)255 int LuaContext::state_api_set_description(lua_State* l) {
256
257 return state_boundary_handle(l, [&] {
258 CustomState& state = *check_state(l, 1);
259 std::string description;
260 if (lua_isstring(l, 2)) {
261 description = LuaTools::check_string(l, 2);
262 }
263 else if (!lua_isnil(l, 2)) {
264 LuaTools::type_error(l, 2, "string or nil");
265 }
266
267 state.set_description(description);
268
269 return 0;
270 });
271 }
272
273 /**
274 * \brief Implementation of state:get_entity().
275 * \param l The Lua context that is calling this function.
276 * \return Number of values to return to Lua.
277 */
state_api_get_entity(lua_State * l)278 int LuaContext::state_api_get_entity(lua_State* l) {
279
280 return state_boundary_handle(l, [&] {
281 CustomState& state = *check_state(l, 1);
282
283 if (!state.has_entity()) {
284 lua_pushnil(l);
285 }
286 else {
287 Entity& entity = state.get_entity();
288 push_entity(l, entity);
289 }
290 return 1;
291 });
292 }
293
294 /**
295 * \brief Implementation of state:get_map().
296 * \param l The Lua context that is calling this function.
297 * \return Number of values to return to Lua.
298 */
state_api_get_map(lua_State * l)299 int LuaContext::state_api_get_map(lua_State* l) {
300
301 return state_boundary_handle(l, [&] {
302 CustomState& state = *check_state(l, 1);
303
304 if (!state.has_entity()) {
305 lua_pushnil(l);
306 }
307 else {
308 Entity& entity = state.get_entity();
309 if (!entity.is_on_map()) {
310 lua_pushnil(l);
311 }
312 else {
313 push_map(l, entity.get_map());
314 }
315 }
316 return 1;
317 });
318 }
319
320 /**
321 * \brief Implementation of state:get_game().
322 * \param l The Lua context that is calling this function.
323 * \return Number of values to return to Lua.
324 */
state_api_get_game(lua_State * l)325 int LuaContext::state_api_get_game(lua_State* l) {
326
327 return state_boundary_handle(l, [&] {
328 CustomState& state = *check_state(l, 1);
329
330 if (!state.has_entity()) {
331 lua_pushnil(l);
332 }
333 else {
334 Entity& entity = state.get_entity();
335 if (!entity.is_on_map()) {
336 lua_pushnil(l);
337 }
338 else {
339 Map& map = entity.get_map();
340 if (!map.is_game_running()) {
341 lua_pushnil(l);
342 }
343 else {
344 push_game(l, map.get_game().get_savegame());
345 }
346 }
347 }
348 return 1;
349 });
350 }
351
352 /**
353 * \brief Implementation of state:is_started().
354 * \param l The Lua context that is calling this function.
355 * \return Number of values to return to Lua.
356 */
state_api_is_started(lua_State * l)357 int LuaContext::state_api_is_started(lua_State* l) {
358
359 return state_boundary_handle(l, [&] {
360 const CustomState& state = *check_state(l, 1);
361
362 lua_pushboolean(l, state.is_current_state());
363 return 1;
364 });
365 }
366
367 /**
368 * \brief Implementation of state:is_visible().
369 * \param l The Lua context that is calling this function.
370 * \return Number of values to return to Lua.
371 */
state_api_is_visible(lua_State * l)372 int LuaContext::state_api_is_visible(lua_State* l) {
373
374 return state_boundary_handle(l, [&] {
375 const CustomState& state = *check_state(l, 1);
376
377 lua_pushboolean(l, state.is_visible());
378 return 1;
379 });
380 }
381
382 /**
383 * \brief Implementation of state:set_visible().
384 * \param l The Lua context that is calling this function.
385 * \return Number of values to return to Lua.
386 */
state_api_set_visible(lua_State * l)387 int LuaContext::state_api_set_visible(lua_State* l) {
388
389 return LuaTools::exception_boundary_handle(l, [&] {
390 CustomState& state = *check_state(l, 1);
391 bool visible = LuaTools::opt_boolean(l, 2, true);
392
393 state.set_visible(visible);
394
395 return 0;
396 });
397 }
398
399 /**
400 * \brief Implementation of state:get_can_control_direction().
401 * \param l The Lua context that is calling this function.
402 * \return Number of values to return to Lua.
403 */
state_api_get_can_control_direction(lua_State * l)404 int LuaContext::state_api_get_can_control_direction(lua_State* l) {
405
406 return state_boundary_handle(l, [&] {
407 const CustomState& state = *check_state(l, 1);
408
409 lua_pushboolean(l, state.get_can_control_direction());
410 return 1;
411 });
412 }
413
414 /**
415 * \brief Implementation of state:set_can_control_direction().
416 * \param l The Lua context that is calling this function.
417 * \return Number of values to return to Lua.
418 */
state_api_set_can_control_direction(lua_State * l)419 int LuaContext::state_api_set_can_control_direction(lua_State* l) {
420
421 return state_boundary_handle(l, [&] {
422 CustomState& state = *check_state(l, 1);
423 bool can_control_direction = LuaTools::check_boolean(l, 2);
424
425 state.set_can_control_direction(can_control_direction);
426
427 return 0;
428 });
429 }
430
431 /**
432 * \brief Implementation of state:get_can_control_movement().
433 * \param l The Lua context that is calling this function.
434 * \return Number of values to return to Lua.
435 */
state_api_get_can_control_movement(lua_State * l)436 int LuaContext::state_api_get_can_control_movement(lua_State* l) {
437
438 return state_boundary_handle(l, [&] {
439 const CustomState& state = *check_state(l, 1);
440
441 lua_pushboolean(l, state.get_can_control_movement());
442 return 1;
443 });
444 }
445
446 /**
447 * \brief Implementation of state:set_can_control_movement().
448 * \param l The Lua context that is calling this function.
449 * \return Number of values to return to Lua.
450 */
state_api_set_can_control_movement(lua_State * l)451 int LuaContext::state_api_set_can_control_movement(lua_State* l) {
452
453 return state_boundary_handle(l, [&] {
454 CustomState& state = *check_state(l, 1);
455 bool can_control_movement = LuaTools::check_boolean(l, 2);
456
457 state.set_can_control_movement(can_control_movement);
458
459 return 0;
460 });
461 }
462
463 /**
464 * \brief Implementation of state:get_draw_override().
465 * \param l The Lua context that is calling this function.
466 * \return Number of values to return to Lua.
467 */
state_api_get_draw_override(lua_State * l)468 int LuaContext::state_api_get_draw_override(lua_State* l) {
469
470 return state_boundary_handle(l, [&] {
471 const CustomState& state = *check_state(l, 1);
472
473 ScopedLuaRef draw_override = state.get_draw_override();
474 if (draw_override.is_empty()) {
475 lua_pushnil(l);
476 }
477 else {
478 push_ref(l, draw_override);
479 }
480 return 1;
481 });
482 }
483
484 /**
485 * \brief Implementation of state:set_draw_override().
486 * \param l The Lua context that is calling this function.
487 * \return Number of values to return to Lua.
488 */
state_api_set_draw_override(lua_State * l)489 int LuaContext::state_api_set_draw_override(lua_State* l) {
490
491 return state_boundary_handle(l, [&] {
492 CustomState& state = *check_state(l, 1);
493 ScopedLuaRef draw_override;
494 if (lua_gettop(l) >= 2) {
495 if (lua_isfunction(l, 2)) {
496 draw_override = LuaTools::check_function(l, 2);
497 }
498 else if (!lua_isnil(l, 2)) {
499 LuaTools::type_error(l, 2, "function or nil");
500 }
501 }
502
503 state.set_draw_override(draw_override);
504
505 return 0;
506 });
507 }
508
509 /**
510 * \brief Implementation of state:set_can_traverse().
511 * \param l The Lua context that is calling this function.
512 * \return Number of values to return to Lua.
513 */
state_api_set_can_traverse(lua_State * l)514 int LuaContext::state_api_set_can_traverse(lua_State* l) {
515
516 return state_boundary_handle(l, [&] {
517 CustomState& state = *check_state(l, 1);
518
519 bool type_specific = false;
520 EntityType type = EntityType::TILE;
521 int index = 2;
522 if (lua_isstring(l, index)) {
523 ++index;
524 type_specific = true;
525 type = LuaTools::check_enum<EntityType>(
526 l, 2
527 );
528 }
529
530 if (lua_isnil(l, index)) {
531 // Reset the setting.
532 if (!type_specific) {
533 state.reset_can_traverse_entities();
534 }
535 else {
536 state.reset_can_traverse_entities(type);
537 }
538 }
539 else if (lua_isboolean(l, index)) {
540 // Boolean value.
541 bool traversable = lua_toboolean(l, index);
542 if (!type_specific) {
543 state.set_can_traverse_entities(traversable);
544 }
545 else {
546 state.set_can_traverse_entities(type, traversable);
547 }
548 }
549 else if (lua_isfunction(l, index)) {
550 // Custom boolean function.
551 const ScopedLuaRef& traversable_test_ref = LuaTools::check_function(l, index);
552 if (!type_specific) {
553 state.set_can_traverse_entities(traversable_test_ref);
554 }
555 else {
556 state.set_can_traverse_entities(type, traversable_test_ref);
557 }
558 }
559 else {
560 LuaTools::type_error(l, index, "boolean, function or nil");
561 }
562
563 return 0;
564 });
565 }
566
567 /**
568 * \brief Implementation of state:can_traverse_ground().
569 * \param l The Lua context that is calling this function.
570 * \return Number of values to return to Lua.
571 */
state_api_get_can_traverse_ground(lua_State * l)572 int LuaContext::state_api_get_can_traverse_ground(lua_State* l) {
573
574 return state_boundary_handle(l, [&] {
575 const CustomState& state = *check_state(l, 1);
576 Ground ground = LuaTools::check_enum<Ground>(l, 2);
577
578 bool traversable = state.get_can_traverse_ground(ground);
579
580 lua_pushboolean(l, traversable);
581 return 1;
582 });
583 }
584
585 /**
586 * \brief Implementation of state:set_can_traverse_ground().
587 * \param l The Lua context that is calling this function.
588 * \return Number of values to return to Lua.
589 */
state_api_set_can_traverse_ground(lua_State * l)590 int LuaContext::state_api_set_can_traverse_ground(lua_State* l) {
591
592 return state_boundary_handle(l, [&] {
593 CustomState& state = *check_state(l, 1);
594 Ground ground = LuaTools::check_enum<Ground>(l, 2);
595 bool traversable = LuaTools::check_boolean(l, 3);
596
597 state.set_can_traverse_ground(ground, traversable);
598
599 return 0;
600 });
601 }
602
603 /**
604 * \brief Implementation of state:is_gravity_enabled().
605 * \param l The Lua context that is calling this function.
606 * \return Number of values to return to Lua.
607 */
state_api_is_gravity_enabled(lua_State * l)608 int LuaContext::state_api_is_gravity_enabled(lua_State* l) {
609
610 return state_boundary_handle(l, [&] {
611 const CustomState& state = *check_state(l, 1);
612
613 lua_pushboolean(l, state.is_touching_ground());
614 return 1;
615 });
616 }
617
618 /**
619 * \brief Implementation of state:set_gravity_enabled().
620 * \param l The Lua context that is calling this function.
621 * \return Number of values to return to Lua.
622 */
state_api_set_gravity_enabled(lua_State * l)623 int LuaContext::state_api_set_gravity_enabled(lua_State* l) {
624
625 return state_boundary_handle(l, [&] {
626 CustomState& state = *check_state(l, 1);
627 bool gravity_enabled = LuaTools::check_boolean(l, 2);
628
629 state.set_touching_ground(gravity_enabled);
630
631 return 0;
632 });
633 }
634
635 /**
636 * \brief Implementation of state:is_affected_by_ground().
637 * \param l The Lua context that is calling this function.
638 * \return Number of values to return to Lua.
639 */
state_api_is_affected_by_ground(lua_State * l)640 int LuaContext::state_api_is_affected_by_ground(lua_State* l) {
641
642 return state_boundary_handle(l, [&] {
643 const CustomState& state = *check_state(l, 1);
644 Ground ground = LuaTools::check_enum<Ground>(l, 2);
645
646 lua_pushboolean(l, state.is_affected_by_ground(ground));
647 return 1;
648 });
649 }
650
651 /**
652 * \brief Implementation of state:set_affected_by_ground().
653 * \param l The Lua context that is calling this function.
654 * \return Number of values to return to Lua.
655 */
state_api_set_affected_by_ground(lua_State * l)656 int LuaContext::state_api_set_affected_by_ground(lua_State* l) {
657
658 return state_boundary_handle(l, [&] {
659 CustomState& state = *check_state(l, 1);
660 Ground ground = LuaTools::check_enum<Ground>(l, 2);
661 bool affected = LuaTools::opt_boolean(l, 3, true);
662
663 state.set_affected_by_ground(ground, affected);
664
665 return 0;
666 });
667 }
668
669 /**
670 * \brief Implementation of state:get_can_come_from_bad_ground().
671 * \param l The Lua context that is calling this function.
672 * \return Number of values to return to Lua.
673 */
state_api_get_can_come_from_bad_ground(lua_State * l)674 int LuaContext::state_api_get_can_come_from_bad_ground(lua_State* l) {
675
676 return state_boundary_handle(l, [&] {
677 const CustomState& state = *check_state(l, 1);
678
679 lua_pushboolean(l, state.get_can_come_from_bad_ground());
680 return 1;
681 });
682 }
683
684 /**
685 * \brief Implementation of state:set_can_come_from_bad_ground().
686 * \param l The Lua context that is calling this function.
687 * \return Number of values to return to Lua.
688 */
state_api_set_can_come_from_bad_ground(lua_State * l)689 int LuaContext::state_api_set_can_come_from_bad_ground(lua_State* l) {
690
691 return state_boundary_handle(l, [&] {
692 CustomState& state = *check_state(l, 1);
693 bool can_come_from_bad_ground = LuaTools::check_boolean(l, 2);
694
695 state.set_can_come_from_bad_ground(can_come_from_bad_ground);
696
697 return 0;
698 });
699 }
700
701 /**
702 * \brief Implementation of state:get_can_be_hurt().
703 * \param l The Lua context that is calling this function.
704 * \return Number of values to return to Lua.
705 */
state_api_get_can_be_hurt(lua_State * l)706 int LuaContext::state_api_get_can_be_hurt(lua_State* l) {
707
708 return state_boundary_handle(l, [&] {
709 CustomState& state = *check_state(l, 1);
710
711 lua_pushboolean(l, state.get_can_be_hurt(nullptr));
712 return 1;
713 });
714 }
715
716 /**
717 * \brief Implementation of state:set_can_be_hurt().
718 * \param l The Lua context that is calling this function.
719 * \return Number of values to return to Lua.
720 */
state_api_set_can_be_hurt(lua_State * l)721 int LuaContext::state_api_set_can_be_hurt(lua_State* l) {
722
723 return state_boundary_handle(l, [&] {
724 CustomState& state = *check_state(l, 1);
725
726 if (lua_isboolean(l, 2)) {
727 bool can_be_hurt = LuaTools::check_boolean(l, 2);
728 state.set_can_be_hurt(can_be_hurt);
729 }
730 else if (lua_isfunction(l, 2)) {
731 // Custom boolean function.
732 const ScopedLuaRef& can_be_hurt_callback = LuaTools::check_function(l, 2);
733 state.set_can_be_hurt(can_be_hurt_callback);
734 }
735 else {
736 LuaTools::arg_error(l, 2, "boolean or function");
737 }
738
739 return 0;
740 });
741 }
742
743 /**
744 * \brief Implementation of state:get_can_use_sword().
745 * \param l The Lua context that is calling this function.
746 * \return Number of values to return to Lua.
747 */
state_api_get_can_use_sword(lua_State * l)748 int LuaContext::state_api_get_can_use_sword(lua_State* l) {
749
750 return state_boundary_handle(l, [&] {
751 const CustomState& state = *check_state(l, 1);
752
753 lua_pushboolean(l, state.get_can_start_sword());
754 return 1;
755 });
756 }
757
758 /**
759 * \brief Implementation of state:set_can_use_sword().
760 * \param l The Lua context that is calling this function.
761 * \return Number of values to return to Lua.
762 */
state_api_set_can_use_sword(lua_State * l)763 int LuaContext::state_api_set_can_use_sword(lua_State* l) {
764
765 return state_boundary_handle(l, [&] {
766 CustomState& state = *check_state(l, 1);
767 bool can_use_sword = LuaTools::check_boolean(l, 2);
768
769 state.set_can_start_sword(can_use_sword);
770
771 return 0;
772 });
773 }
774
775 /**
776 * \brief Implementation of state:get_can_cut().
777 * \param l The Lua context that is calling this function.
778 * \return Number of values to return to Lua.
779 */
state_api_get_can_cut(lua_State * l)780 int LuaContext::state_api_get_can_cut(lua_State* l) {
781
782 return state_boundary_handle(l, [&] {
783 CustomState& state = *check_state(l, 1);
784
785 lua_pushboolean(l, state.get_can_cut(nullptr));
786 return 1;
787 });
788 }
789
790 /**
791 * \brief Implementation of state:set_can_cut().
792 * \param l The Lua context that is calling this function.
793 * \return Number of values to return to Lua.
794 */
state_api_set_can_cut(lua_State * l)795 int LuaContext::state_api_set_can_cut(lua_State* l) {
796
797 return state_boundary_handle(l, [&] {
798 CustomState& state = *check_state(l, 1);
799
800 if (lua_isboolean(l, 2)) {
801 bool can_cut = LuaTools::check_boolean(l, 2);
802 state.set_can_cut(can_cut);
803 }
804 else if (lua_isfunction(l, 2)) {
805 // Custom boolean function.
806 const ScopedLuaRef& can_cut_callback = LuaTools::check_function(l, 2);
807 state.set_can_cut(can_cut_callback);
808 }
809 else {
810 LuaTools::arg_error(l, 2, "boolean or function");
811 }
812
813 return 0;
814 });
815 }
816
817 /**
818 * \brief Implementation of state:get_can_use_shield().
819 * \param l The Lua context that is calling this function.
820 * \return Number of values to return to Lua.
821 */
state_api_get_can_use_shield(lua_State * l)822 int LuaContext::state_api_get_can_use_shield(lua_State* l) {
823
824 return state_boundary_handle(l, [&] {
825 const CustomState& state = *check_state(l, 1);
826
827 lua_pushboolean(l, state.get_can_use_shield());
828 return 1;
829 });
830 }
831
832 /**
833 * \brief Implementation of state:set_can_use_shield().
834 * \param l The Lua context that is calling this function.
835 * \return Number of values to return to Lua.
836 */
state_api_set_can_use_shield(lua_State * l)837 int LuaContext::state_api_set_can_use_shield(lua_State* l) {
838
839 return state_boundary_handle(l, [&] {
840 CustomState& state = *check_state(l, 1);
841 bool can_use_shield = LuaTools::check_boolean(l, 2);
842
843 state.set_can_use_shield(can_use_shield);
844
845 return 0;
846 });
847 }
848
849 /**
850 * \brief Implementation of state:get_can_use_item().
851 * \param l The Lua context that is calling this function.
852 * \return Number of values to return to Lua.
853 */
state_api_get_can_use_item(lua_State * l)854 int LuaContext::state_api_get_can_use_item(lua_State* l) {
855
856 return state_boundary_handle(l, [&] {
857 const CustomState& state = *check_state(l, 1);
858 std::string item_id;
859
860 if (!lua_isnone(l, 2)) {
861 item_id = LuaTools::check_string(l, 2);
862 if (!CurrentQuest::resource_exists(ResourceType::ITEM, item_id)) {
863 LuaTools::arg_error(l, 2, "No such item: '" + item_id + "'");
864 }
865 }
866
867 lua_pushboolean(l, state.get_can_start_item(item_id));
868 return 1;
869 });
870 }
871
872 /**
873 * \brief Implementation of state:set_can_use_item().
874 * \param l The Lua context that is calling this function.
875 * \return Number of values to return to Lua.
876 */
state_api_set_can_use_item(lua_State * l)877 int LuaContext::state_api_set_can_use_item(lua_State* l) {
878
879 return state_boundary_handle(l, [&] {
880 CustomState& state = *check_state(l, 1);
881 std::string item_id;
882 int index = 2;
883 if (lua_isstring(l, 2)) {
884 ++index;
885 item_id = LuaTools::check_string(l, 2);
886 if (!CurrentQuest::resource_exists(ResourceType::ITEM, item_id)) {
887 LuaTools::arg_error(l, 2, "No such item: '" + item_id + "'");
888 }
889 }
890 else if (!lua_isboolean(l, 2)) {
891 LuaTools::type_error(l, 2, "string or boolean");
892 }
893 bool can_use_item = LuaTools::check_boolean(l, index);
894
895 state.set_can_start_item(item_id, can_use_item);
896
897 return 0;
898 });
899 }
900
901 /**
902 * \brief Implementation of state:get_can_interact().
903 * \param l The Lua context that is calling this function.
904 * \return Number of values to return to Lua.
905 */
state_api_get_can_interact(lua_State * l)906 int LuaContext::state_api_get_can_interact(lua_State* l) {
907
908 return state_boundary_handle(l, [&] {
909 const CustomState& state = *check_state(l, 1);
910
911 lua_pushboolean(l, state.get_can_interact());
912 return 1;
913 });
914 }
915
916 /**
917 * \brief Implementation of state:set_can_interact().
918 * \param l The Lua context that is calling this function.
919 * \return Number of values to return to Lua.
920 */
state_api_set_can_interact(lua_State * l)921 int LuaContext::state_api_set_can_interact(lua_State* l) {
922
923 return state_boundary_handle(l, [&] {
924 CustomState& state = *check_state(l, 1);
925 bool can_interact = LuaTools::check_boolean(l, 2);
926
927 state.set_can_interact(can_interact);
928
929 return 0;
930 });
931 }
932
933 /**
934 * \brief Implementation of state:get_can_grab().
935 * \param l The Lua context that is calling this function.
936 * \return Number of values to return to Lua.
937 */
state_api_get_can_grab(lua_State * l)938 int LuaContext::state_api_get_can_grab(lua_State* l) {
939
940 return state_boundary_handle(l, [&] {
941 const CustomState& state = *check_state(l, 1);
942
943 lua_pushboolean(l, state.get_can_grab());
944 return 1;
945 });
946 }
947
948 /**
949 * \brief Implementation of state:set_can_grab().
950 * \param l The Lua context that is calling this function.
951 * \return Number of values to return to Lua.
952 */
state_api_set_can_grab(lua_State * l)953 int LuaContext::state_api_set_can_grab(lua_State* l) {
954
955 return state_boundary_handle(l, [&] {
956 CustomState& state = *check_state(l, 1);
957 bool can_grab = LuaTools::check_boolean(l, 2);
958
959 state.set_can_grab(can_grab);
960
961 return 0;
962 });
963 }
964
965 /**
966 * \brief Implementation of state:get_can_push().
967 * \param l The Lua context that is calling this function.
968 * \return Number of values to return to Lua.
969 */
state_api_get_can_push(lua_State * l)970 int LuaContext::state_api_get_can_push(lua_State* l) {
971
972 return state_boundary_handle(l, [&] {
973 const CustomState& state = *check_state(l, 1);
974
975 lua_pushboolean(l, state.get_can_push());
976 return 1;
977 });
978 }
979
980 /**
981 * \brief Implementation of state:set_can_push().
982 * \param l The Lua context that is calling this function.
983 * \return Number of values to return to Lua.
984 */
state_api_set_can_push(lua_State * l)985 int LuaContext::state_api_set_can_push(lua_State* l) {
986
987 return state_boundary_handle(l, [&] {
988 CustomState& state = *check_state(l, 1);
989 bool can_push = LuaTools::check_boolean(l, 2);
990
991 state.set_can_push(can_push);
992
993 return 0;
994 });
995 }
996
997 /**
998 * \brief Implementation of state:get_pushing_delay().
999 * \param l The Lua context that is calling this function.
1000 * \return Number of values to return to Lua.
1001 */
state_api_get_pushing_delay(lua_State * l)1002 int LuaContext::state_api_get_pushing_delay(lua_State* l) {
1003
1004 return state_boundary_handle(l, [&] {
1005 const CustomState& state = *check_state(l, 1);
1006
1007 lua_pushinteger(l, state.get_pushing_delay());
1008 return 1;
1009 });
1010 }
1011
1012 /**
1013 * \brief Implementation of state:set_pushing_delay().
1014 * \param l The Lua context that is calling this function.
1015 * \return Number of values to return to Lua.
1016 */
state_api_set_pushing_delay(lua_State * l)1017 int LuaContext::state_api_set_pushing_delay(lua_State* l) {
1018
1019 return state_boundary_handle(l, [&] {
1020 CustomState& state = *check_state(l, 1);
1021 int pushing_delay = LuaTools::check_int(l, 2);
1022
1023 if (pushing_delay < 0) {
1024 LuaTools::arg_error(l, 2, "Pushing delay should be positive or zero");
1025 }
1026 state.set_pushing_delay(pushing_delay);
1027
1028 return 0;
1029 });
1030 }
1031
1032 /**
1033 * \brief Implementation of state:get_can_pick_treasure().
1034 * \param l The Lua context that is calling this function.
1035 * \return Number of values to return to Lua.
1036 */
state_api_get_can_pick_treasure(lua_State * l)1037 int LuaContext::state_api_get_can_pick_treasure(lua_State* l) {
1038
1039 return state_boundary_handle(l, [&] {
1040 const CustomState& state = *check_state(l, 1);
1041
1042 lua_pushboolean(l, state.get_can_pick_treasure());
1043 return 1;
1044 });
1045 }
1046
1047 /**
1048 * \brief Implementation of state:set_can_pick_treasure().
1049 * \param l The Lua context that is calling this function.
1050 * \return Number of values to return to Lua.
1051 */
state_api_set_can_pick_treasure(lua_State * l)1052 int LuaContext::state_api_set_can_pick_treasure(lua_State* l) {
1053
1054 return state_boundary_handle(l, [&] {
1055 CustomState& state = *check_state(l, 1);
1056 bool can_pick_treasure = LuaTools::check_boolean(l, 2);
1057
1058 state.set_can_pick_treasure(can_pick_treasure);
1059
1060 return 0;
1061 });
1062 }
1063
1064 /**
1065 * \brief Implementation of state:get_can_use_teletransporter().
1066 * \param l The Lua context that is calling this function.
1067 * \return Number of values to return to Lua.
1068 */
state_api_get_can_use_teletransporter(lua_State * l)1069 int LuaContext::state_api_get_can_use_teletransporter(lua_State* l) {
1070
1071 return state_boundary_handle(l, [&] {
1072 const CustomState& state = *check_state(l, 1);
1073
1074 lua_pushboolean(l, state.get_can_take_teletransporter());
1075 return 1;
1076 });
1077 }
1078
1079 /**
1080 * \brief Implementation of state:set_can_use_teletransporter().
1081 * \param l The Lua context that is calling this function.
1082 * \return Number of values to return to Lua.
1083 */
state_api_set_can_use_teletransporter(lua_State * l)1084 int LuaContext::state_api_set_can_use_teletransporter(lua_State* l) {
1085
1086 return state_boundary_handle(l, [&] {
1087 CustomState& state = *check_state(l, 1);
1088 bool can_take_teletransporter = LuaTools::check_boolean(l, 2);
1089
1090 state.set_can_take_teletransporter(can_take_teletransporter);
1091
1092 return 0;
1093 });
1094 }
1095
1096 /**
1097 * \brief Implementation of state:get_can_use_switch().
1098 * \param l The Lua context that is calling this function.
1099 * \return Number of values to return to Lua.
1100 */
state_api_get_can_use_switch(lua_State * l)1101 int LuaContext::state_api_get_can_use_switch(lua_State* l) {
1102
1103 return state_boundary_handle(l, [&] {
1104 const CustomState& state = *check_state(l, 1);
1105
1106 lua_pushboolean(l, state.get_can_take_switch());
1107 return 1;
1108 });
1109 }
1110
1111 /**
1112 * \brief Implementation of state:set_can_use_switch().
1113 * \param l The Lua context that is calling this function.
1114 * \return Number of values to return to Lua.
1115 */
state_api_set_can_use_switch(lua_State * l)1116 int LuaContext::state_api_set_can_use_switch(lua_State* l) {
1117
1118 return state_boundary_handle(l, [&] {
1119 CustomState& state = *check_state(l, 1);
1120 bool can_take_switch = LuaTools::check_boolean(l, 2);
1121
1122 state.set_can_take_switch(can_take_switch);
1123
1124 return 0;
1125 });
1126 }
1127
1128 /**
1129 * \brief Implementation of state:get_can_use_stream().
1130 * \param l The Lua context that is calling this function.
1131 * \return Number of values to return to Lua.
1132 */
state_api_get_can_use_stream(lua_State * l)1133 int LuaContext::state_api_get_can_use_stream(lua_State* l) {
1134
1135 return state_boundary_handle(l, [&] {
1136 const CustomState& state = *check_state(l, 1);
1137
1138 lua_pushboolean(l, state.get_can_take_stream());
1139 return 1;
1140 });
1141 }
1142
1143 /**
1144 * \brief Implementation of state:set_can_use_stream().
1145 * \param l The Lua context that is calling this function.
1146 * \return Number of values to return to Lua.
1147 */
state_api_set_can_use_stream(lua_State * l)1148 int LuaContext::state_api_set_can_use_stream(lua_State* l) {
1149
1150 return state_boundary_handle(l, [&] {
1151 CustomState& state = *check_state(l, 1);
1152 bool can_take_stream = LuaTools::check_boolean(l, 2);
1153
1154 state.set_can_take_stream(can_take_stream);
1155
1156 return 0;
1157 });
1158 }
1159
1160 /**
1161 * \brief Implementation of state:get_can_use_stairs().
1162 * \param l The Lua context that is calling this function.
1163 * \return Number of values to return to Lua.
1164 */
state_api_get_can_use_stairs(lua_State * l)1165 int LuaContext::state_api_get_can_use_stairs(lua_State* l) {
1166
1167 return state_boundary_handle(l, [&] {
1168 const CustomState& state = *check_state(l, 1);
1169
1170 lua_pushboolean(l, state.get_can_take_stairs());
1171 return 1;
1172 });
1173 }
1174
1175 /**
1176 * \brief Implementation of state:set_can_use_stairs().
1177 * \param l The Lua context that is calling this function.
1178 * \return Number of values to return to Lua.
1179 */
state_api_set_can_use_stairs(lua_State * l)1180 int LuaContext::state_api_set_can_use_stairs(lua_State* l) {
1181
1182 return state_boundary_handle(l, [&] {
1183 CustomState& state = *check_state(l, 1);
1184 bool can_take_stairs = LuaTools::check_boolean(l, 2);
1185
1186 state.set_can_take_stairs(can_take_stairs);
1187
1188 return 0;
1189 });
1190 }
1191
1192 /**
1193 * \brief Implementation of state:get_can_use_jumper().
1194 * \param l The Lua context that is calling this function.
1195 * \return Number of values to return to Lua.
1196 */
state_api_get_can_use_jumper(lua_State * l)1197 int LuaContext::state_api_get_can_use_jumper(lua_State* l) {
1198
1199 return state_boundary_handle(l, [&] {
1200 const CustomState& state = *check_state(l, 1);
1201
1202 lua_pushboolean(l, state.get_can_take_jumper());
1203 return 1;
1204 });
1205 }
1206
1207 /**
1208 * \brief Implementation of state:set_can_use_jumper().
1209 * \param l The Lua context that is calling this function.
1210 * \return Number of values to return to Lua.
1211 */
state_api_set_can_use_jumper(lua_State * l)1212 int LuaContext::state_api_set_can_use_jumper(lua_State* l) {
1213
1214 return state_boundary_handle(l, [&] {
1215 CustomState& state = *check_state(l, 1);
1216 bool can_take_jumper = LuaTools::check_boolean(l, 2);
1217
1218 state.set_can_take_jumper(can_take_jumper);
1219
1220 return 0;
1221 });
1222 }
1223
1224 /**
1225 * \brief Implementation of state:get_jumper_delay().
1226 * \param l The Lua context that is calling this function.
1227 * \return Number of values to return to Lua.
1228 */
state_api_get_jumper_delay(lua_State * l)1229 int LuaContext::state_api_get_jumper_delay(lua_State* l) {
1230
1231 return state_boundary_handle(l, [&] {
1232 const CustomState& state = *check_state(l, 1);
1233
1234 lua_pushinteger(l, state.get_jumper_delay());
1235 return 1;
1236 });
1237 }
1238
1239 /**
1240 * \brief Implementation of state:set_jumper_delay().
1241 * \param l The Lua context that is calling this function.
1242 * \return Number of values to return to Lua.
1243 */
state_api_set_jumper_delay(lua_State * l)1244 int LuaContext::state_api_set_jumper_delay(lua_State* l) {
1245
1246 return state_boundary_handle(l, [&] {
1247 CustomState& state = *check_state(l, 1);
1248 int jumper_delay = LuaTools::check_int(l, 2);
1249
1250 if (jumper_delay < 0) {
1251 LuaTools::arg_error(l, 2, "Jumper delay should be positive or zero");
1252 }
1253 state.set_jumper_delay(jumper_delay);
1254
1255 return 0;
1256 });
1257 }
1258
1259 /**
1260 * \brief Implementation of state:get_carried_object_action().
1261 * \param l The Lua context that is calling this function.
1262 * \return Number of values to return to Lua.
1263 */
state_api_get_carried_object_action(lua_State * l)1264 int LuaContext::state_api_get_carried_object_action(lua_State* l) {
1265
1266 return state_boundary_handle(l, [&] {
1267 const CustomState& state = *check_state(l, 1);
1268
1269 CarriedObject::Behavior behavior = state.get_previous_carried_object_behavior();
1270 push_string(l, enum_to_name(behavior));
1271 return 1;
1272 });
1273 }
1274
1275 /**
1276 * \brief Implementation of state:set_carried_object_action().
1277 * \param l The Lua context that is calling this function.
1278 * \return Number of values to return to Lua.
1279 */
state_api_set_carried_object_action(lua_State * l)1280 int LuaContext::state_api_set_carried_object_action(lua_State* l) {
1281
1282 return state_boundary_handle(l, [&] {
1283 CustomState& state = *check_state(l, 1);
1284 CarriedObject::Behavior behavior = LuaTools::check_enum<CarriedObject::Behavior>(l, 2);
1285
1286 state.set_previous_carried_object_behavior(behavior);
1287 return 0;
1288 });
1289 }
1290
1291 /**
1292 * \brief Calls the on_started() method of a Lua custom state.
1293 *
1294 * Does nothing if the method is not defined.
1295 *
1296 * \param state The custom state that has just started.
1297 * \param previous_state_name Name of the previous state.
1298 * \param previous_state The previous state object if it was a custom one.
1299 */
state_on_started(CustomState & state,const std::string & previous_state_name,CustomState * previous_state)1300 void LuaContext::state_on_started(
1301 CustomState& state,
1302 const std::string& previous_state_name,
1303 CustomState* previous_state) {
1304
1305 if (!userdata_has_field(state, "on_started")) {
1306 return;
1307 }
1308
1309 push_state(current_l, state);
1310 on_started(previous_state_name, previous_state);
1311 lua_pop(current_l, 1);
1312 }
1313
1314 /**
1315 * \brief Calls the on_finished() method of a custom state if it is defined.
1316 *
1317 * Also stops timers associated to the state.
1318 *
1319 * \param state The custom state that has just finished.
1320 * \param next_state_name Name of the next state.
1321 * \param next_state The next state object if it is a custom one.
1322 */
state_on_finished(CustomState & state,const std::string & next_state_name,CustomState * next_state)1323 void LuaContext::state_on_finished(
1324 CustomState& state,
1325 const std::string& next_state_name,
1326 CustomState* next_state) {
1327
1328 run_on_main([this, &state, next_state_name, next_state](lua_State* l) {
1329 push_state(l, state);
1330 if (userdata_has_field(state, "on_finished")) {
1331 on_finished(next_state_name, next_state);
1332 }
1333 remove_timers(-1); // Stop timers associated to this state.
1334 lua_pop(current_l, 1);
1335 });
1336 }
1337
1338 /**
1339 * \brief Calls the on_update() method of a Lua custom state.
1340 *
1341 * Does nothing if the method is not defined.
1342 *
1343 * \param state A custom state.
1344 */
state_on_update(CustomState & state)1345 void LuaContext::state_on_update(CustomState& state) {
1346
1347 if (!userdata_has_field(state, "on_update")) {
1348 return;
1349 }
1350
1351 run_on_main([this, &state](lua_State* l) {
1352 push_state(l, state);
1353 on_update();
1354 lua_pop(l, 1);
1355 });
1356 }
1357
1358 /**
1359 * \brief Calls the on_suspended() method of a Lua custom state.
1360 *
1361 * Does nothing if the method is not defined.
1362 *
1363 * \param state A custom state.
1364 * \param suspended \c true if the state is suspended.
1365 */
state_on_suspended(CustomState & state,bool suspended)1366 void LuaContext::state_on_suspended(CustomState& state, bool suspended) {
1367
1368 if (!userdata_has_field(state, "on_suspended")) {
1369 return;
1370 }
1371 run_on_main([this, &state, suspended](lua_State* l) {
1372 push_state(l, state);
1373 on_suspended(suspended);
1374 lua_pop(l, 1);
1375 });
1376 }
1377
1378 /**
1379 * \brief Calls the on_pre_draw() method of a Lua custom state.
1380 *
1381 * Does nothing if the method is not defined.
1382 *
1383 * \param state A custom state.
1384 * \param camera The camera where to draw the entity.
1385 */
state_on_pre_draw(CustomState & state,Camera & camera)1386 void LuaContext::state_on_pre_draw(CustomState& state, Camera& camera) {
1387
1388 if (!userdata_has_field(state, "on_pre_draw")) {
1389 return;
1390 }
1391 run_on_main([this, &state, &camera](lua_State* l) {
1392 push_state(l, state);
1393 on_pre_draw(camera);
1394 lua_pop(l, 1);
1395 });
1396 }
1397
1398 /**
1399 * \brief Calls the on_post_draw() method of a Lua custom state.
1400 *
1401 * Does nothing if the method is not defined.
1402 *
1403 * \param state A custom state.
1404 * \param camera The camera where to draw the entity.
1405 */
state_on_post_draw(CustomState & state,Camera & camera)1406 void LuaContext::state_on_post_draw(CustomState& state, Camera& camera) {
1407
1408 if (!userdata_has_field(state, "on_post_draw")) {
1409 return;
1410 }
1411 run_on_main([this, &state, &camera](lua_State* l) {
1412 push_state(l, state);
1413 on_post_draw(camera);
1414 lua_pop(l, 1);
1415 });
1416 }
1417
1418 /**
1419 * \brief Calls the on_map_started() method of a Lua custom state.
1420 *
1421 * Does nothing if the method is not defined.
1422 *
1423 * \param state A custom state.
1424 * \param map The map.
1425 * \param destination Destination entity where the hero is placed or nullptr.
1426 */
state_on_map_started(CustomState & state,Map & map,const std::shared_ptr<Destination> & destination)1427 void LuaContext::state_on_map_started(
1428 CustomState& state, Map& map, const std::shared_ptr<Destination>& destination) {
1429
1430 if (!userdata_has_field(state, "on_map_started")) {
1431 return;
1432 }
1433 run_on_main([this, &state, &map, &destination](lua_State* l) {
1434 push_state(l, state);
1435 on_map_started(map, destination);
1436 lua_pop(l, 1);
1437 });
1438 }
1439
1440 /**
1441 * \brief Calls the on_map_opening_transition_finished() method of a Lua custom state.
1442 *
1443 * Does nothing if the method is not defined.
1444 *
1445 * \param state A custom state.
1446 * \param map The map.
1447 * \param destination Destination entity where the hero is placed or nullptr.
1448 */
state_on_map_opening_transition_finished(CustomState & state,Map & map,const std::shared_ptr<Destination> & destination)1449 void LuaContext::state_on_map_opening_transition_finished(
1450 CustomState& state, Map& map, const std::shared_ptr<Destination>& destination) {
1451
1452 if (!userdata_has_field(state, "on_map_opening_transition_finished")) {
1453 return;
1454 }
1455 run_on_main([this, &state, &map, &destination](lua_State* l) {
1456 push_state(l, state);
1457 on_map_opening_transition_finished(map, destination);
1458 lua_pop(l, 1);
1459 });
1460 }
1461
1462 /**
1463 * \brief Calls the on_map_finished() method of a Lua custom state.
1464 *
1465 * Does nothing if the method is not defined.
1466 *
1467 * \param state A custom state.
1468 */
state_on_map_finished(CustomState & state)1469 void LuaContext::state_on_map_finished(CustomState& state) {
1470
1471 if (!userdata_has_field(state, "on_map_finished")) {
1472 return;
1473 }
1474 run_on_main([this, &state](lua_State* l) {
1475 push_state(l, state);
1476 on_map_finished();
1477 lua_pop(l, 1);
1478 });
1479 }
1480
1481 /**
1482 * \brief Calls the on_position_changed() method of a Lua custom state.
1483 *
1484 * Does nothing if the method is not defined.
1485 *
1486 * \param state A custom state.
1487 * \param xy The new coordinates.
1488 * \param layer The new layer.
1489 */
state_on_position_changed(CustomState & state,const Point & xy,int layer)1490 void LuaContext::state_on_position_changed(CustomState& state, const Point& xy, int layer) {
1491
1492 if (!userdata_has_field(state, "on_position_changed")) {
1493 return;
1494 }
1495 run_on_main([this, &state, xy, layer](lua_State* l) {
1496 push_state(l, state);
1497 on_position_changed(xy, layer);
1498 lua_pop(l, 1);
1499 });
1500 }
1501
1502 /**
1503 * \brief Calls the state_on_ground_below_changed() method of a Lua custom state.
1504 *
1505 * Does nothing if the method is not defined.
1506 *
1507 * \param state A custom state.
1508 * \param ground_below The new ground below the entity.
1509 */
state_on_ground_below_changed(CustomState & state,Ground ground_below)1510 void LuaContext::state_on_ground_below_changed(CustomState& state, Ground ground_below) {
1511
1512 if (!userdata_has_field(state, "on_ground_below_changed")) {
1513 return;
1514 }
1515
1516 run_on_main([this, &state, ground_below](lua_State* l){
1517 push_state(l, state);
1518 on_ground_below_changed(ground_below);
1519 lua_pop(l, 1);
1520 });
1521 }
1522
1523 /**
1524 * \brief Calls the on_obstacle_reached() method of a Lua custom state.
1525 *
1526 * Does nothing if the method is not defined.
1527 *
1528 * \param state A custom state.
1529 * \param movement The movement that reached an obstacle.
1530 */
state_on_obstacle_reached(CustomState & state,Movement & movement)1531 void LuaContext::state_on_obstacle_reached(CustomState& state, Movement& movement) {
1532
1533 if (!userdata_has_field(state, "on_obstacle_reached")) {
1534 return;
1535 }
1536 run_on_main([this, &state, &movement](lua_State* l) {
1537 push_state(l, state);
1538 on_obstacle_reached(movement);
1539 lua_pop(l, 1);
1540 });
1541 }
1542
1543 /**
1544 * \brief Calls the on_movement_started() method of a Lua custom state.
1545 *
1546 * Does nothing if the method is not defined.
1547 *
1548 * \param state A custom state.
1549 * \param movement The movement that has just started.
1550 */
state_on_movement_started(CustomState & state,Movement & movement)1551 void LuaContext::state_on_movement_started(CustomState& state, Movement& movement) {
1552
1553 if (!userdata_has_field(state, "on_movement_started")) {
1554 return;
1555 }
1556
1557 run_on_main([this, &state, &movement](lua_State* l) {
1558 push_state(l, state);
1559 on_movement_started(movement);
1560 lua_pop(l, 1);
1561 });
1562 }
1563
1564 /**
1565 * \brief Calls the on_movement_changed() method of a Lua custom state.
1566 *
1567 * Does nothing if the method is not defined.
1568 *
1569 * \param state A custom state.
1570 * \param movement The movement of the entity.
1571 */
state_on_movement_changed(CustomState & state,Movement & movement)1572 void LuaContext::state_on_movement_changed(CustomState& state, Movement& movement) {
1573
1574 if (!userdata_has_field(state, "on_movement_changed")) {
1575 return;
1576 }
1577
1578 run_on_main([this, &state, &movement](lua_State* l) {
1579 push_state(l, state);
1580 on_movement_changed(movement);
1581 lua_pop(l, 1);
1582 });
1583 }
1584
1585 /**
1586 * \brief Calls the on_movement_finished() method of a Lua custom state.
1587 *
1588 * Does nothing if the method is not defined.
1589 *
1590 * \param state A custom state.
1591 */
state_on_movement_finished(CustomState & state)1592 void LuaContext::state_on_movement_finished(CustomState& state) {
1593
1594 if (!userdata_has_field(state, "on_movement_finished")) {
1595 return;
1596 }
1597
1598 run_on_main([this, &state](lua_State* l) {
1599 push_state(l, state);
1600 on_movement_finished();
1601 lua_pop(l, 1);
1602 });
1603 }
1604
1605 /**
1606 * \brief Calls the on_attacked_enemy() method of a Lua custom state.
1607 *
1608 * Does nothing if the method is not defined.
1609 *
1610 * \param state A custom state.
1611 * \param The enemy that was attacked.
1612 * \param enemy_sprite Sprite that was attacked if any.
1613 * \param attack How the enemy was attacked.
1614 * \param reaction How the enemy reacted to the attack.
1615 */
state_on_attacked_enemy(CustomState & state,Enemy & enemy,Sprite * enemy_sprite,EnemyAttack attack,const EnemyReaction::Reaction & reaction)1616 void LuaContext::state_on_attacked_enemy(
1617 CustomState& state,
1618 Enemy& enemy,
1619 Sprite* enemy_sprite,
1620 EnemyAttack attack,
1621 const EnemyReaction::Reaction& reaction
1622 ) {
1623 if (!userdata_has_field(state, "on_attacked_enemy")) {
1624 return;
1625 }
1626
1627 run_on_main([this, &state, &enemy, &enemy_sprite, &attack, &reaction](lua_State* l) {
1628 push_state(l, state);
1629 on_attacked_enemy(enemy, enemy_sprite, attack, reaction);
1630 lua_pop(l, 1);
1631 });
1632 }
1633
1634 /**
1635 * \brief Notifies a Lua custom state that an input event has just occurred.
1636 *
1637 * The appropriate callback in the state is triggered if it exists.
1638 * Also notifies the menus of the state if the state itself does not handle the
1639 * event.
1640 *
1641 * \param event The input event to handle.
1642 * \param state A custom state.
1643 * \return \c true if the event was handled and should stop being propagated.
1644 */
state_on_input(CustomState & state,const InputEvent & event)1645 bool LuaContext::state_on_input(CustomState& state, const InputEvent& event) {
1646
1647 push_state(current_l, state);
1648 bool handled = on_input(event);
1649 if (!handled) {
1650 handled = menus_on_input(-1, event);
1651 }
1652 lua_pop(current_l, 1);
1653 return handled;
1654 }
1655
1656 /**
1657 * \brief Calls the on_command_pressed() method of a Lua custom state.
1658 *
1659 * Also notifies the menus of the state if the state itself does not handle the
1660 * event.
1661 *
1662 * \param state A state.
1663 * \param command The command pressed.
1664 * \return \c true if the event was handled and should stop being propagated.
1665 */
state_on_command_pressed(CustomState & state,GameCommand command)1666 bool LuaContext::state_on_command_pressed(CustomState& state, GameCommand command) {
1667
1668 bool handled = false;
1669 push_state(current_l, state);
1670 if (userdata_has_field(state, "on_command_pressed")) {
1671 handled = on_command_pressed(command);
1672 }
1673 if (!handled) {
1674 handled = menus_on_command_pressed(-1, command);
1675 }
1676 lua_pop(current_l, 1);
1677 return handled;
1678 }
1679
1680 /**
1681 * \brief Calls the on_command_released() method of a Lua custom state.
1682 *
1683 * Also notifies the menus of the state if the state itself does not handle the
1684 * event.
1685 *
1686 * \param state A state.
1687 * \param command The command released.
1688 * \return \c true if the event was handled and should stop being propagated.
1689 */
state_on_command_released(CustomState & state,GameCommand command)1690 bool LuaContext::state_on_command_released(CustomState& state, GameCommand command) {
1691
1692 bool handled = false;
1693 push_state(current_l, state);
1694 if (userdata_has_field(state, "on_command_released")) {
1695 handled = on_command_released(command);
1696 }
1697 if (!handled) {
1698 handled = menus_on_command_released(-1, command);
1699 }
1700 lua_pop(current_l, 1);
1701 return handled;
1702 }
1703
1704 }
1705