/src/server/game/Spells/Spell.cpp
C++ | 7453 lines | 5814 code | 1007 blank | 632 comment | 2218 complexity | d9e7a50b5eb0c9922b1987c566c7600b MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "Common.h"
- #include "DatabaseEnv.h"
- #include "WorldPacket.h"
- #include "WorldSession.h"
- #include "GridNotifiers.h"
- #include "GridNotifiersImpl.h"
- #include "Opcodes.h"
- #include "Log.h"
- #include "UpdateMask.h"
- #include "World.h"
- #include "ObjectMgr.h"
- #include "SpellMgr.h"
- #include "Player.h"
- #include "Pet.h"
- #include "Unit.h"
- #include "Totem.h"
- #include "Spell.h"
- #include "DynamicObject.h"
- #include "Guild.h"
- #include "Group.h"
- #include "UpdateData.h"
- #include "MapManager.h"
- #include "ObjectAccessor.h"
- #include "CellImpl.h"
- #include "SharedDefines.h"
- #include "LootMgr.h"
- #include "VMapFactory.h"
- #include "Battleground.h"
- #include "Util.h"
- #include "TemporarySummon.h"
- #include "Vehicle.h"
- #include "SpellAuraEffects.h"
- #include "ScriptMgr.h"
- #include "ConditionMgr.h"
- #include "DisableMgr.h"
- #include "SpellScript.h"
- #include "InstanceScript.h"
- #include "SpellInfo.h"
- #include "DB2Stores.h"
- #include "Battlefield.h"
- #include "BattlefieldMgr.h"
- extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
- SpellDestination::SpellDestination()
- {
- _position.Relocate(0, 0, 0, 0);
- _transportGUID.Clear();
- _transportOffset.Relocate(0, 0, 0, 0);
- }
- SpellDestination::SpellDestination(float x, float y, float z, float orientation, uint32 mapId)
- {
- _position.Relocate(x, y, z, orientation);
- _transportGUID.Clear();
- _position.m_mapId = mapId;
- _transportOffset.Relocate(0, 0, 0, 0);
- }
- SpellDestination::SpellDestination(Position const& pos)
- {
- _position.Relocate(pos);
- _transportGUID.Clear();
- _transportOffset.Relocate(0, 0, 0, 0);
- }
- SpellDestination::SpellDestination(WorldObject const& wObj)
- {
- _transportGUID = wObj.GetTransGUID();
- _transportOffset.Relocate(wObj.GetTransOffsetX(), wObj.GetTransOffsetY(), wObj.GetTransOffsetZ(), wObj.GetTransOffsetO());
- _position.Relocate(wObj);
- }
- void SpellDestination::Relocate(Position const& pos)
- {
- if (_transportGUID)
- {
- Position offset;
- _position.GetPositionOffsetTo(pos, offset);
- _transportOffset.RelocateOffset(offset);
- }
- _position.Relocate(pos);
- }
- void SpellDestination::RelocateOffset(Position const& offset)
- {
- if (_transportGUID)
- _transportOffset.RelocateOffset(offset);
- _position.RelocateOffset(offset);
- }
- SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0), m_strTarget()
- {
- m_objectTarget = NULL;
- m_itemTarget = NULL;
- m_itemTargetEntry = 0;
- m_targetMask = 0;
- }
- SpellCastTargets::~SpellCastTargets() { }
- void SpellCastTargets::Read(ByteBuffer& data, Unit* caster)
- {
- data >> m_targetMask;
- if (m_targetMask == TARGET_FLAG_NONE)
- return;
- if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_UNIT_MINIPET | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_CORPSE_ALLY))
- data >> m_objectTargetGUID.ReadAsPacked();
- if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
- data >> m_itemTargetGUID.ReadAsPacked();
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- {
- data >> m_src._transportGUID.ReadAsPacked();
- if (m_src._transportGUID)
- data >> m_src._transportOffset.PositionXYZStream();
- else
- data >> m_src._position.PositionXYZStream();
- }
- else
- {
- m_src._transportGUID = caster->GetTransGUID();
- if (m_src._transportGUID)
- m_src._transportOffset.Relocate(caster->GetTransOffsetX(), caster->GetTransOffsetY(), caster->GetTransOffsetZ(), caster->GetTransOffsetO());
- else
- m_src._position.Relocate(caster);
- }
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- data >> m_dst._transportGUID.ReadAsPacked();
- if (m_dst._transportGUID)
- data >> m_dst._transportOffset.PositionXYZStream();
- else
- data >> m_dst._position.PositionXYZStream();
- }
- else
- {
- m_dst._transportGUID = caster->GetTransGUID();
- if (m_dst._transportGUID)
- m_dst._transportOffset.Relocate(caster->GetTransOffsetX(), caster->GetTransOffsetY(), caster->GetTransOffsetZ(), caster->GetTransOffsetO());
- else
- m_dst._position.Relocate(caster);
- }
- if (m_targetMask & TARGET_FLAG_STRING)
- data >> m_strTarget;
- Update(caster);
- }
- 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))
- data << m_objectTargetGUID.WriteAsPacked();
- if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM))
- {
- if (m_itemTarget)
- data << m_itemTarget->GetPackGUID();
- else
- data << uint8(0);
- }
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- {
- data << m_src._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (m_src._transportGUID)
- data << m_src._transportOffset.PositionXYZStream();
- else
- data << m_src._position.PositionXYZStream();
- }
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- {
- data << m_dst._transportGUID.WriteAsPacked(); // relative position guid here - transport for example
- if (m_dst._transportGUID)
- data << m_dst._transportOffset.PositionXYZStream();
- else
- data << m_dst._position.PositionXYZStream();
- }
- if (m_targetMask & TARGET_FLAG_STRING)
- data << m_strTarget;
- }
- ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const
- {
- switch (m_origObjectTargetGUID.GetHigh())
- {
- case HIGHGUID_PLAYER:
- case HIGHGUID_VEHICLE:
- case HIGHGUID_UNIT:
- case HIGHGUID_PET:
- return m_origObjectTargetGUID;
- default:
- return ObjectGuid();
- }
- }
- void SpellCastTargets::SetOrigUnitTarget(Unit* target)
- {
- if (!target)
- return;
- m_origObjectTargetGUID = target->GetGUID();
- }
- ObjectGuid SpellCastTargets::GetUnitTargetGUID() const
- {
- if (m_objectTargetGUID.IsUnit())
- return m_objectTargetGUID;
- return ObjectGuid::Empty;
- }
- Unit* SpellCastTargets::GetUnitTarget() const
- {
- if (m_objectTarget)
- return m_objectTarget->ToUnit();
- return NULL;
- }
- void SpellCastTargets::SetUnitTarget(Unit* target)
- {
- if (!target)
- return;
- m_objectTarget = target;
- m_objectTargetGUID = target->GetGUID();
- m_targetMask |= TARGET_FLAG_UNIT;
- }
- ObjectGuid SpellCastTargets::GetGOTargetGUID() const
- {
- if (m_objectTargetGUID.IsAnyTypeGameObject())
- return m_objectTargetGUID;
- return ObjectGuid::Empty;
- }
- GameObject* SpellCastTargets::GetGOTarget() const
- {
- if (m_objectTarget)
- return m_objectTarget->ToGameObject();
- return NULL;
- }
- void SpellCastTargets::SetGOTarget(GameObject* target)
- {
- if (!target)
- return;
- m_objectTarget = target;
- m_objectTargetGUID = target->GetGUID();
- m_targetMask |= TARGET_FLAG_GAMEOBJECT;
- }
- ObjectGuid SpellCastTargets::GetCorpseTargetGUID() const
- {
- if (m_objectTargetGUID.IsCorpse())
- return m_objectTargetGUID;
- return ObjectGuid::Empty;
- }
- Corpse* SpellCastTargets::GetCorpseTarget() const
- {
- if (m_objectTarget)
- return m_objectTarget->ToCorpse();
- return NULL;
- }
- WorldObject* SpellCastTargets::GetObjectTarget() const
- {
- return m_objectTarget;
- }
- ObjectGuid SpellCastTargets::GetObjectTargetGUID() const
- {
- return m_objectTargetGUID;
- }
- void SpellCastTargets::RemoveObjectTarget()
- {
- m_objectTarget = NULL;
- m_objectTargetGUID.Clear();
- m_targetMask &= ~(TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK);
- }
- void SpellCastTargets::SetItemTarget(Item* item)
- {
- if (!item)
- return;
- m_itemTarget = item;
- m_itemTargetGUID = item->GetGUID();
- m_itemTargetEntry = item->GetEntry();
- m_targetMask |= TARGET_FLAG_ITEM;
- }
- void SpellCastTargets::SetTradeItemTarget(Player* caster)
- {
- m_itemTargetGUID.Set(uint64(TRADE_SLOT_NONTRADED));
- m_itemTargetEntry = 0;
- m_targetMask |= TARGET_FLAG_TRADE_ITEM;
- Update(caster);
- }
- void SpellCastTargets::UpdateTradeSlotItem()
- {
- if (m_itemTarget && (m_targetMask & TARGET_FLAG_TRADE_ITEM))
- {
- m_itemTargetGUID = m_itemTarget->GetGUID();
- m_itemTargetEntry = m_itemTarget->GetEntry();
- }
- }
- SpellDestination const* SpellCastTargets::GetSrc() const
- {
- return &m_src;
- }
- Position const* SpellCastTargets::GetSrcPos() const
- {
- return &m_src._position;
- }
- void SpellCastTargets::SetSrc(float x, float y, float z)
- {
- m_src = SpellDestination(x, y, z);
- m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
- }
- void SpellCastTargets::SetSrc(Position const& pos)
- {
- m_src = SpellDestination(pos);
- m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
- }
- void SpellCastTargets::SetSrc(WorldObject const& wObj)
- {
- m_src = SpellDestination(wObj);
- m_targetMask |= TARGET_FLAG_SOURCE_LOCATION;
- }
- void SpellCastTargets::ModSrc(Position const& pos)
- {
- ASSERT(m_targetMask & TARGET_FLAG_SOURCE_LOCATION);
- m_src.Relocate(pos);
- }
- void SpellCastTargets::RemoveSrc()
- {
- m_targetMask &= ~(TARGET_FLAG_SOURCE_LOCATION);
- }
- SpellDestination const* SpellCastTargets::GetDst() const
- {
- return &m_dst;
- }
- WorldLocation const* SpellCastTargets::GetDstPos() const
- {
- return &m_dst._position;
- }
- void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
- {
- m_dst = SpellDestination(x, y, z, orientation, mapId);
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
- }
- void SpellCastTargets::SetDst(Position const& pos)
- {
- m_dst = SpellDestination(pos);
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
- }
- void SpellCastTargets::SetDst(WorldObject const& wObj)
- {
- m_dst = SpellDestination(wObj);
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
- }
- void SpellCastTargets::SetDst(SpellDestination const& spellDest)
- {
- m_dst = spellDest;
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
- }
- void SpellCastTargets::SetDst(SpellCastTargets const& spellTargets)
- {
- m_dst = spellTargets.m_dst;
- m_targetMask |= TARGET_FLAG_DEST_LOCATION;
- }
- void SpellCastTargets::ModDst(Position const& pos)
- {
- ASSERT(m_targetMask & TARGET_FLAG_DEST_LOCATION);
- m_dst.Relocate(pos);
- }
- void SpellCastTargets::ModDst(SpellDestination const& spellDest)
- {
- ASSERT(m_targetMask & TARGET_FLAG_DEST_LOCATION);
- m_dst = spellDest;
- }
- void SpellCastTargets::RemoveDst()
- {
- m_targetMask &= ~(TARGET_FLAG_DEST_LOCATION);
- }
- void SpellCastTargets::Update(Unit* caster)
- {
- m_objectTarget = m_objectTargetGUID ? ((m_objectTargetGUID == caster->GetGUID()) ? caster : ObjectAccessor::GetWorldObject(*caster, m_objectTargetGUID)) : NULL;
- m_itemTarget = NULL;
- if (caster->GetTypeId() == TYPEID_PLAYER)
- {
- Player* player = caster->ToPlayer();
- if (m_targetMask & TARGET_FLAG_ITEM)
- m_itemTarget = player->GetItemByGuid(m_itemTargetGUID);
- else if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
- if (m_itemTargetGUID.GetRawValue() == TRADE_SLOT_NONTRADED) // here it is not guid but slot. Also prevents hacking slots
- if (TradeData* pTrade = player->GetTradeData())
- m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
- if (m_itemTarget)
- m_itemTargetEntry = m_itemTarget->GetEntry();
- }
- // update positions by transport move
- if (HasSrc() && m_src._transportGUID)
- {
- if (WorldObject* transport = ObjectAccessor::GetWorldObject(*caster, m_src._transportGUID))
- {
- m_src._position.Relocate(transport);
- m_src._position.RelocateOffset(m_src._transportOffset);
- }
- }
- if (HasDst() && m_dst._transportGUID)
- {
- if (WorldObject* transport = ObjectAccessor::GetWorldObject(*caster, m_dst._transportGUID))
- {
- m_dst._position.Relocate(transport);
- m_dst._position.RelocateOffset(m_dst._transportOffset);
- }
- }
- }
- void SpellCastTargets::OutDebug() const
- {
- if (!m_targetMask)
- TC_LOG_INFO("spells", "No targets");
- TC_LOG_INFO("spells", "target mask: %u", m_targetMask);
- if (m_targetMask & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
- TC_LOG_INFO("spells", "Object target: %s", m_objectTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_ITEM)
- TC_LOG_INFO("spells", "Item target: %s", m_itemTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_TRADE_ITEM)
- TC_LOG_INFO("spells", "Trade item target: %s", m_itemTargetGUID.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION)
- TC_LOG_INFO("spells", "Source location: transport guid:%s trans offset: %s position: %s", m_src._transportGUID.ToString().c_str(), m_src._transportOffset.ToString().c_str(), m_src._position.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_DEST_LOCATION)
- TC_LOG_INFO("spells", "Destination location: transport guid:%s trans offset: %s position: %s", m_dst._transportGUID.ToString().c_str(), m_dst._transportOffset.ToString().c_str(), m_dst._position.ToString().c_str());
- if (m_targetMask & TARGET_FLAG_STRING)
- TC_LOG_INFO("spells", "String: %s", m_strTarget.c_str());
- TC_LOG_INFO("spells", "speed: %f", m_speed);
- TC_LOG_INFO("spells", "elevation: %f", m_elevation);
- }
- SpellValue::SpellValue(SpellInfo const* proto)
- {
- for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- EffectBasePoints[i] = proto->Effects[i].BasePoints;
- MaxAffectedTargets = proto->MaxAffectedTargets;
- RadiusMod = 1.0f;
- AuraStackAmount = 1;
- }
- Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) :
- m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
- m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
- , m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster))
- {
- m_customError = SPELL_CUSTOM_ERROR_NONE;
- m_skipCheck = skipCheck;
- m_selfContainer = NULL;
- m_referencedFromCurrentSpell = false;
- m_executedCurrently = false;
- m_needComboPoints = m_spellInfo->NeedsComboPoints();
- m_comboPointGain = 0;
- m_delayStart = 0;
- m_delayAtDamageCount = 0;
- m_applyMultiplierMask = 0;
- m_auraScaleMask = 0;
- memset(m_damageMultipliers, 0, sizeof(m_damageMultipliers));
- // Get data for type of attack
- switch (m_spellInfo->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_MELEE:
- if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_REQ_OFFHAND)
- m_attackType = OFF_ATTACK;
- else
- m_attackType = BASE_ATTACK;
- break;
- case SPELL_DAMAGE_CLASS_RANGED:
- m_attackType = m_spellInfo->IsRangedWeaponSpell() ? RANGED_ATTACK : BASE_ATTACK;
- break;
- default:
- // Wands
- if (m_spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)
- m_attackType = RANGED_ATTACK;
- else
- m_attackType = BASE_ATTACK;
- break;
- }
- m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
- if (m_attackType == RANGED_ATTACK)
- // wand case
- if ((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId() == TYPEID_PLAYER)
- if (Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK))
- m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->DamageType);
- if (originalCasterGUID)
- m_originalCasterGUID = originalCasterGUID;
- else
- m_originalCasterGUID = m_caster->GetGUID();
- if (m_originalCasterGUID == m_caster->GetGUID())
- m_originalCaster = m_caster;
- else
- {
- m_originalCaster = ObjectAccessor::GetUnit(*m_caster, m_originalCasterGUID);
- if (m_originalCaster && !m_originalCaster->IsInWorld())
- m_originalCaster = NULL;
- }
- m_spellState = SPELL_STATE_NULL;
- _triggeredCastFlags = triggerFlags;
- if (info->AttributesEx4 & SPELL_ATTR4_TRIGGERED)
- _triggeredCastFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT);
- m_CastItem = NULL;
- m_castItemGUID.Clear();
- m_castItemEntry = 0;
- unitTarget = NULL;
- itemTarget = NULL;
- gameObjTarget = NULL;
- destTarget = NULL;
- damage = 0;
- effectHandleMode = SPELL_EFFECT_HANDLE_LAUNCH;
- m_diminishLevel = DIMINISHING_LEVEL_1;
- m_diminishGroup = DIMINISHING_NONE;
- m_damage = 0;
- m_healing = 0;
- m_procAttacker = 0;
- m_procVictim = 0;
- m_procEx = 0;
- focusObject = NULL;
- m_cast_count = 0;
- m_glyphIndex = 0;
- m_preCastSpell = 0;
- m_triggeredByAuraSpell = NULL;
- m_spellAura = NULL;
- //Auto Shot & Shoot (wand)
- m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell();
- m_runesState = 0;
- m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before.
- m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
- m_timer = 0; // will set to castime in prepare
- m_channeledDuration = 0; // will be setup in Spell::handle_immediate
- m_immediateHandled = false;
- m_channelTargetEffectMask = 0;
- // Determine if spell can be reflected back to the caster
- // Patch 1.2 notes: Spell Reflection no longer reflects abilities
- m_canReflect = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !(m_spellInfo->Attributes & SPELL_ATTR0_ABILITY)
- && !(m_spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REFLECTED) && !(m_spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
- && !m_spellInfo->IsPassive() && !m_spellInfo->IsPositive();
- CleanupTargetList();
- memset(m_effectExecuteData, 0, MAX_SPELL_EFFECTS * sizeof(ByteBuffer*));
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- m_destTargets[i] = SpellDestination(*m_caster);
- }
- Spell::~Spell()
- {
- // unload scripts
- while (!m_loadedScripts.empty())
- {
- std::list<SpellScript*>::iterator itr = m_loadedScripts.begin();
- (*itr)->_Unload();
- delete (*itr);
- m_loadedScripts.erase(itr);
- }
- if (m_referencedFromCurrentSpell && m_selfContainer && *m_selfContainer == this)
- {
- // Clean the reference to avoid later crash.
- // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
- TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID %u. However, spell still referenced.", m_spellInfo->Id);
- *m_selfContainer = NULL;
- }
- if (m_caster && m_caster->GetTypeId() == TYPEID_PLAYER)
- ASSERT(m_caster->ToPlayer()->m_spellModTakingSpell != this);
- delete m_spellValue;
- CheckEffectExecuteData();
- }
- void Spell::InitExplicitTargets(SpellCastTargets const& targets)
- {
- m_targets = targets;
- m_targets.SetOrigUnitTarget(m_targets.GetUnitTarget());
- // this function tries to correct spell explicit targets for spell
- // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
- // this also makes sure that we correctly send explicit targets to client (removes redundant data)
- uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
- if (WorldObject* target = m_targets.GetObjectTarget())
- {
- // 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* unit = 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->GetTarget()))
- if (m_spellInfo->CheckExplicitTarget(m_caster, selectedUnit) == SPELL_CAST_OK)
- unit = selectedUnit;
- }
- // try to use attacked unit as a target
- else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
- unit = m_caster->GetVictim();
- // didn't find anything - let's use self as target
- if (!unit && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY))
- unit = m_caster;
- m_targets.SetUnitTarget(unit);
- }
- }
- // check if spell needs dst target
- if (neededTargets & TARGET_FLAG_DEST_LOCATION)
- {
- // and target isn't set
- if (!m_targets.HasDst())
- {
- // try to use unit target if provided
- if (WorldObject* target = targets.GetObjectTarget())
- m_targets.SetDst(*target);
- // or use self if not available
- else
- m_targets.SetDst(*m_caster);
- }
- }
- else
- m_targets.RemoveDst();
- if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
- {
- if (!targets.HasSrc())
- m_targets.SetSrc(*m_caster);
- }
- else
- m_targets.RemoveSrc();
- }
- void Spell::SelectExplicitTargets()
- {
- // here go all explicit target changes made to explicit targets after spell prepare phase is finished
- if (Unit* target = m_targets.GetUnitTarget())
- {
- // check for explicit target redirection, for Grounding Totem for example
- if (m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT_ENEMY
- || (m_spellInfo->GetExplicitTargetMask() & TARGET_FLAG_UNIT && !m_spellInfo->IsPositive()))
- {
- Unit* redirect;
- switch (m_spellInfo->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_MAGIC:
- redirect = m_caster->GetMagicHitRedirectTarget(target, m_spellInfo);
- break;
- case SPELL_DAMAGE_CLASS_MELEE:
- case SPELL_DAMAGE_CLASS_RANGED:
- redirect = m_caster->GetMeleeHitRedirectTarget(target, m_spellInfo);
- break;
- default:
- redirect = NULL;
- break;
- }
- if (redirect && (redirect != target))
- m_targets.SetUnitTarget(redirect);
- }
- }
- }
- void Spell::SelectSpellTargets()
- {
- // select targets for cast phase
- SelectExplicitTargets();
- uint32 processedAreaEffectsMask = 0;
- for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- // not call for empty effect.
- // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
- if (!m_spellInfo->Effects[i].IsEffect())
- continue;
- // set expected type of implicit targets to be sent to client
- uint32 implicitTargetMask = GetTargetFlagMask(m_spellInfo->Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(m_spellInfo->Effects[i].TargetB.GetObjectType());
- if (implicitTargetMask & TARGET_FLAG_UNIT)
- m_targets.SetTargetFlag(TARGET_FLAG_UNIT);
- if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
- m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT);
- SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetA, processedAreaEffectsMask);
- SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetB, processedAreaEffectsMask);
- // Select targets of effect based on effect type
- // those are used when no valid target could be added for spell effect based on spell target type
- // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
- // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
- // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
- SelectEffectTypeImplicitTargets(i);
- if (m_targets.HasDst())
- AddDestTarget(*m_targets.GetDst(), i);
- if (m_spellInfo->IsChanneled())
- {
- uint8 mask = (1 << i);
- for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
- {
- if (ihit->effectMask & mask)
- {
- m_channelTargetEffectMask |= mask;
- break;
- }
- }
- }
- else if (m_auraScaleMask)
- {
- bool checkLvl = !m_UniqueTargetInfo.empty();
- for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();)
- {
- // remove targets which did not pass min level check
- if (m_auraScaleMask && ihit->effectMask == m_auraScaleMask)
- {
- // Do not check for selfcast
- if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID())
- {
- m_UniqueTargetInfo.erase(ihit++);
- continue;
- }
- }
- ++ihit;
- }
- if (checkLvl && m_UniqueTargetInfo.empty())
- {
- SendCastResult(SPELL_FAILED_LOWLEVEL);
- finish(false);
- }
- }
- }
- if (m_targets.HasDst())
- {
- if (m_targets.HasTraj())
- {
- float speed = m_targets.GetSpeedXY();
- if (speed > 0.0f)
- m_delayMoment = uint64(std::floor(m_targets.GetDist2d() / speed * 1000.0f));
- }
- else if (m_spellInfo->Speed > 0.0f)
- {
- float dist = m_caster->GetDistance(*m_targets.GetDstPos());
- if (!(m_spellInfo->AttributesEx9 & SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
- m_delayMoment = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
- else
- m_delayMoment = uint64(m_spellInfo->Speed * 1000.0f);
- }
- }
- }
- void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask)
- {
- if (!targetType.GetTarget())
- return;
- uint32 effectMask = 1 << effIndex;
- // set the same target list for all effects
- // some spells appear to need this, however this requires more research
- switch (targetType.GetSelectionCategory())
- {
- case TARGET_SELECT_CATEGORY_NEARBY:
- case TARGET_SELECT_CATEGORY_CONE:
- case TARGET_SELECT_CATEGORY_AREA:
- // targets for effect already selected
- if (effectMask & processedEffectMask)
- return;
- // choose which targets we can select at once
- for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j)
- {
- SpellEffectInfo const* effects = GetSpellInfo()->Effects;
- if (effects[j].IsEffect() &&
- effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
- effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
- effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
- effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) &&
- CheckScriptEffectImplicitTargets(effIndex, j))
- {
- effectMask |= 1 << j;
- }
- }
- processedEffectMask |= effectMask;
- break;
- default:
- break;
- }
- switch (targetType.GetSelectionCategory())
- {
- case TARGET_SELECT_CATEGORY_CHANNEL:
- SelectImplicitChannelTargets(effIndex, targetType);
- break;
- case TARGET_SELECT_CATEGORY_NEARBY:
- SelectImplicitNearbyTargets(effIndex, targetType, effectMask);
- break;
- case TARGET_SELECT_CATEGORY_CONE:
- SelectImplicitConeTargets(effIndex, targetType, effectMask);
- break;
- case TARGET_SELECT_CATEGORY_AREA:
- SelectImplicitAreaTargets(effIndex, targetType, effectMask);
- break;
- case TARGET_SELECT_CATEGORY_DEFAULT:
- switch (targetType.GetObjectType())
- {
- case TARGET_OBJECT_TYPE_SRC:
- switch (targetType.GetReferenceType())
- {
- case TARGET_REFERENCE_TYPE_CASTER:
- m_targets.SetSrc(*m_caster);
- break;
- default:
- ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
- break;
- }
- break;
- case TARGET_OBJECT_TYPE_DEST:
- switch (targetType.GetReferenceType())
- {
- case TARGET_REFERENCE_TYPE_CASTER:
- SelectImplicitCasterDestTargets(effIndex, targetType);
- break;
- case TARGET_REFERENCE_TYPE_TARGET:
- SelectImplicitTargetDestTargets(effIndex, targetType);
- break;
- case TARGET_REFERENCE_TYPE_DEST:
- SelectImplicitDestDestTargets(effIndex, targetType);
- break;
- default:
- ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
- break;
- }
- break;
- default:
- switch (targetType.GetReferenceType())
- {
- case TARGET_REFERENCE_TYPE_CASTER:
- SelectImplicitCasterObjectTargets(effIndex, targetType);
- break;
- case TARGET_REFERENCE_TYPE_TARGET:
- SelectImplicitTargetObjectTargets(effIndex, targetType);
- break;
- default:
- ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
- break;
- }
- break;
- }
- break;
- case TARGET_SELECT_CATEGORY_NYI:
- TC_LOG_DEBUG("spells", "SPELL: target type %u, found in spellID %u, effect %u is not implemented yet!", m_spellInfo->Id, effIndex, targetType.GetTarget());
- break;
- default:
- ASSERT(false && "Spell::SelectEffectImplicitTargets: received not implemented select target category");
- break;
- }
- }
- void Spell::SelectImplicitChannelTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
- {
- if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
- {
- ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target reference type");
- return;
- }
- Spell* channeledSpell = m_originalCaster->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
- if (!channeledSpell)
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
- return;
- }
- switch (targetType.GetTarget())
- {
- case TARGET_UNIT_CHANNEL_TARGET:
- {
- WorldObject* target = ObjectAccessor::GetUnit(*m_caster, m_originalCaster->GetChannelObjectGuid());
- CallScriptObjectTargetSelectHandlers(target, effIndex, targetType);
- // unit target may be no longer avalible - teleported out of map for example
- if (target && target->ToUnit())
- AddUnitTarget(target->ToUnit(), 1 << effIndex);
- else
- TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
- break;
- }
- case TARGET_DEST_CHANNEL_TARGET:
- if (channeledSpell->m_targets.HasDst())
- m_targets.SetDst(channeledSpell->m_targets);
- else if (WorldObject* target = ObjectAccessor::GetWorldObject(*m_caster, m_originalCaster->GetChannelObjectGuid()))
- {
- CallScriptObjectTargetSelectHandlers(target, effIndex, targetType);
- if (target)
- m_targets.SetDst(*target);
- }
- else
- TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
- break;
- case TARGET_DEST_CHANNEL_CASTER:
- m_targets.SetDst(*channeledSpell->GetCaster());
- break;
- default:
- ASSERT(false && "Spell::SelectImplicitChannelTargets: received not implemented target type");
- break;
- }
- }
- void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
- {
- if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
- {
- ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
- return;
- }
- float range = 0.0f;
- switch (targetType.GetCheckType())
- {
- case TARGET_CHECK_ENEMY:
- range = m_spellInfo->GetMaxRange(false, m_caster, this);
- break;
- case TARGET_CHECK_ALLY:
- case TARGET_CHECK_PARTY:
- case TARGET_CHECK_RAID:
- case TARGET_CHECK_RAID_CLASS:
- range = m_spellInfo->GetMaxRange(true, m_caster, this);
- break;
- case TARGET_CHECK_ENTRY:
- case TARGET_CHECK_DEFAULT:
- range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive(), m_caster, this);
- break;
- default:
- ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
- break;
- }
- ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
- // handle emergency case - try to use other provided targets if no conditions provided
- if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: no conditions entry for target with TARGET_CHECK_ENTRY of spell ID %u, effect %u - selecting default targets", m_spellInfo->Id, effIndex);
- switch (targetType.GetObjectType())
- {
- case TARGET_OBJECT_TYPE_GOBJ:
- if (m_spellInfo->RequiresSpellFocus)
- {
- if (focusObject)
- AddGOTarget(focusObject, effMask);
- return;
- }
- break;
- case TARGET_OBJECT_TYPE_DEST:
- if (m_spellInfo->RequiresSpellFocus)
- {
- if (focusObject)
- m_targets.SetDst(*focusObject);
- return;
- }
- break;
- default:
- break;
- }
- }
- WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
- if (!target)
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID %u, effect %u", m_spellInfo->Id, effIndex);
- return;
- }
- CallScriptObjectTargetSelectHandlers(target, effIndex, targetType);
- if (!target)
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id %u set NULL target, effect %u", m_spellInfo->Id, effIndex);
- return;
- }
- switch (targetType.GetObjectType())
- {
- case TARGET_OBJECT_TYPE_UNIT:
- {
- if (Unit* unitTarget = target->ToUnit())
- AddUnitTarget(unitTarget, effMask, true, false);
- else
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id %u set object of wrong type, expected unit, got %s, effect %u", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
- return;
- }
- break;
- }
- case TARGET_OBJECT_TYPE_GOBJ:
- if (GameObject* gobjTarget = target->ToGameObject())
- AddGOTarget(gobjTarget, effMask);
- else
- {
- TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id %u set object of wrong type, expected gameobject, got %s, effect %u", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
- return;
- }
- break;
- case TARGET_OBJECT_TYPE_DEST:
- m_targets.SetDst(*target);
- break;
- default:
- ASSERT(false && "Spell::SelectImplicitNearbyTargets: received not implemented target object type");
- break;
- }
- SelectImplicitChainTargets(effIndex, targetType, target, effMask);
- }
- void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
- {
- if (targetType.GetReferenceType() != TARGET_REFERENCE_TYPE_CASTER)
- {
- ASSERT(false && "Spell::SelectImplicitConeTargets: received not implemented target reference type");
- return;
- }
- std::list<WorldObject*> targets;
- SpellTargetObjectTypes objectType = targetType.GetObjectType();
- SpellTargetCheckTypes selectionType = targetType.GetCheckType();
- ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
- float coneAngle = float(M_PI) / 2;
- float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
- if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
- {
- Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);
- Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> searcher(m_caster, targets, check, containerTypeMask);
- SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius);
- CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType);
- if (!targets.empty())
- {
- // Other special target selection goes here
- if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
- Trinity::Containers::RandomResizeList(targets, maxTargets);
- for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
- {
- if (Unit* unitTarget = (*itr)->ToUnit())
- AddUnitTarget(unitTarget, effMask, false);
- else if (GameObject* gObjTarget = (*itr)->ToGameObject())
- AddGOTarget(gObjTarget, effMask);
- }
- }
- }
- }
- void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32 effMask)
- {
- Unit* referer = NULL;
- switch (targetType.GetReferenceType())
- {
- case TARGET_REFERENCE_TYPE_SRC:
- case TARGET_REFERENCE_TYPE_DEST:
- case TARGET_REFERENCE_TYPE_CASTER:
- referer = m_caster;
- break;
- case TARGET_REFERENCE_TYPE_TARGET:
- referer = m_targets.GetUnitTarget();
- break;
- case TARGET_REFERENCE_TYPE_LAST:
- {
- // find last added target for this effect
- for (std::list<TargetInfo>::reverse_iterator ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
- {
- if (ihit->effectMask & (1<<effIndex))
- {
- referer = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
- break;
- }
- }
- break;
- }
- default:
- ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type");
- return;
- }
- if (!referer)
- return;
- Position const* center = NULL;
- switch (targetType.GetReferenceType())
- {
- case TARGET_REFERENCE_TYPE_SRC:
- center = m_targets.GetSrcPos();
- break;
- case TARGET_REFERENCE_TYPE_DEST:
- center = m_targets.GetDstPos();
- break;
- case TARGET_REFERENCE_TYPE_CASTER:
- case TARGET_REFERENCE_TYPE_TARGET:
- case TARGET_REFERENCE_TYPE_LAST:
- center = referer;
- break;
- default:
- ASSERT(false && "Spell::SelectImplicitAreaTargets: received not implemented target reference type");
- return;
- }
- std::list<WorldObject*> targets;
- float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
- SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions);
- CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType);
- if (!targets.empty())
- {
- // Other special target selection goes here
- if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
- Trinity::Containers::RandomResizeList(targets, maxTargets);
- for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
- {
- if (Unit* unitTarget = (*itr)->ToUnit())
- AddUnitTarget(unitTarget, effMask, false, true, center);
- else if (GameObject* gObjTarget = (*itr)->ToGameObject())
- AddGOTarget(gObjTarget, effMask);
- }
- }
- }
- void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
- {
- SpellDestination dest(*m_caster);
- switch (targetType.GetTarget())
- {
- case TARGET_DEST_CASTER:
- break;
- case TARGET_DEST_HOME:
- if (Player* playerCaster = m_caster->ToPlayer())
- dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
- break;
- case TARGET_DEST_DB:
- if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex))
- {
- /// @todo fix this check
- if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND))
- dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
- else if (st->target_mapId == m_caster->GetMapId())
- dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
- }
- else
- {
- TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id);
- if (WorldObject* target = m_targets.GetObjectTarget())
- dest = SpellDestination(*target);
- }
- break;
- case TARGET_DEST_CASTER_FISHING:
- {
- float minDist = m_spellInfo->GetMinRange(true);
- float maxDist = m_spellInfo->GetMaxRange(true);
- float dist = frand(minDist, maxDist);
- float x, y, z;
- float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle);
- float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z, true, 50.0f);
- float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
- LiquidData liquidData;
- if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData))
- liquidLevel = liquidData.level;
- if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
- {
- SendCastResult(SPELL_FAILED_NOT_HERE);
- SendChannelUpdate(0);
- finish(false);
- return;
- }
- if (ground + 0.75 > liquidLevel)
- {
- SendCastResult(SPELL_FAILED_TOO_SHALLOW);
- SendChannelUpdate(0);
- finish(false);
- return;
- }
- dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
- break;
- }
- default:
- {
- float dist;
- float angle = targetType.CalcDirectionAngle();
- float objSize = m_caster->GetObjectSize();
- if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON)
- dist = PET_FOLLOW_DIST;
- else
- dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
- if (dist < objSize)
- dist = objSize;
- else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM)
- dist = objSize + (dist - objSize) * float(rand_norm());
- Position pos = dest._position;
- m_caster->MovePositionToFirstCollision(pos, dist, angle);
- dest.Relocate(pos);
- break;
- }
- }
- CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType);
- m_targets.SetDst(dest);
- }
- void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
- {
- ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
- WorldObject* target = m_targets.GetObjectTarget();
- SpellDestination dest(*target);
- switch (targetType.GetTarget())
- {
- case TARGET_DEST_TARGET_ENEMY:
- case TARGET_DEST_TARGET_ANY:
- break;
- default:
- {
- float angle = targetType.CalcDirectionAngle();
- float objSize = target->GetObjectSize();
- float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
- if (dist < objSize)
- dist = objSize;
- else if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM)
- dist = objSize + (dist - objSize) * float(rand_norm());
- Position pos = dest._position;
- target->MovePositionToFirstCollision(pos, dist, angle);
- dest.Relocate(pos);
- break;
- }
- }
- CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType);
- m_targets.SetDst(dest);
- }
- void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
- {
- // set destination to caster if no dest provided
- // can only happen if previous destination target could not be set for some reason
- // (not found nearby target, or channel target for example
- // maybe we should abort the spell in such case?
- CheckDst();
- SpellDestination dest(*m_targets.GetDst());
- switch (targetType.GetTarget())
- {
- case TARGET_DEST_DYNOBJ_ENEMY:
- case TARGET_DEST_DYNOBJ_ALLY:
- case TARGET_DEST_DYNOBJ_NONE:
- case TARGET_DEST_DEST:
- return;
- case TARGET_DEST_TRAJ:
- SelectImplicitTrajTargets(effIndex);
- return;
- default:
- {
- float angle = targetType.CalcDirectionAngle();
- float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
- if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM)
- dist *= float(rand_norm());
- Position pos = dest._position;
- m_ca…
Large files files are truncated, but you can click here to view the full file