diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp index f86cccbf0a9..77b72637d88 100644 --- a/src/common/Collision/DynamicTree.cpp +++ b/src/common/Collision/DynamicTree.cpp @@ -221,7 +221,7 @@ bool DynamicMapTree::isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, PhaseShift const& phaseShift) const { - G3D::Vector3 v(x, y, z + 0.5f); + G3D::Vector3 v(x, y, z); G3D::Ray r(v, G3D::Vector3(0, 0, -1)); DynamicTreeIntersectionCallback callback(phaseShift); impl->intersectZAllignedRay(r, callback, maxSearchDist); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 073e064b3f8..a6c474862cb 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2867,7 +2867,7 @@ void Creature::UpdateMovementFlags() // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc) float ground = GetFloorZ(); - bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling + bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling if (GetCreatureTemplate()->InhabitType & INHABIT_AIR && isInAir && !IsFalling()) { diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index d82cf667475..7d0e25952cd 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1289,7 +1289,7 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 void WorldObject::UpdatePositionData() { PositionFullTerrainStatus data; - GetMap()->GetFullTerrainStatusForPosition(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), data); + GetMap()->GetFullTerrainStatusForPosition(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), data, MAP_ALL_LIQUIDS); ProcessPositionDataChanged(data); } @@ -1408,22 +1408,22 @@ bool WorldObject::IsInMap(const WorldObject* obj) const bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist) const { - return IsInDist(x, y, z, dist); + return IsInDist(x, y, z, dist + GetCombatReach()); } -bool WorldObject::IsWithinDist3d(const Position* pos, float dist) const +bool WorldObject::IsWithinDist3d(Position const* pos, float dist) const { - return IsInDist(pos, dist); + return IsInDist(pos, dist + GetCombatReach()); } bool WorldObject::IsWithinDist2d(float x, float y, float dist) const { - return IsInDist2d(x, y, dist); + return IsInDist2d(x, y, dist + GetCombatReach()); } -bool WorldObject::IsWithinDist2d(const Position* pos, float dist) const +bool WorldObject::IsWithinDist2d(Position const* pos, float dist) const { - return IsInDist2d(pos, dist); + return IsInDist2d(pos, dist + GetCombatReach()); } bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const @@ -1438,7 +1438,7 @@ bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, Position WorldObject::GetHitSpherePointFor(Position const& dest) const { - G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ()); + G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ() + GetCollisionHeight()); G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(GetPosition()), GetCombatReach()); @@ -1449,13 +1449,17 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks ch { if (IsInWorld()) { + oz += GetCollisionHeight(); float x, y, z; if (GetTypeId() == TYPEID_PLAYER) + { GetPosition(x, y, z); + z += GetCollisionHeight(); + } else GetHitSpherePointFor({ ox, oy, oz }, x, y, z); - return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f, checks, ignoreFlags); + return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z, ox, oy, oz, checks, ignoreFlags); } return true; @@ -1466,13 +1470,25 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, LineOfSightChecks che if (!IsInMap(obj)) return false; - float x, y, z; + float ox, oy, oz; if (obj->GetTypeId() == TYPEID_PLAYER) - obj->GetPosition(x, y, z); + { + obj->GetPosition(ox, oy, oz); + oz += GetCollisionHeight(); + } else - obj->GetHitSpherePointFor(GetPosition(), x, y, z); + obj->GetHitSpherePointFor({ GetPositionX(), GetPositionY(), GetPositionZ() + GetCollisionHeight() }, ox, oy, oz); - return IsWithinLOS(x, y, z, checks, ignoreFlags); + float x, y, z; + if (GetTypeId() == TYPEID_PLAYER) + { + GetPosition(x, y, z); + z += GetCollisionHeight(); + } + else + GetHitSpherePointFor({ obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + obj->GetCollisionHeight() }, x, y, z); + + return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z, ox, oy, oz, checks, ignoreFlags); } void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const @@ -1630,9 +1646,7 @@ Position WorldObject::GetRandomPoint(const Position &srcPos, float distance) con void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const { - float new_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z + 2.0f, true); - if (new_z > INVALID_HEIGHT) - z = new_z + 0.05f; // just to be sure that we are not a few pixel under the surface + z = GetMapHeight(x, y, z); } void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const @@ -1652,8 +1666,8 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const bool canSwim = ToCreature()->CanSwim(); float ground_z = z; float max_z = canSwim - ? GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)) - : ((ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true))); + ? GetMapWaterOrGroundLevel(x, y, z, &ground_z) + : (ground_z = GetMapHeight(x, y, z)); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -1664,7 +1678,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); + float ground_z = GetMapHeight(x, y, z); if (z < ground_z) z = ground_z; } @@ -1676,7 +1690,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const if (!ToPlayer()->CanFly()) { float ground_z = z; - float max_z = GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, &ground_z, !ToUnit()->HasAuraType(SPELL_AURA_WATER_WALK)); + float max_z = GetMapWaterOrGroundLevel(x, y, z, &ground_z); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -1687,7 +1701,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); + float ground_z = GetMapHeight(x, y, z); if (z < ground_z) z = ground_z; } @@ -1695,7 +1709,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } default: { - float ground_z = GetMap()->GetHeight(GetPhaseShift(), x, y, z, true); + float ground_z = GetMapHeight(x, y, z); if (ground_z > INVALID_HEIGHT) z = ground_z; break; @@ -2476,8 +2490,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) return; } - ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true); - floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true); + ground = GetMapHeight(destx, desty, MAX_HEIGHT); + floor = GetMapHeight(destx, desty, pos.m_positionZ); destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor; float step = dist/10.0f; @@ -2489,8 +2503,8 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) { destx -= step * std::cos(angle); desty -= step * std::sin(angle); - ground = GetMap()->GetHeight(GetPhaseShift(), destx, desty, MAX_HEIGHT, true); - floor = GetMap()->GetHeight(GetPhaseShift(), destx, desty, pos.m_positionZ, true); + ground = GetMapHeight(destx, desty, MAX_HEIGHT); + floor = GetMapHeight(destx, desty, pos.m_positionZ); destz = std::fabs(ground - pos.m_positionZ) <= std::fabs(floor - pos.m_positionZ) ? ground : floor; } // we have correct destz now @@ -2507,38 +2521,13 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) pos.SetOrientation(GetOrientation()); } -// @todo: replace with WorldObject::UpdateAllowedPositionZ -float NormalizeZforCollision(WorldObject* obj, float x, float y, float z) -{ - float ground = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, MAX_HEIGHT, true); - float floor = obj->GetMap()->GetHeight(obj->GetPhaseShift(), x, y, z + 2.0f, true); - float helper = std::fabs(ground - z) <= std::fabs(floor - z) ? ground : floor; - if (z > helper) // must be above ground - { - if (Unit* unit = obj->ToUnit()) - { - if (unit->CanFly()) - return z; - } - LiquidData liquid_status; - ZLiquidStatus res = obj->GetMap()->GetLiquidStatus(obj->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status); - if (res && liquid_status.level > helper) // water must be above ground - { - if (liquid_status.level > z) // z is underwater - return z; - else - return std::fabs(liquid_status.level - z) <= std::fabs(helper - z) ? liquid_status.level : helper; - } - } - return helper; -} - void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float angle) { angle += GetOrientation(); float destx, desty, destz; destx = pos.m_positionX + dist * std::cos(angle); desty = pos.m_positionY + dist * std::sin(angle); + destz = pos.m_positionZ; // Prevent invalid coordinates here, position is unchanged if (!Trinity::IsValidMapCoord(destx, desty)) @@ -2547,9 +2536,9 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float return; } - destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ()); + UpdateAllowedPositionZ(destx, desty, destz); bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY), - pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f); + pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); // collision occured if (col) @@ -2561,7 +2550,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float } // check dynamic collision - col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + 0.5f, destx, desty, destz + 0.5f, destx, desty, destz, -0.5f); + col = GetMap()->getObjectHitPos(GetPhaseShift(), pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); // Collided with a gameobject if (col) @@ -2580,7 +2569,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float { destx -= step * std::cos(angle); desty -= step * std::sin(angle); - destz = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ()); + UpdateAllowedPositionZ(destx, desty, destz); } // we have correct destz now else @@ -2592,7 +2581,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float Trinity::NormalizeMapCoord(pos.m_positionX); Trinity::NormalizeMapCoord(pos.m_positionY); - pos.m_positionZ = NormalizeZforCollision(this, destx, desty, pos.GetPositionZ()); + UpdateAllowedPositionZ(destx, desty, pos.m_positionZ); pos.SetOrientation(GetOrientation()); } @@ -2781,6 +2770,22 @@ float WorldObject::GetFloorZ() const return std::max(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ())); } +float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const +{ + if (Unit const* unit = ToUnit()) + return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, !unit->HasAuraType(SPELL_AURA_WATER_WALK), GetCollisionHeight()); + + return z; +} + +float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const +{ + if (z != MAX_HEIGHT) + z += GetCollisionHeight(); + + return GetMap()->GetHeight(GetPhaseShift(), x, y, z, vmap, distanceToSearch); +} + template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector&, uint32, float) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 8a8444608da..1fe3dd19bf2 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -59,6 +59,8 @@ struct QuaternionData; typedef std::unordered_map UpdateDataMapType; +float const DEFAULT_COLLISION_HEIGHT = 2.03128f; // Most common value in dbc + class TC_GAME_API Object { public: @@ -471,6 +473,10 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation virtual float GetStationaryO() const { return GetOrientation(); } float GetFloorZ() const; + virtual float GetCollisionHeight() const { return 0.0f; } + + float GetMapWaterOrGroundLevel(float x, float y, float z, float* ground = nullptr) const; + float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f) const; // DEFAULT_HEIGHT_SEARCH in map.h uint16 GetAIAnimKitId() const { return m_aiAnimKitId; } void SetAIAnimKitId(uint16 animKitId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 03499ed1fbf..cbe6eaed42e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2062,7 +2062,7 @@ void Player::SetObjectScale(float scale) SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, scale * DEFAULT_WORLD_OBJECT_SIZE); SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH); if (IsInWorld()) - SendMovementSetCollisionHeight(scale * GetCollisionHeight(IsMounted())); + SendMovementSetCollisionHeight(scale * GetCollisionHeight()); } bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const @@ -27981,39 +27981,6 @@ void Player::SendMovementSetCollisionHeight(float height) Movement::PacketSender(this, NULL_OPCODE, SMSG_MOVE_SET_COLLISION_HEIGHT, SMSG_MOVE_UPDATE_COLLISION_HEIGHT, &extra).Send(); } -float Player::GetCollisionHeight(bool mounted) const -{ - if (mounted) - { - CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID)); - if (!mountDisplayInfo) - return GetCollisionHeight(false); - - CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId); - if (!mountModelData) - return GetCollisionHeight(false); - - CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); - ASSERT(displayInfo); - CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); - ASSERT(modelData); - - float scaleMod = GetObjectScale(); // 99% sure about this - - return scaleMod * mountModelData->MountHeight + modelData->CollisionHeight * 0.5f; - } - else - { - //! Dismounting case - use basic default model data - CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); - ASSERT(displayInfo); - CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); - ASSERT(modelData); - - return modelData->CollisionHeight; - } -} - std::string Player::GetMapAreaAndZoneString() const { uint32 areaId = GetAreaId(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0fe7039dd8a..353e7eccdd3 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2348,9 +2348,6 @@ class TC_GAME_API Player : public Unit, public GridObject bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } - //! Return collision height sent to client - float GetCollisionHeight(bool mounted) const; - std::string GetMapAreaAndZoneString() const; std::string GetCoordsMapAreaAndZoneString() const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 199ad39dab7..ce32a2e7aea 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8204,7 +8204,7 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) if (charm->GetTypeId() == TYPEID_UNIT) charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - player->SendMovementSetCollisionHeight(player->GetCollisionHeight(true)); + player->SendMovementSetCollisionHeight(player->GetCollisionHeight()); } RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT); @@ -8221,7 +8221,7 @@ void Unit::Dismount() if (Player* thisPlayer = ToPlayer()) { SendUpdateToSet(); - thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(false)); + thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight()); } WorldPacket data(SMSG_DISMOUNT, 8); @@ -14806,6 +14806,30 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/ target->SendDirectMessage(&data); } +float Unit::GetCollisionHeight() const +{ + float scaleMod = GetObjectScale(); // 99% sure about this + + if (IsMounted()) + { + if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID))) + { + if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId)) + { + CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId()); + CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelId); + return scaleMod * (mountModelData->MountHeight + modelData->CollisionHeight * 0.5f); + } + } + } + + //! Dismounting case - use basic default model data + CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId()); + CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelId); + + return scaleMod * modelData->CollisionHeight; +} + SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const { Unit::AuraEffectList swaps = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 19d93640682..2677ebc3025 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1902,6 +1902,7 @@ class TC_GAME_API Unit : public WorldObject virtual void TextEmote(uint32 textId, WorldObject const* target = nullptr, bool isBossEmote = false); virtual void Whisper(uint32 textId, Player* target, bool isBossWhisper = false); + float GetCollisionHeight() const override; protected: explicit Unit (bool isWorldObject); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 22c19d7b90e..d46d9777e6f 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2312,7 +2312,7 @@ float GridMap::getLiquidLevel(float x, float y) const } // Get water state on map -inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) +inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) { // Check water type (if no water return) if (!_liquidGlobalFlags && !_liquidFlags) @@ -2378,7 +2378,7 @@ inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 R float ground_level = getHeight(x, y); // Check water level and ground level - if (liquid_level < ground_level || z < ground_level - 2) + if (liquid_level < ground_level || z < ground_level) return LIQUID_MAP_NO_WATER; // All ok in water -> store data @@ -2393,13 +2393,13 @@ inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 R // For speed check as int values float delta = liquid_level - z; - if (delta > 2.0f) // Under water + if (delta > collisionHeight) // Under water return LIQUID_MAP_UNDER_WATER; if (delta > 0.0f) // In water return LIQUID_MAP_IN_WATER; - if (delta > -0.1f) // Walk on water + if (delta > -0.1f) // Walk on water return LIQUID_MAP_WATER_WALK; - // Above water + // Above water return LIQUID_MAP_ABOVE_WATER; } @@ -2442,18 +2442,18 @@ bool Map::HasGrid(uint32 mapId, int32 gx, int32 gy) const return childMapItr != m_childTerrainMaps->end() && (*childMapItr)->GridMaps[gx][gy] && (*childMapItr)->GridMaps[gx][gy]->fileExists(); } -float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const +float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight /*= DEFAULT_COLLISION_HEIGHT*/) const { if (const_cast(this)->GetGrid(x, y)) { // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(phaseShift, x, y, z, true, 50.0f); + float ground_z = GetHeight(phaseShift, x, y, z + collisionHeight, true, 50.0f); if (ground) *ground = ground_z; LiquidData liquid_status; - ZLiquidStatus res = GetLiquidStatus(phaseShift, x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + ZLiquidStatus res = GetLiquidStatus(phaseShift, x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight); return res ? liquid_status.level : ground_z; } @@ -2468,8 +2468,7 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y)) { float gridHeight = gmap->getHeight(x, y); - // look from a bit higher pos to find the floor, ignore under surface case - if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE)) + if (z > gridHeight) mapHeight = gridHeight; } @@ -2478,7 +2477,7 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float { VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); if (vmgr->isHeightCalcEnabled()) - vmapHeight = vmgr->getHeight(terrainMapId, x, y, z + 2.0f, maxSearchDist); // look from a bit higher pos to find the floor + vmapHeight = vmgr->getHeight(terrainMapId, x, y, z, maxSearchDist); } // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT @@ -2563,7 +2562,7 @@ void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& zoneid = area->zone; } -ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const +ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) const { ZLiquidStatus result = LIQUID_MAP_NO_WATER; VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); @@ -2621,11 +2620,11 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float float delta = liquid_level - z; // Get position delta - if (delta > 2.0f) // Under water + if (delta > collisionHeight) // Under water return LIQUID_MAP_UNDER_WATER; if (delta > 0.0f) // In water return LIQUID_MAP_IN_WATER; - if (delta > -0.1f) // Walk on water + if (delta > -0.1f) // Walk on water return LIQUID_MAP_WATER_WALK; result = LIQUID_MAP_ABOVE_WATER; } @@ -2636,7 +2635,7 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y)) { LiquidData map_data; - ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data); + ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight); // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level)) { @@ -2655,7 +2654,7 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float return result; } -void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType) const +void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType, float collisionHeight) const { VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); VMAP::AreaAndLiquidData vmapData; @@ -2758,7 +2757,7 @@ void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, data.liquidInfo->type_flags = 1 << liquidFlagType; float delta = vmapData.liquidInfo->level - z; - if (delta > 2.0f) + if (delta > collisionHeight) data.liquidStatus = LIQUID_MAP_UNDER_WATER; else if (delta > 0.0f) data.liquidStatus = LIQUID_MAP_IN_WATER; @@ -2771,7 +2770,7 @@ void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, if (gmap && useGridLiquid) { LiquidData gridMapLiquid; - ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid); + ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid, collisionHeight); if (gridMapStatus != LIQUID_MAP_NO_WATER && (gridMapLiquid.level > vmapData.floorZ)) { if (GetId() == 530 && gridMapLiquid.entry == 2) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index fe69303168d..98035fa8b51 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -247,7 +247,7 @@ public: uint16 getArea(float x, float y) const; inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} float getLiquidLevel(float x, float y) const; - ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); + ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0, float collisionHeight = 2.03128f); // DEFAULT_COLLISION_HEIGHT in Object.h bool fileExists() const { return _fileExists; } }; @@ -398,8 +398,8 @@ class TC_GAME_API Map : public GridRefManager // can return INVALID_HEIGHT if under z+2 z coord not found height float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; - void GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS) const; - ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; + void GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h + ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const; uint32 GetAreaId(PhaseShift const& phaseShift, Position const& pos) const @@ -563,7 +563,7 @@ class TC_GAME_API Map : public GridRefManager BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast(this); else return nullptr; } BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast(this); return nullptr; } - float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const; + float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { return std::max(GetStaticHeight(phaseShift, x, y, z, vmap, maxSearchDist), GetGameObjectFloor(phaseShift, x, y, z, maxSearchDist)); } float GetHeight(PhaseShift const& phaseShift, Position const& pos, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { return GetHeight(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist); } diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 959c4d4ad9d..728c42564cf 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -438,7 +438,9 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) float moveTimeHalf = speedZ / Movement::gravity; float dist = 2 * moveTimeHalf * speedXY; - _owner->GetClosePoint(x, y, z, _owner->GetCombatReach(), dist, angle); + _owner->GetNearPoint2D(x, y, dist, _owner->GetOrientation() + angle); + z = _owner->GetPositionZ(); + _owner->UpdateAllowedPositionZ(x, y, z); MoveJump(x, y, z, 0.0f, speedXY, speedZ); } @@ -481,7 +483,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool if (_owner->IsFlying()) point.z = z; else - point.z = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), point.x, point.y, z); + point.z = _owner->GetMapHeight(point.x, point.y, z); init.Path().push_back(point); } @@ -567,11 +569,11 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info) void MotionMaster::MoveFall(uint32 id /*=0*/) { // use larger distance for vmap height search than in most other cases - float tz = _owner->GetMap()->GetHeight(_owner->GetPhaseShift(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE); + float tz = _owner->GetMapHeight(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE); if (tz <= INVALID_HEIGHT) { TC_LOG_DEBUG("misc", "MotionMaster::MoveFall: unable to retrieve a proper height at map %u (x: %f, y: %f, z: %f).", - _owner->GetMap()->GetId(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); + _owner->GetMap()->GetId(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ() + _owner->GetPositionZ()); return; } diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index 0de1fd19870..d2a707e5ba3 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -117,12 +117,7 @@ void FleeingMovementGenerator::SetTargetLocation(T* owner) // Add LOS check for target point Position mypos = owner->GetPosition(); - bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight( - PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), mypos.m_positionX, mypos.m_positionY), - mypos.m_positionX, mypos.m_positionY, mypos.m_positionZ + 2.0f, destination.m_positionX, destination.m_positionY, - destination.m_positionZ + 2.0f, VMAP::ModelIgnoreFlags::Nothing); - - if (!isInLOS) + if (!owner->IsWithinLOS(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ())) { _timer.Reset(200); return; diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 9b688e2f9b3..336098c673a 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -186,7 +186,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con // Check both start and end points, if they're both in water, then we can *safely* let the creature move for (uint32 i = 0; i < _pathPoints.size(); ++i) { - ZLiquidStatus status = _sourceUnit->GetMap()->GetLiquidStatus(_sourceUnit->GetPhaseShift(), _pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, nullptr); + ZLiquidStatus status = _sourceUnit->GetMap()->GetLiquidStatus(_sourceUnit->GetPhaseShift(), _pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, nullptr, _sourceUnit->GetCollisionHeight()); // One of the points is not in the water, cancel movement. if (status == LIQUID_MAP_NO_WATER) { @@ -649,7 +649,7 @@ void PathGenerator::UpdateFilter() NavTerrainFlag PathGenerator::GetNavTerrain(float x, float y, float z) { LiquidData data; - ZLiquidStatus liquidStatus = _sourceUnit->GetMap()->GetLiquidStatus(_sourceUnit->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &data); + ZLiquidStatus liquidStatus = _sourceUnit->GetMap()->GetLiquidStatus(_sourceUnit->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &data, _sourceUnit->GetCollisionHeight()); if (liquidStatus == LIQUID_MAP_NO_WATER) return NAV_GROUND; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index d2aef5a6eda..4cdffddeee6 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1329,10 +1329,10 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici float angle = float(rand_norm()) * static_cast(M_PI * 35.0f / 180.0f) - static_cast(M_PI * 17.5f / 180.0f); m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle); - float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseShift(), x, y, z, true, 50.0f); + float ground = m_caster->GetMapHeight(x, y, z); float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; LiquidData liquidData; - if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquidData)) + if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquidData, m_caster->GetCollisionHeight())) liquidLevel = liquidData.level; if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 122f26f4046..04407cdf857 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -252,8 +252,8 @@ public: Map2ZoneCoordinates(zoneX, zoneY, zoneId); Map const* map = object->GetMap(); - float groundZ = map->GetHeight(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT); - float floorZ = map->GetHeight(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()); + float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT); + float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()); GridCoord gridCoord = Trinity::ComputeGridCoord(object->GetPositionX(), object->GetPositionY()); @@ -296,7 +296,7 @@ public: zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap); LiquidData liquidStatus; - ZLiquidStatus status = map->GetLiquidStatus(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus); + ZLiquidStatus status = map->GetLiquidStatus(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus, object->GetCollisionHeight()); if (status) handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 20ce49097d9..5d93781c699 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -649,7 +649,7 @@ struct boss_jormungarAI : public BossAI events.SetPhase(PHASE_SUBMERGED); events.ScheduleEvent(EVENT_EMERGE, 5*IN_MILLISECONDS, 0, PHASE_SUBMERGED); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX()+ frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionY() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionZ()); + me->GetMotionMaster()->MovePoint(0, ToCCommonLoc[1].GetPositionX()+ frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionY() + frand(-40.0f, 40.0f), ToCCommonLoc[1].GetPositionZ() + me->GetCollisionHeight()); WasMobile = !WasMobile; }