aboutsummaryrefslogtreecommitdiff
path: root/src/game/Spell.cpp
diff options
context:
space:
mode:
authorXanadu <none@none>2010-03-19 00:21:57 +0100
committerXanadu <none@none>2010-03-19 00:21:57 +0100
commit812874a55bc3b21ae069e283a9c7fd5531aeb751 (patch)
treefcc191c56a111d17a08cf9b490723adf5ca8489b /src/game/Spell.cpp
parent35a7f4849e161ebab96120a091cce7ed40bb5fc8 (diff)
Fixed broken missile visuals in certain DST and SRC type spells (Void Reaver's Arcane Orb and many others). Achieved by fixing wildly incorrect SMSG_SPELL_GO target mask data handling.
--HG-- branch : trunk
Diffstat (limited to 'src/game/Spell.cpp')
-rw-r--r--src/game/Spell.cpp98
1 files changed, 77 insertions, 21 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index b71d4bb7c1e..d8cdfe3ee96 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -127,8 +127,10 @@ SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0)
m_itemTargetEntry = 0;
m_srcPos.Relocate(0,0,0,0);
+ m_dstPos.Relocate(0,0,0,0);
m_strTarget = "";
m_targetMask = 0;
+ m_intTargetFlags = 0;
}
SpellCastTargets::~SpellCastTargets()
@@ -142,13 +144,13 @@ void SpellCastTargets::setUnitTarget(Unit *target)
m_unitTarget = target;
m_unitTargetGUID = target->GetGUID();
- m_targetMask |= TARGET_FLAG_UNIT;
+ m_intTargetFlags |= FLAG_INT_UNIT;
}
void SpellCastTargets::setSrc(float x, float y, float z)
{
m_srcPos.Relocate(x, y, z);
- m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
+ m_intTargetFlags |= FLAG_INT_SRC_LOC;
}
void SpellCastTargets::setSrc(Position *pos)
@@ -156,14 +158,14 @@ void SpellCastTargets::setSrc(Position *pos)
if(pos)
{
m_srcPos.Relocate(pos);
- m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
+ m_intTargetFlags |= FLAG_INT_SRC_LOC;
}
}
void SpellCastTargets::setDst(float x, float y, float z, float orientation, uint32 mapId)
{
m_dstPos.Relocate(x, y, z, orientation);
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
+ m_intTargetFlags |= FLAG_INT_DST_LOC;
if(mapId != MAPID_INVALID)
m_dstPos.m_mapId = mapId;
}
@@ -173,7 +175,7 @@ void SpellCastTargets::setDst(Position *pos)
if(pos)
{
m_dstPos.Relocate(pos);
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
+ m_intTargetFlags |= FLAG_INT_DST_LOC;
}
}
@@ -181,7 +183,7 @@ void SpellCastTargets::setGOTarget(GameObject *target)
{
m_GOTarget = target;
m_GOTargetGUID = target->GetGUID();
- // m_targetMask |= TARGET_FLAG_OBJECT;
+ m_intTargetFlags |= FLAG_INT_OBJECT;
}
void SpellCastTargets::setItemTarget(Item* item)
@@ -237,12 +239,19 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
// TARGET_FLAG_UNK2 is used for non-combat pets, maybe other?
if( m_targetMask & ( TARGET_FLAG_UNIT | TARGET_FLAG_UNK2 ))
+ {
if(!data->readPackGUID(m_unitTargetGUID))
return false;
+ if (m_targetMask & TARGET_FLAG_UNIT)
+ m_intTargetFlags |= FLAG_INT_UNIT;
+ }
if( m_targetMask & ( TARGET_FLAG_OBJECT ))
+ {
if(!data->readPackGUID(m_GOTargetGUID))
return false;
+ m_intTargetFlags |= FLAG_INT_OBJECT;
+ }
if(( m_targetMask & ( TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM )) && caster->GetTypeId() == TYPEID_PLAYER)
if(!data->readPackGUID(m_itemTargetGUID))
@@ -263,6 +272,7 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
*data >> m_srcPos.m_positionX >> m_srcPos.m_positionY >> m_srcPos.m_positionZ;
if(!m_srcPos.IsPositionValid())
return false;
+ m_intTargetFlags |= FLAG_INT_SRC_LOC;
}
else
m_srcPos.Relocate(caster);
@@ -279,6 +289,8 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster )
if(!m_dstPos.IsPositionValid())
return false;
+ m_intTargetFlags |= FLAG_INT_DST_LOC;
+
if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
{
if(data->rpos() + 4 + 4 <= data->size())
@@ -344,21 +356,13 @@ void SpellCastTargets::write ( WorldPacket * data )
if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION )
{
- if(m_unitTarget)
- data->append(m_unitTarget->GetPackGUID());
- else
- *data << uint8(0);
-
+ *data << uint8(0); // It seems the client doesn't like unit target GUID being sent here, we must send 0
*data << m_srcPos.m_positionX << m_srcPos.m_positionY << m_srcPos.m_positionZ;
}
if( m_targetMask & TARGET_FLAG_DEST_LOCATION )
{
- if(m_unitTarget)
- data->append(m_unitTarget->GetPackGUID());
- else
- *data << uint8(0);
-
+ *data << uint8(0); // It seems the client doesn't like unit target GUID being sent here, we must send 0
*data << m_dstPos.m_positionX << m_dstPos.m_positionY << m_dstPos.m_positionZ;
}
@@ -2290,7 +2294,6 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
{
case 46584: // Raise Dead
{
- m_targets.m_targetMask &= ~TARGET_FLAG_DEST_LOCATION;
if (WorldObject* result = FindCorpseUsing<Trinity::RaiseDeadObjectCheck> ())
{
switch(result->GetTypeId())
@@ -2597,6 +2600,30 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere
}
}
+ if (!m_targets.HasSrc() && m_spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
+ m_targets.setSrc(m_caster);
+
+ if (!m_targets.HasDst() && m_spellInfo->Targets & TARGET_FLAG_DEST_LOCATION)
+ {
+ Unit *target = m_targets.getUnitTarget();
+ if (!target)
+ {
+ if(m_caster->GetTypeId() == TYPEID_UNIT)
+ target = m_caster->getVictim();
+ else
+ target = ObjectAccessor::GetUnit(*m_caster, m_caster->ToPlayer()->GetSelection());
+ }
+
+ if (target)
+ m_targets.setDst(target);
+ else
+ {
+ SendCastResult(SPELL_FAILED_BAD_TARGETS);
+ finish(false);
+ return;
+ }
+ }
+
// Fill aura scaling information
if (m_caster->IsControlledByPlayer() && !IsPassiveSpell(m_spellInfo->Id) && m_spellInfo->spellLevel && !IsChanneledSpell(m_spellInfo) && !m_IsTriggeredSpell)
{
@@ -2697,7 +2724,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere
// set timer base at cast time
ReSetTimer();
- sLog.outDebug("Spell::prepare: spell id %u source %u caster %d triggered %u mask %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, m_IsTriggeredSpell ? 1 : 0, m_targets.m_targetMask);
+ sLog.outDebug("Spell::prepare: spell id %u source %u caster %d triggered %u mask %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, m_IsTriggeredSpell ? 1 : 0, m_targets.getTargetMask());
//if(m_targets.getUnitTarget())
// sLog.outError("Spell::prepare: unit target %u", m_targets.getUnitTarget()->GetEntry());
//if(m_targets.HasDst())
@@ -3045,7 +3072,7 @@ uint64 Spell::handle_delayed(uint64 t_offset)
m_immediateHandled = true;
}
- bool single_missile = (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION);
+ bool single_missile = (m_targets.getIntTargetFlags() & FLAG_INT_DST_LOC);
// now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases)
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -3530,6 +3557,19 @@ void Spell::SendSpellStart()
data << uint32(castFlags); // cast flags
data << uint32(m_timer); // delay?
+ // Preliminary setting of the target mask for the SMSG_SPELL_START packet. This will be
+ // adjusted again later in SendSpellGo() based on the real targets obtained in SelectSpellTargets()
+ if (m_spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_SOURCE_LOCATION);
+
+ if (m_spellInfo->Targets & TARGET_FLAG_DEST_LOCATION)
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_DEST_LOCATION);
+
+ if (m_targets.getTargetMask() & (TARGET_FLAG_SOURCE_LOCATION | TARGET_FLAG_DEST_LOCATION))
+ m_targets.setTargetMask(m_targets.getTargetMask() & ~TARGET_FLAG_UNIT);
+ else if (m_targets.getIntTargetFlags() & FLAG_INT_UNIT)
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_UNIT);
+
m_targets.write(&data);
if(castFlags & CAST_FLAG_POWER_LEFT_SELF)
@@ -3597,6 +3637,22 @@ void Spell::SendSpellGo()
data << uint32(castFlags); // cast flags
data << uint32(getMSTime()); // timestamp
+ if ((m_spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) && m_targets.HasSrc())
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_SOURCE_LOCATION);
+ else
+ m_targets.setTargetMask(m_targets.getTargetMask() & ~TARGET_FLAG_SOURCE_LOCATION);
+
+ if ((m_spellInfo->Targets & TARGET_FLAG_DEST_LOCATION) && m_targets.HasDst())
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_DEST_LOCATION);
+ else
+ m_targets.setTargetMask(m_targets.getTargetMask() & ~TARGET_FLAG_DEST_LOCATION);
+
+ // Can't have TARGET_FLAG_UNIT when *_LOCATION is present - it breaks missile visuals
+ if (m_targets.getTargetMask() & (TARGET_FLAG_SOURCE_LOCATION | TARGET_FLAG_DEST_LOCATION))
+ m_targets.setTargetMask(m_targets.getTargetMask() & ~TARGET_FLAG_UNIT);
+ else if (m_targets.getIntTargetFlags() & FLAG_INT_UNIT)
+ m_targets.setTargetMask(m_targets.getTargetMask() | TARGET_FLAG_UNIT);
+
WriteSpellGoTargets(&data);
m_targets.write(&data);
@@ -3634,7 +3690,7 @@ void Spell::SendSpellGo()
data << uint32(0);
}
- if ( m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION )
+ if ( m_targets.getTargetMask() & TARGET_FLAG_DEST_LOCATION )
{
data << uint8(0);
}
@@ -4514,7 +4570,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// Additional check for some spells
// If 0 spell effect empty - client not send target data (need use selection)
// TODO: check it on next client version
- if (m_targets.m_targetMask == TARGET_FLAG_SELF &&
+ if (m_targets.getTargetMask() == TARGET_FLAG_SELF &&
m_spellInfo->EffectImplicitTargetA[1] == TARGET_UNIT_TARGET_ENEMY)
{
if (target = m_caster->GetUnit(*m_caster, m_caster->ToPlayer()->GetSelection()))