Ejemplo n.º 1
0
/**
 * @brief Notifies this entity that another sprite is overlapping it.
 *
 * This function is called by check_collision(MapEntity*, Sprite*) when another entity's
 * sprite overlaps a sprite of this detector.
 *
 * @param other_entity the entity overlapping this detector
 * @param other_sprite the sprite of other_entity that is overlapping this detector
 * @param this_sprite the sprite of this detector that is overlapping the other entity's sprite
 */
void Destructible::notify_collision(MapEntity& other_entity,
    Sprite& other_sprite, Sprite& this_sprite) {

  if (features[subtype].can_be_cut
      && !is_being_cut
      && !is_disabled()
      && !is_regenerating
      && other_entity.is_hero()
      && other_sprite.contains("sword")) {

    Hero& hero = static_cast<Hero&>(other_entity);
    if (hero.is_striking_with_sword(*this)) {

      play_destroy_animation();
      hero.check_position(); // to update the ground under the hero
      create_pickable();

      if (can_explode()) {
        explode();
      }
    }
  }

  // TODO use dynamic dispatch
  if (other_entity.get_type() == EXPLOSION
      && can_explode()
      && !is_being_cut
      && !is_disabled()
      && !is_regenerating) {

    play_destroy_animation();
    create_pickable();
    explode();
  }
}
Ejemplo n.º 2
0
/**
 * \brief Destroys the item while it is being thrown.
 */
void CarriedItem::break_item() {

  if (is_throwing && throwing_direction != 3) {
    // destroy the item where it is actually drawn
    set_y(get_y() - item_height);
  }

  get_movement()->stop();

  if (!can_explode()) {
    if (!destruction_sound_id.empty()) {
      Sound::play(destruction_sound_id);
    }
    if (get_sprite().has_animation("destroy")) {
      get_sprite().set_current_animation("destroy");
    }
    else {
      remove_from_map();
    }
  }
  else {
    get_entities().add_entity(std::make_shared<Explosion>(
        "", get_layer(), get_xy(), true
    ));
    Sound::play("explosion");
    if (is_throwing) {
      remove_from_map(); // because if the item was still carried by the hero, then the hero class will destroy it
    }
  }
  is_throwing = false;
  is_breaking = true;
}
Ejemplo n.º 3
0
/**
 * \brief This function is called when this carried item collides an enemy.
 * \param enemy the enemy
 */
void CarriedItem::notify_collision_with_enemy(Enemy &enemy) {

  if (is_throwing
      && !can_explode()
      && get_damage_on_enemies() > 0) {
    enemy.try_hurt(EnemyAttack::THROWN_ITEM, *this, nullptr);
  }
}
Ejemplo n.º 4
0
/**
 * @brief This function is called when this carried item collides an enemy.
 * @param enemy the enemy
 */
void CarriedItem::notify_collision_with_enemy(Enemy &enemy) {

  if (is_throwing
      && !can_explode()
      && get_damage_on_enemies() > 0) {
    enemy.try_hurt(ATTACK_THROWN_ITEM, *this, NULL);
  }
}
Ejemplo n.º 5
0
/**
 * \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();
  }
}
Ejemplo n.º 6
0
/**
 * \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();
  }
}
Ejemplo n.º 7
0
/**
 * \brief Notifies this detector that the player is interacting with it by
 * pressing the action command.
 *
 * This function is called when the player presses the action command
 * while the hero is facing this detector, and the action command effect lets
 * him do this.
 */
void Destructible::notify_action_command_pressed() {

  KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect();

  if ((effect == KeysEffect::ACTION_KEY_LIFT || effect == KeysEffect::ACTION_KEY_LOOK)
      && features[subtype].can_be_lifted
      && !is_being_cut
      && !is_disabled()
      && !is_regenerating) {

    int weight = features[subtype].weight;

    if (get_equipment().has_ability("lift", weight)) {

      uint32_t explosion_date = can_explode() ? System::now() + 6000 : 0;
      get_hero().start_lifting(new CarriedItem(
          get_hero(),
          *this,
          get_animation_set_id(),
          get_destruction_sound_id(),
          get_damage_on_enemies(),
          explosion_date)
      );

      // play the sound
      Sound::play("lift");

      // create the pickable item
      create_pickable();

      // remove the item from the map
      if (!features[subtype].can_regenerate) {
        destruction_callback();
        remove_from_map();
      }
      else {
        // the item can actually regenerate
        play_destroy_animation();
      }
    }
    else {
      if (features[subtype].can_be_cut
          && !features[subtype].can_explode
          && !get_equipment().has_ability("sword", 1)) {
        get_game().start_dialog("_cannot_lift_should_cut", LUA_REFNIL);
      }
      else if (!get_equipment().has_ability("lift", 1)) {
        get_game().start_dialog("_cannot_lift_too_heavy", LUA_REFNIL);
      }
      else {
        get_game().start_dialog("_cannot_lift_still_too_heavy", LUA_REFNIL);
      }
    }
  }
}
Ejemplo n.º 8
0
/**
 * \brief This function is called by the map when the game is suspended or resumed.
 * \param suspended true to suspend the entity, false to resume it
 */
void CarriedItem::set_suspended(bool suspended) {

  Entity::set_suspended(suspended); // suspend the animation and the movement

  if (is_throwing) {
    // suspend the shadow
    shadow_sprite->set_suspended(suspended);
  }

  if (!suspended && get_when_suspended() != 0) {
    // recalculate the timers
    uint32_t diff = System::now() - get_when_suspended();
    if (is_throwing) {
      next_down_date += diff;
    }
    if (can_explode()) {
      explosion_date += diff;
    }
  }
}
Ejemplo n.º 9
0
/**
 * \brief Returns whether an enemy character is considered as an obstacle for this entity.
 * \param enemy an enemy
 * \return true if this enemy is considered as an obstacle for this entity.
 */
bool CarriedItem::is_enemy_obstacle(Enemy& /* enemy */) {
  // if this item explodes when reaching an obstacle, then we consider enemies as obstacles
  return can_explode();
}
Ejemplo n.º 10
0
/**
 * \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++;
      }
    }
  }
}
Ejemplo n.º 11
0
/**
 * \brief Returns whether the item is broken.
 * \return true if the item is broken
 */
bool CarriedItem::is_broken() const {
  return is_breaking && (get_sprite().is_animation_finished() || can_explode());
}
Ejemplo n.º 12
0
/**
 * \brief Returns whether the item is about to explode.
 * \return true if the item is about to explode
 */
bool CarriedItem::will_explode_soon()  const{
  return can_explode() && System::now() >= explosion_date - 1500;
}
Ejemplo n.º 13
0
/**
 * @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++;
      }
    }
  }
}