diff options
| author | QAston <qaston@gmail.com> | 2011-08-26 12:05:47 +0200 |
|---|---|---|
| committer | QAston <qaston@gmail.com> | 2011-08-26 12:06:13 +0200 |
| commit | 5c48d9ec8ab587f6d26b04b6b2becb340a9804a8 (patch) | |
| tree | 87bd738171d5af8ea7e3e19341e82b2cdd7462ca /src/server/game/Spells/Spell.cpp | |
| parent | e41774750f58c64a87f511dff4aeeda506ea7b48 (diff) | |
Core/Spells: Store explicit unit, corpse and GO targets in one variable, because both client and server can't handle more than one explicit object target; Add spell explicit target validation.
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 280 |
1 files changed, 119 insertions, 161 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index af8e1b2c1a9..a7370c3f74f 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -58,13 +58,10 @@ extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0) { - m_unitTarget = NULL; + m_objectTarget = NULL; m_itemTarget = NULL; - m_GOTarget = NULL; - m_unitTargetGUID = 0; - m_GOTargetGUID = 0; - m_CorpseTargetGUID = 0; + m_objectTargetGUID = 0; m_itemTargetGUID = 0; m_itemTargetEntry = 0; @@ -89,18 +86,12 @@ void SpellCastTargets::Read(ByteBuffer& data, Unit* caster) if (m_targetMask == TARGET_FLAG_NONE) return; - if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET)) - data.readPackGUID(m_unitTargetGUID); - - if (m_targetMask & (TARGET_FLAG_GAMEOBJECT)) - data.readPackGUID(m_GOTargetGUID); + if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY)) + data.readPackGUID(m_objectTargetGUID); if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM)) data.readPackGUID(m_itemTargetGUID); - if (m_targetMask & (TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY)) - data.readPackGUID(m_CorpseTargetGUID); - if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) { data.readPackGUID(m_srcTransGUID); @@ -146,26 +137,7 @@ void SpellCastTargets::Write(ByteBuffer& data) data << uint32(m_targetMask); if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET)) - { - if (m_targetMask & TARGET_FLAG_UNIT) - { - if (m_unitTarget) - data.append(m_unitTarget->GetPackGUID()); - else - data << uint8(0); - } - else if (m_targetMask & TARGET_FLAG_GAMEOBJECT) - { - if (m_GOTarget) - data.append(m_GOTarget->GetPackGUID()); - else - data << uint8(0); - } - else if (m_targetMask & (TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_CORPSE_ENEMY)) - data.appendPackGUID(m_CorpseTargetGUID); - else - data << uint8(0); - } + data.appendPackGUID(m_objectTargetGUID); if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM)) { @@ -197,44 +169,101 @@ void SpellCastTargets::Write(ByteBuffer& data) data << m_strTarget; } +uint64 SpellCastTargets::GetUnitTargetGUID() const +{ + switch (GUID_HIPART(m_objectTargetGUID)) + { + case HIGHGUID_PLAYER: + case HIGHGUID_VEHICLE: + case HIGHGUID_UNIT: + case HIGHGUID_PET: + return m_objectTargetGUID; + default: + return 0LL; + } +} + +Unit* SpellCastTargets::GetUnitTarget() const +{ + if (m_objectTarget) + return m_objectTarget->ToUnit(); + return NULL; +} + void SpellCastTargets::SetUnitTarget(Unit* target) { if (!target) return; - m_unitTarget = target; - m_unitTargetGUID = target->GetGUID(); + m_objectTarget = target; + m_objectTargetGUID = target->GetGUID(); m_targetMask |= TARGET_FLAG_UNIT; } -void SpellCastTargets::RemoveUnitTarget() +uint64 SpellCastTargets::GetGOTargetGUID() const +{ + switch (GUID_HIPART(m_objectTargetGUID)) + { + case HIGHGUID_TRANSPORT: + case HIGHGUID_MO_TRANSPORT: + case HIGHGUID_GAMEOBJECT: + return m_objectTargetGUID; + default: + return 0LL; + } +} + +GameObject* SpellCastTargets::GetGOTarget() const { - m_unitTarget = NULL; - m_unitTargetGUID = 0LL; - m_targetMask &= ~(TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET); + if (m_objectTarget) + return m_objectTarget->ToGameObject(); + return NULL; } + void SpellCastTargets::SetGOTarget(GameObject* target) { if (!target) return; - m_GOTarget = target; - m_GOTargetGUID = target->GetGUID(); + m_objectTarget = target; + m_objectTargetGUID = target->GetGUID(); m_targetMask |= TARGET_FLAG_GAMEOBJECT; } -void SpellCastTargets::RemoveGOTarget() +uint64 SpellCastTargets::GetCorpseTargetGUID() const +{ + switch (GUID_HIPART(m_objectTargetGUID)) + { + case HIGHGUID_CORPSE: + return m_objectTargetGUID; + default: + return 0LL; + } +} + +Corpse* SpellCastTargets::GetCorpseTarget() const +{ + if (m_objectTarget) + return m_objectTarget->ToCorpse(); + return NULL; +} + +WorldObject* SpellCastTargets::GetObjectTarget() const +{ + return m_objectTarget; +} + +uint64 SpellCastTargets::GetObjectTargetGUID() const { - m_GOTarget = NULL; - m_GOTargetGUID = 0LL; - m_targetMask &= ~(TARGET_FLAG_GAMEOBJECT); + return m_objectTargetGUID; } -void SpellCastTargets::RemoveCorpseTarget() +void SpellCastTargets::RemoveObjectTarget() { - m_CorpseTargetGUID = 0; - m_targetMask &= ~(TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY); + m_objectTarget = NULL; + m_objectTargetGUID = 0LL; + m_targetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK); } void SpellCastTargets::SetItemTarget(Item* item) @@ -370,8 +399,7 @@ void SpellCastTargets::RemoveDst() void SpellCastTargets::Update(Unit* caster) { - m_GOTarget = m_GOTargetGUID ? caster->GetMap()->GetGameObject(m_GOTargetGUID) : NULL; - m_unitTarget = m_unitTargetGUID ? (m_unitTargetGUID == caster->GetGUID() ? caster : ObjectAccessor::GetUnit(*caster, m_unitTargetGUID)) : NULL; + m_objectTarget = m_objectTargetGUID ? ((m_objectTargetGUID == caster->GetGUID()) ? caster : ObjectAccessor::GetWorldObject(*caster, m_objectTargetGUID)) : NULL; m_itemTarget = NULL; if (caster->GetTypeId() == TYPEID_PLAYER) @@ -411,28 +439,21 @@ void SpellCastTargets::Update(Unit* caster) void SpellCastTargets::OutDebug() const { if (!m_targetMask) - sLog->outString("TARGET_FLAG_NONE"); - - if (m_targetMask & TARGET_FLAG_UNIT) - sLog->outString("TARGET_FLAG_UNIT: " UI64FMTD, m_unitTargetGUID); - if (m_targetMask & TARGET_FLAG_UNIT_MINIPET) - sLog->outString("TARGET_FLAG_UNIT_MINIPET: " UI64FMTD, m_unitTargetGUID); - if (m_targetMask & TARGET_FLAG_GAMEOBJECT) - sLog->outString("TARGET_FLAG_GAMEOBJECT: " UI64FMTD, m_GOTargetGUID); - if (m_targetMask & TARGET_FLAG_CORPSE_ENEMY) - sLog->outString("TARGET_FLAG_CORPSE_ENEMY: " UI64FMTD, m_CorpseTargetGUID); - if (m_targetMask & TARGET_FLAG_CORPSE_ALLY) - sLog->outString("TARGET_FLAG_CORPSE_ALLY: " UI64FMTD, m_CorpseTargetGUID); + sLog->outString("No targets"); + + sLog->outString("target mask: %u", m_targetMask); + if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK)) + sLog->outString("Object target: " UI64FMTD, m_objectTargetGUID); if (m_targetMask & TARGET_FLAG_ITEM) - sLog->outString("TARGET_FLAG_ITEM: " UI64FMTD, m_itemTargetGUID); + sLog->outString("Item target: " UI64FMTD, m_itemTargetGUID); if (m_targetMask & TARGET_FLAG_TRADE_ITEM) - sLog->outString("TARGET_FLAG_TRADE_ITEM: " UI64FMTD, m_itemTargetGUID); + sLog->outString("Trade item target: " UI64FMTD, m_itemTargetGUID); if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) - sLog->outString("TARGET_FLAG_SOURCE_LOCATION: transport guid:" UI64FMTD " trans offset: %s position: %s", m_srcTransGUID, m_srcTransOffset.ToString().c_str(), m_srcPos.ToString().c_str()); + sLog->outString("Source location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_srcTransGUID, m_srcTransOffset.ToString().c_str(), m_srcPos.ToString().c_str()); if (m_targetMask & TARGET_FLAG_DEST_LOCATION) - sLog->outString("TARGET_FLAG_DEST_LOCATION: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dstTransGUID, m_dstTransOffset.ToString().c_str(), m_dstPos.ToString().c_str()); + sLog->outString("Destination location: transport guid:" UI64FMTD " trans offset: %s position: %s", m_dstTransGUID, m_dstTransOffset.ToString().c_str(), m_dstPos.ToString().c_str()); if (m_targetMask & TARGET_FLAG_STRING) - sLog->outString("TARGET_FLAG_STRING: %s", m_strTarget.c_str()); + sLog->outString("String: %s", m_strTarget.c_str()); sLog->outString("speed: %f", m_speed); sLog->outString("elevation: %f", m_elevation); } @@ -608,19 +629,27 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets) // this also makes sure that we correctly send explicit targets to client (removes redundant data) uint32 neededTargets = m_spellInfo->GetExplicitTargetMask(); - // check if spell needs unit target (allow spells with corpse flag to accept unit targets - unit target is sent by client when corpse not yet released) - if (neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)) + if (WorldObject* target = m_targets.GetObjectTarget()) { - Unit* target = targets.GetUnitTarget(); - - if (!target) + // check if object target is valid with needed target flags + // for unit case allow corpse target mask because player with not released corpse is a unit target + if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK))) + || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK)) + || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK))) + m_targets.RemoveObjectTarget(); + } + else + { + // try to select correct unit target if not provided by client or by serverside cast + if (neededTargets & (TARGET_FLAG_UNIT_MASK)) { + Unit* target = NULL; // try to use player selection as a target if (Player* playerCaster = m_caster->ToPlayer()) { // selection has to be found and to be valid target for the spell if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetSelection())) - if (IsValidSingleTargetSpell(selectedUnit)) + if (m_spellInfo->CheckExplicitTarget(m_caster, selectedUnit) == SPELL_CAST_OK) target = selectedUnit; } // try to use attacked unit as a target @@ -629,17 +658,10 @@ void Spell::InitExplicitTargets(SpellCastTargets const& targets) // didn't find anything - let's use self as target if (!target && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY | TARGET_FLAG_UNIT)) target = m_caster; + + m_targets.SetUnitTarget(target); } - m_targets.SetUnitTarget(target); } - else - m_targets.RemoveUnitTarget(); - - if (!(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK)) - m_targets.RemoveGOTarget(); - - if (!(neededTargets & TARGET_FLAG_CORPSE_MASK)) - m_targets.RemoveCorpseTarget(); // check if spell needs dst target if (neededTargets & TARGET_FLAG_DEST_LOCATION) @@ -746,15 +768,15 @@ void Spell::SelectSpellTargets() AddUnitTarget(target, i, false); } break; + case SPELL_EFFECT_SKIN_PLAYER_CORPSE: case SPELL_EFFECT_RESURRECT_NEW: - if (m_targets.GetUnitTarget()) - AddUnitTarget(m_targets.GetUnitTarget(), i, false); - if (m_targets.GetCorpseTargetGUID()) + if (WorldObject* target = m_targets.GetObjectTarget()) { - Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID()); - if (corpse) + if (Unit* unitTarget = target->ToUnit()) + AddUnitTarget(unitTarget, i, false); + else if (Corpse* corpseTarget = target->ToCorpse()) { - Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); + Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()); if (owner) AddUnitTarget(owner, i, false); } @@ -786,20 +808,6 @@ void Spell::SelectSpellTargets() break; } break; - case SPELL_EFFECT_SKIN_PLAYER_CORPSE: - if (m_targets.GetUnitTarget()) - AddUnitTarget(m_targets.GetUnitTarget(), i, false); - else if (m_targets.GetCorpseTargetGUID()) - { - Corpse *corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID()); - if (corpse) - { - Player* owner = ObjectAccessor::FindPlayer(corpse->GetOwnerGUID()); - if (owner) - AddUnitTarget(owner, i, false); - } - } - break; default: AddUnitTarget(m_caster, i, false); break; @@ -2095,12 +2103,10 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur) case TARGET_UNIT_TARGET_RAID: case TARGET_UNIT_TARGET_PARTY: case TARGET_UNIT_TARGET_MINIPET: - if (IsValidSingleTargetSpell(target)) - AddUnitTarget(target, i, false); + AddUnitTarget(target, i, false); break; case TARGET_UNIT_TARGET_PASSENGER: - if (target->IsOnVehicle(m_caster)) - AddUnitTarget(target, i, false); + AddUnitTarget(target, i, false); break; case TARGET_UNIT_LASTTARGET_AREA_PARTY: case TARGET_UNIT_TARGET_AREA_RAID_CLASS: @@ -4166,13 +4172,7 @@ void Spell::SendChannelUpdate(uint32 time) void Spell::SendChannelStart(uint32 duration) { - uint64 channelTarget = 0; - if (m_targets.GetUnitTargetGUID()) - channelTarget = m_targets.GetUnitTargetGUID(); - else if (m_targets.GetGOTargetGUID()) - channelTarget = m_targets.GetGOTargetGUID(); - else if (m_targets.GetCorpseTargetGUID()) - channelTarget = m_targets.GetCorpseTargetGUID(); + uint64 channelTarget = m_targets.GetObjectTargetGUID(); WorldPacket data(MSG_CHANNEL_START, (8+4+4)); data.append(m_caster->GetPackGUID()); @@ -4708,6 +4708,12 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_DONT_REPORT; } + { + SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_caster, m_targets.GetObjectTarget()); + if (castResult != SPELL_CAST_OK) + return castResult; + } + if (Unit* target = m_targets.GetUnitTarget()) { SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, false); @@ -5447,15 +5453,6 @@ SpellCastResult Spell::CheckPetCast(Unit* target) } } - Unit* _target = m_targets.GetUnitTarget(); - - // for target dead/target not valid - if (_target) - { - if (!IsValidSingleTargetSpell(_target)) - return SPELL_FAILED_BAD_TARGETS; - } - // cooldown if (Creature const* creatureCaster = m_caster->ToCreature()) if (creatureCaster->HasSpellCooldown(m_spellInfo->Id)) @@ -6564,45 +6561,6 @@ bool SpellEvent::IsDeletable() const return m_Spell->IsDeletable(); } -bool Spell::IsValidSingleTargetEffect(Unit const* target, Targets type) const -{ - switch (type) - { - case TARGET_UNIT_TARGET_ENEMY: - return !m_caster->IsFriendlyTo(target); - case TARGET_UNIT_TARGET_ALLY: - case TARGET_UNIT_LASTTARGET_AREA_PARTY: - return m_caster->IsFriendlyTo(target); - case TARGET_UNIT_TARGET_PARTY: - return m_caster != target && m_caster->IsInPartyWith(target); - case TARGET_UNIT_TARGET_RAID: - return m_caster->IsInRaidWith(target); - case TARGET_UNIT_TARGET_MINIPET: - return target->GetGUID() == m_caster->GetCritterGUID(); - default: - break; - } - return true; -} - -bool Spell::IsValidSingleTargetSpell(Unit const* target) const -{ - if (target->GetMapId() == MAPID_INVALID) - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::IsValidSingleTargetSpell - a spell was cast on '%s' (GUIDLow: %u), but they have an invalid map id!", target->GetName(), target->GetGUIDLow()); - return false; - } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (!IsValidSingleTargetEffect(target, m_spellInfo->Effects[i].TargetA.GetTarget())) - return false; - // Need to check B? - //if (!IsValidSingleTargetEffect(m_spellInfo->Effects[i].TargetB, target) - // return false; - } - return true; -} - bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const { if (target->isAlive()) |
