/** * \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); } } }
/** * \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); } } }
/** * @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(); } }
/** * @brief Notifies this detector that a collision was just detected with an entity. * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision (useful if * the detector has several collision modes) */ void DynamicTile::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { if (entity_overlapping.is_hero()) { // tell the hero that he is on the ground of this tile Hero& hero = (Hero&) entity_overlapping; Ground ground = Map::obstacle_to_ground(tile_pattern->get_obstacle()); hero.set_ground(ground); } }
/** * \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 Pickable::notify_collision(MapEntity& other_entity, Sprite& other_sprite, Sprite& this_sprite) { // taking the item with the sword if (other_entity.is_hero() && other_sprite.contains("sword")) { try_give_item_to_player(); } }
/** * \brief This function is called when another entity overlaps this crystal block. * \param entity_overlapping the other entity * \param collision_mode the collision mode that detected the collision */ void CrystalBlock::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { if (entity_overlapping.is_hero() && is_raised()) { // see if we have to make fim fall Hero& hero = static_cast<Hero&>(entity_overlapping); if (hero.can_control_movement()) { Rectangle collision_box = hero.get_bounding_box(); int x1 = get_top_left_x(); int x2 = x1 + get_width(); int y1 = get_top_left_y(); int y2 = y1 + get_height(); int jump_direction = 0; int jump_length = 0; bool jumped = false; const Rectangle &hero_center = hero.get_center_point(); if (hero_center.get_y() < y1) { // fall to the north collision_box.set_y(y1 - 16); jump_direction = 2; jump_length = hero.get_top_left_y() + 16 - y1; jumped = try_jump(hero, collision_box, jump_direction, jump_length); } else if (hero_center.get_y() >= y2) { // fall to the south collision_box.set_y(y2); jump_direction = 6; jump_length = y2 - hero.get_top_left_y(); jumped = try_jump(hero, collision_box, jump_direction, jump_length); } if (!jumped) { if (hero_center.get_x() >= x2) { // fall to the east collision_box.set_x(x2); jump_direction = 0; jump_length = x2 - hero.get_top_left_x(); try_jump(hero, collision_box, jump_direction, jump_length); } else if (hero_center.get_x() < x1) { // fall to the west collision_box.set_x(x1 - 16); jump_direction = 4; jump_length = hero.get_top_left_x() + 16 - x1; try_jump(hero, collision_box, jump_direction, jump_length); } } } } }
/** * \copydoc Detector::notify_collision(MapEntity&, Sprite&, Sprite&) */ void Pickable::notify_collision( MapEntity& other_entity, Sprite& /* this_sprite */, Sprite& other_sprite ) { // taking the item with the sword if (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()) { try_give_item_to_player(); } } }
/** * @brief This function is called by the engine when an entity overlaps the shop item. * * If the entity is the hero, we allow him to buy the item. * * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision */ void ShopItem::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { if (entity_overlapping.is_hero() && !get_game().is_suspended()) { Hero &hero = (Hero&) entity_overlapping; if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { // we show the 'look' icon get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \brief This function is called by the engine when an entity overlaps the shop item. * * If the entity is the hero, we allow him to buy the item. * * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void ShopTreasure::notify_collision( MapEntity& entity_overlapping, CollisionMode /* collision_mode */) { if (entity_overlapping.is_hero() && !get_game().is_suspended()) { Hero& hero = static_cast<Hero&>(entity_overlapping); if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { // we show the 'look' icon get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } }
/** * \brief Returns whether an entity's collides with this jumper. * * The result depends on the sensor's shape. * * \param entity the entity * \return true if the entity's collides with this jumper */ bool Jumper::test_collision_custom(MapEntity& entity) { if (!entity.is_hero()) { return false; } Hero& hero = static_cast<Hero&>(entity); const int direction8 = get_direction(); if (!is_jump_diagonal()) { int expected_hero_direction4 = direction8 / 2; if (!hero.is_moving_towards(expected_hero_direction4)) { return false; } } return is_in_jump_position(hero); }
/** * @brief Returns whether an entity's collides with this entity. * @param entity an entity * @return true if the entity's collides with this entity */ bool Teletransporter::test_collision_custom(MapEntity& entity) { bool collision = false; bool normal_case = true; // specific collision tests for some situations if (entity.is_hero()) { Hero& hero = (Hero&) entity; if (is_on_map_side()) { // scrolling towards an adjacent map Rectangle facing_point = hero.get_facing_point(transition_direction); collision = hero.is_moving_towards(transition_direction) && overlaps(facing_point.get_x(), facing_point.get_y()); normal_case = false; } else if (!get_map().test_collision_with_border(get_center_point()) && hero.get_ground() == GROUND_HOLE) { // falling into a hole collision = overlaps(hero.get_ground_point()); normal_case = false; } } // normal case if (normal_case) { const Rectangle& entity_rectangle = entity.get_bounding_box(); int x1 = entity_rectangle.get_x() + 4; int x2 = x1 + entity_rectangle.get_width() - 9; int y1 = entity_rectangle.get_y() + 4; int y2 = y1 + entity_rectangle.get_height() - 9; collision = overlaps(x1, y1) && overlaps(x2, y1) && overlaps(x1, y2) && overlaps(x2, y2); } if (!collision && !is_on_map_side()) { transporting_hero = false; } return collision; }
/** * @brief Notifies this detector that a collision was just detected with another entity. * * This function is called by the engine when there is a collision with another entity. * * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision */ void Door::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { if (is_closed() && entity_overlapping.is_hero()) { Hero& hero = static_cast<Hero&>(entity_overlapping); if (get_keys_effect().get_action_key_effect() == KeysEffect::ACTION_KEY_NONE && hero.is_free()) { if (can_open()) { // The action command opens the door. get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_OPEN); } else if (!get_cannot_open_dialog_id().empty()) { // The action command shows a dialog. get_keys_effect().set_action_key_effect(KeysEffect::ACTION_KEY_LOOK); } } } }
/** * \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(); } }
/** * @brief Returns whether an entity's collides with this jumper. * * The result depends on the sensor's shape. * * @param entity the entity * @return true if the entity's collides with this jumper */ bool Jumper::test_collision_custom(MapEntity &entity) { if (!entity.is_hero()) { return false; } Hero &hero = (Hero&) entity; int direction8 = get_direction(); // if the sensor's has one of the four main directions, then // its shape is exactly its rectangle if (direction8 % 2 == 0) { int expected_hero_direction4 = direction8 / 2; if (hero.get_ground() == GROUND_DEEP_WATER) { // if the hero is swimming, the jumper can be used the opposite way expected_hero_direction4 = (expected_hero_direction4 + 2) % 4; } if (!hero.is_moving_towards(expected_hero_direction4)) { return false; } bool horizontal = (direction8 % 4 == 0); // horizontal or vertical jumper const Rectangle &facing_point = hero.get_facing_point(expected_hero_direction4); return overlaps(facing_point.get_x() + (horizontal ? 0 : -8), facing_point.get_y() + (horizontal ? -8 : 0)) && overlaps(facing_point.get_x() + (horizontal ? 0 : 7), facing_point.get_y() + (horizontal ? 7 : 0)); } // otherwise, the sensor's shape is a diagonal bar return is_point_in_diagonal(hero.get_facing_point((direction8 - 1) / 2)) || is_point_in_diagonal(hero.get_facing_point((direction8 + 1) % 8 / 2)); }
void Pickable::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { if(entity_overlapping.is_hero() && pickable) { remove_from_map(); hero_pick_item(); } }