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