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