/** * @brief Returns whether an entity collides with this detector with respect to a custom rule. * @param entity the entity * @return true if the entity's collides with this detector with respect to the custom rule */ bool DynamicTile::test_collision_custom(MapEntity &entity) { // we must test the same coordinates as non-dynamic tiles (see Hero::get_ground_point()) return overlaps(entity.get_x(), entity.get_y() - 2); }
/** * @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 CrystalSwitch::notify_collision(MapEntity &other_entity, Sprite &other_sprite, Sprite &this_sprite) { other_entity.notify_collision_with_crystal_switch(*this, other_sprite); }
/** * @brief This function is called when another entity collides with this crystal switch. * @param entity_overlapping the other entity * @param collision_mode the collision mode that detected the collision */ void CrystalSwitch::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_crystal_switch(*this, collision_mode); }
/** * \brief Returns whether this entity is an obstacle for another one. * \param other another entity * \return true if this entity is an obstacle for the other one */ bool Sensor::is_obstacle_for(const MapEntity& other) const { return other.is_sensor_obstacle(*this); }
/** * \brief Tests whether a point collides with the ground of the map. * * The ground is the terrain of the point. It is defined by the tiles and * by the presence of entities that may change it * (like dynamic tiles and destructible items). * * This method also returns true if the point is outside the map. * * \param layer Layer of the point. * \param x X of the point in pixels. * \param y Y of the point in pixels. * \param entity_to_check The entity to check (used to decide what grounds are * considered as obstacle). * \param [out] found_diagonal_wall \c true if the ground under this point was * a diagonal wall, unchanged otherwise. * Your algorithm may decide to check more points if there is a diagonal wall. * \return \c true if this point is on an obstacle. */ bool Map::test_collision_with_ground( Layer layer, int x, int y, const MapEntity& entity_to_check, bool& found_diagonal_wall) const { bool on_obstacle = false; int x_in_tile, y_in_tile; // If the point is outside the map, this is an obstacle. if (test_collision_with_border(x, y)) { return true; } // Get the ground property under this point. Ground ground = get_ground(layer, x, y); switch (ground) { case GROUND_EMPTY: case GROUND_TRAVERSABLE: case GROUND_GRASS: case GROUND_ICE: // The square is not an obstacle. on_obstacle = false; break; case GROUND_WALL: // The square is entirely an obstacle. on_obstacle = true; break; case GROUND_WALL_TOP_RIGHT: case GROUND_WALL_TOP_RIGHT_WATER: // The upper right half of the square is an obstacle // so we have to test the position of the point in the square. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_TOP_LEFT: case GROUND_WALL_TOP_LEFT_WATER: // Same thing. x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile <= 7 - x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_BOTTOM_LEFT: case GROUND_WALL_BOTTOM_LEFT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= x_in_tile; found_diagonal_wall = true; break; case GROUND_WALL_BOTTOM_RIGHT: case GROUND_WALL_BOTTOM_RIGHT_WATER: x_in_tile = x & 7; y_in_tile = y & 7; on_obstacle = y_in_tile >= 7 - x_in_tile; found_diagonal_wall = true; break; case GROUND_LOW_WALL: on_obstacle = entity_to_check.is_low_wall_obstacle(); break; case GROUND_SHALLOW_WATER: on_obstacle = entity_to_check.is_shallow_water_obstacle(); break; case GROUND_DEEP_WATER: on_obstacle = entity_to_check.is_deep_water_obstacle(); break; case GROUND_HOLE: on_obstacle = entity_to_check.is_hole_obstacle(); break; case GROUND_LAVA: on_obstacle = entity_to_check.is_lava_obstacle(); break; case GROUND_PRICKLE: on_obstacle = entity_to_check.is_prickle_obstacle(); break; case GROUND_LADDER: on_obstacle = entity_to_check.is_ladder_obstacle(); break; } return on_obstacle; }
/** * \copydoc Detector::notify_collision(MapEntity&, Sprite&, Sprite&) */ void Crystal::notify_collision(MapEntity& other_entity, Sprite& /* this_sprite */, Sprite& other_sprite) { other_entity.notify_collision_with_crystal(*this, other_sprite); }
/** * \brief Notifies the enemy that a collision was just detected with another entity * \param entity_overlapping the other entity * \param collision_mode the collision mode that detected the collision */ void Enemy::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_enemy(*this); }
/** * \brief Returns whether this entity is an obstacle for another one. * \param other another entity * \return true */ bool Block::is_obstacle_for(const MapEntity& other) const { return other.is_block_obstacle(*this); }
/** * \brief 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 Block::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_block(*this); }
/** * @brief Notifies this entity 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 Explosion::notify_collision(MapEntity &other_entity, Sprite &other_sprite, Sprite &this_sprite) { other_entity.notify_collision_with_explosion(*this, other_sprite); }
/** * \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(); }
/** * \brief This function is called by the engine when an entity overlaps the destructible item. * * If the entity is the hero, we allow him to lift the item. * * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void Destructible::notify_collision(MapEntity &entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_destructible(*this, collision_mode); }
/** * \brief Tests whether an entity's collides with this entity. * * This custom collision test is used for destructible items that change the ground drawn under the hero. * * \param entity an entity * \return true if the entity's collides with this entity */ bool Destructible::test_collision_custom(MapEntity &entity) { return overlaps(entity.get_x(), entity.get_y() - 2); }
/** * \brief Returns whether this entity is an obstacle for another one. * * For a destructible item, this does not depend on the other * entity but only on the subtype of destructible item. * * \param other another entity * \return true if this entity is an obstacle for others */ bool Destructible::is_obstacle_for(const MapEntity& other) const { return features[subtype].can_be_lifted && !is_being_cut && other.is_destructible_obstacle(*this); }
/** * @brief Sets the entity to target with this movement. */ void PathFindingMovement::set_target(MapEntity& target) { this->target = ⌖ target.increment_refcount(); next_recomputation_date = System::now() + 100; }
/** * \brief Returns whether an entity's rectangle is overlapping the detector's rectangle. * * This method is called by check_collision(MapEntity*) when the detector's collision * mode is COLLISION_RECTANGLE. * * \param entity the entity * \return true if the entity's rectangle is overlapping the detector's rectangle */ bool Detector::test_collision_rectangle(MapEntity& entity) { return entity.overlaps(*this); }
/** * \brief This function is called by the engine when an entity overlaps this detector. * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void Bomb::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_bomb(*this, collision_mode); }
/** * \brief Returns whether an entity's rectangle is entirely inside the detector's rectangle. * * This method is called by check_collision(MapEntity*) when the detector's collision * mode is COLLISION_INSIDE. * * \param entity the entity * \return true if the entity's rectangle is entirely inside the detector's rectangle */ bool Detector::test_collision_inside(MapEntity& entity) { return get_bounding_box().contains(entity.get_bounding_box()); }
/** * \brief Makes the enemy receive an attack. * * He might resist to the attack or get hurt. * * \param attack type of attack * \param source the entity attacking the enemy (often the hero) * \param this_sprite the sprite of this enemy that received the attack, or NULL * if the attack comes from a non pixel-precise collision test */ void Enemy::try_hurt(EnemyAttack attack, MapEntity& source, Sprite* this_sprite) { EnemyReaction::Reaction reaction = get_attack_consequence(attack, this_sprite); if (invulnerable || reaction.type == EnemyReaction::IGNORED) { // ignore the attack return; } invulnerable = true; vulnerable_again_date = System::now() + 500; switch (reaction.type) { case EnemyReaction::PROTECTED: // attack failure sound Sound::play("sword_tapping"); break; case EnemyReaction::IMMOBILIZED: // get immobilized hurt(source); immobilize(); notify_hurt(source, attack, 0); break; case EnemyReaction::CUSTOM: // custom attack (defined in the script) if (is_in_normal_state()) { custom_attack(attack, this_sprite); } else { // no attack was made: notify the source correctly reaction.type = EnemyReaction::IGNORED; invulnerable = false; } break; case EnemyReaction::HURT: if (is_immobilized() && get_sprite().get_current_animation() == "shaking") { stop_immobilized(); } // compute the number of health points lost by the enemy if (attack == ATTACK_SWORD) { // for a sword attack, the damage depends on the sword and the variant of sword attack used int damage_multiplicator = ((Hero&) source).get_sword_damage_factor(); reaction.life_lost *= damage_multiplicator; } else if (attack == ATTACK_THROWN_ITEM) { reaction.life_lost *= ((CarriedItem&) source).get_damage_on_enemies(); } life -= reaction.life_lost; hurt(source); notify_hurt(source, attack, reaction.life_lost); break; case EnemyReaction::IGNORED: case EnemyReaction::REACTION_NUMBER: Debug::die(StringConcat() << "Invalid enemy reaction" << reaction.type); break; } // notify the source source.notify_attacked_enemy(attack, *this, reaction, get_life() <= 0); }
/** * \brief Returns whether the facing point of an entity is overlapping the detector's rectangle. * * This method is called by check_collision(MapEntity*) when the detector's collision * mode is COLLISION_FACING_POINT. * * \param entity the entity * \return true if the entity's facing point is overlapping the detector's rectangle */ bool Detector::test_collision_facing_point(MapEntity& entity) { return entity.is_facing_point_in(get_bounding_box()); }
/** * \brief Notifies this enemy that a pixel-precise 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 enemy. * * \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 Enemy::notify_collision(MapEntity &other_entity, Sprite &other_sprite, Sprite &this_sprite) { other_entity.notify_collision_with_enemy(*this, this_sprite, other_sprite); }
/** * \brief Returns whether the center point of an entity is overlapping the detector's rectangle. * * This method is called by check_collision(MapEntity*) when the detector's collision * mode is COLLISION_CENTER. * * \param entity the entity * \return true if the entity's center is overlapping the detector's rectangle */ bool Detector::test_collision_center(MapEntity& entity) { return entity.is_center_in(get_bounding_box()); }
/** * \brief This function is called by the engine when an entity overlaps this sensor. * \param entity_overlapping the entity overlapping the detector * \param collision_mode the collision mode that detected the collision */ void Sensor::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_sensor(*this, collision_mode); }
/** * \brief Makes the camera move towards an entity. * * The camera will be centered on the entity's center point. * If there was already a movement, the new one replaces it. * Note that the camera will not update its movement if the entity moves. * * \param entity the target entity */ void Camera::move(MapEntity& entity) { const Rectangle& center = entity.get_center_point(); move(center.get_x(), center.get_y()); }
void Chest::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_chest(*this); }
/** * @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); } }
/** * @brief Returns whether this entity is an obstacle for another one. * @param other another entity * @return true if this entity is an obstacle for the other one */ bool CrystalSwitch::is_obstacle_for(MapEntity &other) { return other.is_crystal_switch_obstacle(*this); }
/** * @brief Notifies this entity that a pixel-precise 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 Fire::notify_collision(MapEntity& other_entity, Sprite& other_sprite, Sprite& this_sprite) { other_entity.notify_collision_with_fire(*this, other_sprite); }
/** * \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 Stairs::is_obstacle_for(MapEntity& other) { return other.is_stairs_obstacle(*this); }
/** * @brief This function is called by the engine when an entity overlaps the teletransporter. * @param entity_overlapping the entity overlapping the detector * @param collision_mode the collision mode that detected the collision */ void Teletransporter::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) { entity_overlapping.notify_collision_with_teletransporter(*this, collision_mode); }