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/Equipment.h"
19 #include "solarus/core/Game.h"
20 #include "solarus/core/GameCommands.h"
21 #include "solarus/core/Geometry.h"
22 #include "solarus/core/Map.h"
23 #include "solarus/core/System.h"
24 #include "solarus/hero/FreeState.h"
25 #include "solarus/hero/HeroSprites.h"
26 #include "solarus/hero/RunningState.h"
27 #include "solarus/entities/Enemy.h"
28 #include "solarus/entities/Jumper.h"
29 #include "solarus/entities/Stream.h"
30 #include "solarus/movements/JumpMovement.h"
31 #include "solarus/movements/StraightMovement.h"
32 #include <memory>
33 
34 namespace Solarus {
35 
36 /**
37  * \brief Constructor.
38  * \param hero The hero controlled by this state.
39  * \param command The game command that triggers running.
40  */
RunningState(Hero & hero,GameCommand command)41 Hero::RunningState::RunningState(Hero& hero, GameCommand command):
42   HeroState(hero, "running"),
43   phase(0),
44   next_phase_date(0),
45   next_sound_date(0),
46   command(command) {
47 
48 }
49 
50 /**
51  * \brief Starts this state.
52  * \param previous_state the previous state
53  */
start(const State * previous_state)54 void Hero::RunningState::start(const State* previous_state) {
55 
56   HeroState::start(previous_state);
57 
58   get_sprites().set_animation_prepare_running();
59 
60   phase = 0;
61 
62   uint32_t now = System::now();
63   next_phase_date = now + 500;
64   next_sound_date = now + 300;
65 }
66 
67 /**
68  * \brief Stops this state.
69  */
stop(const State * next_state)70 void Hero::RunningState::stop(const State* next_state) {
71 
72   HeroState::stop(next_state);
73 
74   if (phase != 0) {
75     get_entity().clear_movement();
76   }
77 }
78 
79 /**
80  * \brief Updates this state.
81  */
update()82 void Hero::RunningState::update() {
83 
84   HeroState::update();
85 
86   if (is_suspended()) {
87     return;
88   }
89 
90   uint32_t now = System::now();
91 
92   if (!is_bouncing() && now >= next_sound_date) {
93     Sound::play("running");
94     next_sound_date = now + 170;
95   }
96 
97   Hero& hero = get_entity();
98   if (phase == 0) {
99 
100     if (now >= next_phase_date) {
101 
102       double angle = Geometry::degrees_to_radians(get_sprites().get_animation_direction() * 90);
103       std::shared_ptr<StraightMovement> movement =
104           std::make_shared<StraightMovement>(false, true);
105       movement->set_max_distance(3000);
106       movement->set_speed(300);
107       movement->set_angle(angle);
108       hero.clear_movement();
109       hero.set_movement(movement);
110 
111       get_sprites().set_animation_running();
112       phase++;
113     }
114     else if (!is_pressing_running_key()) {
115       hero.set_state(std::make_shared<FreeState>(hero));
116     }
117   }
118   else if (hero.get_movement()->is_finished()) {
119     hero.start_state_from_ground();
120   }
121 }
122 
123 /**
124  * \brief Notifies this state that the game was just suspended or resumed.
125  * \param suspended true if the game is suspended
126  */
set_suspended(bool suspended)127 void Hero::RunningState::set_suspended(bool suspended) {
128 
129   HeroState::set_suspended(suspended);
130 
131   if (!suspended) {
132     uint32_t diff = System::now() - get_when_suspended();
133     next_phase_date += diff;
134     next_sound_date += diff;
135   }
136 }
137 
138 /**
139  * \brief Returns whether the hero is bouncing after he reached an obstacle during the run.
140  * \return true if the hero is bouncing
141  */
is_bouncing() const142 bool Hero::RunningState::is_bouncing() const {
143   return phase == 2;
144 }
145 
146 /**
147  * \brief Returns whether the hero is still pressing the key that made him
148  * start running.
149  * \return true if the hero is still pressing the running key
150  */
is_pressing_running_key() const151 bool Hero::RunningState::is_pressing_running_key() const {
152 
153   return get_commands().is_command_pressed(command);
154 }
155 
156 /**
157  * \brief Notifies this state that a directional key was just pressed.
158  * \param direction4 direction of the key (0 to 3)
159  */
notify_direction_command_pressed(int direction4)160 void Hero::RunningState::notify_direction_command_pressed(int direction4) {
161 
162   if (!is_bouncing()
163       && direction4 != get_sprites().get_animation_direction()) {
164     Hero& hero = get_entity();
165     hero.set_state(std::make_shared<FreeState>(hero));
166   }
167 }
168 
169 /**
170  * \brief Notifies this state that the hero has just failed to change its
171  * position because of obstacles.
172  */
notify_obstacle_reached()173 void Hero::RunningState::notify_obstacle_reached() {
174 
175   HeroState::notify_obstacle_reached();
176 
177   if (phase == 1) {
178     int opposite_direction = (get_sprites().get_animation_direction8() + 4) % 8;
179     get_entity().set_movement(std::make_shared<JumpMovement>(
180         opposite_direction, 32, 64, false
181     ));
182     get_sprites().set_animation_hurt();
183     Sound::play("running_obstacle");
184     phase++;
185   }
186 }
187 
188 /**
189  * \brief Returns the direction of the hero's movement as defined by the controls applied by the player
190  * and the movements allowed is the current state.
191  *
192  * If he is not moving, -1 is returned.
193  * This direction may be different from the real movement direction because of obstacles.
194  *
195  * \return the hero's wanted direction between 0 and 7, or -1 if he is stopped
196  */
get_wanted_movement_direction8() const197 int Hero::RunningState::get_wanted_movement_direction8() const {
198   return get_sprites().get_animation_direction8();
199 }
200 
201 /**
202  * \brief Returns whether the hero can take stairs in this state.
203  * If false is returned, stairs have no effect (but they are obstacle for the hero).
204  * \return true if the hero ignores the effect of stairs in this state
205  */
get_can_take_stairs() const206 bool Hero::RunningState::get_can_take_stairs() const {
207   return !is_bouncing();
208 }
209 
210 /**
211  * \brief Returns whether can trigger a jumper in this state.
212  *
213  * If false is returned, jumpers have no effect (but they are obstacle
214  * for the hero).
215  *
216  * \return true if the hero can use jumpers in this state
217  */
get_can_take_jumper() const218 bool Hero::RunningState::get_can_take_jumper() const {
219   return !is_bouncing();
220 }
221 
222 /**
223  * \brief Notifies this state that the hero is activating a jumper.
224  * \param jumper The jumper activated.
225  */
notify_jumper_activated(Jumper & jumper)226 void Hero::RunningState::notify_jumper_activated(Jumper& jumper) {
227 
228   // Jump immediately.
229   get_entity().start_jumping(
230       jumper.get_direction(),
231       jumper.get_jump_length(),
232       true,
233       true
234   );
235 }
236 
237 /**
238  * \brief Returns whether the hero can be hurt by an attacker in this state.
239  * \param attacker an attacker that is trying to hurt the hero
240  * (or nullptr if the source of the attack is not an enemy)
241  * \return true if the hero can be hurt in this state
242  */
get_can_be_hurt(Entity * attacker)243 bool Hero::RunningState::get_can_be_hurt(Entity* attacker) {
244 
245   if (phase == 0) {
246     // Preparing to run.
247     return true;
248   }
249 
250   if (attacker != nullptr && attacker->get_type() == EntityType::ENEMY) {
251     // TODO move get_can_hurt_hero_running to Entity.
252     Enemy* enemy = static_cast<Enemy*>(attacker);
253     return enemy->get_can_hurt_hero_running();
254   }
255 
256   return false;
257 }
258 
259 /**
260  * \brief Returns whether the hero can pick a treasure in this state.
261  * \param item The equipment item to obtain.
262  * \return true if the hero can pick that treasure in this state.
263  */
get_can_pick_treasure(EquipmentItem &) const264 bool Hero::RunningState::get_can_pick_treasure(EquipmentItem& /* item */) const {
265   return true;
266 }
267 
268 /**
269  * \copydoc Entity::State::can_sword_hit_crystal
270  */
can_sword_hit_crystal() const271 bool Hero::RunningState::can_sword_hit_crystal() const {
272   return true;
273 }
274 
275 /**
276  * \brief Returns whether the game over sequence can start in the current state.
277  * \return true if the game over sequence can start in the current state
278  */
can_start_gameover_sequence() const279 bool Hero::RunningState::can_start_gameover_sequence() const {
280   return !is_bouncing();
281 }
282 
283 /**
284  * \brief Returns whether the hero is touching the ground in the current state.
285  * \return true if the hero is touching the ground in the current state
286  */
is_touching_ground() const287 bool Hero::RunningState::is_touching_ground() const {
288   return !is_bouncing();
289 }
290 
291 /**
292  * \brief Returns whether the hero ignores the effect of deep water in this state.
293  * \return true if the hero ignores the effect of deep water in the current state
294  */
can_avoid_deep_water() const295 bool Hero::RunningState::can_avoid_deep_water() const {
296   return is_bouncing();
297 }
298 
299 /**
300  * \brief Returns whether the hero ignores the effect of holes in this state.
301  * \return true if the hero ignores the effect of holes in the current state
302  */
can_avoid_hole() const303 bool Hero::RunningState::can_avoid_hole() const {
304   return is_bouncing();
305 }
306 
307 /**
308  * \brief Returns whether the hero ignores the effect of lava in this state.
309  * \return true if the hero ignores the effect of lava in the current state
310  */
can_avoid_lava() const311 bool Hero::RunningState::can_avoid_lava() const {
312   return is_bouncing();
313 }
314 
315 /**
316  * \brief Returns whether the hero ignores the effect of prickles in this state.
317  * \return true if the hero ignores the effect of prickles in the current state
318  */
can_avoid_prickle() const319 bool Hero::RunningState::can_avoid_prickle() const {
320   return is_bouncing();
321 }
322 
323 /**
324  * \brief Returns whether the hero ignores the effect of teletransporters in this state.
325  * \return true if the hero ignores the effect of teletransporters in this state
326  */
can_avoid_teletransporter() const327 bool Hero::RunningState::can_avoid_teletransporter() const {
328   return is_bouncing();
329 }
330 
331 /**
332  * \copydoc Entity::State::can_avoid_stream
333  */
can_avoid_stream(const Stream &) const334 bool Hero::RunningState::can_avoid_stream(const Stream& /* stream */) const {
335   return is_bouncing();
336 }
337 
338 /**
339  * \copydoc Entity::State::can_persist_on_stream
340  */
can_persist_on_stream(const Stream & stream) const341 bool Hero::RunningState::can_persist_on_stream(const Stream& stream) const {
342 
343   // Continue to run if this is a non-blocking stream.
344   return stream.get_allow_movement();
345 }
346 
347 /**
348  * \brief Returns whether a sensor is considered as an obstacle in this state.
349  * \param sensor a sensor
350  * \return true if the sensor is an obstacle in this state
351  */
is_sensor_obstacle(Sensor &)352 bool Hero::RunningState::is_sensor_obstacle(Sensor& /* sensor */) {
353   return is_bouncing();
354 }
355 
356 /**
357  * \copydoc Entity::State::is_cutting_with_sword
358  */
is_cutting_with_sword(Entity & entity)359 bool Hero::RunningState::is_cutting_with_sword(Entity& entity) {
360 
361   // check the distance to the detector
362   const int distance = 8;
363   Point tested_point = get_entity().get_facing_point();
364 
365   switch (get_sprites().get_animation_direction()) {
366 
367     case 0: // right
368       tested_point.x += distance;
369       break;
370 
371     case 1: // up
372       tested_point.y -= distance;
373       break;
374 
375     case 2: // left
376       tested_point.x -= distance;
377       break;
378 
379     case 3: // down
380       tested_point.y += distance;
381       break;
382   }
383 
384   return entity.overlaps(tested_point);
385 }
386 
387 /**
388  * \brief Returns the damage power of the sword for the current attack.
389  * \return the current damage factor of the sword
390  */
get_sword_damage_factor() const391 int Hero::RunningState::get_sword_damage_factor() const {
392 
393   // the damage are multiplied by 2
394   return HeroState::get_sword_damage_factor() * 2;
395 }
396 
397 }
398 
399