Merge branch 'develop21' of https://github.com/mangoszero/server into develop21

This commit is contained in:
Foereaper 2015-03-26 11:55:35 +01:00
commit 5432d5e621
2 changed files with 166 additions and 25 deletions

View File

@ -4929,24 +4929,28 @@ SpellCastResult Spell::CheckCast(bool strict)
case SPELL_EFFECT_LEAP:
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 = 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; }
if (!m_caster || m_caster->IsTaxiFlying())
return SPELL_FAILED_NOT_ON_TAXI;
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; }
// Blink has leap first and then removing of auras with root effect
// need further research with this
if (m_spellInfo->Effect[i] != SPELL_EFFECT_LEAP)
{
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 (((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 (bg->GetStatus() != STATUS_IN_PROGRESS)
{ return SPELL_FAILED_TRY_AGAIN; }
return SPELL_FAILED_TRY_AGAIN;
}
break;
}
default: break;

View File

@ -56,6 +56,7 @@
#include "Util.h"
#include "TemporarySummon.h"
#include "ScriptMgr.h"
#include "G3D/Vector3.h"
#ifdef ENABLE_ELUNA
#include "LuaEngine.h"
#endif /* ENABLE_ELUNA */
@ -4360,24 +4361,160 @@ void Spell::EffectBlock(SpellEffectIndex /*eff_idx*/)
void Spell::EffectLeapForward(SpellEffectIndex eff_idx)
{
if (unitTarget->IsTaxiFlying())
{ return; }
float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[eff_idx]));
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;
unitTarget->GetClosePoint(fx, fy, fz, unitTarget->GetObjectBoundingRadius(), dis);
float ox, oy, oz;
unitTarget->GetPosition(ox, oy, oz);
//
GridMapLiquidData liquidData;
if (unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
{
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))
{ unitTarget->UpdateAllowedPositionZ(fx, fy, fz); }
// check any obstacle and fix coords
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)