Index: src/game/Spell.cpp =================================================================== --- src/game/Spell.cpp (revision 6405) +++ src/game/Spell.cpp (working copy) @@ -3821,18 +3821,50 @@ case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: { float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); - float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); - // teleport a bit above terrain level to avoid falling below it - float fz = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx,fy,m_caster->GetPositionZ(),true); - if(fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled - return SPELL_FAILED_TRY_AGAIN; + + // orientation coordinates + float ox = m_caster->GetPositionX(); + float oy = m_caster->GetPositionY(); + float oz = m_caster->GetPositionZ(); + + // destination coordinates + float fx = ox + dis * cos(m_caster->GetOrientation()); + float fy = oy + dis * sin(m_caster->GetOrientation()); + + // possible destination z coordinate + float fz_ground = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx, fy, MAX_HEIGHT, true); + float fz_floor = MapManager::Instance().GetBaseMap(m_caster->GetMapId())->GetHeight(fx, fy, m_caster->GetPositionZ(), true); + + // absolute diferente between orientation z and possible destination z + float ground_dif = fabs(fz_ground - oz); + float floor_dif = fabs(fz_floor - oz); + + // control caster to not climb/drop when destination z > +-8; or we don't have a valid destination z value + if (ground_dif > 8.0 && floor_dif > 8.0) return SPELL_FAILED_TRY_AGAIN; + + // begin -- chech if we hit something in the way + bool hit_ground = false, hit_floor = false; + float fx2, fy2, fz2; + hit_ground = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(m_caster->GetMapId(), ox, oy, oz + ground_dif + 0.75, fx, fy, fz_ground + 0.75, fx2, fy2, fz2, -0.75); + hit_floor = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(m_caster->GetMapId(), ox, oy, oz + floor_dif + 0.75, fx, fy, fz_floor + 0.75, fx2, fy2, fz2, -0.75); + + if (ground_dif <= 8.0 && floor_dif <= 8.0) // both possible destination z are valid. + { + if (hit_ground == true && hit_floor == true) return SPELL_FAILED_TRY_AGAIN; // we hit something in the way of both possible destination z + } + else + { + if (ground_dif <= 8.0) // only fz_ground destination z is valid. + { + if (hit_ground == true) return SPELL_FAILED_TRY_AGAIN; // we hit something in the way of destination z + } + else // only fz_floor destination z is valid. + { + if (hit_floor == true) return SPELL_FAILED_TRY_AGAIN; // we hit something in the way of destination z + } + } + // end -- chech if we hit something in the way - float caster_pos_z = m_caster->GetPositionZ(); - // Control the caster to not climb or drop when +-fz > 8 - if(!(fz<=caster_pos_z+8 && fz>=caster_pos_z-8)) - return SPELL_FAILED_TRY_AGAIN; - // not allow use this effect at battleground until battleground start if(m_caster->GetTypeId()==TYPEID_PLAYER) if(BattleGround const *bg = ((Player*)m_caster)->GetBattleGround()) Index: src/game/SpellEffects.cpp =================================================================== --- src/game/SpellEffects.cpp (revision 6405) +++ src/game/SpellEffects.cpp (working copy) @@ -5222,21 +5222,53 @@ uint32 mapid = m_caster->GetMapId(); float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - // before caster - float fx,fy,fz; - unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis); - float ox,oy,oz; - unitTarget->GetPosition(ox,oy,oz); + // orientation coordinates + float ox = unitTarget->GetPositionX(); + float oy = unitTarget->GetPositionY(); + float oz = unitTarget->GetPositionZ(); + + // destination coordinates + float fx = ox + dis * cos(unitTarget->GetOrientation()); + float fy = oy + dis * sin(unitTarget->GetOrientation()); + + // possible z destination coordinate + float fz_ground = MapManager::Instance().GetBaseMap(unitTarget->GetMapId())->GetHeight(fx, fy, MAX_HEIGHT, true); + float fz_floor = MapManager::Instance().GetBaseMap(unitTarget->GetMapId())->GetHeight(fx, fy, unitTarget->GetPositionZ(), true); + + // absolute diferente between orientation z and destination z + float ground_dif = fabs(fz_ground - oz); + float floor_dif = fabs(fz_floor - oz); + + // chech if we hit something in the way + float fz, fx2, fy2, fz2; + bool hit_ground = false, hit_floor = false; + hit_ground = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox, oy, oz + ground_dif + 0.75, fx, fy, fz_ground + 0.75, fx2, fy2, fz2, -0.75); + hit_floor = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox, oy, oz + floor_dif + 0.75, fx, fy, fz_floor + 0.75, fx2, fy2, fz2, -0.75); + + // begin -- choose the best destination z to go + if (ground_dif <= 8.0 && floor_dif <= 8.0) + { + if (fz_ground >= fz_floor) + { + if (hit_ground == false) fz = fz_ground; + else if (hit_floor == false) fz = fz_floor; + } + else + { + if (hit_floor == false) fz = fz_floor; + else if (hit_ground == false) fz = fz_ground; + } + } + else + { + if (ground_dif <= 8.0) fz = fz_ground; + else fz = fz_floor; + } + // end -- choose the best destination z to go + + // a little increment + fz += 0.06; - float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case - if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5)) - { - fx = fx2; - fy = fy2; - fz = fz2; - unitTarget->UpdateGroundPositionZ(fx,fy,fz); - } - if(unitTarget->GetTypeId() == TYPEID_PLAYER) ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0)); else