1 /*
2 * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3 *
4 * Solarus is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Solarus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "solarus/audio/Sound.h"
18 #include "solarus/core/Debug.h"
19 #include "solarus/core/CommandsEffects.h"
20 #include "solarus/core/Equipment.h"
21 #include "solarus/core/EquipmentItem.h"
22 #include "solarus/core/Game.h"
23 #include "solarus/core/Geometry.h"
24 #include "solarus/core/Map.h"
25 #include "solarus/core/System.h"
26 #include "solarus/entities/Block.h"
27 #include "solarus/entities/Bomb.h"
28 #include "solarus/entities/Boomerang.h"
29 #include "solarus/entities/Chest.h"
30 #include "solarus/entities/Crystal.h"
31 #include "solarus/entities/Destination.h"
32 #include "solarus/entities/Destructible.h"
33 #include "solarus/entities/Enemy.h"
34 #include "solarus/entities/Entities.h"
35 #include "solarus/entities/GroundInfo.h"
36 #include "solarus/entities/Hero.h"
37 #include "solarus/entities/Jumper.h"
38 #include "solarus/entities/Sensor.h"
39 #include "solarus/entities/Stairs.h"
40 #include "solarus/entities/Stream.h"
41 #include "solarus/entities/StreamAction.h"
42 #include "solarus/entities/Switch.h"
43 #include "solarus/entities/Teletransporter.h"
44 #include "solarus/graphics/Sprite.h"
45 #include "solarus/hero/BackToSolidGroundState.h"
46 #include "solarus/hero/BoomerangState.h"
47 #include "solarus/hero/BowState.h"
48 #include "solarus/hero/CarryingState.h"
49 #include "solarus/hero/CustomState.h"
50 #include "solarus/hero/FallingState.h"
51 #include "solarus/hero/ForcedWalkingState.h"
52 #include "solarus/hero/FreeState.h"
53 #include "solarus/hero/FrozenState.h"
54 #include "solarus/hero/GrabbingState.h"
55 #include "solarus/hero/HeroSprites.h"
56 #include "solarus/hero/HookshotState.h"
57 #include "solarus/hero/HurtState.h"
58 #include "solarus/hero/JumpingState.h"
59 #include "solarus/hero/LiftingState.h"
60 #include "solarus/hero/PlungingState.h"
61 #include "solarus/hero/PullingState.h"
62 #include "solarus/hero/PushingState.h"
63 #include "solarus/hero/RunningState.h"
64 #include "solarus/hero/StairsState.h"
65 #include "solarus/hero/SwordLoadingState.h"
66 #include "solarus/hero/SwordSwingingState.h"
67 #include "solarus/hero/SwimmingState.h"
68 #include "solarus/hero/TreasureState.h"
69 #include "solarus/hero/UsingItemState.h"
70 #include "solarus/hero/VictoryState.h"
71 #include "solarus/lua/LuaContext.h"
72 #include "solarus/lua/LuaTools.h"
73 #include "solarus/movements/StraightMovement.h"
74 #include <lua.hpp>
75 #include <algorithm>
76 #include <sstream>
77 #include <utility>
78
79 namespace Solarus {
80
81 namespace {
82
83 /**
84 * \brief Implementation of the callback used to return solid ground coordinates.
85 * \param l A Lua state.
86 * \return Number of values to return to Lua.
87 */
l_solid_ground_callback(lua_State * l)88 int l_solid_ground_callback(lua_State* l) {
89
90 int x = LuaTools::check_int(l, lua_upvalueindex(1));
91 int y = LuaTools::check_int(l, lua_upvalueindex(2));
92 int layer = LuaTools::check_int(l, lua_upvalueindex(3));
93
94 lua_pushinteger(l, x);
95 lua_pushinteger(l, y);
96 lua_pushinteger(l, layer);
97 return 3;
98 }
99
100 }
101
102 /**
103 * \brief Creates a hero.
104 * \param equipment the equipment (needed to build the sprites even outside a game)
105 */
Hero(Equipment & equipment)106 Hero::Hero(Equipment& equipment):
107 Entity("hero", 0, 0, Point(0, 0), Size(16, 16)),
108 invincible(false),
109 end_invincible_date(0),
110 normal_walking_speed(88),
111 walking_speed(normal_walking_speed),
112 delayed_teletransporter(nullptr),
113 on_raised_blocks(false),
114 last_solid_ground_coords(0, 0),
115 last_solid_ground_layer(0),
116 target_solid_ground_callback(),
117 next_ground_date(0),
118 next_ice_date(0),
119 ice_movement_direction8(0) {
120
121 // position
122 set_origin(8, 13);
123 last_solid_ground_coords = { -1, -1 };
124 last_solid_ground_layer = 0;
125
126 // sprites
127 set_drawn_in_y_order(true);
128 sprites = std::unique_ptr<HeroSprites>(new HeroSprites(*this, equipment));
129 }
130
131 /**
132 * \brief Returns the type of entity.
133 * \return the type of entity
134 */
get_type() const135 EntityType Hero::get_type() const {
136 return ThisType;
137 }
138
139 /**
140 * \brief Returns the item currently carried by the hero, if any.
141 *
142 * This function is used internally to allow this item to be preserved between
143 * different hero states.
144 *
145 * \return The carried object or nullptr.
146 */
get_carried_object()147 std::shared_ptr<CarriedObject> Hero::get_carried_object() {
148 return get_state()->get_carried_object();
149 }
150
151 /**
152 * \brief Suspends or resumes the animation and the movements of the hero.
153 *
154 * This function is called by the map when the game is suspended or resumed.
155 *
156 * \param suspended true to suspend the hero, false to resume it
157 */
set_suspended(bool suspended)158 void Hero::set_suspended(bool suspended) {
159
160 Entity::set_suspended(suspended);
161
162 if (!suspended) {
163
164 uint32_t diff = System::now() - get_when_suspended();
165 next_ground_date += diff;
166
167 if (end_invincible_date != 0) {
168 end_invincible_date += diff;
169 }
170 }
171
172 sprites->set_suspended(suspended);
173 get_state()->set_suspended(suspended);
174 }
175
176 /**
177 * \brief Updates the hero's position, movement and animation.
178 *
179 * This function is called repeatedly by the game loop.
180 */
update()181 void Hero::update() {
182
183 update_invincibility();
184 update_movement();
185 update_direction();
186 sprites->update();
187
188 // Update the state now because it may be impacted by movements and sprites.
189 update_state();
190
191 if (!is_suspended()) {
192 update_ground_effects();
193 check_collision_with_detectors();
194 check_gameover();
195 }
196 }
197
198 /**
199 * \brief Updates the sprites direction according to the wanted movement direction.
200 */
update_direction()201 void Hero::update_direction() {
202
203 int wanted_direction8 = get_wanted_movement_direction8();
204 if (wanted_direction8 == -1) {
205 return;
206 }
207
208 int old_animation_direction = sprites->get_animation_direction();
209 int animation_direction = sprites->get_animation_direction(wanted_direction8, get_real_movement_direction8());
210
211 if (animation_direction != old_animation_direction
212 && animation_direction != -1
213 && !is_direction_locked()) {
214 // If the direction defined by the directional keys has changed,
215 // update the sprite's direction of animation
216 // (unless the direction is locked).
217 sprites->set_animation_direction(animation_direction);
218 }
219 }
220
221 /**
222 * \brief Updates the hero's position according to its movement.
223 *
224 * This function is called repeatedly by update().
225 */
update_movement()226 void Hero::update_movement() {
227
228 if (!get_map().is_loaded()) {
229 // Can happen during transitions.
230 return;
231 }
232
233 if (on_raised_blocks && !get_state()->is_touching_ground()) {
234 // If the hero was already over raised blocks, keep it that way while he
235 // is not touching ground.
236 }
237 else {
238 on_raised_blocks = get_entities().overlaps_raised_blocks(get_layer(), get_bounding_box());
239 }
240
241 if (get_movement() != nullptr) {
242 get_movement()->update();
243 }
244 // TODO clear_old_movements() is missing
245
246 update_stream_action();
247 }
248
249 /**
250 * \brief Updates the effects (if any) of the ground below the hero.
251 *
252 * This function is called repeatedly.
253 */
update_ground_effects()254 void Hero::update_ground_effects() {
255
256 // see if it's time to do something (depending on the ground)
257 uint32_t now = System::now();
258 if (now >= next_ground_date) {
259
260 if (is_ground_visible() && get_movement() != nullptr) {
261
262 // a special ground is displayed under the hero and it's time to play a sound
263 const std::shared_ptr<StraightMovement> movement =
264 std::dynamic_pointer_cast<StraightMovement>(get_movement());
265 if (movement != nullptr) {
266 // TODO replace the dynamic_pointer_cast by a virtual method get_speed() in Movement.
267 double speed = movement->get_speed();
268 next_ground_date = now + std::max(150, (int) (20000 / speed));
269 if (sprites->is_walking() && get_state()->is_touching_ground()) {
270 sprites->play_ground_sound();
271 }
272 }
273 }
274
275 else {
276
277 Ground ground = get_ground_below();
278 if (ground == Ground::HOLE && !get_state()->can_avoid_hole()) {
279 // the hero is being attracted by a hole and it's time to move one more pixel into the hole
280
281 next_ground_date = now + 60;
282
283 if (get_distance(last_solid_ground_coords) >= 8) {
284 // too far from the solid ground: make the hero fall
285 set_walking_speed(normal_walking_speed);
286 set_state(std::make_shared<FallingState>(*this));
287 }
288 else {
289 // not too far yet
290 apply_additional_ground_movement();
291 }
292 }
293 else if (ground == Ground::ICE) {
294
295 // Slide on ice.
296 if (!get_state()->can_avoid_ice()) {
297 apply_additional_ground_movement();
298 }
299
300 next_ground_date = now + 30;
301
302 if (now >= next_ice_date) {
303 // Time to update the additional movement.
304 update_ice();
305 ice_movement_direction8 = get_wanted_movement_direction8();
306 }
307 }
308 }
309 }
310 }
311
312 /**
313 * \brief Updates the additional movement applied when the hero is on ice ground.
314 */
update_ice()315 void Hero::update_ice() {
316
317 uint32_t now = System::now();
318 int wanted_movement_direction8 = get_wanted_movement_direction8();
319 if (wanted_movement_direction8 == -1) {
320 // The player wants to stop.
321 if (ice_movement_direction8 == -1) {
322 // And he does for a while so stop.
323 ground_dxy = { 0, 0 };
324 next_ice_date = now + 300;
325 }
326 else {
327 // But he was just moving on ice: continue the ice movement.
328 ground_dxy = direction_to_xy_move(ice_movement_direction8) * 2;
329 next_ice_date = now + 300;
330 }
331 }
332 else {
333 // The player wants to move.
334 if (ice_movement_direction8 == -1) {
335 // But he was not just moving on ice: resist to the wanted movement.
336 ground_dxy = direction_to_xy_move((wanted_movement_direction8 + 4) % 8);
337 next_ice_date = now + 300;
338 }
339 else if (ice_movement_direction8 != wanted_movement_direction8) {
340 // He changed his direction: continue the ice movement strongly.
341 ground_dxy = direction_to_xy_move(ice_movement_direction8) * 2;
342 next_ice_date = now + 300;
343 }
344 else {
345 // He continues in the same direction.
346 ground_dxy = direction_to_xy_move(wanted_movement_direction8);
347 next_ice_date = now + 300;
348 }
349 }
350 }
351
352 /**
353 * \brief Stops the additional movement applied when the hero is on ice ground.
354 */
stop_ice_movement()355 void Hero::stop_ice_movement() {
356
357 ice_movement_direction8 = 0;
358 ground_dxy = { 0, 0 };
359 }
360
361 /**
362 * \brief Changes the position of the hero as an effect of his current ground
363 * (like hole or ice).
364 */
apply_additional_ground_movement()365 void Hero::apply_additional_ground_movement() {
366
367 if (ground_dxy.x == 0 && ground_dxy.y == 0) {
368 return;
369 }
370
371 bool moved = false;
372 Rectangle collision_box = get_bounding_box();
373 collision_box.add_xy(ground_dxy);
374
375 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
376 set_bounding_box(collision_box);
377 notify_position_changed();
378 moved = true;
379 }
380
381 if (!moved && ground_dxy.x != 0) { // try x only
382 collision_box = get_bounding_box();
383 collision_box.add_xy(ground_dxy.x, 0);
384 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
385 set_bounding_box(collision_box);
386 notify_position_changed();
387 moved = true;
388 }
389 }
390
391 if (!moved && ground_dxy.y != 0) { // try y only
392 collision_box = get_bounding_box();
393 collision_box.add_xy(0, ground_dxy.y);
394 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
395 set_bounding_box(collision_box);
396 notify_position_changed();
397 moved = true;
398 }
399 }
400
401 if (!moved) {
402 if (get_ground_below() == Ground::HOLE) {
403 // the hero cannot be moved towards the direction previously calculated
404 set_walking_speed(normal_walking_speed);
405 set_state(std::make_shared<FallingState>(*this));
406 }
407 }
408 }
409
410 /**
411 * \brief Checks that the hero has still some life.
412 *
413 * If his life reaches zero, this function starts the gameover sequence.
414 */
check_gameover()415 void Hero::check_gameover() {
416
417 if (get_equipment().get_life() <= 0 &&
418 get_state()->can_start_gameover_sequence()) {
419 sprites->stop_blinking();
420 get_game().start_game_over();
421 }
422 }
423
424 /**
425 * \copydoc Entity::built_in_draw
426 */
built_in_draw(Camera &)427 void Hero::built_in_draw(Camera& /* camera */) {
428
429 get_state()->draw_on_map();
430 }
431
432 /**
433 * \brief This function is called when a low-level input event occurs.
434 * \param event The event to handle.
435 * \return \c true if the event was handled.
436 * If \c false, notify_command_pressed/released() can then still be called
437 * if they apply.
438 */
notify_input(const InputEvent & event)439 bool Hero::notify_input(const InputEvent& event) {
440 return get_state()->notify_input(event);
441 }
442
443 /**
444 * \brief This function is called when a game command is pressed
445 * and the game is not suspended.
446 * \param command The command pressed.
447 */
notify_command_pressed(GameCommand command)448 void Hero::notify_command_pressed(GameCommand command) {
449 get_state()->notify_command_pressed(command);
450 }
451
452 /**
453 * \brief This function is called when a game command is released
454 * if the game is not suspended.
455 * \param command The command released.
456 */
notify_command_released(GameCommand command)457 void Hero::notify_command_released(GameCommand command) {
458 get_state()->notify_command_released(command);
459 }
460
461 /**
462 * \brief Returns the sprites currently representing the hero.
463 * \return the sprites
464 */
get_hero_sprites() const465 const HeroSprites& Hero::get_hero_sprites() const {
466 return *sprites;
467 }
468
469 /**
470 * \overload Non-const version.
471 */
get_hero_sprites()472 HeroSprites& Hero::get_hero_sprites() {
473 return *sprites;
474 }
475
476 /**
477 * \brief Returns the direction of the hero's sprites.
478 *
479 * It is different from the movement direction.
480 *
481 * \return the direction of the sprites (0 to 3)
482 */
get_animation_direction() const483 int Hero::get_animation_direction() const {
484 return sprites->get_animation_direction();
485 }
486
487 /**
488 * \brief Changes the direction of the hero's sprites.
489 *
490 * It is different from the movement direction.
491 *
492 * \param direction4 the direction to set (0 to 3)
493 */
set_animation_direction(int direction4)494 void Hero::set_animation_direction(int direction4) {
495 sprites->set_animation_direction(direction4);
496 }
497
498 /**
499 * \brief Returns whether the sprites animations are finished.
500 * \return true if the animation is finished
501 */
is_animation_finished() const502 bool Hero::is_animation_finished() const {
503 return sprites->is_animation_finished();
504 }
505
506 /**
507 * \brief Loads (or reloads) the sprites and sounds of the hero and his equipment.
508 *
509 * The sprites and sounds depend on its tunic, sword and shield as specified in the savegame.
510 * This function must be called at the game beginning
511 * and as soon as the hero's equipment is changed.
512 */
rebuild_equipment()513 void Hero::rebuild_equipment() {
514
515 sprites->rebuild_equipment();
516 }
517
518 /**
519 * \brief Returns whether the shadow should be currently displayed, separate from the tunic sprite.
520 * \return true if the shadow should be currently displayed.
521 */
is_shadow_visible() const522 bool Hero::is_shadow_visible() const {
523 return get_displayed_xy().y != get_y();
524 }
525
526 /**
527 * \copydoc Entity::notify_creating
528 */
notify_creating()529 void Hero::notify_creating() {
530
531 Entity::notify_creating();
532 get_hero_sprites().notify_creating();
533
534 // At this point the map is known and loaded. Notify the state.
535 get_state()->set_map(get_map());
536 }
537
538 /**
539 * \copydoc Entity::notify_map_starting
540 */
notify_map_starting(Map & map,const std::shared_ptr<Destination> & destination)541 void Hero::notify_map_starting(Map& map, const std::shared_ptr<Destination>& destination) {
542
543 Entity::notify_map_starting(map, destination);
544
545 // At this point the map is known and loaded. Notify the state.
546 get_state()->set_map(get_map());
547 }
548
549 /**
550 * \copydoc Entity::notify_map_started
551 */
notify_map_started(Map & map,const std::shared_ptr<Destination> & destination)552 void Hero::notify_map_started(Map& map, const std::shared_ptr<Destination>& destination) {
553
554 Entity::notify_map_started(map, destination);
555 get_state()->notify_map_started(map, destination);
556 }
557
558 /**
559 * \copydoc Entity::notify_map_opening_transition_finishing
560 */
notify_map_opening_transition_finishing(Map & map,const std::shared_ptr<Destination> & destination)561 void Hero::notify_map_opening_transition_finishing(Map& map, const std::shared_ptr<Destination>& destination) {
562
563 Entity::notify_map_opening_transition_finishing(map, destination);
564
565 int side = get_map().get_destination_side();
566 if (side != -1) {
567 // the hero was placed on the side of the map:
568 // there was a scrolling between the previous map and this one
569
570 switch (side) {
571
572 case 0: // right side
573 set_x(get_map().get_width() - 8);
574 break;
575
576 case 1: // top side
577 set_y(13);
578 break;
579
580 case 2: // left side
581 set_x(8);
582 break;
583
584 case 3: // bottom side
585 set_y(get_map().get_height() - 3);
586 break;
587
588 default:
589 Debug::die("Invalid destination side");
590 }
591 }
592 check_position();
593 if (get_state()->is_touching_ground()) { // Don't change the state during stairs.
594 start_state_from_ground();
595 }
596 }
597
598 /**
599 * \copydoc Entity::notify_map_opening_transition_finished
600 */
notify_map_opening_transition_finished(Map & map,const std::shared_ptr<Destination> & destination)601 void Hero::notify_map_opening_transition_finished(Map& map, const std::shared_ptr<Destination>& destination) {
602
603 Entity::notify_map_opening_transition_finished(map, destination);
604 get_state()->notify_map_opening_transition_finished(map, destination);
605 }
606
607 /**
608 * \copydoc Entity::notify_map_finished
609 */
notify_map_finished()610 void Hero::notify_map_finished() {
611
612 Entity::notify_map_finished();
613 get_state()->notify_map_finished();
614 }
615
616 /**
617 * \copydoc Entity::notify_tileset_changed
618 */
notify_tileset_changed()619 void Hero::notify_tileset_changed() {
620
621 Entity::notify_tileset_changed();
622 get_hero_sprites().notify_tileset_changed();
623 }
624
625 /**
626 * \brief Puts the hero on a map.
627 *
628 * This function is called when the current map is changed.
629 * Does nothing if the hero is already on this map.
630 *
631 * \param map The map.
632 */
place_on_map(Map & map)633 void Hero::place_on_map(Map& map) {
634
635 if (is_on_map() &&
636 &get_map() == &map
637 ) {
638 // No change.
639 return;
640 }
641
642 // Add the hero to the map.
643 const HeroPtr& shared_hero = std::static_pointer_cast<Hero>(shared_from_this());
644 map.get_entities().add_entity(shared_hero);
645
646 last_solid_ground_coords = { -1, -1 };
647 last_solid_ground_layer = 0;
648 reset_target_solid_ground_callback();
649 get_hero_sprites().set_clipping_rectangle();
650
651 get_state()->set_map(map);
652
653 Entity::set_map(map);
654 }
655
656 /**
657 * \brief Places the hero on the map specified and at its destination point selected.
658 * \param map The new map.
659 * \param previous_map_location Position of the previous map in its world
660 * (because the previous map is already destroyed).
661 */
place_on_destination(Map & map,const Rectangle & previous_map_location)662 void Hero::place_on_destination(Map& map, const Rectangle& previous_map_location) {
663
664 const std::string& destination_name = map.get_destination_name();
665
666 if (destination_name == "_same") {
667
668 // The hero's coordinates are the same as on the previous map
669 // but 1) we need to take into account the location of both maps
670 // and 2) we may have to change the layer.
671
672 const Rectangle& next_map_location = map.get_location();
673 int x = get_x() - next_map_location.get_x() + previous_map_location.get_x();
674 int y = get_y() - next_map_location.get_y() + previous_map_location.get_y();
675
676 int layer = map.get_max_layer();
677 while (layer > map.get_min_layer() &&
678 map.get_ground(layer, x, y, this) == Ground::EMPTY) {
679 // TODO check the whole hero's bounding box rather than just a point.
680 --layer;
681 }
682 place_on_map(map);
683 set_xy(x, y);
684 map.get_entities().notify_entity_bounding_box_changed(*this);
685 map.get_entities().set_entity_layer(*this, layer);
686 last_solid_ground_coords = { x, y };
687 last_solid_ground_layer = get_layer();
688
689 start_free();
690 check_position(); // To appear initially swimming, for example.
691 }
692 else {
693 int side = map.get_destination_side();
694
695 if (side != -1) {
696
697 // Go to a side of the other map.
698 int layer = get_layer();
699 if (!map.is_valid_layer(layer)) {
700 std::ostringstream oss;
701 oss << "Layer " << layer << " does not exist on map '" << map.get_id()
702 + "'. Placing the hero on layer 0 instead.";
703 Debug::error(oss.str());
704 layer = 0;
705 set_layer(layer);
706 }
707 place_on_map(map);
708
709 switch (side) {
710
711 case 0: // Right side.
712 set_x(map.get_width());
713 set_y(get_y() - map.get_location().get_y() + previous_map_location.get_y());
714 break;
715
716 case 1: // Top side.
717 set_y(5);
718 set_x(get_x() - map.get_location().get_x() + previous_map_location.get_x());
719 break;
720
721 case 2: // Left side.
722 set_x(0);
723 set_y(get_y() - map.get_location().get_y() + previous_map_location.get_y());
724 break;
725
726 case 3: // Bottom side.
727 set_y(map.get_height() + 5);
728 set_x(get_x() - map.get_location().get_x() + previous_map_location.get_x());
729 break;
730
731 default:
732 Debug::die("Invalid destination side");
733 }
734 map.get_entities().notify_entity_bounding_box_changed(*this);
735 map.get_entities().set_entity_layer(*this, layer);
736 last_solid_ground_coords = get_xy();
737 last_solid_ground_layer = get_layer();
738
739 // Note that we keep the hero's state from the previous map.
740 check_position(); // Correctly initialize the ground.
741 }
742 else {
743
744 // Normal case: the location is specified by a destination point object.
745
746 const std::shared_ptr<Destination> destination = map.get_destination();
747
748 if (destination == nullptr) {
749 // This is embarrassing: there is no valid destination that we can use.
750 // The map is probably in an early development phase.
751 // For now, let's place the hero at the top-left corner of the map.
752 Debug::error(
753 std::string("No valid destination on map '") + map.get_id()
754 + "'. Placing the hero at (0,0) instead."
755 );
756 place_on_map(map);
757 sprites->set_animation_direction(3);
758 set_top_left_xy(0, 0);
759 map.get_entities().notify_entity_bounding_box_changed(*this);
760 map.get_entities().set_entity_layer(*this, map.get_max_layer());
761 }
762 else {
763 // Normal case.
764 place_on_map(map);
765 if (destination->get_direction() != -1) {
766 sprites->set_animation_direction(destination->get_direction());
767 }
768 set_xy(destination->get_xy());
769 map.get_entities().notify_entity_bounding_box_changed(*this);
770 map.get_entities().set_entity_layer(*this, destination->get_layer());
771 }
772 last_solid_ground_coords = get_xy();
773 last_solid_ground_layer = get_layer();
774
775 // Remove boomerangs in case the map remains the same.
776 const std::set<std::shared_ptr<Boomerang>>& boomerangs =
777 map.get_entities().get_entities_by_type<Boomerang>();
778 for (const std::shared_ptr<Boomerang>& boomerang : boomerangs) {
779 boomerang->remove_from_map();
780 }
781
782 if (destination != nullptr) {
783 get_lua_context()->destination_on_activated(*destination);
784 }
785
786 const std::shared_ptr<const Stairs> stairs = get_stairs_overlapping();
787 if (stairs != nullptr) {
788 // The hero arrived on the map by stairs.
789 set_state(std::make_shared<StairsState>(*this, stairs, Stairs::REVERSE_WAY));
790 }
791 else {
792 // The hero arrived on the map by a usual destination point.
793 start_free();
794 check_position(); // To appear initially swimming, for example.
795 }
796 }
797 }
798 }
799
800 /**
801 * \copydoc Entity::get_facing_point
802 *
803 * TODO remove this override
804 */
get_facing_point() const805 Point Hero::get_facing_point() const {
806
807 return get_touching_point(get_animation_direction());
808 }
809
810 /**
811 * \copydoc Entity::notify_facing_entity_changed
812 */
notify_facing_entity_changed(Entity * facing_entity)813 void Hero::notify_facing_entity_changed(Entity* facing_entity) {
814
815 CommandsEffects& commands_effects = get_commands_effects();
816 if (facing_entity != nullptr) {
817 if (facing_entity->can_be_lifted() &&
818 is_free() &&
819 commands_effects.get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE) {
820 commands_effects.set_action_key_effect(CommandsEffects::ACTION_KEY_LIFT);
821 }
822 }
823 else {
824 // No more facing entity.
825 if (commands_effects.is_action_key_acting_on_facing_entity()) {
826 // The hero just stopped facing an entity that was showing an action icon.
827 commands_effects.set_action_key_effect(CommandsEffects::ACTION_KEY_NONE);
828 }
829 }
830 }
831
832 /**
833 * \brief Returns whether there is an obstacle in front of the hero.
834 *
835 * This function returns whether he is touching an obstacle that
836 * is just in front of him.
837 * Note that even if this function returns true, the hero
838 * may still be able to move in that direction due to the possibly sliding movement.
839 * This information is calculated and not stored, so it is
840 * always up to date.
841 *
842 * \return true if the hero is facing an obstacle
843 */
is_facing_obstacle()844 bool Hero::is_facing_obstacle() {
845
846 Rectangle collision_box = get_bounding_box();
847 switch (sprites->get_animation_direction()) {
848
849 case 0:
850 collision_box.add_x(1);
851 break;
852
853 case 1:
854 collision_box.add_y(-1);
855 break;
856
857 case 2:
858 collision_box.add_x(-1);
859 break;
860
861 case 3:
862 collision_box.add_y(1);
863 break;
864
865 default:
866 Debug::die("Invalid animation direction");
867 break;
868 }
869
870 return get_map().test_collision_with_obstacles(get_layer(), collision_box, *this);
871 }
872
873 /**
874 * \brief Returns whether the facing point of the hero is overlapping an obstacle.
875 *
876 * This function returns whether his facing point is overlapping an obstacle of the map.
877 * This information is calculated and not stored, so it is always up to date.
878 *
879 * \return true if the facing point is overlapping an obstacle
880 */
is_facing_point_on_obstacle()881 bool Hero::is_facing_point_on_obstacle() {
882
883 const Point& facing_point = get_facing_point();
884 return get_map().test_collision_with_obstacles(
885 get_layer(), facing_point, *this);
886 }
887
888 /**
889 * \brief Returns whether the hero is looking towards the specified direction.
890 * \param direction4 a direction (0 to 3)
891 * \return true if the hero is looking towards the specified direction
892 */
is_facing_direction4(int direction4) const893 bool Hero::is_facing_direction4(int direction4) const {
894 return get_animation_direction() == direction4;
895 }
896
897 /**
898 * \brief Returns whether the hero is looking towards the specified direction.
899 * \param direction8 a direction (0 to 7)
900 * \return true if the hero is looking towards the specified direction
901 * (always false for diagonal directions)
902 */
is_facing_direction8(int direction8) const903 bool Hero::is_facing_direction8(int direction8) const {
904 return get_animation_direction() * 2 == direction8;
905 }
906
907 /**
908 * \brief Returns whether the hero is currently on raised crystal blocks.
909 * \return true if the hero is currently on raised crystal blocks
910 */
is_on_raised_blocks() const911 bool Hero::is_on_raised_blocks() const {
912 return on_raised_blocks;
913 }
914
915 /**
916 * \brief Returns the stairs the hero may be currently overlapping.
917 * \return the stairs the hero is currently overlapping, or nullptr
918 */
get_stairs_overlapping() const919 std::shared_ptr<const Stairs> Hero::get_stairs_overlapping() const {
920
921 std::set<std::shared_ptr<const Stairs>> all_stairs =
922 get_entities().get_entities_by_type<Stairs>(get_layer());
923 for (const std::shared_ptr<const Stairs>& stairs: all_stairs) {
924
925 if (overlaps(*stairs)) {
926 return stairs;
927 }
928 }
929
930 return nullptr;
931 }
932
933 /**
934 * \brief Returns whether the player can control his movements in the current state.
935 * \return true if the player can control his movements
936 */
can_control_movement() const937 bool Hero::can_control_movement() const {
938
939 if (has_stream_action()
940 && !get_stream_action()->get_stream().get_allow_movement()) {
941 // A stream prevents the control.
942 return false;
943 }
944
945 return get_state()->get_can_control_movement();
946 }
947
948 /**
949 * \brief Returns the speed applied to the walking movement on normal ground.
950 * \return The normal walking speed in pixels per second.
951 */
get_normal_walking_speed() const952 int Hero::get_normal_walking_speed() const {
953 return normal_walking_speed;
954 }
955
956 /**
957 * \brief Sets the speed applied to the walking movement on normal ground.
958 * \param normal_walking_speed The normal walking speed to set in pixels per second.
959 */
set_normal_walking_speed(int normal_walking_speed)960 void Hero::set_normal_walking_speed(int normal_walking_speed) {
961
962 bool was_normal = (this->walking_speed == this->normal_walking_speed);
963 this->normal_walking_speed = normal_walking_speed;
964 if (was_normal) {
965 set_walking_speed(normal_walking_speed);
966 }
967 }
968
969 /**
970 * \brief Returns the current speed applied to the hero's movements when he is walking.
971 * \return The current walking speed.
972 */
get_walking_speed() const973 int Hero::get_walking_speed() const {
974 return walking_speed;
975 }
976
977 /**
978 * \brief Sets the speed to apply to the hero's movements when he is walking.
979 * \param walking_speed the new walking speed
980 */
set_walking_speed(int walking_speed)981 void Hero::set_walking_speed(int walking_speed) {
982
983 if (walking_speed != this->walking_speed) {
984 this->walking_speed = walking_speed;
985 get_state()->notify_walking_speed_changed();
986 }
987 }
988
989 /**
990 * \brief Returns the direction of the hero's movement as defined by the controls applied by the player.
991 *
992 * If he is not moving, -1 is returned.
993 * This direction may be different from the real movement direction because of obstacles.
994 *
995 * \return the hero's wanted direction between 0 and 7, or -1 if he is stopped
996 */
get_wanted_movement_direction8() const997 int Hero::get_wanted_movement_direction8() const {
998 return get_state()->get_wanted_movement_direction8();
999 }
1000
1001 /**
1002 * \brief Returns the actual direction of the hero's movement.
1003 *
1004 * This function returns the actual direction of the hero's movement, which can be different from the one
1005 * defined by the directional keys pressed by the player because we consider obstacles here.
1006 * If he does not want to move, -1 is returned. If he is trying to move but cannot because of obstacles,
1007 * the direction he is trying to move toward is returned.
1008 * This function is not used to compute the hero's movement (PlayerMovement does that) but only
1009 * to decide what direction to give to its sprites once the movement is already computed.
1010 *
1011 * \return the hero's actual direction between 0 and 7, or -1 if he is stopped
1012 */
get_real_movement_direction8()1013 int Hero::get_real_movement_direction8() {
1014
1015 int result;
1016
1017 int wanted_direction8 = get_wanted_movement_direction8();
1018 if (wanted_direction8 == -1) {
1019 // the hero does not want to move
1020 result = -1;
1021 }
1022 else {
1023 // the hero wants to move
1024
1025 Rectangle collision_box(get_bounding_box());
1026
1027 // if we can move towards the wanted direction, no problem
1028 Point xy_move = direction_to_xy_move(wanted_direction8);
1029 collision_box.add_xy(xy_move);
1030 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1031 result = wanted_direction8;
1032 }
1033 else {
1034 // otherwise, see if he can move in one of the two closest directions (i.e. he is sliding)
1035
1036 int alternative_direction8 = (wanted_direction8 + 1) % 8;
1037 collision_box = get_bounding_box();
1038 xy_move = direction_to_xy_move(alternative_direction8);
1039 collision_box.add_xy(xy_move);
1040 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1041 result = alternative_direction8;
1042 }
1043 else {
1044 alternative_direction8 = (wanted_direction8 - 1) % 8;
1045 collision_box = get_bounding_box();
1046 xy_move = direction_to_xy_move(alternative_direction8);
1047 collision_box.add_xy(xy_move);
1048 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1049 result = alternative_direction8;
1050 }
1051 else {
1052 // he is not sliding, he wants to move but can't
1053 result = wanted_direction8;
1054 }
1055 }
1056 }
1057 }
1058
1059 return result;
1060 }
1061
1062 /**
1063 * \brief Returns whether the hero is moving towards the specified direction
1064 * among the four main directions.
1065 *
1066 * If the hero is not moving, false is returned.
1067 * If he is making a diagonal move, this function considers that he is moving
1068 * towards both directions.
1069 *
1070 * \param direction4 One of the four main directions (0 to 3).
1071 * \return \c true if the hero is moving in that direction,
1072 * even if he is actually doing a diagonal move.
1073 */
is_moving_towards(int direction4) const1074 bool Hero::is_moving_towards(int direction4) const {
1075
1076 const std::shared_ptr<const Movement>& movement = get_movement();
1077 if (movement == nullptr || movement->is_stopped()) {
1078 return false;
1079 }
1080
1081 int direction8 = direction4 * 2;
1082 int movement_direction8 = get_wanted_movement_direction8();
1083
1084 return movement_direction8 != -1
1085 && (movement_direction8 == direction8
1086 || (movement_direction8 + 1) % 8 == direction8
1087 || (movement_direction8 + 7) % 8 == direction8);
1088 }
1089
1090 /**
1091 * \brief Returns whether the animation direction is locked.
1092 *
1093 * When this function returns false, which is the case most of the time,
1094 * it means that the animation direction is set to the movement direction.
1095 * When it returns true, it means that the animation direction is fixed
1096 * and do not depends on the movement direction anymore (this is the case
1097 * when the hero is loading his sword).
1098 *
1099 * \return true if the animation direction is locked
1100 */
is_direction_locked() const1101 bool Hero::is_direction_locked() const {
1102 return get_state()->is_direction_locked();
1103 }
1104
1105 /**
1106 * \brief This function is called when the hero's position is changed.
1107 */
notify_position_changed()1108 void Hero::notify_position_changed() {
1109
1110 if (is_on_map()) {
1111 get_entities().notify_entity_bounding_box_changed(*this);
1112 }
1113
1114 check_position();
1115 get_state()->notify_position_changed();
1116
1117 if (are_movement_notifications_enabled()) {
1118 get_lua_context()->entity_on_position_changed(*this, get_xy(), get_layer());
1119 }
1120 }
1121
1122 /**
1123 * \brief This function is called when the layer of this entity has just changed.
1124 */
notify_layer_changed()1125 void Hero::notify_layer_changed() {
1126 get_state()->notify_layer_changed();
1127 }
1128
1129 /**
1130 * \brief Notifies this entity that it has just failed to change its position
1131 * because of obstacles.
1132 */
notify_obstacle_reached()1133 void Hero::notify_obstacle_reached() {
1134
1135 Entity::notify_obstacle_reached();
1136
1137 get_state()->notify_obstacle_reached();
1138
1139 if (get_ground_below() == Ground::ICE) {
1140 ground_dxy = { 0, 0 };
1141 ice_movement_direction8 = -1;
1142 }
1143 }
1144
1145 /**
1146 * \brief This function is called when the movement of the entity starts.
1147 */
notify_movement_started()1148 void Hero::notify_movement_started() {
1149
1150 Entity::notify_movement_started();
1151 get_state()->notify_movement_started();
1152 }
1153
1154 /**
1155 * \brief This function is called when the movement of the entity is finished.
1156 */
notify_movement_finished()1157 void Hero::notify_movement_finished() {
1158
1159 Entity::notify_movement_finished();
1160 get_state()->notify_movement_finished();
1161 }
1162
1163 /**
1164 * \brief Updates the hero depending on its movement.
1165 *
1166 * This function is called when the hero's movement direction changes (for instance
1167 * because the player pressed or released a directional key, or the hero just reached an obstacle).
1168 * It updates the hero's animations and collisions according to the new movement.
1169 */
notify_movement_changed()1170 void Hero::notify_movement_changed() {
1171
1172 update_direction();
1173
1174 // let the state pick the animation corresponding to the movement tried by the player
1175 get_state()->notify_movement_changed();
1176 check_position();
1177
1178 if (get_ground_below() == Ground::ICE) {
1179 update_ice();
1180 }
1181 Entity::notify_movement_changed();
1182 }
1183
1184 /**
1185 * \brief Checks collisions with detectors, determines the facing entity
1186 * and the ground below the hero in its current position.
1187 *
1188 * This function is called when these checks have to be done again,
1189 * e.g. when the position, the direction or the state of the hero changes.
1190 */
check_position()1191 void Hero::check_position() {
1192
1193 if (!is_on_map()) {
1194 return;
1195 }
1196
1197 if (get_state()->are_collisions_ignored()) {
1198 // Do not take care of the ground or detectors.
1199 return;
1200 }
1201
1202 // Recompute the facing entity.
1203 set_facing_entity(nullptr);
1204 check_collision_with_detectors();
1205
1206 if (is_suspended()
1207 && get_map().test_collision_with_border(get_ground_point())) {
1208 // When suspended, the hero may have invalid coordinates
1209 // (e.g. transition between maps).
1210 return;
1211 }
1212
1213 // Determine the new ground if it has changed.
1214 update_ground_below();
1215
1216 // Save the hero's last valid position.
1217 Ground ground = get_ground_below();
1218 if (ground != Ground::DEEP_WATER
1219 && ground != Ground::HOLE
1220 && ground != Ground::LAVA
1221 && ground != Ground::PRICKLE
1222 && ground != Ground::EMPTY
1223 && get_state()->get_can_come_from_bad_ground()
1224 && (get_xy() != last_solid_ground_coords)) {
1225
1226 last_solid_ground_coords = get_xy();
1227 last_solid_ground_layer = get_layer();
1228 }
1229
1230 // With empty ground, possibly go to the lower layer.
1231 if (ground == Ground::EMPTY && get_state()->is_touching_ground()) {
1232
1233 int x = get_top_left_x();
1234 int y = get_top_left_y();
1235 int layer = get_layer();
1236
1237 if (layer > get_map().get_min_layer()
1238 && get_map().get_ground(layer, x, y, this) == Ground::EMPTY
1239 && get_map().get_ground(layer, x + 15, y, this) == Ground::EMPTY
1240 && get_map().get_ground(layer, x, y + 15, this) == Ground::EMPTY
1241 && get_map().get_ground(layer, x + 15, y + 15, this) == Ground::EMPTY) {
1242
1243 get_entities().set_entity_layer(*this, layer - 1);
1244 Ground new_ground = get_map().get_ground(get_layer(), x, y, this);
1245 if (get_state()->is_free() &&
1246 (new_ground == Ground::TRAVERSABLE
1247 || new_ground == Ground::GRASS
1248 || new_ground == Ground::LADDER)) {
1249 Sound::play("hero_lands");
1250 }
1251 }
1252 }
1253 }
1254
1255 /**
1256 * \brief Stops the movement of the player and lets the player restart it when he can.
1257 *
1258 * This function is typically called when the player temporarily loses the control
1259 * (e.g. because of a script or a map change) whereas the movement remains the same.
1260 * Then the movement may want to move a few pixels more as soon as it is resumed.
1261 * This function removes such residual effects of the player's movement.
1262 * If the current movement is not controlled by the player, this function has no effect.
1263 */
reset_movement()1264 void Hero::reset_movement() {
1265
1266 if (can_control_movement()) {
1267 get_movement()->stop();
1268 }
1269 }
1270
1271 /**
1272 * \brief Starts activating the new ground of the hero.
1273 */
notify_ground_below_changed()1274 void Hero::notify_ground_below_changed() {
1275
1276 const bool suspended = get_game().is_suspended();
1277
1278 Entity::notify_ground_below_changed();
1279
1280 sprites->destroy_ground();
1281
1282 switch (get_ground_below()) {
1283
1284 case Ground::TRAVERSABLE:
1285 set_walking_speed(normal_walking_speed);
1286 break;
1287
1288 case Ground::DEEP_WATER:
1289 // Deep water: plunge if the hero is not jumping.
1290 if (!get_state()->can_avoid_deep_water()) {
1291
1292 if (suspended) {
1293 // During a transition, it is okay to start swimming
1294 // but we don't want to start plunging right now.
1295 if (get_state()->is_touching_ground()) {
1296 start_deep_water();
1297 }
1298 }
1299 else {
1300 start_deep_water();
1301 }
1302 }
1303 break;
1304
1305 case Ground::HOLE:
1306 // Hole: fall into the hole or get attracted to it.
1307 // But wait for the teletransporter opening transition to finish if any.
1308 if (!suspended
1309 && !get_state()->can_avoid_hole()) {
1310 start_hole();
1311 }
1312 break;
1313
1314 case Ground::ICE:
1315 // Ice: make the hero slide.
1316 if (!get_state()->can_avoid_ice()) {
1317 start_ice();
1318 }
1319 break;
1320
1321 case Ground::LAVA:
1322 // Lava: plunge into lava.
1323 if (!suspended
1324 && !get_state()->can_avoid_lava()) {
1325 start_lava();
1326 }
1327 break;
1328
1329 case Ground::PRICKLE:
1330 // Prickles.
1331 if (!suspended
1332 && !get_state()->can_avoid_prickle()) {
1333 start_prickle(500);
1334 }
1335 break;
1336
1337 case Ground::SHALLOW_WATER:
1338 if (get_state()->is_affected_by_shallow_water()) {
1339 start_shallow_water();
1340 }
1341 break;
1342
1343 case Ground::GRASS:
1344 if (get_state()->is_affected_by_grass()) {
1345 start_grass();
1346 }
1347 break;
1348
1349 case Ground::LADDER:
1350 if (!suspended &&
1351 get_state()->is_affected_by_ladder()) {
1352 set_walking_speed(normal_walking_speed * 3 / 5);
1353 }
1354 break;
1355
1356 case Ground::WALL:
1357 case Ground::LOW_WALL:
1358 case Ground::WALL_TOP_RIGHT:
1359 case Ground::WALL_TOP_LEFT:
1360 case Ground::WALL_BOTTOM_LEFT:
1361 case Ground::WALL_BOTTOM_RIGHT:
1362 case Ground::WALL_TOP_RIGHT_WATER:
1363 case Ground::WALL_TOP_LEFT_WATER:
1364 case Ground::WALL_BOTTOM_LEFT_WATER:
1365 case Ground::WALL_BOTTOM_RIGHT_WATER:
1366 // The hero is stuck in a wall. Damn.
1367 // This is the fault of the quest maker, unless there is a bug in Solarus.
1368 // The user will have to save and quit his game.
1369 // TODO maybe we could use the back to solid ground mechanism here?
1370 break;
1371
1372 case Ground::EMPTY:
1373 break;
1374 }
1375
1376 // Notify the state.
1377 get_state()->notify_ground_below_changed();
1378 }
1379
1380 /**
1381 * \brief Returns whether the hero is in a state such that
1382 * a ground can be displayed under him.
1383 */
is_ground_visible() const1384 bool Hero::is_ground_visible() const {
1385
1386 Ground ground = get_ground_below();
1387 return (ground == Ground::GRASS || ground == Ground::SHALLOW_WATER)
1388 && get_state()->is_touching_ground();
1389 }
1390
1391 /**
1392 * \brief Returns whether this entity is sensible to the ground below it.
1393 * \return \c true if this entity is sensible to its ground.
1394 */
is_ground_observer() const1395 bool Hero::is_ground_observer() const {
1396 return true;
1397 }
1398
1399 /**
1400 * \brief Returns the last point of solid ground where the hero was.
1401 * \return The last solid ground coordinates, or
1402 * <tt>-1,-1</tt> if the hero never was on solid ground on this map yet.
1403 */
get_last_solid_ground_coords() const1404 const Point& Hero::get_last_solid_ground_coords() const {
1405 return last_solid_ground_coords;
1406 }
1407
1408 /**
1409 * \brief Returns the layer of the last of solid ground where the hero was.
1410 * \return The last solid ground layer, or
1411 * 0 if the hero never was on solid ground on this map yet.
1412 */
get_last_solid_ground_layer() const1413 int Hero::get_last_solid_ground_layer() const {
1414 return last_solid_ground_layer;
1415 }
1416
1417 /**
1418 * \brief Returns the function indicated by the last call to
1419 * set_target_solid_callback().
1420 * \return The Lua function that gives solid ground coordinates, or
1421 * an empty ref if set_target_solid_callback() was not called.
1422 */
get_target_solid_ground_callback() const1423 const ScopedLuaRef& Hero::get_target_solid_ground_callback() const {
1424 return target_solid_ground_callback;
1425 }
1426
1427 /**
1428 * \brief Creates a Lua function that returns the given coordinates and layer.
1429 *
1430 * This function can be used as callback for specifying the solid ground position.
1431 *
1432 * \param xy Coordinates the function should return.
1433 * \param layer Layer the function should return.
1434 * \return Lua ref to a function that returns this solid position.
1435 */
make_solid_ground_callback(const Point & xy,int layer) const1436 ScopedLuaRef Hero::make_solid_ground_callback(
1437 const Point& xy, int layer) const {
1438
1439 LuaContext* lua_context = get_lua_context();
1440 if (lua_context == nullptr) {
1441 return ScopedLuaRef();
1442 }
1443 lua_State* l = lua_context->get_internal_state();
1444
1445 lua_pushinteger(l, xy.x);
1446 lua_pushinteger(l, xy.y);
1447 lua_pushinteger(l, layer);
1448 lua_pushcclosure(l, l_solid_ground_callback, 3);
1449
1450 ScopedLuaRef callback_ref = LuaTools::create_ref(l, -1);
1451 lua_pop(l, 1);
1452 return callback_ref;
1453 }
1454
1455 /**
1456 * \brief Specifies a function indicating where the hero will go back
1457 * if he falls into a hole or some other bad ground.
1458 * \param target_solid_ground_callback A Lua function that gives the
1459 * coordinates and layer of where the hero should go if he falls into
1460 * a hole or some other bad ground.
1461 * An empty ref means returning automatically to the last solid ground
1462 * position.
1463 */
set_target_solid_ground_callback(const ScopedLuaRef & target_solid_ground_callback)1464 void Hero::set_target_solid_ground_callback(
1465 const ScopedLuaRef& target_solid_ground_callback) {
1466
1467 this->target_solid_ground_callback = target_solid_ground_callback;
1468 }
1469
1470 /**
1471 * \brief Forgets the function indicating where the hero was supposed to go
1472 * back if he falls into a hole or some other bad ground.
1473 *
1474 * The hero will now get back to the last solid ground instead of going back
1475 * to a custom position.
1476 */
reset_target_solid_ground_callback()1477 void Hero::reset_target_solid_ground_callback() {
1478
1479 set_target_solid_ground_callback(ScopedLuaRef());
1480 }
1481
1482 /**
1483 * \brief Returns whether this entity is an obstacle for another one.
1484 * \param other another entity
1485 * \return true if this entity is an obstacle for the other one
1486 */
is_obstacle_for(Entity & other)1487 bool Hero::is_obstacle_for(Entity& other) {
1488 return other.is_hero_obstacle(*this);
1489 }
1490
1491 /**
1492 * \copydoc Entity::is_traversable_obstacle
1493 */
is_traversable_obstacle() const1494 bool Hero::is_traversable_obstacle() const {
1495 return get_state()->is_traversable_obstacle();
1496 }
1497
1498 /**
1499 * \copydoc Entity::is_wall_obstacle
1500 */
is_wall_obstacle() const1501 bool Hero::is_wall_obstacle() const {
1502 return get_state()->is_wall_obstacle();
1503 }
1504
1505 /**
1506 * \copydoc Entity::is_low_wall_obstacle
1507 */
is_low_wall_obstacle() const1508 bool Hero::is_low_wall_obstacle() const {
1509 return get_state()->is_low_wall_obstacle();
1510 }
1511
1512 /**
1513 * \copydoc Entity::is_grass_obstacle
1514 */
is_grass_obstacle() const1515 bool Hero::is_grass_obstacle() const {
1516 return get_state()->is_grass_obstacle();
1517 }
1518
1519 /**
1520 * \copydoc Entity::is_shallow_water_obstacle
1521 */
is_shallow_water_obstacle() const1522 bool Hero::is_shallow_water_obstacle() const {
1523 return get_state()->is_shallow_water_obstacle();
1524 }
1525
1526 /**
1527 * \copydoc Entity::is_deep_water_obstacle
1528 */
is_deep_water_obstacle() const1529 bool Hero::is_deep_water_obstacle() const {
1530 return get_state()->is_deep_water_obstacle();
1531 }
1532
1533 /**
1534 * \copydoc Entity::is_hole_obstacle
1535 */
is_hole_obstacle() const1536 bool Hero::is_hole_obstacle() const {
1537 return get_state()->is_hole_obstacle();
1538 }
1539
1540 /**
1541 * \copydoc Entity::is_ice_obstacle
1542 */
is_ice_obstacle() const1543 bool Hero::is_ice_obstacle() const {
1544 return get_state()->is_ice_obstacle();
1545 }
1546
1547 /**
1548 * \copydoc Entity::is_lava_obstacle
1549 */
is_lava_obstacle() const1550 bool Hero::is_lava_obstacle() const {
1551 return get_state()->is_lava_obstacle();
1552 }
1553
1554 /**
1555 * \copydoc Entity::is_prickle_obstacle
1556 */
is_prickle_obstacle() const1557 bool Hero::is_prickle_obstacle() const {
1558 return get_state()->is_prickle_obstacle();
1559 }
1560
1561 /**
1562 * \copydoc Entity::is_ladder_obstacle
1563 */
is_ladder_obstacle() const1564 bool Hero::is_ladder_obstacle() const {
1565 return get_state()->is_ladder_obstacle();
1566 }
1567
1568 /**
1569 * \copydoc Entity::is_hero_obstacle
1570 */
is_hero_obstacle(Hero & hero)1571 bool Hero::is_hero_obstacle(Hero& hero) {
1572 return get_state()->is_hero_obstacle(hero);
1573 }
1574
1575 /**
1576 * \copydoc Entity::is_block_obstacle
1577 */
is_block_obstacle(Block & block)1578 bool Hero::is_block_obstacle(Block& block) {
1579 return get_state()->is_block_obstacle(block);
1580 }
1581
1582 /**
1583 * \copydoc Entity::is_teletransporter_obstacle
1584 */
is_teletransporter_obstacle(Teletransporter & teletransporter)1585 bool Hero::is_teletransporter_obstacle(Teletransporter& teletransporter) {
1586 return get_state()->is_teletransporter_obstacle(teletransporter);
1587 }
1588
1589 /**
1590 * \copydoc Entity::is_stream_obstacle
1591 */
is_stream_obstacle(Stream & stream)1592 bool Hero::is_stream_obstacle(Stream& stream) {
1593 return get_state()->is_stream_obstacle(stream);
1594 }
1595
1596 /**
1597 * \copydoc Entity::is_stairs_obstacle
1598 */
is_stairs_obstacle(Stairs & stairs)1599 bool Hero::is_stairs_obstacle(Stairs& stairs) {
1600 return get_state()->is_stairs_obstacle(stairs);
1601 }
1602
1603 /**
1604 * \copydoc Entity::is_sensor_obstacle
1605 */
is_sensor_obstacle(Sensor & sensor)1606 bool Hero::is_sensor_obstacle(Sensor& sensor) {
1607 return get_state()->is_sensor_obstacle(sensor);
1608 }
1609
1610 /**
1611 * \copydoc Entity::is_switch_obstacle
1612 */
is_switch_obstacle(Switch & sw)1613 bool Hero::is_switch_obstacle(Switch& sw) {
1614 return get_state()->is_switch_obstacle(sw);
1615 }
1616
1617 /**
1618 * \copydoc Entity::is_raised_block_obstacle
1619 */
is_raised_block_obstacle(CrystalBlock & raised_block)1620 bool Hero::is_raised_block_obstacle(CrystalBlock& raised_block) {
1621 return get_state()->is_raised_block_obstacle(raised_block);
1622 }
1623
1624 /**
1625 * \copydoc Entity::is_crystal_obstacle
1626 */
is_crystal_obstacle(Crystal & crystal)1627 bool Hero::is_crystal_obstacle(Crystal& crystal) {
1628 return get_state()->is_crystal_obstacle(crystal);
1629 }
1630
1631 /**
1632 * \copydoc Entity::is_npc_obstacle
1633 */
is_npc_obstacle(Npc & npc)1634 bool Hero::is_npc_obstacle(Npc& npc) {
1635 return get_state()->is_npc_obstacle(npc);
1636 }
1637
1638 /**
1639 * \copydoc Entity::is_door_obstacle
1640 */
is_door_obstacle(Door & door)1641 bool Hero::is_door_obstacle(Door& door) {
1642 return get_state()->is_door_obstacle(door);
1643 }
1644
1645 /**
1646 * \copydoc Entity::is_enemy_obstacle
1647 */
is_enemy_obstacle(Enemy & enemy)1648 bool Hero::is_enemy_obstacle(Enemy& enemy) {
1649 return get_state()->is_enemy_obstacle(enemy);
1650 }
1651
1652 /**
1653 * \copydoc Entity::is_jumper_obstacle
1654 */
is_jumper_obstacle(Jumper & jumper,const Rectangle & candidate_position)1655 bool Hero::is_jumper_obstacle(Jumper& jumper, const Rectangle& candidate_position) {
1656 return get_state()->is_jumper_obstacle(jumper, candidate_position);
1657 }
1658
1659 /**
1660 * \copydoc Entity::is_destructible_obstacle
1661 */
is_destructible_obstacle(Destructible & destructible)1662 bool Hero::is_destructible_obstacle(Destructible& destructible) {
1663 return get_state()->is_destructible_obstacle(destructible);
1664 }
1665
1666 /**
1667 * \copydoc Entity::is_separator_obstacle
1668 */
is_separator_obstacle(Separator & separator,const Rectangle &)1669 bool Hero::is_separator_obstacle(Separator& separator, const Rectangle& /* candidate_position */) {
1670 return get_state()->is_separator_obstacle(separator);
1671 }
1672
1673 /**
1674 * \copydoc Entity::notify_collision_with_destructible
1675 */
notify_collision_with_destructible(Destructible & destructible,CollisionMode collision_mode)1676 void Hero::notify_collision_with_destructible(
1677 Destructible& destructible, CollisionMode collision_mode) {
1678 destructible.notify_collision_with_hero(*this, collision_mode);
1679 }
1680
1681 /**
1682 * \copydoc Enemy::notify_collision_with_enemy(Enemy&, CollisionMode)
1683 */
notify_collision_with_enemy(Enemy & enemy,CollisionMode collision_mode)1684 void Hero::notify_collision_with_enemy(Enemy& enemy, CollisionMode collision_mode) {
1685
1686 if (enemy.get_attacking_collision_mode() != collision_mode) {
1687 // Not the collision mode used to attack the hero.
1688 return;
1689 }
1690 enemy.attack_hero(*this, nullptr);
1691 }
1692
1693 /**
1694 * \copydoc Enemy::notify_collision_with_enemy(Enemy&, Sprite&, Sprite&))
1695 */
notify_collision_with_enemy(Enemy & enemy,Sprite & this_sprite,Sprite & enemy_sprite)1696 void Hero::notify_collision_with_enemy(
1697 Enemy& enemy, Sprite& this_sprite, Sprite& enemy_sprite) {
1698
1699 const std::string& this_sprite_id = this_sprite.get_animation_set_id();
1700 if (this_sprite_id == get_hero_sprites().get_sword_sprite_id()) {
1701 // the hero's sword overlaps the enemy
1702 enemy.try_hurt(EnemyAttack::SWORD, *this, &enemy_sprite);
1703 }
1704 else if (this_sprite_id == get_hero_sprites().get_tunic_sprite_id()) {
1705
1706 if (enemy.get_attacking_collision_mode() != CollisionMode::COLLISION_SPRITE) {
1707 // The enemy does not attack with sprite collisions.
1708 return;
1709 }
1710
1711 // The hero's body sprite overlaps the enemy.
1712 // Check that the 16x16 rectangle of the hero also overlaps the enemy.
1713 const Size& enemy_sprite_size = enemy_sprite.get_size();
1714 const Point& enemy_sprite_origin = enemy_sprite.get_origin();
1715 const Point& enemy_sprite_offset = enemy_sprite.get_xy();
1716 Rectangle enemy_sprite_rectangle(
1717 enemy.get_x() - enemy_sprite_origin.x + enemy_sprite_offset.x,
1718 enemy.get_y() - enemy_sprite_origin.y + enemy_sprite_offset.y,
1719 enemy_sprite_size.width,
1720 enemy_sprite_size.height
1721 );
1722
1723 if (overlaps(enemy_sprite_rectangle)) {
1724 enemy.attack_hero(*this, &enemy_sprite);
1725 }
1726 }
1727 }
1728
1729 /**
1730 * \brief This function is called when a teletransporter detects a collision with the hero.
1731 * \param teletransporter the teletransporter
1732 * \param collision_mode the collision mode that detected the event
1733 */
notify_collision_with_teletransporter(Teletransporter & teletransporter,CollisionMode)1734 void Hero::notify_collision_with_teletransporter(
1735 Teletransporter& teletransporter, CollisionMode /* collision_mode */) {
1736
1737 if (!can_avoid_teletransporter(teletransporter)) {
1738
1739 update_ground_below(); // Make sure the ground is up-to-date.
1740 bool on_hole = get_ground_below() == Ground::HOLE;
1741 if (on_hole || get_state()->is_teletransporter_delayed()) {
1742 // Fall into the hole (or do something else) first, transport later
1743 this->delayed_teletransporter = std::static_pointer_cast<Teletransporter>(
1744 teletransporter.shared_from_this()
1745 );
1746 }
1747 else {
1748 teletransporter.transport_hero(*this); // usual case: transport right now
1749 }
1750 }
1751 }
1752
1753 /**
1754 * \brief Returns a teletransporter that has detected a collision with the hero
1755 * bu will be activated when the current action is finished
1756 * (e.g. falling into a hole or taking stairs).
1757 * \return The delayed teletransporter or nullptr.
1758 */
get_delayed_teletransporter()1759 std::shared_ptr<Teletransporter> Hero::get_delayed_teletransporter() {
1760 return delayed_teletransporter;
1761 }
1762
1763 /**
1764 * \copydoc Entity::notify_collision_with_stream
1765 */
notify_collision_with_stream(Stream & stream,int dx,int dy)1766 void Hero::notify_collision_with_stream(
1767 Stream& stream, int dx, int dy) {
1768
1769 if (has_stream_action()) {
1770 // There is already an active stream.
1771 return;
1772 }
1773
1774 if (get_state()->can_avoid_stream(stream)) {
1775 // Streams are ignored in the current state of the hero.
1776 return;
1777 }
1778
1779 // Check that the feet of the hero are on the stream.
1780 if (!stream.overlaps(get_ground_point())) {
1781 return;
1782 }
1783
1784 bool activate_stream = false;
1785
1786 if (stream.get_allow_movement()) {
1787 // The stream can be forced: there is no risk.
1788 // Even if the stream is faster than the player's movement,
1789 // he can still move perpendicularly.
1790 activate_stream = true;
1791 }
1792 else if (dx != 0 && dy != 0) {
1793 // Case of a diagonal stream.
1794 // TODO Diagonal streams are always activated for now, this could be improved.
1795 activate_stream = true;
1796 }
1797 else {
1798 // This is a blocking stream.
1799 // Check that the hero can go in the stream's direction.
1800 // Otherwise the hero, would be trapped forever if there
1801 // is an obstacle after the stream.
1802 Map& map = get_map();
1803 Rectangle collision_box(0, 0, 16, 16);
1804
1805 // First check that the exit of the stream is clear.
1806 collision_box.set_xy(stream.get_bounding_box().get_xy());
1807 collision_box.add_xy(dx, dy);
1808 if (!map.test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1809 // The stream's exit is clear.
1810 // Check that we can make at least one pixel with the stream.
1811 // Because maybe we have already passed the exit and cannot do more.
1812 const bool horizontal = dx != 0;
1813 if (horizontal) {
1814 collision_box.set_xy(
1815 get_top_left_x() + dx,
1816 get_top_left_y()
1817 );
1818 }
1819 else {
1820 collision_box.set_xy(
1821 get_top_left_x(),
1822 get_top_left_y() + dy
1823 );
1824 }
1825
1826 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1827 // We can make at least one pixel with the stream.
1828 activate_stream = true;
1829 }
1830 else {
1831 // We would be blocked if we took the stream straight.
1832 // Maybe we won't get blocked when getting aligned with the stream.
1833 // Let's check that.
1834
1835 if (horizontal) {
1836 // Horizontal stream: try to align the Y coordinate.
1837 collision_box.set_xy(
1838 get_top_left_x() + dx,
1839 stream.get_top_left_y()
1840 );
1841 }
1842 else {
1843 // Vertical stream: try to align the X coordinate.
1844 collision_box.set_xy(
1845 stream.get_top_left_x(),
1846 get_top_left_y() + dy
1847 );
1848 }
1849
1850 if (!map.test_collision_with_obstacles(get_layer(), collision_box, *this)) {
1851 // We can move into the direction when correctly aligned.
1852 activate_stream = true;
1853 }
1854 }
1855 }
1856 }
1857
1858 if (activate_stream) {
1859 stream.activate(*this);
1860 if (!get_state()->can_persist_on_stream(stream)) {
1861 start_free();
1862 }
1863 }
1864 }
1865
1866 /**
1867 * \brief This function is called when a stairs entity detects a collision
1868 * with this entity.
1869 * \param stairs The stairs.
1870 * \param collision_mode The collision mode that detected the event.
1871 */
notify_collision_with_stairs(Stairs & stairs,CollisionMode collision_mode)1872 void Hero::notify_collision_with_stairs(
1873 Stairs& stairs, CollisionMode collision_mode) {
1874
1875 if (get_state()->get_can_take_stairs()) {
1876
1877 Stairs::Way stairs_way;
1878 if (stairs.is_inside_floor()) {
1879 stairs_way = (get_layer() == stairs.get_layer()) ?
1880 Stairs::NORMAL_WAY : Stairs::REVERSE_WAY;
1881 }
1882 else {
1883 stairs_way = (collision_mode == COLLISION_TOUCHING) ?
1884 Stairs::NORMAL_WAY : Stairs::REVERSE_WAY;
1885 }
1886
1887 // Check that the hero is exactly aligned with the stairs.
1888 if (stairs.get_direction() % 2 == 0) {
1889 // Horizontal stairs.
1890 if (get_top_left_y() != stairs.get_top_left_y()) {
1891 return;
1892 }
1893 }
1894 else {
1895 // Vertical stairs.
1896 if (get_top_left_x() != stairs.get_top_left_x()) {
1897 return;
1898 }
1899 }
1900
1901 // Check whether the hero is trying to move in the direction of the stairs.
1902 int correct_direction = stairs.get_movement_direction(stairs_way);
1903 if (is_moving_towards(correct_direction / 2)) {
1904 std::shared_ptr<const Stairs> shared_stairs =
1905 std::static_pointer_cast<const Stairs>(stairs.shared_from_this());
1906 set_state(std::make_shared<StairsState>(*this, shared_stairs, stairs_way));
1907 }
1908 }
1909 }
1910
1911 /**
1912 * \copydoc Entity::notify_collision_with_jumper
1913 */
notify_collision_with_jumper(Jumper & jumper,CollisionMode collision_mode)1914 void Hero::notify_collision_with_jumper(Jumper& jumper,
1915 CollisionMode collision_mode) {
1916
1917 if (collision_mode == COLLISION_CUSTOM) {
1918 get_state()->notify_jumper_activated(jumper);
1919 }
1920 }
1921
1922 /**
1923 * \brief This function is called when a sensor detects a collision with this entity.
1924 * \param sensor a sensor
1925 * \param collision_mode the collision mode that detected the collision
1926 */
notify_collision_with_sensor(Sensor & sensor,CollisionMode collision_mode)1927 void Hero::notify_collision_with_sensor(Sensor& sensor, CollisionMode collision_mode) {
1928
1929 if (collision_mode == COLLISION_CONTAINING // the hero is entirely inside the sensor
1930 && !get_state()->can_avoid_sensor()) {
1931 sensor.activate(*this);
1932 }
1933 }
1934
1935 /**
1936 * \brief This function is called when a switch detects a collision with this entity.
1937 * \param sw the switch
1938 * \param collision_mode the collision mode that detected the event
1939 */
notify_collision_with_switch(Switch & sw,CollisionMode)1940 void Hero::notify_collision_with_switch(Switch& sw, CollisionMode /* collision_mode */) {
1941
1942 // it's normally a walkable switch
1943 if (sw.is_walkable()
1944 && !get_state()->can_avoid_switch()) {
1945 sw.try_activate(*this);
1946 }
1947 }
1948
1949 /**
1950 * \brief This function is called when a the sprite of a switch
1951 * detects a pixel-precise collision with a sprite of this entity.
1952 * \param sw the switch
1953 * \param sprite_overlapping the sprite of the current entity that collides with the crystal
1954 */
notify_collision_with_switch(Switch & sw,Sprite & sprite_overlapping)1955 void Hero::notify_collision_with_switch(Switch& sw, Sprite& sprite_overlapping) {
1956
1957 // it's normally a solid switch
1958 const std::string& sprite_id = sprite_overlapping.get_animation_set_id();
1959 if (sprite_id == get_hero_sprites().get_sword_sprite_id() && // the hero's sword is overlapping the switch
1960 sw.is_solid() &&
1961 get_state()->can_sword_hit_crystal()) {
1962 // note that solid switches and crystals have the same rules for the sword
1963
1964 sw.try_activate();
1965 }
1966 }
1967
1968 /**
1969 * \brief This function is called when a crystal detects a collision with this entity.
1970 * \param crystal the crystal
1971 * \param collision_mode the collision mode that detected the event
1972 */
notify_collision_with_crystal(Crystal &,CollisionMode collision_mode)1973 void Hero::notify_collision_with_crystal(Crystal& /* crystal */, CollisionMode collision_mode) {
1974
1975 if (collision_mode == COLLISION_FACING) {
1976 // The hero is touching the crystal and is looking in its direction.
1977
1978 if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE
1979 && is_free()) {
1980
1981 // We show the action icon.
1982 get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_LOOK);
1983 }
1984 }
1985 }
1986
1987 /**
1988 * \brief This function is called when a the sprite of a crystal
1989 * detects a pixel-precise collision with a sprite of this entity.
1990 * \param crystal the crystal
1991 * \param sprite_overlapping the sprite of the current entity that collides with the crystal
1992 */
notify_collision_with_crystal(Crystal & crystal,Sprite & sprite_overlapping)1993 void Hero::notify_collision_with_crystal(Crystal& crystal, Sprite& sprite_overlapping) {
1994
1995 const std::string sprite_id = sprite_overlapping.get_animation_set_id();
1996 if (sprite_id == get_hero_sprites().get_sword_sprite_id() && // the hero's sword is overlapping the crystal
1997 get_state()->can_sword_hit_crystal()) {
1998
1999 crystal.activate(*this);
2000 }
2001 }
2002
2003 /**
2004 * \brief This function is called when a chest detects a collision with this entity.
2005 * \param chest the chest
2006 */
notify_collision_with_chest(Chest & chest)2007 void Hero::notify_collision_with_chest(Chest& chest) {
2008
2009 if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE
2010 && is_free()
2011 && is_facing_direction4(1)
2012 && !chest.is_open()) {
2013
2014 // We show the 'open' icon even if the chest cannot be opened yet.
2015 get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_OPEN);
2016 }
2017 }
2018
2019 /**
2020 * \brief This function is called when a block detects a collision with this entity.
2021 * \param block the block
2022 */
notify_collision_with_block(Block &)2023 void Hero::notify_collision_with_block(Block& /* block */) {
2024
2025 if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE &&
2026 is_free() &&
2027 can_grab()
2028 ) {
2029 // We allow to grab using the action command.
2030 get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_GRAB);
2031 }
2032 }
2033
2034 /**
2035 * \copydoc Entity::notify_collision_with_separator
2036 */
notify_collision_with_separator(Separator & separator,CollisionMode)2037 void Hero::notify_collision_with_separator(
2038 Separator& separator, CollisionMode /* collision_mode */) {
2039
2040 const CameraPtr& camera = get_map().get_camera();
2041 if (camera == nullptr) {
2042 return;
2043 }
2044 if (camera->get_tracked_entity().get() == this) {
2045 camera->notify_tracked_entity_traversing_separator(separator);
2046 }
2047 }
2048
2049 /**
2050 * \brief This function is called when an explosion's sprite detects a collision with a sprite of the hero.
2051 * \param explosion the explosion
2052 * \param sprite_overlapping the sprite of the hero that collides with the explosion
2053 */
notify_collision_with_explosion(Explosion & explosion,Sprite & sprite_overlapping)2054 void Hero::notify_collision_with_explosion(
2055 Explosion& explosion, Sprite& sprite_overlapping) {
2056
2057 const std::string& sprite_id = sprite_overlapping.get_animation_set_id();
2058 if (!get_state()->can_avoid_explosion() &&
2059 sprite_id == get_hero_sprites().get_tunic_sprite_id() &&
2060 can_be_hurt(&explosion)) {
2061 hurt(explosion, nullptr, 2);
2062 }
2063 }
2064
2065 /**
2066 * \brief Makes the hero escape from an entity that is overlapping him.
2067 *
2068 * This function is called when an entity that just appeared may overlap the hero
2069 * (e.g. a chest or a door).
2070 *
2071 * \param entity the entity that just appeared
2072 * \param direction the direction of the hero relative to the entity
2073 * (the hero will be moved into this direction): 0 to 3
2074 */
avoid_collision(Entity & entity,int direction)2075 void Hero::avoid_collision(Entity& entity, int direction) {
2076
2077 // fix the hero's position, whatever the entity's) size is
2078 switch (direction) {
2079
2080 case 0:
2081 set_top_left_x(entity.get_top_left_x() + entity.get_width());
2082 set_top_left_y(entity.get_center_point().y - 8);
2083 break;
2084
2085 case 1:
2086 set_top_left_y(entity.get_top_left_y() - this->get_height());
2087 set_top_left_x(entity.get_center_point().x - 8);
2088 break;
2089
2090 case 2:
2091 set_top_left_x(entity.get_top_left_x() - this->get_width());
2092 set_top_left_y(entity.get_center_point().y - 8);
2093 break;
2094
2095 case 3:
2096 set_top_left_y(entity.get_top_left_y() + entity.get_height());
2097 set_top_left_x(entity.get_center_point().x - 8);
2098 break;
2099
2100 default:
2101 Debug::die("Invalid direction in Hero::avoid_collision()");
2102 break;
2103 }
2104 reset_movement();
2105 }
2106
2107 /**
2108 * \brief Notifies the hero that the entity he is pushing or pulling
2109 * cannot move anymore because of a collision.
2110 */
notify_grabbed_entity_collision()2111 void Hero::notify_grabbed_entity_collision() {
2112 get_state()->notify_grabbed_entity_collision();
2113 }
2114
2115 /**
2116 * \brief Tests whether the hero is cutting with his sword the specified entity
2117 * for which a collision was detected.
2118 *
2119 * When the sword sprite collides with an entity,
2120 * this function can be called to determine whether the hero is
2121 * really cutting this particular entity precisely.
2122 * This depends on the hero's state, his direction and his
2123 * distance to the detector.
2124 * This function assumes that there is already a collision
2125 * between the sword sprite and the detector's sprite.
2126 * This function should be called to check whether the
2127 * hero wants to cut a bush or some grass.
2128 * Returns false by default.
2129 *
2130 * \param entity The entity to check.
2131 * \return \c true if the sword is cutting this entity.
2132 */
is_striking_with_sword(Entity & entity) const2133 bool Hero::is_striking_with_sword(Entity& entity) const {
2134 return get_state()->is_cutting_with_sword(entity);
2135 }
2136
2137 /**
2138 * \brief Snaps the hero to the entity he is facing.
2139 *
2140 * The hero is snapped if there is no collision and if he is not too far.
2141 */
try_snap_to_facing_entity()2142 void Hero::try_snap_to_facing_entity() {
2143
2144 Rectangle collision_box = get_bounding_box();
2145 const Point& center = collision_box.get_center();
2146 const Entity* facing_entity = get_facing_entity();
2147 const Point& facing_entity_center = facing_entity->get_center_point();
2148
2149 if (get_animation_direction() % 2 == 0) {
2150 if (abs(center.y - facing_entity_center.y) <= 5) {
2151 collision_box.set_center(center.x, facing_entity_center.y);
2152 }
2153 }
2154 else {
2155 if (abs(center.x - facing_entity_center.x) <= 5) {
2156 collision_box.set_center(facing_entity_center.x, center.y);
2157 }
2158 }
2159
2160 if (!get_map().test_collision_with_obstacles(get_layer(), collision_box, *this)) {
2161 set_bounding_box(collision_box);
2162 notify_position_changed();
2163 }
2164 }
2165
2166 /**
2167 * \copydoc Entity::notify_attacked_enemy
2168 */
notify_attacked_enemy(EnemyAttack attack,Enemy & victim,Sprite * victim_sprite,const EnemyReaction::Reaction & result,bool killed)2169 void Hero::notify_attacked_enemy(
2170 EnemyAttack attack,
2171 Enemy& victim,
2172 Sprite* victim_sprite,
2173 const EnemyReaction::Reaction& result,
2174 bool killed) {
2175
2176 get_state()->notify_attacked_enemy(attack, victim, victim_sprite, result, killed);
2177 }
2178
2179 /**
2180 * \brief Returns the damage power of the sword for the current attack.
2181 *
2182 * The value returned takes into account the power of the current sword
2183 * and the fact that a spin attack is more powerful than other attacks.
2184 *
2185 * \return the current damage factor of the sword
2186 */
get_sword_damage_factor() const2187 int Hero::get_sword_damage_factor() const {
2188 return get_state()->get_sword_damage_factor();
2189 }
2190
2191 /**
2192 * \brief Returns whether the hero is currently invincible.
2193 * \return \c true if the hero is currently invincible.
2194 */
is_invincible() const2195 bool Hero::is_invincible() const {
2196 return invincible;
2197 }
2198
2199 /**
2200 * \brief Sets the hero temporarily invincible or stops the invincibility.
2201 * \param invincible \c true to make the hero invincible, \c false to stop.
2202 * \param duration How long to stay invincible in milliseconds.
2203 * 0 means infinite. No effect if \c invincible is \c false.
2204 */
set_invincible(bool invincible,uint32_t duration)2205 void Hero::set_invincible(bool invincible, uint32_t duration) {
2206
2207 this->invincible = invincible;
2208 this->end_invincible_date = 0;
2209 if (invincible) {
2210 this->end_invincible_date = (duration == 0) ? 0 : System::now() + duration;
2211 }
2212 }
2213
2214 /**
2215 * \brief Checks whether the invincibility should end.
2216 */
update_invincibility()2217 void Hero::update_invincibility() {
2218
2219 if (is_invincible() &&
2220 end_invincible_date != 0 &&
2221 System::now() >= end_invincible_date) {
2222 set_invincible(false, 0);
2223 }
2224 }
2225
2226 /**
2227 * \brief Returns whether the hero can be hurt currently.
2228 * \param attacker An attacker that is trying to hurt the hero
2229 * (or nullptr if the source of the attack is not an entity).
2230 * \return \c true if the hero can be hurt.
2231 */
can_be_hurt(Entity * attacker) const2232 bool Hero::can_be_hurt(Entity* attacker) const {
2233 return !is_invincible() && get_state()->get_can_be_hurt(attacker);
2234 }
2235
2236 /**
2237 * \brief Hurts the hero, an entity being the source of the attack.
2238 * \param source An entity that hurts the hero (usually an enemy).
2239 * \param source_sprite Sprite of the source entity that is hurting the hero
2240 * or nullptr.
2241 * \param damage Number of life points to remove
2242 * (this number may be reduced later by the tunic on by hero:on_taking_damage()).
2243 */
hurt(Entity & source,Sprite * source_sprite,int damage)2244 void Hero::hurt(
2245 Entity& source,
2246 Sprite* source_sprite,
2247 int damage
2248 ) {
2249 Point source_xy = source.get_xy();
2250 if (source_sprite != nullptr) {
2251 // Add the offset of the sprite if any.
2252 source_xy += source_sprite->get_xy();
2253 }
2254 set_state(std::make_shared<HurtState>(*this, &source_xy, damage));
2255 }
2256
2257 /**
2258 * \brief Hurts the hero, a point being the source of the attack.
2259 * \param source_xy Coordinates of whatever hurts the hero.
2260 * \param damage Number of life points to remove
2261 * (this number may be reduced later by the tunic on by hero:on_taking_damage()).
2262 */
hurt(const Point & source_xy,int damage)2263 void Hero::hurt(const Point& source_xy, int damage) {
2264
2265 set_state(std::make_shared<HurtState>(*this, &source_xy, damage));
2266 }
2267
2268 /**
2269 * \brief Hurts the hero, with no located source of the attack.
2270 * \param damage Number of life points to remove
2271 * (this number may be reduced later by the tunic on by hero:on_taking_damage()).
2272 */
hurt(int damage)2273 void Hero::hurt(int damage) {
2274
2275 set_state(std::make_shared<HurtState>(*this, nullptr, damage));
2276 }
2277
2278 /**
2279 * \brief Draws a grass sprite below the hero and makes him walk slower.
2280 */
start_grass()2281 void Hero::start_grass() {
2282
2283 // Display a special sprite below the hero.
2284 sprites->create_ground(Ground::GRASS);
2285
2286 uint32_t now = System::now();
2287 next_ground_date = std::max(next_ground_date, now);
2288
2289 set_walking_speed(normal_walking_speed * 4 / 5);
2290 }
2291
2292 /**
2293 * \brief Draws a shallow water sprite below the hero and makes him walk
2294 * slower.
2295 */
start_shallow_water()2296 void Hero::start_shallow_water() {
2297
2298 // Display a special sprite below the hero.
2299 sprites->create_ground(Ground::SHALLOW_WATER);
2300
2301 uint32_t now = System::now();
2302 next_ground_date = std::max(next_ground_date, now);
2303
2304 set_walking_speed(normal_walking_speed * 4 / 5);
2305 }
2306
2307 /**
2308 * \brief This function is called when the hero was dying but the game-over
2309 * sequence was canceled.
2310 */
notify_game_over_finished()2311 void Hero::notify_game_over_finished() {
2312
2313 if (is_on_map()) {
2314 sprites->blink(2000);
2315 start_state_from_ground();
2316 }
2317 }
2318
2319 /**
2320 * \brief Makes the hero drown or swim.
2321 */
start_deep_water()2322 void Hero::start_deep_water() {
2323
2324 const bool can_swim = get_equipment().has_ability(Ability::SWIM);
2325 const bool can_jump_over_water = get_equipment().has_ability(Ability::JUMP_OVER_WATER);
2326
2327 if (!get_state()->is_touching_ground()) {
2328 // Entering water from above the ground
2329 // (e.g. after a jump).
2330 set_state(std::make_shared<PlungingState>(*this));
2331 }
2332 else {
2333 // Entering water normally (e.g. by walking).
2334 if (can_swim) {
2335 set_state(std::make_shared<SwimmingState>(*this));
2336 }
2337 else if (can_jump_over_water) {
2338 int direction8 = get_wanted_movement_direction8();
2339 if (direction8 == -1) {
2340 direction8 = get_animation_direction() * 2;
2341 }
2342 start_jumping(direction8, 32, false, true);
2343 }
2344 else {
2345 set_state(std::make_shared<PlungingState>(*this));
2346 }
2347 }
2348 }
2349
2350 /**
2351 * \brief Makes the hero move towards a hole of fall into it.
2352 */
start_hole()2353 void Hero::start_hole() {
2354
2355 if (!can_control_movement()) {
2356 // the player has no control (e.g. he is running or being hurt):
2357 // fall immediately
2358 set_state(std::make_shared<FallingState>(*this));
2359 }
2360 else {
2361 // otherwise, push the hero towards the hole
2362
2363 next_ground_date = System::now();
2364
2365 // Don't calculate the attraction direction based on the wanted movement
2366 // because the wanted movement may be different from the real one.
2367
2368 if (last_solid_ground_coords.x == -1 ||
2369 (last_solid_ground_coords == get_xy())) {
2370 // Fall immediately because the hero was not moving but directly placed on the hole.
2371 set_state(std::make_shared<FallingState>(*this));
2372 }
2373 else {
2374 ground_dxy = { 0, 0 };
2375
2376 if (get_x() > last_solid_ground_coords.x) {
2377 ground_dxy.x = 1;
2378 }
2379 else if (get_x() < last_solid_ground_coords.x) {
2380 ground_dxy.x = -1;
2381 }
2382
2383 if (get_y() > last_solid_ground_coords.y) {
2384 ground_dxy.y = 1;
2385 }
2386 else if (get_y() < last_solid_ground_coords.y) {
2387 ground_dxy.y = -1;
2388 }
2389 set_walking_speed(normal_walking_speed / 3);
2390 }
2391 }
2392 }
2393
2394 /**
2395 * \brief Makes the hero slide on ice ground.
2396 */
start_ice()2397 void Hero::start_ice() {
2398
2399 next_ground_date = System::now();
2400 next_ice_date = System::now();
2401
2402 ice_movement_direction8 = get_wanted_movement_direction8();
2403 if (ice_movement_direction8 == -1) {
2404 ground_dxy = { 0, 0 };
2405 }
2406 else {
2407 // Exagerate the movement.
2408 ground_dxy = direction_to_xy_move(ice_movement_direction8);
2409 }
2410 }
2411
2412 /**
2413 * \brief Makes the hero drown into lava.
2414 */
start_lava()2415 void Hero::start_lava() {
2416
2417 // plunge into the lava
2418 set_state(std::make_shared<PlungingState>(*this));
2419 }
2420
2421 /**
2422 * \brief Makes the hero being hurt by prickles.
2423 * \param delay delay before returning control to the player
2424 */
start_prickle(uint32_t delay)2425 void Hero::start_prickle(uint32_t delay) {
2426
2427 Sound::play("hero_hurt");
2428 get_equipment().remove_life(2);
2429 start_back_to_solid_ground(true, delay, false);
2430 }
2431
2432 /**
2433 * \brief Returns whether the hero can walk normally and interact with entities.
2434 * \return true if the hero can walk normally
2435 */
is_free() const2436 bool Hero::is_free() const {
2437
2438 return get_state()->is_free();
2439 }
2440
2441 /**
2442 * \brief Returns whether the hero is currently using an equipment item.
2443 * \return true if the hero is using an equipment item.
2444 */
is_using_item() const2445 bool Hero::is_using_item() const {
2446
2447 return get_state()->is_using_item();
2448 }
2449
2450 /**
2451 * \brief When the hero is using an equipment item, returns that item.
2452 * \return The current equipment item.
2453 */
get_item_being_used()2454 EquipmentItemUsage& Hero::get_item_being_used() {
2455
2456 return get_state()->get_item_being_used();
2457 }
2458
2459 /**
2460 * \brief Returns whether the hero is grabbing and moving an entity in its current state.
2461 *
2462 * If he is not grabbing any entity, false is returned.
2463 *
2464 * \return true if the hero is grabbing and moving an entity
2465 */
is_moving_grabbed_entity() const2466 bool Hero::is_moving_grabbed_entity() const {
2467
2468 return get_state()->is_moving_grabbed_entity();
2469 }
2470
2471 /**
2472 * \brief Returns whether the hero is brandishing a treasure.
2473 * \return \c true if the hero is brandishing a treasure.
2474 */
is_brandishing_treasure() const2475 bool Hero::is_brandishing_treasure() const {
2476
2477 return get_state()->is_brandishing_treasure();
2478 }
2479
2480 /**
2481 * \brief Returns whether the hero is grabbing or pulling an entity.
2482 * \return true if the hero is grabbing or pulling an entity
2483 */
is_grabbing_or_pulling() const2484 bool Hero::is_grabbing_or_pulling() const {
2485
2486 return get_state()->is_grabbing_or_pulling();
2487 }
2488
2489 /**
2490 * \brief Lets the hero walk normally.
2491 */
start_free()2492 void Hero::start_free() {
2493
2494 set_state(std::make_shared<FreeState>(*this));
2495 }
2496
2497 /**
2498 * \brief Lets the hero walk.
2499 *
2500 * If the hero is carrying item in the current state, the item is preserved.
2501 * If the hero is loading his sword in the current state, this continues.
2502 * If the hero is running in the current state, he continues to run.
2503 */
start_free_carrying_loading_or_running()2504 void Hero::start_free_carrying_loading_or_running() {
2505
2506 if (get_state()->get_name() == "sword loading") {
2507 // Nothing to do: just keep the sword loaded.
2508 return;
2509 }
2510
2511 if (get_state()->get_name() == "running" && get_state()->is_touching_ground()) {
2512 // Nothing to do: just keep running.
2513 return;
2514 }
2515
2516 if (get_state()->is_carrying_item()) {
2517 set_state(std::make_shared<CarryingState>(*this, get_state()->get_carried_object()));
2518 }
2519 else {
2520 set_state(std::make_shared<FreeState>(*this));
2521 }
2522 }
2523
2524 /**
2525 * \brief Makes the hero brandish a treasure.
2526 * \param treasure The treasure to give him. It must be obtainable.
2527 * \param callback_ref Lua ref to a function to call when the
2528 * treasure's dialog finishes (possibly an empty ref).
2529 */
start_treasure(const Treasure & treasure,const ScopedLuaRef & callback_ref)2530 void Hero::start_treasure(
2531 const Treasure& treasure,
2532 const ScopedLuaRef& callback_ref
2533 ) {
2534 set_state(std::make_shared<TreasureState>(*this, treasure, callback_ref));
2535 }
2536
2537 /**
2538 * \brief Makes the hero walk with a predetermined path.
2539 *
2540 * The player does not control him anymore.
2541 *
2542 * \param path the succession of basic moves
2543 * composing this movement (each character represents
2544 * a direction between '0' and '7'), as in PathMovement
2545 * \param loop true to make the movement return to the beginning
2546 * once finished
2547 * \param ignore_obstacles true to make the movement ignore obstacles
2548 */
start_forced_walking(const std::string & path,bool loop,bool ignore_obstacles)2549 void Hero::start_forced_walking(const std::string& path, bool loop, bool ignore_obstacles) {
2550 set_state(std::make_shared<ForcedWalkingState>(*this, path, loop, ignore_obstacles));
2551 }
2552
2553 /**
2554 * \brief Makes the hero jump into a direction.
2555 *
2556 * While he is jumping, the player does not control him anymore.
2557 *
2558 * \param direction8 direction of the jump (0 to 7)
2559 * \param distance distance of the jump in pixels
2560 * \param ignore_obstacles true make the movement ignore obstacles
2561 * \param with_sound true to play the "jump" sound
2562 */
start_jumping(int direction8,int distance,bool ignore_obstacles,bool with_sound)2563 void Hero::start_jumping(
2564 int direction8,
2565 int distance,
2566 bool ignore_obstacles,
2567 bool with_sound) {
2568
2569 set_state(std::make_shared<JumpingState>(
2570 *this,
2571 direction8,
2572 distance,
2573 ignore_obstacles,
2574 with_sound));
2575 }
2576
2577 /**
2578 * \brief Makes the hero brandish his sword meaning a victory.
2579 * \param callback_ref Lua ref to a function to call when the
2580 * victory sequence finishes (possibly an empty ref).
2581 */
start_victory(const ScopedLuaRef & callback_ref)2582 void Hero::start_victory(const ScopedLuaRef& callback_ref) {
2583 set_state(std::make_shared<VictoryState>(*this, callback_ref));
2584 }
2585
2586 /**
2587 * \brief Freezes the hero.
2588 *
2589 * When the hero is frozen, he cannot move.
2590 * The current animation of the hero's sprites is stopped and the "stopped" animation is played.
2591 * You can call start_free() to unfreeze him.
2592 */
start_frozen()2593 void Hero::start_frozen() {
2594 set_state(std::make_shared<FrozenState>(*this));
2595 }
2596
2597 /**
2598 * \brief Makes the hero lift a destructible item.
2599 * \param item_to_lift The item to lift.
2600 */
start_lifting(const std::shared_ptr<CarriedObject> & item_to_lift)2601 void Hero::start_lifting(const std::shared_ptr<CarriedObject>& item_to_lift) {
2602 set_state(std::make_shared<LiftingState>(*this, item_to_lift));
2603 }
2604
2605 /**
2606 * \brief Starts running with the speed shoes.
2607 */
start_running()2608 void Hero::start_running() {
2609
2610 // The running state may be triggered by the action command or an
2611 // item command.
2612 GameCommand command;
2613 if (is_free()) {
2614 command = GameCommand::ACTION;
2615 }
2616 else {
2617 command = get_commands().is_command_pressed(GameCommand::ITEM_1) ?
2618 GameCommand::ITEM_1 : GameCommand::ITEM_2;
2619 }
2620 set_state(std::make_shared<RunningState>(*this, command));
2621 }
2622
2623 /**
2624 * \brief Starts pushing an obstacle.
2625 */
start_pushing()2626 void Hero::start_pushing() {
2627
2628 get_equipment().notify_ability_used(Ability::PUSH);
2629 set_state(std::make_shared<PushingState>(*this));
2630 }
2631
2632 /**
2633 * \brief Starts grabbing an obstacle.
2634 */
start_grabbing()2635 void Hero::start_grabbing() {
2636
2637 get_equipment().notify_ability_used(Ability::GRAB);
2638 set_state(std::make_shared<GrabbingState>(*this));
2639 }
2640
2641 /**
2642 * \brief Starts pulling an obstacle.
2643 */
start_pulling()2644 void Hero::start_pulling() {
2645
2646 get_equipment().notify_ability_used(Ability::PULL);
2647 set_state(std::make_shared<PullingState>(*this));
2648 }
2649
2650 /**
2651 * \brief Returns whether the hero can pick a treasure in his current state.
2652 * \param item The equipment item to pick.
2653 * \return true if this equipment item can currently be picked.
2654 */
can_pick_treasure(EquipmentItem & item)2655 bool Hero::can_pick_treasure(EquipmentItem& item) {
2656
2657 return get_state()->get_can_pick_treasure(item);
2658 }
2659
2660 /**
2661 * \brief Returns whether the hero currently ignores the effect of a teletransporter.
2662 * \param teletransporter A candidate teletransporter.
2663 * \return \c true if the hero currently ignores this teletransporter.
2664 */
can_avoid_teletransporter(const Teletransporter & teletransporter) const2665 bool Hero::can_avoid_teletransporter(const Teletransporter& teletransporter) const {
2666
2667 if (teletransporter.is_on_map_side()) {
2668 // Never ignore this kind of teletransporter.
2669 return false;
2670 }
2671
2672 if (has_stream_action()) {
2673 // Ignore teletransporters until the stream is finished.
2674 return true;
2675 }
2676
2677 return get_state()->can_avoid_teletransporter();
2678 }
2679
2680 /**
2681 * \brief Returns whether the hero can currently start running.
2682 * \return \c true if the hero can run.
2683 */
can_run() const2684 bool Hero::can_run() const {
2685
2686 if (!get_equipment().has_ability(Ability::RUN)) {
2687 return false;
2688 }
2689
2690 if (
2691 has_stream_action() &&
2692 !get_stream_action()->get_stream().get_allow_movement()
2693 ) {
2694 // Don't run on a blocking stream.
2695 return false;
2696 }
2697
2698 return is_free();
2699 }
2700
2701 /**
2702 * \brief Returns whether the hero can currently push an obstacle.
2703 * \return \c true if the hero can push.
2704 */
can_push() const2705 bool Hero::can_push() const {
2706
2707 return get_equipment().has_ability(Ability::PUSH);
2708 }
2709
2710 /**
2711 * \brief Returns whether the hero can currently grab an obstacle.
2712 * \return \c true if the hero can grab.
2713 */
can_grab() const2714 bool Hero::can_grab() const {
2715
2716 return get_equipment().has_ability(Ability::GRAB);
2717 }
2718
2719 /**
2720 * \brief Returns whether the hero can currently pull an obstacle.
2721 * \return \c true if the hero can pull.
2722 */
can_pull() const2723 bool Hero::can_pull() const {
2724
2725 return get_equipment().has_ability(Ability::PULL);
2726 }
2727
2728 /**
2729 * \brief Returns whether the hero can interact with the given NPC.
2730 * \param npc A non-playing character.
2731 * \return \c true if the hero can interact with this NPC.
2732 */
can_interact_with_npc(Npc & npc)2733 bool Hero::can_interact_with_npc(Npc& npc) {
2734 return get_state()->get_can_interact_with_npc(npc);
2735 }
2736
2737 /**
2738 * \brief Returns whether the hero can stop attacks with a shield in his
2739 * current state.
2740 * \return \c true if the shield is active is this state.
2741 */
can_use_shield() const2742 bool Hero::can_use_shield() const {
2743
2744 return get_state()->get_can_use_shield();
2745 }
2746
2747
2748 /**
2749 * \brief Returns whether the hero can currently use his sword.
2750 * \return \c true if the sword can be used now.
2751 */
can_start_sword() const2752 bool Hero::can_start_sword() const {
2753
2754 if (has_stream_action() &&
2755 !get_stream_action()->get_stream().get_allow_attack()) {
2756 // A stream prevents from using the sword.
2757 return false;
2758 }
2759
2760 return get_state()->get_can_start_sword();
2761 }
2762
2763 /**
2764 * \brief Starts using the sword.
2765 */
start_sword()2766 void Hero::start_sword() {
2767 set_state(std::make_shared<SwordSwingingState>(*this));
2768 }
2769
2770 /**
2771 * \brief Starts loading the sword.
2772 * \param spin_attack_delay Delay before allowing the spin attack (-1 means never).
2773 */
start_sword_loading(int spin_attack_delay)2774 void Hero::start_sword_loading(int spin_attack_delay) {
2775 set_state(std::make_shared<SwordLoadingState>(*this, spin_attack_delay));
2776 }
2777
2778 /**
2779 * \brief Returns whether the hero can starts using an equipment item.
2780 * \param item The equipment item to use.
2781 * \return true if this equipment item can currently be used.
2782 */
can_start_item(EquipmentItem & item)2783 bool Hero::can_start_item(EquipmentItem& item) {
2784
2785 if (!item.is_saved()) {
2786 // This item has no possession state, it cannot be used.
2787 return false;
2788 }
2789
2790 if (!item.is_assignable()) {
2791 // This item cannot be used explicitly.
2792 return false;
2793 }
2794
2795 if (item.get_variant() == 0) {
2796 // The player does not have this item.
2797 return false;
2798 }
2799
2800 if (has_stream_action() &&
2801 !get_stream_action()->get_stream().get_allow_item()) {
2802 // A stream prevents from using items.
2803 return false;
2804 }
2805
2806 return get_state()->get_can_start_item(item);
2807 }
2808
2809 /**
2810 * \brief Starts using an equipment item.
2811 * \param item The equipment item to use.
2812 */
start_item(EquipmentItem & item)2813 void Hero::start_item(EquipmentItem& item) {
2814 Debug::check_assertion(can_start_item(item),
2815 std::string("The hero cannot start using item '")
2816 + item.get_name() + "' now");
2817 set_state(std::make_shared<UsingItemState>(*this, item));
2818 }
2819
2820 /**
2821 * \brief Starts shooting a boomerang.
2822 * \param max_distance maximum distance of the movement in pixels
2823 * \param speed speed of the movement in pixels per second
2824 * \param tunic_preparing_animation animation name of the hero's tunic sprite
2825 * when preparing the boomerang
2826 * \param sprite_name animation set id that represents the boomerang
2827 */
start_boomerang(int max_distance,int speed,const std::string & tunic_preparing_animation,const std::string & sprite_name)2828 void Hero::start_boomerang(int max_distance, int speed,
2829 const std::string& tunic_preparing_animation,
2830 const std::string& sprite_name) {
2831
2832 set_state(std::make_shared<BoomerangState>(*this, max_distance, speed,
2833 tunic_preparing_animation, sprite_name));
2834 }
2835
2836 /**
2837 * \brief Starts shooting an arrow with a bow.
2838 */
start_bow()2839 void Hero::start_bow() {
2840 set_state(std::make_shared<BowState>(*this));
2841 }
2842
2843 /**
2844 * \brief Starts shooting the hookshot.
2845 */
start_hookshot()2846 void Hero::start_hookshot() {
2847 set_state(std::make_shared<HookshotState>(*this));
2848 }
2849
2850 /**
2851 * \brief Makes the hero return to his last solid ground position.
2852 * \param use_specified_position true to get back to the place previously specified (if any),
2853 * false to get back to the last coordinates with solid ground
2854 * \param end_delay a delay to add at the end before returning control to the hero (default 0)
2855 * \param with_sound true to play a sound when returning to solid ground (default true)
2856 */
start_back_to_solid_ground(bool use_specified_position,uint32_t end_delay,bool with_sound)2857 void Hero::start_back_to_solid_ground(bool use_specified_position,
2858 uint32_t end_delay, bool with_sound) {
2859
2860 set_state(std::make_shared<BackToSolidGroundState>(
2861 *this, use_specified_position, end_delay, with_sound));
2862 }
2863
2864 /**
2865 * \brief Activates immediately the state corresponding to the current ground.
2866 *
2867 * Only the state is changed here.
2868 * Some other functions like start_deep_water() and start_hole()
2869 * are triggered when the ground changes (for example,
2870 * going from normal ground to deep water ground) and make more
2871 * complex transitions.
2872 * This function is supposed to called when the ground was ignored
2873 * and you want to apply its effect now (no matter whether it has changed or not).
2874 * This function is typically called at the end of a state that ignores
2875 * the ground (like JumpingState) to choose the
2876 * correct next state depending on the ground the hero lands on.
2877 */
start_state_from_ground()2878 void Hero::start_state_from_ground() {
2879
2880 update_ground_below(); // Make sure the ground is up-to-date.
2881
2882 switch (get_ground_below()) {
2883
2884 case Ground::DEEP_WATER:
2885 if (get_state()->is_touching_ground()
2886 && get_equipment().has_ability(Ability::SWIM)) {
2887 set_state(std::make_shared<SwimmingState>(*this));
2888 }
2889 else {
2890 set_state(std::make_shared<PlungingState>(*this));
2891 }
2892 break;
2893
2894 case Ground::HOLE:
2895 set_state(std::make_shared<FallingState>(*this));
2896 break;
2897
2898 case Ground::LAVA:
2899 set_state(std::make_shared<PlungingState>(*this));
2900 break;
2901
2902 case Ground::PRICKLE:
2903 // There is no specific state for prickles (yet?).
2904 set_state(std::make_shared<FreeState>(*this));
2905 start_prickle(0);
2906 break;
2907
2908 case Ground::SHALLOW_WATER:
2909 start_shallow_water();
2910 start_free_carrying_loading_or_running();
2911 break;
2912
2913 case Ground::GRASS:
2914 start_grass();
2915 start_free_carrying_loading_or_running();
2916 break;
2917
2918 case Ground::TRAVERSABLE:
2919 case Ground::EMPTY:
2920 case Ground::LADDER:
2921 case Ground::ICE:
2922 start_free_carrying_loading_or_running();
2923 break;
2924
2925 case Ground::WALL:
2926 case Ground::LOW_WALL:
2927 case Ground::WALL_TOP_RIGHT:
2928 case Ground::WALL_TOP_LEFT:
2929 case Ground::WALL_BOTTOM_LEFT:
2930 case Ground::WALL_BOTTOM_RIGHT:
2931 case Ground::WALL_TOP_RIGHT_WATER:
2932 case Ground::WALL_TOP_LEFT_WATER:
2933 case Ground::WALL_BOTTOM_LEFT_WATER:
2934 case Ground::WALL_BOTTOM_RIGHT_WATER:
2935 // The hero is stuck in a wall,
2936 // possibly because a teletransporter sent him here.
2937 // It is the fault of the quest maker and there is not much we can do.
2938 start_free_carrying_loading_or_running();
2939 break;
2940 }
2941 }
2942
2943 /**
2944 * @brief Starts the given custom Lua state.
2945 * @param custom_state The Lua state object.
2946 */
start_custom_state(const std::shared_ptr<CustomState> & custom_state)2947 void Hero::start_custom_state(const std::shared_ptr<CustomState>& custom_state) {
2948
2949 custom_state->set_entity(*this);
2950 set_state(custom_state);
2951 }
2952
2953 }
2954
2955