diff --git a/src/badguy/crusher.cpp b/src/badguy/crusher.cpp index 0dfb20407ad..69828762cdf 100644 --- a/src/badguy/crusher.cpp +++ b/src/badguy/crusher.cpp @@ -123,31 +123,40 @@ HitResponse Crusher::collision(GameObject& other, const CollisionHit& hit) { auto* player = dynamic_cast(&other); + bool crushed_bottom = m_state == CRUSHING && !m_sideways && hit.bottom; + bool crushed_sideways = m_state == CRUSHING && m_sideways && + ((hit.left && m_physic.get_velocity_x() < 0.f) || + (hit.right && m_physic.get_velocity_x() > 0.f)); + bool is_crushing = crushed_bottom || crushed_sideways; // If the other object is the player, and the collision is at the // bottom of the crusher, hurt the player. - if (player && hit.bottom && player->on_ground() && m_state == CRUSHING) { + if (player && is_crushing && + ((crushed_bottom && player->on_ground()) || crushed_sideways)) { SoundManager::current()->play("sounds/brick.wav", get_pos()); set_state(RECOVERING); if (player->is_invincible()) { return ABORT_MOVE; } + if(crushed_sideways) + { + // TODO: Is there a better method than introducing + // a completely new player method (e.g. by returning + // ABORT_MOVE from this function)? + player->ignore_sideways_crush(); + } player->kill(false); return FORCE_MOVE; } auto* badguy = dynamic_cast(&other); - if (badguy && m_state == CRUSHING && ((!m_sideways && hit.bottom) || - (m_sideways && ((hit.left && m_physic.get_velocity_x() < 0.f) || - (hit.right && m_physic.get_velocity_x() > 0.f))))) + if (badguy && is_crushing) { badguy->kill_fall(); } auto* rock = dynamic_cast(&other); - if (rock && !rock->is_grabbed() && m_state == CRUSHING && ((!m_sideways && hit.bottom) || - (m_sideways && ((hit.left && m_physic.get_velocity_x() < 0.f) || - (hit.right && m_physic.get_velocity_x() > 0.f))))) + if (rock && !rock->is_grabbed() && is_crushing) { SoundManager::current()->play("sounds/brick.wav", get_pos()); m_physic.reset(); @@ -226,14 +235,20 @@ Crusher::collision_solid(const CollisionHit& hit) } } } - if (hit.bottom) - spawn_roots(Direction::DOWN); - else if (hit.top) - spawn_roots(Direction::UP); - else if (hit.left) - spawn_roots(Direction::LEFT); - else if (hit.right) - spawn_roots(Direction::RIGHT); + if(m_sideways) + { + if (hit.left) + spawn_roots(Direction::LEFT); + else if (hit.right) + spawn_roots(Direction::RIGHT); + } + else + { + if (hit.bottom) + spawn_roots(Direction::DOWN); + else if (hit.top) + spawn_roots(Direction::UP); + } break; default: log_debug << "Crusher in invalid state" << std::endl; @@ -637,18 +652,27 @@ Crusher::eye_position(bool right) const } break; case RECOVERING: + { + // Amplitude dependent on size. + auto amplitude = static_cast(m_sprite->get_width()) / 64.0f * 2.0f; + + //Phase factor due to cooldown timer. + auto cooldown_phase_factor = (m_ic_size == NORMAL ? RECOVER_SPEED_NORMAL : RECOVER_SPEED_LARGE) + m_cooldown_timer * 13.0f; + + // Phase factor due to y position. + auto y_position_phase_factor = !m_sideways ? get_pos().y / 13 : get_pos().x / 13; + + auto phase_factor = y_position_phase_factor - cooldown_phase_factor; + // Eyes spin while crusher is recovering, giving a dazed impression. return Vector(sinf((right ? 1 : -1) * // X motion of each eye is opposite of the other. - ((!m_sideways ? get_pos().y / 13 : get_pos().x / 13) - // Phase factor due to y position. - (m_ic_size == NORMAL ? RECOVER_SPEED_NORMAL : RECOVER_SPEED_LARGE) + m_cooldown_timer * 13.0f)) * //Phase factor due to cooldown timer. - static_cast(m_sprite->get_width()) / 64.0f * 2.0f - (right ? 1 : -1) * // Amplitude dependent on size. - static_cast(m_sprite->get_width()) / 64.0f * 2.0f, // Offset to keep eyes visible. + phase_factor) * amplitude - (right ? 1 : -1) * + amplitude, // Offset to keep eyes visible. cosf((right ? 3.1415f : 0.0f) + // Eyes spin out of phase of eachother. - (!m_sideways ? get_pos().y / 13 : get_pos().x / 13) - // Phase factor due to y position. - (m_ic_size == NORMAL ? RECOVER_SPEED_NORMAL : RECOVER_SPEED_LARGE) + m_cooldown_timer * 13.0f) * //Phase factor due to cooldown timer. - static_cast(m_sprite->get_width()) / 64.0f * 2.0f - // Amplitude dependent on size. - static_cast(m_sprite->get_width()) / 64.0f * 2.0f); // Offset to keep eyes visible. + phase_factor) * amplitude - + amplitude); // Offset to keep eyes visible. + } default: log_debug << "Crusher in invalid state" << std::endl; break; diff --git a/src/object/player.cpp b/src/object/player.cpp index 168a2a35244..e4b0f331023 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -185,6 +185,7 @@ Player::Player(PlayerStatus& player_status, const std::string& name_, int player m_jump_early_apex(false), m_on_ice(false), m_ice_this_frame(false), + m_ignore_sideways_crush(false), //m_santahatsprite(SpriteManager::current()->create("images/creatures/tux/santahat.sprite")), m_multiplayer_arrow(SpriteManager::current()->create("images/engine/hud/arrowdown.png")), m_tag_timer(), @@ -2324,8 +2325,13 @@ Player::collision_solid(const CollisionHit& hit) // crushed? if (hit.crush) { - if (hit.left || hit.right) { - kill(true); + if ((hit.left || hit.right)) { + if (m_ignore_sideways_crush) { + m_ignore_sideways_crush = false; + } + else { + kill(true); + } } else if (hit.top || hit.bottom) { kill(false); } diff --git a/src/object/player.hpp b/src/object/player.hpp index 720ec781949..7894d4c2dc9 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -425,6 +425,7 @@ class Player final : public MovingObject void remove_collected_key(Key* key); bool track_state() const override { return false; } + void ignore_sideways_crush() { m_ignore_sideways_crush = true; } private: void handle_input(); @@ -500,6 +501,7 @@ class Player final : public MovingObject bool m_jump_early_apex; bool m_on_ice; bool m_ice_this_frame; + bool m_ignore_sideways_crush; //SpritePtr m_santahatsprite; SpritePtr m_multiplayer_arrow;