rendered paste bodyIndex: 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