1 /*
2  * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "solarus/core/CommandsEffects.h"
18 #include "solarus/core/Equipment.h"
19 #include "solarus/core/Game.h"
20 #include "solarus/core/System.h"
21 #include "solarus/hero/FreeState.h"
22 #include "solarus/hero/GrabbingState.h"
23 #include "solarus/hero/HeroSprites.h"
24 #include "solarus/movements/PlayerMovement.h"
25 
26 namespace Solarus {
27 
28 /**
29  * \brief Constructor.
30  * \param hero The hero controlled by this state.
31  */
FreeState(Hero & hero)32 Hero::FreeState::FreeState(Hero& hero):
33   PlayerMovementState(hero, "free"),
34   pushing_direction4(0),
35   start_pushing_date(0) {
36 
37 
38 }
39 
40 /**
41  * \brief Starts this state.
42  * \param previous_state the previous state
43  */
start(const State * previous_state)44 void Hero::FreeState::start(const State* previous_state) {
45 
46   PlayerMovementState::start(previous_state);
47 
48   pushing_direction4 = -1;
49   start_pushing_date = 0;
50 }
51 
52 /**
53  * \brief Stops this state.
54  * \param next_state the next state
55  */
stop(const State * next_state)56 void Hero::FreeState::stop(const State* next_state) {
57 
58   PlayerMovementState::stop(next_state);
59 
60   get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE);
61 }
62 
63 /**
64  * \brief Updates this state.
65  */
update()66 void Hero::FreeState::update() {
67 
68   PlayerMovementState::update();
69 
70   if (!is_suspended()
71       && is_current_state()
72       && pushing_direction4 != -1                                       // The hero is trying to push
73       && get_wanted_movement_direction8() != pushing_direction4 * 2) {  // but his movement direction has changed.
74 
75     pushing_direction4 = -1; // stop trying to push
76   }
77 }
78 
79 /**
80  * \brief Notifies this state that the game was just suspended or resumed.
81  * \param suspended true if the game is suspended
82  */
set_suspended(bool suspended)83 void Hero::FreeState::set_suspended(bool suspended) {
84 
85   PlayerMovementState::set_suspended(suspended);
86 
87   if (!suspended) {
88     start_pushing_date += System::now() - get_when_suspended();
89   }
90 }
91 
92 /**
93  * \brief Notifies this state that the action command was just pressed.
94  */
notify_action_command_pressed()95 void Hero::FreeState::notify_action_command_pressed() {
96 
97   Hero& hero = get_entity();
98   Entity* facing_entity = hero.get_facing_entity();
99   bool facing_entity_interaction = false;
100   if (facing_entity != nullptr) {
101     if (get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_NONE ||
102         get_commands_effects().is_action_key_acting_on_facing_entity()
103     ) {
104       // Action on the facing entity.
105       facing_entity_interaction = facing_entity->notify_action_command_pressed();
106     }
107   }
108 
109   if (!facing_entity_interaction) {
110     // The event was not handled by the facing entity.
111     if (hero.is_facing_point_on_obstacle() &&
112         hero.can_grab()
113     ) {
114       // Grab an obstacle.
115       hero.start_grabbing();
116     }
117     else if (hero.can_run()) {
118       // Run.
119       hero.start_running();
120     }
121   }
122 }
123 
124 /**
125  * \brief Notifies this state that the hero has just failed to change its
126  * position because of obstacles.
127  */
notify_obstacle_reached()128 void Hero::FreeState::notify_obstacle_reached() {
129 
130   PlayerMovementState::notify_obstacle_reached();
131 
132   Hero& hero = get_entity();
133   Equipment& equipment = get_equipment();
134   if (hero.is_facing_point_on_obstacle() &&   // He is really facing an obstacle.
135       equipment.has_ability(Ability::PUSH)    // He is able to push.
136   ) {
137 
138     uint32_t now = System::now();
139     if (pushing_direction4 == -1) {
140       start_pushing_date = now + 800;  // Start animation "pushing" after 800 ms.
141       pushing_direction4 = hero.get_animation_direction();
142     }
143     else if (now >= start_pushing_date) {
144       equipment.notify_ability_used(Ability::PUSH);
145       hero.start_pushing();
146     }
147   }
148 }
149 
150 /**
151  * \brief Returns whether the hero can walk normally and interact with entities
152  * in this state.
153  * \return true
154  */
is_free() const155 bool Hero::FreeState::is_free() const {
156   return true;
157 }
158 
159 /**
160  * \copydoc Entity::State::get_can_interact_with_npc
161  */
get_can_interact_with_npc(Npc &) const162 bool Hero::FreeState::get_can_interact_with_npc(Npc& /* npc */) const {
163   return true;
164 }
165 
166 /**
167  * \brief Returns whether the hero can swing his sword in this state.
168  * \return true if the hero can swing his sword in this state
169  */
get_can_start_sword() const170 bool Hero::FreeState::get_can_start_sword() const {
171   return true;
172 }
173 
174 /**
175  * \brief Returns whether the hero can use an equipment item in this state.
176  * \param item The equipment item to check.
177  * \return true if the hero can use this equipment item in this state.
178  */
get_can_start_item(EquipmentItem &) const179 bool Hero::FreeState::get_can_start_item(EquipmentItem& /* item */) const {
180 
181   return get_entity().get_ground_below() != Ground::HOLE;
182 }
183 
184 /**
185  * \brief Returns whether the hero can take stairs in this state.
186  * If false is returned, stairs have no effect (but they are obstacle for the hero).
187  * \return true if the hero ignores the effect of stairs in this state
188  */
get_can_take_stairs() const189 bool Hero::FreeState::get_can_take_stairs() const {
190   return true;
191 }
192 
193 /**
194  * \copydoc Entity::State::get_previous_carried_object_behavior
195  */
get_previous_carried_object_behavior() const196 CarriedObject::Behavior Hero::FreeState::get_previous_carried_object_behavior() const {
197   return CarriedObject::Behavior::REMOVE;
198 }
199 
200 /**
201  * Gives the sprites the animation stopped corresponding to this state.
202  */
set_animation_stopped()203 void Hero::FreeState::set_animation_stopped() {
204   get_sprites().set_animation_stopped_normal();
205 }
206 
207 /**
208  * Gives the sprites the animation walking corresponding to this state.
209  */
set_animation_walking()210 void Hero::FreeState::set_animation_walking() {
211   get_sprites().set_animation_walking_normal();
212 }
213 
214 }
215 
216