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)32Hero::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)44void 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)56void 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()66void 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)83void 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()95void 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()128void 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() const155bool 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 &) const162bool 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() const170bool 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 &) const179bool 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() const189bool 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() const196CarriedObject::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()203void 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()210void Hero::FreeState::set_animation_walking() { 211 get_sprites().set_animation_walking_normal(); 212 } 213 214 } 215 216