/** * @brief Notifies this entity that it has just attacked an enemy. * * This function is called even if this attack was not successful. * * @param attack the attack * @param victim the enemy just hurt * @param result indicates how the enemy has reacted to the attack * @param killed indicates that the attack has just killed the enemy */ void CarriedItem::notify_attacked_enemy(EnemyAttack attack, Enemy& victim, EnemyReaction::Reaction& result, bool killed) { if (result.type != EnemyReaction::IGNORED) { break_item(); } }
/** * \brief This function is called when a crystal detects a collision with this entity. * \param crystal the crystal * \param collision_mode the collision mode that detected the event */ void CarriedItem::notify_collision_with_crystal(Crystal& crystal, CollisionMode collision_mode) { if (collision_mode == COLLISION_OVERLAPPING && is_being_thrown() && !can_explode()) { crystal.activate(*this); break_item(); } }
/** * \brief This function is called when a switch detects a collision with this entity. * \param sw the switch * \param collision_mode the collision mode that detected the event */ void CarriedItem::notify_collision_with_switch(Switch& sw, CollisionMode collision_mode) { if (collision_mode == COLLISION_OVERLAPPING && is_being_thrown() && !can_explode()) { sw.try_activate(); break_item(); } }
/** * \brief Destroys the item after it finishes its thrown movement. * * How the item breaks depends on the ground where it lands. */ void CarriedItem::break_item_on_ground() { get_movement()->stop(); Ground ground = get_ground_below(); switch (ground) { case Ground::EMPTY: // Nothing here: fall one layer below. { int layer = get_layer(); if (layer == 0) { // Cannot fall lower. break_item(); } else { get_entities().set_entity_layer(*this, layer - 1); break_item_on_ground(); // Do this again on the next layer. } break; } case Ground::HOLE: Sound::play("jump"); remove_from_map(); break; case Ground::DEEP_WATER: case Ground::LAVA: Sound::play("walk_on_water"); remove_from_map(); break; default: // Break the item normally. break_item(); break; } is_throwing = false; is_breaking = true; }
/** * \copydoc Entity::notify_attacked_enemy */ void CarriedItem::notify_attacked_enemy( EnemyAttack /* attack */, Enemy& /* victim */, const Sprite* /* victim_sprite */, EnemyReaction::Reaction& result, bool /* killed */) { if (result.type != EnemyReaction::ReactionType::IGNORED) { break_item(); } }
/** * \brief Notifies this entity that it has just failed to change its position * because of obstacles. */ void CarriedItem::notify_obstacle_reached() { if (is_throwing && !is_broken()) { break_item(); } }
/** * \brief This function is called repeatedly. */ void CarriedItem::update() { // update the sprite and the position Entity::update(); if (is_suspended()) { return; } // when the hero finishes lifting the item, start carrying it if (is_lifting && get_movement()->is_finished()) { is_lifting = false; // make the item follow the hero clear_movement(); set_movement(std::make_shared<RelativeMovement>( std::static_pointer_cast<Hero>(hero.shared_from_this()), 0, -18, true )); } // when the item has finished flying, destroy it else if (can_explode() && !is_breaking) { uint32_t now = System::now(); if (now >= explosion_date) { break_item(); } else if (will_explode_soon()) { std::string animation = get_sprite().get_current_animation(); if (animation == "stopped") { get_sprite().set_current_animation("stopped_explosion_soon"); } else if (animation == "walking") { get_sprite().set_current_animation("walking_explosion_soon"); } } } if (is_broken()) { remove_from_map(); } else if (is_throwing) { shadow_sprite->update(); if (break_one_layer_above) { break_item(); int layer = get_layer(); if (layer != get_map().get_highest_layer()) { get_entities().set_entity_layer(*this, layer + 1); } break_one_layer_above = false; } else if (get_movement()->is_stopped() || y_increment >= 7) { // Interrupt the movement. break_item_on_ground(); } else { uint32_t now = System::now(); while (now >= next_down_date) { next_down_date += 40; item_height -= y_increment; y_increment++; } } } }
/** * @brief This function is called repeatedly. */ void CarriedItem::update() { // update the sprite and the position MapEntity::update(); if (suspended) { return; } // when the hero finishes lifting the item, start carrying it if (is_lifting && get_movement()->is_finished()) { is_lifting = false; // make the item follow the hero clear_movement(); set_movement(new FollowMovement(&hero, 0, -18, true)); } // when the item has finished flying, destroy it else if (can_explode() && !is_breaking) { uint32_t now = System::now(); if (now >= explosion_date) { break_item(); } else if (will_explode_soon()) { std::string animation = get_sprite().get_current_animation(); if (animation == "stopped") { get_sprite().set_current_animation("stopped_explosion_soon"); } else if (animation == "walking") { get_sprite().set_current_animation("walking_explosion_soon"); } } } if (is_throwing) { shadow_sprite->update(); if (is_broken()) { remove_from_map(); } else if (break_on_intermediate_layer) { break_item(); get_entities().set_entity_layer(*this, LAYER_INTERMEDIATE); break_on_intermediate_layer = false; } else if (get_movement()->is_stopped() || y_increment >= 7) { break_item(); } else { uint32_t now = System::now(); while (now >= next_down_date) { next_down_date += 40; item_height -= y_increment; y_increment++; } } } }