Example #1
0
/**
 * \brief This function is called by the engine when an entity overlaps the pickable item.
 *
 * If the entity is the player, we give him the item, and the map is notified
 * to destroy it.
 * \param entity_overlapping the entity overlapping the detector
 * \param collision_mode the collision mode that detected the collision
 */
void Pickable::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) {

    if (entity_overlapping.is_hero()) {
        try_give_item_to_player();
    }
    else if (entity_followed == NULL) {

        if (entity_overlapping.get_type() == ENTITY_BOOMERANG) {
            Boomerang& boomerang = static_cast<Boomerang&>(entity_overlapping);
            if (!boomerang.is_going_back()) {
                boomerang.go_back();
            }
            entity_followed = &boomerang;
        }
        else if (entity_overlapping.get_type() == ENTITY_HOOKSHOT) {
            Hookshot& hookshot = static_cast<Hookshot&>(entity_overlapping);
            if (!hookshot.is_going_back()) {
                hookshot.go_back();
            }
            entity_followed = &hookshot;
        }

        if (entity_followed != NULL) {
            clear_movement();
            set_movement(new FollowMovement(entity_followed, 0, 0, true));
            falling_height = FALLING_NONE;
            set_blinking(false);
        }
    }
}
Example #2
0
/**
 * \brief This function is called by the engine when an entity overlaps the pickable item.
 *
 * If the entity is the player, we give him the item, and the map is notified
 * to destroy it.
 * \param entity_overlapping the entity overlapping the detector
 * \param collision_mode the collision mode that detected the collision
 */
void Pickable::notify_collision(MapEntity& entity_overlapping, CollisionMode /* collision_mode */) {

  if (entity_overlapping.is_hero()) {
    try_give_item_to_player();
  }
  else if (entity_followed == nullptr) {

    MapEntityPtr shared_entity_overlapping =
        std::static_pointer_cast<MapEntity>(entity_overlapping.shared_from_this());
    if (entity_overlapping.get_type() == ENTITY_BOOMERANG) {
      Boomerang& boomerang = static_cast<Boomerang&>(entity_overlapping);
      if (!boomerang.is_going_back()) {
        boomerang.go_back();
      }
      entity_followed = shared_entity_overlapping;
    }
    else if (entity_overlapping.get_type() == ENTITY_HOOKSHOT) {
      Hookshot& hookshot = static_cast<Hookshot&>(entity_overlapping);
      if (!hookshot.is_going_back()) {
        hookshot.go_back();
      }
      entity_followed = shared_entity_overlapping;
    }

    if (entity_followed != nullptr) {
      clear_movement();
      set_movement(std::make_shared<FollowMovement>(
          entity_followed, 0, 0, true
      ));
      falling_height = FALLING_NONE;
      set_blinking(false);
    }
  }
}
Example #3
0
/**
 * \brief Returns the destination point specified by the last call to
 * set_destination().
 *
 * Returns NULL if the destination point was set to a special value
 * ("_same", "_side0", "_side1", "_side2" or "_side3").
 *
 * \return The destination point previously set, or NULL.
 */
Destination* Map::get_destination() {

  if (destination_name == "_same"
      || destination_name.substr(0,5) == "_side") {
    return NULL;
  }

  Debug::check_assertion(is_loaded(), "This map is not loaded");

  Destination* destination = NULL;
  std::string destination_name = this->destination_name;
  if (!destination_name.empty()) {
    // Use the destination whose name was specified.
    MapEntity* entity = get_entities().get_entity(destination_name);

    if (entity->get_type() != ENTITY_DESTINATION) {
      Debug::die(std::string("Map '") + get_id() + "': entity '"
          + destination_name + "' is not a destination");
    }
    destination = static_cast<Destination*>(entity);
  }
  else {
    // No destination name was set: use the default one.
    destination = get_entities().get_default_destination();
    if (destination == NULL) {
      Debug::die(std::string("Map '") + get_id() + "' has no destination entity");
    }
  }

  return destination;
}
Example #4
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();
  }
}
Example #5
0
/**
 * \brief Removes any boomerang from the map.
 */
void MapEntities::remove_arrows() {

  // TODO this function may be slow if there are a lot of entities: store the arrows?
  std::list<MapEntity*>::iterator it;
  for (it = all_entities.begin(); it != all_entities.end(); it++) {
    MapEntity* entity = *it;
    if (entity->get_type() == ARROW) {
      remove_entity(entity);
    }
  }
}
Example #6
0
/**
 * \brief Sets whether this custom entity can be traversed by the specified
 * entity.
 * \param entity The entity to test.
 * \return \c true if the entity can traverse this custom entity.
 */
bool CustomEntity::is_traversable_by_entity(MapEntity& entity) {

    // Find the obstacle settings.
    const TraversableInfo& info = get_traversable_by_entity_info(entity.get_type());

    if (info.is_empty()) {
        // Nothing was set: make the custom entity traversable by default.
        return true;
    }

    return info.is_traversable(*this, entity);
}
Example #7
0
/**
 * @brief Returns the entity with the specified type and name, or NULL if it doesn't exist.
 * @param type type of entity
 * @param name name of the entity to get
 * @return the entity requested, or NULL if there is no entity with the specified type and name
 */
MapEntity* MapEntities::find_entity(EntityType type, const std::string &name) {

  list<MapEntity*>::iterator i;
  for (i = all_entities.begin(); i != all_entities.end(); i++) {

    MapEntity *entity = *i;
    if (entity->get_type() == type && entity->get_name() == name && !entity->is_being_removed()) {
      return entity;
    }
  }

  return NULL;
}
Example #8
0
/**
 * @brief Returns the entities of the map with the specified type and having the specified name prefix.
 * @param type type of entity
 * @param prefix prefix of the name
 * @return the entities of this type and having this prefix in their name
 */
list<MapEntity*> MapEntities::get_entities_with_prefix(EntityType type, const std::string &prefix) {

  list<MapEntity*> entities;

  list<MapEntity*>::iterator i;
  for (i = all_entities.begin(); i != all_entities.end(); i++) {

    MapEntity *entity = *i;
    if (entity->get_type() == type && entity->has_prefix(prefix) && !entity->is_being_removed()) {
      entities.push_back(entity);
    }
  }

  return entities;
}
Example #9
0
/**
 * @brief Returns all entities of the map with the specified type.
 * @param type type of entity
 * @return the entities of this type
 */
list<MapEntity*> MapEntities::get_entities(EntityType type) {

  list<MapEntity*> entities;

  list<MapEntity*>::iterator i;
  for (i = all_entities.begin(); i != all_entities.end(); i++) {

    MapEntity *entity = *i;
    if (entity->get_type() == type && !entity->is_being_removed()) {
      entities.push_back(entity);
    }
  }

  return entities;
}
Example #10
0
/**
 * \copydoc Detector::notify_collision(MapEntity&, Sprite&, Sprite&)
 */
void Destructible::notify_collision(
    MapEntity& other_entity,
    Sprite& /* this_sprite */,
    Sprite& other_sprite
) {
  if (get_can_be_cut()
      && !is_being_cut
      && !is_waiting_for_regeneration()
      && !is_regenerating
      && other_entity.is_hero()) {

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

      play_destroy_animation();
      hero.check_position();  // To update the ground under the hero.
      create_treasure();

      get_lua_context().destructible_on_cut(*this);

      if (get_can_explode()) {
        explode();
      }
    }
  }

  // TODO use dynamic dispatch
  if (other_entity.get_type() == EntityType::EXPLOSION
      && get_can_explode()
      && !is_being_cut
      && !is_waiting_for_regeneration()
      && !is_regenerating) {

    play_destroy_animation();
    create_treasure();
    explode();
  }
}
Example #11
0
/**
 * \brief Returns the destination point specified by the last call to
 * set_destination().
 *
 * If the destination point was set to a special value
 * ("_same", "_side0", "_side1", "_side2" or "_side3"), returns nullptr.
 *
 * If the destination name is empty, returns the default destination if any,
 * or nullptr.
 *
 * Otherwise, if there is no destination entity with this name on the map,
 * prints an error message and returns the default destination if any or nullptr.
 *
 * \return The destination point previously set, or nullptr.
 */
Destination* Map::get_destination() {

  if (destination_name == "_same"
      || destination_name.substr(0,5) == "_side") {
    return nullptr;
  }

  Debug::check_assertion(is_loaded(), "This map is not loaded");

  Destination* destination = nullptr;
  if (!destination_name.empty()) {
    // Use the destination whose name was specified.
    MapEntity* entity = get_entities().find_entity(destination_name);

    if (entity == nullptr || entity->get_type() != EntityType::DESTINATION) {
      Debug::error(
          std::string("Map '") + get_id() + "': No such destination: '"
          + destination_name + "'"
      );
      // Perhaps the game was saved with a destination that no longer exists
      // or whose name was changed during the development of the quest.
      // This is not a fatal error: we will use the default destination
      // instead. It is up to quest makers to avoid this situation once their
      // quest is released.
    }
    else {
      destination = static_cast<Destination*>(entity);
    }
  }

  if (destination == nullptr) {
    // No valid destination name was set: use the default one if any.
    destination = get_entities().get_default_destination();
  }

  return destination;
}
Example #12
0
/**
 * \brief Removes and destroys the entities placed in the entities_to_remove list.
 */
void MapEntities::remove_marked_entities() {

  list<MapEntity*>::iterator it;

  // remove the marked entities
  for (it = entities_to_remove.begin();
       it != entities_to_remove.end();
       it++) {

    MapEntity* entity = *it;
    Layer layer = entity->get_layer();

    // remove it from the obstacle entities list if present
    if (entity->can_be_obstacle()) {

      if (entity->has_layer_independent_collisions()) {
        for (int i = 0; i < LAYER_NB; i++) {
          obstacle_entities[i].remove(entity);
        }
      }
      else {
        obstacle_entities[layer].remove(entity);
      }
    }

    // remove it from the detectors list if present
    if (entity->is_detector()) {
      detectors.remove(static_cast<Detector*>(entity));
    }

    // remove it from the ground obsevers list if present
    if (entity->is_ground_observer()) {
      ground_observers[layer].remove(entity);
    }

    // remove it from the ground modifiers list if present
    if (entity->is_ground_modifier()) {
      ground_modifiers[layer].remove(entity);
    }

    // remove it from the sprite entities list if present
    if (entity->is_drawn_in_y_order()) {
      entities_drawn_y_order[layer].remove(entity);
    }
    else if (entity->can_be_drawn()) {
      entities_drawn_first[layer].remove(entity);
    }

    // remove it from the whole list
    all_entities.remove(entity);
    const std::string& name = entity->get_name();
    if (!name.empty()) {
      named_entities.erase(name);
    }

    // update the specific entities lists
    switch (entity->get_type()) {

      case STAIRS:
        stairs[layer].remove(static_cast<Stairs*>(entity));
        break;

      case CRYSTAL_BLOCK:
        crystal_blocks[layer].remove(static_cast<CrystalBlock*>(entity));
        break;

      case SEPARATOR:
        separators.remove(static_cast<Separator*>(entity));
        break;

      case BOOMERANG:
        this->boomerang = NULL;
        break;

      default:
      break;
    }

    // destroy it
    destroy_entity(entity);
  }
  entities_to_remove.clear();
}
Example #13
0
/**
 * \brief Returns whether this entity is an obstacle for another one
 * when it is enabled.
 * \param other another entity
 * \return true if this entity is an obstacle for the other one
 */
bool Wall::is_obstacle_for(MapEntity& other) {

    std::set<EntityType>::const_iterator it =
        entity_types_stopped.find(other.get_type());
    return it != entity_types_stopped.end();
}
Example #14
0
/**
 * \brief Returns whether this entity is an obstacle for another one
 * when it is enabled.
 * \param other another entity
 * \return true if this entity is an obstacle for the other one
 */
bool Wall::is_obstacle_for(MapEntity &other) {
  return entity_types_stopped[other.get_type()];
}
Example #15
0
/**
 * \brief Returns whether this entity is an obstacle for another one
 * when it is enabled.
 * \param other another entity
 * \return true if this entity is an obstacle for the other one
 */
bool Wall::is_obstacle_for(MapEntity& other) {

  const auto it = entity_types_stopped.find(other.get_type());
  return it != entity_types_stopped.end();
}
Example #16
0
/**
 * @brief Notifies this detector that a pixel-perfect collision was just detected with another sprite.
 *
 * 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 Door::notify_collision(MapEntity& other_entity, Sprite& other_sprite, Sprite& this_sprite) {

  if (other_entity.get_type() == EXPLOSION) {
    notify_collision_with_explosion(static_cast<Explosion&>(other_entity), other_sprite);
  }
}