[Core] Improved Blink (c2618,c2623)
1 - Implement generating path ( where unit can walk - there blink will available ) 2 - Implement Water path (if blink starting before (or in) water - Z coord will safe, if starting IN water, and last point on a ground (if it available) - new Z will on a ground. 3 - Implement Safe blink , both parts : * - blink at abyss ( unit will stoped before abyss ) * - blink in falling, where difference between unit Z and land Z < 8 yards - unit will blink on a land, if blink in falling, but difference will more then 8 yards - just blink forward All parts of blink has check LoS (c2618) Blink -> Check if we are near of liquid level before assigning previous Z to next Z. (c2623) @cyberium Also when we tp to water we have to set final z a bit under the liquid level. Not at liquid level.
This commit is contained in:
parent
4de5fa3543
commit
4839283c1c
@ -4929,24 +4929,28 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||||||
case SPELL_EFFECT_LEAP:
|
case SPELL_EFFECT_LEAP:
|
||||||
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
|
case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER:
|
||||||
{
|
{
|
||||||
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
|
if (!m_caster || m_caster->IsTaxiFlying())
|
||||||
float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation());
|
return SPELL_FAILED_NOT_ON_TAXI;
|
||||||
float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation());
|
|
||||||
// teleport a bit above terrain level to avoid falling below it
|
|
||||||
float fz = m_caster->GetMap()->GetHeight(fx, fy, m_caster->GetPositionZ());
|
|
||||||
if (fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled
|
|
||||||
{ return SPELL_FAILED_TRY_AGAIN; }
|
|
||||||
|
|
||||||
float caster_pos_z = m_caster->GetPositionZ();
|
// Blink has leap first and then removing of auras with root effect
|
||||||
// Control the caster to not climb or drop when +-fz > 8
|
// need further research with this
|
||||||
if (!(fz <= caster_pos_z + 8 && fz >= caster_pos_z - 8))
|
if (m_spellInfo->Effect[i] != SPELL_EFFECT_LEAP)
|
||||||
{ return SPELL_FAILED_TRY_AGAIN; }
|
{
|
||||||
|
if (m_caster->hasUnitState(UNIT_STAT_ROOT))
|
||||||
|
return SPELL_FAILED_ROOTED;
|
||||||
|
}
|
||||||
|
|
||||||
// not allow use this effect at battleground until battleground start
|
|
||||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
if (((Player*)m_caster)->HasMovementFlag(MOVEFLAG_ONTRANSPORT))
|
||||||
|
return SPELL_FAILED_NOT_ON_TRANSPORT;
|
||||||
|
|
||||||
|
// not allow use this effect at battleground until battleground start
|
||||||
if (BattleGround const* bg = ((Player*)m_caster)->GetBattleGround())
|
if (BattleGround const* bg = ((Player*)m_caster)->GetBattleGround())
|
||||||
if (bg->GetStatus() != STATUS_IN_PROGRESS)
|
if (bg->GetStatus() != STATUS_IN_PROGRESS)
|
||||||
{ return SPELL_FAILED_TRY_AGAIN; }
|
return SPELL_FAILED_TRY_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "TemporarySummon.h"
|
#include "TemporarySummon.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
|
#include "G3D/Vector3.h"
|
||||||
#ifdef ENABLE_ELUNA
|
#ifdef ENABLE_ELUNA
|
||||||
#include "LuaEngine.h"
|
#include "LuaEngine.h"
|
||||||
#endif /* ENABLE_ELUNA */
|
#endif /* ENABLE_ELUNA */
|
||||||
@ -4360,24 +4361,160 @@ void Spell::EffectBlock(SpellEffectIndex /*eff_idx*/)
|
|||||||
|
|
||||||
void Spell::EffectLeapForward(SpellEffectIndex eff_idx)
|
void Spell::EffectLeapForward(SpellEffectIndex eff_idx)
|
||||||
{
|
{
|
||||||
if (unitTarget->IsTaxiFlying())
|
float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
|
||||||
{ return; }
|
const float IN_OR_UNDER_LIQUID_RANGE = 0.8f; // range to make player under liquid or on liquid surface from liquid level
|
||||||
|
|
||||||
if (m_spellInfo->rangeIndex == SPELL_RANGE_IDX_SELF_ONLY)
|
G3D::Vector3 prevPos, nextPos;
|
||||||
|
float orientation = unitTarget->GetOrientation();
|
||||||
|
|
||||||
|
prevPos.x = unitTarget->GetPositionX();
|
||||||
|
prevPos.y = unitTarget->GetPositionY();
|
||||||
|
prevPos.z = unitTarget->GetPositionZ();
|
||||||
|
|
||||||
|
float groundZ = prevPos.z;
|
||||||
|
bool isPrevInLiquid = false;
|
||||||
|
|
||||||
|
// falling case
|
||||||
|
if (!unitTarget->GetMap()->GetHeightInRange(prevPos.x, prevPos.y, groundZ, 3.0f) && unitTarget->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING))
|
||||||
{
|
{
|
||||||
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
|
nextPos.x = prevPos.x + dist * cos(orientation);
|
||||||
|
nextPos.y = prevPos.y + dist * sin(orientation);
|
||||||
|
nextPos.z = prevPos.z - 2.0f; // little hack to avoid the impression to go up when teleporting instead of continue to fall. This value may need some tweak
|
||||||
|
|
||||||
// before caster
|
//
|
||||||
float fx, fy, fz;
|
GridMapLiquidData liquidData;
|
||||||
unitTarget->GetClosePoint(fx, fy, fz, unitTarget->GetObjectBoundingRadius(), dis);
|
if (unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
|
||||||
float ox, oy, oz;
|
{
|
||||||
unitTarget->GetPosition(ox, oy, oz);
|
if (fabs(nextPos.z - liquidData.level) < 10.0f)
|
||||||
|
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fix z to ground if near of it
|
||||||
|
unitTarget->GetMap()->GetHeightInRange(nextPos.x, nextPos.y, nextPos.z, 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
if (unitTarget->GetMap()->GetHitPosition(ox, oy, oz + 0.5f, fx, fy, fz, -0.5f))
|
// check any obstacle and fix coords
|
||||||
{ unitTarget->UpdateAllowedPositionZ(fx, fy, fz); }
|
unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 0.5f, nextPos.x, nextPos.y, nextPos.z, -0.5f);
|
||||||
|
|
||||||
unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(), unitTarget == m_caster);
|
// teleport
|
||||||
|
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
|
||||||
|
|
||||||
|
//sLog.outString("Falling BLINK!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fix origin position if player was jumping and near of the ground but not in ground
|
||||||
|
if (fabs(prevPos.z - groundZ) > 0.5f)
|
||||||
|
prevPos.z = groundZ;
|
||||||
|
|
||||||
|
//check if in liquid
|
||||||
|
isPrevInLiquid = unitTarget->GetMap()->GetTerrain()->IsInWater(prevPos.x, prevPos.y, prevPos.z);
|
||||||
|
|
||||||
|
const float step = 2.0f; // step length before next check slope/edge/water
|
||||||
|
const float maxSlope = 50.0f; // 50(degree) max seem best value for walkable slope
|
||||||
|
const float MAX_SLOPE_IN_RADIAN = maxSlope / 180.0f * M_PI_F;
|
||||||
|
float nextZPointEstimation = 1.0f;
|
||||||
|
float destx = prevPos.x + dist * cos(orientation);
|
||||||
|
float desty = prevPos.y + dist * sin(orientation);
|
||||||
|
const uint32 numChecks = ceil(fabs(dist / step));
|
||||||
|
const float DELTA_X = (destx - prevPos.x) / numChecks;
|
||||||
|
const float DELTA_Y = (desty - prevPos.y) / numChecks;
|
||||||
|
|
||||||
|
for (uint32 i = 1; i < numChecks + 1; ++i)
|
||||||
|
{
|
||||||
|
// compute next point average position
|
||||||
|
nextPos.x = prevPos.x + DELTA_X;
|
||||||
|
nextPos.y = prevPos.y + DELTA_Y;
|
||||||
|
nextPos.z = prevPos.z + nextZPointEstimation;
|
||||||
|
|
||||||
|
bool isInLiquid = false;
|
||||||
|
bool isInLiquidTested = false;
|
||||||
|
bool isOnGround = false;
|
||||||
|
GridMapLiquidData liquidData;
|
||||||
|
|
||||||
|
// try fix height for next position
|
||||||
|
if (!unitTarget->GetMap()->GetHeightInRange(nextPos.x, nextPos.y, nextPos.z))
|
||||||
|
{
|
||||||
|
// we cant so test if we are on water
|
||||||
|
if (!unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
|
||||||
|
{
|
||||||
|
// not in water and cannot get correct height, maybe flying?
|
||||||
|
//sLog.outString("Can't get height of point %u, point value %s", i, nextPos.toString().c_str());
|
||||||
|
nextPos = prevPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isInLiquid = true;
|
||||||
|
isInLiquidTested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
isOnGround = true; // player is on ground
|
||||||
|
|
||||||
|
if (isInLiquid || (!isInLiquidTested && unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData)))
|
||||||
|
{
|
||||||
|
if (!isPrevInLiquid && fabs(liquidData.level - prevPos.z) > 2.0f)
|
||||||
|
{
|
||||||
|
// on edge of water with difference a bit to high to continue
|
||||||
|
//sLog.outString("Ground vs liquid edge detected!");
|
||||||
|
nextPos = prevPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((liquidData.level - IN_OR_UNDER_LIQUID_RANGE) > nextPos.z)
|
||||||
|
nextPos.z = prevPos.z; // we are under water so next z equal prev z
|
||||||
|
else
|
||||||
|
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE; // we are on water surface, so next z equal liquid level
|
||||||
|
|
||||||
|
isInLiquid = true;
|
||||||
|
|
||||||
|
float ground = nextPos.z;
|
||||||
|
if (unitTarget->GetMap()->GetHeightInRange(nextPos.x, nextPos.y, ground))
|
||||||
|
{
|
||||||
|
if (nextPos.z < ground)
|
||||||
|
{
|
||||||
|
nextPos.z = ground;
|
||||||
|
isOnGround = true; // player is on ground of the water
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//unitTarget->SummonCreature(VISUAL_WAYPOINT, nextPos.x, nextPos.y, nextPos.z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000);
|
||||||
|
float hitZ = nextPos.z + 1.5f;
|
||||||
|
if (unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 1.5f, nextPos.x, nextPos.y, hitZ, -1.0f))
|
||||||
|
{
|
||||||
|
//sLog.outString("Blink collision detected!");
|
||||||
|
nextPos = prevPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOnGround)
|
||||||
|
{
|
||||||
|
// project vector to get only positive value
|
||||||
|
float ac = fabs(prevPos.z - nextPos.z);
|
||||||
|
|
||||||
|
// compute slope (in radian)
|
||||||
|
float slope = atan(ac / step);
|
||||||
|
|
||||||
|
// check slope value
|
||||||
|
if (slope > MAX_SLOPE_IN_RADIAN)
|
||||||
|
{
|
||||||
|
//sLog.outString("bad slope detected! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
|
||||||
|
nextPos = prevPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//sLog.outString("slope is ok! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
//sLog.outString("point %u is ok, coords %s", i, nextPos.toString().c_str());
|
||||||
|
nextZPointEstimation = (nextPos.z - prevPos.z) / 2.0f;
|
||||||
|
isPrevInLiquid = isInLiquid;
|
||||||
|
prevPos = nextPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::EffectReputation(SpellEffectIndex eff_idx)
|
void Spell::EffectReputation(SpellEffectIndex eff_idx)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user