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/Debug.h"
19 #include "solarus/core/Game.h"
20 #include "solarus/core/Geometry.h"
21 #include "solarus/core/MainLoop.h"
22 #include "solarus/core/Map.h"
23 #include "solarus/entities/Entities.h"
24 #include "solarus/entities/Hero.h"
25 #include "solarus/graphics/Drawable.h"
26 #include "solarus/lua/ExportableToLua.h"
27 #include "solarus/lua/ExportableToLuaPtr.h"
28 #include "solarus/lua/LuaContext.h"
29 #include "solarus/lua/LuaTools.h"
30 #include "solarus/movements/CircleMovement.h"
31 #include "solarus/movements/JumpMovement.h"
32 #include "solarus/movements/PathFindingMovement.h"
33 #include "solarus/movements/PathMovement.h"
34 #include "solarus/movements/PixelMovement.h"
35 #include "solarus/movements/RandomMovement.h"
36 #include "solarus/movements/RandomPathMovement.h"
37 #include "solarus/movements/TargetMovement.h"
38
39 namespace Solarus {
40
41 /**
42 * Name of the Lua table representing the movement module.
43 */
44 const std::string LuaContext::movement_module_name = "sol.movement";
45
46 /**
47 * Name of the Lua table representing the straight movement module.
48 */
49 const std::string LuaContext::movement_straight_module_name = "sol.straight_movement";
50
51 /**
52 * Name of the Lua table representing the target movement module.
53 */
54 const std::string LuaContext::movement_target_module_name = "sol.target_movement";
55
56 /**
57 * Name of the Lua table representing the random movement module.
58 */
59 const std::string LuaContext::movement_random_module_name = "sol.random_movement";
60
61 /**
62 * Name of the Lua table representing the path movement module.
63 */
64 const std::string LuaContext::movement_path_module_name = "sol.path_movement";
65
66 /**
67 * Name of the Lua table representing the random path movement module.
68 */
69 const std::string LuaContext::movement_random_path_module_name = "sol.random_path_movement";
70
71 /**
72 * Name of the Lua table representing the path finding movement module.
73 */
74 const std::string LuaContext::movement_path_finding_module_name = "sol.path_finding_movement";
75
76 /**
77 * Name of the Lua table representing the circle movement module.
78 */
79 const std::string LuaContext::movement_circle_module_name = "sol.circle_movement";
80
81 /**
82 * Name of the Lua table representing the jump movement module.
83 */
84 const std::string LuaContext::movement_jump_module_name = "sol.jump_movement";
85
86 /**
87 * Name of the Lua table representing the pixel movement module.
88 */
89 const std::string LuaContext::movement_pixel_module_name = "sol.pixel_movement";
90
91 /**
92 * \brief Initializes the movement features provided to Lua.
93 */
register_movement_module()94 void LuaContext::register_movement_module() {
95
96 // Functions of sol.movement.
97 const std::vector<luaL_Reg> movement_functions = {
98 { "create", movement_api_create }
99 };
100
101 // Methods common to all movement types.
102 const std::vector<luaL_Reg> movement_common_methods = {
103 { "get_xy", movement_api_get_xy },
104 { "set_xy", movement_api_set_xy },
105 { "start", movement_api_start },
106 { "stop", movement_api_stop },
107 { "is_suspended", movement_api_is_suspended },
108 { "get_ignore_suspend", movement_api_get_ignore_suspend },
109 { "set_ignore_suspend", movement_api_set_ignore_suspend },
110 { "get_ignore_obstacles", movement_api_get_ignore_obstacles },
111 { "set_ignore_obstacles", movement_api_set_ignore_obstacles },
112 { "get_direction4", movement_api_get_direction4 }
113 };
114
115 // Metamethods of all movement types.
116 const std::vector<luaL_Reg> metamethods = {
117 { "__gc", userdata_meta_gc },
118 { "__newindex", userdata_meta_newindex_as_table },
119 { "__index", userdata_meta_index_as_table },
120 };
121
122 register_type(
123 movement_module_name,
124 movement_functions,
125 movement_common_methods,
126 metamethods
127 );
128
129 // Straight movement.
130 std::vector<luaL_Reg> straight_movement_methods = {
131 { "get_speed", straight_movement_api_get_speed },
132 { "set_speed", straight_movement_api_set_speed },
133 { "get_angle", straight_movement_api_get_angle },
134 { "set_angle", straight_movement_api_set_angle },
135 { "get_max_distance", straight_movement_api_get_max_distance },
136 { "set_max_distance", straight_movement_api_set_max_distance },
137 { "is_smooth", straight_movement_api_is_smooth },
138 { "set_smooth", straight_movement_api_set_smooth }
139 };
140 straight_movement_methods.insert(
141 straight_movement_methods.end(),
142 movement_common_methods.begin(),
143 movement_common_methods.end()
144 );
145 register_type(
146 movement_straight_module_name,
147 {},
148 straight_movement_methods,
149 metamethods
150 );
151
152 // Random movement.
153 std::vector<luaL_Reg> random_movement_methods = {
154 { "get_speed", random_movement_api_get_speed },
155 { "set_speed", random_movement_api_set_speed },
156 { "get_angle", random_movement_api_get_angle },
157 { "get_max_distance", random_movement_api_get_max_distance },
158 { "set_max_distance", random_movement_api_set_max_distance },
159 { "is_smooth", random_movement_api_is_smooth },
160 { "set_smooth", random_movement_api_set_smooth }
161 };
162 random_movement_methods.insert(
163 random_movement_methods.end(),
164 movement_common_methods.begin(),
165 movement_common_methods.end()
166 );
167 register_type(
168 movement_random_module_name,
169 {},
170 random_movement_methods,
171 metamethods
172 );
173
174 // Target movement.
175 std::vector<luaL_Reg> target_movement_methods = {
176 { "set_target", target_movement_api_set_target },
177 { "get_speed", target_movement_api_get_speed },
178 { "set_speed", target_movement_api_set_speed },
179 { "get_angle", target_movement_api_get_angle },
180 { "is_smooth", target_movement_api_is_smooth },
181 { "set_smooth", target_movement_api_set_smooth },
182 };
183 target_movement_methods.insert(
184 target_movement_methods.end(),
185 movement_common_methods.begin(),
186 movement_common_methods.end()
187 );
188 register_type(
189 movement_target_module_name,
190 {},
191 target_movement_methods,
192 metamethods
193 );
194
195 // Path movement.
196 std::vector<luaL_Reg> path_movement_methods = {
197 { "get_path", path_movement_api_get_path },
198 { "set_path", path_movement_api_set_path },
199 { "get_speed", path_movement_api_get_speed },
200 { "set_speed", path_movement_api_set_speed },
201 { "get_loop", path_movement_api_get_loop },
202 { "set_loop", path_movement_api_set_loop },
203 { "get_snap_to_grid", path_movement_api_get_snap_to_grid },
204 { "set_snap_to_grid", path_movement_api_set_snap_to_grid },
205 };
206 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
207 path_movement_methods.insert(path_movement_methods.end(), {
208 { "get_angle", path_movement_api_get_angle },
209 });
210 }
211
212 path_movement_methods.insert(
213 path_movement_methods.end(),
214 movement_common_methods.begin(),
215 movement_common_methods.end()
216 );
217 register_type(
218 movement_path_module_name,
219 {},
220 path_movement_methods,
221 metamethods
222 );
223
224 // Random path movement.
225 std::vector<luaL_Reg> random_path_movement_methods = {
226 { "get_speed", random_path_movement_api_get_speed },
227 { "set_speed", random_path_movement_api_set_speed },
228 };
229 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
230 random_path_movement_methods.insert(random_path_movement_methods.end(), {
231 { "get_angle", random_path_movement_api_get_angle },
232 });
233 }
234 random_path_movement_methods.insert(
235 random_path_movement_methods.end(),
236 movement_common_methods.begin(),
237 movement_common_methods.end()
238 );
239 register_type(
240 movement_random_path_module_name,
241 {},
242 random_path_movement_methods,
243 metamethods
244 );
245
246 // Path finding movement.
247 std::vector<luaL_Reg> path_finding_movement_methods = {
248 { "set_target", path_finding_movement_api_set_target },
249 { "get_speed", path_finding_movement_api_get_speed },
250 { "set_speed", path_finding_movement_api_set_speed },
251 };
252 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
253 path_finding_movement_methods.insert(path_finding_movement_methods.end(), {
254 { "get_angle", path_finding_movement_api_get_angle },
255 });
256 }
257 path_finding_movement_methods.insert(
258 path_finding_movement_methods.end(),
259 movement_common_methods.begin(),
260 movement_common_methods.end()
261 );
262 register_type(
263 movement_path_finding_module_name,
264 {},
265 path_finding_movement_methods,
266 metamethods
267 );
268
269 // Circle movement.
270 std::vector<luaL_Reg> circle_movement_methods = {
271 { "set_center", circle_movement_api_set_center },
272 { "get_radius", circle_movement_api_get_radius },
273 { "set_radius", circle_movement_api_set_radius },
274 { "get_radius_speed", circle_movement_api_get_radius_speed },
275 { "set_radius_speed", circle_movement_api_set_radius_speed },
276 { "is_clockwise", circle_movement_api_is_clockwise },
277 { "set_clockwise", circle_movement_api_set_clockwise },
278 { "get_initial_angle", circle_movement_api_get_initial_angle },
279 { "set_initial_angle", circle_movement_api_set_initial_angle },
280 { "get_angle_speed", circle_movement_api_get_angle_speed },
281 { "set_angle_speed", circle_movement_api_set_angle_speed },
282 { "get_max_rotations", circle_movement_api_get_max_rotations },
283 { "set_max_rotations", circle_movement_api_set_max_rotations },
284 { "get_duration", circle_movement_api_get_duration },
285 { "set_duration", circle_movement_api_set_duration },
286 { "get_loop_delay", circle_movement_api_get_loop_delay },
287 { "set_loop_delay", circle_movement_api_set_loop_delay }
288 };
289 if (CurrentQuest::is_format_at_least({ 1, 6 })) {
290 circle_movement_methods.insert(circle_movement_methods.end(), {
291 { "get_center", circle_movement_api_get_center },
292 { "get_angle_from_center", circle_movement_api_get_angle_from_center },
293 { "set_angle_from_center", circle_movement_api_set_angle_from_center },
294 { "get_angular_speed", circle_movement_api_get_angular_speed },
295 { "set_angular_speed", circle_movement_api_set_angular_speed },
296 });
297 }
298 circle_movement_methods.insert(
299 circle_movement_methods.end(),
300 movement_common_methods.begin(),
301 movement_common_methods.end()
302 );
303 register_type(
304 movement_circle_module_name,
305 {},
306 circle_movement_methods,
307 metamethods
308 );
309
310 // Jump movement.
311 std::vector<luaL_Reg> jump_movement_methods = {
312 { "get_direction8", jump_movement_api_get_direction8 },
313 { "set_direction8", jump_movement_api_set_direction8 },
314 { "get_distance", jump_movement_api_get_distance },
315 { "set_distance", jump_movement_api_set_distance },
316 { "get_speed", jump_movement_api_get_speed },
317 { "set_speed", jump_movement_api_set_speed },
318 };
319 jump_movement_methods.insert(
320 jump_movement_methods.end(),
321 movement_common_methods.begin(),
322 movement_common_methods.end()
323 );
324 register_type(
325 movement_jump_module_name,
326 {},
327 jump_movement_methods,
328 metamethods
329 );
330
331 // Pixel movement.
332 std::vector<luaL_Reg> pixel_movement_methods = {
333 { "get_trajectory", pixel_movement_api_get_trajectory },
334 { "set_trajectory", pixel_movement_api_set_trajectory },
335 { "get_loop", pixel_movement_api_get_loop },
336 { "set_loop", pixel_movement_api_set_loop },
337 { "get_delay", pixel_movement_api_get_delay },
338 { "set_delay", pixel_movement_api_set_delay }
339 };
340 pixel_movement_methods.insert(
341 pixel_movement_methods.end(),
342 movement_common_methods.begin(),
343 movement_common_methods.end()
344 );
345 register_type(
346 movement_pixel_module_name,
347 {},
348 pixel_movement_methods,
349 metamethods
350 );
351
352 // Create the table that will store the movements applied to x,y points.
353 // ...
354 lua_newtable(current_l);
355 // ... movements
356 lua_newtable(current_l);
357 // ... movements meta
358 lua_pushstring(current_l, "v");
359 // ... movements meta "v"
360 lua_setfield(current_l, -2, "__mode");
361 // ... movements meta
362 lua_setmetatable(current_l, -2);
363 // ... movements
364 lua_setfield(current_l, LUA_REGISTRYINDEX, "sol.movements_on_points");
365 // ...
366 }
367
368 /**
369 * \brief Returns whether a value is a userdata of type movement.
370 * \param l A Lua context.
371 * \param index An index in the stack.
372 * \return \c true if the value at this index is a movement.
373 */
is_movement(lua_State * l,int index)374 bool LuaContext::is_movement(lua_State* l, int index) {
375 return is_straight_movement(l, index)
376 || is_random_movement(l, index)
377 || is_target_movement(l, index)
378 || is_path_movement(l, index)
379 || is_random_path_movement(l, index)
380 || is_path_finding_movement(l, index)
381 || is_circle_movement(l, index)
382 || is_jump_movement(l, index)
383 || is_pixel_movement(l, index);
384 }
385
386 /**
387 * \brief Checks that the userdata at the specified index of the stack is a
388 * movement (of any subtype) and returns it.
389 * \param l A Lua context.
390 * \param index An index in the stack.
391 * \return The movement.
392 */
check_movement(lua_State * l,int index)393 std::shared_ptr<Movement> LuaContext::check_movement(lua_State* l, int index) {
394
395 if (is_movement(l, index)) {
396 const ExportableToLuaPtr& userdata = *(static_cast<ExportableToLuaPtr*>(
397 lua_touserdata(l, index)
398 ));
399 return std::static_pointer_cast<Movement>(userdata);
400 }
401 else {
402 LuaTools::type_error(l, index, "movement");
403 }
404 }
405
406 /**
407 * \brief Pushes a movement userdata onto the stack.
408 * \param l A Lua context.
409 * \param movement A movement.
410 */
push_movement(lua_State * l,Movement & movement)411 void LuaContext::push_movement(lua_State* l, Movement& movement) {
412
413 push_userdata(l, movement);
414 }
415
416 /**
417 * \brief Starts moving an x,y point.
418 *
419 * The point is a Lua table with two fields x and y.
420 * Fields x and y may be initially missing.
421 *
422 * \param movement The movement to apply to the points.
423 * \param point_index Index of the x,y table in the Lua stack.
424 */
start_movement_on_point(const std::shared_ptr<Movement> & movement,int point_index)425 void LuaContext::start_movement_on_point(
426 const std::shared_ptr<Movement>& movement, int point_index
427 ) {
428 int x = 0;
429 int y = 0;
430 // ...
431 lua_getfield(current_l, LUA_REGISTRYINDEX, "sol.movements_on_points");
432 // ... movements
433 push_movement(current_l, *movement);
434 // ... movements movement
435 lua_pushvalue(current_l, point_index);
436 // ... movements movement xy
437 lua_getfield(current_l, -1, "x");
438 // ... movements movement xy x/nil
439 if (lua_isnil(current_l, -1)) {
440 // ... movements movement xy nil
441 lua_pop(current_l, 1);
442 // ... movements movement xy
443 lua_pushinteger(current_l, 0);
444 // ... movements movement xy 0
445 lua_setfield(current_l, -2, "x");
446 // ... movements movement xy
447 }
448 else {
449 // ... movements movement xy x
450 x = LuaTools::check_int(current_l, -1);
451 lua_pop(current_l, 1);
452 // ... movements movement xy
453 }
454 lua_getfield(current_l, -1, "y");
455 // ... movements movement xy y/nil
456 if (lua_isnil(current_l, -1)) {
457 // ... movements movement xy nil
458 lua_pop(current_l, 1);
459 // ... movements movement xy
460 lua_pushinteger(current_l, 0);
461 // ... movements movement xy 0
462 lua_setfield(current_l, -2, "y");
463 // ... movements movement xy
464 }
465 else {
466 // ... movements movement xy y
467 y = LuaTools::check_int(current_l, -1);
468 lua_pop(current_l, 1);
469 // ... movements movement xy
470 }
471
472 lua_settable(current_l, -3);
473 // ... movements
474 lua_pop(current_l, 1);
475 // ...
476 movement->set_xy(x, y);
477
478 // Tell the movement it is now controlling this table.
479 movement->notify_object_controlled();
480 }
481
482 /**
483 * \brief Stops moving an x,y point.
484 * \param movement The movement to stop.
485 */
stop_movement_on_point(const std::shared_ptr<Movement> & movement)486 void LuaContext::stop_movement_on_point(const std::shared_ptr<Movement>& movement) {
487
488 // ...
489 lua_getfield(current_l, LUA_REGISTRYINDEX, "sol.movements_on_points");
490 // ... movements
491 push_movement(current_l, *movement);
492 // ... movements movement
493 lua_pushnil(current_l);
494 // ... movements movement nil
495 lua_settable(current_l, -3);
496 // ... movements
497 lua_pop(current_l, 1);
498 // ...
499 }
500
501 /**
502 * \brief Updates all movements applied to x,y points.
503 *
504 * Movements applied to map entities or drawables are already updated
505 * by the entity or the drawable.
506 * This may change in the future in order to unify the handling of movements.
507 */
update_movements()508 void LuaContext::update_movements() {
509
510 lua_getfield(current_l, LUA_REGISTRYINDEX, "sol.movements_on_points");
511 std::vector<std::shared_ptr<Movement>> movements;
512 lua_pushnil(current_l); // First key.
513 while (lua_next(current_l, -2)) {
514 const std::shared_ptr<Movement>& movement = check_movement(current_l, -2);
515 movements.push_back(movement);
516 lua_pop(current_l, 1); // Pop the value, keep the key for next iteration.
517 }
518 lua_pop(current_l, 1); // Pop the movements table.
519
520 // Work on a copy of the list because the list may be changed during the iteration.
521 for (const std::shared_ptr<Movement>& movement : movements) {
522 movement->update();
523 }
524 }
525
526 /**
527 * \brief Implementation of sol.movement.create().
528 * \param l The Lua context that is calling this function.
529 * \return Number of values to return to Lua.
530 */
movement_api_create(lua_State * l)531 int LuaContext::movement_api_create(lua_State* l) {
532
533 return state_boundary_handle(l, [&] {
534 LuaContext& lua_context = get();
535 const std::string& type = LuaTools::check_string(l, 1);
536
537 std::shared_ptr<Movement> movement;
538 if (type == "straight") {
539 std::shared_ptr<StraightMovement> straight_movement =
540 std::make_shared<StraightMovement>(false, true);
541 straight_movement->set_speed(32);
542 movement = straight_movement;
543 }
544 else if (type == "random") {
545 movement = std::make_shared<RandomMovement>(32);
546 }
547 else if (type == "target") {
548 Game* game = lua_context.get_main_loop().get_game();
549 if (game != nullptr) {
550 // If we are on a map, the default target is the hero.
551 movement = std::make_shared<TargetMovement>(
552 game->get_hero(), 0, 0, 96, false
553 );
554 }
555 else {
556 movement = std::make_shared<TargetMovement>(
557 nullptr, 0, 0, 32, false
558 );
559 }
560 }
561 else if (type == "path") {
562 movement = std::make_shared<PathMovement>(
563 "", 32, false, false, false
564 );
565 }
566 else if (type == "random_path") {
567 movement = std::make_shared<RandomPathMovement>(32);
568 }
569 else if (type == "path_finding") {
570 std::shared_ptr<PathFindingMovement> path_finding_movement =
571 std::make_shared<PathFindingMovement>(32);
572 Game* game = lua_context.get_main_loop().get_game();
573 if (game != nullptr) {
574 // If we are on a map, the default target is the hero.
575 path_finding_movement->set_target(game->get_hero());
576 }
577 movement = path_finding_movement;
578 }
579 else if (type == "circle") {
580 movement = std::make_shared<CircleMovement>();
581 }
582 else if (type == "jump") {
583 movement = std::make_shared<JumpMovement>(0, 0, 0, false);
584 }
585 else if (type == "pixel") {
586 movement = std::make_shared<PixelMovement>("", 30, false, false);
587 }
588 else {
589 LuaTools::arg_error(l, 1, "should be one of: "
590 "\"straight\", "
591 "\"random\", "
592 "\"target\", "
593 "\"path\", "
594 "\"random_path\", "
595 "\"path_finding\", "
596 "\"circle\", "
597 "\"jump\" or "
598 "\"pixel\"");
599 }
600
601 push_movement(l, *movement);
602 return 1;
603 });
604 }
605
606 /**
607 * \brief Implementation of movement:get_xy().
608 * \param l The Lua context that is calling this function.
609 * \return Number of values to return to Lua.
610 */
movement_api_get_xy(lua_State * l)611 int LuaContext::movement_api_get_xy(lua_State* l) {
612
613 return state_boundary_handle(l, [&] {
614 Movement& movement = *check_movement(l, 1);
615
616 const Point& xy = movement.get_xy();
617 lua_pushinteger(l, xy.x);
618 lua_pushinteger(l, xy.y);
619 return 2;
620 });
621 }
622
623 /**
624 * \brief Implementation of movement:set_xy().
625 * \param l The Lua context that is calling this function.
626 * \return Number of values to return to Lua.
627 */
movement_api_set_xy(lua_State * l)628 int LuaContext::movement_api_set_xy(lua_State* l) {
629
630 return state_boundary_handle(l, [&] {
631 Movement& movement = *check_movement(l, 1);
632 int x = LuaTools::check_int(l, 2);
633 int y = LuaTools::check_int(l, 3);
634
635 movement.set_xy(x, y);
636
637 return 0;
638 });
639 }
640
641 /**
642 * \brief Implementation of movement:start().
643 * \param l The Lua context that is calling this function.
644 * \return Number of values to return to Lua.
645 */
movement_api_start(lua_State * l)646 int LuaContext::movement_api_start(lua_State* l) {
647
648 return state_boundary_handle(l, [&] {
649 LuaContext& lua_context = get();
650
651 std::shared_ptr<Movement> movement = check_movement(l, 1);
652 movement_api_stop(l); // First, stop any previous movement.
653
654 ScopedLuaRef callback_ref = LuaTools::opt_function(l, 3);
655
656 if (lua_type(l, 2) == LUA_TTABLE) {
657 lua_context.start_movement_on_point(movement, 2);
658 }
659 else if (is_entity(l, 2)) {
660 Entity& entity = *check_entity(l, 2);
661 if (!entity.is_on_map() ||
662 !entity.get_map().is_started()
663 ) {
664 LuaTools::arg_error(l, 2, "This entity is not on the current map");
665 }
666 entity.clear_movement();
667 entity.set_movement(movement);
668 }
669 else if (is_drawable(l, 2)) {
670 Drawable& drawable = *check_drawable(l, 2);
671 drawable.start_movement(movement);
672 }
673 else {
674 LuaTools::type_error(l, 2, "table, entity or drawable");
675 }
676 movement->set_finished_callback(callback_ref);
677
678 return 0;
679 });
680 }
681
682 /**
683 * \brief Implementation of movement:stop().
684 * \param l The Lua context that is calling this function.
685 * \return Number of values to return to Lua.
686 */
movement_api_stop(lua_State * l)687 int LuaContext::movement_api_stop(lua_State* l) {
688
689 return state_boundary_handle(l, [&] {
690 LuaContext& lua_context = get();
691
692 std::shared_ptr<Movement> movement = check_movement(l, 1);
693
694 Entity* entity = movement->get_entity();
695 if (entity != nullptr) {
696 // The object controlled is a map entity.
697 entity->clear_movement();
698 }
699 else {
700 Drawable* drawable = movement->get_drawable();
701 if (drawable != nullptr) {
702 // The object controlled is a drawable.
703 drawable->stop_movement();
704 }
705 else {
706 // The object controlled is a point.
707 lua_context.stop_movement_on_point(movement);
708 }
709 }
710
711 return 0;
712 });
713 }
714
715 /**
716 * \brief Implementation of movement:is_suspended().
717 * \param l The Lua context that is calling this function.
718 * \return Number of values to return to Lua.
719 */
movement_api_is_suspended(lua_State * l)720 int LuaContext::movement_api_is_suspended(lua_State* l) {
721
722 return state_boundary_handle(l, [&] {
723 std::shared_ptr<Movement> movement = check_movement(l, 1);
724
725 lua_pushboolean(l, movement->is_suspended());
726 return 1;
727 });
728 }
729
730 /**
731 * \brief Implementation of movement:get_ignore_suspend().
732 * \param l The Lua context that is calling this function.
733 * \return Number of values to return to Lua.
734 */
movement_api_get_ignore_suspend(lua_State * l)735 int LuaContext::movement_api_get_ignore_suspend(lua_State* l) {
736
737 return state_boundary_handle(l, [&] {
738 std::shared_ptr<Movement> movement = check_movement(l, 1);
739
740 lua_pushboolean(l, movement->get_ignore_suspend());
741 return 1;
742 });
743 }
744
745 /**
746 * \brief Implementation of movement:set_ignore_suspend().
747 * \param l The Lua context that is calling this function.
748 * \return Number of values to return to Lua.
749 */
movement_api_set_ignore_suspend(lua_State * l)750 int LuaContext::movement_api_set_ignore_suspend(lua_State* l) {
751
752 return state_boundary_handle(l, [&] {
753 std::shared_ptr<Movement> movement = check_movement(l, 1);
754 bool ignore_suspend = LuaTools::opt_boolean(l, 2, true);
755
756 movement->set_ignore_suspend(ignore_suspend);
757
758 return 0;
759 });
760 }
761
762 /**
763 * \brief Implementation of movement:get_ignore_obstacles().
764 * \param l The Lua context that is calling this function.
765 * \return Number of values to return to Lua.
766 */
movement_api_get_ignore_obstacles(lua_State * l)767 int LuaContext::movement_api_get_ignore_obstacles(lua_State* l) {
768
769 return state_boundary_handle(l, [&] {
770 std::shared_ptr<Movement> movement = check_movement(l, 1);
771
772 lua_pushboolean(l, movement->are_obstacles_ignored());
773 return 1;
774 });
775 }
776
777 /**
778 * \brief Implementation of movement:set_ignore_obstacles().
779 * \param l The Lua context that is calling this function.
780 * \return Number of values to return to Lua.
781 */
movement_api_set_ignore_obstacles(lua_State * l)782 int LuaContext::movement_api_set_ignore_obstacles(lua_State* l) {
783
784 return state_boundary_handle(l, [&] {
785 std::shared_ptr<Movement> movement = check_movement(l, 1);
786 bool ignore_obstacles = LuaTools::opt_boolean(l, 2, true);
787
788 movement->set_ignore_obstacles(ignore_obstacles);
789
790 return 0;
791 });
792 }
793
794 /**
795 * \brief Implementation of movement:get_direction4().
796 * \param l The Lua context that is calling this function.
797 * \return Number of values to return to Lua.
798 */
movement_api_get_direction4(lua_State * l)799 int LuaContext::movement_api_get_direction4(lua_State* l) {
800
801 return state_boundary_handle(l, [&] {
802 std::shared_ptr<Movement> movement = check_movement(l, 1);
803 lua_pushinteger(l, movement->get_displayed_direction4());
804 return 1;
805 });
806 }
807
808 /**
809 * \brief Returns whether a value is a userdata of type straight movement.
810 * \param l A Lua context.
811 * \param index An index in the stack.
812 * \return \c true if the value at this index is a straight movement.
813 */
is_straight_movement(lua_State * l,int index)814 bool LuaContext::is_straight_movement(lua_State* l, int index) {
815 return is_userdata(l, index, movement_straight_module_name);
816 }
817
818 /**
819 * \brief Checks that the userdata at the specified index of the stack is a
820 * straight movement and returns it.
821 * \param l A Lua context.
822 * \param index An index in the stack.
823 * \return The movement.
824 */
check_straight_movement(lua_State * l,int index)825 std::shared_ptr<StraightMovement> LuaContext::check_straight_movement(lua_State* l, int index) {
826
827 return std::static_pointer_cast<StraightMovement>(check_userdata(
828 l, index, movement_straight_module_name
829 ));
830 }
831
832 /**
833 * \brief Implementation of straight_movement:get_speed().
834 * \param l The Lua context that is calling this function.
835 * \return Number of values to return to Lua.
836 */
straight_movement_api_get_speed(lua_State * l)837 int LuaContext::straight_movement_api_get_speed(lua_State* l) {
838
839 return state_boundary_handle(l, [&] {
840 const StraightMovement& movement = *check_straight_movement(l, 1);
841 lua_pushinteger(l, movement.get_speed());
842 return 1;
843 });
844 }
845
846 /**
847 * \brief Implementation of straight_movement:set_speed().
848 * \param l The Lua context that is calling this function.
849 * \return Number of values to return to Lua.
850 */
straight_movement_api_set_speed(lua_State * l)851 int LuaContext::straight_movement_api_set_speed(lua_State* l) {
852
853 return state_boundary_handle(l, [&] {
854 StraightMovement& movement = *check_straight_movement(l, 1);
855 int speed = LuaTools::check_int(l, 2);
856 movement.set_speed(speed);
857 return 0;
858 });
859 }
860
861 /**
862 * \brief Implementation of straight_movement:get_angle().
863 * \param l The Lua context that is calling this function.
864 * \return Number of values to return to Lua.
865 */
straight_movement_api_get_angle(lua_State * l)866 int LuaContext::straight_movement_api_get_angle(lua_State* l) {
867
868 return state_boundary_handle(l, [&] {
869 const StraightMovement& movement = *check_straight_movement(l, 1);
870 lua_pushnumber(l, movement.get_angle());
871 return 1;
872 });
873 }
874
875 /**
876 * \brief Implementation of straight_movement:set_angle().
877 * \param l The Lua context that is calling this function.
878 * \return Number of values to return to Lua.
879 */
straight_movement_api_set_angle(lua_State * l)880 int LuaContext::straight_movement_api_set_angle(lua_State* l) {
881
882 return state_boundary_handle(l, [&] {
883 StraightMovement& movement = *check_straight_movement(l, 1);
884 double angle = LuaTools::check_number(l, 2);
885 movement.set_angle(angle);
886 return 0;
887 });
888 }
889
890 /**
891 * \brief Implementation of straight_movement:get_max_distance().
892 * \param l The Lua context that is calling this function.
893 * \return Number of values to return to Lua.
894 */
straight_movement_api_get_max_distance(lua_State * l)895 int LuaContext::straight_movement_api_get_max_distance(lua_State* l) {
896
897 return state_boundary_handle(l, [&] {
898 const StraightMovement& movement = *check_straight_movement(l, 1);
899 lua_pushinteger(l, movement.get_max_distance());
900 return 1;
901 });
902 }
903
904 /**
905 * \brief Implementation of straight_movement:set_max_distance().
906 * \param l The Lua context that is calling this function.
907 * \return Number of values to return to Lua.
908 */
straight_movement_api_set_max_distance(lua_State * l)909 int LuaContext::straight_movement_api_set_max_distance(lua_State* l) {
910
911 return state_boundary_handle(l, [&] {
912 StraightMovement& movement = *check_straight_movement(l, 1);
913 int max_distance = LuaTools::check_int(l, 2);
914 movement.set_max_distance(max_distance);
915 return 0;
916 });
917 }
918
919 /**
920 * \brief Implementation of straight_movement:is_smooth().
921 * \param l The Lua context that is calling this function.
922 * \return Number of values to return to Lua.
923 */
straight_movement_api_is_smooth(lua_State * l)924 int LuaContext::straight_movement_api_is_smooth(lua_State* l) {
925
926 return state_boundary_handle(l, [&] {
927 const StraightMovement& movement = *check_straight_movement(l, 1);
928 lua_pushboolean(l, movement.is_smooth());
929 return 1;
930 });
931 }
932
933 /**
934 * \brief Implementation of straight_movement:set_smooth().
935 * \param l The Lua context that is calling this function.
936 * \return Number of values to return to Lua.
937 */
straight_movement_api_set_smooth(lua_State * l)938 int LuaContext::straight_movement_api_set_smooth(lua_State* l) {
939
940 return state_boundary_handle(l, [&] {
941 StraightMovement& movement = *check_straight_movement(l, 1);
942 bool smooth = LuaTools::opt_boolean(l, 2, true);
943 movement.set_smooth(smooth);
944
945 return 0;
946 });
947 }
948
949 /**
950 * \brief Returns whether a value is a userdata of type random movement.
951 * \param l A Lua context.
952 * \param index An index in the stack.
953 * \return \c true if the value at this index is a random movement.
954 */
is_random_movement(lua_State * l,int index)955 bool LuaContext::is_random_movement(lua_State* l, int index) {
956 return is_userdata(l, index, movement_random_module_name);
957 }
958
959 /**
960 * \brief Checks that the userdata at the specified index of the stack is a
961 * random movement and returns it.
962 * \param l A Lua context.
963 * \param index An index in the stack.
964 * \return The movement.
965 */
check_random_movement(lua_State * l,int index)966 std::shared_ptr<RandomMovement> LuaContext::check_random_movement(lua_State* l, int index) {
967 return std::static_pointer_cast<RandomMovement>(check_userdata(
968 l, index, movement_random_module_name
969 ));
970 }
971
972 /**
973 * \brief Implementation of random_movement:get_speed().
974 * \param l The Lua context that is calling this function.
975 * \return Number of values to return to Lua.
976 */
random_movement_api_get_speed(lua_State * l)977 int LuaContext::random_movement_api_get_speed(lua_State* l) {
978
979 return state_boundary_handle(l, [&] {
980 const RandomMovement& movement = *check_random_movement(l, 1);
981 lua_pushinteger(l, movement.get_speed());
982 return 1;
983 });
984 }
985
986 /**
987 * \brief Implementation of random_movement:set_speed().
988 * \param l The Lua context that is calling this function.
989 * \return Number of values to return to Lua.
990 */
random_movement_api_set_speed(lua_State * l)991 int LuaContext::random_movement_api_set_speed(lua_State* l) {
992
993 return state_boundary_handle(l, [&] {
994 RandomMovement& movement = *check_random_movement(l, 1);
995 int speed = LuaTools::check_int(l, 2);
996 movement.set_normal_speed(speed);
997 return 0;
998 });
999 }
1000
1001 /**
1002 * \brief Implementation of random_movement:get_angle().
1003 * \param l The Lua context that is calling this function.
1004 * \return Number of values to return to Lua.
1005 */
random_movement_api_get_angle(lua_State * l)1006 int LuaContext::random_movement_api_get_angle(lua_State* l) {
1007
1008 return state_boundary_handle(l, [&] {
1009 const RandomMovement& movement = *check_random_movement(l, 1);
1010 lua_pushnumber(l, movement.get_angle());
1011 return 1;
1012 });
1013 }
1014
1015 /**
1016 * \brief Implementation of random_movement:get_max_distance().
1017 * \param l The Lua context that is calling this function.
1018 * \return Number of values to return to Lua.
1019 */
random_movement_api_get_max_distance(lua_State * l)1020 int LuaContext::random_movement_api_get_max_distance(lua_State* l) {
1021
1022 return state_boundary_handle(l, [&] {
1023 const RandomMovement& movement = *check_random_movement(l, 1);
1024 lua_pushinteger(l, movement.get_max_radius());
1025 return 1;
1026 });
1027 }
1028
1029 /**
1030 * \brief Implementation of random_movement:set_max_distance().
1031 * \param l The Lua context that is calling this function.
1032 * \return Number of values to return to Lua.
1033 */
random_movement_api_set_max_distance(lua_State * l)1034 int LuaContext::random_movement_api_set_max_distance(lua_State* l) {
1035
1036 return state_boundary_handle(l, [&] {
1037 RandomMovement& movement = *check_random_movement(l, 1);
1038 int max_radius = LuaTools::check_int(l, 2);
1039 movement.set_max_radius(max_radius);
1040 return 0;
1041 });
1042 }
1043
1044 /**
1045 * \brief Implementation of random_movement:is_smooth().
1046 * \param l The Lua context that is calling this function.
1047 * \return Number of values to return to Lua.
1048 */
random_movement_api_is_smooth(lua_State * l)1049 int LuaContext::random_movement_api_is_smooth(lua_State* l) {
1050
1051 return state_boundary_handle(l, [&] {
1052 const RandomMovement& movement = *check_random_movement(l, 1);
1053 lua_pushboolean(l, movement.is_smooth());
1054 return 1;
1055 });
1056 }
1057
1058 /**
1059 * \brief Implementation of random_movement:set_smooth().
1060 * \param l The Lua context that is calling this function.
1061 * \return Number of values to return to Lua.
1062 */
random_movement_api_set_smooth(lua_State * l)1063 int LuaContext::random_movement_api_set_smooth(lua_State* l) {
1064
1065 return state_boundary_handle(l, [&] {
1066 RandomMovement& movement = *check_random_movement(l, 1);
1067 bool smooth = LuaTools::opt_boolean(l, 2, true);
1068 movement.set_smooth(smooth);
1069
1070 return 0;
1071 });
1072 }
1073
1074 /**
1075 * \brief Returns whether a value is a userdata of type target movement.
1076 * \param l A Lua context.
1077 * \param index An index in the stack.
1078 * \return \c true if the value at this index is a target movement.
1079 */
is_target_movement(lua_State * l,int index)1080 bool LuaContext::is_target_movement(lua_State* l, int index) {
1081 return is_userdata(l, index, movement_target_module_name);
1082 }
1083
1084 /**
1085 * \brief Checks that the userdata at the specified index of the stack is a
1086 * target movement and returns it.
1087 * \param l A Lua context.
1088 * \param index An index in the stack.
1089 * \return The movement.
1090 */
check_target_movement(lua_State * l,int index)1091 std::shared_ptr<TargetMovement> LuaContext::check_target_movement(lua_State* l, int index) {
1092 return std::static_pointer_cast<TargetMovement>(check_userdata(
1093 l, index, movement_target_module_name
1094 ));
1095 }
1096
1097 /**
1098 * \brief Implementation of target_movement:set_target().
1099 * \param l The Lua context that is calling this function.
1100 * \return Number of values to return to Lua.
1101 */
target_movement_api_set_target(lua_State * l)1102 int LuaContext::target_movement_api_set_target(lua_State* l) {
1103
1104 return state_boundary_handle(l, [&] {
1105 TargetMovement& movement = *check_target_movement(l, 1);
1106 if (lua_isnumber(l, 2)) {
1107 // The target is a fixed point.
1108 int x = LuaTools::check_int(l, 2);
1109 int y = LuaTools::check_int(l, 3);
1110 movement.set_target(nullptr, Point(x, y));
1111 }
1112 else {
1113 // the target is an entity, possibly with an offset.
1114 EntityPtr target = check_entity(l, 2);
1115 int x = 0;
1116 int y = 0;
1117 if (lua_isnumber(l, 3)) {
1118 // There is an offset.
1119 x = LuaTools::check_int(l, 3);
1120 y = LuaTools::check_int(l, 4);
1121 }
1122 movement.set_target(target, Point(x, y));
1123 }
1124
1125 return 0;
1126 });
1127 }
1128
1129 /**
1130 * \brief Implementation of target_movement:get_speed().
1131 * \param l The Lua context that is calling this function.
1132 * \return Number of values to return to Lua.
1133 */
target_movement_api_get_speed(lua_State * l)1134 int LuaContext::target_movement_api_get_speed(lua_State* l) {
1135
1136 return state_boundary_handle(l, [&] {
1137 const TargetMovement& movement = *check_target_movement(l, 1);
1138 lua_pushinteger(l, movement.get_speed());
1139 return 1;
1140 });
1141 }
1142
1143 /**
1144 * \brief Implementation of target_movement:set_speed().
1145 * \param l The Lua context that is calling this function.
1146 * \return Number of values to return to Lua.
1147 */
target_movement_api_set_speed(lua_State * l)1148 int LuaContext::target_movement_api_set_speed(lua_State* l) {
1149
1150 return state_boundary_handle(l, [&] {
1151 TargetMovement& movement = *check_target_movement(l, 1);
1152 int speed = LuaTools::check_int(l, 2);
1153 movement.set_moving_speed(speed);
1154 return 0;
1155 });
1156 }
1157
1158 /**
1159 * \brief Implementation of target_movement:get_angle().
1160 * \param l The Lua context that is calling this function.
1161 * \return Number of values to return to Lua.
1162 */
target_movement_api_get_angle(lua_State * l)1163 int LuaContext::target_movement_api_get_angle(lua_State* l) {
1164
1165 return state_boundary_handle(l, [&] {
1166 const TargetMovement& movement = *check_target_movement(l, 1);
1167 lua_pushnumber(l, movement.get_angle());
1168 return 1;
1169 });
1170 }
1171
1172 /**
1173 * \brief Implementation of target_movement:is_smooth().
1174 * \param l The Lua context that is calling this function.
1175 * \return Number of values to return to Lua.
1176 */
target_movement_api_is_smooth(lua_State * l)1177 int LuaContext::target_movement_api_is_smooth(lua_State* l) {
1178
1179 return state_boundary_handle(l, [&] {
1180 const TargetMovement& movement = *check_target_movement(l, 1);
1181 lua_pushboolean(l, movement.is_smooth());
1182 return 1;
1183 });
1184 }
1185
1186 /**
1187 * \brief Implementation of target_movement:set_smooth().
1188 * \param l The Lua context that is calling this function.
1189 * \return Number of values to return to Lua.
1190 */
target_movement_api_set_smooth(lua_State * l)1191 int LuaContext::target_movement_api_set_smooth(lua_State* l) {
1192
1193 return state_boundary_handle(l, [&] {
1194 TargetMovement& movement = *check_target_movement(l, 1);
1195 bool smooth = LuaTools::opt_boolean(l, 2, true);
1196 movement.set_smooth(smooth);
1197
1198 return 0;
1199 });
1200 }
1201
1202 /**
1203 * \brief Returns whether a value is a userdata of type path movement.
1204 * \param l A Lua context.
1205 * \param index An index in the stack.
1206 * \return \c true if the value at this index is a path movement.
1207 */
is_path_movement(lua_State * l,int index)1208 bool LuaContext::is_path_movement(lua_State* l, int index) {
1209 return is_userdata(l, index, movement_path_module_name);
1210 }
1211
1212 /**
1213 * \brief Checks that the userdata at the specified index of the stack is a
1214 * path movement and returns it.
1215 * \param l A Lua context.
1216 * \param index An index in the stack.
1217 * \return The movement.
1218 */
check_path_movement(lua_State * l,int index)1219 std::shared_ptr<PathMovement> LuaContext::check_path_movement(lua_State* l, int index) {
1220 return std::static_pointer_cast<PathMovement>(check_userdata(
1221 l, index, movement_path_module_name
1222 ));
1223 }
1224
1225 /**
1226 * \brief Implementation of path_movement:get_path().
1227 * \param l The Lua context that is calling this function.
1228 * \return Number of values to return to Lua.
1229 */
path_movement_api_get_path(lua_State * l)1230 int LuaContext::path_movement_api_get_path(lua_State* l) {
1231
1232 return state_boundary_handle(l, [&] {
1233 const PathMovement& movement = *check_path_movement(l, 1);
1234
1235 const std::string& path = movement.get_path();
1236 // Build a Lua array containing the path.
1237 lua_settop(l, 1);
1238 lua_newtable(l);
1239 for (size_t i = 0; i < path.size(); i++) {
1240 int direction8 = path[i] - '0';
1241 lua_pushinteger(l, direction8);
1242 lua_rawseti(l, 2, static_cast<int>(i + 1));
1243 }
1244
1245 return 1;
1246 });
1247 }
1248
1249 /**
1250 * \brief Implementation of path_movement:set_path().
1251 * \param l The Lua context that is calling this function.
1252 * \return Number of values to return to Lua.
1253 */
path_movement_api_set_path(lua_State * l)1254 int LuaContext::path_movement_api_set_path(lua_State* l) {
1255
1256 return state_boundary_handle(l, [&] {
1257 PathMovement& movement = *check_path_movement(l, 1);
1258 LuaTools::check_type(l, 2, LUA_TTABLE);
1259
1260 // build the path as a string from the Lua table
1261 std::string path = "";
1262 lua_pushnil(l); // first key
1263 while (lua_next(l, 2) != 0) {
1264 int direction8 = LuaTools::check_int(l, 4);
1265 path += ('0' + direction8);
1266 lua_pop(l, 1); // pop the value, let the key for the iteration
1267 }
1268 movement.set_path(path);
1269
1270 return 0;
1271 });
1272 }
1273
1274 /**
1275 * \brief Implementation of path_movement:get_speed().
1276 * \param l The Lua context that is calling this function.
1277 * \return Number of values to return to Lua.
1278 */
path_movement_api_get_speed(lua_State * l)1279 int LuaContext::path_movement_api_get_speed(lua_State* l) {
1280
1281 return state_boundary_handle(l, [&] {
1282 const PathMovement& movement = *check_path_movement(l, 1);
1283 lua_pushinteger(l, movement.get_speed());
1284 return 1;
1285 });
1286 }
1287
1288 /**
1289 * \brief Implementation of path_movement:set_speed().
1290 * \param l The Lua context that is calling this function.
1291 * \return Number of values to return to Lua.
1292 */
path_movement_api_set_speed(lua_State * l)1293 int LuaContext::path_movement_api_set_speed(lua_State* l) {
1294
1295 return state_boundary_handle(l, [&] {
1296 PathMovement& movement = *check_path_movement(l, 1);
1297 int speed = LuaTools::check_int(l, 2);
1298 movement.set_speed(speed);
1299 return 0;
1300 });
1301 }
1302
1303 /**
1304 * \brief Implementation of path_movement:get_angle().
1305 * \param l The Lua context that is calling this function.
1306 * \return Number of values to return to Lua.
1307 */
path_movement_api_get_angle(lua_State * l)1308 int LuaContext::path_movement_api_get_angle(lua_State* l) {
1309 return state_boundary_handle(l, [&] {
1310 const PathMovement& movement = *check_path_movement(l,1);
1311 lua_pushnumber(l,movement.get_angle());
1312 return 1;
1313 });
1314 }
1315
1316 /**
1317 * \brief Implementation of path_movement:get_loop().
1318 * \param l The Lua context that is calling this function.
1319 * \return Number of values to return to Lua.
1320 */
path_movement_api_get_loop(lua_State * l)1321 int LuaContext::path_movement_api_get_loop(lua_State* l) {
1322
1323 return state_boundary_handle(l, [&] {
1324 const PathMovement& movement = *check_path_movement(l, 1);
1325 lua_pushboolean(l, movement.get_loop());
1326 return 1;
1327 });
1328 }
1329
1330 /**
1331 * \brief Implementation of path_movement:set_loop().
1332 * \param l The Lua context that is calling this function.
1333 * \return Number of values to return to Lua.
1334 */
path_movement_api_set_loop(lua_State * l)1335 int LuaContext::path_movement_api_set_loop(lua_State* l) {
1336
1337 return state_boundary_handle(l, [&] {
1338 PathMovement& movement = *check_path_movement(l, 1);
1339 bool loop = LuaTools::opt_boolean(l, 2, true);
1340
1341 movement.set_loop(loop);
1342
1343 return 0;
1344 });
1345 }
1346
1347 /**
1348 * \brief Implementation of path_movement:get_snap_to_grid().
1349 * \param l The Lua context that is calling this function.
1350 * \return Number of values to return to Lua.
1351 */
path_movement_api_get_snap_to_grid(lua_State * l)1352 int LuaContext::path_movement_api_get_snap_to_grid(lua_State* l) {
1353
1354 return state_boundary_handle(l, [&] {
1355 const PathMovement& movement = *check_path_movement(l, 1);
1356 lua_pushboolean(l, movement.get_snap_to_grid());
1357 return 1;
1358 });
1359 }
1360
1361 /**
1362 * \brief Implementation of path_movement:set_snap_to_grid().
1363 * \param l The Lua context that is calling this function.
1364 * \return Number of values to return to Lua.
1365 */
path_movement_api_set_snap_to_grid(lua_State * l)1366 int LuaContext::path_movement_api_set_snap_to_grid(lua_State* l) {
1367
1368 return state_boundary_handle(l, [&] {
1369 PathMovement& movement = *check_path_movement(l, 1);
1370 bool snap_to_grid = LuaTools::opt_boolean(l, 2, true);
1371
1372 movement.set_snap_to_grid(snap_to_grid);
1373
1374 return 0;
1375 });
1376 }
1377
1378 /**
1379 * \brief Checks that the userdata at the specified index of the stack is a
1380 * random path movement and returns it.
1381 * \param l A Lua context.
1382 * \param index An index in the stack.
1383 * \return The movement.
1384 */
check_random_path_movement(lua_State * l,int index)1385 std::shared_ptr<RandomPathMovement> LuaContext::check_random_path_movement(lua_State* l, int index) {
1386 return std::static_pointer_cast<RandomPathMovement>(check_userdata(
1387 l, index, movement_random_path_module_name
1388 ));
1389 }
1390
1391 /**
1392 * \brief Returns whether a value is a userdata of type random path movement.
1393 * \param l A Lua context.
1394 * \param index An index in the stack.
1395 * \return \c true if the value at this index is a random path movement.
1396 */
is_random_path_movement(lua_State * l,int index)1397 bool LuaContext::is_random_path_movement(lua_State* l, int index) {
1398 return is_userdata(l, index, movement_random_path_module_name);
1399 }
1400
1401 /**
1402 * \brief Implementation of random_path_movement:get_speed().
1403 * \param l The Lua context that is calling this function.
1404 * \return Number of values to return to Lua.
1405 */
random_path_movement_api_get_speed(lua_State * l)1406 int LuaContext::random_path_movement_api_get_speed(lua_State* l) {
1407
1408 return state_boundary_handle(l, [&] {
1409 const RandomPathMovement& movement = *check_random_path_movement(l, 1);
1410 lua_pushinteger(l, movement.get_speed());
1411 return 1;
1412 });
1413 }
1414
1415 /**
1416 * \brief Implementation of random_path_movement:get_angle().
1417 * \param l The Lua context that is calling this function.
1418 * \return Number of values to return to Lua.
1419 */
random_path_movement_api_get_angle(lua_State * l)1420 int LuaContext::random_path_movement_api_get_angle(lua_State* l) {
1421 return state_boundary_handle(l, [&] {
1422 const PathMovement& movement = *check_random_path_movement(l,1);
1423 lua_pushnumber(l,movement.get_angle());
1424 return 1;
1425 });
1426 }
1427
1428
1429 /**
1430 * \brief Implementation of random_path_movement:set_speed().
1431 * \param l The Lua context that is calling this function.
1432 * \return Number of values to return to Lua.
1433 */
random_path_movement_api_set_speed(lua_State * l)1434 int LuaContext::random_path_movement_api_set_speed(lua_State* l) {
1435
1436 return state_boundary_handle(l, [&] {
1437 RandomPathMovement& movement = *check_random_path_movement(l, 1);
1438 int speed = LuaTools::check_int(l, 2);
1439 movement.set_speed(speed);
1440 return 0;
1441 });
1442 }
1443
1444 /**
1445 * \brief Returns whether a value is a userdata of type path finding movement.
1446 * \param l A Lua context.
1447 * \param index An index in the stack.
1448 * \return \c true if the value at this index is a path finding movement.
1449 */
is_path_finding_movement(lua_State * l,int index)1450 bool LuaContext::is_path_finding_movement(lua_State* l, int index) {
1451 return is_userdata(l, index, movement_path_finding_module_name);
1452 }
1453
1454 /**
1455 * \brief Checks that the userdata at the specified index of the stack is a
1456 * path finding movement and returns it.
1457 * \param l A Lua context.
1458 * \param index An index in the stack.
1459 * \return The movement.
1460 */
check_path_finding_movement(lua_State * l,int index)1461 std::shared_ptr<PathFindingMovement> LuaContext::check_path_finding_movement(lua_State* l, int index) {
1462 return std::static_pointer_cast<PathFindingMovement>(check_userdata(
1463 l, index, movement_path_finding_module_name
1464 ));
1465 }
1466
1467 /**
1468 * \brief Implementation of path_finding_movement:set_target().
1469 * \param l The Lua context that is calling this function.
1470 * \return Number of values to return to Lua.
1471 */
path_finding_movement_api_set_target(lua_State * l)1472 int LuaContext::path_finding_movement_api_set_target(lua_State* l) {
1473
1474 return state_boundary_handle(l, [&] {
1475 PathFindingMovement& movement = *check_path_finding_movement(l, 1);
1476 EntityPtr target = check_entity(l, 2);
1477
1478 movement.set_target(target);
1479
1480 return 0;
1481 });
1482 }
1483
1484 /**
1485 * \brief Implementation of path_finding_movement:get_speed().
1486 * \param l The Lua context that is calling this function.
1487 * \return Number of values to return to Lua.
1488 */
path_finding_movement_api_get_speed(lua_State * l)1489 int LuaContext::path_finding_movement_api_get_speed(lua_State* l) {
1490
1491 return state_boundary_handle(l, [&] {
1492 const PathFindingMovement& movement = *check_path_finding_movement(l, 1);
1493 lua_pushinteger(l, movement.get_speed());
1494 return 1;
1495 });
1496 }
1497
1498 /**
1499 * \brief Implementation of path_finding_movement:get_angle().
1500 * \param l The Lua context that is calling this function.
1501 * \return Number of values to return to Lua.
1502 */
path_finding_movement_api_get_angle(lua_State * l)1503 int LuaContext::path_finding_movement_api_get_angle(lua_State* l) {
1504 return state_boundary_handle(l, [&] {
1505 const PathMovement& movement = *check_path_finding_movement(l,1);
1506 lua_pushnumber(l,movement.get_angle());
1507 return 1;
1508 });
1509 }
1510
1511
1512 /**
1513 * \brief Implementation of path_finding_movement:set_speed().
1514 * \param l The Lua context that is calling this function.
1515 * \return Number of values to return to Lua.
1516 */
path_finding_movement_api_set_speed(lua_State * l)1517 int LuaContext::path_finding_movement_api_set_speed(lua_State* l) {
1518
1519 return state_boundary_handle(l, [&] {
1520 PathFindingMovement& movement = *check_path_finding_movement(l, 1);
1521 int speed = LuaTools::check_int(l, 2);
1522 movement.set_speed(speed);
1523 return 0;
1524 });
1525 }
1526
1527 /**
1528 * \brief Returns whether a value is a userdata of type circle movement.
1529 * \param l A Lua context.
1530 * \param index An index in the stack.
1531 * \return \c true if the value at this index is a circle movement.
1532 */
is_circle_movement(lua_State * l,int index)1533 bool LuaContext::is_circle_movement(lua_State* l, int index) {
1534 return is_userdata(l, index, movement_circle_module_name);
1535 }
1536
1537 /**
1538 * \brief Checks that the userdata at the specified index of the stack is a
1539 * circle movement and returns it.
1540 * \param l a Lua context
1541 * \param index An index in the stack.
1542 * \return The movement.
1543 */
check_circle_movement(lua_State * l,int index)1544 std::shared_ptr<CircleMovement> LuaContext::check_circle_movement(lua_State* l, int index) {
1545 return std::static_pointer_cast<CircleMovement>(check_userdata(
1546 l, index, movement_circle_module_name
1547 ));
1548 }
1549
1550 /**
1551 * \brief Implementation of circle_movement:get_center().
1552 * \param l The Lua context that is calling this function.
1553 * \return Number of values to return to Lua.
1554 */
circle_movement_api_get_center(lua_State * l)1555 int LuaContext::circle_movement_api_get_center(lua_State* l) {
1556
1557 return state_boundary_handle(l, [&] {
1558 const CircleMovement& movement = *check_circle_movement(l, 1);
1559
1560 const Point& xy = movement.get_center();
1561 lua_pushinteger(l, xy.x);
1562 lua_pushinteger(l, xy.y);
1563 return 2;
1564 });
1565 }
1566
1567 /**
1568 * \brief Implementation of circle_movement:set_center().
1569 * \param l The Lua context that is calling this function.
1570 * \return Number of values to return to Lua.
1571 */
circle_movement_api_set_center(lua_State * l)1572 int LuaContext::circle_movement_api_set_center(lua_State* l) {
1573
1574 return state_boundary_handle(l, [&] {
1575 CircleMovement& movement = *check_circle_movement(l, 1);
1576 if (lua_isnumber(l, 2)) {
1577 // the center is a fixed point
1578 int x = LuaTools::check_int(l, 2);
1579 int y = LuaTools::check_int(l, 3);
1580 movement.set_center(Point(x, y));
1581 }
1582 else {
1583 // the center is an entity
1584
1585 EntityPtr center = check_entity(l, 2);
1586 int dx = LuaTools::opt_int(l, 3, 0);
1587 int dy = LuaTools::opt_int(l, 4, 0);
1588 movement.set_center(center, dx, dy);
1589 }
1590
1591 return 0;
1592 });
1593 }
1594
1595 /**
1596 * \brief Implementation of circle_movement:get_radius().
1597 * \param l The Lua context that is calling this function.
1598 * \return Number of values to return to Lua.
1599 */
circle_movement_api_get_radius(lua_State * l)1600 int LuaContext::circle_movement_api_get_radius(lua_State* l) {
1601
1602 return state_boundary_handle(l, [&] {
1603 const CircleMovement& movement = *check_circle_movement(l, 1);
1604 lua_pushinteger(l, movement.get_radius());
1605 return 1;
1606 });
1607 }
1608
1609 /**
1610 * \brief Implementation of circle_movement:set_radius().
1611 * \param l The Lua context that is calling this function.
1612 * \return Number of values to return to Lua.
1613 */
circle_movement_api_set_radius(lua_State * l)1614 int LuaContext::circle_movement_api_set_radius(lua_State* l) {
1615
1616 return state_boundary_handle(l, [&] {
1617 CircleMovement& movement = *check_circle_movement(l, 1);
1618 int radius = LuaTools::check_int(l, 2);
1619 movement.set_radius(radius);
1620 return 0;
1621 });
1622 }
1623
1624 /**
1625 * \brief Implementation of circle_movement:get_radius_speed().
1626 * \param l The Lua context that is calling this function.
1627 * \return Number of values to return to Lua.
1628 */
circle_movement_api_get_radius_speed(lua_State * l)1629 int LuaContext::circle_movement_api_get_radius_speed(lua_State* l) {
1630
1631 return state_boundary_handle(l, [&] {
1632 const CircleMovement& movement = *check_circle_movement(l, 1);
1633 lua_pushinteger(l, movement.get_radius_speed());
1634 return 1;
1635 });
1636 }
1637
1638 /**
1639 * \brief Implementation of circle_movement:set_radius_speed().
1640 * \param l The Lua context that is calling this function.
1641 * \return Number of values to return to Lua.
1642 */
circle_movement_api_set_radius_speed(lua_State * l)1643 int LuaContext::circle_movement_api_set_radius_speed(lua_State* l) {
1644
1645 return state_boundary_handle(l, [&] {
1646 CircleMovement& movement = *check_circle_movement(l, 1);
1647 int radius_speed = LuaTools::check_int(l, 2);
1648 movement.set_radius_speed(radius_speed);
1649 return 0;
1650 });
1651 }
1652
1653 /**
1654 * \brief Implementation of circle_movement:is_clockwise().
1655 * \param l The Lua context that is calling this function.
1656 * \return Number of values to return to Lua.
1657 */
circle_movement_api_is_clockwise(lua_State * l)1658 int LuaContext::circle_movement_api_is_clockwise(lua_State* l) {
1659
1660 return state_boundary_handle(l, [&] {
1661 const CircleMovement& movement = *check_circle_movement(l, 1);
1662 lua_pushboolean(l, movement.is_clockwise());
1663 return 1;
1664 });
1665 }
1666
1667 /**
1668 * \brief Implementation of circle_movement:set_clockwise().
1669 * \param l The Lua context that is calling this function.
1670 * \return Number of values to return to Lua.
1671 */
circle_movement_api_set_clockwise(lua_State * l)1672 int LuaContext::circle_movement_api_set_clockwise(lua_State* l) {
1673
1674 return state_boundary_handle(l, [&] {
1675 CircleMovement& movement = *check_circle_movement(l, 1);
1676 bool clockwise = LuaTools::opt_boolean(l, 2, true);
1677
1678 movement.set_clockwise(clockwise);
1679
1680 return 0;
1681 });
1682 }
1683
1684 /**
1685 * \brief Implementation of circle_movement:get_angle_from_center().
1686 * \param l The Lua context that is calling this function.
1687 * \return Number of values to return to Lua.
1688 */
circle_movement_api_get_angle_from_center(lua_State * l)1689 int LuaContext::circle_movement_api_get_angle_from_center(lua_State* l) {
1690
1691 return state_boundary_handle(l, [&] {
1692 const CircleMovement& movement = *check_circle_movement(l, 1);
1693 lua_pushnumber(l, movement.get_angle_from_center());
1694 return 1;
1695 });
1696 }
1697
1698 /**
1699 * \brief Implementation of circle_movement:get_initial_angle().
1700 * \param l The Lua context that is calling this function.
1701 * \return Number of values to return to Lua.
1702 */
circle_movement_api_get_initial_angle(lua_State * l)1703 int LuaContext::circle_movement_api_get_initial_angle(lua_State* l) {
1704
1705 return state_boundary_handle(l, [&] {
1706
1707 get().warning_deprecated(
1708 { 1, 6 },
1709 "circle_movement:get_initial_angle()",
1710 "Use circle_movement:get_angle_from_center() in radians instead."
1711 );
1712
1713 const CircleMovement& movement = *check_circle_movement(l, 1);
1714 int degrees = Geometry::radians_to_degrees(movement.get_initial_angle());
1715 lua_pushinteger(l, degrees);
1716 return 1;
1717 });
1718 }
1719
1720 /**
1721 * \brief Implementation of circle_movement:set_angle_from_center().
1722 * \param l The Lua context that is calling this function.
1723 * \return Number of values to return to Lua.
1724 */
circle_movement_api_set_angle_from_center(lua_State * l)1725 int LuaContext::circle_movement_api_set_angle_from_center(lua_State* l) {
1726
1727 return state_boundary_handle(l, [&] {
1728 CircleMovement& movement = *check_circle_movement(l, 1);
1729 double angle_from_center = LuaTools::check_number(l, 2);
1730 movement.set_angle_from_center(angle_from_center);
1731 return 0;
1732 });
1733 }
1734
1735 /**
1736 * \brief Implementation of circle_movement:set_initial_angle().
1737 * \param l The Lua context that is calling this function.
1738 * \return Number of values to return to Lua.
1739 */
circle_movement_api_set_initial_angle(lua_State * l)1740 int LuaContext::circle_movement_api_set_initial_angle(lua_State* l) {
1741
1742 return state_boundary_handle(l, [&] {
1743
1744 get().warning_deprecated(
1745 { 1, 6 },
1746 "circle_movement:set_initial_angle()",
1747 "Use circle_movement:set_angle_from_center() in radians instead."
1748 );
1749
1750 CircleMovement& movement = *check_circle_movement(l, 1);
1751 int initial_angle_degrees = LuaTools::check_int(l, 2);
1752 movement.set_angle_from_center(Geometry::degrees_to_radians(initial_angle_degrees));
1753 return 0;
1754 });
1755 }
1756
1757 /**
1758 * \brief Implementation of circle_movement:get_angular_speed().
1759 * \param l The Lua context that is calling this function.
1760 * \return Number of values to return to Lua.
1761 */
circle_movement_api_get_angular_speed(lua_State * l)1762 int LuaContext::circle_movement_api_get_angular_speed(lua_State* l) {
1763
1764 return state_boundary_handle(l, [&] {
1765 const CircleMovement& movement = *check_circle_movement(l, 1);
1766
1767 lua_pushnumber(l, movement.get_angular_speed());
1768 return 1;
1769 });
1770 }
1771
1772 /**
1773 * \brief Implementation of circle_movement:get_angle_speed().
1774 * \param l The Lua context that is calling this function.
1775 * \return Number of values to return to Lua.
1776 */
circle_movement_api_get_angle_speed(lua_State * l)1777 int LuaContext::circle_movement_api_get_angle_speed(lua_State* l) {
1778
1779 return state_boundary_handle(l, [&] {
1780
1781 get().warning_deprecated(
1782 { 1, 6 },
1783 "circle_movement:get_angle_speed()",
1784 "Use circle_movement:get_angular_speed() in radians instead."
1785 );
1786
1787 const CircleMovement& movement = *check_circle_movement(l, 1);
1788
1789 int degrees_per_second = Geometry::radians_to_degrees(movement.get_angular_speed());
1790
1791 lua_pushinteger(l, degrees_per_second);
1792 return 1;
1793 });
1794 }
1795
1796 /**
1797 * \brief Implementation of circle_movement:set_angular_speed().
1798 * \param l The Lua context that is calling this function.
1799 * \return Number of values to return to Lua.
1800 */
circle_movement_api_set_angular_speed(lua_State * l)1801 int LuaContext::circle_movement_api_set_angular_speed(lua_State* l) {
1802
1803 return state_boundary_handle(l, [&] {
1804 CircleMovement& movement = *check_circle_movement(l, 1);
1805 double angular_speed = LuaTools::check_number(l, 2);
1806
1807 movement.set_angular_speed(angular_speed);
1808
1809 return 0;
1810 });
1811 }
1812
1813 /**
1814 * \brief Implementation of circle_movement:set_angle_speed().
1815 * \param l The Lua context that is calling this function.
1816 * \return Number of values to return to Lua.
1817 */
circle_movement_api_set_angle_speed(lua_State * l)1818 int LuaContext::circle_movement_api_set_angle_speed(lua_State* l) {
1819
1820 return state_boundary_handle(l, [&] {
1821
1822 get().warning_deprecated(
1823 { 1, 6 },
1824 "circle_movement:set_angle_speed()",
1825 "Use circle_movement:set_angular_speed() in radians instead."
1826 );
1827
1828 CircleMovement& movement = *check_circle_movement(l, 1);
1829 int angle_speed_degrees = LuaTools::check_int(l, 2);
1830
1831 movement.set_angular_speed(Geometry::degrees_to_radians(angle_speed_degrees));
1832
1833 return 0;
1834 });
1835 }
1836
1837 /**
1838 * \brief Implementation of circle_movement:get_max_rotations().
1839 * \param l The Lua context that is calling this function.
1840 * \return Number of values to return to Lua.
1841 */
circle_movement_api_get_max_rotations(lua_State * l)1842 int LuaContext::circle_movement_api_get_max_rotations(lua_State* l) {
1843
1844 return state_boundary_handle(l, [&] {
1845 const CircleMovement& movement = *check_circle_movement(l, 1);
1846 lua_pushinteger(l, movement.get_max_rotations());
1847 return 1;
1848 });
1849 }
1850
1851 /**
1852 * \brief Implementation of circle_movement:set_max_rotations().
1853 * \param l The Lua context that is calling this function.
1854 * \return Number of values to return to Lua.
1855 */
circle_movement_api_set_max_rotations(lua_State * l)1856 int LuaContext::circle_movement_api_set_max_rotations(lua_State* l) {
1857
1858 return state_boundary_handle(l, [&] {
1859 CircleMovement& movement = *check_circle_movement(l, 1);
1860 int max_rotations = LuaTools::check_int(l, 2);
1861 movement.set_max_rotations(max_rotations);
1862 return 0;
1863 });
1864 }
1865
1866 /**
1867 * \brief Implementation of circle_movement:get_duration().
1868 * \param l The Lua context that is calling this function.
1869 * \return Number of values to return to Lua.
1870 */
circle_movement_api_get_duration(lua_State * l)1871 int LuaContext::circle_movement_api_get_duration(lua_State* l) {
1872
1873 return state_boundary_handle(l, [&] {
1874 const CircleMovement& movement = *check_circle_movement(l, 1);
1875 lua_pushinteger(l, movement.get_duration());
1876 return 1;
1877 });
1878 }
1879
1880 /**
1881 * \brief Implementation of circle_movement:set_duration().
1882 * \param l The Lua context that is calling this function.
1883 * \return Number of values to return to Lua.
1884 */
circle_movement_api_set_duration(lua_State * l)1885 int LuaContext::circle_movement_api_set_duration(lua_State* l) {
1886
1887 return state_boundary_handle(l, [&] {
1888 CircleMovement& movement = *check_circle_movement(l, 1);
1889 int duration = LuaTools::check_int(l, 2);
1890 movement.set_duration(duration);
1891 return 0;
1892 });
1893 }
1894
1895 /**
1896 * \brief Implementation of circle_movement:get_loop_delay().
1897 * \param l The Lua context that is calling this function.
1898 * \return Number of values to return to Lua.
1899 */
circle_movement_api_get_loop_delay(lua_State * l)1900 int LuaContext::circle_movement_api_get_loop_delay(lua_State* l) {
1901
1902 return state_boundary_handle(l, [&] {
1903 const CircleMovement& movement = *check_circle_movement(l, 1);
1904 lua_pushinteger(l, movement.get_loop());
1905 return 1;
1906 });
1907 }
1908
1909 /**
1910 * \brief Implementation of circle_movement:set_loop_delay().
1911 * \param l The Lua context that is calling this function.
1912 * \return Number of values to return to Lua.
1913 */
circle_movement_api_set_loop_delay(lua_State * l)1914 int LuaContext::circle_movement_api_set_loop_delay(lua_State* l) {
1915
1916 return state_boundary_handle(l, [&] {
1917 CircleMovement& movement = *check_circle_movement(l, 1);
1918 int loop_delay = LuaTools::check_int(l, 2);
1919 movement.set_loop(loop_delay);
1920 return 0;
1921 });
1922 }
1923
1924 /**
1925 * \brief Returns whether a value is a userdata of type jump movement.
1926 * \param l A Lua context.
1927 * \param index An index in the stack.
1928 * \return \c true if the value at this index is a jump movement.
1929 */
is_jump_movement(lua_State * l,int index)1930 bool LuaContext::is_jump_movement(lua_State* l, int index) {
1931 return is_userdata(l, index, movement_jump_module_name);
1932 }
1933
1934 /**
1935 * \brief Checks that the userdata at the specified index of the stack is a
1936 * jump movement and returns it.
1937 * \param l A Lua context.
1938 * \param index An index in the stack.
1939 * \return The movement.
1940 */
check_jump_movement(lua_State * l,int index)1941 std::shared_ptr<JumpMovement> LuaContext::check_jump_movement(lua_State* l, int index) {
1942 return std::static_pointer_cast<JumpMovement>(check_userdata(
1943 l, index, movement_jump_module_name
1944 ));
1945 }
1946
1947 /**
1948 * \brief Implementation of jump_movement:get_direction8().
1949 * \param l The Lua context that is calling this function.
1950 * \return Number of values to return to Lua.
1951 */
jump_movement_api_get_direction8(lua_State * l)1952 int LuaContext::jump_movement_api_get_direction8(lua_State* l) {
1953
1954 return state_boundary_handle(l, [&] {
1955 const JumpMovement& movement = *check_jump_movement(l, 1);
1956 lua_pushinteger(l, movement.get_direction8());
1957 return 1;
1958 });
1959 }
1960
1961 /**
1962 * \brief Implementation of jump_movement:set_direction8().
1963 * \param l The Lua context that is calling this function.
1964 * \return Number of values to return to Lua.
1965 */
jump_movement_api_set_direction8(lua_State * l)1966 int LuaContext::jump_movement_api_set_direction8(lua_State* l) {
1967
1968 return state_boundary_handle(l, [&] {
1969 JumpMovement& movement = *check_jump_movement(l, 1);
1970 int direction8 = LuaTools::check_int(l, 2);
1971 movement.set_direction8(direction8);
1972 return 0;
1973 });
1974 }
1975
1976 /**
1977 * \brief Implementation of jump_movement:get_distance().
1978 * \param l The Lua context that is calling this function.
1979 * \return Number of values to return to Lua.
1980 */
jump_movement_api_get_distance(lua_State * l)1981 int LuaContext::jump_movement_api_get_distance(lua_State* l) {
1982
1983 return state_boundary_handle(l, [&] {
1984 const JumpMovement& movement = *check_jump_movement(l, 1);
1985 lua_pushinteger(l, movement.get_distance());
1986 return 1;
1987 });
1988 }
1989
1990 /**
1991 * \brief Implementation of jump_movement:set_distance().
1992 * \param l The Lua context that is calling this function.
1993 * \return Number of values to return to Lua.
1994 */
jump_movement_api_set_distance(lua_State * l)1995 int LuaContext::jump_movement_api_set_distance(lua_State* l) {
1996
1997 return state_boundary_handle(l, [&] {
1998 JumpMovement& movement = *check_jump_movement(l, 1);
1999 int distance = LuaTools::check_int(l, 2);
2000 movement.set_distance(distance);
2001 return 0;
2002 });
2003 }
2004
2005 /**
2006 * \brief Implementation of jump_movement:get_speed().
2007 * \param l The Lua context that is calling this function.
2008 * \return Number of values to return to Lua.
2009 */
jump_movement_api_get_speed(lua_State * l)2010 int LuaContext::jump_movement_api_get_speed(lua_State* l) {
2011
2012 return state_boundary_handle(l, [&] {
2013 const JumpMovement& movement = *check_jump_movement(l, 1);
2014 lua_pushinteger(l, movement.get_speed());
2015 return 1;
2016 });
2017 }
2018
2019 /**
2020 * \brief Implementation of jump_movement:set_speed().
2021 * \param l The Lua context that is calling this function.
2022 * \return Number of values to return to Lua.
2023 */
jump_movement_api_set_speed(lua_State * l)2024 int LuaContext::jump_movement_api_set_speed(lua_State* l) {
2025
2026 return state_boundary_handle(l, [&] {
2027 JumpMovement& movement = *check_jump_movement(l, 1);
2028 int speed = LuaTools::check_int(l, 2);
2029 movement.set_speed(speed);
2030 return 0;
2031 });
2032 }
2033
2034 /**
2035 * \brief Returns whether a value is a userdata of type pixel movement.
2036 * \param l A Lua context.
2037 * \param index An index in the stack.
2038 * \return \c true if the value at this index is a pixel movement.
2039 */
is_pixel_movement(lua_State * l,int index)2040 bool LuaContext::is_pixel_movement(lua_State* l, int index) {
2041 return is_userdata(l, index, movement_pixel_module_name);
2042 }
2043
2044 /**
2045 * \brief Checks that the userdata at the specified index of the stack is a
2046 * pixel movement and returns it.
2047 * \param l A Lua context.
2048 * \param index An index in the stack.
2049 * \return The movement.
2050 */
check_pixel_movement(lua_State * l,int index)2051 std::shared_ptr<PixelMovement> LuaContext::check_pixel_movement(lua_State* l, int index) {
2052 return std::static_pointer_cast<PixelMovement>(check_userdata(
2053 l, index, movement_pixel_module_name
2054 ));
2055 }
2056
2057 /**
2058 * \brief Implementation of pixel_movement:get_trajectory().
2059 * \param l The Lua context that is calling this function.
2060 * \return Number of values to return to Lua.
2061 */
pixel_movement_api_get_trajectory(lua_State * l)2062 int LuaContext::pixel_movement_api_get_trajectory(lua_State* l) {
2063
2064 return state_boundary_handle(l, [&] {
2065 const PixelMovement& movement = *check_pixel_movement(l, 1);
2066
2067 const std::list<Point>& trajectory = movement.get_trajectory();
2068 // build a Lua array containing the trajectory
2069 lua_settop(l, 1);
2070 lua_newtable(l);
2071 int i = 1;
2072 for (const Point& xy: trajectory) {
2073 lua_newtable(l);
2074 lua_pushinteger(l, xy.x);
2075 lua_rawseti(l, 3, 1);
2076 lua_pushinteger(l, xy.y);
2077 lua_rawseti(l, 3, 2);
2078 lua_rawseti(l, 2, i);
2079 ++i;
2080 }
2081
2082 return 1;
2083 });
2084 }
2085
2086 /**
2087 * \brief Implementation of pixel_movement:set_trajectory().
2088 * \param l The Lua context that is calling this function.
2089 * \return Number of values to return to Lua.
2090 */
pixel_movement_api_set_trajectory(lua_State * l)2091 int LuaContext::pixel_movement_api_set_trajectory(lua_State* l) {
2092
2093 return state_boundary_handle(l, [&] {
2094 PixelMovement& movement = *check_pixel_movement(l, 1);
2095 LuaTools::check_type(l, 2, LUA_TTABLE);
2096
2097 // build the trajectory as a string from the Lua table
2098 std::list<Point> trajectory;
2099 lua_pushnil(l); // first key
2100 while (lua_next(l, 2) != 0) {
2101 LuaTools::check_type(l, 4, LUA_TTABLE);
2102 lua_rawgeti(l, 4, 1);
2103 lua_rawgeti(l, 4, 2);
2104 int x = LuaTools::check_int(l, 5);
2105 int y = LuaTools::check_int(l, 6);
2106 trajectory.emplace_back(x, y);
2107 lua_settop(l, 3); // let the key for the iteration
2108 }
2109 movement.set_trajectory(trajectory);
2110
2111 return 0;
2112 });
2113 }
2114
2115 /**
2116 * \brief Implementation of pixel_movement:get_loop().
2117 * \param l The Lua context that is calling this function.
2118 * \return Number of values to return to Lua.
2119 */
pixel_movement_api_get_loop(lua_State * l)2120 int LuaContext::pixel_movement_api_get_loop(lua_State* l) {
2121
2122 return state_boundary_handle(l, [&] {
2123 const PixelMovement& movement = *check_pixel_movement(l, 1);
2124 lua_pushboolean(l, movement.get_loop());
2125 return 1;
2126 });
2127 }
2128
2129 /**
2130 * \brief Implementation of pixel_movement:set_loop().
2131 * \param l The Lua context that is calling this function.
2132 * \return Number of values to return to Lua.
2133 */
pixel_movement_api_set_loop(lua_State * l)2134 int LuaContext::pixel_movement_api_set_loop(lua_State* l) {
2135
2136 return state_boundary_handle(l, [&] {
2137 PixelMovement& movement = *check_pixel_movement(l, 1);
2138 bool loop = LuaTools::opt_boolean(l, 2, true);
2139
2140 movement.set_loop(loop);
2141
2142 return 0;
2143 });
2144 }
2145
2146 /**
2147 * \brief Implementation of pixel_movement:get_delay().
2148 * \param l The Lua context that is calling this function.
2149 * \return Number of values to return to Lua.
2150 */
pixel_movement_api_get_delay(lua_State * l)2151 int LuaContext::pixel_movement_api_get_delay(lua_State* l) {
2152
2153 return state_boundary_handle(l, [&] {
2154 const PixelMovement& movement = *check_pixel_movement(l, 1);
2155 lua_pushinteger(l, movement.get_delay());
2156 return 1;
2157 });
2158 }
2159
2160 /**
2161 * \brief Implementation of pixel_movement:set_delay().
2162 * \param l The Lua context that is calling this function.
2163 * \return Number of values to return to Lua.
2164 */
pixel_movement_api_set_delay(lua_State * l)2165 int LuaContext::pixel_movement_api_set_delay(lua_State* l) {
2166
2167 return state_boundary_handle(l, [&] {
2168 PixelMovement& movement = *check_pixel_movement(l, 1);
2169 uint32_t delay = uint32_t(LuaTools::check_int(l, 2));
2170 movement.set_delay(delay);
2171 return 0;
2172 });
2173 }
2174
2175 /**
2176 * \brief Calls the on_position_changed() method of a Lua movement.
2177 *
2178 * Does nothing if the method is not defined.
2179 *
2180 * \param movement A movement.
2181 * \param xy The new coordinates.
2182 */
movement_on_position_changed(Movement & movement,const Point & xy)2183 void LuaContext::movement_on_position_changed(
2184 Movement& movement, const Point& xy) {
2185
2186 run_on_main([this,&movement,&xy](lua_State* current_l){
2187 // ...
2188 push_movement(current_l, movement);
2189 // ... movement
2190 lua_getfield(current_l, LUA_REGISTRYINDEX, "sol.movements_on_points");
2191 // ... movement movements
2192 lua_pushvalue(current_l, -2);
2193 // ... movement movements movement
2194 lua_gettable(current_l, -2);
2195 // ... movement movements xy/nil
2196 if (!lua_isnil(current_l, -1)) {
2197 // ... movement movements xy
2198 lua_pushinteger(current_l, xy.x);
2199 // ... movement movements xy x
2200 lua_setfield(current_l, -2, "x");
2201 // ... movement movements xy
2202 lua_pushinteger(current_l, xy.y);
2203 // ... movement movements xy y
2204 lua_setfield(current_l, -2, "y");
2205 // ... movement movements xy
2206 }
2207 lua_pop(current_l, 2);
2208 // ... movement
2209 if (userdata_has_field(movement, "on_position_changed")) {
2210 on_position_changed(xy);
2211 }
2212 lua_pop(current_l, 1);
2213 });
2214 }
2215
2216 /**
2217 * \brief Calls the on_obstacle_reached() method of a Lua movement.
2218 *
2219 * Does nothing if the method is not defined.
2220 *
2221 * \param movement A movement.
2222 */
movement_on_obstacle_reached(Movement & movement)2223 void LuaContext::movement_on_obstacle_reached(Movement& movement) {
2224
2225 if (!userdata_has_field(movement, "on_obstacle_reached")) {
2226 return;
2227 }
2228
2229 run_on_main([this,&movement](lua_State* l){
2230 push_movement(l, movement);
2231 on_obstacle_reached();
2232 lua_pop(l, 1);
2233 });
2234 }
2235
2236 /**
2237 * \brief Calls the on_changed() method of a Lua movement.
2238 *
2239 * Does nothing if the method is not defined.
2240 *
2241 * \param movement A movement.
2242 */
movement_on_changed(Movement & movement)2243 void LuaContext::movement_on_changed(Movement& movement) {
2244
2245 if (!userdata_has_field(movement, "on_changed")) {
2246 return;
2247 }
2248
2249 run_on_main([this,&movement](lua_State* l){
2250 push_movement(l, movement);
2251 on_changed();
2252 lua_pop(l, 1);
2253 });
2254 }
2255
2256 /**
2257 * \brief Calls the on_finished() method of a Lua movement.
2258 *
2259 * Does nothing if the method is not defined.
2260 *
2261 * \param movement A movement.
2262 */
movement_on_finished(Movement & movement)2263 void LuaContext::movement_on_finished(Movement& movement) {
2264
2265 if (!userdata_has_field(movement, "on_finished")) {
2266 return;
2267 }
2268
2269 run_on_main([this,&movement](lua_State* l){
2270 push_movement(l, movement);
2271 on_finished();
2272 lua_pop(l, 1);
2273 });
2274 }
2275
2276 }
2277
2278