diff options
author | Jeremy <Golrag@users.noreply.github.com> | 2018-02-16 20:59:19 +0100 |
---|---|---|
committer | jackpoz <giacomopoz@gmail.com> | 2018-02-16 20:59:19 +0100 |
commit | 9e0faace9a5114fc2324c2c601ba943272e0d6ff (patch) | |
tree | ee7cb56b687598c96d5e967d8f8857fc5cee8b07 /src | |
parent | 8aa10f6c65ba7fc8363a663b305fede95d0ccb58 (diff) |
Core/Entities: Reduce the probability of units dropping under the map (#21322)
Reduce the probabilty of going under the map
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Collision/DynamicTree.cpp | 13 | ||||
-rw-r--r-- | src/common/Collision/DynamicTree.h | 1 | ||||
-rw-r--r-- | src/common/Collision/Management/IVMapManager.h | 3 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.cpp | 19 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.h | 1 | ||||
-rw-r--r-- | src/common/Collision/Maps/MapTree.cpp | 13 | ||||
-rw-r--r-- | src/common/Collision/Maps/MapTree.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 185 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 2 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 50 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 57 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 26 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 1 |
13 files changed, 301 insertions, 71 deletions
diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp index 96378ef9c0d..a69d54c7f9a 100644 --- a/src/common/Collision/DynamicTree.cpp +++ b/src/common/Collision/DynamicTree.cpp @@ -254,3 +254,16 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, else return -G3D::finf(); } + +float DynamicMapTree::getCeil(float x, float y, float z, float maxSearchDist, uint32 phasemask) const +{ + G3D::Vector3 v(x, y, z); + G3D::Ray r(v, G3D::Vector3(0, 0, 1)); + DynamicTreeIntersectionCallback callback(phasemask); + impl->intersectZAllignedRay(r, callback, maxSearchDist); + + if (callback.didHit()) + return v.z + maxSearchDist; + + return G3D::finf(); +} diff --git a/src/common/Collision/DynamicTree.h b/src/common/Collision/DynamicTree.h index 9b7d5f15e20..aa7a4bb3d2a 100644 --- a/src/common/Collision/DynamicTree.h +++ b/src/common/Collision/DynamicTree.h @@ -51,6 +51,7 @@ public: float pModifyDist) const; float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const; + float getCeil(float x, float y, float z, float maxSearchDist, uint32 phasemask) const; void insert(GameObjectModel const&); void remove(GameObjectModel const&); diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index e9aae51a025..7fa9ddb12e3 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -49,6 +49,8 @@ namespace VMAP #define VMAP_INVALID_HEIGHT -100000.0f // for check #define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case + #define VMAP_INVALID_CEIL_VALUE 200000.0f + #define VMAP_INVALID_CEIL 100000.0f struct AreaAndLiquidData { @@ -92,6 +94,7 @@ namespace VMAP virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) = 0; virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist) = 0; + virtual float getCeil(unsigned int /*pMapId*/, float /*x*/, float /*y*/, float /*z*/, float /*maxSearchDist*/) { return VMAP_INVALID_CEIL_VALUE; } /** test if we hit an object. return true if we hit one. rx, ry, rz will hold the hit position or the dest position, if no intersection was found return a position, that is pReduceDist closer to the origin diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp index 5b9cb34874b..922d68140d3 100644 --- a/src/common/Collision/Management/VMapManager2.cpp +++ b/src/common/Collision/Management/VMapManager2.cpp @@ -234,6 +234,25 @@ namespace VMAP return VMAP_INVALID_HEIGHT_VALUE; } + float VMapManager2::getCeil(unsigned int mapId, float x, float y, float z, float maxSearchDist) + { + if (isHeightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_HEIGHT)) + { + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); + if (instanceTree != iInstanceMapTrees.end()) + { + Vector3 pos = convertPositionToInternalRep(x, y, z); + float height = instanceTree->second->getCeil(pos, maxSearchDist); + if (!(height < G3D::finf())) + return height = VMAP_INVALID_CEIL_VALUE; // No height + + return height; + } + } + + return VMAP_INVALID_CEIL_VALUE; + } + bool VMapManager2::getAreaInfo(unsigned int mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index 831383ac555..b50348b8928 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -113,6 +113,7 @@ namespace VMAP */ bool getObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) override; float getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist) override; + float getCeil(unsigned int mapId, float x, float y, float z, float maxSearchDist) override; bool processCommand(char* /*command*/) override { return false; } // for debug and extensions diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index 3a927acc310..c96adb6c87c 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -236,6 +236,19 @@ namespace VMAP return(height); } + float StaticMapTree::getCeil(const G3D::Vector3 & pPos, float maxSearchDist) const + { + float height = G3D::finf(); + Vector3 dir = Vector3(0, 0, 1); + G3D::Ray ray(pPos, dir); // direction with length of 1 + float maxDist = maxSearchDist; + if (getIntersectionTime(ray, maxDist, false, ModelIgnoreFlags::Nothing)) + { + height = pPos.z + maxDist; + } + return(height); + } + //========================================================= LoadResult StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY) { diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 48470bf0261..186f1120915 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -75,6 +75,7 @@ namespace VMAP bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2, ModelIgnoreFlags ignoreFlags) const; bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const; float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const; + float getCeil(const G3D::Vector3& pPos, float maxSearchDist) const; bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const; bool GetLocationInfo(const G3D::Vector3 &pos, LocationInfo &info) const; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 763fdc1b4cc..bd41de9e657 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1487,7 +1487,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const else { float ground_z = GetMapHeight(x, y, z); - if (z < ground_z) + if (std::fabs(z - ground_z) < GetCollisionHeight()) z = ground_z; } break; @@ -1510,7 +1510,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const else { float ground_z = GetMapHeight(x, y, z); - if (z < ground_z) + if (std::fabs(z - ground_z) < GetCollisionHeight()) z = ground_z; } break; @@ -2305,13 +2305,95 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) pos.SetOrientation(GetOrientation()); } +// Only call this function when you already checked for collision with vmap/gameobject. +// You should check for collision again after this one has been called. +// excludeCollisionHeight should only be true if you had collision, it wont add it to raycasts for dest position. +float WorldObject::SelectBestZForDestination(float x, float y, float z, bool excludeCollisionHeight) const +{ + if (Unit const* unit = ToUnit()) + { + float const ground = GetFloorZ(); + bool const isInAir = (G3D::fuzzyGt(unit->GetPositionZMinusOffset(), ground + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(unit->GetPositionZMinusOffset(), ground - GROUND_HEIGHT_TOLERANCE)); + if (unit->IsFlying() && isInAir) + return z; + } + + float myX, myY, myZ; + GetPosition(myX, myY, myZ); + + float const myCollisionHeight = GetCollisionHeight(); + float const destCollisionHeight = excludeCollisionHeight ? 0.0f : myCollisionHeight; + + float const myGridHeight = GetMap()->GetGridMapHeight(myX, myY); + float const myVmapFloor = std::max(GetMap()->GetVMapFloor(myX, myY, myZ, 150.0f, myCollisionHeight), + GetMap()->GetGameObjectFloor(GetPhaseMask(), myX, myY, myZ, 150.0f, myCollisionHeight)); + + // which of these 3 do I want ? + float const destGridHeight = GetMap()->GetGridMapHeight(x, y); + float const destCeil = GetMap()->GetCeil(GetPhaseMask(), x, y, z, 150.0f, destCollisionHeight); + float const destVmapFloor = std::max(GetMap()->GetVMapFloor(x, y, z, 150.0f, destCollisionHeight), + GetMap()->GetGameObjectFloor(GetPhaseMask(), x, y, z, 150.0f, destCollisionHeight)); + + bool const hasVmapFloor = myVmapFloor > INVALID_HEIGHT; + bool const hasDestGridHeight = destGridHeight > INVALID_HEIGHT; + bool const hasDestVmapCeil = destCeil < VMAP_INVALID_CEIL && destCeil != destVmapFloor; + bool const hasDestVmapFloor = destVmapFloor > INVALID_HEIGHT; + bool const destBetweenVmaps = hasDestVmapCeil && hasDestVmapFloor; + bool const noVmap = !hasDestVmapFloor && !hasDestVmapCeil; + + // It is possible that while moving, our feet are slightly moving under the ground. Jumping / reconnecting fixes this issue but we don't want to rely on that. + myZ += myCollisionHeight; + bool const isOnVmap = hasVmapFloor && + ((myZ < myGridHeight && std::fabs(myVmapFloor - myZ) < std::fabs(myGridHeight - myZ)) || + (myZ > myGridHeight && myVmapFloor > myGridHeight)); + + bool const hasToFollowGridHeight = hasDestGridHeight && (noVmap || + (z > destGridHeight && destGridHeight > destVmapFloor) || + (z < destGridHeight && hasDestVmapFloor && !hasDestVmapCeil) || + (z < destGridHeight && !hasDestVmapFloor) || + (destBetweenVmaps && !isOnVmap && destGridHeight > destVmapFloor && destGridHeight < destCeil)); + + float result = INVALID_HEIGHT; + if (hasToFollowGridHeight) + { + result = destGridHeight; + if (hasDestVmapFloor) + if (std::fabs(destVmapFloor - destGridHeight) < myCollisionHeight) + result = std::max(destVmapFloor, destGridHeight); + + if (hasDestVmapCeil) + if (std::fabs(destCeil - destGridHeight) < myCollisionHeight) + result = std::max(destCeil, destGridHeight); + } + else if (hasDestVmapFloor) + result = destVmapFloor; + else if (hasDestVmapCeil) + result = destCeil; + + if (Unit const* unit = ToUnit()) + if (!unit->CanSwim()) + return result; + + LiquidData liquidData; + ZLiquidStatus const liquidStatus = GetMap()->GetLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData, destCollisionHeight); + switch (liquidStatus) + { + case LIQUID_MAP_ABOVE_WATER: + return std::max<float>(liquidData.level, result); + case LIQUID_MAP_IN_WATER: + case LIQUID_MAP_UNDER_WATER: + return std::max<float>(z, result); + default: + return result; + } +} + 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; + float destx = pos.m_positionX + dist * std::cos(angle); + float desty = pos.m_positionY + dist * std::sin(angle); + float destz = pos.m_positionZ; // Prevent invalid coordinates here, position is unchanged if (!Trinity::IsValidMapCoord(destx, desty)) @@ -2320,52 +2402,72 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float return; } - UpdateAllowedPositionZ(destx, desty, destz); - bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(), pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); - - // collision occured + bool const col = ComputeCollisionPosition(pos, { destx, desty, destz }, destx, desty, destz); if (col) - { - // move back a bit - destx -= CONTACT_DISTANCE * std::cos(angle); - desty -= CONTACT_DISTANCE * std::sin(angle); dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty)); - } - // check dynamic collision - col = GetMap()->getObjectHitPos(GetPhaseMask(), pos.m_positionX, pos.m_positionY, pos.m_positionZ, destx, desty, destz, destx, desty, destz, -0.5f); + destz = SelectBestZForDestination(destx, desty, destz, col); - // Collided with a gameobject - if (col) + float const step = dist / 10.0f; + // do not allow too big z changes + for (uint8 j = 0; j < 10 && std::fabs(pos.m_positionZ - destz) > 6.0f; ++j) { - destx -= CONTACT_DISTANCE * std::cos(angle); - desty -= CONTACT_DISTANCE * std::sin(angle); - dist = std::sqrt((pos.m_positionX - destx)*(pos.m_positionX - destx) + (pos.m_positionY - desty)*(pos.m_positionY - desty)); + destx -= step * std::cos(angle); + desty -= step * std::sin(angle); + // There should not be any collision between our position and destx, desty, pos.m_positionZ at this point. + // Use pos.m_positionZ here because destz was not good. + destz = SelectBestZForDestination(destx, desty, pos.m_positionZ, col); } - float step = dist / 10.0f; + Trinity::NormalizeMapCoord(destx); + Trinity::NormalizeMapCoord(desty); + // We might want to loop until there is no more collision with a better z position. (And/or until a fixed #attemps have been made). + ComputeCollisionPosition(pos, { destx, desty, destz }, destx, desty, destz); + pos.Relocate(destx, desty, destz); + pos.SetOrientation(GetOrientation()); +} - for (uint8 j = 0; j < 10; ++j) +bool WorldObject::ComputeCollisionPosition(Position const& startPosition, Position const& endPosition, float& x, float& y, float& z) const +{ + Position vmapCollisionPos; + bool const vmapCollision = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(), startPosition.m_positionX, startPosition.m_positionY, startPosition.m_positionZ + GetCollisionHeight(), endPosition.m_positionX, endPosition.m_positionY, endPosition.m_positionZ + GetCollisionHeight(), vmapCollisionPos.m_positionX, vmapCollisionPos.m_positionY, vmapCollisionPos.m_positionZ, -CONTACT_DISTANCE * 2.0f); + Position gameObjectCollisionPos; + bool const gameObjectCollision = GetMap()->getObjectHitPos(GetPhaseMask(), startPosition.m_positionX, startPosition.m_positionY, startPosition.m_positionZ + GetCollisionHeight(), endPosition.m_positionX, endPosition.m_positionY, endPosition.m_positionZ + GetCollisionHeight(), gameObjectCollisionPos.m_positionX, gameObjectCollisionPos.m_positionY, gameObjectCollisionPos.m_positionZ, -CONTACT_DISTANCE * 2.0f); + + // Both collision occures, check which one is closest to start. + if (vmapCollision && gameObjectCollision) { - // do not allow too big z changes - if (std::fabs(pos.m_positionZ - destz) > 6.0f) + if (startPosition.GetExactDist(vmapCollision) < startPosition.GetExactDist(gameObjectCollisionPos)) { - destx -= step * std::cos(angle); - desty -= step * std::sin(angle); - UpdateAllowedPositionZ(destx, desty, destz); - } - // we have correct destz now - else - { - pos.Relocate(destx, desty, destz); - break; + x = vmapCollisionPos.m_positionX; + y = vmapCollisionPos.m_positionY; + z = vmapCollisionPos.m_positionZ; + return true; } + + x = gameObjectCollisionPos.m_positionX; + y = gameObjectCollisionPos.m_positionY; + z = gameObjectCollisionPos.m_positionZ; + return true; } - Trinity::NormalizeMapCoord(pos.m_positionX); - Trinity::NormalizeMapCoord(pos.m_positionY); - UpdateAllowedPositionZ(destx, desty, pos.m_positionZ); - pos.SetOrientation(GetOrientation()); + if (vmapCollision) + { + x = vmapCollisionPos.m_positionX; + y = vmapCollisionPos.m_positionY; + z = vmapCollisionPos.m_positionZ; + return true; + } + + if (gameObjectCollision) + { + x = gameObjectCollisionPos.m_positionX; + y = gameObjectCollisionPos.m_positionY; + z = gameObjectCollisionPos.m_positionZ; + return true; + } + + return false; } void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) @@ -2558,10 +2660,7 @@ float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* gr 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(GetPhaseMask(), x, y, z, vmap, distanceToSearch); + return GetMap()->GetHeight(GetPhaseMask(), x, y, z, vmap, distanceToSearch, GetCollisionHeight()); } template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index fd4b34d7892..a3311615c4f 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -274,6 +274,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void MovePosition(Position &pos, float dist, float angle); Position GetNearPosition(float dist, float angle); void MovePositionToFirstCollision(Position &pos, float dist, float angle); + bool ComputeCollisionPosition(Position const& startPosition, Position const& endPosition, float& x, float& y, float& z) const; Position GetFirstCollisionPosition(float dist, float angle); Position GetRandomNearPosition(float radius); void GetContactPoint(WorldObject const* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const; @@ -492,6 +493,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation bool CanDetect(WorldObject const* obj, bool ignoreStealth, bool checkAlert = false) const; bool CanDetectInvisibilityOf(WorldObject const* obj) const; bool CanDetectStealthOf(WorldObject const* obj, bool checkAlert = false) const; + float SelectBestZForDestination(float x, float y, float z, bool excludeCollisionHeight) const; }; namespace Trinity diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 6958392f66d..8a55e13da77 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2377,12 +2377,12 @@ inline GridMap* Map::GetGrid(float x, float y) return GridMaps[gx][gy]; } -float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight /*= DEFAULT_COLLISION_HEIGHT*/) const +float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight /*= DEFAULT_COLLISION_HEIGHT*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { if (const_cast<Map*>(this)->GetGrid(x, y)) { // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(phasemask, x, y, z + collisionHeight, true, 50.0f); + float ground_z = GetHeight(phasemask, x, y, z, true, maxSearchDist, collisionHeight); if (ground) *ground = ground_z; @@ -2403,30 +2403,22 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl return VMAP_INVALID_HEIGHT_VALUE; } -float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const +float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/, float collisionHeight) const { // find raw .map surface under Z coordinates - float mapHeight = VMAP_INVALID_HEIGHT_VALUE; - if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) - { - float gridHeight = gmap->getHeight(x, y); - if (z > gridHeight) - mapHeight = gridHeight; - } + float const gridHeight = GetGridMapHeight(x, y); + float mapHeight = z + collisionHeight > gridHeight ? gridHeight : VMAP_INVALID_HEIGHT_VALUE; float vmapHeight = VMAP_INVALID_HEIGHT_VALUE; if (checkVMap) - { - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->isHeightCalcEnabled()) - vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist); - } + vmapHeight = GetVMapFloor(x, y, z, maxSearchDist, collisionHeight); - // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT - // vmapheight set for any under Z value or <= INVALID_HEIGHT - if (vmapHeight > INVALID_HEIGHT) + bool const hasVmapFloor = vmapHeight > INVALID_HEIGHT; + bool const hasMapFloor = mapHeight > INVALID_HEIGHT; + + if (hasVmapFloor) { - if (mapHeight > INVALID_HEIGHT) + if (hasMapFloor) { // we have mapheight and vmapheight and must select more appropriate @@ -2441,7 +2433,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float return vmapHeight; // we have only vmapHeight (if have) } - return mapHeight; // explicitly use map data + return gridHeight; // explicitly use map data } float Map::GetMinHeight(float x, float y) const @@ -2452,6 +2444,19 @@ float Map::GetMinHeight(float x, float y) const return -500.0f; } +float Map::GetGridMapHeight(float x, float y) const +{ + if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) + return gmap->getHeight(x, y); + + return VMAP_INVALID_HEIGHT_VALUE; +} + +float Map::GetVMapFloor(float x, float y, float z, float maxSearchDist, float collisionHeight) const +{ + return VMAP::VMapFactory::createOrGetVMapManager()->getHeight(GetId(), x, y, z + collisionHeight, maxSearchDist); +} + inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) { bool outdoor = true; @@ -2771,6 +2776,11 @@ float Map::GetWaterLevel(float x, float y) const return 0; } +float Map::GetCeil(float x, float y, float z, float maxSearchDist, float collisionHeight) const +{ + return VMAP::VMapFactory::createOrGetVMapManager()->getCeil(GetId(), x, y, z + collisionHeight, maxSearchDist); +} + bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { if ((checks & LINEOFSIGHT_CHECK_VMAP) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 37e8f3294e9..9c1f4748b06 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -538,20 +538,63 @@ class TC_GAME_API Map : public GridRefManager<NGridType> BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap*>(this); else return nullptr; } BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap const*>(this); return nullptr; } - float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h + // FLOOR, CEIL AND HEIGHT + float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = 0.0f, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; float GetMinHeight(float x, float y) const; - float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; - float GetHeight(Position const& pos, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { return GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist); } - float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist), GetGameObjectFloor(phasemask, x, y, z, maxSearchDist)); } - float GetHeight(uint32 phasemask, Position const& pos, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { return GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist); } + float GetGridMapHeight(float x, float y) const; + float GetVMapFloor(float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const; + float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const; + float GetHeight(Position const& pos, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist, collisionHeight); + } + + float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return std::max<float>(GetHeight(x, y, z, vmap, maxSearchDist, collisionHeight), GetGameObjectFloor(phasemask, x, y, z, maxSearchDist, collisionHeight)); + } + + float GetHeight(uint32 phasemask, Position const& pos, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist, collisionHeight); + } + + float GetCeil(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return std::min<float>(GetCeil(x, y, z, maxSearchDist, collisionHeight), GetGameObjectCeil(phasemask, x, y, z, maxSearchDist, collisionHeight)); + } + + float GetCeil(uint32 phasemask, Position const& pos, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return GetCeil(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), maxSearchDist, collisionHeight); + } + + float GetCeil(Position const& pos, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return GetCeil(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), maxSearchDist, collisionHeight); + } + + float GetCeil(float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const; + + float GetGameObjectCeil(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return _dynamicTree.getCeil(x, y, z + collisionHeight, maxSearchDist, phasemask); + } + + float GetGameObjectCeil(uint32 phasemask, Position const& pos, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const + { + return GetGameObjectCeil(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + collisionHeight, maxSearchDist, phasemask); + } + + // bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const; void Balance() { _dynamicTree.balance(); } void RemoveGameObjectModel(GameObjectModel const& model) { _dynamicTree.remove(model); } void InsertGameObjectModel(GameObjectModel const& model) { _dynamicTree.insert(model); } bool ContainsGameObjectModel(GameObjectModel const& model) const { return _dynamicTree.contains(model);} - float GetGameObjectFloor(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const + float GetGameObjectFloor(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH, float collisionHeight = 0.0f) const { - return _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask); + return _dynamicTree.getHeight(x, y, z + collisionHeight, maxSearchDist, phasemask); } bool getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index b6b5c22b6e1..7eaad1835ec 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1359,6 +1359,32 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation()); break; } + case TARGET_DEST_CASTER_FRONT_LEAP: + { + float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + float angle = targetType.CalcDirectionAngle(); + + Position pos = dest._position; + + m_caster->MovePositionToFirstCollision(pos, dist, angle); + // Generate path to that point. + if (!m_preGeneratedPath) + m_preGeneratedPath = std::make_unique<PathGenerator>(m_caster); + + m_preGeneratedPath->SetPathLengthLimit(dist); + + // Should we use straightline here ? What do we do when we don't have a full path ? + bool pathResult = m_preGeneratedPath->CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false, true); + if (pathResult && m_preGeneratedPath->GetPathType() & (PATHFIND_NORMAL | PATHFIND_SHORTCUT)) + { + pos.m_positionX = m_preGeneratedPath->GetActualEndPosition().x; + pos.m_positionY = m_preGeneratedPath->GetActualEndPosition().y; + pos.m_positionZ = m_preGeneratedPath->GetActualEndPosition().z; + } + + dest.Relocate(pos); + break; + } default: { float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b1691bb4d2a..9ea2928c423 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4426,7 +4426,6 @@ void Spell::EffectLeap(SpellEffIndex /*effIndex*/) return; Position pos = destTarget->GetPosition(); - pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetDistance(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()), 0.0f); unitTarget->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), unitTarget == m_caster); } |