From 0d4adf5a3ee542a90966b48407da9c78975fe059 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Tue, 10 May 2022 22:37:53 +0200 Subject: [PATCH] fix(Core/Spells): Blink. (#11663) * fix(Core/Spells): Blink. Fixes #6427 Fixes #7571 * Update. --- src/server/game/Maps/Map.cpp | 4 +- src/server/game/Spells/Spell.cpp | 213 +++++++++++++++++++++++++++++-- 2 files changed, 206 insertions(+), 11 deletions(-) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index f670719e8..bf8b8ea09 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2257,9 +2257,9 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, // Get position delta if (delta > collisionHeight) liquidData.Status = LIQUID_MAP_UNDER_WATER; - if (delta > 0.0f) + else if (delta > 0.0f) liquidData.Status = LIQUID_MAP_IN_WATER; - if (delta > -0.1f) + else if (delta > -0.1f) liquidData.Status = LIQUID_MAP_WATER_WALK; else liquidData.Status = LIQUID_MAP_ABOVE_WATER; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 93c8f5ed6..c5297bd44 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1407,19 +1407,214 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici } case TARGET_DEST_CASTER_FRONT_LEAP: { - Unit* unitCaster = m_caster->ToUnit(); - if (!unitCaster) + float distance = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + Map* map = m_caster->GetMap(); + uint32 mapid = m_caster->GetMapId(); + uint32 phasemask = m_caster->GetPhaseMask(); + float collisionHeight = m_caster->GetCollisionHeight(); + float destx, desty, destz, ground, startx, starty, startz, starto; + + Position pos; + Position lastpos; + m_caster->GetPosition(startx, starty, startz, starto); + pos.Relocate(startx, starty, startz, starto); + destx = pos.GetPositionX() + distance * cos(pos.GetOrientation()); + desty = pos.GetPositionY() + distance * sin(pos.GetOrientation()); + + ground = map->GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + + bool isCasterInWater = m_caster->IsInWater(); + if (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || (pos.GetPositionZ() - ground < distance)) { - break; + float tstX, tstY, tstZ, prevX, prevY, prevZ; + float tstZ1, tstZ2, tstZ3, destz1, destz2, destz3, srange, srange1, srange2, srange3; + float maxtravelDistZ = 2.65f; + float overdistance = 0.0f; + float totalpath = 0.0f; + float beforewaterz = 0.0f; + bool inwater = false; + bool wcol = false; + const float step = 2.0f; + const uint8 numChecks = ceil(fabs(distance / step)); + const float DELTA_X = (destx - pos.GetPositionX()) / numChecks; + const float DELTA_Y = (desty - pos.GetPositionY()) / numChecks; + int j = 1; + for (; j < (numChecks + 1); j++) + { + prevX = pos.GetPositionX() + (float(j - 1) * DELTA_X); + prevY = pos.GetPositionY() + (float(j - 1) * DELTA_Y); + tstX = pos.GetPositionX() + (float(j) * DELTA_X); + tstY = pos.GetPositionY() + (float(j) * DELTA_Y); + + if (j < 2) + { + prevZ = pos.GetPositionZ(); + } + else + { + prevZ = tstZ; + } + + tstZ = map->GetHeight(phasemask, tstX, tstY, prevZ + maxtravelDistZ, true); + ground = tstZ; + + if (!isCasterInWater) + { + if (map->IsInWater(phasemask, tstX, tstY, tstZ, collisionHeight)) + { + if (!(beforewaterz != 0.0f)) + { + beforewaterz = prevZ; + } + tstZ = beforewaterz; + srange = sqrt((tstY - prevY) * (tstY - prevY) + (tstX - prevX) * (tstX - prevX)); + //TC_LOG_ERROR("server", "(start was from land) step in water , number of cycle = %i , distance of step = %f, total path = %f, Z = %f", j, srange, totalpath, tstZ); + } + } + else if (map->IsInWater(phasemask, tstX, tstY, tstZ, collisionHeight)) + { + prevZ = pos.GetPositionZ(); + tstZ = pos.GetPositionZ(); + srange = sqrt((tstY - prevY) * (tstY - prevY) + (tstX - prevX) * (tstX - prevX)); + + inwater = true; + if (inwater && (fabs(tstZ - ground) < 2.0f)) + { + wcol = true; + //TC_LOG_ERROR("server", "step in water with collide and use standart check (for continue way after possible collide), number of cycle = %i ", j); + } + + // if (j < 2) + // TC_LOG_ERROR("server", "(start in water) step in water, number of cycle = %i , distance of step = %f, total path = %f", j, srange, totalpath); + // else + // TC_LOG_ERROR("server", "step in water, number of cycle = %i , distance of step = %f, total path = %f", j, srange, totalpath); + } + + bool IsInWater = map->IsInWater(phasemask, tstX, tstY, tstZ, collisionHeight); + if ((!IsInWater && tstZ != beforewaterz) || wcol) // second safety check z for blink way if on the ground + { + if (inwater && !IsInWater) + inwater = false; + + // highest available point + tstZ1 = map->GetHeight(phasemask, tstX, tstY, prevZ + maxtravelDistZ, true, 25.0f); + // upper or floor + tstZ2 = map->GetHeight(phasemask, tstX, tstY, prevZ, true, 25.0f); + //lower than floor + tstZ3 = map->GetHeight(phasemask, tstX, tstY, prevZ - maxtravelDistZ / 2, true, 25.0f); + + //distance of rays, will select the shortest in 3D + srange1 = sqrt((tstY - prevY) * (tstY - prevY) + (tstX - prevX) * (tstX - prevX) + (tstZ1 - prevZ) * (tstZ1 - prevZ)); + //TC_LOG_ERROR("server", "step = %i, distance of ray1 = %f", j, srange1); + srange2 = sqrt((tstY - prevY) * (tstY - prevY) + (tstX - prevX) * (tstX - prevX) + (tstZ2 - prevZ) * (tstZ2 - prevZ)); + //TC_LOG_ERROR("server", "step = %i, distance of ray2 = %f", j, srange2); + srange3 = sqrt((tstY - prevY) * (tstY - prevY) + (tstX - prevX) * (tstX - prevX) + (tstZ3 - prevZ) * (tstZ3 - prevZ)); + //TC_LOG_ERROR("server", "step = %i, distance of ray3 = %f", j, srange3); + + if (srange1 < srange2) + { + tstZ = tstZ1; + srange = srange1; + } + else if (srange3 < srange2) + { + tstZ = tstZ3; + srange = srange3; + } + else + { + tstZ = tstZ2; + srange = srange2; + } + + //TC_LOG_ERROR("server", "step on ground, number of cycle = %i , distance of step = %f, total path = %f", j, srange, totalpath); + } + + destx = tstX; + desty = tstY; + destz = tstZ; + + totalpath += srange; + + if (totalpath > distance) + { + overdistance = totalpath - distance; + //TC_LOG_ERROR("server", "total path > than distance in 3D , need to move back a bit for save distance, total path = %f, overdistance = %f", totalpath, overdistance); + } + + bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); + // check dynamic collision + bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); + + // collision occured + if (col || dcol || (overdistance > 0.0f && !map->IsInWater(phasemask, tstX, tstY, ground, collisionHeight)) || (fabs(prevZ - tstZ) > maxtravelDistZ && (tstZ > prevZ))) + { + if ((overdistance > 0.0f) && (overdistance < step)) + { + destx = prevX + overdistance * cos(pos.GetOrientation()); + desty = prevY + overdistance * sin(pos.GetOrientation()); + //TC_LOG_ERROR("server", "(collision) collision occured 1"); + } + else + { + // move back a bit + destx = tstX - (0.6 * cos(pos.GetOrientation())); + desty = tstY - (0.6 * sin(pos.GetOrientation())); + //TC_LOG_ERROR("server", "(collision) collision occured 2"); + } + + // highest available point + destz1 = map->GetHeight(phasemask, destx, desty, prevZ + maxtravelDistZ, true, 25.0f); + // upper or floor + destz2 = map->GetHeight(phasemask, destx, desty, prevZ, true, 25.0f); + //lower than floor + destz3 = map->GetHeight(phasemask, destx, desty, prevZ - maxtravelDistZ / 2, true, 25.0f); + + //distance of rays, will select the shortest in 3D + srange1 = sqrt((desty - prevY) * (desty - prevY) + (destx - prevX) * (destx - prevX) + (destz1 - prevZ) * (destz1 - prevZ)); + srange2 = sqrt((desty - prevY) * (desty - prevY) + (destx - prevX) * (destx - prevX) + (destz2 - prevZ) * (destz2 - prevZ)); + srange3 = sqrt((desty - prevY) * (desty - prevY) + (destx - prevX) * (destx - prevX) + (destz3 - prevZ) * (destz3 - prevZ)); + + if (srange1 < srange2) + destz = destz1; + else if (srange3 < srange2) + destz = destz3; + else + destz = destz2; + + if (inwater && destz < prevZ && !wcol) + destz = prevZ; + //TC_LOG_ERROR("server", "(collision) destZ rewrited in prevZ"); + + break; + } + // we have correct destz now + } + //} + + lastpos.Relocate(destx, desty, destz + 0.5f, pos.GetOrientation()); + dest = SpellDestination(lastpos); } + else + { + float z = pos.GetPositionZ(); + bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, pos.GetPositionX(), pos.GetPositionY(), z + 0.5f, destx, desty, z + 0.5f, destx, desty, z, -0.5f); + // check dynamic collision + bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z + 0.5f, destx, desty, z + 0.5f, destx, desty, z, -0.5f); - float dist = m_spellInfo->Effects[effIndex].CalcRadius(unitCaster); - float angle = targetType.CalcDirectionAngle(); + // collision occured + if (col || dcol) + { + // move back a bit + destx = destx - (0.6 * cos(pos.GetOrientation())); + desty = desty - (0.6 * sin(pos.GetOrientation())); + } - Position pos = dest._position; - - unitCaster->MovePositionToFirstCollision(pos, dist, angle); - dest.Relocate(pos); + lastpos.Relocate(destx, desty, z, pos.GetOrientation()); + dest = SpellDestination(lastpos); + //float range = sqrt((desty - pos.GetPositionY())*(desty - pos.GetPositionY()) + (destx - pos.GetPositionX())*(destx - pos.GetPositionX())); + //TC_LOG_ERROR("server", "Blink number 2, in falling but at a hight, distance of blink = %f", range); + } break; } default: