aboutsummaryrefslogtreecommitdiff
path: root/src/game/Spell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Spell.cpp')
-rw-r--r--src/game/Spell.cpp153
1 files changed, 141 insertions, 12 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 03d1f0399f6..a18c05e63b2 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -112,7 +112,7 @@ struct PrioritizeHealth
typedef std::priority_queue<PrioritizeHealthUnitWraper, std::vector<PrioritizeHealthUnitWraper>, PrioritizeHealth> PrioritizeHealthUnitQueue;
-SpellCastTargets::SpellCastTargets()
+SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0)
{
m_unitTarget = NULL;
m_itemTarget = NULL;
@@ -285,6 +285,16 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
*data >> m_destX >> m_destY >> m_destZ;
if(!Trinity::IsValidMapCoord(m_destX, m_destY, m_destZ))
return false;
+
+ if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
+ {
+ if(data->rpos() + 4 + 4 <= data->size())
+ {
+ *data >> m_elevation >> m_speed;
+ //*data >> uint16 >> uint8 >> uint32 >> uint32;
+ //*data >> float >> float >> float >> float...
+ }
+ }
}
if( m_targetMask & TARGET_FLAG_STRING )
@@ -510,7 +520,7 @@ WorldObject* Spell::FindCorpseUsing()
return result;
}
-void Spell::FillTargetMap()
+void Spell::SelectSpellTargets()
{
for(uint32 i = 0; i < 3; ++i)
{
@@ -529,9 +539,9 @@ void Spell::FillTargetMap()
uint32 targetB = m_spellInfo->EffectImplicitTargetB[i];
if(targetA)
- SetTargetMap(i, targetA);
+ SelectEffectTargets(i, targetA);
if(targetB) // In very rare case !A && B
- SetTargetMap(i, targetB);
+ SelectEffectTargets(i, targetB);
if(effectTargetType != SPELL_REQUIRE_UNIT)
{
@@ -679,7 +689,7 @@ void Spell::FillTargetMap()
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
// AreaAura
if(m_spellInfo->Attributes == 0x9050000 || m_spellInfo->Attributes == 0x10000)
- SetTargetMap(i, TARGET_UNIT_PARTY_TARGET);
+ SelectEffectTargets(i, TARGET_UNIT_PARTY_TARGET);
break;
case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
if(m_targets.getUnitTarget())
@@ -739,12 +749,17 @@ void Spell::FillTargetMap()
}
}
- if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
+ if(m_targets.HasDst())
{
- if(m_spellInfo->speed > 0.0f && m_targets.HasDst())
+ if(m_targets.HasTraj())
+ {
+ float speed = m_targets.GetSpeedXY();
+ if(speed > 0.0f)
+ m_delayMoment = (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f);
+ }
+ else if(m_spellInfo->speed > 0.0f)
{
float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
- if (dist < 5.0f) dist = 5.0f;
m_delayMoment = (uint64) floor(dist / m_spellInfo->speed * 1000.0f);
}
}
@@ -1805,7 +1820,7 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
}
}
-void Spell::SetTargetMap(uint32 i, uint32 cur)
+void Spell::SelectEffectTargets(uint32 i, uint32 cur)
{
SpellNotifyPushType pushType = PUSH_NONE;
Player *modOwner = NULL;
@@ -2055,7 +2070,9 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
case TARGET_DEST_DYNOBJ_ALLY:
case TARGET_DEST_DYNOBJ_NONE:
case TARGET_DEST_DEST:
+ return;
case TARGET_DEST_TRAJ:
+ SelectTrajTargets();
return;
case TARGET_DEST_DEST_FRONT: angle = 0.0f; break;
case TARGET_DEST_DEST_BACK: angle = M_PI; break;
@@ -2679,7 +2696,11 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura
// set timer base at cast time
ReSetTimer();
- sLog.outDebug("Spell::prepare: spell id %u source %u caster %d target %d triggered %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, m_targets.getUnitTarget() ? m_targets.getUnitTarget()->GetEntry() : -1, m_IsTriggeredSpell ? 1 : 0);
+ sLog.outDebug("Spell::prepare: spell id %u source %u caster %d triggered %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, m_IsTriggeredSpell ? 1 : 0);
+ //if(m_targets.getUnitTarget())
+ // sLog.outError("Spell::prepare: unit target %u", m_targets.getUnitTarget()->GetEntry());
+ //if(m_targets.HasDst())
+ // sLog.outError("Spell::prepare: pos target %f %f %f", m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
//Containers for channeled spells have to be set
//TODO:Apply this to all casted spells if needed
@@ -2823,7 +2844,7 @@ void Spell::cast(bool skipCheck)
}
}
- FillTargetMap();
+ SelectSpellTargets();
// Spell may be finished after target map check
if(m_spellState == SPELL_STATE_FINISHED)
@@ -5361,7 +5382,7 @@ bool Spell::CanAutoCast(Unit* target)
if(result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
{
- FillTargetMap();
+ SelectSpellTargets();
//check if among target units, our WANTED target is as well (->only self cast spells return false)
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
if( ihit->targetGUID == targetguid )
@@ -6547,6 +6568,114 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value)
}
}
+void Spell::SelectTrajTargets()
+{
+ if(!m_targets.HasTraj())
+ return;
+
+ float dist2d = m_targets.GetDist2d();
+ float dz = m_targets.m_destZ - m_targets.m_srcZ;
+
+ UnitList unitList;
+ SearchAreaTarget(unitList, dist2d, PUSH_IN_THIN_LINE, SPELL_TARGETS_ANY);
+ if(unitList.empty())
+ return;
+
+ unitList.sort(TargetDistanceOrder(m_caster));
+
+ float sinE = sin(m_targets.m_elevation);
+ float dcosE = 2 * cos(m_targets.m_elevation);
+ float divisor = dist2d * (dist2d - dcosE);
+ if(abs(divisor) < 0.0001f) divisor = 0.0001f;
+ float a = (dz - dist2d * sinE) / divisor;
+ float b = sinE - dcosE * a;
+ if(a > -0.0001f) a = -0.0001f;
+
+ float bestDist;
+ UnitList::const_iterator itr = unitList.begin();
+ for(; itr != unitList.end(); ++itr)
+ {
+ if(m_caster == *itr || m_caster == (*itr)->m_Vehicle || m_caster->m_Vehicle == *itr)
+ continue;
+
+ const float size = (*itr)->GetObjectSize() * 0.6f; // 1/sqrt(3)
+ const float objDist2d = m_caster->GetExactDistance2d((*itr)->GetPositionX(), (*itr)->GetPositionY()) * cos(m_caster->GetRelativeAngle(*itr));
+ const float dz = (*itr)->GetPositionZ() - m_caster->GetPositionZ();
+
+ float dist = objDist2d - size;
+ float height = dist * (a * dist + b);
+ if(height < dz + size && height > dz - size)
+ {
+ bestDist = dist > 0 ? dist : 0;
+ break;
+ }
+
+ height = dz - size;
+ float sqrt1 = b * b + 4 * a * height;
+ if(sqrt1 > 0)
+ {
+ sqrt1 = sqrt(sqrt1);
+ dist = (sqrt1 - b) / (2 * a);
+ if(dist < objDist2d + size && dist > objDist2d - size)
+ {
+ bestDist = dist;
+ break;
+ }
+ }
+
+ height = dz + size;
+ float sqrt2 = b * b + 4 * a * height;
+ if(sqrt2 > 0)
+ {
+ sqrt2 = sqrt(sqrt2);
+ dist = (sqrt2 - b) / (2 * a);
+ if(dist < objDist2d + size && dist > objDist2d - size)
+ {
+ bestDist = dist;
+ break;
+ }
+
+ dist = (-sqrt2 - b) / (2 * a);
+ if(dist < objDist2d + size && dist > objDist2d - size)
+ {
+ bestDist = dist;
+ break;
+ }
+ }
+
+ if(sqrt1 > 0)
+ {
+ dist = (-sqrt1 - b) / (2 * a);
+ if(dist < objDist2d + size && dist > objDist2d - size)
+ {
+ bestDist = dist;
+ break;
+ }
+ }
+ }
+
+ if(itr != unitList.end())
+ {
+ float x = m_targets.m_srcX + cos(m_caster->GetOrientation()) * bestDist;
+ float y = m_targets.m_srcY + sin(m_caster->GetOrientation()) * bestDist;
+ float z = m_targets.m_srcZ + bestDist * (a * bestDist + b);
+ float distSq = (*itr)->GetExactDistSq(x, y, z);
+ float sizeSq = (*itr)->GetObjectSize();
+ sizeSq *= sizeSq;
+ if(distSq > sizeSq)
+ {
+ float factor = 1 - sqrt(sizeSq / distSq);
+ x += factor * ((*itr)->GetPositionX() - x);
+ y += factor * ((*itr)->GetPositionY() - y);
+ z += factor * ((*itr)->GetPositionZ() - z);
+
+ distSq = (*itr)->GetExactDistSq(x, y, z);
+ }
+
+ m_targets.setDestination(x, y, z);
+ }
+}
+
void Spell::FillRaidOrPartyTargets( UnitList &TagUnitMap, Unit* target, float radius, bool raid, bool withPets, bool withcaster )
{
Player *pTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();