/src/server/game/Entities/Unit/Unit.cpp
C++ | 12650 lines | 9953 code | 1410 blank | 1287 comment | 3557 complexity | 7ec1cff59d0e2ad064991a504da14235 MD5 | raw file
- /*
- * Copyright (C) 2008-2012 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.
- */
- #include "Common.h"
- #include "CreatureAIImpl.h"
- #include "Log.h"
- #include "Opcodes.h"
- #include "WorldPacket.h"
- #include "WorldSession.h"
- #include "World.h"
- #include "ObjectMgr.h"
- #include "SpellMgr.h"
- #include "Unit.h"
- #include "QuestDef.h"
- #include "Player.h"
- #include "Creature.h"
- #include "Spell.h"
- #include "Group.h"
- #include "SpellAuras.h"
- #include "SpellAuraEffects.h"
- #include "MapManager.h"
- #include "ObjectAccessor.h"
- #include "CreatureAI.h"
- #include "Formulas.h"
- #include "Pet.h"
- #include "Util.h"
- #include "Totem.h"
- #include "Battleground.h"
- #include "OutdoorPvP.h"
- #include "InstanceSaveMgr.h"
- #include "GridNotifiersImpl.h"
- #include "CellImpl.h"
- #include "CreatureGroups.h"
- #include "PetAI.h"
- #include "PassiveAI.h"
- #include "TemporarySummon.h"
- #include "Vehicle.h"
- #include "Transport.h"
- #include "InstanceScript.h"
- #include "MoveSplineInit.h"
- #include "MoveSpline.h"
- #include "PathFinder.h"
- #include <math.h>
- float baseMoveSpeed[MAX_MOVE_TYPE] =
- {
- 2.5f, // MOVE_WALK
- 7.0f, // MOVE_RUN
- 4.5f, // MOVE_RUN_BACK
- 4.722222f, // MOVE_SWIM
- 2.5f, // MOVE_SWIM_BACK
- 3.141594f, // MOVE_TURN_RATE
- 7.0f, // MOVE_FLIGHT
- 4.5f, // MOVE_FLIGHT_BACK
- 3.14f // MOVE_PITCH_RATE
- };
- float playerBaseMoveSpeed[MAX_MOVE_TYPE] = {
- 2.5f, // MOVE_WALK
- 7.0f, // MOVE_RUN
- 4.5f, // MOVE_RUN_BACK
- 4.722222f, // MOVE_SWIM
- 2.5f, // MOVE_SWIM_BACK
- 3.141594f, // MOVE_TURN_RATE
- 7.0f, // MOVE_FLIGHT
- 4.5f, // MOVE_FLIGHT_BACK
- 3.14f // MOVE_PITCH_RATE
- };
- // Used for prepare can/can`t triggr aura
- static bool InitTriggerAuraData();
- // Define can trigger auras
- static bool isTriggerAura[TOTAL_AURAS];
- // Define can`t trigger auras (need for disable second trigger)
- static bool isNonTriggerAura[TOTAL_AURAS];
- // Triggered always, even from triggered spells
- static bool isAlwaysTriggeredAura[TOTAL_AURAS];
- // Prepare lists
- static bool procPrepared = InitTriggerAuraData();
- DamageInfo::DamageInfo(Unit* _attacker, Unit* _victim, uint32 _damage, SpellEntry const* _spellInfo, SpellSchoolMask _schoolMask, DamageEffectType _damageType)
- : m_attacker(_attacker), m_victim(_victim), m_damage(_damage), m_spellInfo(_spellInfo), m_schoolMask(_schoolMask),
- m_damageType(_damageType), m_attackType(BASE_ATTACK)
- {
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
- }
- DamageInfo::DamageInfo(CalcDamageInfo& dmgInfo)
- : m_attacker(dmgInfo.attacker), m_victim(dmgInfo.target), m_damage(dmgInfo.damage), m_spellInfo(NULL), m_schoolMask(SpellSchoolMask(dmgInfo.damageSchoolMask)),
- m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.attackType)
- {
- m_absorb = 0;
- m_resist = 0;
- m_block = 0;
- }
- void DamageInfo::ModifyDamage(int32 amount)
- {
- amount = std::min(amount, int32(GetDamage()));
- m_damage += amount;
- }
- void DamageInfo::AbsorbDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_absorb += amount;
- m_damage -= amount;
- }
- void DamageInfo::ResistDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_resist += amount;
- m_damage -= amount;
- }
- void DamageInfo::BlockDamage(uint32 amount)
- {
- amount = std::min(amount, GetDamage());
- m_block += amount;
- m_damage -= amount;
- }
- static uint32 SpellFamilyNameByClass[] = {4, 10, 9, 8, 6, 15, 11, 3, 5, 18, 7};
- ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
- :_actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
- _hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo) { }
- // we can disable this warning for this since it only
- // causes undefined behavior when passed to the base class constructor
- #ifdef _MSC_VER
- #pragma warning(disable:4355)
- #endif
- Unit::Unit(bool isWorldObject): WorldObject(isWorldObject),
- m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false),
- m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0),
- m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL),
- m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline())
- {
- #ifdef _MSC_VER
- #pragma warning(default:4355)
- #endif
- m_objectType |= TYPEMASK_UNIT;
- m_objectTypeId = TYPEID_UNIT;
- m_updateFlag = (UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION);
- m_attackTimer[BASE_ATTACK] = 0;
- m_attackTimer[OFF_ATTACK] = 0;
- m_attackTimer[RANGED_ATTACK] = 0;
- m_modAttackSpeedPct[BASE_ATTACK] = 1.0f;
- m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
- m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
- m_extraAttacks = 0;
- m_canDualWield = false;
- m_rootTimes = 0;
- m_state = 0;
- m_deathState = ALIVE;
- for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
- m_currentSpells[i] = NULL;
- m_addDmgOnce = 0;
- for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- m_SummonSlot[i] = 0;
- m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
- m_auraUpdateIterator = m_ownedAuras.end();
- m_interruptMask = 0;
- m_transform = 0;
- m_canModifyStats = false;
- for(uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
- m_spellImmune[i].clear();
- for(uint8 i = 0; i < UNIT_MOD_END; ++i)
- {
- m_auraModifiersGroup[i][BASE_VALUE] = 0.0f;
- m_auraModifiersGroup[i][BASE_PCT] = 1.0f;
- m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
- m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
- }
- // implement 50% base damage from offhand
- m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
- for(uint8 i = 0; i < MAX_ATTACK; ++i)
- {
- m_weaponDamage[i][MINDAMAGE] = BASE_MINDAMAGE;
- m_weaponDamage[i][MAXDAMAGE] = BASE_MAXDAMAGE;
- }
- for(uint8 i = 0; i < MAX_STATS; ++i)
- m_createStats[i] = 0.0f;
- m_attacking = NULL;
- m_modMeleeHitChance = 0.0f;
- m_modRangedHitChance = 0.0f;
- m_modSpellHitChance = 0.0f;
- m_baseSpellCritChance = 5;
- m_CombatTimer = 0;
- m_lastManaUse = 0;
- for(uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
- m_threatModifier[i] = 1.0f;
- m_isSorted = true;
- for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
- m_speed_rate[i] = 1.0f;
- m_charmInfo = NULL;
- m_reducedThreatPercent = 0;
- m_misdirectionTargetGUID = 0;
- // remove aurastates allowing special moves
- for(uint8 i = 0; i < MAX_REACTIVE; ++i)
- m_reactiveTimer[i] = 0;
- m_cleanupDone = false;
- m_duringRemoveFromWorld = false;
- m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
- _focusSpell = NULL;
- _targetLocked = false;
- m_lastLiquid = NULL;
- }
- bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const
- {
- GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory);
- return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration;
- }
- void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd)
- {
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime());
- }
- void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo)
- {
- m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0;
- }
- Unit::~Unit()
- {
- // set current spells as deletable
- for(uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
- {
- if(m_currentSpells[i])
- {
- m_currentSpells[i]->SetReferencedFromCurrent(false);
- m_currentSpells[i] = NULL;
- }
- }
- _DeleteRemovedAuras();
- // remove veiw point for spectator
- if (!m_sharedVision.empty())
- {
- for (SharedVisionList::iterator itr = m_sharedVision.begin(); itr != m_sharedVision.end(); ++itr)
- if ((*itr)->isSpectator() && (*itr)->getSpectateFrom())
- {
- (*itr)->SetViewpoint((*itr)->getSpectateFrom(), false);
- if (m_sharedVision.empty())
- break;
- --itr;
- }
- }
- delete m_charmInfo;
- delete m_vehicleKit;
- delete movespline;
- ASSERT(!m_duringRemoveFromWorld);
- ASSERT(!m_attacking);
- ASSERT(m_attackers.empty());
- ASSERT(m_sharedVision.empty());
- ASSERT(m_Controlled.empty());
- ASSERT(m_appliedAuras.empty());
- ASSERT(m_ownedAuras.empty());
- ASSERT(m_removedAuras.empty());
- ASSERT(m_gameObj.empty());
- ASSERT(m_dynObj.empty());
- }
- void Unit::Update(uint32 p_time)
- {
- m_Events.Update(p_time);
- if(!IsInWorld())
- return;
- _UpdateSpells(p_time);
- // If this is set during update SetCantProc(false) call is missing somewhere in the code
- // Having this would prevent spells from being proced, so let's crash
- ASSERT(!m_procDeep);
- if(CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))
- SendThreatListUpdate();
- // update combat timer only for players and pets (only pets with PetAI)
- if(isInCombat() && (GetTypeId() == TYPEID_PLAYER || (ToCreature()->isPet() && IsControlledByPlayer())))
- {
- // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
- // targets without stopping half way there and running off.
- // These flags are reset after target dies or another command is given.
- if(m_HostileRefManager.isEmpty())
- {
- // m_CombatTimer set at aura start and it will be freeze until aura removing
- if(m_CombatTimer <= p_time)
- ClearInCombat();
- else
- m_CombatTimer -= p_time;
- }
- }
- // not implemented before 3.0.2
- //if(!HasUnitState(UNIT_STAT_CASTING))
- {
- if(uint32 base_att = getAttackTimer(BASE_ATTACK))
- setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
- if(uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
- setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
- if(uint32 off_att = getAttackTimer(OFF_ATTACK))
- setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
- }
- // update abilities available only for fraction of time
- UpdateReactives(p_time);
- if(isAlive())
- {
- ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, HealthBelowPct(20));
- ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, HealthBelowPct(35));
- ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
- }
- UpdateSplineMovement(p_time);
- i_motionMaster.UpdateMotion(p_time);
- }
- bool Unit::haveOffhandWeapon() const
- {
- if(GetTypeId() == TYPEID_PLAYER)
- return ToPlayer()->GetWeaponForAttack(OFF_ATTACK, true);
- else
- return m_canDualWield;
- }
- void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
- {
- Movement::MoveSplineInit init(*this);
- init.MoveTo(x, y, z, generatePath, forceDestination);
- init.SetVelocity(speed);
- init.Launch();
- }
- void Unit::UpdateSplineMovement(uint32 t_diff)
- {
- if(movespline->Finalized())
- return;
- movespline->updateState(t_diff);
- bool arrived = movespline->Finalized();
- if(arrived)
- DisableSpline();
- m_movesplineTimer.Update(t_diff);
- if(m_movesplineTimer.Passed() || arrived)
- {
- m_movesplineTimer.Reset(400 /*POSITION_UPDATE_DELAY*/);
- Movement::Location loc = movespline->ComputePosition();
- if(GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->SetPosition(loc.x,loc.y,loc.z,loc.orientation);
- else
- GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation);
- }
- }
- void Unit::DisableSpline()
- {
- m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD));
- movespline->_Interrupt();
- }
- void Unit::SendMonsterMoveExitVehicle(Position const* newPos)
- {
- WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size());
- data.append(GetPackGUID());
- data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // new in 3.1, bool
- data << GetPositionX() << GetPositionY() << GetPositionZ();
- data << getMSTime();
- data << uint8(SPLINETYPE_FACING_ANGLE);
- data << float(GetOrientation()); // guess
- data << uint32(SPLINEFLAG_EXIT_VEHICLE);
- data << uint32(0); // Time in between points
- data << uint32(1); // 1 single waypoint
- data << newPos->GetPositionX();
- data << newPos->GetPositionY();
- data << newPos->GetPositionZ();
- SendMessageToSet(&data, true);
- }
- void Unit::SendMonsterMoveTransport(Unit* vehicleOwner)
- {
- // TODO: Turn into BuildMonsterMoveTransport packet and allow certain variables (for npc movement aboard vehicles)
- WorldPacket data(SMSG_MONSTER_MOVE_TRANSPORT, GetPackGUID().size()+vehicleOwner->GetPackGUID().size() + 47);
- data.append(GetPackGUID());
- data.append(vehicleOwner->GetPackGUID());
- data << int8(GetTransSeat());
- data << uint8(GetTypeId() == TYPEID_PLAYER ? 1 : 0); // boolean
- data << GetPositionX() - vehicleOwner->GetPositionX();
- data << GetPositionY() - vehicleOwner->GetPositionY();
- data << GetPositionZ() - vehicleOwner->GetPositionZ();
- data << uint32(getMSTime()); // should be an increasing constant that indicates movement packet count
- data << uint8(SPLINETYPE_FACING_ANGLE);
- data << GetTransOffsetO(); // facing angle?
- data << uint32(SPLINEFLAG_TRANSPORT);
- data << uint32(GetTransTime()); // move time
- data << uint32(1); // amount of waypoints
- data << uint32(0); // waypoint X
- data << uint32(0); // waypoint Y
- data << uint32(0); // waypoint Z
- SendMessageToSet(&data, true);
- }
- void Unit::resetAttackTimer(WeaponAttackType type)
- {
- m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
- }
- bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const
- {
- if(!obj || !IsInMap(obj)) return false;
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float distsq = dx*dx + dy*dy + dz*dz;
- float sizefactor = GetCombatReach() + obj->GetCombatReach();
- float maxdist = dist2compare + sizefactor;
- return distsq < maxdist * maxdist;
- }
- bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const
- {
- if(!obj || !IsInMap(obj)) return false;
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float distsq = dx*dx + dy*dy + dz*dz;
- float sizefactor = GetMeleeReach() + obj->GetMeleeReach();
- float maxdist = dist + sizefactor;
- return distsq < maxdist * maxdist;
- }
- void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const
- {
- float combat_reach = GetCombatReach();
- if(combat_reach < 0.1f) // sometimes bugged for players
- combat_reach = DEFAULT_COMBAT_REACH;
- uint32 attacker_number = getAttackers().size();
- if(attacker_number > 0)
- --attacker_number;
- GetNearPoint(obj, x, y, z, obj->GetCombatReach(), distance2dMin+(distance2dMax-distance2dMin) * (float)rand_norm()
- , GetAngle(obj) + (attacker_number ? (static_cast<float>(M_PI/2) - static_cast<float>(M_PI) * (float)rand_norm()) * float(attacker_number) / combat_reach * 0.3f : 0));
- }
- void Unit::SetVisibleAura(uint8 slot, AuraApplication * aur)
- {
- if (Aura* aura = aur->GetBase())
- if (Player *player = ToPlayer())
- if (player->HaveSpectators() && slot < MAX_AURAS)
- {
- SpectatorAddonMsg msg;
- uint64 casterID = 0;
- if (aura->GetCaster())
- casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
- msg.SetPlayer(player->GetName());
- msg.CreateAura(casterID, aura->GetSpellProto()->Id,
- aur->IsPositive(), aura->GetSpellProto()->Dispel,
- aura->GetDuration(), aura->GetMaxDuration(),
- aura->GetStackAmount(), false);
- player->SendSpectatorAddonMsgToBG(msg);
- }
- m_visibleAuras[slot] = aur;
- UpdateAuraForGroup(slot);
- }
- void Unit::RemoveVisibleAura(uint8 slot)
- {
- AuraApplication *aurApp = GetVisibleAura(slot);
- if (aurApp && slot < MAX_AURAS)
- {
- if (Aura* aura = aurApp->GetBase())
- if (Player *player = ToPlayer())
- if (player->HaveSpectators())
- {
- SpectatorAddonMsg msg;
- uint64 casterID = 0;
- if (aura->GetCaster())
- casterID = (aura->GetCaster()->ToPlayer()) ? aura->GetCaster()->GetGUID() : 0;
- msg.SetPlayer(player->GetName());
- msg.CreateAura(casterID, aura->GetSpellProto()->Id,
- aurApp->IsPositive(), aura->GetSpellProto()->Dispel,
- aura->GetDuration(), aura->GetMaxDuration(),
- aura->GetStackAmount(), true);
- player->SendSpectatorAddonMsgToBG(msg);
- }
- }
- m_visibleAuras.erase(slot);
- UpdateAuraForGroup(slot);
- }
- void Unit::UpdateInterruptMask()
- {
- m_interruptMask = 0;
- for(AuraApplicationList::const_iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
- m_interruptMask |= (*i)->GetBase()->GetSpellProto()->AuraInterruptFlags;
- if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if(spell->getState() == SPELL_STATE_CASTING)
- m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
- }
- bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint32 familyFlags) const
- {
- if(!HasAuraType(auraType))
- return false;
- AuraEffectList const& auras = GetAuraEffectsByType(auraType);
- for(AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if(SpellEntry const* iterSpellProto = (*itr)->GetSpellProto())
- if(iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags[0] & familyFlags)
- return true;
- return false;
- }
- void Unit::DealDamageMods(Unit* victim, uint32 &damage, uint32* absorb)
- {
- if(!victim || !victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
- {
- if(absorb)
- *absorb += damage;
- damage = 0;
- return;
- }
- uint32 originalDamage = damage;
- if(absorb && originalDamage > damage)
- *absorb += (originalDamage - damage);
- }
- uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* pCleanDMG, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const* pSpell, bool durabilityLoss)
- {
- if(!pVictim)
- return 0;
- if(pVictim->IsAIEnabled)
- pVictim->GetAI()->DamageTaken(this, damage);
- if(IsAIEnabled)
- GetAI()->DamageDealt(pVictim, damage, damagetype);
- if(damage >= pVictim->GetHealth() && this->GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->UpdateKillingTimedAchievementProgress(pVictim->GetEntry(),pVictim->GetTypeId());
- if(damagetype != NODAMAGE)
- {
- // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
- if(pSpell)
- {
- if(!(pSpell->AttributesEx4 & SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, pSpell->Id);
- } else pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0);
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vCopyDamageCopy(pVictim->GetAuraEffectsByType(SPELL_AURA_SHARE_DAMAGE_PCT));
- // copy damage to casters of this aura
- for(AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if(!((*i)->GetBase()->IsAppliedOnTarget(pVictim->GetGUID())))
- continue;
- // check damage school mask
- if(((*i)->GetMiscValue() & damageSchoolMask) == 0)
- continue;
- Unit* shareDamageTarget = (*i)->GetCaster();
- if(!shareDamageTarget)
- continue;
- SpellEntry const* spell = (*i)->GetSpellProto();
- uint32 share = CalculatePctN(damage, (*i)->GetAmount());
- // TODO: check packets if damage is done by pVictim, or by attacker of pVictim
- DealDamageMods(shareDamageTarget, share, NULL);
- DealDamage(shareDamageTarget, share, NULL, NODAMAGE, GetSpellSchoolMask(spell), spell, false);
- }
- }
- // Rage from Damage made (only from direct weapon damage)
- if(pCleanDMG && damagetype == DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE)
- {
- uint32 weaponSpeedHitFactor;
- uint32 rage_damage = damage + pCleanDMG->absorbed_damage;
- switch(pCleanDMG->attackType)
- {
- case BASE_ATTACK:
- {
- weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 3.5f);
- if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
- weaponSpeedHitFactor *= 2;
- RewardRage(rage_damage, weaponSpeedHitFactor, true);
- break;
- }
- case OFF_ATTACK:
- {
- weaponSpeedHitFactor = uint32(GetAttackTime(pCleanDMG->attackType) / 1000.0f * 1.75f);
- if(pCleanDMG->hitOutCome == MELEE_HIT_CRIT)
- weaponSpeedHitFactor *= 2;
- RewardRage(rage_damage, weaponSpeedHitFactor, true);
- break;
- }
- default:
- break;
- }
- }
- if(!damage)
- {
- // Rage from absorbed damage
- if(pCleanDMG && pCleanDMG->absorbed_damage && pVictim->getPowerType() == POWER_RAGE)
- pVictim->RewardRage(pCleanDMG->absorbed_damage, 0, false);
- return 0;
- }
- uint32 health = pVictim->GetHealth();
- // duel ends when player has 1 or less hp
- bool duel_hasEnded = false;
- bool duel_wasMounted = false;
- if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->ToPlayer()->duel && damage >= (health-1))
- {
- // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if(pVictim->ToPlayer()->duel->opponent == this || pVictim->ToPlayer()->duel->opponent->GetGUID() == GetOwnerGUID())
- damage = health - 1;
- duel_hasEnded = true;
- } else if(pVictim->IsVehicle() && damage >= (health-1) && pVictim->GetCharmer() && pVictim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) {
- Player* pPlayer = pVictim->GetCharmer()->ToPlayer();
- if(pPlayer && pPlayer->duel && pPlayer->duel->isMounted)
- {
- // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
- if(pPlayer->duel->opponent == this || pPlayer->duel->opponent->GetGUID() == GetCharmerGUID())
- damage = health - 1;
- duel_wasMounted = true;
- duel_hasEnded = true;
- }
- }
- if(GetTypeId() == TYPEID_PLAYER && this != pVictim)
- {
- Player* pKiller = ToPlayer();
- // in bg, count dmg if pVictim is also a player
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- if(Battleground* pBG = pKiller->GetBattleground())
- pBG->UpdatePlayerScore(pKiller, SCORE_DAMAGE_DONE, damage);
- pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, damage, 0, pVictim);
- pKiller->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
- }
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED, damage);
- else if(!pVictim->IsControlledByPlayer() || pVictim->IsVehicle()) {
- if(!pVictim->ToCreature()->hasLootRecipient())
- pVictim->ToCreature()->SetLootRecipient(this);
- if(IsControlledByPlayer())
- pVictim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
- }
- if(health <= damage)
- {
- if(pVictim->GetTypeId() == TYPEID_PLAYER && pVictim != this)
- {
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, health);
- // call before auras are removed
- if(Player* pPlayer = GetCharmerOrOwnerPlayerOrPlayerItself())
- pPlayer->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, pVictim);
- }
- // Heirloom trinkets on "kill a target that yields experience or honor" effect
- if(this->ToPlayer() && this->isAlive()) {
- if(this->ToPlayer()->isHonorOrXPTarget(pVictim)) {
- AuraEffectList const& heirloom = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator j = heirloom.begin(); j != heirloom.end(); ++j)
- {
- if((*j)->GetId() == 59915 && this->getPowerType() == POWER_MANA)
- this->CastSpell(this, 59914, true);
- if((*j)->GetId() == 59906)
- {
- int32 bonushealth = this->GetMaxHealth() * this->GetAura(59906)->GetEffect(0)->GetAmount() / 100;
- this->CastCustomSpell(this, 59913, &bonushealth, 0, 0, true);
- }
- }
- }
- }
- Kill(pVictim, durabilityLoss);
- } else {
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- pVictim->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED, damage);
- pVictim->ModifyHealth(- (int32)damage);
- if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, pSpell ? pSpell->Id : 0);
- if(pVictim->GetTypeId() != TYPEID_PLAYER)
- pVictim->AddThreat(this, (float)damage, damageSchoolMask, pSpell);
- else { // pVictim is a player
- // random durability for items (HIT TAKEN)
- if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) {
- EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
- pVictim->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
- }
- }
- // Rage from damage received
- if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
- {
- uint32 rage_damage = damage + (pCleanDMG ? pCleanDMG->absorbed_damage : 0);
- pVictim->RewardRage(rage_damage, 0, false);
- }
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // random durability for items (HIT DONE)
- if(roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
- {
- EquipmentSlots slot = EquipmentSlots(urand(0, EQUIPMENT_SLOT_END-1));
- ToPlayer()->DurabilityPointLossForEquipSlot(slot);
- }
- }
- if(damagetype != NODAMAGE && damage)
- {
- if(pVictim != this && pVictim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
- {
- if(damagetype != DOT)
- {
- if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_GENERIC_SPELL])
- {
- if(pSpell->getState() == SPELL_STATE_PREPARING)
- {
- uint32 interruptFlags = pSpell->m_spellInfo->InterruptFlags;
- if(interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
- pVictim->InterruptNonMeleeSpells(false);
- else if(interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
- pSpell->Delayed();
- }
- }
- }
- if(Spell* pSpell = pVictim->m_currentSpells[CURRENT_CHANNELED_SPELL])
- {
- if(pSpell->getState() == SPELL_STATE_CASTING)
- {
- uint32 channelInterruptFlags = pSpell->m_spellInfo->ChannelInterruptFlags;
- if(((channelInterruptFlags & CHANNEL_FLAG_DELAY) != 0) && (damagetype != DOT))
- pSpell->DelayedChannel();
- }
- }
- }
- }
- // last damage from duel opponent
- if(duel_hasEnded)
- {
- Player* pPlayer;
- duel_wasMounted ? pPlayer = pVictim->GetCharmer()->ToPlayer() : pPlayer = pVictim->ToPlayer();
- if(!pPlayer->isAlive())
- pPlayer->ResurrectPlayer(1.0f);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
- pPlayer->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
- pPlayer->SetHealth(1);
- pPlayer->duel->opponent->CombatStopWithPets(true);
- pPlayer->CombatStopWithPets(true);
- pPlayer->CastSpell(pPlayer, 7267, true);
- pPlayer->DuelComplete(DUEL_WON);
- }
- }
- return damage;
- }
- void Unit::CastStop(uint32 except_spellid)
- {
- for(uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
- if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
- InterruptSpell(CurrentSpellTypes(i), false);
- }
- void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
- if(!spellInfo)
- {
- sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastSpell(Unit* Victim, SpellEntry const* spellInfo, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- if(!spellInfo)
- {
- sLog->outError("CastSpell: unknown spell by caster: %s %u)", (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(!originalCaster && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem() && IsControlledByPlayer())
- if(Unit* owner = GetOwner())
- originalCaster=owner->GetGUID();
- SpellCastTargets targets;
- targets.SetUnitTarget(Victim);
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", spellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, spellInfo, triggered, originalCaster);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- void Unit::CastCustomSpell(Unit* target, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- CustomSpellValues values;
- if(bp0)
- values.AddSpellMod(SPELLVALUE_BASE_POINT0, *bp0);
- if(bp1)
- values.AddSpellMod(SPELLVALUE_BASE_POINT1, *bp1);
- if(bp2)
- values.AddSpellMod(SPELLVALUE_BASE_POINT2, *bp2);
- CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* target, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- CustomSpellValues values;
- values.AddSpellMod(mod, value);
- CastCustomSpell(spellId, values, target, triggered, castItem, triggeredByAura, originalCaster);
- }
- void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const& value, Unit* Victim, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell: unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- SpellCastTargets targets;
- targets.SetUnitTarget(Victim);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- if(castItem)
- {
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- pSpell->m_CastItem = castItem;
- }
- for(CustomSpellValues::const_iterator itr = value.begin(); itr != value.end(); ++itr)
- pSpell->SetSpellValue(itr->first, itr->second);
- pSpell->prepare(&targets, triggeredByAura);
- }
- // used for scripting
- void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item* castItem, AuraEffect const* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- SpellCastTargets targets;
- targets.SetDst(x, y, z, GetOrientation());
- if(OriginalVictim)
- targets.SetUnitTarget(OriginalVictim);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- void Unit::CastSpell(GameObject* pGO, uint32 spellId, bool triggered, Item* castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
- {
- if(!pGO)
- return;
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellId);
- if(!pSpellInfo)
- {
- sLog->outError("CastSpell(x, y, z): unknown spell id %i by caster: %s %u)", spellId, (GetTypeId() == TYPEID_PLAYER ? "player (GUID:" : "creature (Entry:"), (GetTypeId() == TYPEID_PLAYER ? GetGUIDLow() : GetEntry()));
- return;
- }
- if(castItem)
- sLog->outDebug(DebugLogFilters(LOG_FILTER_SPELLS_AURAS | LOG_FILTER_PLAYER_ITEMS), "WORLD: cast Item spellId - %i", pSpellInfo->Id);
- if(!originalCaster && triggeredByAura)
- originalCaster = triggeredByAura->GetCasterGUID();
- Spell* pSpell = new Spell(this, pSpellInfo, triggered, originalCaster);
- SpellCastTargets targets;
- targets.SetGOTarget(pGO);
- pSpell->m_CastItem = castItem;
- pSpell->prepare(&targets, triggeredByAura);
- }
- // Obsolete func need remove, here only for comotability vs another patches
- uint32 Unit::SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage)
- {
- SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(spellID);
- SpellNonMeleeDamage damageInfo(this, victim, pSpellInfo->Id, pSpellInfo->SchoolMask);
- damage = SpellDamageBonus(victim, pSpellInfo, damage, SPELL_DIRECT_DAMAGE);
- CalculateSpellDamageTaken(&damageInfo, damage, pSpellInfo);
- DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
- return damageInfo.damage;
- }
- void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const* spellInfo, WeaponAttackType attackType, bool crit)
- {
- if(damage < 0)
- return;
- Unit* victim = damageInfo->target;
- if(!victim || !victim->isAlive())
- return;
- SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
- uint32 crTypeMask = victim->GetCreatureTypeMask();
- if(IsDamageReducedByArmor(damageSchoolMask, spellInfo))
- damage = CalcArmorReducedDamage(victim, damage, spellInfo, attackType);
- bool blocked = false;
- // Per-school calc
- switch(spellInfo->DmgClass)
- {
- // Melee and Ranged Spells
- case SPELL_DAMAGE_CLASS_RANGED:
- case SPELL_DAMAGE_CLASS_MELEE:
- {
- // Physical Damage
- if(damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)
- {
- // Get blocked status
- blocked = isSpellBlocked(victim, spellInfo, attackType);
- }
- if(crit)
- {
- damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
- // Calculate crit bonus
- uint32 crit_bonus = damage;
- // Apply crit_damage bonus for melee spells
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
- damage += crit_bonus;
- // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
- float critPctDamageMod = 0.0f;
- if(attackType == RANGED_ATTACK)
- critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
- else
- critPctDamageMod += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
- // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
- critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellInfo)) - 1.0f) * 100;
- // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
- critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
- if(critPctDamageMod != 0)
- AddPctF(damage, critPctDamageMod);
- }
- // Spell weapon based damage CAN BE crit & blocked at same time
- if(blocked)
- {
- damageInfo->blocked = victim->GetShieldBlockValue();
- // double blocked amount if block is critical
- if(victim->isBlockCritical())
- damageInfo->blocked += damageInfo->blocked;
- if(damage < int32(damageInfo->blocked))
- damageInfo->blocked = uint32(damage);
- damage -= damageInfo->blocked;
- }
- if(attackType != RANGED_ATTACK)
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_MELEE);
- else
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_RANGED);
- break;
- }
- // Magical Attacks
- case SPELL_DAMAGE_CLASS_NONE:
- case SPELL_DAMAGE_CLASS_MAGIC:
- {
- // If crit add critical bonus
- if(crit)
- {
- damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
- damage = SpellCriticalDamageBonus(spellInfo, damage, victim);
- }
- ApplyResilience(victim, NULL, &damage, crit, CR_CRIT_TAKEN_SPELL);
- break;
- }
- default:
- break;
- }
- // Calculate absorb resist
- if(damage > 0)
- {
- CalcAbsorbResist(victim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist, spellInfo);
- damage -= damageInfo->absorb + damageInfo->resist;
- }
- else
- damage = 0;
- damageInfo->damage = damage;
- }
- void Unit::DealSpellDamage(SpellNonMeleeDamage* pDamageInfo, bool durabilityLoss)
- {
- if(pDamageInfo == 0)
- return;
- Unit* victim = pDamageInfo->target;
- if(!victim)
- return;
- if(!victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->HasUnitState(UNIT_STAT_ONVEHICLE) && victim->GetVehicleBase() != this) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
- return;
- SpellEntry const* pSpellEntry = sSpellStore.LookupEntry(pDamageInfo->SpellID);
- if(pSpellEntry == NULL)
- {
- sLog->outDebug(LOG_FILTER_UNITS, "Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", pDamageInfo->SpellID);
- return;
- }
- // Call default DealDamage
- CleanDamage cleanDamage(pDamageInfo->cleanDamage, pDamageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(victim, pDamageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(pDamageInfo->schoolMask), pSpellEntry, durabilityLoss);
- }
- // TODO for melee need create structure as in
- void Unit::CalculateMeleeDamage(Unit* pVictim, uint32 damage, CalcDamageInfo* pDamageInfo, WeaponAttackType attackType)
- {
- pDamageInfo->attacker = this;
- pDamageInfo->target = pVictim;
- pDamageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
- pDamageInfo->attackType = attackType;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- pDamageInfo->absorb = 0;
- pDamageInfo->resist = 0;
- pDamageInfo->blocked_amount = 0;
- pDamageInfo->TargetState = 0;
- pDamageInfo->HitInfo = 0;
- pDamageInfo->procAttacker = PROC_FLAG_NONE;
- pDamageInfo->procVictim = PROC_FLAG_NONE;
- pDamageInfo->procEx = PROC_EX_NONE;
- pDamageInfo->hitOutCome = MELEE_HIT_EVADE;
- if(!pVictim)
- return;
- if(!isAlive() || !pVictim->isAlive())
- return;
- // Select HitInfo/procAttacker/procVictim flag based on attack type
- switch(attackType)
- {
- case BASE_ATTACK:
- {
- pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_MAINHAND_ATTACK;
- pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
- pDamageInfo->HitInfo = HITINFO_NORMALSWING2;
- break;
- }
- case OFF_ATTACK:
- {
- pDamageInfo->procAttacker = PROC_FLAG_DONE_MELEE_AUTO_ATTACK | PROC_FLAG_DONE_OFFHAND_ATTACK;
- pDamageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK;
- pDamageInfo->HitInfo = HITINFO_LEFTSWING;
- break;
- }
- default:
- return;
- }
- // Physical Immune check
- if(pDamageInfo->target->IsImmunedToDamage(SpellSchoolMask(pDamageInfo->damageSchoolMask)))
- {
- pDamageInfo->HitInfo |= HITINFO_NORMALSWING;
- pDamageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
- pDamageInfo->procEx |= PROC_EX_IMMUNE;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- return;
- }
- damage += CalculateDamage(pDamageInfo->attackType, false, true);
- // Add melee damage bonus
- MeleeDamageBonus(pDamageInfo->target, &damage, pDamageInfo->attackType);
- // Calculate armor reduction
- if(IsDamageReducedByArmor((SpellSchoolMask)(pDamageInfo->damageSchoolMask)))
- {
- pDamageInfo->damage = CalcArmorReducedDamage(pDamageInfo->target, damage, NULL, pDamageInfo->attackType);
- pDamageInfo->cleanDamage += damage - pDamageInfo->damage;
- } else pDamageInfo->damage = damage;
- pDamageInfo->hitOutCome = RollMeleeOutcomeAgainst(pDamageInfo->target, pDamageInfo->attackType);
- switch(pDamageInfo->hitOutCome)
- {
- case MELEE_HIT_EVADE:
- {
- pDamageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
- pDamageInfo->TargetState = VICTIMSTATE_EVADES;
- pDamageInfo->procEx|=PROC_EX_EVADE;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- return;
- }
- case MELEE_HIT_MISS:
- {
- pDamageInfo->HitInfo |= HITINFO_MISS;
- pDamageInfo->TargetState = VICTIMSTATE_INTACT;
- pDamageInfo->procEx |= PROC_EX_MISS;
- pDamageInfo->damage = 0;
- pDamageInfo->cleanDamage = 0;
- break;
- }
- case MELEE_HIT_NORMAL:
- {
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx|=PROC_EX_NORMAL_HIT;
- break;
- }
- case MELEE_HIT_CRIT:
- {
- pDamageInfo->HitInfo |= HITINFO_CRITICALHIT;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_CRITICAL_HIT;
- // Crit bonus calc
- pDamageInfo->damage += pDamageInfo->damage;
- float mod = 0.0f;
- // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
- if(pDamageInfo->attackType == RANGED_ATTACK)
- mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
- else
- mod += pDamageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
- // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
- mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, pDamageInfo->damageSchoolMask) - 1.0f) * 100;
- uint32 crTypeMask = pDamageInfo->target->GetCreatureTypeMask();
- // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
- mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
- if(mod != 0)
- AddPctF(pDamageInfo->damage, mod);
- break;
- }
- case MELEE_HIT_PARRY:
- {
- pDamageInfo->TargetState = VICTIMSTATE_PARRY;
- pDamageInfo->procEx |= PROC_EX_PARRY;
- pDamageInfo->cleanDamage += pDamageInfo->damage;
- pDamageInfo->damage = 0;
- break;
- }
- case MELEE_HIT_DODGE:
- {
- pDamageInfo->TargetState = VICTIMSTATE_DODGE;
- pDamageInfo->procEx |= PROC_EX_DODGE;
- pDamageInfo->cleanDamage += pDamageInfo->damage;
- pDamageInfo->damage = 0;
- break;
- }
- case MELEE_HIT_BLOCK:
- {
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->HitInfo |= HITINFO_BLOCK;
- pDamageInfo->procEx |= PROC_EX_BLOCK;
- pDamageInfo->blocked_amount = pDamageInfo->target->GetShieldBlockValue();
- if(pDamageInfo->target->isBlockCritical())
- pDamageInfo->blocked_amount+=pDamageInfo->blocked_amount;
- if(pDamageInfo->blocked_amount >= pDamageInfo->damage)
- {
- pDamageInfo->TargetState = VICTIMSTATE_BLOCKS;
- pDamageInfo->blocked_amount = pDamageInfo->damage;
- pDamageInfo->procEx |= PROC_EX_FULL_BLOCK;
- } else pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- pDamageInfo->damage -= pDamageInfo->blocked_amount;
- pDamageInfo->cleanDamage += pDamageInfo->blocked_amount;
- break;
- }
- case MELEE_HIT_GLANCING:
- {
- pDamageInfo->HitInfo |= HITINFO_GLANCING;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel());
- if(leveldif > 3)
- leveldif = 3;
- float reducePercent = 1 - leveldif * 0.1f;
- pDamageInfo->cleanDamage += pDamageInfo->damage-uint32(reducePercent * pDamageInfo->damage);
- pDamageInfo->damage = uint32(reducePercent * pDamageInfo->damage);
- break;
- }
- case MELEE_HIT_CRUSHING:
- {
- pDamageInfo->HitInfo |= HITINFO_CRUSHING;
- pDamageInfo->TargetState = VICTIMSTATE_HIT;
- pDamageInfo->procEx |= PROC_EX_NORMAL_HIT;
- // 150% normal damage
- pDamageInfo->damage += (pDamageInfo->damage / 2);
- break;
- }
- default:
- break;
- }
- int32 resilienceReduction = pDamageInfo->damage;
- if(attackType != RANGED_ATTACK)
- ApplyResilience(pVictim, NULL, &resilienceReduction, (pDamageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
- else
- ApplyResilience(pVictim, NULL, &resilienceReduction, (pDamageInfo->hitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_RANGED);
- resilienceReduction = pDamageInfo->damage - resilienceReduction;
- pDamageInfo->damage -= resilienceReduction;
- pDamageInfo->cleanDamage += resilienceReduction;
- // Calculate absorb resist
- if(int32(pDamageInfo->damage) > 0)
- {
- pDamageInfo->procVictim |= PROC_FLAG_TAKEN_DAMAGE;
- // Calculate absorb & resists
- CalcAbsorbResist(pDamageInfo->target, SpellSchoolMask(pDamageInfo->damageSchoolMask), DIRECT_DAMAGE, pDamageInfo->damage, &pDamageInfo->absorb, &pDamageInfo->resist);
- pDamageInfo->damage -= pDamageInfo->absorb + pDamageInfo->resist;
- if(pDamageInfo->absorb)
- {
- pDamageInfo->HitInfo |= HITINFO_ABSORB;
- pDamageInfo->procEx |= PROC_EX_ABSORB;
- }
- if(pDamageInfo->resist)
- pDamageInfo->HitInfo |= HITINFO_RESIST;
- }
- else // Impossible get negative result but....
- pDamageInfo->damage = 0;
- }
- void Unit::DealMeleeDamage(CalcDamageInfo* pDamageInfo, bool durabilityLoss)
- {
- Unit* victim = pDamageInfo->target;
- if(!victim->isAlive() || victim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (victim->HasUnitState(UNIT_STAT_ONVEHICLE) && victim->GetVehicleBase() != this) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode()))
- return;
- // Hmmmm dont like this emotes client must by self do all animations
- if(pDamageInfo->HitInfo & HITINFO_CRITICALHIT)
- victim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
- if(pDamageInfo->blocked_amount && pDamageInfo->TargetState != VICTIMSTATE_BLOCKS)
- victim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
- if(pDamageInfo->TargetState == VICTIMSTATE_PARRY)
- {
- // Get attack timers
- float offtime = float(victim->getAttackTimer(OFF_ATTACK));
- float basetime = float(victim->getAttackTimer(BASE_ATTACK));
- // Reduce attack time
- if(victim->haveOffhandWeapon() && offtime < basetime)
- {
- float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
- float percent60 = 3.0f * percent20;
- if(offtime > percent20 && offtime <= percent60)
- victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
- else if(offtime > percent60)
- {
- offtime -= 2.0f * percent20;
- victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
- }
- } else {
- float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20f;
- float percent60 = 3.0f * percent20;
- if(basetime > percent20 && basetime <= percent60)
- victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
- else if(basetime > percent60)
- {
- basetime -= 2.0f * percent20;
- victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
- }
- }
- }
- // Call default DealDamage
- CleanDamage cleanDamage(pDamageInfo->cleanDamage, pDamageInfo->absorb, pDamageInfo->attackType, pDamageInfo->hitOutCome);
- DealDamage(victim, pDamageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(pDamageInfo->damageSchoolMask), NULL, durabilityLoss);
- // If this is a creature and it attacks from behind it has a probability to daze it's victim
- if((pDamageInfo->hitOutCome == MELEE_HIT_CRIT || pDamageInfo->hitOutCome == MELEE_HIT_CRUSHING || pDamageInfo->hitOutCome == MELEE_HIT_NORMAL || pDamageInfo->hitOutCome == MELEE_HIT_GLANCING) &&
- GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(M_PI, this)
- && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss()))
- {
- // -probability is between 0% and 40%
- // 20% base chance
- float Probability = 20.0f;
- // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
- if(victim->getLevel() < 30)
- Probability = 0.65f * victim->getLevel() + 0.5f;
- uint32 VictimDefense = victim->GetDefenseSkillValue();
- uint32 AttackerMeleeSkill = GetUnitMeleeSkill();
- VictimDefense = VictimDefense > 1 ? VictimDefense : 1;
- Probability *= AttackerMeleeSkill/VictimDefense;
- if(Probability > 40.0f)
- Probability = 40.0f;
- if(roll_chance_f(Probability))
- CastSpell(victim, 1604, true);
- }
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->CastItemCombatSpell(victim, pDamageInfo->attackType, pDamageInfo->procVictim, pDamageInfo->procEx);
- // Do effect if any damage done to target
- if(pDamageInfo->damage)
- {
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vDamageShieldsCopy(victim->GetAuraEffectsByType(SPELL_AURA_DAMAGE_SHIELD));
- for(AuraEffectList::const_iterator dmgShieldItr = vDamageShieldsCopy.begin(); dmgShieldItr != vDamageShieldsCopy.end(); ++dmgShieldItr)
- {
- SpellEntry const* i_spellProto = (*dmgShieldItr)->GetSpellProto();
- // Damage shield can be resisted...
- if(SpellMissInfo missInfo = victim->SpellHitResult(this, i_spellProto, false))
- {
- victim->SendSpellMiss(this, i_spellProto->Id, missInfo);
- continue;
- }
- // ...or immuned
- if(IsImmunedToDamage(i_spellProto))
- {
- victim->SendSpellDamageImmune(this, i_spellProto->Id);
- continue;
- }
- uint32 damage = (*dmgShieldItr)->GetAmount();
- if(Unit* caster = (*dmgShieldItr)->GetCaster())
- damage = caster->SpellDamageBonus(this, i_spellProto, damage, SPELL_DIRECT_DAMAGE);
- // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
- victim->DealDamageMods(this, damage, NULL);
- // TODO: Move this to a packet handler
- WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8+8+4+4+4+4));
- data << uint64(victim->GetGUID());
- data << uint64(GetGUID());
- data << uint32(i_spellProto->Id);
- data << uint32(damage); // Damage
- int32 overkill = int32(damage) - int32(GetHealth());
- data << uint32(overkill > 0 ? overkill : 0); // Overkill
- data << uint32(i_spellProto->SchoolMask);
- victim->SendMessageToSet(&data, true);
- victim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(i_spellProto), i_spellProto, true);
- }
- }
- }
- void Unit::HandleEmoteCommand(uint32 anim_id)
- {
- WorldPacket data(SMSG_EMOTE, 4 + 8);
- data << uint32(anim_id);
- data << uint64(GetGUID());
- SendMessageToSet(&data, true);
- }
- bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellEntry const* spellInfo, uint8 effIndex)
- {
- // only physical spells damage gets reduced by armor
- if((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
- return false;
- if(spellInfo)
- {
- // there are spells with no specific attribute but they have "ignores armor" in tooltip
- if(sSpellMgr->GetSpellCustomAttr(spellInfo->Id) & SPELL_ATTR0_CU_IGNORE_ARMOR)
- return false;
- // bleeding effects are not reduced by armor
- if(effIndex != MAX_SPELL_EFFECTS && spellInfo->EffectApplyAuraName[effIndex] == SPELL_AURA_PERIODIC_DAMAGE)
- if(GetSpellMechanicMask(spellInfo, effIndex) & (1<<MECHANIC_BLEED))
- return false;
- }
- return true;
- }
- uint32 Unit::CalcArmorReducedDamage(Unit* victim, const uint32 damage, SpellEntry const* spellInfo, WeaponAttackType /*attackType*/)
- {
- uint32 newdamage = 0;
- float armor = float(victim->GetArmor());
- // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
- armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL);
- if(spellInfo)
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
- AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
- for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
- {
- if((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL
- && (*j)->IsAffectedOnSpell(spellInfo))
- armor = floor(AddPctN(armor, -(*j)->GetAmount()));
- }
- AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
- for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
- {
- if((*j)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
- armor = floor(AddPctN(armor, -(*j)->GetAmount()));
- }
- if(GetTypeId() == TYPEID_PLAYER)
- {
- float bonusPct = 0;
- AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT);
- for(AuraEffectList::const_iterator itr = ResIgnoreAuras.begin(); itr != ResIgnoreAuras.end(); ++itr)
- {
- // item neutral spell
- if((*itr)->GetSpellProto()->EquippedItemClass == -1)
- {
- /*
- armor = floor(AddPctN(armor, -(*itr)->GetAmount()));
- continue;
- */
- if (!spellInfo || (*itr)->IsAffectedOnSpell(spellInfo) || (*itr)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) //(*itr)->GetMiscValue() & GetSpellSchoolMask(spellInfo)
- bonusPct += (*itr)->GetAmount();
- else if (!(*itr)->GetMiscValue() && !(*itr)->HasSpellClassMask())
- bonusPct += (*itr)->GetAmount();
- }
- // item dependent spell - check current weapons
- // for (int i = 0; i < MAX_ATTACK; ++i)
- else
- {
- if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*itr)->GetSpellProto()))
- bonusPct += (*itr)->GetAmount();
- /*
- Item* weapon = ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true);
- if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
- {
- armor = floor(AddPctN(armor, -(*itr)->GetAmount()));
- break;
- }
- */
- }
- }
- // }
- /*
- // Apply Player CR_ARMOR_PENETRATION rating
- if(GetTypeId() == TYPEID_PLAYER)
- {
- */
- float maxArmorPen = 0;
- if(victim->getLevel() < 60)
- maxArmorPen = float(450 + 85 * victim->getLevel()); // 400 - original
- else
- maxArmorPen = 450 + 85 * victim->getLevel() + 4.5f * 85 * (victim->getLevel() - 59);
- // Cap armor penetration to this number
- maxArmorPen = std::min((armor + maxArmorPen) / 3, armor);
- // Figure out how much armor do we ignore
- float armorPen = CalculatePctF(maxArmorPen, bonusPct + ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION));
- // Got the value, apply it
- armor -= armorPen;
- }
- if(armor < 0.0f)
- armor = 0.0f;
- float levelModifier = getLevel();
- if(levelModifier > 59)
- levelModifier = levelModifier + (4.5f * (levelModifier - 59));
- float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40);
- tmpvalue = tmpvalue / (1.0f + tmpvalue);
- if(tmpvalue < 0.0f)
- tmpvalue = 0.0f;
- if(tmpvalue > 0.75f)
- tmpvalue = 0.75f;
- newdamage = uint32(damage - (damage * tmpvalue));
- return (newdamage > 1) ? newdamage : 1;
- }
- void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, SpellEntry const* spellInfo)
- {
- if(!victim || !victim->isAlive() || !damage)
- return;
- DamageInfo dmgInfo = DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype);
- // Magic damage, check for resists
- if((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
- {
- float baseVictimResistance = float(victim->GetResistance(GetFirstSchoolInMask(schoolMask)));
- float ignoredResistance = float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
- if(Player* pPlayer = ToPlayer())
- ignoredResistance += float(pPlayer->GetSpellPenetrationItemMod());
- float victimResistance = baseVictimResistance + ignoredResistance;
- static uint32 const BOSS_LEVEL = 83;
- static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
- uint32 level = victim->getLevel();
- float resistanceConstant = 0.0f;
- if(level == BOSS_LEVEL)
- resistanceConstant = BOSS_RESISTANCE_CONSTANT;
- else
- resistanceConstant = level * 5.0f;
- float averageResist = victimResistance / (victimResistance + resistanceConstant);
- float discreteResistProbability[11];
- for(uint32 i = 0; i < 11; ++i)
- {
- discreteResistProbability[i] = 0.5f - 2.5f * fabs(0.1f * i - averageResist);
- if(discreteResistProbability[i] < 0.0f)
- discreteResistProbability[i] = 0.0f;
- }
- if(averageResist <= 0.1f)
- {
- discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
- discreteResistProbability[1] = 5.0f * averageResist;
- discreteResistProbability[2] = 2.5f * averageResist;
- }
- float r = float(rand_norm());
- uint32 i = 0;
- float probabilitySum = discreteResistProbability[0];
- while(r >= probabilitySum && i < 10)
- probabilitySum += discreteResistProbability[++i];
- float damageResisted;
- if(this->GetTypeId() == TYPEID_PLAYER && this->getClass() == CLASS_PALADIN)
- {
- //if(this->HasAura(53375))
- //else
- if(this->HasAura(53376))
- damageResisted = float(damage * i / 20);
- } else damageResisted = float(damage * i / 10);
- // These spells should ignore any resistances
- if(spellInfo && spellInfo->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- damageResisted = 0;
- AuraEffectList const& ResIgnoreAurasAb = GetAuraEffectsByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST);
- for(AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j)
- if(((*j)->GetMiscValue() & schoolMask) && (*j)->IsAffectedOnSpell(spellInfo))
- AddPctN(damageResisted, -(*j)->GetAmount());
- AuraEffectList const& ResIgnoreAuras = GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_TARGET_RESIST);
- for(AuraEffectList::const_iterator j = ResIgnoreAuras.begin(); j != ResIgnoreAuras.end(); ++j)
- if((*j)->GetMiscValue() & schoolMask)
- AddPctN(damageResisted, -(*j)->GetAmount());
- dmgInfo.ResistDamage(uint32(damageResisted));
- }
- // Ignore Absorption Auras
- float auraAbsorbMod = 0;
- AuraEffectList const& AbsIgnoreAurasA = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL);
- for(AuraEffectList::const_iterator itr = AbsIgnoreAurasA.begin(); itr != AbsIgnoreAurasA.end(); ++itr)
- {
- if(!((*itr)->GetMiscValue() & schoolMask))
- continue;
- if((*itr)->GetAmount() > auraAbsorbMod)
- auraAbsorbMod = float((*itr)->GetAmount());
- }
- AuraEffectList const& AbsIgnoreAurasB = GetAuraEffectsByType(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL);
- for(AuraEffectList::const_iterator itr = AbsIgnoreAurasB.begin(); itr != AbsIgnoreAurasB.end(); ++itr)
- {
- if(!((*itr)->GetMiscValue() & schoolMask))
- continue;
- if(((*itr)->GetAmount() > auraAbsorbMod) && (*itr)->IsAffectedOnSpell(spellInfo))
- auraAbsorbMod = float((*itr)->GetAmount());
- }
- RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
- vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
- // absorb without mana cost
- for(AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
- {
- AuraEffect* absorbAurEff = *itr;
- // Check if aura was removed during iteration - we don't need to work on such auras
- AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
- if(!aurApp)
- continue;
- if(!(absorbAurEff->GetMiscValue() & schoolMask))
- continue;
- // get amount which can be still absorbed by the aura
- int32 currentAbsorb = absorbAurEff->GetAmount();
- // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
- if(currentAbsorb < 0)
- currentAbsorb = 0;
- uint32 absorb = currentAbsorb;
- bool defaultPrevented = false;
- absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented);
- currentAbsorb = absorb;
- if(defaultPrevented)
- continue;
- // Apply absorb mod auras
- AddPctF(currentAbsorb, -auraAbsorbMod);
- // absorb must be smaller than the damage itself
- currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
- dmgInfo.AbsorbDamage(currentAbsorb);
- absorb = currentAbsorb;
- absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, dmgInfo, absorb);
- // Check if our aura is using amount to count damage
- if(absorbAurEff->GetAmount() >= 0)
- {
- // Reduce shield amount
- absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
- // Aura cannot absorb anything more - remove it
- if(absorbAurEff->GetAmount() <= 0)
- absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- }
- }
- // absorb by mana cost
- AuraEffectList vManaShieldCopy(victim->GetAuraEffectsByType(SPELL_AURA_MANA_SHIELD));
- for(AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
- {
- AuraEffect* absorbAurEff = *itr;
- // Check if aura was removed during iteration - we don't need to work on such auras
- AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID());
- if(!aurApp)
- continue;
- // check damage school mask
- if(!(absorbAurEff->GetMiscValue() & schoolMask))
- continue;
- // get amount which can be still absorbed by the aura
- int32 currentAbsorb = absorbAurEff->GetAmount();
- // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
- if(currentAbsorb < 0)
- currentAbsorb = 0;
- uint32 absorb = currentAbsorb;
- bool defaultPrevented = false;
- absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, absorb, defaultPrevented);
- currentAbsorb = absorb;
- if(defaultPrevented)
- continue;
- AddPctF(currentAbsorb, -auraAbsorbMod);
- // absorb must be smaller than the damage itself
- currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
- int32 manaReduction = currentAbsorb;
- // lower absorb amount by talents
- if(float manaMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(absorbAurEff->GetSpellProto(), absorbAurEff->GetEffIndex(), absorbAurEff->GetCaster()))
- manaReduction = int32(float(manaReduction) * manaMultiplier);
- int32 manaTaken = -victim->ModifyPower(POWER_MANA, -manaReduction);
- // take case when mana has ended up into account
- currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
- dmgInfo.AbsorbDamage(currentAbsorb);
- absorb = currentAbsorb;
- absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, absorb);
- // Check if our aura is using amount to count damage
- if(absorbAurEff->GetAmount() >= 0)
- {
- absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
- if((absorbAurEff->GetAmount() <= 0))
- absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- }
- }
- // split damage auras - only when not damaging self
- if(victim != this)
- {
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSplitDamageFlatCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_FLAT));
- for(AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if(!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
- continue;
- // check damage school mask
- if(!((*itr)->GetMiscValue() & schoolMask))
- continue;
- // Damage can be splitted only if aura has an alive caster
- Unit* caster = (*itr)->GetCaster();
- if(!caster || (caster == victim) || !caster->IsInWorld() || !caster->isAlive())
- continue;
- int32 splitDamage = (*itr)->GetAmount();
- // absorb must be smaller than the damage itself
- splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
- dmgInfo.AbsorbDamage(splitDamage);
- uint32 splitted = splitDamage;
- uint32 splitted_absorb = 0;
- DealDamageMods(caster, splitted, &splitted_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
- }
- // We're going to call functions which can modify content of the list during iteration over it's elements
- // Let's copy the list so we can prevent iterator invalidation
- AuraEffectList vSplitDamagePctCopy(victim->GetAuraEffectsByType(SPELL_AURA_SPLIT_DAMAGE_PCT));
- for(AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(), next; (itr != vSplitDamagePctCopy.end()) && (dmgInfo.GetDamage() > 0); ++itr)
- {
- // Check if aura was removed during iteration - we don't need to work on such auras
- if(!((*itr)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
- continue;
- // check damage school mask
- if(!((*itr)->GetMiscValue() & schoolMask))
- continue;
- // Damage can be splitted only if aura has an alive caster
- Unit* caster = (*itr)->GetCaster();
- if(!caster || (caster == victim) || !caster->IsInWorld() || !caster->isAlive())
- continue;
- int32 splitDamage = CalculatePctN(dmgInfo.GetDamage(), (*itr)->GetAmount());
- // absorb must be smaller than the damage itself
- splitDamage = RoundToInterval(splitDamage, 0, int32(dmgInfo.GetDamage()));
- dmgInfo.AbsorbDamage(splitDamage);
- uint32 splitted = splitDamage;
- uint32 split_absorb = 0;
- DealDamageMods(caster, splitted, &split_absorb);
- SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
- DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellProto(), false);
- }
- }
- *resist = dmgInfo.GetResist();
- *absorb = dmgInfo.GetAbsorb();
- }
- void Unit::CalcHealAbsorb(Unit* victim, const SpellEntry *healSpell, uint32 &healAmount, uint32 &absorb)
- {
- if(!healAmount)
- return;
- int32 RemainingHeal = healAmount;
- // Need remove expired auras after
- bool existExpired = false;
- // absorb without mana cost
- AuraEffectList const& vHealAbsorb = victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_HEAL_ABSORB);
- for(AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && RemainingHeal > 0; ++i)
- {
- if(!((*i)->GetMiscValue() & healSpell->SchoolMask))
- continue;
- // Max Amount can be absorbed by this aura
- int32 currentAbsorb = (*i)->GetAmount();
- // Found empty aura (impossible but..)
- if(currentAbsorb <= 0)
- {
- existExpired = true;
- continue;
- }
- // currentAbsorb - damage can be absorbed by shield
- // If need absorb less damage
- if(RemainingHeal < currentAbsorb)
- currentAbsorb = RemainingHeal;
- RemainingHeal -= currentAbsorb;
- // Reduce shield amount
- (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
- // Need remove it later
- if((*i)->GetAmount() <= 0)
- existExpired = true;
- }
- // Remove all expired absorb auras
- if(existExpired)
- {
- for(AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();)
- {
- AuraEffect* auraEff = *i;
- ++i;
- if(auraEff->GetAmount() <= 0)
- {
- uint32 removedAuras = victim->m_removedAurasCount;
- auraEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
- if(removedAuras+1 < victim->m_removedAurasCount)
- i = vHealAbsorb.begin();
- }
- }
- }
- absorb = RemainingHeal > 0 ? (healAmount - RemainingHeal) : healAmount;
- healAmount = RemainingHeal;
- }
- void Unit::AttackerStateUpdate (Unit* pVictim, WeaponAttackType attType, bool extra)
- {
- if(HasUnitState(UNIT_STAT_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
- return;
- if(!pVictim->isAlive())
- return;
- if((attType == BASE_ATTACK || attType == OFF_ATTACK) && !this->IsWithinLOSInMap(pVictim) && !isPet())
- return;
- CombatStart(pVictim);
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK);
- uint32 hitInfo;
- if(attType == BASE_ATTACK)
- hitInfo = HITINFO_NORMALSWING2;
- else if(attType == OFF_ATTACK)
- hitInfo = HITINFO_LEFTSWING;
- else
- return; // ignore ranged case
- // melee attack spell casted at main hand attack only - no normal melee dmg dealt
- if(attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL])
- m_currentSpells[CURRENT_MELEE_SPELL]->cast();
- else
- {
- // attack can be redirected to another target
- pVictim = SelectMagnetTarget(pVictim);
- CalcDamageInfo damageInfo;
- CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
- // Send log damage message to client
- DealDamageMods(pVictim, damageInfo.damage, &damageInfo.absorb);
- SendAttackStateUpdate(&damageInfo);
- //TriggerAurasProcOnEvent(damageInfo);
- ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
- DealMeleeDamage(&damageInfo, true);
- }
- if(!extra && m_extraAttacks)
- {
- while(m_extraAttacks)
- {
- AttackerStateUpdate(pVictim, BASE_ATTACK, true);
- if(m_extraAttacks > 0)
- --m_extraAttacks;
- }
- }
- }
- MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit* victim, WeaponAttackType attType) const
- {
- // This is only wrapper
- // Miss chance based on melee
- //float miss_chance = MeleeMissChanceCalc(victim, attType);
- float miss_chance = MeleeSpellMissChance(victim, attType, int32(GetWeaponSkillValue(attType, victim)) - int32(victim->GetDefenseSkillValue(this)), 0);
- // Critical hit chance
- float crit_chance = GetUnitCriticalChance(attType, victim);
- // stunned target cannot dodge and this is check in GetUnitDodgeChance() (returned 0 in this case)
- float dodge_chance = victim->GetUnitDodgeChance();
- float block_chance = victim->GetUnitBlockChance();
- float parry_chance = victim->GetUnitParryChance();
- // Useful if want to specify crit & miss chances for melee, else it could be removed
- sLog->outDebug(LOG_FILTER_UNITS, "MELEE OUTCOME: miss %f crit %f dodge %f parry %f block %f", miss_chance, crit_chance, dodge_chance, parry_chance, block_chance);
- return RollMeleeOutcomeAgainst(victim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100), int32(parry_chance*100), int32(block_chance*100));
- }
- MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const
- {
- if(victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
- return MELEE_HIT_EVADE;
- int32 attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
- int32 victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
- int32 attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
- int32 victimDefenseSkill = victim->GetDefenseSkillValue(this);
- // bonus from skills is 0.04%
- int32 skillBonus = 4 * (attackerWeaponSkill - victimMaxSkillValueForLevel);
- int32 sum = 0, tmp = 0;
- int32 roll = urand(0, 10000);
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: skill bonus of %d for attacker", skillBonus);
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: rolled %d, miss %d, dodge %d, parry %d, block %d, crit %d",
- roll, miss_chance, dodge_chance, parry_chance, block_chance, crit_chance);
- tmp = miss_chance;
- if(tmp > 0 && roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: MISS");
- return MELEE_HIT_MISS;
- }
- // always crit against a sitting target (except 0 crit chance)
- if(victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT (sitting victim)");
- return MELEE_HIT_CRIT;
- }
- // Dodge chance
- // only players can't dodge if attacker is behind
- if(victim->GetTypeId() == TYPEID_PLAYER && !victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: attack came from behind and victim was a player.");
- }
- else
- {
- // Reduce dodge chance by attacker expertise rating
- if(GetTypeId() == TYPEID_PLAYER)
- dodge_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
- else
- dodge_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
- // Modify dodge chance by attacker SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
- dodge_chance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
- dodge_chance = int32 (float (dodge_chance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
- tmp = dodge_chance;
- if((tmp > 0) // check if unit _can_ dodge
- && ((tmp -= skillBonus) > 0)
- && roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: DODGE <%d, %d)", sum-tmp, sum);
- return MELEE_HIT_DODGE;
- }
- }
- // parry & block chances
- // check if attack comes from behind, nobody can parry or block if attacker is behind
- if(!victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: attack came from behind.");
- else
- {
- // Reduce parry chance by attacker expertise rating
- if(GetTypeId() == TYPEID_PLAYER)
- parry_chance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100);
- else
- parry_chance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
- if(victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY))
- {
- int32 tmp2 = int32(parry_chance);
- if(tmp2 > 0 // check if unit _can_ parry
- && (tmp2 -= skillBonus) > 0
- && roll < (sum += tmp2))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: PARRY <%d, %d)", sum-tmp2, sum);
- return MELEE_HIT_PARRY;
- }
- }
- if(victim->GetTypeId() == TYPEID_PLAYER || !(victim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK))
- {
- tmp = block_chance;
- if(tmp > 0 // check if unit _can_ block
- && (tmp -= skillBonus) > 0
- && roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum);
- return MELEE_HIT_BLOCK;
- }
- }
- }
- // Critical chance
- tmp = crit_chance;
- if(tmp > 0 && roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT <%d, %d)", sum-tmp, sum);
- if(GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRIT DISABLED)");
- else
- return MELEE_HIT_CRIT;
- }
- // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon)
- if(attType != RANGED_ATTACK &&
- (GetTypeId() == TYPEID_PLAYER || ToCreature()->isPet()) &&
- victim->GetTypeId() != TYPEID_PLAYER && !victim->ToCreature()->isPet() &&
- getLevel() < victim->getLevelForTarget(this))
- {
- // cap possible value (with bonuses > max skill)
- int32 skill = attackerWeaponSkill;
- int32 maxskill = attackerMaxSkillValueForLevel;
- skill = (skill > maxskill) ? maxskill : skill;
- tmp = (10 + (victimDefenseSkill - skill)) * 100;
- tmp = tmp > 4000 ? 4000 : tmp;
- if(roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: GLANCING <%d, %d)", sum-4000, sum);
- return MELEE_HIT_GLANCING;
- }
- }
- // mobs can score crushing blows if they're 4 or more levels above victim
- if(getLevelForTarget(victim) >= victim->getLevelForTarget(this) + 4 &&
- // can be from by creature (if can) or from controlled player that considered as creature
- !IsControlledByPlayer() &&
- !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH))
- {
- // when their weapon skill is 15 or more above victim's defense skill
- tmp = victimDefenseSkill;
- int32 tmpmax = victimMaxSkillValueForLevel;
- // having defense above your maximum (from items, talents etc.) has no effect
- tmp = tmp > tmpmax ? tmpmax : tmp;
- // tmp = mob's level * 5 - player's current defense skill
- tmp = attackerMaxSkillValueForLevel - tmp;
- if(tmp >= 15)
- {
- // add 2% chance per lacking skill point, min. is 15%
- tmp = tmp * 200 - 1500;
- if(roll < (sum += tmp))
- {
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: CRUSHING <%d, %d)", sum-tmp, sum);
- return MELEE_HIT_CRUSHING;
- }
- }
- }
- sLog->outDebug(LOG_FILTER_UNITS, "RollMeleeOutcomeAgainst: NORMAL");
- return MELEE_HIT_NORMAL;
- }
- uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
- {
- float min_damage, max_damage;
- if(GetTypeId() == TYPEID_PLAYER && (normalized || !addTotalPct))
- ToPlayer()->CalculateMinMaxDamage(attType, normalized, addTotalPct, min_damage, max_damage);
- else
- {
- switch(attType)
- {
- case RANGED_ATTACK:
- min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
- max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
- break;
- case BASE_ATTACK:
- min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
- max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
- break;
- case OFF_ATTACK:
- min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
- max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
- break;
- // Just for good manner
- default:
- min_damage = 0.0f;
- max_damage = 0.0f;
- break;
- }
- }
- if(GetTypeId() == TYPEID_PLAYER)
- {
- min_damage /= GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT);
- max_damage /= GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT);
- }
- if(min_damage > max_damage)
- std::swap(min_damage, max_damage);
- if(max_damage == 0.0f)
- max_damage = 5.0f;
- // Rounding
- min_damage += 0.5f;
- max_damage += 0.5f;
- return urand((uint32)min_damage, (uint32)max_damage);
- }
- float Unit::CalculateLevelPenalty(SpellEntry const* spellProto) const
- {
- if(spellProto->spellLevel <= 0 || spellProto->spellLevel >= spellProto->maxLevel)
- return 1.0f;
- float LvlPenalty = 0.0f;
- if(spellProto->spellLevel < 20)
- LvlPenalty = 20.0f - spellProto->spellLevel * 3.75f;
- float LvlFactor = (float(spellProto->spellLevel) + 6.0f) / float(getLevel());
- if(LvlFactor > 1.0f)
- LvlFactor = 1.0f;
- return AddPctF(LvlFactor, -LvlPenalty);
- }
- void Unit::SendMeleeAttackStart(Unit* victim)
- {
- WorldPacket data(SMSG_ATTACKSTART, 8 + 8);
- data << uint64(GetGUID());
- data << uint64(victim->GetGUID());
- SendMessageToSet(&data, true);
- sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ATTACKSTART");
- }
- void Unit::SendMeleeAttackStop(Unit* pVictim)
- {
- WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size
- data.append(GetPackGUID());
- data.append(pVictim ? pVictim->GetPackGUID() : 0); // can be 0x00...
- data << uint32(0); // can be 0x1
- SendMessageToSet(&data, true);
- sLog->outDebug(LOG_FILTER_UNITS, "WORLD: Sent SMSG_ATTACKSTOP");
- if(pVictim)
- sLog->outDebug(LOG_FILTER_UNITS, "%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow(), (pVictim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), pVictim->GetGUIDLow());
- else
- sLog->outDebug(LOG_FILTER_UNITS, "%s %u stopped attacking", (GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), GetGUIDLow());
- //sLog->outDetail("%s %u stopped attacking %s %u", (GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), GetGUIDLow(), (pVictim->GetTypeId() == TYPEID_PLAYER ? "player" : "creature"), pVictim->GetGUIDLow());
- }
- bool Unit::isSpellBlocked(Unit* pVictim, SpellEntry const* pSpellEntry, WeaponAttackType attackType)
- {
- // These spells can't be blocked
- if(pSpellEntry && pSpellEntry->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
- return false;
- if(pVictim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || pVictim->HasInArc(M_PI, this))
- {
- // Check creatures flags_extra for disable block
- if(pVictim->GetTypeId() == TYPEID_UNIT &&
- pVictim->ToCreature()->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK)
- return false;
- float blockChance = pVictim->GetUnitBlockChance();
- blockChance += (int32(GetWeaponSkillValue(attackType)) - int32(pVictim->GetMaxSkillValueForLevel())) * 0.04f;
- if(roll_chance_f(blockChance))
- return true;
- }
- return false;
- }
- bool Unit::isBlockCritical()
- {
- if(roll_chance_i(GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_CRIT_CHANCE)))
- return true;
- return false;
- }
- int32 Unit::GetMechanicResistChance(const SpellEntry* spell)
- {
- if(!spell)
- return 0;
- int32 resist_mech = 0;
- for(uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
- {
- if(spell->Effect[eff] == 0)
- break;
- int32 effect_mech = GetEffectMechanic(spell, eff);
- if(effect_mech)
- {
- int32 temp = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
- if(resist_mech < temp)
- resist_mech = temp;
- }
- }
- return resist_mech;
- }
- // Melee based spells hit result calculations
- SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellEntry const* spell)
- {
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- return SPELL_MISS_NONE;
- WeaponAttackType attType = BASE_ATTACK;
- // Check damage class instead of attack type to correctly handle judgements
- // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
- if(spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
- attType = RANGED_ATTACK;
- int32 attackerWeaponSkill;
- // skill value for these spells (for example judgements) is 5* level
- if(spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !IsRangedWeaponSpell(spell))
- attackerWeaponSkill = getLevel() * 5;
- // bonus from skills is 0.04% per skill Diff
- else
- attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
- int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
- int32 fullSkillDiff = attackerWeaponSkill - int32(victim->GetDefenseSkillValue(this));
- uint32 roll = urand(0, 10000);
- uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, fullSkillDiff, spell->Id) * 100.0f);
- // Roll miss
- uint32 tmp = missChance;
- if(roll < tmp)
- return SPELL_MISS_MISS;
- // Chance resist mechanic (select max value from every mechanic spell effect)
- int32 resist_mech = 0;
- // Get effects mechanic and chance
- for(uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
- {
- int32 effect_mech = GetEffectMechanic(spell, eff);
- if(effect_mech)
- {
- int32 temp = victim->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_MECHANIC_RESISTANCE, effect_mech);
- if(resist_mech < temp*100)
- resist_mech = temp*100;
- }
- }
- // Roll chance
- tmp += resist_mech;
- if(roll < tmp)
- return SPELL_MISS_RESIST;
- bool canDodge = true;
- bool canParry = true;
- bool canBlock = spell->AttributesEx3 & SPELL_ATTR3_BLOCKABLE_SPELL;
- // Same spells cannot be parry/dodge
- if(spell->Attributes & SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK)
- return SPELL_MISS_NONE;
- // Chance resist mechanic
- int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
- tmp += resist_chance;
- if(roll < tmp)
- return SPELL_MISS_RESIST;
- // Ranged attacks can only miss, resist and deflect
- if(attType == RANGED_ATTACK)
- {
- /*
- canParry = false;
- canDodge = false;
- */
- // Judgements cannot be deflected
- if(spell->Category == SPELLCATEGORY_JUDGEMENT)
- return SPELL_MISS_NONE;
- // only if in front
- if(victim->HasInArc(M_PI, this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
- tmp+=deflect_chance;
- if(roll < tmp)
- return SPELL_MISS_DEFLECT;
- }
- return SPELL_MISS_NONE;
- }
- // Check for attack from behind
- if(!victim->HasInArc(M_PI, this) && !victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- // Can`t dodge from behind in PvP (but its possible in PvE)
- if(victim->GetTypeId() == TYPEID_PLAYER)
- canDodge = false;
- // Can`t parry or block
- canParry = false;
- canBlock = false;
- }
- // Check creatures flags_extra for disable parry
- if(victim->GetTypeId() == TYPEID_UNIT)
- {
- uint32 flagEx = victim->ToCreature()->GetCreatureInfo()->flags_extra;
- if(flagEx & CREATURE_FLAG_EXTRA_NO_PARRY)
- canParry = false;
- // Check creatures flags_extra for disable block
- if(flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK)
- canBlock = false;
- }
- // Ignore combat result aura
- AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
- for(AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
- {
- if(!(*i)->IsAffectedOnSpell(spell))
- continue;
- switch((*i)->GetMiscValue())
- {
- case MELEE_HIT_DODGE: canDodge = false; break;
- case MELEE_HIT_BLOCK: canBlock = false; break;
- case MELEE_HIT_PARRY: canParry = false; break;
- default:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
- break;
- }
- }
- if(canDodge)
- {
- // Roll dodge
- int32 dodgeChance = int32(victim->GetUnitDodgeChance() * 100.0f) - skillDiff * 4;
- // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
- dodgeChance += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE) * 100;
- dodgeChance = int32(float(dodgeChance) * GetTotalAuraMultiplier(SPELL_AURA_MOD_ENEMY_DODGE));
- // Reduce dodge chance by attacker expertise rating
- if(GetTypeId() == TYPEID_PLAYER)
- dodgeChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- else
- dodgeChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
- if(dodgeChance < 0)
- dodgeChance = 0;
- if(roll < (tmp += dodgeChance))
- return SPELL_MISS_DODGE;
- }
- if(canParry)
- {
- // Roll parry
- int32 parryChance = int32(victim->GetUnitParryChance() * 100.0f) - skillDiff * 4;
- // Reduce parry chance by attacker expertise rating
- if(GetTypeId() == TYPEID_PLAYER)
- parryChance -= int32(ToPlayer()->GetExpertiseDodgeOrParryReduction(attType) * 100.0f);
- else
- parryChance -= GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE) * 25;
- if(parryChance < 0)
- parryChance = 0;
- tmp += parryChance;
- if(roll < tmp)
- return SPELL_MISS_PARRY;
- }
- if(canBlock)
- {
- int32 blockChance = int32(victim->GetUnitBlockChance() * 100.0f) - skillDiff * 4;
- if(blockChance < 0)
- blockChance = 0;
- tmp += blockChance;
- if(roll < tmp)
- return SPELL_MISS_BLOCK;
- }
- return SPELL_MISS_NONE;
- }
- // TODO need use unit spell resistances in calculations
- SpellMissInfo Unit::MagicSpellHitResult(Unit* pVictim, SpellEntry const* spell)
- {
- // Can`t miss on dead target (on skinning for example)
- if(!pVictim->isAlive() && pVictim->GetTypeId() != TYPEID_PLAYER)
- return SPELL_MISS_NONE;
- SpellSchoolMask schoolMask = GetSpellSchoolMask(spell);
- // PvP - PvE spell misschances per leveldif > 2
- int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
- int32 thisLevel = getLevelForTarget(pVictim);
- if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTrigger())
- thisLevel = std::max<int32>(thisLevel, spell->spellLevel);
- int32 leveldif = int32(pVictim->getLevelForTarget(this)) - thisLevel;
- // Base hit chance from attacker and victim levels
- int32 modHitChance;
- if(leveldif < 3)
- modHitChance = 96 - leveldif;
- else
- modHitChance = 94 - (leveldif - 2) * lchance;
- // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
- // Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
- modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will ignore target's avoidance effects
- if(!(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT))
- {
- // Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
- if(!(spell->SpellFamilyName == SPELLFAMILY_WARLOCK && spell->SpellIconID == 3178)) // Chaos Bolt should ignore it
- modHitChance += pVictim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
- // Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
- if(IsAreaOfEffectSpell(spell))
- modHitChance -= pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
- // Decrease hit chance from victim rating bonus
- if(pVictim->GetTypeId() == TYPEID_PLAYER)
- modHitChance -= int32(pVictim->ToPlayer()->GetRatingBonusValue(CR_HIT_TAKEN_SPELL));
- }
- int32 HitChance = modHitChance * 100;
- // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings
- HitChance += int32(m_modSpellHitChance * 100.0f);
- if(HitChance < 100)
- HitChance = 100;
- else if(HitChance > 10000)
- HitChance = 10000;
- int32 tmp = 10000 - HitChance;
- int32 rand = irand(0, 10000);
- if(rand < tmp)
- return SPELL_MISS_MISS;
- // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore
- // resist and deflect chances
- if(spell->AttributesEx3 & SPELL_ATTR3_IGNORE_HIT_RESULT)
- return SPELL_MISS_NONE;
- // Chance resist mechanic (select max value from every mechanic spell effect)
- int32 resist_chance = pVictim->GetMechanicResistChance(spell) * 100;
- tmp += resist_chance;
- // Chance resist debuff
- if(!IsPositiveSpell(spell->Id))
- {
- bool bNegativeAura = false;
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if(spell->EffectApplyAuraName[i] != 0)
- {
- bNegativeAura = true;
- break;
- }
- }
- if(bNegativeAura)
- {
- tmp += pVictim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
- tmp += pVictim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
- }
- }
- // Roll chance
- if(rand < tmp)
- return SPELL_MISS_RESIST;
- // Chaos Bolt cannot be deflected
- if(spell->SpellFamilyName == SPELLFAMILY_WARLOCK && spell->SpellIconID == 3178)
- return SPELL_MISS_NONE;
- // cast by caster in front of victim
- if(pVictim->HasInArc(M_PI, this) || pVictim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
- {
- int32 deflect_chance = pVictim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
- tmp += deflect_chance;
- if(rand < tmp)
- return SPELL_MISS_DEFLECT;
- }
- return SPELL_MISS_NONE;
- }
- // Calculate spell hit result can be:
- // Every spell can: Evade/Immune/Reflect/Sucesful hit
- // For melee based spells:
- // Miss
- // Dodge
- // Parry
- // For spells
- // Resist
- SpellMissInfo Unit::SpellHitResult(Unit* pVictim, SpellEntry const* pSpell, bool CanReflect)
- {
- if(!pVictim)
- return SPELL_MISS_NONE;
- // Check for immune
- if(pVictim->IsImmunedToSpell(pSpell))
- return SPELL_MISS_IMMUNE;
- // All positive spells can`t miss
- // TODO: client not show miss log for this spells - so need find info for this in dbc and use it!
- if(IsPositiveSpell(pSpell->Id)
- &&(!IsHostileTo(pVictim))) // prevent from affecting enemy by "positive" spell
- return SPELL_MISS_NONE;
- // Check for immune
- if(pVictim->IsImmunedToDamage(pSpell))
- return SPELL_MISS_IMMUNE;
- if(this == pVictim)
- return SPELL_MISS_NONE;
- // Return evade for units in evade mode
- if(pVictim->GetTypeId() == TYPEID_UNIT && pVictim->ToCreature()->IsInEvadeMode())
- return SPELL_MISS_EVADE;
- // Try victim reflect spell
- if(CanReflect)
- {
- int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
- Unit::AuraEffectList const& mReflectSpellsSchool = pVictim->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
- for(Unit::AuraEffectList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- if((*i)->GetMiscValue() & GetSpellSchoolMask(pSpell))
- reflectchance += (*i)->GetAmount();
- if(reflectchance > 0 && roll_chance_i(reflectchance))
- {
- return SPELL_MISS_REFLECT;
- }
- }
- switch(pSpell->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_RANGED:
- case SPELL_DAMAGE_CLASS_MELEE:
- return MeleeSpellHitResult(pVictim, pSpell);
- case SPELL_DAMAGE_CLASS_NONE:
- return SPELL_MISS_NONE;
- case SPELL_DAMAGE_CLASS_MAGIC:
- return MagicSpellHitResult(pVictim, pSpell);
- }
- return SPELL_MISS_NONE;
- }
- uint32 Unit::GetDefenseSkillValue(Unit const* target) const
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // in PvP use full skill instead current skill value
- uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
- ? ToPlayer()->GetMaxSkillValue(SKILL_DEFENSE) : ToPlayer()->GetSkillValue(SKILL_DEFENSE);
- value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
- return value;
- }
- else
- return GetUnitMeleeSkill(target);
- }
- float Unit::GetUnitDodgeChance() const
- {
- if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED) || HasUnitState(UNIT_STAT_CASTING))
- return 0.0f;
- if(GetTypeId() == TYPEID_PLAYER)
- return GetFloatValue(PLAYER_DODGE_PERCENTAGE);
- else
- {
- if(ToCreature()->isTotem())
- return 0.0f;
- else
- {
- float dodge = 5.0f;
- dodge += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT);
- return dodge > 0.0f ? dodge : 0.0f;
- }
- }
- }
- float Unit::GetUnitParryChance() const
- {
- if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
- return 0.0f;
- float chance = 0.0f;
- if(Player const* player = ToPlayer())
- {
- if(player->CanParry())
- {
- Item* tmpitem = player->GetWeaponForAttack(BASE_ATTACK, true);
- if(!tmpitem)
- tmpitem = player->GetWeaponForAttack(OFF_ATTACK, true);
- if(tmpitem)
- chance = GetFloatValue(PLAYER_PARRY_PERCENTAGE);
- }
- }
- else if(GetTypeId() == TYPEID_UNIT)
- {
- if(GetCreatureType() == CREATURE_TYPE_HUMANOID)
- {
- chance = 5.0f;
- chance += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT);
- }
- }
- return chance > 0.0f ? chance : 0.0f;
- }
- float Unit::GetUnitBlockChance() const
- {
- if(IsNonMeleeSpellCasted(false) || HasUnitState(UNIT_STAT_CONTROLLED))
- return 0.0f;
- if(Player const* player = ToPlayer())
- {
- if(player->CanBlock())
- {
- Item* tmpitem = player->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->Block)
- return GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
- }
- // is player but has no block ability or no not broken shield equipped
- return 0.0f;
- }
- else
- {
- if(ToCreature()->isTotem())
- return 0.0f;
- else
- {
- float block = 5.0f;
- block += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT);
- return block > 0.0f ? block : 0.0f;
- }
- }
- }
- float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const
- {
- float crit;
- if(GetTypeId() == TYPEID_PLAYER)
- {
- switch(attackType)
- {
- case BASE_ATTACK:
- crit = GetFloatValue(PLAYER_CRIT_PERCENTAGE);
- break;
- case OFF_ATTACK:
- crit = GetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE);
- break;
- case RANGED_ATTACK:
- crit = GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE);
- break;
- // Just for good manner
- default:
- crit = 0.0f;
- break;
- }
- }
- else
- {
- crit = 5.0f;
- crit += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
- crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
- }
- // flat aura mods
- if(attackType == RANGED_ATTACK)
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE);
- else
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE);
- crit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
- // reduce crit chance from Rating for players
- if(attackType != RANGED_ATTACK)
- {
- ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_MELEE);
- // Glyph of barkskin
- if(victim->HasAura(63057) && victim->HasAura(22812))
- crit -= 25.0f;
- }
- else
- ApplyResilience(victim, &crit, NULL, false, CR_CRIT_TAKEN_RANGED);
- // Apply crit chance from defence skill
- crit += (int32(GetMaxSkillValueForLevel(victim)) - int32(victim->GetDefenseSkillValue(this))) * 0.04f;
- if(crit < 0.0f)
- crit = 0.0f;
- return crit;
- }
- uint32 Unit::GetWeaponSkillValue (WeaponAttackType attType, Unit const* target) const
- {
- uint32 value = 0;
- if(Player const* player = ToPlayer())
- {
- Item* item = player->GetWeaponForAttack(attType, true);
- // feral or unarmed skill only for base attack
- if(attType != BASE_ATTACK && !item)
- return 0;
- if(IsInFeralForm())
- return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
- // weapon skill or (unarmed for base attack and fist weapons)
- uint32 skill;
- if(item && item->GetSkill() != SKILL_FIST_WEAPONS)
- skill = item->GetSkill();
- else
- skill = SKILL_UNARMED;
- // in PvP use full skill instead current skill value
- value = (target && target->IsControlledByPlayer())
- ? player->GetMaxSkillValue(skill)
- : player->GetSkillValue(skill);
- // Modify value from ratings
- value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL));
- switch(attType)
- {
- case BASE_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND)); break;
- case OFF_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND)); break;
- case RANGED_ATTACK: value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED)); break;
- default: break;
- }
- }
- else
- value = GetUnitMeleeSkill(target);
- return value;
- }
- void Unit::_DeleteRemovedAuras()
- {
- while(!m_removedAuras.empty())
- {
- delete m_removedAuras.front();
- m_removedAuras.pop_front();
- }
- }
- void Unit::_UpdateSpells(uint32 time)
- {
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
- _UpdateAutoRepeatSpell();
- // remove finished spells from current pointers
- for(uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
- {
- if(m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
- {
- m_currentSpells[i]->SetReferencedFromCurrent(false);
- m_currentSpells[i] = NULL; // remove pointer
- }
- }
- // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
- for(m_auraUpdateIterator = m_ownedAuras.begin(); m_auraUpdateIterator != m_ownedAuras.end();)
- {
- Aura* i_aura = m_auraUpdateIterator->second;
- ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
- i_aura->UpdateOwner(time, this);
- }
- // remove expired auras - do that after updates(used in scripts?)
- for(AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
- {
- if(i->second->IsExpired())
- RemoveOwnedAura(i, AURA_REMOVE_BY_EXPIRE);
- else
- ++i;
- }
- for(VisibleAuraMap::iterator itr = m_visibleAuras.begin(); itr != m_visibleAuras.end(); ++itr)
- if(itr->second->IsNeedClientUpdate())
- itr->second->ClientUpdate();
- _DeleteRemovedAuras();
- if(!m_gameObj.empty())
- {
- GameObjectList::iterator itr;
- for(itr = m_gameObj.begin(); itr != m_gameObj.end();)
- {
- if(!(*itr)->isSpawned())
- {
- (*itr)->SetOwnerGUID(0);
- (*itr)->SetRespawnTime(0);
- (*itr)->Delete();
- m_gameObj.erase(itr++);
- }
- else
- ++itr;
- }
- }
- }
- void Unit::_UpdateAutoRepeatSpell()
- {
- // check "realtime" interrupts
- if((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCasted(false, false, true, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == 75))
- {
- // cancel wand shoot
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- m_AutoRepeatFirstCast = true;
- return;
- }
- // apply delay (Auto Shot (spellID 75) not affected)
- if(m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
- setAttackTimer(RANGED_ATTACK, 500);
- m_AutoRepeatFirstCast = false;
- // castroutine
- if(isAttackReady(RANGED_ATTACK))
- {
- // Check if able to cast
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK)
- {
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- return;
- }
- // we want to shoot
- Spell* spell = new Spell(this, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo, true);
- spell->prepare(&(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets));
- // all went good, reset attack
- resetAttackTimer(RANGED_ATTACK);
- }
- }
- void Unit::SetCurrentCastedSpell(Spell* pSpell)
- {
- ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
- CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
- if(pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
- // break same type spell if it is not delayed
- InterruptSpell(CSpellType, false);
- // special breakage effects:
- switch(CSpellType)
- {
- case CURRENT_GENERIC_SPELL:
- {
- // generic spells always break channeled not delayed spells
- InterruptSpell(CURRENT_CHANNELED_SPELL, false);
- // autorepeat breaking
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
- {
- // break autorepeat if not Auto Shot
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- m_AutoRepeatFirstCast = true;
- }
- AddUnitState(UNIT_STAT_CASTING);
- } break;
- case CURRENT_CHANNELED_SPELL:
- {
- // channel spells always break generic non-delayed and any channeled spells
- InterruptSpell(CURRENT_GENERIC_SPELL, false);
- InterruptSpell(CURRENT_CHANNELED_SPELL);
- // it also does break autorepeat if not Auto Shot
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL] &&
- m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != 75)
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
- AddUnitState(UNIT_STAT_CASTING);
- } break;
- case CURRENT_AUTOREPEAT_SPELL:
- {
- // only Auto Shoot does not break anything
- if(pSpell->m_spellInfo->Id != 75)
- {
- // generic autorepeats break generic non-delayed and channeled non-delayed spells
- InterruptSpell(CURRENT_GENERIC_SPELL, false);
- InterruptSpell(CURRENT_CHANNELED_SPELL, false);
- }
- // special action: set first cast flag
- m_AutoRepeatFirstCast = true;
- } break;
- default:
- {
- // other spell types don't break anything now
- } break;
- }
- // current spell (if it is still here) may be safely deleted now
- if(m_currentSpells[CSpellType])
- m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
- // set new current spell
- m_currentSpells[CSpellType] = pSpell;
- pSpell->SetReferencedFromCurrent(true);
- pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
- }
- void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
- {
- ASSERT(spellType < CURRENT_MAX_SPELL);
- Spell* spell = m_currentSpells[spellType];
- if(spell
- && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
- && (withInstant || spell->GetCastTime() > 0))
- {
- // for example, do not let self-stun aura interrupt itself
- if(!spell->IsInterruptable())
- return;
- // send autorepeat cancel message for autorepeat spells
- if(spellType == CURRENT_AUTOREPEAT_SPELL)
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->SendAutoRepeatCancel(this);
- if(spell->getState() != SPELL_STATE_FINISHED)
- spell->cancel();
- m_currentSpells[spellType] = NULL;
- spell->SetReferencedFromCurrent(false);
- }
- }
- void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/)
- {
- Spell* spell = m_currentSpells[spellType];
- if(!spell)
- return;
- if(spellType == CURRENT_CHANNELED_SPELL)
- spell->SendChannelUpdate(0);
- spell->finish(ok);
- }
- bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
- {
- // We don't do loop here to explicitly show that melee spell is excluded.
- // Maybe later some special spells will be excluded too.
- // if checkInstant then instant spells shouldn't count as being casted
- if(!skipInstant && m_currentSpells[CURRENT_GENERIC_SPELL] && !m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
- return false;
- // generic spells are casted when they are not finished and not delayed
- if(m_currentSpells[CURRENT_GENERIC_SPELL] &&
- (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
- (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
- {
- if(!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
- return(true);
- }
- // channeled spells may be delayed, but they are still considered casted
- else if(!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
- (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED))
- {
- if(!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS))
- return(true);
- }
- // autorepeat spells may be finished or delayed, but they are still considered casted
- else if(!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
- return(true);
- return(false);
- }
- void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
- {
- // generic spells are interrupted if they are not finished or delayed
- if(m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
- InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
- // autorepeat spells are interrupted if they are not finished or delayed
- if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
- InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
- // channeled spells are interrupted if they are not finished, even if they are delayed
- if(m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
- InterruptSpell(CURRENT_CHANNELED_SPELL, true, true);
- }
- Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
- {
- for(uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
- if(m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
- return m_currentSpells[i];
- return NULL;
- }
- int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
- {
- if(Spell const* spell = FindCurrentSpellBySpellId(spell_id))
- return spell->GetCastTime();
- return 0;
- }
- bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
- {
- return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
- }
- bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
- {
- return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target);
- }
- bool Unit::SetWalk(bool enable)
- {
- if(enable == IsWalking())
- return false;
- if(enable)
- AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
- else
- RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
- return true;
- }
- bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/)
- {
- if(disable == IsLevitating())
- return false;
- if(disable)
- AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
- else
- RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
- return true;
- }
- bool Unit::isInAccessiblePlaceFor(Creature const* c) const
- {
- if(IsInWater())
- return c->canSwim();
- else
- return c->canWalk() || c->canFly();
- }
- bool Unit::IsInWater() const
- {
- return GetBaseMap()->IsInWater(GetPositionX(), GetPositionY(), GetPositionZ());
- }
- bool Unit::IsUnderWater() const
- {
- return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ());
- }
- void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z)
- {
- if(!isPet() && !IsVehicle())
- return;
- LiquidData liquid_status;
- ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
- if(!res)
- {
- if(m_lastLiquid && m_lastLiquid->SpellId)
- RemoveAurasDueToSpell(m_lastLiquid->SpellId);
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
- m_lastLiquid = NULL;
- return;
- }
- if(uint32 liqEntry = liquid_status.entry)
- {
- LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
- if(m_lastLiquid && m_lastLiquid->SpellId && m_lastLiquid->Id != liqEntry)
- RemoveAurasDueToSpell(m_lastLiquid->SpellId);
- if(liquid && liquid->SpellId)
- {
- if(res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))
- CastSpell(this, liquid->SpellId, true);
- else
- RemoveAurasDueToSpell(liquid->SpellId);
- }
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
- m_lastLiquid = liquid;
- }
- else if(m_lastLiquid && m_lastLiquid->SpellId)
- {
- RemoveAurasDueToSpell(m_lastLiquid->SpellId);
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
- m_lastLiquid = NULL;
- }
- }
- void Unit::DeMorph()
- {
- SetDisplayId(GetNativeDisplayId());
- }
- Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellEntry const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
- {
- ASSERT(casterGUID || caster);
- if(!casterGUID)
- casterGUID = caster->GetGUID();
- // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
- if(!IsMultiSlotAura(newAura))
- {
- // check if cast item changed
- uint64 castItemGUID = 0;
- if(castItem)
- castItemGUID = castItem->GetGUID();
- // find current aura from spell and change it's stackamount, or refresh it's duration
- if(Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, (sSpellMgr->GetSpellCustomAttr(newAura->Id) & SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : 0, 0))
- {
- // effect masks do not match
- // extremely rare case
- // let's just recreate aura
- if(effMask != foundAura->GetEffectMask())
- return NULL;
- // update basepoints with new values - effect amount will be recalculated in ModStackAmount
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if(!foundAura->HasEffect(i))
- continue;
- int bp;
- if(baseAmount)
- bp = *(baseAmount + i);
- else
- bp = foundAura->GetSpellProto()->EffectBasePoints[i];
- int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(i)->m_baseAmount));
- *oldBP = bp;
- }
- // correct cast item guid if needed
- if(castItemGUID != foundAura->GetCastItemGUID())
- {
- uint64* oldGUID = const_cast<uint64 *>(&foundAura->m_castItemGuid);
- *oldGUID = castItemGUID;
- }
- // try to increase stack amount
- foundAura->ModStackAmount(1);
- return foundAura;
- }
- }
- return NULL;
- }
- void Unit::_AddAura(UnitAura* pAura, Unit* pCaster)
- {
- if(m_cleanupDone)
- sLog->outDetail("OH FUCK! Unit::_AddAura ID: %u", pAura->GetId());
- m_ownedAuras.insert(AuraMap::value_type(pAura->GetId(), pAura));
- _RemoveNoStackAurasDueToAura(pAura);
- if(pAura->IsRemoved())
- return;
- if(!pCaster)
- return;
- pAura->SetIsSingleTarget(pCaster && IsSingleTargetSpell(pAura->GetSpellProto()));
- if(pAura->IsSingleTarget())
- {
- ASSERT((IsInWorld() && !IsDuringRemoveFromWorld()) || (pAura->GetCasterGUID() == GetGUID()));
- // register single target aura
- pCaster->GetSingleCastAuras().push_back(pAura);
- // remove other single target auras
- Unit::AuraList& scAuras = pCaster->GetSingleCastAuras();
- for(Unit::AuraList::iterator itr = scAuras.begin(); itr != scAuras.end();)
- {
- if((*itr) != pAura &&
- IsSingleTargetSpells((*itr)->GetSpellProto(), pAura->GetSpellProto()))
- {
- (*itr)->Remove();
- itr = scAuras.begin();
- }
- else
- ++itr;
- }
- }
- }
- // creates aura application instance and registers it in lists
- // aura application effects are handled separately to prevent aura list corruption
- AuraApplication* Unit::_CreateAuraApplication(Aura* pAura, uint8 effMask)
- {
- // can't apply aura on unit which is going to be deleted - to not create a memory leak
- if(m_cleanupDone)
- sLog->outDetail("OH FUCK! Unit::_CreateAuraApplication ID: %u", pAura->GetId());
- // aura musn't be removed
- ASSERT(!pAura->IsRemoved());
- // aura mustn't be already applied on target
- ASSERT(!pAura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
- SpellEntry const* aurSpellInfo = pAura->GetSpellProto();
- uint32 aurId = aurSpellInfo->Id;
- // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
- if(!isAlive() && !IsDeathPersistentSpell(aurSpellInfo) &&
- (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
- return NULL;
- Unit* pCaster = pAura->GetCaster();
- AuraApplication* aurApp = new AuraApplication(this, pCaster, pAura, effMask);
- m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
- if(aurSpellInfo->AuraInterruptFlags)
- {
- m_interruptableAuras.push_back(aurApp);
- AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
- }
- if(AuraState aState = GetSpellAuraState(pAura->GetSpellProto()))
- m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
- pAura->_ApplyForTarget(this, pCaster, aurApp);
- return aurApp;
- }
- void Unit::_ApplyAuraEffect(Aura* pAura, uint8 effIndex)
- {
- ASSERT(pAura);
- ASSERT(pAura->HasEffect(effIndex));
- AuraApplication* aurApp = pAura->GetApplicationOfTarget(GetGUID());
- ASSERT(aurApp);
- if(!aurApp->GetEffectMask())
- _ApplyAura(aurApp, 1 << effIndex);
- else
- aurApp->_HandleEffect(effIndex, true);
- }
- // handles effects of aura application
- // should be done after registering aura in lists
- void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask)
- {
- Aura* aura = aurApp->GetBase();
- _RemoveNoStackAurasDueToAura(aura);
- if(aurApp->GetRemoveMode())
- return;
- // Update target aura state flag
- if(AuraState aState = GetSpellAuraState(aura->GetSpellProto()))
- ModifyAuraState(aState, true);
- if(aurApp->GetRemoveMode())
- return;
- // Sitdown on apply aura req seated
- if(aura->GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState())
- SetStandState(UNIT_STAND_STATE_SIT);
- Unit* caster = aura->GetCaster();
- if(aurApp->GetRemoveMode())
- return;
- aura->HandleAuraSpecificMods(aurApp, caster, true, false);
- // apply effects of the aura
- for(uint8 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
- {
- if(effMask & 1 << i && (!aurApp->GetRemoveMode()))
- aurApp->_HandleEffect(i, true);
- }
- }
- // removes aura application from lists and unapplies effects
- void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
- {
- AuraApplication* aurApp = i->second;
- ASSERT(aurApp);
- ASSERT(!aurApp->GetRemoveMode());
- ASSERT(aurApp->GetTarget() == this);
- aurApp->SetRemoveMode(removeMode);
- Aura* aura = aurApp->GetBase();
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura %u now is remove mode %d", aura->GetId(), removeMode);
- // dead loop is killing the server probably
- ASSERT(m_removedAurasCount < 0xFFFFFFFF);
- ++m_removedAurasCount;
- Unit* caster = aura->GetCaster();
- // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
- m_appliedAuras.erase(i);
- if(aura->GetSpellProto()->AuraInterruptFlags)
- {
- m_interruptableAuras.remove(aurApp);
- UpdateInterruptMask();
- }
- bool auraStateFound = false;
- AuraState auraState = GetSpellAuraState(aura->GetSpellProto());
- if(auraState)
- {
- bool canBreak = false;
- // Get mask of all aurastates from remaining auras
- for(AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
- {
- if(itr->second == aurApp)
- {
- m_auraStateAuras.erase(itr);
- itr = m_auraStateAuras.lower_bound(auraState);
- canBreak = true;
- continue;
- }
- auraStateFound = true;
- ++itr;
- }
- }
- aurApp->_Remove();
- aura->_UnapplyForTarget(this, caster, aurApp);
- // remove effects of the spell - needs to be done after removing aura from lists
- for(uint8 itr = 0 ; itr < MAX_SPELL_EFFECTS; ++itr)
- {
- if(aurApp->HasEffect(itr))
- aurApp->_HandleEffect(itr, false);
- }
- // all effect mustn't be applied
- ASSERT(!aurApp->GetEffectMask());
- // Remove totem at next update if totem loses its aura
- if(aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem()&& ToTotem()->GetSummonerGUID() == aura->GetCasterGUID())
- {
- if(ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
- ToTotem()->setDeathState(JUST_DIED);
- }
- // Remove aurastates only if were not found
- if(!auraStateFound)
- ModifyAuraState(auraState, false);
- aura->HandleAuraSpecificMods(aurApp, caster, false, false);
- i = m_appliedAuras.begin();
- }
- void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode)
- {
- // aura can be removed from unit only if it's applied on it, shouldn't happen
- ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
- uint32 spellId = aurApp->GetBase()->GetId();
- for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
- {
- if(iter->second == aurApp)
- {
- _UnapplyAura(iter, removeMode);
- return;
- }
- else
- ++iter;
- }
- ASSERT(false);
- }
- void Unit::_RemoveNoStackAuraApplicationsDueToAura(Aura* pAura)
- {
- // dynobj auras can stack infinite number of times
- if(pAura->GetType() == DYNOBJ_AURA_TYPE)
- return;
- SpellEntry const* pSpellEntry = pAura->GetSpellProto();
- uint32 spellId = pSpellEntry->Id;
- // passive spell special case (only non stackable with ranks)
- if(IsPassiveSpell(spellId) && IsPassiveSpellStackableWithRanks(pSpellEntry))
- return;
- bool remove = false;
- for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
- {
- if(remove)
- {
- remove = false;
- i = m_appliedAuras.begin();
- }
- if(!_IsNoStackAuraDueToAura(pAura, i->second->GetBase()))
- continue;
- RemoveAura(i, AURA_REMOVE_BY_DEFAULT);
- if(i == m_appliedAuras.end())
- break;
- remove = true;
- }
- }
- void Unit::_RemoveNoStackAurasDueToAura(Aura* pAura)
- {
- SpellEntry const* pSpellEntry = pAura->GetSpellProto();
- uint32 spellId = pSpellEntry->Id;
- // passive spell special case (only non stackable with ranks)
- if(IsPassiveSpell(spellId) && IsPassiveSpellStackableWithRanks(pSpellEntry))
- return;
- bool remove = false;
- for(AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end(); ++i)
- {
- if(remove)
- {
- remove = false;
- i = m_ownedAuras.begin();
- }
- if(!_IsNoStackAuraDueToAura(pAura, i->second))
- continue;
- RemoveOwnedAura(i, AURA_REMOVE_BY_DEFAULT);
- if(i == m_ownedAuras.end())
- break;
- remove = true;
- }
- }
- bool Unit::_IsNoStackAuraDueToAura(Aura* pAppliedAura, Aura* pExistingAura) const
- {
- SpellEntry const* pSpellEntryAP = pAppliedAura->GetSpellProto();
- // Do not check already applied aura
- if(pExistingAura == pAppliedAura)
- return false;
- // Do not check dynobj auras for stacking
- if(pExistingAura->GetType() != UNIT_AURA_TYPE)
- return false;
- SpellEntry const* pSpellEntryEP = pExistingAura->GetSpellProto();
- uint32 i_spellId = pSpellEntryEP->Id;
- bool sameCaster = pAppliedAura->GetCasterGUID() == pExistingAura->GetCasterGUID();
- if(IsPassiveSpell(i_spellId))
- {
- // passive non-stackable spells not stackable only for same caster
- if(!sameCaster)
- return false;
- // passive non-stackable spells not stackable only with another rank of same spell
- if(!sSpellMgr->IsRankSpellDueToSpell(pSpellEntryAP, i_spellId))
- return false;
- }
- bool is_triggered_by_spell = false;
- // prevent triggering aura of removing aura that triggered it
- // prevent triggered aura of removing aura that triggering it (triggered effect early some aura of parent spell
- for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
- {
- if(pSpellEntryEP->EffectTriggerSpell[j] == pSpellEntryAP->Id
- || pSpellEntryAP->EffectTriggerSpell[j] == pSpellEntryEP->Id) // I do not know what is this for
- {
- is_triggered_by_spell = true;
- break;
- }
- }
- if(is_triggered_by_spell)
- return false;
- if(sSpellMgr->CanAurasStack(pAppliedAura, pExistingAura, sameCaster))
- return false;
- return true;
- }
- void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
- {
- if(apply)
- m_modAuras[aurEff->GetAuraType()].push_back(aurEff);
- else
- m_modAuras[aurEff->GetAuraType()].remove(aurEff);
- }
- // All aura base removes should go threw this function!
- void Unit::RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode)
- {
- Aura* aura = i->second;
- ASSERT(!aura->IsRemoved());
- // if unit currently update aura list then make safe update iterator shift to next
- if(m_auraUpdateIterator == i)
- ++m_auraUpdateIterator;
- m_ownedAuras.erase(i);
- m_removedAuras.push_back(aura);
- // Unregister single target aura
- if(aura->IsSingleTarget())
- aura->UnregisterSingleTarget();
- aura->_Remove(removeMode);
- i = m_ownedAuras.begin();
- }
- void Unit::RemoveOwnedAura(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
- {
- for(AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
- if(((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!caster || itr->second->GetCasterGUID() == caster))
- {
- RemoveOwnedAura(itr, removeMode);
- itr = m_ownedAuras.lower_bound(spellId);
- }
- else
- ++itr;
- }
- void Unit::RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode)
- {
- if(aura->IsRemoved())
- return;
- ASSERT(aura->GetOwner() == this);
- uint32 spellId = aura->GetId();
- for(AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId); ++itr)
- {
- if(itr->second == aura)
- {
- RemoveOwnedAura(itr, removeMode);
- return;
- }
- }
- }
- Aura* Unit::GetOwnedAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, Aura* except) const
- {
- for(AuraMap::const_iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId); ++itr)
- if(((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID) && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID) && (!except || except != itr->second))
- return itr->second;
- return NULL;
- }
- void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
- {
- AuraApplication* aurApp = i->second;
- // Do not remove aura which is already being removed
- if(aurApp->GetRemoveMode())
- return;
- Aura* aura = aurApp->GetBase();
- _UnapplyAura(i, mode);
- // Remove aura - for Area and Target auras
- if(aura->GetOwner() == this)
- aura->Remove(mode);
- }
- void Unit::RemoveAura(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
- {
- Aura const* aura = iter->second->GetBase();
- if(((aura->GetEffectMask() & reqEffMask) == reqEffMask)
- && (!caster || aura->GetCasterGUID() == caster))
- {
- RemoveAura(iter, removeMode);
- return;
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAura(AuraApplication* aurApp, AuraRemoveMode mode)
- {
- // we've special situation here, RemoveAura called while during aura removal
- // this kind of call is needed only when aura effect removal handler
- // or event triggered by it expects to remove
- // not yet removed effects of an aura
- if(aurApp->GetRemoveMode())
- {
- // remove remaining effects of an aura
- for(uint8 itr = 0 ; itr < MAX_SPELL_EFFECTS; ++itr)
- {
- if(aurApp->HasEffect(itr))
- aurApp->_HandleEffect(itr, false);
- }
- return;
- }
- // no need to remove
- if(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
- return;
- uint32 spellId = aurApp->GetBase()->GetId();
- for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
- {
- if(aurApp == iter->second)
- {
- RemoveAura(iter, mode);
- return;
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode)
- {
- if(aura->IsRemoved())
- return;
- if(AuraApplication* aurApp = aura->GetApplicationOfTarget(GetGUID()))
- RemoveAura(aurApp, mode);
- }
- void Unit::RemoveAurasDueToSpell(uint32 spellId, uint64 caster, uint8 reqEffMask, AuraRemoveMode removeMode)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
- {
- Aura const* pAura = iter->second->GetBase();
- if(pAura && ((pAura->GetEffectMask() & reqEffMask) == reqEffMask) && (!caster || pAura->GetCasterGUID() == caster))
- {
- RemoveAura(iter, removeMode);
- iter = m_appliedAuras.lower_bound(spellId);
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAuraFromStack(uint32 spellId, uint64 caster, AuraRemoveMode removeMode)
- {
- for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
- {
- Aura* pAura = iter->second;
- if((pAura->GetType() == UNIT_AURA_TYPE) && (!caster || pAura->GetCasterGUID() == caster))
- {
- pAura->ModStackAmount(-1, removeMode);
- return;
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit* dispeller, uint8 chargesRemoved/*= 1*/)
- {
- for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
- {
- Aura* aura = iter->second;
- if(aura->GetCasterGUID() == casterGUID)
- {
- if(aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES)
- aura->ModCharges(-chargesRemoved, AURA_REMOVE_BY_ENEMY_SPELL);
- else
- aura->ModStackAmount(-chargesRemoved, AURA_REMOVE_BY_ENEMY_SPELL);
- switch(aura->GetSpellProto()->SpellFamilyName)
- {
- case SPELLFAMILY_WARLOCK:
- {
- // Unstable Affliction (crash if before removeaura?)
- if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x0100)
- {
- Unit* caster = aura->GetCaster();
- if(!caster)
- break;
- if(AuraEffect const* aurEff = aura->GetEffect(EFFECT_0))
- {
- int32 damage = aurEff->GetAmount() * 9;
- // backfire damage and silence
- caster->CastCustomSpell(dispeller, 31117, &damage, NULL, NULL, true, NULL, aurEff);
- }
- }
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- // Lifebloom
- if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x10)
- {
- if(AuraEffect const* aurEff = aura->GetEffect(EFFECT_1))
- {
- // final heal
- int32 healAmount = aurEff->GetAmount();
- int32 stack = chargesRemoved;
- CastCustomSpell(this, 33778, &healAmount, &stack, NULL, true, NULL, NULL, aura->GetCasterGUID());
- // mana
- if(Unit* caster = aura->GetCaster())
- {
- int32 mana = CalculatePctU(caster->GetCreateMana(), aura->GetSpellProto()->ManaCostPercentage) * chargesRemoved / 2;
- caster->CastCustomSpell(caster, 64372, &mana, NULL, NULL, true, NULL, NULL, aura->GetCasterGUID());
- }
- }
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- // Flame Shock
- if(aura->GetSpellProto()->SpellFamilyFlags[0] & 0x10000000)
- {
- if(Unit* caster = aura->GetCaster())
- {
- uint32 triggeredSpellId = 0;
- // Lava Flows
- if(AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 3087, 0))
- {
- switch(aurEff->GetId())
- {
- case 51482: // Rank 3
- triggeredSpellId = 65264;
- break;
- case 51481: // Rank 2
- triggeredSpellId = 65263;
- break;
- case 51480: // Rank 1
- triggeredSpellId = 64694;
- break;
- default:
- sLog->outError("Unit::RemoveAurasDueToSpellByDispel: Unknown rank of Lava Flows (%d) found", aurEff->GetId());
- }
- }
- if(triggeredSpellId)
- caster->CastSpell(caster, triggeredSpellId, true);
- }
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Wyvern Sting
- if(aura->GetSpellProto()->SpellFamilyFlags[1] & 0x1000)
- {
- Unit* caster = aura->GetCaster();
- if(caster && !(dispeller->GetTypeId() == TYPEID_UNIT && dispeller->ToCreature()->isTotem()))
- { // Noxious Stings
- if(AuraEffect* auraEff = caster->GetAuraEffect(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, SPELLFAMILY_HUNTER, 3521, 1))
- if(Aura* newAura = caster->AddAura(aura->GetId(), dispeller))
- newAura->SetDuration(aura->GetDuration() / 100 * auraEff->GetAmount());
- }
- }
- }
- default:
- break;
- }
- return;
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit* stealer)
- {
- for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
- {
- Aura* aura = iter->second;
- if(aura->GetCasterGUID() == casterGUID)
- {
- int32 damage[MAX_SPELL_EFFECTS];
- int32 baseDamage[MAX_SPELL_EFFECTS];
- uint8 effMask = 0;
- uint8 recalculateMask = 0;
- Unit* caster = aura->GetCaster();
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if(aura->GetEffect(i))
- {
- baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
- damage[i] = aura->GetEffect(i)->GetAmount();
- effMask |= (1<<i);
- if(aura->GetEffect(i)->CanBeRecalculated())
- recalculateMask |= (1<<i);
- }
- else
- {
- baseDamage[i] = 0;
- damage[i] = 0;
- }
- }
- bool stealCharge = aura->GetSpellProto()->AttributesEx7 & SPELL_ATTR7_DISPEL_CHARGES;
- int32 dur = std::min(2 * MINUTE * IN_MILLISECONDS, aura->GetDuration());
- if(Aura* newAura = stealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
- {
- if(stealCharge)
- newAura->ModCharges(1);
- else
- newAura->ModStackAmount(1);
- newAura->SetDuration(dur);
- }
- else
- {
- // single target state must be removed before aura creation to preserve existing single target aura
- if(aura->IsSingleTarget())
- aura->UnregisterSingleTarget();
- if(Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellProto(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID()))
- {
- // created aura must not be single target aura,, so stealer won't loose it on recast
- if(newAura->IsSingleTarget())
- {
- newAura->UnregisterSingleTarget();
- // bring back single target aura status to the old aura
- aura->SetIsSingleTarget(true);
- caster->GetSingleCastAuras().push_back(aura);
- }
- // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
- newAura->SetLoadedState(aura->GetMaxDuration(), dur, stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, &damage[0]);
- newAura->ApplyForTargets();
- }
- }
- if(stealCharge)
- aura->ModCharges(-1, AURA_REMOVE_BY_ENEMY_SPELL);
- else
- aura->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL);
- return;
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAurasDueToItemSpell(Item* castItem, uint32 spellId)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
- {
- if(!castItem || iter->second->GetBase()->GetCastItemGUID() == castItem->GetGUID())
- {
- RemoveAura(iter);
- iter = m_appliedAuras.upper_bound(spellId); // overwrite by more appropriate
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAurasByType(AuraType auraType, uint64 casterGUID, Aura* except, bool negative, bool positive)
- {
- for(AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
- {
- Aura* aura = (*iter)->GetBase();
- AuraApplication* aurApp = aura->GetApplicationOfTarget(GetGUID());
- ++iter;
- if(aurApp && aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
- && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
- {
- uint32 removedAuras = m_removedAurasCount;
- RemoveAura(aurApp);
- if(m_removedAurasCount > removedAuras + 1)
- iter = m_modAuras[auraType].begin();
- }
- }
- }
- void Unit::RemoveAurasWithAttribute(uint32 flags)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- SpellEntry const* spell = iter->second->GetBase()->GetSpellProto();
- if(spell->Attributes & flags)
- RemoveAura(iter);
- else
- ++iter;
- }
- }
- void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
- {
- // single target auras from other casters
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- AuraApplication const* aurApp = iter->second;
- Aura const* aura = aurApp->GetBase();
- if(aura->GetCasterGUID() != GetGUID() && IsSingleTargetSpell(aura->GetSpellProto()))
- {
- if(!newPhase)
- RemoveAura(iter);
- else
- {
- Unit* caster = aura->GetCaster();
- if(!caster || !caster->InSamePhase(newPhase))
- RemoveAura(iter);
- else
- ++iter;
- }
- }
- else
- ++iter;
- }
- // single target auras at other targets
- AuraList& scAuras = GetSingleCastAuras();
- for(AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
- {
- Aura* aura = *iter;
- if(aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase))
- {
- aura->Remove();
- iter = scAuras.begin();
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except)
- {
- if(!(m_interruptMask & flag))
- return;
- // interrupt auras
- for(AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
- {
- Aura* aura = (*iter)->GetBase();
- ++iter;
- if((aura->GetSpellProto()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except))
- {
- uint32 removedAuras = m_removedAurasCount;
- RemoveAura(aura);
- if(m_removedAurasCount > removedAuras + 1)
- iter = m_interruptableAuras.begin();
- }
- }
- // interrupt channeled spell
- if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if(spell->getState() == SPELL_STATE_CASTING
- && (spell->m_spellInfo->ChannelInterruptFlags & flag)
- && spell->m_spellInfo->Id != except)
- InterruptNonMeleeSpells(false);
- UpdateInterruptMask();
- }
- void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if(!casterGUID || aura->GetCasterGUID() == casterGUID)
- {
- SpellEntry const* spell = aura->GetSpellProto();
- if(spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags.HasFlag(familyFlag1, familyFlag2, familyFlag3))
- {
- RemoveAura(iter);
- continue;
- }
- }
- ++iter;
- }
- }
- void Unit::RemoveMovementImpairingAuras()
- {
- RemoveAurasWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_ROOT));
- }
- void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if(!except || aura->GetId() != except)
- {
- if(GetAllSpellMechanicMask(aura->GetSpellProto()) & mechanic_mask)
- {
- RemoveAura(iter, removemode);
- continue;
- }
- }
- ++iter;
- }
- }
- void Unit::RemoveAreaAurasDueToLeaveWorld()
- {
- // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
- for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
- {
- Aura* aura = iter->second;
- ++iter;
- Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
- for(Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
- {
- AuraApplication* aurApp = itr->second;
- ++itr;
- if(Unit* pTarget = aurApp->GetTarget())
- {
- if(pTarget == this)
- continue;
- pTarget->RemoveAura(aurApp);
- // things linked on aura remove may apply new area aura - so start from the beginning
- iter = m_ownedAuras.begin();
- }
- }
- }
- // remove area auras owned by others
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- if(iter->second->GetBase()->GetOwner() != this)
- {
- RemoveAura(iter);
- }
- else
- ++iter;
- }
- }
- void Unit::RemoveAllAuras()
- {
- // this may be a dead loop if some events on aura remove will continiously apply aura on remove
- // we want to have all auras removed, so use your brain when linking events
- while(!m_appliedAuras.empty() || !m_ownedAuras.empty())
- {
- AuraApplicationMap::iterator aurAppIter;
- for(aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
- _UnapplyAura(aurAppIter, AURA_REMOVE_BY_DEFAULT);
- AuraMap::iterator aurIter;
- for(aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
- RemoveOwnedAura(aurIter);
- }
- }
- void Unit::RemoveArenaAuras()
- {
- // in join, remove positive buffs, on end, remove negative
- // used to remove positive visible auras in arenas
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- AuraApplication const* aurApp = iter->second;
- Aura const* aura = aurApp->GetBase();
- if(!(aura->GetSpellProto()->AttributesEx4 & SPELL_ATTR4_UNK21) // don't remove stances, shadowform, pally/hunter auras
- && !aura->IsPassive() // don't remove passive auras
- && (aurApp->IsPositive() || !(aura->GetSpellProto()->AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT))) // not negative death persistent auras
- RemoveAura(iter);
- else
- ++iter;
- }
- }
- void Unit::RemoveAllAurasOnDeath()
- {
- // used just after dieing to remove all visible auras
- // and disable the mods for the passive ones
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if(!aura->IsPassive() && !aura->IsDeathPersistent())
- _UnapplyAura(iter, AURA_REMOVE_BY_DEATH);
- else
- ++iter;
- }
- for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
- {
- Aura* aura = iter->second;
- if(!aura->IsPassive() && !aura->IsDeathPersistent())
- RemoveOwnedAura(iter, AURA_REMOVE_BY_DEATH);
- else
- ++iter;
- }
- }
- void Unit::RemoveAllAurasRequiringDeadTarget()
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if(!aura->IsPassive() && IsRequiringDeadTargetSpell(aura->GetSpellProto()))
- _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
- }
- for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
- {
- Aura* aura = iter->second;
- if(!aura->IsPassive() && IsRequiringDeadTargetSpell(aura->GetSpellProto()))
- RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
- }
- }
- void Unit::RemoveAllAurasExceptType(AuraType type)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if(!IsSpellHaveAura(aura->GetSpellProto(), type))
- _UnapplyAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
- }
- for(AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
- {
- Aura* aura = iter->second;
- if(!IsSpellHaveAura(aura->GetSpellProto(), type))
- RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
- else
- ++iter;
- }
- }
- void Unit::DelayOwnedAuras(uint32 spellId, uint64 caster, int32 delaytime)
- {
- for(AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);++iter)
- {
- Aura* aura = iter->second;
- if(!caster || aura->GetCasterGUID() == caster)
- {
- if(aura->GetDuration() < delaytime)
- aura->SetDuration(0);
- else
- aura->SetDuration(aura->GetDuration() - delaytime);
- // update for out of range group members (on 1 slot use)
- aura->SetNeedClientUpdateForTargets();
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Aura %u partially interrupted on unit %u, new duration: %u ms", aura->GetId(), GetGUIDLow(), aura->GetDuration());
- }
- }
- }
- void Unit::_RemoveAllAuraStatMods()
- {
- for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
- (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
- }
- void Unit::_ApplyAllAuraStatMods()
- {
- for(AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
- (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
- }
- AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
- {
- for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
- if(itr->second->HasEffect(effIndex) && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
- return itr->second->GetBase()->GetEffect(effIndex);
- return NULL;
- }
- AuraEffect* Unit::GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, uint64 caster) const
- {
- uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
- while(true)
- {
- if(AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
- return aurEff;
- SpellChainNode const* chainNode = sSpellMgr->GetSpellChainNode(rankSpell);
- if(!chainNode)
- break;
- else
- rankSpell = chainNode->next;
- }
- return NULL;
- }
- AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
- {
- AuraEffectList const& auras = GetAuraEffectsByType(type);
- for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- if(effIndex != (*itr)->GetEffIndex())
- continue;
- SpellEntry const* spell = (*itr)->GetSpellProto();
- if(spell->SpellIconID == iconId && spell->SpellFamilyName == uint32(name) && !spell->SpellFamilyFlags)
- return *itr;
- }
- return NULL;
- }
- AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID)
- {
- AuraEffectList const& auras = GetAuraEffectsByType(type);
- for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
- {
- SpellEntry const* spell = (*i)->GetSpellProto();
- if(spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags.HasFlag(familyFlag1, familyFlag2, familyFlag3))
- {
- if(casterGUID && (*i)->GetCasterGUID() != casterGUID)
- continue;
- return (*i);
- }
- }
- return NULL;
- }
- AuraApplication* Unit::GetAuraApplication(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
- {
- for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- if(((aura->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || aura->GetCasterGUID() == casterGUID) && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID) && (!except || except != itr->second))
- return itr->second;
- }
- return NULL;
- }
- Aura* Unit::GetAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
- {
- AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
- return aurApp ? aurApp->GetBase() : NULL;
- }
- AuraApplication* Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
- {
- uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
- while(true)
- {
- if(AuraApplication* aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
- return aurApp;
- SpellChainNode const* chainNode = sSpellMgr->GetSpellChainNode(rankSpell);
- if(!chainNode)
- break;
- else
- rankSpell = chainNode->next;
- }
- return NULL;
- }
- Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
- {
- AuraApplication* aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
- return aurApp ? aurApp->GetBase() : NULL;
- }
- bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
- {
- for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
- if(itr->second->HasEffect(effIndex) && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
- return true;
- return false;
- }
- uint32 Unit::GetAuraCount(uint32 spellId) const
- {
- uint32 count = 0;
- for(AuraApplicationMap::const_iterator itr = m_appliedAuras.lower_bound(spellId); itr != m_appliedAuras.upper_bound(spellId); ++itr)
- {
- if(!itr->second->GetBase()->GetStackAmount())
- count++;
- else
- count += (uint32)itr->second->GetBase()->GetStackAmount();
- }
- return count;
- }
- bool Unit::HasAura(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask) const
- {
- if(GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask))
- return true;
- return false;
- }
- bool Unit::HasAuraType(AuraType auraType) const
- {
- return (!m_modAuras[auraType].empty());
- }
- bool Unit::HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const
- {
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if(caster == (*i)->GetCasterGUID())
- return true;
- return false;
- }
- bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const
- {
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if(miscvalue == (*i)->GetMiscValue())
- return true;
- return false;
- }
- bool Unit::HasAuraTypeWithAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
- {
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if((*i)->IsAffectedOnSpell(affectedSpell))
- return true;
- return false;
- }
- bool Unit::HasAuraTypeWithValue(AuraType auratype, int32 value) const
- {
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if(value == (*i)->GetAmount())
- return true;
- return false;
- }
- bool Unit::HasNegativeAuraWithInterruptFlag(uint32 flag, uint64 guid)
- {
- if(!(m_interruptMask & flag))
- return false;
- for(AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
- {
- if(!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellProto()->AuraInterruptFlags & flag && (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
- return true;
- }
- return false;
- }
- bool Unit::HasNegativeAuraWithAttribute(uint32 flag, uint64 guid)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
- {
- Aura const* aura = iter->second->GetBase();
- if(!iter->second->IsPositive() && aura->GetSpellProto()->Attributes & flag && (!guid || aura->GetCasterGUID() == guid))
- return true;
- }
- return false;
- }
- bool Unit::HasAuraWithMechanic(uint32 mechanicMask)
- {
- for(AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
- {
- SpellEntry const* spellInfo = iter->second->GetBase()->GetSpellProto();
- if(spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
- return true;
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if(iter->second->HasEffect(i) && spellInfo->Effect[i] && spellInfo->EffectMechanic[i])
- if(mechanicMask & (1 << spellInfo->EffectMechanic[i]))
- return true;
- }
- return false;
- }
- AuraEffect* Unit::IsScriptOverriden(SpellEntry const* spell, int32 script) const
- {
- AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
- {
- if((*i)->GetMiscValue() == script)
- if((*i)->IsAffectedOnSpell(spell))
- return (*i);
- }
- return NULL;
- }
- uint32 Unit::GetDiseasesByCaster(uint64 casterGUID, bool remove)
- {
- static const AuraType diseaseAuraTypes[] =
- {
- SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
- SPELL_AURA_LINKED, // Crypt Fever and Ebon Plague
- SPELL_AURA_NONE
- };
- uint32 diseases = 0;
- for(AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
- {
- for(AuraEffectList::iterator i = m_modAuras[*itr].begin(); i != m_modAuras[*itr].end();)
- {
- // Get auras with disease dispel type by caster
- if((*i)->GetSpellProto()->Dispel == DISPEL_DISEASE
- && (*i)->GetCasterGUID() == casterGUID)
- {
- ++diseases;
- if(remove)
- {
- RemoveAura((*i)->GetId(), (*i)->GetCasterGUID());
- i = m_modAuras[*itr].begin();
- continue;
- }
- }
- ++i;
- }
- }
- return diseases;
- }
- uint32 Unit::GetDoTsByCaster(uint64 casterGUID) const
- {
- static const AuraType diseaseAuraTypes[] =
- {
- SPELL_AURA_PERIODIC_DAMAGE,
- SPELL_AURA_PERIODIC_DAMAGE_PERCENT,
- SPELL_AURA_NONE
- };
- uint32 dots = 0;
- for(AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
- {
- Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
- for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
- {
- // Get auras by caster
- if((*i)->GetCasterGUID() == casterGUID)
- ++dots;
- }
- }
- return dots;
- }
- int32 Unit::GetTotalAuraModifier(AuraType auratype) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- modifier += (*i)->GetAmount();
- return modifier;
- }
- float Unit::GetTotalAuraMultiplier(AuraType auratype) const
- {
- float multiplier = 1.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- AddPctN(multiplier, (*i)->GetAmount());
- return multiplier;
- }
- int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype)
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- if((*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- return modifier;
- }
- int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue()& misc_mask)
- modifier += (*i)->GetAmount();
- }
- return modifier;
- }
- float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const
- {
- float multiplier = 1.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue()& misc_mask)
- AddPctN(multiplier, (*i)->GetAmount());
- }
- return multiplier;
- }
- int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if(except != (*i) && (*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue() == misc_value)
- modifier += (*i)->GetAmount();
- }
- return modifier;
- }
- float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const
- {
- float multiplier = 1.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue() == misc_value)
- AddPctN(multiplier, (*i)->GetAmount());
- }
- return multiplier;
- }
- int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetTotalAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->IsAffectedOnSpell(affectedSpell))
- modifier += (*i)->GetAmount();
- }
- return modifier;
- }
- float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
- {
- float multiplier = 1.0f;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->IsAffectedOnSpell(affectedSpell))
- AddPctN(multiplier, (*i)->GetAmount());
- }
- return multiplier;
- }
- int32 Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() > modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellEntry const* affectedSpell) const
- {
- int32 modifier = 0;
- AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
- for(AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
- {
- if((*i)->IsAffectedOnSpell(affectedSpell) && (*i)->GetAmount() < modifier)
- modifier = (*i)->GetAmount();
- }
- return modifier;
- }
- void Unit::_RegisterDynObject(DynamicObject* dynObj)
- {
- m_dynObj.push_back(dynObj);
- }
- void Unit::_UnregisterDynObject(DynamicObject* dynObj)
- {
- m_dynObj.remove(dynObj);
- }
- DynamicObject* Unit::GetDynObject(uint32 spellId)
- {
- if(m_dynObj.empty())
- return NULL;
- for(DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end();++i)
- {
- DynamicObject* dynObj = *i;
- if(dynObj->GetSpellId() == spellId)
- return dynObj;
- }
- return NULL;
- }
- void Unit::RemoveDynObject(uint32 spellId)
- {
- if(m_dynObj.empty())
- return;
- for(DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
- {
- DynamicObject* dynObj = *i;
- if(dynObj->GetSpellId() == spellId)
- {
- dynObj->Remove();
- i = m_dynObj.begin();
- }
- else
- ++i;
- }
- }
- void Unit::RemoveAllDynObjects()
- {
- while(!m_dynObj.empty())
- m_dynObj.front()->Remove();
- }
- GameObject* Unit::GetGameObject(uint32 spellId) const
- {
- for(GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
- if((*i)->GetSpellId() == spellId)
- return *i;
- return NULL;
- }
- void Unit::AddGameObject(GameObject* gameObj)
- {
- if(!gameObj || !gameObj->GetOwnerGUID() == 0) return;
- m_gameObj.push_back(gameObj);
- gameObj->SetOwnerGUID(GetGUID());
- if(GetTypeId() == TYPEID_PLAYER && gameObj->GetSpellId())
- {
- SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
- // Need disable spell use for owner
- if(createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
- ToPlayer()->AddSpellAndCategoryCooldowns(createBySpell, 0, NULL, true);
- }
- }
- void Unit::RemoveGameObject(GameObject* gameObj, bool del)
- {
- if(!gameObj || !gameObj->GetOwnerGUID() == GetGUID()) return;
- gameObj->SetOwnerGUID(0);
- for(uint32 i = 0; i < 4; ++i)
- {
- if(m_ObjectSlot[i] == gameObj->GetGUID())
- {
- m_ObjectSlot[i] = 0;
- break;
- }
- }
- // GO created by some spell
- if(uint32 spellid = gameObj->GetSpellId())
- {
- RemoveAurasDueToSpell(spellid);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- SpellEntry const* createBySpell = sSpellStore.LookupEntry(spellid);
- // Need activate spell use for owner
- if(createBySpell && createBySpell->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE)
- // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
- ToPlayer()->SendCooldownEvent(createBySpell);
- }
- }
- m_gameObj.remove(gameObj);
- if(del)
- {
- gameObj->SetRespawnTime(0);
- gameObj->Delete();
- }
- }
- void Unit::RemoveGameObject(uint32 spellid, bool del)
- {
- if(m_gameObj.empty())
- return;
- GameObjectList::iterator i, next;
- for(i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
- {
- next = i;
- if(spellid == 0 || (*i)->GetSpellId() == spellid)
- {
- (*i)->SetOwnerGUID(0);
- if(del)
- {
- (*i)->SetRespawnTime(0);
- (*i)->Delete();
- }
- next = m_gameObj.erase(i);
- }
- else
- ++next;
- }
- }
- void Unit::RemoveAllGameObjects()
- {
- // remove references to unit
- for(GameObjectList::iterator i = m_gameObj.begin(); i != m_gameObj.end();)
- {
- (*i)->SetOwnerGUID(0);
- (*i)->SetRespawnTime(0);
- (*i)->Delete();
- i = m_gameObj.erase(i);
- }
- }
- void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
- {
- WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+4+1+4+4+1+1+4+4+1)); // we guess size
- data.append(log->target->GetPackGUID());
- data.append(log->attacker->GetPackGUID());
- data << uint32(log->SpellID);
- data << uint32(log->damage); // damage amount
- int32 overkill = log->damage - log->target->GetHealth();
- data << uint32(overkill > 0 ? overkill : 0); // overkill
- data << uint8 (log->schoolMask); // damage school
- data << uint32(log->absorb); // AbsorbedDamage
- data << uint32(log->resist); // resist
- data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
- data << uint8 (log->unused); // unused
- data << uint32(log->blocked); // blocked
- data << uint32(log->HitInfo);
- data << uint8 (0); // flag to use extend data
- SendMessageToSet(&data, true);
- }
- void Unit::SendSpellNonMeleeDamageLog(Unit* target, uint32 SpellID, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
- {
- SpellNonMeleeDamage log(this, target, SpellID, damageSchoolMask);
- log.damage = Damage - AbsorbedDamage - Resist - Blocked;
- log.absorb = AbsorbedDamage;
- log.resist = Resist;
- log.physicalLog = PhysicalDamage;
- log.blocked = Blocked;
- log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6;
- if(CriticalHit)
- log.HitInfo |= SPELL_HIT_TYPE_CRIT;
- SendSpellNonMeleeDamageLog(&log);
- }
- void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const* procSpell, SpellEntry const* procAura)
- {
- // Not much to do if no flags are set.
- if(procAttacker)
- ProcDamageAndSpellFor(false, victim, procAttacker, procExtra, attType, procSpell, amount, procAura);
- // Now go on with a victim's events'n'auras
- // Not much to do if no flags are set or there is no victim
- if(victim && victim->isAlive() && procVictim)
- victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura);
- }
- void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
- {
- AuraEffect const* aura = pInfo->auraEff;
- WorldPacket data(SMSG_PERIODICAURALOG, 30);
- data.append(GetPackGUID());
- data.appendPackGUID(aura->GetCasterGUID());
- data << uint32(aura->GetId()); // spellId
- data << uint32(1); // count
- data << uint32(aura->GetAuraType()); // auraId
- switch(aura->GetAuraType())
- {
- case SPELL_AURA_PERIODIC_DAMAGE:
- case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
- data << uint32(pInfo->damage); // damage
- data << uint32(pInfo->overDamage); // overkill?
- data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
- data << uint32(pInfo->absorb); // absorb
- data << uint32(pInfo->resist); // resist
- data << uint8(pInfo->critical); // new 3.1.2 critical tick
- break;
- case SPELL_AURA_PERIODIC_HEAL:
- case SPELL_AURA_OBS_MOD_HEALTH:
- data << uint32(pInfo->damage); // damage
- data << uint32(pInfo->overDamage); // overheal
- data << uint32(pInfo->absorb); // absorb
- data << uint8(pInfo->critical); // new 3.1.2 critical tick
- break;
- case SPELL_AURA_OBS_MOD_POWER:
- case SPELL_AURA_PERIODIC_ENERGIZE:
- data << uint32(aura->GetMiscValue()); // power type
- data << uint32(pInfo->damage); // damage
- break;
- case SPELL_AURA_PERIODIC_MANA_LEECH:
- data << uint32(aura->GetMiscValue()); // power type
- data << uint32(pInfo->damage); // amount
- data << float(pInfo->multiplier); // gain multiplier
- break;
- default:
- sLog->outError("Unit::SendPeriodicAuraLog: unknown aura %u", uint32(aura->GetAuraType()));
- return;
- }
- SendMessageToSet(&data, true);
- }
- void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo)
- {
- WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
- data << uint32(spellID);
- data << uint64(GetGUID());
- data << uint8(0); // can be 0 or 1
- data << uint32(1); // target count
- // for(i = 0; i < target count; ++i)
- data << uint64(target->GetGUID()); // target GUID
- data << uint8(missInfo);
- // end loop
- SendMessageToSet(&data, true);
- }
- void Unit::SendSpellDamageResist(Unit* target, uint32 spellId)
- {
- WorldPacket data(SMSG_PROCRESIST, 8+8+4+1);
- data << uint64(GetGUID());
- data << uint64(target->GetGUID());
- data << uint32(spellId);
- data << uint8(0); // bool - log format: 0-default, 1-debug
- SendMessageToSet(&data, true);
- }
- void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId)
- {
- WorldPacket data(SMSG_SPELLORDAMAGE_IMMUNE, 8+8+4+1);
- data << uint64(GetGUID());
- data << uint64(target->GetGUID());
- data << uint32(spellId);
- data << uint8(0); // bool - log format: 0-default, 1-debug
- SendMessageToSet(&data, true);
- }
- void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
- {
- sLog->outDebug(LOG_FILTER_UNITS, "WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
- uint32 count = 1;
- size_t maxsize = 4+5+5+4+4+1+4+4+4+4+4+1+4+4+4+4+4*12;
- WorldPacket data(SMSG_ATTACKERSTATEUPDATE, maxsize); // we guess size
- data << uint32(damageInfo->HitInfo);
- data.append(damageInfo->attacker->GetPackGUID());
- data.append(damageInfo->target->GetPackGUID());
- data << uint32(damageInfo->damage); // Full damage
- int32 overkill = damageInfo->damage - damageInfo->target->GetHealth();
- data << uint32(overkill < 0 ? 0 : overkill); // Overkill
- data << uint8(count); // Sub damage count
- for(uint32 i = 0; i < count; ++i)
- {
- data << uint32(damageInfo->damageSchoolMask); // School of sub damage
- data << float(damageInfo->damage); // sub damage
- data << uint32(damageInfo->damage); // Sub Damage
- }
- if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2))
- {
- for(uint32 i = 0; i < count; ++i)
- data << uint32(damageInfo->absorb); // Absorb
- }
- if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2))
- {
- for(uint32 i = 0; i < count; ++i)
- data << uint32(damageInfo->resist); // Resist
- }
- data << uint8(damageInfo->TargetState);
- data << uint32(0);
- data << uint32(0);
- if(damageInfo->HitInfo & HITINFO_BLOCK)
- data << uint32(damageInfo->blocked_amount);
- if(damageInfo->HitInfo & HITINFO_UNK3)
- data << uint32(0);
- if(damageInfo->HitInfo & HITINFO_UNK1)
- {
- data << uint32(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0);
- data << float(0); // Found in a loop with 1 iteration
- data << float(0); // ditto ^
- data << uint32(0);
- }
- SendMessageToSet(&data, true);
- }
- void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
- {
- CalcDamageInfo dmgInfo;
- dmgInfo.HitInfo = HitInfo;
- dmgInfo.attacker = this;
- dmgInfo.target = target;
- dmgInfo.damage = Damage - AbsorbDamage - Resist - BlockedAmount;
- dmgInfo.damageSchoolMask = damageSchoolMask;
- dmgInfo.absorb = AbsorbDamage;
- dmgInfo.resist = Resist;
- dmgInfo.TargetState = TargetState;
- dmgInfo.blocked_amount = BlockedAmount;
- SendAttackStateUpdate(&dmgInfo);
- }
- bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
- {
- SpellEntry const* hasteSpell = triggeredByAura->GetSpellProto();
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
- switch(hasteSpell->SpellFamilyName)
- {
- case SPELLFAMILY_ROGUE:
- {
- switch(hasteSpell->Id)
- {
- // Blade Flurry
- case 13877:
- case 33735:
- {
- target = SelectNearbyTarget(victim);
- if(!target)
- return false;
- basepoints0 = damage;
- triggered_spell_id = 22482;
- break;
- }
- }
- break;
- }
- }
- // processed charge only counting case
- if(!triggered_spell_id)
- return true;
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", hasteSpell->Id, triggered_spell_id);
- return false;
- }
- // default case
- if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
- return false;
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if(basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
- {
- SpellEntry const* triggeredByAuraSpell = triggeredByAura->GetSpellProto();
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
- switch(triggeredByAuraSpell->SpellFamilyName)
- {
- case SPELLFAMILY_MAGE:
- {
- switch(triggeredByAuraSpell->Id)
- {
- // Focus Magic
- case 54646:
- {
- Unit* caster = triggeredByAura->GetCaster();
- if(!caster)
- return false;
- triggered_spell_id = 54648;
- target = caster;
- break;
- }
- }
- }
- }
- // processed charge only counting case
- if(!triggered_spell_id)
- return true;
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleHasteAuraProc: Spell %u have not existed triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id);
- return false;
- }
- // default case
- if(!target || (target != this && !target->isAlive()))
- return false;
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if(basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
- {
- SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
- uint32 effIndex = triggeredByAura->GetEffIndex();
- int32 triggerAmount = triggeredByAura->GetAmount();
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- uint32 cooldown_spell_id = 0; // for random trigger, will be one of the triggered spell to avoid repeatable triggers
- // otherwise, it's the triggered_spell_id by default
- Unit* target = victim;
- int32 basepoints0 = 0;
- uint64 originalCaster = 0;
- switch(dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- switch(dummySpell->Id)
- {
- // Bloodworms Health Leech
- case 50453:
- {
- Unit* pOwner = GetOwner();
- if(pOwner)
- {
- basepoints0 = int32(damage * 1.50f);
- target = pOwner;
- triggered_spell_id = 50454;
- break;
- }
- return false;
- }
- // Eye for an Eye
- case 9799:
- case 25988:
- {
- // return damage % to attacker but < 50% own total health
- basepoints0 = int32(std::min(CalculatePctN(damage, triggerAmount), CountPctFromMaxHealth(50)));
- triggered_spell_id = 25997;
- break;
- }
- // Sweeping Strikes
- case 18765:
- case 35429:
- {
- if(HasAura(46924))
- return false;
- target = SelectNearbyTarget(victim);
- if(!target)
- return false;
- triggered_spell_id = 26654;
- break;
- }
- // Wrecking Crew
- case 46867:
- {
- if(!procSpell)
- return false;
- triggered_spell_id = 57518;
- break;
- }
- // Unstable Power
- case 24658:
- {
- if(!procSpell || procSpell->Id == 24659)
- return false;
- // Need remove one 24659 aura
- RemoveAuraFromStack(24659);
- return true;
- }
- // Restless Strength
- case 24661:
- {
- // Need remove one 24662 aura
- RemoveAuraFromStack(24662);
- return true;
- }
- // Adaptive Warding (Frostfire Regalia set)
- case 28764:
- {
- if(!procSpell)
- return false;
- // find Mage Armor
- if(!GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0, 0))
- return false;
- switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
- {
- case SPELL_SCHOOL_NORMAL:
- case SPELL_SCHOOL_HOLY:
- return false; // ignored
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
- default:
- return false;
- }
- target = this;
- break;
- }
- // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
- case 27539:
- {
- if(!procSpell)
- return false;
- switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
- {
- case SPELL_SCHOOL_NORMAL:
- return false; // ignore
- case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
- default:
- return false;
- }
- target = this;
- break;
- }
- // Mana Leech (Passive) (Priest Pet Aura)
- case 28305:
- {
- // Cast on owner
- target = GetOwner();
- if(!target)
- return false;
- triggered_spell_id = 34650;
- break;
- }
- // Mark of Malice
- case 33493:
- {
- // Cast finish spell at last charge
- if(triggeredByAura->GetBase()->GetCharges() > 1)
- return false;
- target = this;
- triggered_spell_id = 33494;
- break;
- }
- // Twisted Reflection (boss spell)
- case 21063:
- triggered_spell_id = 21064;
- break;
- // Vampiric Aura (boss spell)
- case 38196:
- {
- basepoints0 = 3 * damage; // 300%
- if(basepoints0 < 0)
- return false;
- triggered_spell_id = 31285;
- target = this;
- break;
- }
- // Aura of Madness (Darkmoon Card: Madness trinket)
- //=====================================================
- // 39511 Sociopath: +35 strength (Paladin, Rogue, Druid, Warrior)
- // 40997 Delusional: +70 attack power (Rogue, Hunter, Paladin, Warrior, Druid)
- // 40998 Kleptomania: +35 agility (Warrior, Rogue, Paladin, Hunter, Druid)
- // 40999 Megalomania: +41 damage/healing (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- // 41002 Paranoia: +35 spell/melee/ranged crit strike rating (All classes)
- // 41005 Manic: +35 haste (spell, melee and ranged) (All classes)
- // 41009 Narcissism: +35 intellect (Druid, Shaman, Priest, Warlock, Mage, Paladin, Hunter)
- // 41011 Martyr Complex: +35 stamina (All classes)
- // 41406 Dementia: Every 5 seconds either gives you +5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- // 41409 Dementia: Every 5 seconds either gives you -5% damage/healing. (Druid, Shaman, Priest, Warlock, Mage, Paladin)
- case 39446:
- {
- if(GetTypeId() != TYPEID_PLAYER || !isAlive())
- return false;
- // Select class defined buff
- switch(getClass())
- {
- case CLASS_PALADIN: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
- case CLASS_DRUID: // 39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409
- triggered_spell_id = RAND(39511, 40997, 40998, 40999, 41002, 41005, 41009, 41011, 41409);
- cooldown_spell_id = 39511;
- break;
- case CLASS_ROGUE: // 39511, 40997, 40998, 41002, 41005, 41011
- case CLASS_WARRIOR: // 39511, 40997, 40998, 41002, 41005, 41011
- case CLASS_DEATH_KNIGHT: // 39511, 40997, 40998, 41002, 41005, 41011
- triggered_spell_id = RAND(39511, 40997, 40998, 41002, 41005, 41011);
- cooldown_spell_id = 39511;
- break;
- case CLASS_PRIEST: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_SHAMAN: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_MAGE: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- case CLASS_WARLOCK: // 40999, 41002, 41005, 41009, 41011, 41406, 41409
- triggered_spell_id = RAND(40999, 41002, 41005, 41009, 41011, 41406, 41409);
- cooldown_spell_id = 40999;
- break;
- case CLASS_HUNTER: // 40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409
- triggered_spell_id = RAND(40997, 40999, 41002, 41005, 41009, 41011, 41406, 41409);
- cooldown_spell_id = 40997;
- break;
- default:
- return false;
- }
- target = this;
- if(roll_chance_i(10))
- ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); // TODO: It should be moved to database, shouldn't it?
- break;
- }
- // Sunwell Exalted Caster Neck (??? neck)
- // cast ??? Light's Wrath if Exalted by Aldor
- // cast ??? Arcane Bolt if Exalted by Scryers
- case 46569:
- return false; // old unused version
- // Sunwell Exalted Caster Neck (Shattered Sun Pendant of Acumen neck)
- // cast 45479 Light's Wrath if Exalted by Aldor
- // cast 45429 Arcane Bolt if Exalted by Scryers
- case 45481:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // Get Aldor reputation rank
- if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45479;
- break;
- }
- // Get Scryers reputation rank
- if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- // triggered at positive/self casts also, current attack target used then
- if(IsFriendlyTo(target))
- {
- target = getVictim();
- if(!target)
- {
- uint64 selected_guid = ToPlayer()->GetSelection();
- target = ObjectAccessor::GetUnit(*this, selected_guid);
- if(!target)
- return false;
- }
- if(IsFriendlyTo(target))
- return false;
- }
- triggered_spell_id = 45429;
- break;
- }
- return false;
- }
- // Sunwell Exalted Melee Neck (Shattered Sun Pendant of Might neck)
- // cast 45480 Light's Strength if Exalted by Aldor
- // cast 45428 Arcane Strike if Exalted by Scryers
- case 45482:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // Get Aldor reputation rank
- if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45480;
- break;
- }
- // Get Scryers reputation rank
- if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- triggered_spell_id = 45428;
- break;
- }
- return false;
- }
- // Sunwell Exalted Tank Neck (Shattered Sun Pendant of Resolve neck)
- // cast 45431 Arcane Insight if Exalted by Aldor
- // cast 45432 Light's Ward if Exalted by Scryers
- case 45483:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // Get Aldor reputation rank
- if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45432;
- break;
- }
- // Get Scryers reputation rank
- if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45431;
- break;
- }
- return false;
- }
- // Sunwell Exalted Healer Neck (Shattered Sun Pendant of Restoration neck)
- // cast 45478 Light's Salvation if Exalted by Aldor
- // cast 45430 Arcane Surge if Exalted by Scryers
- case 45484:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // Get Aldor reputation rank
- if(ToPlayer()->GetReputationRank(932) == REP_EXALTED)
- {
- target = this;
- triggered_spell_id = 45478;
- break;
- }
- // Get Scryers reputation rank
- if(ToPlayer()->GetReputationRank(934) == REP_EXALTED)
- {
- triggered_spell_id = 45430;
- break;
- }
- return false;
- }
- // Living Seed
- case 48504:
- {
- triggered_spell_id = 48503;
- basepoints0 = triggerAmount;
- target = this;
- break;
- }
- // Kill command
- case 58914:
- {
- // Remove aura stack from pet
- RemoveAuraFromStack(58914);
- Unit* owner = GetOwner();
- if(!owner)
- return true;
- // reduce the owner's aura stack
- owner->RemoveAuraFromStack(34027);
- return true;
- }
- // Vampiric Touch (generic, used by some boss)
- case 52723:
- case 60501:
- {
- triggered_spell_id = 52724;
- basepoints0 = damage / 2;
- target = this;
- break;
- }
- // Shadowfiend Death (Gain mana if pet dies with Glyph of Shadowfiend)
- case 57989:
- {
- Unit* owner = GetOwner();
- if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return false;
- // Glyph of Shadowfiend (need cast as self cast for owner, no hidden cooldown)
- owner->CastSpell(owner, 58227, true, castItem, triggeredByAura);
- return true;
- }
- // Divine purpose
- case 31871:
- case 31872:
- {
- // Roll chane
- if(!victim || !victim->isAlive() || !roll_chance_i(triggerAmount))
- return false;
- // Remove any stun effect on target
- victim->RemoveAurasWithMechanic(1<<MECHANIC_STUN, AURA_REMOVE_BY_ENEMY_SPELL);
- return true;
- }
- // Glyph of Scourge Strike
- case 58642:
- {
- triggered_spell_id = 69961; // Glyph of Scourge Strike
- break;
- }
- // Glyph of Life Tap
- case 63320:
- {
- triggered_spell_id = 63321; // Life Tap
- break;
- }
- // Purified Shard of the Scale - Onyxia 10 Caster Trinket
- case 69755:
- {
- triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69733 : 69729;
- break;
- }
- // Shiny Shard of the Scale - Onyxia 25 Caster Trinket
- case 69739:
- {
- triggered_spell_id = (procFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS) ? 69734 : 69730;
- break;
- }
- case 71519: // Deathbringer's Will Normal
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- std::vector<uint32> RandomSpells;
- switch(getClass())
- {
- case CLASS_WARRIOR:
- case CLASS_PALADIN:
- case CLASS_DEATH_KNIGHT:
- RandomSpells.push_back(71484);
- RandomSpells.push_back(71491);
- RandomSpells.push_back(71492);
- break;
- case CLASS_SHAMAN:
- case CLASS_ROGUE:
- RandomSpells.push_back(71486);
- RandomSpells.push_back(71485);
- RandomSpells.push_back(71492);
- break;
- case CLASS_DRUID:
- RandomSpells.push_back(71484);
- RandomSpells.push_back(71485);
- RandomSpells.push_back(71486);
- break;
- case CLASS_HUNTER:
- RandomSpells.push_back(71486);
- RandomSpells.push_back(71491);
- RandomSpells.push_back(71485);
- break;
- default:
- return false;
- }
- if(RandomSpells.empty()) // shouldn't happen
- return false;
- uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
- CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
- for(std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
- {
- if(!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 50362, time(NULL) + 105);
- }
- break;
- }
- case 71562: // Deathbringer's Will Heroic
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- std::vector<uint32> RandomSpells;
- switch(getClass())
- {
- case CLASS_WARRIOR:
- case CLASS_PALADIN:
- case CLASS_DEATH_KNIGHT:
- RandomSpells.push_back(71561);
- RandomSpells.push_back(71559);
- RandomSpells.push_back(71560);
- break;
- case CLASS_SHAMAN:
- case CLASS_ROGUE:
- RandomSpells.push_back(71558);
- RandomSpells.push_back(71556);
- RandomSpells.push_back(71560);
- break;
- case CLASS_DRUID:
- RandomSpells.push_back(71561);
- RandomSpells.push_back(71556);
- RandomSpells.push_back(71558);
- break;
- case CLASS_HUNTER:
- RandomSpells.push_back(71558);
- RandomSpells.push_back(71559);
- RandomSpells.push_back(71556);
- break;
- default:
- return false;
- }
- if(RandomSpells.empty()) // shouldn't happen
- return false;
- uint8 rand_spell = irand(0, (RandomSpells.size() - 1));
- CastSpell(target, RandomSpells[rand_spell], true, castItem, triggeredByAura, originalCaster);
- for(std::vector<uint32>::iterator itr = RandomSpells.begin(); itr != RandomSpells.end(); ++itr)
- {
- if(!ToPlayer()->HasSpellCooldown(*itr))
- ToPlayer()->AddSpellCooldown(*itr, 50363, time(NULL) + 105);
- }
- break;
- }
- case 71875: // Item - Black Bruise: Necrotic Touch Proc
- case 71877:
- {
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 71879;
- break;
- }
- // Item - Shadowmourne Legendary
- case 71903:
- {
- if(!victim || !victim->isAlive() || HasAura(73422)) // cant collect shards while under effect of Chaos Bane buff
- return false;
- CastSpell(this, 71905, true, NULL, triggeredByAura);
- // this can't be handled in AuraScript because we need to know victim
- Aura const* dummy = GetAura(71905);
- if(!dummy || dummy->GetStackAmount() < 10)
- return false;
- RemoveAurasDueToSpell(71905);
- triggered_spell_id = 71904;
- target = victim;
- break;
- }
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- target = triggeredByAura->GetCaster();
- if(!target)
- return false;
- Player* player = target->ToPlayer();
- if(!player)
- return false;
- // not checking Infusion auras because its in targetAuraSpell of credit spell
- if(player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Unholy Infusion
- {
- if(GetEntry() != 36678) // Professor Putricide
- return false;
- CastSpell(target, 71518, true); // Quest Credit
- return true;
- }
- else if(player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Blood Infusion
- {
- if(GetEntry() != 37955) // Blood-Queen Lana'thel
- return false;
- CastSpell(target, 72934, true); // Quest Credit
- return true;
- }
- else if(player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Frost Infusion
- {
- if(GetEntry() != 36853) // Sindragosa
- return false;
- CastSpell(target, 72289, true); // Quest Credit
- return true;
- }
- else if(player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) // A Feast of Souls
- triggered_spell_id = 71203;
- break;
- }
- // Gaseous Bloat (Professor Putricide add)
- case 70215:
- case 72858:
- case 72859:
- case 72860:
- {
- target = getVictim();
- triggered_spell_id = 70701;
- break;
- }
- // Essence of the Blood Queen
- case 70871:
- {
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- CastCustomSpell(70872, SPELLVALUE_BASE_POINT0, basepoints0, this);
- return true;
- }
- case 65032: // Boom aura (321 Boombot)
- {
- if(victim->GetEntry() != 33343) // Scrapbot
- return false;
- InstanceScript* pInstance = GetInstanceScript();
- if(!pInstance)
- return false;
- pInstance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
- break;
- }
- // Meteor Fists
- case 66725:
- {
- target = getVictim();
- triggered_spell_id = 66765;
- InstanceScript* instance = GetInstanceScript();
- if(!instance)
- return false;
- instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Magic Absorption
- if(dummySpell->SpellIconID == 459) // only this spell have SpellIconID == 459 and dummy aura
- {
- if(getPowerType() != POWER_MANA)
- return false;
- // mana reward
- basepoints0 = CalculatePctN(int32(GetMaxPower(POWER_MANA)), triggerAmount);
- target = this;
- triggered_spell_id = 29442;
- break;
- }
- // Master of Elements
- if(dummySpell->SpellIconID == 1920)
- {
- if(!procSpell)
- return false;
- // mana cost save
- int32 cost = int32(procSpell->manaCost + CalculatePctU(GetCreateMana(), procSpell->ManaCostPercentage));
- basepoints0 = CalculatePctN(cost, triggerAmount);
- if(basepoints0 <= 0)
- return false;
- target = this;
- triggered_spell_id = 29077;
- break;
- }
- // Arcane Potency
- if(dummySpell->SpellIconID == 2120)
- {
- if(!procSpell)
- return false;
- target = this;
- switch(dummySpell->Id)
- {
- case 31571: triggered_spell_id = 57529; break;
- case 31572: triggered_spell_id = 57531; break;
- default:
- sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u", dummySpell->Id);
- return false;
- }
- break;
- }
- // Hot Streak
- if(dummySpell->SpellIconID == 2999)
- {
- if(effIndex != 0)
- return false;
- AuraEffect* counter = triggeredByAura->GetBase()->GetEffect(EFFECT_1);
- if(!counter)
- return true;
- // Count spell criticals in a row in second aura
- if(procEx & PROC_EX_CRITICAL_HIT)
- {
- counter->SetAmount(counter->GetAmount() * 2);
- if(counter->GetAmount() < 100) // not enough
- return true;
- // Crititcal counted -> roll chance
- if(roll_chance_i(triggerAmount))
- CastSpell(this, 48108, true, castItem, triggeredByAura);
- }
- counter->SetAmount(25);
- return true;
- }
- // Burnout
- if(dummySpell->SpellIconID == 2998)
- {
- if(!procSpell)
- return false;
- int32 cost = int32(procSpell->manaCost + CalculatePctU(GetCreateMana(), procSpell->ManaCostPercentage));
- basepoints0 = CalculatePctN(cost, triggerAmount);
- if(basepoints0 <= 0)
- return false;
- triggered_spell_id = 44450;
- target = this;
- break;
- }
- // Incanter's Regalia set (add trigger chance to Mana Shield)
- if(dummySpell->SpellFamilyFlags[0] & 0x8000)
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- target = this;
- triggered_spell_id = 37436;
- break;
- }
- switch(dummySpell->Id)
- {
- case 70752: // Mage T10 2P Bonus
- {
- triggered_spell_id = 70753;
- break;
- }
- case 56250: // Glyph of Seduction
- case 56375: // Glyph of Polymorph
- {
- if(!target)
- return false;
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE, 0, target->GetAura(32409)); // SW:D shall not be removed.
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
- target->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
- return true;
- }
- case 56374: // Glyph of Icy Veins
- {
- RemoveAurasByType(SPELL_AURA_HASTE_SPELLS, 0, 0, true, false);
- RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
- return true;
- }
- case 11119: // Ignite
- case 11120:
- case 12846:
- case 12847:
- case 12848:
- {
- switch(dummySpell->Id)
- {
- case 11119: basepoints0 = int32(0.08f * damage); break;
- case 11120: basepoints0 = int32(0.16f * damage); break;
- case 12846: basepoints0 = int32(0.24f * damage); break;
- case 12847: basepoints0 = int32(0.32f * damage); break;
- case 12848: basepoints0 = int32(0.40f * damage); break;
- default:
- sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (IG)", dummySpell->Id);
- return false;
- }
- // 2 damage tick
- basepoints0 /= 2;
- triggered_spell_id = 12654;
- // Add remaining ticks to damage done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- // Glyph of Ice Block
- case 56372:
- {
- Player* plr = ToPlayer();
- if(!plr)
- return false;
- SpellCooldowns const cooldowns = plr->GetSpellCooldowns();
- // remove cooldowns on all ranks of Frost Nova
- for(SpellCooldowns::const_iterator itr = cooldowns.begin(); itr != cooldowns.end(); ++itr)
- {
- SpellEntry const* cdSpell = sSpellStore.LookupEntry(itr->first);
- // Frost Nova
- if(cdSpell && cdSpell->SpellFamilyName == SPELLFAMILY_MAGE
- && cdSpell->SpellFamilyFlags[0] & 0x00000040)
- plr->RemoveSpellCooldown(cdSpell->Id, true);
- }
- break;
- }
- // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
- case 64411:
- {
- if(!victim)
- return false;
- basepoints0 = int32(CalculatePctN(damage, 15));
- if(AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID()))
- {
- // The shield can grow to a maximum size of 20, 000 damage absorbtion
- aurEff->SetAmount(std::min<int32>(aurEff->GetAmount() + basepoints0, 20000));
- // Refresh and return to prevent replacing the aura
- aurEff->GetBase()->RefreshDuration();
- return true;
- }
- target = victim;
- triggered_spell_id = 64413;
- break;
- }
- case 47020: // Enter vehicle XT-002 (Scrapbot)
- {
- if(GetTypeId() != TYPEID_UNIT)
- return false;
- Unit* vehicleBase = GetVehicleBase();
- if(!vehicleBase)
- return false;
- // Todo: Check if this amount is blizzlike
- vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1)));
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- switch(dummySpell->Id)
- {
- // Sweeping Strikes
- case 12328:
- {
- if(HasAura(46924))
- return false;
- target = SelectNearbyTarget(victim);
- if(!target)
- return false;
- triggered_spell_id = 26654;
- break;
- }
- // Victorious
- case 32216:
- {
- RemoveAura(dummySpell->Id);
- return false;
- }
- // Improved Spell Reflection
- case 59088:
- case 59089:
- {
- triggered_spell_id = 59725;
- target = this;
- break;
- }
- }
- // Retaliation
- if(dummySpell->SpellFamilyFlags[1] & 0x8)
- {
- // check attack comes not from behind
- if(!HasInArc(M_PI, victim))
- return false;
- triggered_spell_id = 22858;
- break;
- }
- // Second Wind
- if(dummySpell->SpellIconID == 1697)
- {
- // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example)
- if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
- // Need stun or root mechanic
- if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_STUN))))
- return false;
- switch(dummySpell->Id)
- {
- case 29838: triggered_spell_id = 29842; break;
- case 29834: triggered_spell_id = 29841; break;
- case 42770: triggered_spell_id = 42771; break;
- default:
- sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)", dummySpell->Id);
- return false;
- }
- target = this;
- break;
- }
- // Damage Shield
- if(dummySpell->SpellIconID == 3214)
- {
- // to prevent proc from Sap
- if(procSpell && procSpell->AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH)
- return false;
- triggered_spell_id = 59653;
- // % of amount blocked
- basepoints0 = CalculatePctN(int32(GetShieldBlockValue()), triggerAmount);
- break;
- }
- // Glyph of Blocking
- if(dummySpell->Id == 58375)
- {
- triggered_spell_id = 58374;
- break;
- }
- // Glyph of Sunder Armor
- if(dummySpell->Id == 58387)
- {
- if(!victim || !victim->isAlive() || !procSpell)
- return false;
- target = SelectNearbyTarget(victim);
- if(!target)
- return false;
- triggered_spell_id = 58567;
- break;
- }
- break;
- }
- case SPELLFAMILY_WARLOCK:
- {
- // Seed of Corruption
- if(dummySpell->SpellFamilyFlags[1] & 0x00000010)
- {
- if(procSpell && procSpell->SpellFamilyFlags[1] & 0x8000)
- return false;
- // if damage is more than need or target die from damage deal finish spell
- if(triggeredByAura->GetAmount() <= int32(damage) || GetHealth() <= damage)
- {
- // remember guid before aura delete
- uint64 casterGuid = triggeredByAura->GetCasterGUID();
- // Remove aura (before cast for prevent infinite loop handlers)
- RemoveAurasDueToSpell(triggeredByAura->GetId());
- uint32 spell = sSpellMgr->GetSpellWithRank(27285, sSpellMgr->GetSpellRank(dummySpell->Id));
- // Cast finish spell (triggeredByAura already not exist!)
- if(Unit* caster = GetUnit(*this, casterGuid))
- caster->CastSpell(this, spell, true, castItem);
- return true; // no hidden cooldown
- }
- // Damage counting
- triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
- return true;
- }
- // Seed of Corruption (Mobs cast) - no die req
- if(dummySpell->SpellFamilyFlags.IsEqual(0, 0, 0) && dummySpell->SpellIconID == 1932)
- {
- // if damage is more than need deal finish spell
- if(triggeredByAura->GetAmount() <= int32(damage))
- {
- // remember guid before aura delete
- uint64 casterGuid = triggeredByAura->GetCasterGUID();
- // Remove aura (before cast for prevent infinite loop handlers)
- RemoveAurasDueToSpell(triggeredByAura->GetId());
- // Cast finish spell (triggeredByAura already not exist!)
- if(Unit* caster = GetUnit(*this, casterGuid))
- caster->CastSpell(this, 32865, true, castItem);
- return true; // no hidden cooldown
- }
- // Damage counting
- triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
- return true;
- }
- // Fel Synergy
- if(dummySpell->SpellIconID == 3222)
- {
- target = GetGuardianPet();
- if(!target)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 54181;
- break;
- }
- switch(dummySpell->Id)
- {
- // Siphon Life
- case 63108:
- {
- // Glyph of Siphon Life
- if(HasAura(56216))
- triggerAmount += triggerAmount / 4;
- triggered_spell_id = 63106;
- target = this;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- break;
- }
- // Glyph of Shadowflame
- case 63310:
- {
- triggered_spell_id = 63311;
- break;
- }
- // Nightfall
- case 18094:
- case 18095:
- // Glyph of corruption
- case 56218:
- {
- target = this;
- triggered_spell_id = 17941;
- break;
- }
- // Soul Leech
- case 30293:
- case 30295:
- case 30296:
- {
- // Improved Soul Leech
- AuraEffectList const& SoulLeechAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator i = SoulLeechAuras.begin(); i != SoulLeechAuras.end(); ++i)
- {
- if((*i)->GetId() == 54117 || (*i)->GetId() == 54118)
- {
- if((*i)->GetEffIndex() != 0)
- continue;
- basepoints0 = int32((*i)->GetAmount());
- target = GetGuardianPet();
- if(target)
- {
- // regen mana for pet
- CastCustomSpell(target, 54607, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- }
- // regen mana for caster
- CastCustomSpell(this, 59117, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- // Get second aura of spell for replenishment effect on party
- if(AuraEffect const* aurEff = (*i)->GetBase()->GetEffect(EFFECT_1))
- { // Replenishment - roll chance
- if(roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 57669, true, castItem, triggeredByAura);
- }
- break;
- }
- }
- // health
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 30294;
- break;
- }
- // Shadowflame (Voidheart Raiment set bonus)
- case 37377:
- {
- triggered_spell_id = 37379;
- break;
- }
- // Pet Healing (Corruptor Raiment or Rift Stalker Armor)
- case 37381:
- {
- target = GetGuardianPet();
- if(!target)
- return false;
- // heal amount
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 37382;
- break;
- }
- // Shadowflame Hellfire (Voidheart Raiment set bonus)
- case 39437:
- {
- triggered_spell_id = 37378;
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_PRIEST:
- {
- // Vampiric Touch
- if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
- {
- if(!victim || !victim->isAlive())
- return false;
- if(effIndex != 0)
- return false;
- // victim is caster of aura
- if(triggeredByAura->GetCasterGUID() != victim->GetGUID())
- return false;
- // Energize 0.25% of max. mana
- victim->CastSpell(victim, 57669, true, castItem, triggeredByAura);
- return true; // no hidden cooldown
- }
- // Divine Aegis
- if(dummySpell->SpellIconID == 2820)
- {
- if(!target)
- return false;
- // Multiple effects stack, so let's try to find this aura.
- int32 bonus = 0;
- if(AuraEffect const* aurEff = target->GetAuraEffect(47753, 0))
- bonus = aurEff->GetAmount();
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) + bonus;
- if(basepoints0 > target->getLevel() * 125)
- basepoints0 = target->getLevel() * 125;
- triggered_spell_id = 47753;
- break;
- }
- // Body and Soul
- if(dummySpell->SpellIconID == 2218)
- {
- // Proc only from Abolish desease on self cast
- if(procSpell->Id != 552 || victim != this || !roll_chance_i(triggerAmount))
- return false;
- triggered_spell_id = 64136;
- target = this;
- break;
- }
- switch(dummySpell->Id)
- {
- // Vampiric Embrace
- case 15286:
- {
- if(!victim || !victim->isAlive() || procSpell->SpellFamilyFlags[1] & 0x80000 || target->HasAura(33786))
- return false;
- // heal amount
- int32 total = CalculatePctN(int32(damage), triggerAmount);
- int32 team = total / 5;
- int32 self = total - team;
- CastCustomSpell(this, 15290, &team, &self, NULL, true, castItem, triggeredByAura);
- return true; // no hidden cooldown
- }
- // Priest Tier 6 Trinket (Ashtongue Talisman of Acumen)
- case 40438:
- {
- // Shadow Word: Pain
- if(procSpell->SpellFamilyFlags[0] & 0x8000)
- triggered_spell_id = 40441;
- // Renew
- else if(procSpell->SpellFamilyFlags[0] & 0x40)
- triggered_spell_id = 40440;
- else
- return false;
- target = this;
- break;
- }
- // Glyph of Prayer of Healing
- case 55680:
- {
- triggered_spell_id = 56161;
- SpellEntry const* GoPoH = sSpellStore.LookupEntry(triggered_spell_id);
- if(!GoPoH)
- return false;
- int EffIndex = 0;
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
- {
- if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA)
- {
- EffIndex = i;
- break;
- }
- }
- int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex];
- if(!tickcount)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / tickcount;
- break;
- }
- // Improved Shadowform
- case 47570:
- case 47569:
- {
- if(!roll_chance_i(triggerAmount))
- return false;
- RemoveMovementImpairingAuras();
- break;
- }
- // Glyph of Dispel Magic
- case 55677:
- {
- // Dispel Magic shares spellfamilyflag with abolish disease
- if(procSpell->SpellIconID != 74)
- return false;
- if(!target || !target->IsFriendlyTo(this) || target->GetTypeId() != TYPEID_PLAYER)
- return false;
- basepoints0 = int32(target->CountPctFromMaxHealth(triggerAmount));
- triggered_spell_id = 56131;
- break;
- }
- // Oracle Healing Bonus ("Garments of the Oracle" set)
- case 26169:
- {
- // heal amount
- basepoints0 = int32(CalculatePctN(damage, 10));
- target = this;
- triggered_spell_id = 26170;
- break;
- }
- // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set
- case 39372:
- {
- if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0)
- return false;
- // heal amount
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 39373;
- break;
- }
- // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus)
- case 28809:
- {
- triggered_spell_id = 28810;
- break;
- }
- // Priest T10 Healer 2P Bonus
- case 70770:
- // Flash Heal
- if(procSpell->SpellFamilyFlags[0] & 0x800)
- {
- triggered_spell_id = 70772;
- SpellEntry const* blessHealing = sSpellStore.LookupEntry(triggered_spell_id);
- if(!blessHealing)
- return false;
- basepoints0 = int32(CalculatePctN(damage, triggerAmount) / (GetSpellMaxDuration(blessHealing) / blessHealing->EffectAmplitude[0]));
- }
- break;
- }
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- switch(dummySpell->Id)
- {
- // Glyph of Innervate
- case 54832:
- {
- if(procSpell->SpellIconID != 62)
- return false;
- int32 mana_perc = SpellMgr::CalculateSpellEffectAmount(triggeredByAura->GetSpellProto(), triggeredByAura->GetEffIndex());
- basepoints0 = int32(CalculatePctN(GetCreatePowers(POWER_MANA), mana_perc) / 10);
- triggered_spell_id = 54833;
- target = this;
- break;
- }
- // Glyph of Starfire
- case 54845:
- {
- triggered_spell_id = 54846;
- break;
- }
- // Glyph of Shred
- case 54815:
- {
- if(!target)
- return false;
- // try to find spell Rip on the target
- if(AuraEffect const* AurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00800000, 0x0, 0x0, GetGUID()))
- {
- // Rip's max duration, note: spells which modifies Rip's duration also counted like Glyph of Rip
- uint32 CountMin = AurEff->GetBase()->GetMaxDuration();
- // just Rip's max duration without other spells
- uint32 CountMax = GetSpellMaxDuration(AurEff->GetSpellProto());
- // add possible auras' and Glyph of Shred's max duration
- CountMax += 3 * triggerAmount * IN_MILLISECONDS; // Glyph of Shred -> +6 seconds
- CountMax += HasAura(54818) ? 4 * IN_MILLISECONDS : 0; // Glyph of Rip -> +4 seconds
- CountMax += HasAura(60141) ? 4 * IN_MILLISECONDS : 0; // Rip Duration/Lacerate Damage -> +4 seconds
- // if min < max -> that means caster didn't cast 3 shred yet
- // so set Rip's duration and max duration
- if(CountMin < CountMax)
- {
- AurEff->GetBase()->SetDuration(AurEff->GetBase()->GetDuration() + triggerAmount * IN_MILLISECONDS);
- AurEff->GetBase()->SetMaxDuration(CountMin + triggerAmount * IN_MILLISECONDS);
- return true;
- }
- }
- // if not found Rip
- return false;
- }
- // Glyph of Rake
- case 54821:
- {
- if(procSpell->SpellVisual[0] == 750 && procSpell->EffectApplyAuraName[1] == 3)
- {
- if(target && target->GetTypeId() == TYPEID_UNIT)
- {
- triggered_spell_id = 54820;
- break;
- }
- }
- return false;
- }
- // Leader of the Pack
- case 24932:
- {
- if(triggerAmount <= 0)
- return false;
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- target = this;
- triggered_spell_id = 34299;
- if(triggeredByAura->GetCasterGUID() != GetGUID())
- break;
- int32 basepoints1 = triggerAmount * 2;
- // Improved Leader of the Pack
- // Check cooldown of heal spell cooldown
- if(GetTypeId() == TYPEID_PLAYER && !ToPlayer()->HasSpellCooldown(34299))
- CastCustomSpell(this, 60889, &basepoints1, 0, 0, true, 0, triggeredByAura);
- break;
- }
- // Healing Touch (Dreamwalker Raiment set)
- case 28719:
- {
- // mana back
- basepoints0 = int32(CalculatePctN(procSpell->manaCost, 30));
- target = this;
- triggered_spell_id = 28742;
- break;
- }
- // Glyph of Rejuvenation
- case 54754:
- {
- if(!victim || !victim->HealthBelowPct(uint32(triggerAmount)))
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 54755;
- break;
- }
- // Healing Touch Refund (Idol of Longevity trinket)
- case 28847:
- {
- target = this;
- triggered_spell_id = 28848;
- break;
- }
- // Mana Restore (Malorne Raiment set / Malorne Regalia set)
- case 37288:
- case 37295:
- {
- target = this;
- triggered_spell_id = 37238;
- break;
- }
- // Druid Tier 6 Trinket
- case 40442:
- {
- float chance;
- // Starfire
- if(procSpell->SpellFamilyFlags[0] & 0x4)
- {
- triggered_spell_id = 40445;
- chance = 25.0f;
- }
- // Rejuvenation
- else if(procSpell->SpellFamilyFlags[0] & 0x10)
- {
- triggered_spell_id = 40446;
- chance = 25.0f;
- }
- // Mangle (Bear) and Mangle (Cat)
- else if(procSpell->SpellFamilyFlags[1] & 0x00000440)
- {
- triggered_spell_id = 40452;
- chance = 40.0f;
- }
- else
- return false;
- if(!roll_chance_f(chance))
- return false;
- target = this;
- break;
- }
- // Maim Interrupt
- case 44835:
- {
- // Deadly Interrupt Effect
- triggered_spell_id = 32747;
- break;
- }
- case 57934: // Tricks of the Trade
- {
- if(Unit* unitTarget = GetMisdirectionTarget())
- {
- RemoveAura(dummySpell->Id, GetGUID(), 0, AURA_REMOVE_BY_DEFAULT);
- CastSpell(this, 59628, true);
- CastSpell(unitTarget, 57933, true);
- return true;
- }
- return false;
- }
- // Item - Druid T10 Balance 4P Bonus
- case 70723:
- {
- // Wrath & Starfire
- if((procSpell->SpellFamilyFlags[0] & 0x5) && (procEx & PROC_EX_CRITICAL_HIT))
- {
- triggered_spell_id = 71023;
- SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggeredSpell)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
- // Add remaining ticks to damage done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- }
- break;
- }
- // Item - Druid T10 Restoration 4P Bonus (Rejuvenation)
- case 70664:
- {
- // Proc only from normal Rejuvenation
- if(procSpell->SpellVisual[0] != 32)
- return false;
- Player* caster = ToPlayer();
- if(!caster)
- return false;
- if(!caster->GetGroup() && victim == this)
- return false;
- CastCustomSpell(70691, SPELLVALUE_BASE_POINT0, damage, victim, true);
- return true;
- }
- case 770:
- case 16857:
- if(target->HasAura(33786))
- return false;
- break;
- }
- // Eclipse
- if(dummySpell->SpellIconID == 2856 && GetTypeId() == TYPEID_PLAYER)
- {
- if(!procSpell || effIndex != 0)
- return false;
- bool isWrathSpell = (procSpell->SpellFamilyFlags[0] & 1);
- if(!roll_chance_f(dummySpell->procChance * (isWrathSpell ? 0.6f : 1.0f)))
- return false;
- target = this;
- if(target->HasAura(isWrathSpell ? 48517 : 48518))
- return false;
- triggered_spell_id = isWrathSpell ? 48518 : 48517;
- break;
- }
- // Living Seed
- else if(dummySpell->SpellIconID == 2860)
- {
- triggered_spell_id = 48504;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- break;
- }
- // King of the Jungle
- else if(dummySpell->SpellIconID == 2850)
- {
- // Effect 0 - mod damage while having Enrage
- if(effIndex == 0)
- {
- if(!(procSpell->SpellFamilyFlags[0] & 0x00080000))
- return false;
- triggered_spell_id = 51185;
- basepoints0 = triggerAmount;
- target = this;
- break;
- }
- // Effect 1 - Tiger's Fury restore energy
- else if(effIndex == 1)
- {
- if(!(procSpell->SpellFamilyFlags[2] & 0x00000800))
- return false;
- triggered_spell_id = 51178;
- basepoints0 = triggerAmount;
- target = this;
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- switch(dummySpell->Id)
- {
- // Glyph of Backstab
- case 56800:
- {
- triggered_spell_id = 63975;
- break;
- }
- // Deadly Throw Interrupt
- case 32748:
- {
- // Prevent cast Deadly Throw Interrupt on self from last effect (apply dummy) of Deadly Throw
- if(this == victim)
- return false;
- triggered_spell_id = 32747;
- break;
- }
- // Tricks of the trade
- case 57934:
- {
- triggered_spell_id = 57933; // Tricks of the Trade, increased damage buff
- target = GetMisdirectionTarget();
- if(!target)
- return false;;
- CastSpell(this, 59628, true); // Tricks of the Trade (caster timer)
- break;
- }
- }
- // Cut to the Chase
- if(dummySpell->SpellIconID == 2909)
- {
- // "refresh your Slice and Dice duration to its 5 combo point maximum"
- // lookup Slice and Dice
- if(AuraEffect const* aur = GetAuraEffect(SPELL_AURA_MOD_MELEE_HASTE, SPELLFAMILY_ROGUE, 0x40000, 0, 0))
- {
- aur->GetBase()->SetDuration(GetSpellMaxDuration(aur->GetSpellProto()), true);
- return true;
- }
- return false;
- }
- // Deadly Brew
- else if(dummySpell->SpellIconID == 2963)
- {
- triggered_spell_id = 3409;
- break;
- }
- // Quick Recovery
- else if(dummySpell->SpellIconID == 2116)
- {
- if(!procSpell)
- return false;
- // energy cost save
- basepoints0 = CalculatePctN(int32(procSpell->manaCost), triggerAmount);
- if(basepoints0 <= 0)
- return false;
- target = this;
- triggered_spell_id = 31663;
- break;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Thrill of the Hunt
- if(dummySpell->SpellIconID == 2236)
- {
- if(!procSpell)
- return false;
- Spell* spell = ToPlayer()->m_spellModTakingSpell;
- // Disable charge drop because of Lock and Load
- ToPlayer()->SetSpellModTakingSpell(spell, false);
- // Explosive Shot
- if(procSpell->SpellFamilyFlags[2] & 0x200)
- {
- if(!victim)
- return false;
- if(AuraEffect const* pEff = victim->GetAuraEffect(SPELL_AURA_PERIODIC_DUMMY, SPELLFAMILY_HUNTER, 0x0, 0x80000000, 0x0, GetGUID()))
- basepoints0 = CalculatePowerCost(pEff->GetSpellProto(), this, SpellSchoolMask(pEff->GetSpellProto()->SchoolMask)) * 4/10/3;
- }
- else
- basepoints0 = CalculatePowerCost(procSpell, this, SpellSchoolMask(procSpell->SchoolMask)) * 4/10;
- ToPlayer()->SetSpellModTakingSpell(spell, true);
- if(basepoints0 <= 0)
- return false;
- target = this;
- triggered_spell_id = 34720;
- break;
- }
- // Hunting Party
- if(dummySpell->SpellIconID == 3406)
- {
- triggered_spell_id = 57669;
- target = this;
- break;
- }
- // Improved Mend Pet
- if(dummySpell->SpellIconID == 267)
- {
- int32 chance = SpellMgr::CalculateSpellEffectAmount(triggeredByAura->GetSpellProto(), triggeredByAura->GetEffIndex());
- if(!roll_chance_i(chance))
- return false;
- triggered_spell_id = 24406;
- break;
- }
- // Lock and Load
- if(dummySpell->SpellIconID == 3579)
- {
- // Proc only from periodic (from trap activation proc another aura of this spell)
- if(!(procFlag & PROC_FLAG_DONE_PERIODIC) || !roll_chance_i(triggerAmount))
- return false;
- triggered_spell_id = 56453;
- target = this;
- break;
- }
- // Rapid Recuperation
- if(dummySpell->SpellIconID == 3560)
- {
- // This effect only from Rapid Killing (mana regen)
- if(!(procSpell->SpellFamilyFlags[1] & 0x01000000))
- return false;
- target = this;
- switch(dummySpell->Id)
- {
- case 53228: // Rank 1
- triggered_spell_id = 56654;
- break;
- case 53232: // Rank 2
- triggered_spell_id = 58882;
- break;
- }
- break;
- }
- // Glyph of Mend Pet
- if(dummySpell->Id == 57870)
- {
- victim->CastSpell(victim, 57894, true, NULL, NULL, GetGUID());
- return true;
- }
- // Misdirection
- if(dummySpell->Id == 34477)
- {
- RemoveAura(dummySpell->Id, GetGUID(), 0, AURA_REMOVE_BY_DEFAULT);
- CastSpell(this, 35079, true);
- return true;
- }
- //Roar of Sacrifice (pet talent spell); aura added in SpellMgr::LoadSpellCustomAttr
- if(dummySpell->Id == 53480)
- {
- triggered_spell_id = 67481;
- target = triggeredByAura->GetCaster();
- basepoints0 = CalculatePctN(damage, triggerAmount);
- break;
- }
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
- if(dummySpell->SpellFamilyFlags[0] & 0x8000000)
- {
- if(effIndex != 0)
- return false;
- triggered_spell_id = 25742;
- float ap = GetTotalAttackPowerValue(BASE_ATTACK);
- int32 holy = SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
- SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, victim);
- basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap * 0.022f + 0.044f * holy) / 1000;
- break;
- }
- // Light's Beacon - Beacon of Light
- if(dummySpell->Id == 53651)
- {
- if (!victim)
- return false;
- // Get target of beacon of light
- if(Unit* beaconTarget = triggeredByAura->GetBase()->GetCaster())
- {
- // do not proc when target of beacon of light is healed
- if(beaconTarget == this)
- return false;
- // check if it was heal by paladin which casted this beacon of light
- if(beaconTarget->GetAura(53563, victim->GetGUID())) // if (!beaconTarget || beaconTarget == this || !(beaconTarget->GetAura(53563, victim->GetGUID()))) //
- {
- if(beaconTarget->IsWithinLOSInMap(victim))
- {
- basepoints0 = damage;
- victim->CastCustomSpell(beaconTarget, 53654, &basepoints0, NULL, NULL, true);
- return true;
- }
- }
- }
- return false;
- }
- // Judgements of the Wise
- if(dummySpell->SpellIconID == 3017)
- {
- target = this;
- triggered_spell_id = 31930;
- // replenishment
- CastSpell(this, 57669, true, castItem, triggeredByAura);
- break;
- }
- // Sanctified Wrath
- if(dummySpell->SpellIconID == 3029)
- {
- triggered_spell_id = 57318;
- target = this;
- basepoints0 = triggerAmount;
- CastCustomSpell(target, triggered_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura);
- return true;
- }
- // Sacred Shield
- if(dummySpell->SpellFamilyFlags[1] & 0x80000)
- {
- if(procFlag & PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS)
- {
- if(procSpell->SpellFamilyName == SPELLFAMILY_PALADIN && (procSpell->SpellFamilyFlags[0] & 0x40000000))
- {
- basepoints0 = damage / 12;
- if(basepoints0)
- CastCustomSpell(this, 66922, &basepoints0, NULL, NULL, true, 0, triggeredByAura, victim->GetGUID());
- return true;
- }
- else
- return false;
- }
- else if(damage > 0)
- triggered_spell_id = 58597;
- // Item - Paladin T8 Holy 4P Bonus
- if(Unit* caster = triggeredByAura->GetCaster())
- if(AuraEffect const* aurEff = caster->GetAuraEffect(64895, 0))
- cooldown = aurEff->GetAmount();
- target = this;
- break;
- }
- // Righteous Vengeance
- if(dummySpell->SpellIconID == 3025)
- {
- // 4 damage tick
- basepoints0 = triggerAmount * damage / 400;
- triggered_spell_id = 61840;
- // Add remaining ticks to damage done
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- // Sheath of Light
- if(dummySpell->SpellIconID == 3030)
- {
- // 4 healing tick
- basepoints0 = triggerAmount * damage / 400;
- triggered_spell_id = 54203;
- break;
- }
- switch(dummySpell->Id)
- { // Heart of the Crusader
- case 20335: // rank 1
- triggered_spell_id = 21183;
- break;
- case 20336: // rank 2
- triggered_spell_id = 54498;
- break;
- case 20337: // rank 3
- triggered_spell_id = 54499;
- break;
- // Judgement of Light
- case 20185:
- {
- if(!victim)
- return false;
- // 2% of base mana
- basepoints0 = int32(victim->CountPctFromMaxHealth(2));
- victim->CastCustomSpell(victim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
- return true;
- }
- // Judgement of Wisdom
- case 20186:
- {
- if(victim && victim->isAlive() && victim->getPowerType() == POWER_MANA)
- {
- // 2% of base mana
- basepoints0 = int32(CalculatePctN(victim->GetCreateMana(), 2));
- victim->CastCustomSpell(victim, 20268, &basepoints0, NULL, NULL, true, 0, triggeredByAura);
- }
- return true;
- }
- // Holy Power (Redemption Armor set)
- case 28789:
- {
- if(!victim)
- return false;
- // Set class defined buff
- switch(victim->getClass())
- {
- case CLASS_PALADIN:
- case CLASS_PRIEST:
- case CLASS_SHAMAN:
- case CLASS_DRUID:
- triggered_spell_id = 28795; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
- break;
- case CLASS_MAGE:
- case CLASS_WARLOCK:
- triggered_spell_id = 28793; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
- break;
- case CLASS_HUNTER:
- case CLASS_ROGUE:
- triggered_spell_id = 28791; // Increases the friendly target's attack power by $s1 for $d.
- break;
- case CLASS_WARRIOR:
- triggered_spell_id = 28790; // Increases the friendly target's armor
- break;
- default:
- return false;
- }
- break;
- }
- case 25899: // Greater Blessing of Sanctuary
- case 20911: // Blessing of Sanctuary
- {
- target = this;
- switch(target->getPowerType())
- {
- case POWER_MANA:
- triggered_spell_id = 57319;
- break;
- default:
- return false;
- }
- break;
- }
- // Seal of Vengeance (damage calc on apply aura)
- case 31801:
- {
- if(effIndex != 0) // effect 1, 2 used by seal unleashing code
- return false;
- // At melee attack or Hammer of the Righteous spell damage considered as melee attack
- bool stacker = !procSpell || procSpell->Id == 53595;
- // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
- bool damager = procSpell && procSpell->EquippedItemClass != -1;
- if(!stacker && !damager)
- return false;
- triggered_spell_id = 31803;
- // On target with 5 stacks of Holy Vengeance direct damage is done
- if(Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
- {
- if(aur->GetStackAmount() == 5)
- {
- if(stacker)
- aur->RefreshDuration();
- CastSpell(victim, 42463, true);
- return true;
- }
- }
- if(!stacker)
- return false;
- break;
- }
- // Seal of Corruption
- case 53736:
- {
- if(effIndex != 0) // effect 1, 2 used by seal unleashing code
- return false;
- // At melee attack or Hammer of the Righteous spell damage considered as melee attack
- bool stacker = !procSpell || procSpell->Id == 53595;
- // spells with SPELL_DAMAGE_CLASS_MELEE excluding Judgements
- bool damager = procSpell && procSpell->EquippedItemClass != -1;
- if(!stacker && !damager)
- return false;
- triggered_spell_id = 53742;
- // On target with 5 stacks of Blood Corruption direct damage is done
- if(Aura* aur = victim->GetAura(triggered_spell_id, GetGUID()))
- {
- if(aur->GetStackAmount() == 5)
- {
- if(stacker)
- aur->RefreshDuration();
- CastSpell(victim, 53739, true);
- return true;
- }
- }
- if(!stacker)
- return false;
- break;
- }
- // Spiritual Attunement
- case 31785:
- case 31786:
- {
- // if healed by another unit (pVictim)
- if(this == victim)
- return false;
- // heal amount
- int32 mana=5*(std::min(damage,GetMaxHealth() - GetHealth()))/100;
- EnergizeBySpell(this, 31785, mana, POWER_MANA);
- return true;
- break;
- }
- case 38421:
- case 33776:
- {
- // if healed by another unit (pVictim)
- if(this == victim)
- return false;
- int32 mana = (std::min(damage,GetMaxHealth() - GetHealth()))/10;
- // heal amount
- EnergizeBySpell(this, 33776, mana, POWER_MANA);
- return true;
- break;
- }
- // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal)
- case 40470:
- {
- if(!procSpell)
- return false;
- float chance;
- // Flash of light/Holy light
- if(procSpell->SpellFamilyFlags[0] & 0xC0000000)
- {
- triggered_spell_id = 40471;
- chance = 15.0f;
- }
- // Judgement (any)
- else if(GetSpellSpecific(procSpell) == SPELL_SPECIFIC_JUDGEMENT)
- {
- triggered_spell_id = 40472;
- chance = 50.0f;
- }
- else
- return false;
- if(!roll_chance_f(chance))
- return false;
- break;
- }
- // Glyph of Holy Light
- case 54937:
- {
- triggered_spell_id = 54968;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- break;
- }
- // Item - Paladin T8 Holy 2P Bonus
- case 64890:
- {
- triggered_spell_id = 64891;
- basepoints0 = triggerAmount * damage / 300;
- break;
- }
- case 71406: // Tiny Abomination in a Jar
- case 71545: // Tiny Abomination in a Jar (Heroic)
- {
- if(!victim || !victim->isAlive())
- return false;
- CastSpell(this, 71432, true, NULL, triggeredByAura);
- Aura const* dummy = GetAura(71432);
- if(!dummy || dummy->GetStackAmount() < (dummySpell->Id == 71406 ? 8 : 7))
- return false;
- RemoveAurasDueToSpell(71432);
- triggered_spell_id = 71433; // default main hand attack
- // roll if offhand
- if(Player const* player = ToPlayer())
- if(player->GetWeaponForAttack(OFF_ATTACK, true) && urand(0, 1))
- triggered_spell_id = 71434;
- target = victim;
- break;
- }
- case 99997: // Divine Storm Helper (SERVERSIDE)
- {
- if(victim == this)
- return false;
- triggeredByAura->SetAmount(triggeredByAura->GetAmount() + damage);
- return true;
- }
- break;
- // Item - Icecrown 25 Normal Dagger Proc
- case 71880:
- {
- switch(getPowerType())
- {
- case POWER_MANA:
- triggered_spell_id = 71881;
- break;
- case POWER_RAGE:
- triggered_spell_id = 71883;
- break;
- case POWER_ENERGY:
- triggered_spell_id = 71882;
- break;
- case POWER_RUNIC_POWER:
- triggered_spell_id = 71884;
- break;
- default:
- return false;
- }
- break;
- }
- // Item - Icecrown 25 Heroic Dagger Proc
- case 71892:
- {
- switch(getPowerType())
- {
- case POWER_MANA:
- triggered_spell_id = 71888;
- break;
- case POWER_RAGE:
- triggered_spell_id = 71886;
- break;
- case POWER_ENERGY:
- triggered_spell_id = 71887;
- break;
- case POWER_RUNIC_POWER:
- triggered_spell_id = 71885;
- break;
- default:
- return false;
- }
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- switch(dummySpell->Id)
- {
- /*
- // Earthen Power (Rank 1, 2)
- case 51523:
- case 51524:
- {
- // Totem itself must be a caster of this spell
- Unit* caster = NULL;
- for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) {
- if((*itr)->GetEntry() != 2630)
- continue;
- caster = *itr;
- break;
- }
- if(!caster)
- return false;
- caster->CastSpell(caster, 59566, true, castItem, triggeredByAura, originalCaster);
- return true;
- }
- */
- // Tidal Force
- case 55198:
- {
- // Remove aura stack from caster
- RemoveAuraFromStack(55166);
- // drop charges
- return false;
- }
- // Tidal Waves
- if(dummySpell->SpellIconID == 3057)
- {
- if(!procSpell)
- return false;
- int32 bp0 = -(dummySpell->EffectBasePoints[0]);
- int32 bp1 = dummySpell->EffectBasePoints[0];//BasePoints;
- CastCustomSpell(this, 53390, &bp0, &bp1, NULL, true, 0, 0, GetGUID());
- return true;
- }
- // Totemic Power (The Earthshatterer set)
- case 28823:
- {
- if(!victim)
- return false;
- // Set class defined buff
- switch(victim->getClass())
- {
- case CLASS_PALADIN:
- case CLASS_PRIEST:
- case CLASS_SHAMAN:
- case CLASS_DRUID:
- triggered_spell_id = 28824; // Increases the friendly target's mana regeneration by $s1 per 5 sec. for $d.
- break;
- case CLASS_MAGE:
- case CLASS_WARLOCK:
- triggered_spell_id = 28825; // Increases the friendly target's spell damage and healing by up to $s1 for $d.
- break;
- case CLASS_HUNTER:
- case CLASS_ROGUE:
- triggered_spell_id = 28826; // Increases the friendly target's attack power by $s1 for $d.
- break;
- case CLASS_WARRIOR:
- triggered_spell_id = 28827; // Increases the friendly target's armor
- break;
- default:
- return false;
- }
- break;
- }
- // Lesser Healing Wave (Totem of Flowing Water Relic)
- case 28849:
- {
- target = this;
- triggered_spell_id = 28850;
- break;
- }
- // Windfury Weapon (Passive) 1-5 Ranks
- case 33757:
- {
- Player* plr = ToPlayer();
- if(!plr || !castItem || !castItem->IsEquipped() || !victim || !victim->isAlive())
- return false;
- // custom cooldown processing case
- if(cooldown && plr->HasSpellCooldown(dummySpell->Id))
- return false;
- if(triggeredByAura->GetBase() && castItem->GetGUID() != triggeredByAura->GetBase()->GetCastItemGUID())
- return false;
- WeaponAttackType attType = WeaponAttackType(plr->GetAttackBySlot(castItem->GetSlot()));
- if((attType != BASE_ATTACK && attType != OFF_ATTACK) || !isAttackReady(attType))
- return false;
- // Now compute real proc chance...
- uint32 chance = 20;
- plr->ApplySpellMod(dummySpell->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
- Item* addWeapon = plr->GetWeaponForAttack(attType == BASE_ATTACK ? OFF_ATTACK : BASE_ATTACK, true);
- uint32 enchant_id_add = addWeapon ? addWeapon->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)) : 0;
- SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id_add);
- if(pEnchant && pEnchant->spellid[0] == dummySpell->Id)
- chance += 14;
- if(!roll_chance_i(chance))
- return false;
- // Now amount of extra power stored in 1 effect of Enchant spell
- // Get it by item enchant id
- uint32 spellId;
- switch(castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)))
- {
- case 283: spellId = 8232; break; // 1 Rank
- case 284: spellId = 8235; break; // 2 Rank
- case 525: spellId = 10486; break; // 3 Rank
- case 1669:spellId = 16362; break; // 4 Rank
- case 2636:spellId = 25505; break; // 5 Rank
- case 3785:spellId = 58801; break; // 6 Rank
- case 3786:spellId = 58803; break; // 7 Rank
- case 3787:spellId = 58804; break; // 8 Rank
- default:
- {
- sLog->outError("Unit::HandleDummyAuraProc: non handled item enchantment (rank?) %u for spell id: %u (Windfury)",
- castItem->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)), dummySpell->Id);
- return false;
- }
- }
- SpellEntry const* windfurySpellEntry = sSpellStore.LookupEntry(spellId);
- if(!windfurySpellEntry)
- {
- sLog->outError("Unit::HandleDummyAuraProc: non existed spell id: %u (Windfury)", spellId);
- return false;
- }
- int32 extra_attack_power = CalculateSpellDamage(victim, windfurySpellEntry, 1);
- // Value gained from additional AP
- basepoints0 = int32(extra_attack_power / 14.0f * GetAttackTime(BASE_ATTACK) / 1000);
- triggered_spell_id = 25504;
- // apply cooldown before cast to prevent processing itself
- if(cooldown)
- plr->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
- // Attack Twice
- for(uint32 i = 0; i < 2; ++i)
- CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- return true;
- }
- // Shaman Tier 6 Trinket
- case 40463:
- {
- if(!procSpell)
- return false;
- float chance;
- if(procSpell->SpellFamilyFlags[0] & 0x1)
- {
- triggered_spell_id = 40465; // Lightning Bolt
- chance = 15.0f;
- }
- else if(procSpell->SpellFamilyFlags[0] & 0x80)
- {
- triggered_spell_id = 40465; // Lesser Healing Wave
- chance = 10.0f;
- }
- else if(procSpell->SpellFamilyFlags[1] & 0x00000010)
- {
- triggered_spell_id = 40466; // Stormstrike
- chance = 50.0f;
- }
- else
- return false;
- if(!roll_chance_f(chance))
- return false;
- target = this;
- break;
- }
- // Glyph of Healing Wave
- case 55440:
- {
- // Not proc from self heals
- if(this == victim)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- target = this;
- triggered_spell_id = 55533;
- break;
- }
- // Spirit Hunt
- case 58877:
- {
- // Cast on owner
- target = GetOwner();
- if(!target)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 58879;
- break;
- }
- // Shaman T8 Elemental 4P Bonus
- case 64928:
- {
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 64930; // Electrified
- break;
- }
- // Shaman T9 Elemental 4P Bonus
- case 67228:
- {
- // Lava Burst
- if(procSpell->SpellFamilyFlags[1] & 0x1000)
- {
- triggered_spell_id = 71824;
- SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggeredSpell)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
- }
- break;
- }
- // Item - Shaman T10 Restoration 4P Bonus
- case 70808:
- {
- // Chain Heal
- if((procSpell->SpellFamilyFlags[0] & 0x100) && (procEx & PROC_EX_CRITICAL_HIT))
- {
- triggered_spell_id = 70809;
- SpellEntry const* triggeredSpell = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggeredSpell)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(triggeredSpell) / triggeredSpell->EffectAmplitude[0]);
- }
- break;
- }
- // Item - Shaman T10 Elemental 2P Bonus
- case 70811:
- {
- if(!target)
- return false;
- // Lightning Bolt & Chain Lightning
- if(procSpell->SpellFamilyFlags[0] & 0x3)
- {
- if(ToPlayer()->HasSpellCooldown(16166))
- {
- uint32 newCooldownDelay = ToPlayer()->GetSpellCooldownDelay(16166);
- if(newCooldownDelay < 3)
- newCooldownDelay = 0;
- else
- newCooldownDelay -= 2;
- ToPlayer()->AddSpellCooldown(16166, 0, uint32(time(NULL) + newCooldownDelay));
- WorldPacket data(SMSG_MODIFY_COOLDOWN, 4+8+4);
- data << uint32(16166); // Spell ID
- data << uint64(GetGUID()); // Player GUID
- data << int32(-2000); // Cooldown mod in milliseconds
- ToPlayer()->GetSession()->SendPacket(&data);
- return true;
- }
- }
- return false;
- }
- // Item - Shaman T10 Elemental 4P Bonus
- case 70817:
- {
- if(!target)
- return false;
- // try to find spell Flame Shock on the target
- if(AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID()))
- {
- Aura* flameShock = aurEff->GetBase();
- int32 maxDuration = flameShock->GetMaxDuration();
- int32 newDuration = flameShock->GetDuration() + 2 * aurEff->GetAmplitude();
- flameShock->SetDuration(newDuration);
- // is it blizzlike to change max duration for FS?
- if(newDuration > maxDuration)
- flameShock->SetMaxDuration(newDuration);
- return true;
- }
- // if not found Flame Shock
- return false;
- }
- case 63280: // Glyph of Totem of Wrath
- {
- if(procSpell->SpellIconID != 2019)
- return false;
- AuraEffect* aurEffA = NULL;
- AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for(AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
- {
- SpellEntry const* spell = (*i)->GetSpellProto();
- if(spell->SpellFamilyName == uint32(SPELLFAMILY_SHAMAN) && spell->SpellFamilyFlags.HasFlag(0, 0x02000000, 0))
- {
- if((*i)->GetCasterGUID() != GetGUID())
- continue;
- if(spell->Id == 63283)
- continue;
- aurEffA = (*i);
- break;
- }
- }
- if(aurEffA)
- {
- int32 bp0 = 0, bp1 = 0;
- bp0 = CalculatePctN(triggerAmount, aurEffA->GetAmount());
- if(AuraEffect* aurEffB = aurEffA->GetBase()->GetEffect(EFFECT_1))
- bp1 = CalculatePctN(triggerAmount, aurEffB->GetAmount());
- CastCustomSpell(this, 63283, &bp0, &bp1, NULL, true, NULL, triggeredByAura);
- return true;
- }
- return false;
- }
- break;
- }
- // Frozen Power
- if(dummySpell->SpellIconID == 3780)
- {
- if(!target)
- return false;
- if(GetDistance(target) < 15.0f)
- return false;
- float chance = (float)triggerAmount;
- if(!roll_chance_f(chance))
- return false;
- triggered_spell_id = 63685;
- break;
- }
- // Storm, Earth and Fire
- if(dummySpell->SpellIconID == 3063)
- {
- // Earthbind Totem summon only
- if(procSpell->Id != 2484)
- return false;
- float chance = (float)triggerAmount;
- if(!roll_chance_f(chance))
- return false;
- triggered_spell_id = 64695;
- break;
- }
- // Ancestral Awakening
- if(dummySpell->SpellIconID == 3065)
- {
- triggered_spell_id = 52759;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- target = this;
- break;
- }
- // Earth Shield
- if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
- {
- // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
- originalCaster = triggeredByAura->GetCasterGUID();
- target = this;
- basepoints0 = triggerAmount;
- // Glyph of Earth Shield
- if(AuraEffect* aur = GetAuraEffect(63279, 0))
- AddPctN(basepoints0, aur->GetAmount());
- triggered_spell_id = 379;
- break;
- }
- // Flametongue Weapon (Passive)
- if(dummySpell->SpellFamilyFlags[0] & 0x200000)
- {
- if(GetTypeId() != TYPEID_PLAYER || !victim || !victim->isAlive() || !castItem || !castItem->IsEquipped())
- return false;
- float fire_onhit = float(CalculatePctF(SpellMgr::CalculateSpellEffectAmount(dummySpell, 0), 1.0f));
- float add_spellpower = (float)(SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FIRE)
- + SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_FIRE, victim));
- // 1.3speed = 5%, 2.6speed = 10%, 4.0 speed = 15%, so, 1.0speed = 3.84%
- ApplyPctF(add_spellpower, 3.84f);
- // Enchant on Off-Hand and ready?
- if(castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK))
- {
- float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK) / 1000.0f;
- // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
- basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
- triggered_spell_id = 10444;
- }
- // Enchant on Main-Hand and ready?
- else if(castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK))
- {
- float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK) / 1000.0f;
- // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed
- basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed));
- triggered_spell_id = 10444;
- }
- // If not ready, we should return, shouldn't we?!
- else
- return false;
- CastCustomSpell(victim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- return true;
- }
- // Improved Water Shield
- if(dummySpell->SpellIconID == 2287)
- {
- // Default chance for Healing Wave and Riptide
- float chance = (float)triggeredByAura->GetAmount();
- if(procSpell->SpellFamilyFlags[0] & 0x80)
- // Lesser Healing Wave - 0.6 of default
- chance *= 0.6f;
- else if(procSpell->SpellFamilyFlags[0] & 0x100)
- // Chain heal - 0.3 of default
- chance *= 0.3f;
- if(!roll_chance_f(chance))
- return false;
- // Water Shield
- if(AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0, 0x00000020, 0))
- {
- uint32 spell = aurEff->GetSpellProto()->EffectTriggerSpell[aurEff->GetEffIndex()];
- CastSpell(this, spell, true, castItem, triggeredByAura);
- return true;
- }
- return false;
- }
- // Lightning Overload
- if(dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura
- {
- if(!procSpell || GetTypeId() != TYPEID_PLAYER || !victim)
- return false;
- // custom cooldown processing case
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(dummySpell->Id))
- return false;
- uint32 spellId = 0;
- // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost
- switch(procSpell->Id)
- {
- // Lightning Bolt
- case 403: spellId = 45284; break; // Rank 1
- case 529: spellId = 45286; break; // Rank 2
- case 548: spellId = 45287; break; // Rank 3
- case 915: spellId = 45288; break; // Rank 4
- case 943: spellId = 45289; break; // Rank 5
- case 6041: spellId = 45290; break; // Rank 6
- case 10391: spellId = 45291; break; // Rank 7
- case 10392: spellId = 45292; break; // Rank 8
- case 15207: spellId = 45293; break; // Rank 9
- case 15208: spellId = 45294; break; // Rank 10
- case 25448: spellId = 45295; break; // Rank 11
- case 25449: spellId = 45296; break; // Rank 12
- case 49237: spellId = 49239; break; // Rank 13
- case 49238: spellId = 49240; break; // Rank 14
- // Chain Lightning
- case 421: spellId = 45297; break; // Rank 1
- case 930: spellId = 45298; break; // Rank 2
- case 2860: spellId = 45299; break; // Rank 3
- case 10605: spellId = 45300; break; // Rank 4
- case 25439: spellId = 45301; break; // Rank 5
- case 25442: spellId = 45302; break; // Rank 6
- case 49270: spellId = 49268; break; // Rank 7
- case 49271: spellId = 49269; break; // Rank 8
- default:
- sLog->outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id);
- return false;
- }
- // Chain Lightning
- if(procSpell->SpellFamilyFlags[0] & 0x2)
- {
- // Chain lightning has [LightOverload_Proc_Chance] / [Max_Number_of_Targets] chance to proc of each individual target hit.
- // A maxed LO would have a 33% / 3 = 11% chance to proc of each target.
- // LO chance was already "accounted" at the proc chance roll, now need to divide the chance by [Max_Number_of_Targets]
- float chance = 100.0f / procSpell->EffectChainTarget[effIndex];
- if(!roll_chance_f(chance))
- return false;
- // Remove cooldown (Chain Lightning - have Category Recovery time)
- ToPlayer()->RemoveSpellCooldown(spellId);
- }
- CastSpell(victim, spellId, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown);
- return true;
- }
- // Static Shock
- if(dummySpell->SpellIconID == 3059)
- {
- // Lightning Shield
- if(AuraEffect const* aurEff = GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400, 0, 0))
- {
- uint32 spell = sSpellMgr->GetSpellWithRank(26364, sSpellMgr->GetSpellRank(aurEff->GetId()));
- // custom cooldown processing case
- if(GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(spell))
- ToPlayer()->RemoveSpellCooldown(spell);
- CastSpell(target, spell, true, castItem, triggeredByAura);
- aurEff->GetBase()->DropCharge();
- return true;
- }
- return false;
- }
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Blood-Caked Strike - Blood-Caked Blade
- if(dummySpell->SpellIconID == 138)
- {
- if(!target || !target->isAlive())
- return false;
- triggered_spell_id = dummySpell->EffectTriggerSpell[effIndex];
- break;
- }
- // Improved Blood Presence
- if(dummySpell->SpellIconID == 2636)
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- break;
- }
- // Butchery
- if(dummySpell->SpellIconID == 2664)
- {
- basepoints0 = triggerAmount;
- triggered_spell_id = 50163;
- target = this;
- break;
- }
- // Dancing Rune Weapon
- if(dummySpell->Id == 49028)
- {
- // 1 dummy aura for dismiss rune blade
- if(effIndex != 1)
- return false;
- Unit* pPet = NULL;
- for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) // Find Rune Weapon
- if((*itr)->GetEntry() == 27893)
- {
- pPet = *itr;
- break;
- }
- if(pPet && pPet->getVictim() && damage && procSpell)
- {
- uint32 procDmg = damage / 2;
- pPet->SendSpellNonMeleeDamageLog(pPet->getVictim(), procSpell->Id, procDmg, GetSpellSchoolMask(procSpell), 0, 0, false, 0, false);
- pPet->DealDamage(pPet->getVictim(), procDmg, NULL, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(procSpell), procSpell, true);
- break;
- }
- else
- return false;
- }
- // Mark of Blood
- if(dummySpell->Id == 49005)
- {
- /* if(!target || target->GetTypeId() != TYPEID_PLAYER)
- return false;
- */
- // TODO: need more info (cooldowns/PPM)
- triggered_spell_id = 61607;
- break;
- }
- // Unholy Blight
- if(dummySpell->Id == 49194)
- {
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- // Glyph of Unholy Blight
- if(AuraEffect* glyph=GetAuraEffect(63332, 0))
- AddPctN(basepoints0, glyph->GetAmount());
- triggered_spell_id = 50536;
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- // Vendetta
- if(dummySpell->SpellFamilyFlags[0] & 0x10000)
- {
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- triggered_spell_id = 50181;
- target = this;
- break;
- }
- // Necrosis
- if(dummySpell->SpellIconID == 2709)
- {
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 51460;
- break;
- }
- // Threat of Thassarian
- if(dummySpell->SpellIconID == 2023)
- {
- // Must Dual Wield
- if(!procSpell || !haveOffhandWeapon())
- return false;
- switch(procSpell->Id)
- {
- // Obliterate
- case 49020: triggered_spell_id = 66198; break; // Rank 1
- case 51423: triggered_spell_id = 66972; break; // Rank 2
- case 51424: triggered_spell_id = 66973; break; // Rank 3
- case 51425: triggered_spell_id = 66974; break; // Rank 4
- // Frost Strike
- case 49143: triggered_spell_id = 66196; break; // Rank 1
- case 51416: triggered_spell_id = 66958; break; // Rank 2
- case 51417: triggered_spell_id = 66959; break; // Rank 3
- case 51418: triggered_spell_id = 66960; break; // Rank 4
- case 51419: triggered_spell_id = 66961; break; // Rank 5
- case 55268: triggered_spell_id = 66962; break; // Rank 6
- // Plague Strike
- case 45462: triggered_spell_id = 66216; break; // Rank 1
- case 49917: triggered_spell_id = 66988; break; // Rank 2
- case 49918: triggered_spell_id = 66989; break; // Rank 3
- case 49919: triggered_spell_id = 66990; break; // Rank 4
- case 49920: triggered_spell_id = 66991; break; // Rank 5
- case 49921: triggered_spell_id = 66992; break; // Rank 6
- // Death Strike
- case 49998: triggered_spell_id = 66188; break; // Rank 1
- case 49999: triggered_spell_id = 66950; break; // Rank 2
- case 45463: triggered_spell_id = 66951; break; // Rank 3
- case 49923: triggered_spell_id = 66952; break; // Rank 4
- case 49924: triggered_spell_id = 66953; break; // Rank 5
- // Rune Strike
- case 56815: triggered_spell_id = 66217; break; // Rank 1
- // Blood Strike
- case 45902: triggered_spell_id = 66215; break; // Rank 1
- case 49926: triggered_spell_id = 66975; break; // Rank 2
- case 49927: triggered_spell_id = 66976; break; // Rank 3
- case 49928: triggered_spell_id = 66977; break; // Rank 4
- case 49929: triggered_spell_id = 66978; break; // Rank 5
- case 49930: triggered_spell_id = 66979; break; // Rank 6
- default:
- return false;
- }
- break;
- }
- // Runic Power Back on Snare/Root
- if(dummySpell->Id == 61257)
- {
- // only for spells and hit/crit (trigger start always) and not start from self casted spells
- if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
- // Need snare or root mechanic
- if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_ROOT)|(1<<MECHANIC_SNARE))))
- return false;
- triggered_spell_id = 61258;
- target = this;
- break;
- }
- // Wandering Plague
- if(dummySpell->SpellIconID == 1614)
- {
- if(!roll_chance_f(GetUnitCriticalChance(BASE_ATTACK, victim)))
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- triggered_spell_id = 50526;
- break;
- }
- // Sudden Doom
- if(dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER)
- {
- SpellChainNode const* chain = NULL;
- // get highest rank of the Death Coil spell
- PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
- for(PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- // check if shown in spell book
- if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
- continue;
- SpellEntry const* spellProto = sSpellStore.LookupEntry(itr->first);
- if(!spellProto)
- continue;
- if(spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT
- && spellProto->SpellFamilyFlags[0] & 0x2000)
- {
- SpellChainNode const* newChain = sSpellMgr->GetSpellChainNode(itr->first);
- // No chain entry or entry lower than found entry
- if(!chain || !newChain || (chain->rank < newChain->rank))
- {
- triggered_spell_id = itr->first;
- chain = newChain;
- }
- else
- continue;
- // Found spell is last in chain - do not need to look more
- // Optimisation for most common case
- if(chain && chain->last == itr->first)
- break;
- }
- }
- }
- // Item - Death Knight T10 Melee 4P Bonus
- if(dummySpell->Id == 70656)
- {
- Player* player = ToPlayer();
- if(!player)
- return false;
- for(uint32 i = 0; i < MAX_RUNES; ++i)
- if(player->GetRuneCooldown(i) == 0)
- return false;
- }
- break;
- }
- case SPELLFAMILY_POTION:
- {
- // alchemist's stone
- if(dummySpell->Id == 17619)
- {
- if(procSpell->SpellFamilyName == SPELLFAMILY_POTION)
- {
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; i++)
- {
- if(procSpell->Effect[i] == SPELL_EFFECT_HEAL)
- {
- triggered_spell_id = 21399;
- }
- else if(procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
- {
- triggered_spell_id = 21400;
- }
- else
- continue;
- basepoints0 = int32(CalculateSpellDamage(this, procSpell, i) * 0.4f);
- CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura);
- }
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_PET:
- {
- switch(dummySpell->SpellIconID)
- {
- // Guard Dog
- case 201:
- {
- if(!victim)
- return false;
- triggered_spell_id = 54445;
- target = this;
- float addThreat = float(CalculatePctN(SpellMgr::CalculateSpellEffectAmount(procSpell, 0, this), triggerAmount));
- victim->AddThreat(this, addThreat);
- break;
- }
- // Silverback
- case 1582:
- triggered_spell_id = dummySpell->Id == 62765 ? 62801 : 62800;
- target = this;
- break;
- }
- break;
- }
- default:
- break;
- }
- // if not handled by custom case, get triggered spell from dummySpell proto
- if(!triggered_spell_id)
- triggered_spell_id = dummySpell->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
- // processed charge only counting case
- if(!triggered_spell_id)
- return true;
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
- // default case
- if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
- return false;
- if(cooldown_spell_id == 0)
- cooldown_spell_id = triggered_spell_id;
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(cooldown_spell_id))
- return false;
- if(basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura, originalCaster);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(cooldown_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
- {
- SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
- switch(dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_HUNTER:
- {
- // Aspect of the Viper
- if(dummySpell->SpellFamilyFlags[1] & 0x40000)
- {
- uint32 maxmana = GetMaxPower(POWER_MANA);
- basepoints0 = CalculatePctF(maxmana, GetAttackTime(RANGED_ATTACK) / 1000.0f);
- target = this;
- triggered_spell_id = 34075;
- break;
- }
- break;
- }
- }
- // processed charge only counting case
- if(!triggered_spell_id)
- return true;
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- // Try handle unknown trigger spells
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
- // default case
- if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
- return false;
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if(basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
- {
- SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
- switch(dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_PALADIN:
- {
- // Blessing of Sanctuary
- if(dummySpell->SpellFamilyFlags[0] & 0x10000000)
- {
- switch(getPowerType())
- {
- case POWER_MANA: triggered_spell_id = 57319; break;
- default:
- return false;
- }
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- // Recklessness - prevent double proc
- if(dummySpell->Id == 1719)
- return false;
- break;
- }
- }
- // processed charge only counting case
- if(!triggered_spell_id)
- return true;
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleModDamagePctTakenAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
- // default case
- if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
- return false;
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if(basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- // Used in case when access to whole aura is needed
- // All procs should be handled like this...
- bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 /*procFlag*/, uint32 procEx, uint32 cooldown, bool * handled)
- {
- SpellEntry const* dummySpell = triggeredByAura->GetSpellProto();
- switch(dummySpell->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- switch(dummySpell->Id)
- {
- // Nevermelting Ice Crystal
- case 71564:
- RemoveAuraFromStack(71564);
- *handled = true;
- break;
- case 71756:
- case 72782:
- case 72783:
- case 72784:
- RemoveAuraFromStack(dummySpell->Id);
- *handled = true;
- break;
- // Discerning Eye of the Beast
- case 59915:
- {
- CastSpell(this, 59914, true); // 59914 already has correct basepoints in DBC, no need for custom bp
- *handled = true;
- break;
- }
- // Swift Hand of Justice
- case 59906:
- {
- int32 bp0 = CalculatePctN(GetMaxHealth(), SpellMgr::CalculateSpellEffectAmount(dummySpell, 0));
- CastCustomSpell(this, 59913, &bp0, NULL, NULL, true);
- *handled = true;
- break;
- }
- // Vigilance - original proc picking wrong target
- case 50720:
- {
- *handled = true;
- if(Unit* caster = triggeredByAura->GetCaster())
- {
- CastSpell(caster, 50725, true);
- return true;
- }
- return false;
- }
- }
- break;
- case SPELLFAMILY_PALADIN:
- {
- // Infusion of Light
- if(dummySpell->SpellIconID == 3021)
- {
- // Flash of Light HoT on Flash of Light when Sacred Shield active
- if(procSpell->SpellFamilyFlags[0] & 0x40000000 && procSpell->SpellIconID == 242)
- {
- *handled = true;
- if (victim && victim->HasAura(53601))
- {
- int32 bp0 = CalculatePctN(int32(damage / 12), SpellMgr::CalculateSpellEffectAmount(dummySpell, 2));
- // Item - Paladin T9 Holy 4P Bonus
- if(AuraEffect const* aurEff = GetAuraEffect(67191, 0))
- AddPctN(bp0, aurEff->GetAmount());
- CastCustomSpell(victim, 66922, &bp0, NULL, NULL, true);
- return true;
- }
- }
- // but should not proc on non-critical Holy Shocks
- else if((procSpell->SpellFamilyFlags[0] & 0x200000 || procSpell->SpellFamilyFlags[1] & 0x10000) && !(procEx & PROC_EX_CRITICAL_HIT))
- *handled = true;
- break;
- }
- // Judgements of the Just
- else if(dummySpell->SpellIconID == 3015)
- {
- *handled = true;
- CastSpell(victim, 68055, true);
- return true;
- }
- // Glyph of Divinity
- else if(dummySpell->Id == 54939)
- {
- *handled = true;
- // Check if we are the target and prevent mana gain
- if(triggeredByAura->GetCasterGUID() == victim->GetGUID())
- return false;
- // Lookup base amount mana restore
- for(uint8 i = 0; i<MAX_SPELL_EFFECTS; i++)
- {
- if(procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE)
- {
- // value multiplied by 2 because you should get twice amount
- int32 mana = SpellMgr::CalculateSpellEffectAmount(procSpell, i) * 2;
- CastCustomSpell(this, 54986, 0, &mana, NULL, true);
- }
- }
- return true;
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- switch(dummySpell->Id)
- {
- case 8178: // Grounding Totem
- {
- *handled = true;
- break;
- }
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Combustion
- switch(dummySpell->Id)
- {
- case 11129:
- {
- if(Aura* aura = GetAura(28682))
- {
- if(aura->GetStackAmount() == 10)
- {
- RemoveAurasDueToSpell(11129);
- return false;
- }
- }
- *handled = true;
- Unit* pCaster = triggeredByAura->GetCaster();
- if(!pCaster || !damage)
- return false;
- // last charge and crit
- if(triggeredByAura->GetCharges() <= 1 && (procEx & PROC_EX_CRITICAL_HIT))
- return true; // charge counting (will removed)
- CastSpell(this, 28682, true);
- return (procEx & PROC_EX_CRITICAL_HIT) ? true : false;
- }
- // Empowered Fire
- case 31656:
- case 31657:
- case 31658:
- {
- *handled = true;
- SpellEntry const* spInfo = sSpellStore.LookupEntry(67545);
- if(!spInfo)
- return false;
- int32 bp0 = int32(CalculatePctN(GetCreateMana(), SpellMgr::CalculateSpellEffectAmount(spInfo, 0)));
- CastCustomSpell(this, 67545, &bp0, NULL, NULL, true, NULL, triggeredByAura->GetEffect(EFFECT_0), GetGUID());
- return true;
- }
- }
- break;
- }
- case SPELLFAMILY_ROGUE:
- {
- // prevent proc of Savage Combat
- if(dummySpell->SpellIconID == 1959)
- *handled = true;
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Blood of the North
- // Reaping
- // Death Rune Mastery
- if(dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622)
- {
- *handled = true;
- // Convert recently used Blood Rune to Death Rune
- if(Player* plr = ToPlayer())
- {
- if(!plr || plr->getClass() != CLASS_DEATH_KNIGHT)
- return false;
- RuneType rune = ToPlayer()->GetLastUsedRune();
- // can't proc from death rune use
- if(rune == RUNE_DEATH)
- return false;
- AuraEffect* aurEff = triggeredByAura->GetEffect(EFFECT_0);
- if(!aurEff)
- return false;
- // Reset amplitude - set death rune remove timer to 30s
- aurEff->ResetPeriodic(true);
- uint32 runesLeft;
- if(dummySpell->SpellIconID == 2622)
- runesLeft = 2;
- else
- runesLeft = 1;
- for(uint8 i = 0; i < MAX_RUNES && runesLeft; ++i)
- {
- if(dummySpell->SpellIconID == 2622)
- {
- if(plr->GetCurrentRune(i) == RUNE_DEATH ||
- plr->GetBaseRune(i) == RUNE_BLOOD)
- continue;
- }
- else
- {
- if(plr->GetCurrentRune(i) == RUNE_DEATH ||
- plr->GetBaseRune(i) != RUNE_BLOOD)
- continue;
- }
- if(plr->GetRuneCooldown(i) != plr->GetRuneBaseCooldown(i))
- continue;
- --runesLeft;
- // Mark aura as used
- plr->AddRuneByAuraEffect(i, RUNE_DEATH, aurEff);
- }
- return true;
- }
- return false;
- }
- switch(dummySpell->Id)
- {
- // Bone Shield cooldown
- case 49222:
- {
- *handled = true;
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- {
- if(ToPlayer()->HasSpellCooldown(100000))
- return false;
- ToPlayer()->AddSpellCooldown(100000, 0, time(NULL) + cooldown);
- }
- return true;
- }
- // Hungering Cold aura drop
- case 51209:
- *handled = true;
- // Drop only in not disease case
- if(procSpell && procSpell->Dispel == DISPEL_DISEASE)
- return false;
- return true;
- }
- break;
- }
- case SPELLFAMILY_WARRIOR:
- {
- switch(dummySpell->Id)
- {
- // Item - Warrior T10 Protection 4P Bonus
- case 70844:
- {
- int32 basepoints0 = CalculatePctN(GetMaxHealth(), SpellMgr::CalculateSpellEffectAmount(dummySpell, 1));
- CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true);
- break;
- }
- }
- }
- }
- return false;
- }
- bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
- {
- // Get triggered aura spell info
- SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
- // Basepoints of trigger aura
- int32 triggerAmount = triggeredByAura->GetAmount();
- // Set trigger spell id, target, custom basepoints
- uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
- Unit* target = NULL;
- int32 basepoints0 = 0;
- if(triggeredByAura->GetAuraType() == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE)
- basepoints0 = triggerAmount;
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- // Try handle unknown trigger spells
- if(sSpellStore.LookupEntry(trigger_spell_id) == NULL)
- {
- switch(auraSpellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- switch(auraSpellInfo->Id)
- {
- case 23780: // Aegis of Preservation (Aegis of Preservation trinket)
- trigger_spell_id = 23781;
- break;
- case 33896: // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
- trigger_spell_id = 33898;
- break;
- case 43820: // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
- // Pct value stored in dummy
- basepoints0 = victim->GetCreateHealth() * SpellMgr::CalculateSpellEffectAmount(auraSpellInfo, 1) / 100;
- target = victim;
- break;
- case 57345: // Darkmoon Card: Greatness
- {
- float stat = 0.0f;
- // strength
- if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229; stat = GetStat(STAT_STRENGTH); }
- // agility
- if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233; stat = GetStat(STAT_AGILITY); }
- // intellect
- if(GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234; stat = GetStat(STAT_INTELLECT);}
- // spirit
- if(GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235; }
- break;
- }
- case 64568: // Blood Reserve
- {
- if(HealthBelowPctDamaged(35, damage))
- {
- basepoints0 = triggerAmount;
- trigger_spell_id = 64569;
- RemoveAura(64568);
- }
- break;
- }
- case 67702: // Death's Choice, Item - Coliseum 25 Normal Melee Trinket
- {
- float stat = 0.0f;
- // strength
- if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67708;stat = GetStat(STAT_STRENGTH); }
- // agility
- if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67703; }
- break;
- }
- case 67771: // Death's Choice (heroic), Item - Coliseum 25 Heroic Melee Trinket
- {
- float stat = 0.0f;
- // strength
- if(GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67773;stat = GetStat(STAT_STRENGTH); }
- // agility
- if(GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67772; }
- break;
- }
- // Mana Drain Trigger
- case 27522:
- case 40336:
- {
- // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
- if(isAlive())
- CastSpell(this, 29471, true, castItem, triggeredByAura);
- if(victim && victim->isAlive())
- CastSpell(victim, 27526, true, castItem, triggeredByAura);
- return true;
- }
- // Evasive Maneuvers
- case 50240:
- {
- // Remove a Evasive Charge
- Aura* charge = GetAura(50241);
- if (charge->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL))
- RemoveAurasDueToSpell(50240);
- }
- }
- break;
- case SPELLFAMILY_MAGE:
- if(auraSpellInfo->SpellIconID == 2127) // Blazing Speed
- {
- switch(auraSpellInfo->Id)
- {
- case 31641: // Rank 1
- case 31642: // Rank 2
- trigger_spell_id = 31643;
- break;
- default:
- sLog->outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed", auraSpellInfo->Id);
- return false;
- }
- }
- break;
- case SPELLFAMILY_WARRIOR:
- if(auraSpellInfo->Id == 50421) // Scent of Blood
- {
- CastSpell(this, 50422, true);
- RemoveAuraFromStack(auraSpellInfo->Id);
- return false;
- }
- break;
- case SPELLFAMILY_WARLOCK:
- {
- // Drain Soul
- if(auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
- {
- // Improved Drain Soul
- Unit::AuraEffectList const& mAddFlatModifier = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
- {
- if((*i)->GetMiscValue() == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
- {
- int32 value2 = CalculateSpellDamage(this, (*i)->GetSpellProto(), 2);
- basepoints0 = int32(CalculatePctN(GetMaxPower(POWER_MANA), value2));
- // Drain Soul
- CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- break;
- }
- }
- // Not remove charge (aura removed on death in any cases)
- // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura
- return false;
- }
- // Nether Protection
- else if(auraSpellInfo->SpellIconID == 1985)
- {
- if(!procSpell)
- return false;
- switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
- {
- case SPELL_SCHOOL_NORMAL:
- return false; // ignore
- case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break;
- case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break;
- case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break;
- case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break;
- case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break;
- case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
- default:
- return false;
- }
- }
- break;
- }
- case SPELLFAMILY_PRIEST:
- {
- // Greater Heal Refund
- if(auraSpellInfo->Id == 37594)
- trigger_spell_id = 37595;
- // Blessed Recovery
- else if(auraSpellInfo->SpellIconID == 1875)
- {
- switch(auraSpellInfo->Id)
- {
- case 27811: trigger_spell_id = 27813; break;
- case 27815: trigger_spell_id = 27817; break;
- case 27816: trigger_spell_id = 27818; break;
- default:
- sLog->outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
- return false;
- }
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / 3;
- target = this;
- // Add remaining ticks to healing done
- basepoints0 += GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_HEAL);
- }
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- switch(auraSpellInfo->Id)
- {
- // Druid Forms Trinket
- case 37336:
- {
- switch(GetShapeshiftForm())
- {
- case FORM_NONE: trigger_spell_id = 37344; break;
- case FORM_CAT: trigger_spell_id = 37341; break;
- case FORM_BEAR:
- case FORM_DIREBEAR: trigger_spell_id = 37340; break;
- case FORM_TREE: trigger_spell_id = 37342; break;
- case FORM_MOONKIN: trigger_spell_id = 37343; break;
- default:
- return false;
- }
- break;
- }
- // Druid T9 Feral Relic (Lacerate, Swipe, Mangle, and Shred)
- case 67353:
- {
- switch(GetShapeshiftForm())
- {
- case FORM_CAT: trigger_spell_id = 67355; break;
- case FORM_BEAR:
- case FORM_DIREBEAR: trigger_spell_id = 67354; break;
- default:
- return false;
- }
- break;
- }
- default:
- break;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- if(auraSpellInfo->SpellIconID == 3247) // Piercing Shots
- {
- switch(auraSpellInfo->Id)
- {
- case 53234: // Rank 1
- case 53237: // Rank 2
- case 53238: // Rank 3
- trigger_spell_id = 63468;
- break;
- default:
- sLog->outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots", auraSpellInfo->Id);
- return false;
- }
- SpellEntry const* TriggerPS = sSpellStore.LookupEntry(trigger_spell_id);
- if(!TriggerPS)
- return false;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount) / (GetSpellMaxDuration(TriggerPS) / TriggerPS->EffectAmplitude[0]);
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), trigger_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- switch(auraSpellInfo->Id)
- {
- // Healing Discount
- case 37705:
- {
- trigger_spell_id = 37706;
- target = this;
- break;
- }
- // Soul Preserver
- case 60510:
- {
- trigger_spell_id = 60515;
- target = this;
- break;
- }
- // Lightning Capacitor
- case 37657:
- {
- if(!victim || !victim->isAlive())
- return false;
- // stacking
- CastSpell(this, 37658, true, NULL, triggeredByAura);
- Aura* dummy = GetAura(37658);
- // release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetStackAmount() < triggerAmount)
- return false;
- RemoveAurasDueToSpell(37658);
- trigger_spell_id = 37661;
- target = victim;
- break;
- }
- // Thunder Capacitor
- case 54841:
- {
- if(!victim || !victim->isAlive())
- return false;
- // stacking
- CastSpell(this, 54842, true, NULL, triggeredByAura);
- // counting
- Aura* dummy = GetAura(54842);
- // release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetStackAmount() < triggerAmount)
- return false;
- RemoveAurasDueToSpell(54842);
- trigger_spell_id = 54843;
- target = victim;
- break;
- }
- //Item - Coliseum 25 Normal Caster Trinket
- case 67712:
- {
- if(!victim || !victim->isAlive())
- return false;
- // stacking
- CastSpell(this, 67713, true, NULL, triggeredByAura);
- Aura* dummy = GetAura(67713);
- // release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetStackAmount() < triggerAmount)
- return false;
- RemoveAurasDueToSpell(67713);
- trigger_spell_id = 67714;
- target = victim;
- break;
- }
- //Item - Coliseum 25 Heroic Caster Trinket
- case 67758:
- {
- if(!victim || !victim->isAlive())
- return false;
- // stacking
- CastSpell(this, 67759, true, NULL, triggeredByAura);
- Aura* dummy = GetAura(67759);
- // release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetStackAmount() < triggerAmount)
- return false;
- RemoveAurasDueToSpell(67759);
- trigger_spell_id = 67760;
- target = victim;
- break;
- }
- default:
- // Illumination
- if(auraSpellInfo->SpellIconID == 241)
- {
- if(!procSpell)
- return false;
- // procspell is triggered spell but we need mana cost of original casted spell
- uint32 originalSpellId = procSpell->Id;
- // Holy Shock heal
- if(procSpell->SpellFamilyFlags[1] & 0x00010000)
- {
- switch(procSpell->Id)
- {
- case 25914: originalSpellId = 20473; break;
- case 25913: originalSpellId = 20929; break;
- case 25903: originalSpellId = 20930; break;
- case 27175: originalSpellId = 27174; break;
- case 33074: originalSpellId = 33072; break;
- case 48820: originalSpellId = 48824; break;
- case 48821: originalSpellId = 48825; break;
- default:
- sLog->outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock", procSpell->Id);
- return false;
- }
- }
- SpellEntry const* originalSpell = sSpellStore.LookupEntry(originalSpellId);
- if(!originalSpell)
- {
- sLog->outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu", originalSpellId);
- return false;
- }
- // percent stored in effect 1 (class scripts) base points
- int32 cost = int32(originalSpell->manaCost + CalculatePctU(GetCreateMana(), originalSpell->ManaCostPercentage));
- basepoints0 = CalculatePctN(cost, SpellMgr::CalculateSpellEffectAmount(auraSpellInfo, 1));
- trigger_spell_id = 20272;
- target = this;
- }
- break;
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- switch(auraSpellInfo->Id)
- {
- // Lightning Shield (The Ten Storms set)
- case 23551:
- {
- trigger_spell_id = 23552;
- target = victim;
- break;
- }
- // Damage from Lightning Shield (The Ten Storms set)
- case 23552:
- {
- trigger_spell_id = 27635;
- break;
- }
- // Mana Surge (The Earthfury set)
- case 23572:
- {
- if(!procSpell)
- return false;
- basepoints0 = int32(CalculatePctN(procSpell->manaCost, 35));
- trigger_spell_id = 23571;
- target = this;
- break;
- }
- default:
- {
- // Lightning Shield (overwrite non existing triggered spell call in spell.dbc
- if(auraSpellInfo->SpellFamilyFlags[0] & 0x400)
- {
- trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, sSpellMgr->GetSpellRank(auraSpellInfo->Id));
- }
- // Nature's Guardian
- else if(auraSpellInfo->SpellIconID == 2013)
- {
- // Check health condition - should drop to less 30% (damage deal after this!)
- if(!HealthBelowPctDamaged(30, damage))
- return false;
- if(victim && victim->isAlive())
- victim->getThreatManager().modifyThreatPercent(this, -10);
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- trigger_spell_id = 31616;
- target = this;
- }
- }
- }
- break;
- }
- case SPELLFAMILY_DEATHKNIGHT:
- {
- // Acclimation
- if(auraSpellInfo->SpellIconID == 1930)
- {
- if(!procSpell)
- return false;
- switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
- {
- case SPELL_SCHOOL_NORMAL:
- return false; // ignore
- case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break;
- case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break;
- case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break;
- case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break;
- case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break;
- case SPELL_SCHOOL_ARCANE: trigger_spell_id = 50486; break;
- default:
- return false;
- }
- }
- // Blood Presence (Improved)
- else if(auraSpellInfo->Id == 63611)
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- trigger_spell_id = 50475;
- basepoints0 = CalculatePctN(int32(damage), triggerAmount);
- }
- break;
- }
- default:
- break;
- }
- }
- // All ok. Check current trigger spell
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
- if(triggerEntry == NULL)
- {
- // Not cast unknown spell
- // sLog->outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", auraSpellInfo->Id, triggeredByAura->GetEffIndex());
- return false;
- }
- // not allow proc extra attack spell at extra attack
- if(m_extraAttacks && IsSpellHaveEffect(triggerEntry, SPELL_EFFECT_ADD_EXTRA_ATTACKS))
- return false;
- // Custom requirements (not listed in procEx) Warning! damage dealing after this
- // Custom triggered spells
- switch(auraSpellInfo->Id)
- {
- // Deep Wounds
- case 12834:
- case 12849:
- case 12867:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // now compute approximate weapon damage by formula from wowwiki.com
- Item* item = NULL;
- if(procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK)
- item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
- else
- item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- // dunno if it's really needed but will prevent any possible crashes
- if(!item)
- return false;
- ItemTemplate const* weapon = item->GetTemplate();
- float weaponDPS = weapon->getDPS();
- float attackPower = GetTotalAttackPowerValue(BASE_ATTACK) / 14.0f;
- float weaponSpeed = float(weapon->Delay) / 1000.0f;
- basepoints0 = int32((weaponDPS + attackPower) * weaponSpeed);
- break;
- }
- // Persistent Shield (Scarab Brooch trinket)
- // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
- case 26467:
- {
- basepoints0 = int32(CalculatePctN(damage, 15));
- target = victim;
- trigger_spell_id = 26470;
- break;
- }
- // Unyielding Knights (item exploit 29108\29109)
- case 38164:
- {
- if(!victim || victim->GetEntry() != 19457) // Proc only if your target is Grillok
- return false;
- break;
- }
- // Deflection
- case 52420:
- {
- if(!HealthBelowPct(35))
- return false;
- break;
- }
- case 28845: // Cheat Death
- {
- // When your health drops below 20%
- if(HealthBelowPctDamaged(20, damage) || HealthBelowPct(20))
- return false;
- break;
- }
- // Deadly Swiftness (Rank 1)
- case 31255:
- {
- // whenever you deal damage to a target who is below 20% health.
- if(!victim || !victim->isAlive() || victim->HealthAbovePct(20))
- return false;
- target = this;
- trigger_spell_id = 22588;
- }
- // Greater Heal Refund (Avatar Raiment set)
- case 37594:
- {
- if(!victim || !victim->isAlive())
- return false;
- // Not give if target already have full health
- if(victim->IsFullHealth())
- return false;
- // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
- if(victim->GetHealth() + damage < victim->GetMaxHealth())
- return false;
- break;
- }
- // Bonus Healing (Crystal Spire of Karabor mace)
- case 40971:
- {
- // If your target is below $s1% health
- if(!victim || !victim->isAlive() || victim->HealthAbovePct(triggerAmount))
- return false;
- break;
- }
- // Rapid Recuperation
- case 53228:
- case 53232:
- {
- // This effect only from Rapid Fire (ability cast)
- if(!(procSpell->SpellFamilyFlags[0] & 0x20))
- return false;
- break;
- }
- // Decimation
- case 63156:
- case 63158:
- // Can proc only if target has hp below 35%
- if(!victim || !victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this))
- return false;
- break;
- // Deathbringer Saurfang - Rune of Blood
- case 72408:
- // can proc only if target is marked with rune
- // this should be handled by targetAuraSpell, but because 72408 is not passive
- // one failed proc will remove the entire aura
- if(!victim->HasAura(72410))
- return false;
- break;
- // Deathbringer Saurfang - Blood Beast's Blood Link
- case 72176:
- basepoints0 = 3;
- break;
- // Deathbringer Saurfang - Mark of the Fallen Champion
- case 72256:
- // this should be handled by targetAuraSpell, but because 72408 is not passive
- // one failed proc will remove the entire aura
- CastSpell(NULL, trigger_spell_id, true, NULL, triggeredByAura);
- return true;
- case 15337: // Improved Spirit Tap (Rank 1)
- case 15338: // Improved Spirit Tap (Rank 2)
- {
- if(procSpell->SpellFamilyFlags[0] & 0x800000)
- if((procSpell->Id != 58381) || !roll_chance_i(50))
- return false;
- target = victim;
- break;
- }
- // Professor Putricide - Ooze Spell Tank Protection
- case 71770:
- if(victim)
- victim->CastSpell(victim, trigger_spell_id, true); // EffectImplicitTarget is self
- return true;
- case 45057: // Evasive Maneuvers (Commendation of Kael`thas trinket)
- case 71634: // Item - Icecrown 25 Normal Tank Trinket 1
- case 71640: // Item - Icecrown 25 Heroic Tank Trinket 1
- case 75475: // Item - Chamber of Aspects 25 Normal Tank Trinket
- case 75481: // Item - Chamber of Aspects 25 Heroic Tank Trinket
- {
- // Procs only if damage takes health below $s1%
- if(!HealthBelowPctDamaged(triggerAmount, damage))
- return false;
- break;
- }
- case 55689: // Glyph of Shadow only in shadow form
- if(GetTypeId() == TYPEID_PLAYER)
- if(Player* pPlayer = this->ToPlayer()) {
- if(pPlayer->GetShapeshiftForm() != FORM_SHADOW)
- return false;
- }
- break;
- case 44404: case 54486: case 54488: case 54489: case 54490: //Missile Barrage rank 1-5
- if(!procSpell->SpellFamilyFlags.HasFlag(0x20000000, 0, 0)) //for Arcane Blast normal proc chance
- if(urand(0, 1))
- return false; //for Arcane Barrage, Fireball, Frostbolt, Frostfire Bolt proc chance is halved
- break;
- default:
- break;
- }
- // Sword Specialization
- if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_GENERIC && auraSpellInfo->SpellIconID == 1462 && procSpell)
- {
- if(Player* plr = ToPlayer())
- {
- if(cooldown && plr->HasSpellCooldown(16459))
- return false;
- // this required for attacks like Mortal Strike
- plr->RemoveSpellCooldown(procSpell->Id);
- CastSpell(victim, procSpell->Id, true);
- if(cooldown)
- plr->AddSpellCooldown(16459, 0, time(NULL) + cooldown);
- return true;
- }
- }
- // Blade Barrier
- if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 85)
- {
- Player* plr = ToPlayer();
- if(!plr || plr->getClass() != CLASS_DEATH_KNIGHT)
- return false;
- if(!plr->IsBaseRuneSlotsOnCooldown(RUNE_BLOOD))
- return false;
- }
- // Rime
- else if(auraSpellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && auraSpellInfo->SpellIconID == 56)
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- // Howling Blast
- ToPlayer()->RemoveSpellCategoryCooldown(1248, true);
- }
- // Custom basepoints/target for exist spell
- // dummy basepoints or other customs
- switch(trigger_spell_id)
- {
- // Auras which should proc on area aura source (caster in this case):
- // Turn the Tables
- case 52914:
- case 52915:
- case 52910:
- // Honor Among Thieves
- case 52916:
- {
- target = triggeredByAura->GetBase()->GetCaster();
- if(!target)
- return false;
- if(cooldown && target->GetTypeId() == TYPEID_PLAYER && target->ToPlayer()->HasSpellCooldown(trigger_spell_id))
- return false;
- target->CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- // Cast positive spell on enemy target
- case 7099: // Curse of Mending
- case 39703: // Curse of Mending
- case 29494: // Temptation
- case 20233: // Improved Lay on Hands (cast on target)
- {
- target = victim;
- break;
- }
- // Combo points add triggers (need add combopoint only for main target, and after possible combopoints reset)
- case 15250: // Rogue Setup
- {
- // applied only for main target
- if(!victim || (GetTypeId() == TYPEID_PLAYER && victim != ToPlayer()->GetSelectedUnit()))
- return false;
- break; // continue normal case
- }
- // Finish movies that add combo
- case 14189: // Seal Fate (Netherblade set)
- case 14157: // Ruthlessness
- case 70802: // Rogue T10 4P Bonus
- {
- if(!victim || victim == this)
- return false;
- // Need add combopoint AFTER finish movie (or they dropped in finish phase)
- break;
- }
- case 16870: // Item - Druid T10 Balance 2P Bonus
- {
- if(HasAura(70718))
- CastSpell(this, 70721, true);
- break;
- }
- // Bloodthirst (($m/100)% of max health)
- case 23880:
- {
- basepoints0 = int32(CountPctFromMaxHealth(triggerAmount));
- break;
- }
- // Shamanistic Rage triggered spell
- case 30824:
- {
- basepoints0 = int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), triggerAmount));
- break;
- }
- // Enlightenment (trigger only from mana cost spells)
- case 35095:
- {
- if(!procSpell || procSpell->powerType != POWER_MANA || (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0 && procSpell->manaCostPerlevel == 0))
- return false;
- break;
- }
- // Demonic Pact
- case 48090:
- {
- // Get talent aura from owner
- if(isPet())
- if(Unit* owner = GetOwner())
- {
- if(AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0))
- {
- basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonus(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); // TODO: Is it right?
- CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura);
- return true;
- }
- }
- break;
- }
- case 46916: // Slam!
- case 52437: // Sudden Death
- {
- // Item - Warrior T10 Melee 4P Bonus
- if(AuraEffect const* aurEff = GetAuraEffect(70847, EFFECT_0))
- {
- int32 amount = aurEff->GetAmount();
- if(roll_chance_i(amount))
- CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge
- if(roll_chance_i(amount))
- CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced
- if(roll_chance_i(amount))
- CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced
- }
- break;
- }
- // Sword and Board
- case 50227:
- {
- // Remove cooldown on Shield Slam
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCategoryCooldown(1209, true);
- break;
- }
- // Maelstrom Weapon
- case 53817:
- {
- // have rank dependent proc chance, ignore too often cases
- // PPM = 2.5 * (rank of talent),
- uint32 rank = sSpellMgr->GetSpellRank(auraSpellInfo->Id);
- // 5 rank -> 100% 4 rank -> 80% and etc from full rate
- if(!roll_chance_i(20*rank))
- return false;
- // Item - Shaman T10 Enhancement 4P Bonus
- if(AuraEffect const* aurEff = GetAuraEffect(70832, 0))
- if(Aura const* maelstrom = GetAura(53817))
- if((maelstrom->GetStackAmount() == maelstrom->GetSpellProto()->StackAmount) && roll_chance_i(aurEff->GetAmount()))
- CastSpell(this, 70831, true, castItem, triggeredByAura);
- break;
- }
- // Astral Shift
- case 52179:
- {
- if(procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == victim)
- return false;
- // Need stun, fear or silence mechanic
- if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_SILENCE)|(1<<MECHANIC_STUN)|(1<<MECHANIC_FEAR))))
- return false;
- break;
- }
- // Burning Determination
- case 54748:
- {
- if(!procSpell)
- return false;
- // Need Interrupt or Silenced mechanic
- if(!(GetAllSpellMechanicMask(procSpell) & ((1<<MECHANIC_INTERRUPT)|(1<<MECHANIC_SILENCE))))
- return false;
- break;
- }
- // Lock and Load
- case 56453:
- {
- // Proc only from Frost/Freezing trap activation or from Freezing Arrow (the periodic dmg proc handled elsewhere)
- if(!(procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION) || !procSpell || !(procSpell->SchoolMask & SPELL_SCHOOL_MASK_FROST) || !roll_chance_i(triggerAmount))
- return false;
- break;
- }
- // Glyph of Death's Embrace
- case 58679:
- {
- // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags
- if(!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000))
- return false;
- break;
- }
- // Glyph of Death Grip
- case 58628:
- {
- // remove cooldown of Death Grip
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->RemoveSpellCooldown(49576, true);
- return true;
- }
- // Savage Defense
- case 62606:
- {
- basepoints0 = CalculatePctF(triggerAmount, GetTotalAttackPowerValue(BASE_ATTACK));
- break;
- }
- // Body and Soul
- case 64128:
- case 65081:
- {
- // Proc only from PW:S cast
- if(!(procSpell->SpellFamilyFlags[0] & 0x00000001))
- return false;
- break;
- }
- // Culling the Herd
- case 70893:
- {
- // check if we're doing a critical hit
- if(!(procSpell->SpellFamilyFlags[1] & 0x10000000) && (procEx != PROC_EX_CRITICAL_HIT) )
- return false;
- // check if we're procced by Claw, Bite or Smack (need to use the spell icon ID to detect it)
- if(!(procSpell->SpellIconID == 262 || procSpell->SpellIconID == 1680 || procSpell->SpellIconID == 473 ))
- return false;
- break;
- }
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- if(GetTypeId() != TYPEID_PLAYER)
- return false;
- Player* player = ToPlayer();
- if(player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Unholy Infusion
- {
- if(!player->HasAura(71516) || victim->GetEntry() != 36678) // Shadow Infusion && Professor Putricide
- return false;
- }
- else if(player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Blood Infusion
- {
- if(!player->HasAura(72154) || victim->GetEntry() != 37955) // Thirst Quenched && Blood-Queen Lana'thel
- return false;
- }
- else if(player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE && (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)) // Frost Infusion
- {
- if(!player->HasAura(72290) || victim->GetEntry() != 36853) // Frost-Imbued Blade && Sindragosa
- return false;
- }
- else if(player->GetQuestStatus(24547) != QUEST_STATUS_INCOMPLETE) // A Feast of Souls
- return false;
- if(victim->GetTypeId() != TYPEID_UNIT)
- return false;
- // critters are not allowed
- if(victim->GetCreatureType() == CREATURE_TYPE_CRITTER)
- return false;
- break;
- }
- }
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
- return false;
- // try detect target manually if not set
- if(target == NULL)
- target = !(procFlags & (PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS | PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS)) && IsPositiveSpell(trigger_spell_id) ? this : victim;
- // default case
- if((!target && !sSpellMgr->IsSrcTargetSpell(triggerEntry)) || (target && target != this && !target->isAlive()))
- return false;
- if(basepoints0)
- CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, trigger_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(trigger_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- bool Unit::HandleOverrideClassScriptAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellEntry const* procSpell, uint32 cooldown)
- {
- int32 scriptId = triggeredByAura->GetMiscValue();
- if(!victim || !victim->isAlive())
- return false;
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
- uint32 triggered_spell_id = 0;
- switch(scriptId)
- {
- case 836: // Improved Blizzard (Rank 1)
- {
- if(!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12484;
- break;
- }
- case 988: // Improved Blizzard (Rank 2)
- {
- if(!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12485;
- break;
- }
- case 989: // Improved Blizzard (Rank 3)
- {
- if(!procSpell || procSpell->SpellVisual[0] != 9487)
- return false;
- triggered_spell_id = 12486;
- break;
- }
- case 4533: // Dreamwalker Raiment 2 pieces bonus
- {
- // Chance 50%
- if(!roll_chance_i(50))
- return false;
- switch(victim->getPowerType())
- {
- case POWER_MANA: triggered_spell_id = 28722; break;
- case POWER_RAGE: triggered_spell_id = 28723; break;
- case POWER_ENERGY: triggered_spell_id = 28724; break;
- default:
- return false;
- }
- break;
- }
- case 4537: // Dreamwalker Raiment 6 pieces bonus
- triggered_spell_id = 28750; // Blessing of the Claw
- break;
- case 5497: // Improved Mana Gems
- triggered_spell_id = 37445; // Mana Surge
- break;
- case 7010: // Revitalize - can proc on full hp target
- case 7011:
- case 7012:
- {
- if(!roll_chance_i(triggeredByAura->GetAmount()))
- return false;
- switch(victim->getPowerType())
- {
- case POWER_MANA: triggered_spell_id = 48542; break;
- case POWER_RAGE: triggered_spell_id = 48541; break;
- case POWER_ENERGY: triggered_spell_id = 48540; break;
- case POWER_RUNIC_POWER: triggered_spell_id = 48543; break;
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
- // not processed
- if(!triggered_spell_id)
- return false;
- // standard non-dummy case
- SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
- if(!triggerEntry)
- {
- sLog->outError("Unit::HandleOverrideClassScriptAuraProc: Spell %u triggering for class script id %u", triggered_spell_id, scriptId);
- return false;
- }
- if(cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- CastSpell(victim, triggered_spell_id, true, castItem, triggeredByAura);
- if(cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
- }
- void Unit::setPowerType(Powers new_powertype)
- {
- SetByteValue(UNIT_FIELD_BYTES_0, 3, new_powertype);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- if(ToPlayer()->GetGroup())
- ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
- }
- else if(Pet* pet = ToCreature()->ToPet())
- {
- if(pet->isControlled())
- {
- Unit* owner = GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
- owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
- }
- }
- switch(new_powertype)
- {
- default:
- case POWER_MANA:
- break;
- case POWER_RAGE:
- SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE));
- SetPower(POWER_RAGE, 0);
- break;
- case POWER_FOCUS:
- SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
- SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS));
- break;
- case POWER_ENERGY:
- SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY));
- break;
- case POWER_HAPPINESS:
- SetMaxPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
- SetPower(POWER_HAPPINESS, GetCreatePowers(POWER_HAPPINESS));
- break;
- }
- }
- FactionTemplateEntry const* Unit::getFactionTemplateEntry() const
- {
- FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(getFaction());
- if(!entry)
- {
- static uint64 guid = 0; // prevent repeating spam same faction problem
- if(GetGUID() != guid)
- {
- if(Player const* player = ToPlayer())
- sLog->outError("Player %s has invalid faction (faction template id) #%u", player->GetName(), getFaction());
- else if(Creature const* creature = ToCreature())
- sLog->outError("Creature (template id: %u) has invalid faction (faction template id) #%u", creature->GetCreatureInfo()->Entry, getFaction());
- else
- sLog->outError("Unit (name=%s, type=%u) has invalid faction (faction template id) #%u", GetName(), uint32(GetTypeId()), getFaction());
- guid = GetGUID();
- }
- }
- return entry;
- }
- bool Unit::IsHostileTo(Unit const* unit) const
- {
- if(!unit)
- return false;
- // always non-hostile to self
- if(unit == this)
- return false;
- // always non-hostile to GM in GM mode
- if(unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster())
- return false;
- // always hostile to enemy
- if(getVictim() == unit || unit->getVictim() == this)
- return true;
- // test pet/charm masters instead pers/charmeds
- Unit const* testerOwner = GetCharmerOrOwner();
- Unit const* targetOwner = unit->GetCharmerOrOwner();
- // always hostile to owner's enemy
- if(testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner))
- return true;
- // always hostile to enemy owner
- if(targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this))
- return true;
- // always hostile to owner of owner's enemy
- if(testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner))
- return true;
- Unit const* tester = testerOwner ? testerOwner : this;
- Unit const* target = targetOwner ? targetOwner : unit;
- // always non-hostile to target with common owner, or to owner/pet
- if(tester == target)
- return false;
- // special cases (Duel, etc)
- if(tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER)
- {
- Player const* pTester = (Player const*)tester;
- Player const* pTarget = (Player const*)target;
- // Duel
- if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0)
- return true;
- // Group
- if(pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup())
- return false;
- // Sanctuary
- if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
- return false;
- // PvP FFA state
- if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
- return true;
- // = PvP states
- // Green/Blue (can't attack)
- if(!pTester->HasAuraType(SPELL_AURA_MOD_FACTION) && !pTarget->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- if(pTester->GetTeam() == pTarget->GetTeam())
- return false;
- // Red (can attack) if true, Blue/Yellow (can't attack) in another case
- return pTester->IsPvP() && pTarget->IsPvP();
- }
- }
- // faction base cases
- FactionTemplateEntry const*tester_faction = tester->getFactionTemplateEntry();
- FactionTemplateEntry const*target_faction = target->getFactionTemplateEntry();
- if(!tester_faction || !target_faction)
- return false;
- if(target->isAttackingPlayer() && tester->IsContestedGuard())
- return true;
- // PvC forced reaction and reputation case
- if(tester->GetTypeId() == TYPEID_PLAYER && !tester->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- // forced reaction
- if(target_faction->faction)
- {
- if(ReputationRank const* force = tester->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(target_faction))
- return *force <= REP_HOSTILE;
- // if faction have reputation then hostile state for tester at 100% dependent from at_war state
- if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
- if(FactionState const* factionState = tester->ToPlayer()->GetReputationMgr().GetState(raw_target_faction))
- return (factionState->Flags & FACTION_FLAG_AT_WAR);
- }
- }
- // CvP forced reaction and reputation case
- else if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- // forced reaction
- if(tester_faction->faction)
- {
- if(ReputationRank const* force = target->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(tester_faction))
- return *force <= REP_HOSTILE;
- // apply reputation state
- FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
- if(raw_tester_faction && raw_tester_faction->reputationListID >= 0)
- return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) <= REP_HOSTILE;
- }
- }
- // common faction based case (CvC, PvC, CvP)
- return tester_faction->IsHostileTo(*target_faction);
- }
- bool Unit::IsFriendlyTo(Unit const* pUnit) const
- {
- // always friendly to self
- if(!pUnit)
- return false;
- if(pUnit == this)
- return true;
- // always friendly to GM in GM mode
- if(pUnit->GetTypeId() == TYPEID_PLAYER && ((Player const*)pUnit)->isGameMaster())
- return true;
- // always non-friendly to enemy
- if(getVictim() == pUnit || pUnit->getVictim() == this)
- return false;
- // test pet/charm masters instead pers/charmeds
- Unit const* testerOwner = GetCharmerOrOwner();
- Unit const* targetOwner = pUnit->GetCharmerOrOwner();
- // always non-friendly to owner's enemy
- if(testerOwner && (testerOwner->getVictim() == pUnit || pUnit->getVictim() == testerOwner))
- return false;
- // always non-friendly to enemy owner
- if(targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this))
- return false;
- // always non-friendly to owner of owner's enemy
- if(testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner))
- return false;
- Unit const* tester = testerOwner ? testerOwner : this;
- Unit const* target = targetOwner ? targetOwner : pUnit;
- // always friendly to target with common owner, or to owner/pet
- if(tester == target)
- return true;
- // special cases (Duel)
- if(tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER)
- {
- Player const* pTester = (Player const*)tester;
- Player const* pTarget = (Player const*)target;
- // Duel
- if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0)
- return false;
- // Group
- if(pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup())
- return true;
- // Sanctuary
- if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY))
- return true;
- // PvP FFA state
- if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
- return false;
- // = PvP states
- // Green/Blue (non-attackable)
- if(!pTester->HasAuraType(SPELL_AURA_MOD_FACTION) && !pTarget->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- if(pTester->GetTeam() == pTarget->GetTeam())
- return true;
- // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable)
- return !pTarget->IsPvP();
- }
- }
- // faction base cases
- FactionTemplateEntry const* tester_faction = tester->getFactionTemplateEntry();
- FactionTemplateEntry const* target_faction = target->getFactionTemplateEntry();
- if(!tester_faction || !target_faction)
- return false;
- if(target->isAttackingPlayer() && tester->IsContestedGuard())
- return false;
- // PvC forced reaction and reputation case
- if(tester->GetTypeId() == TYPEID_PLAYER && !tester->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- // forced reaction
- if(target_faction->faction)
- {
- if(ReputationRank const* force = tester->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(target_faction))
- return *force >= REP_FRIENDLY;
- // if faction have reputation then friendly state for tester at 100% dependent from at_war state
- if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
- if(FactionState const* factionState = tester->ToPlayer()->GetReputationMgr().GetState(raw_target_faction))
- return !(factionState->Flags & FACTION_FLAG_AT_WAR);
- }
- }
- // CvP forced reaction and reputation case
- else if(target->GetTypeId() == TYPEID_PLAYER && !target->HasAuraType(SPELL_AURA_MOD_FACTION))
- {
- // forced reaction
- if(tester_faction->faction)
- {
- if(ReputationRank const* force = target->ToPlayer()->GetReputationMgr().GetForcedRankIfAny(tester_faction))
- return *force >= REP_FRIENDLY;
- // apply reputation state
- if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
- if(raw_tester_faction->reputationListID >= 0)
- return ((Player const*)target)->GetReputationMgr().GetRank(raw_tester_faction) >= REP_FRIENDLY;
- }
- }
- // common faction based case (CvC, PvC, CvP)
- return tester_faction->IsFriendlyTo(*target_faction);
- }
- bool Unit::IsHostileToPlayers() const
- {
- FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
- if(!my_faction || !my_faction->faction)
- return false;
- FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
- if(raw_faction && raw_faction->reputationListID >= 0)
- return false;
- return my_faction->IsHostileToPlayers();
- }
- bool Unit::IsNeutralToAll() const
- {
- FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
- if(!my_faction || !my_faction->faction)
- return true;
- FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
- if(raw_faction && raw_faction->reputationListID >= 0)
- return false;
- return my_faction->IsNeutralToAll();
- }
- bool Unit::Attack(Unit* victim, bool meleeAttack)
- {
- if(!victim || victim == this)
- return false;
- // dead units can neither attack nor be attacked
- if(!isAlive() || !victim->IsInWorld() || !victim->isAlive())
- return false;
- // player cannot attack in mount state
- if(GetTypeId() == TYPEID_PLAYER && IsMounted())
- return false;
- // nobody can attack GM in GM-mode
- if(victim->GetTypeId() == TYPEID_PLAYER)
- {
- if(victim->ToPlayer()->isGameMaster())
- return false;
- }
- else
- {
- if(victim->ToCreature()->IsInEvadeMode())
- return false;
- }
- // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
- if(HasAuraType(SPELL_AURA_MOD_UNATTACKABLE))
- RemoveAurasByType(SPELL_AURA_MOD_UNATTACKABLE);
- if(m_attacking)
- {
- if(m_attacking == victim)
- {
- // switch to melee attack from ranged/magic
- if(meleeAttack)
- {
- if(!HasUnitState(UNIT_STAT_MELEE_ATTACKING))
- {
- AddUnitState(UNIT_STAT_MELEE_ATTACKING);
- SendMeleeAttackStart(victim);
- return true;
- }
- }
- else if(HasUnitState(UNIT_STAT_MELEE_ATTACKING))
- {
- ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
- SendMeleeAttackStop(victim);
- return true;
- }
- return false;
- }
- // switch target
- InterruptSpell(CURRENT_MELEE_SPELL);
- if(!meleeAttack)
- ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
- }
- if(m_attacking)
- m_attacking->_removeAttacker(this);
- m_attacking = victim;
- m_attacking->_addAttacker(this);
- // Set our target
- SetTarget(victim->GetGUID());
- if(meleeAttack)
- AddUnitState(UNIT_STAT_MELEE_ATTACKING);
- if(GetTypeId() == TYPEID_UNIT && !ToCreature()->isPet())
- {
- // should not let player enter combat by right clicking target - doesn't helps
- SetInCombatWith(victim);
- if(victim->GetTypeId() == TYPEID_PLAYER)
- victim->SetInCombatWith(this);
- AddThreat(victim, 0.0f);
- ToCreature()->SendAIReaction(AI_REACTION_HOSTILE);
- ToCreature()->CallAssistance();
- }
- // delay offhand weapon attack to next attack time
- if(haveOffhandWeapon())
- resetAttackTimer(OFF_ATTACK);
- if(meleeAttack)
- SendMeleeAttackStart(victim);
- return true;
- }
- bool Unit::AttackStop()
- {
- if(!m_attacking)
- return false;
- Unit* pVictim = m_attacking;
- m_attacking->_removeAttacker(this);
- m_attacking = NULL;
- // Clear our target
- SetTarget(0);
- ClearUnitState(UNIT_STAT_MELEE_ATTACKING);
- InterruptSpell(CURRENT_MELEE_SPELL);
- // reset only at real combat stop
- if(Creature* pCreature = ToCreature())
- {
- pCreature->SetNoCallAssistance(false);
- if(pCreature->HasSearchedAssistance())
- {
- pCreature->SetNoSearchAssistance(false);
- UpdateSpeed(MOVE_RUN, false);
- }
- }
- SendMeleeAttackStop(pVictim);
- return true;
- }
- void Unit::CombatStop(bool includingCast)
- {
- if(includingCast && IsNonMeleeSpellCasted(false))
- InterruptNonMeleeSpells(false);
- AttackStop();
- RemoveAllAttackers();
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
- ClearInCombat();
- }
- void Unit::CombatStopWithPets(bool includingCast)
- {
- CombatStop(includingCast);
- for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- (*itr)->CombatStop(includingCast);
- }
- bool Unit::isAttackingPlayer() const
- {
- if(HasUnitState(UNIT_STAT_ATTACK_PLAYER))
- return true;
- for(ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- if((*itr)->isAttackingPlayer())
- return true;
- for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- if(m_SummonSlot[i])
- if(Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
- if(summon->isAttackingPlayer())
- return true;
- return false;
- }
- void Unit::RemoveAllAttackers()
- {
- while(!m_attackers.empty())
- {
- AttackerSet::iterator iter = m_attackers.begin();
- if(!(*iter)->AttackStop())
- {
- sLog->outError("WORLD: Unit has an attacker that isn't attacking it!");
- m_attackers.erase(iter);
- }
- }
- }
- void Unit::ModifyAuraState(AuraState flag, bool apply)
- {
- if(apply)
- {
- if(!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
- {
- SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
- if(GetTypeId() == TYPEID_PLAYER)
- {
- PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
- for(PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
- continue;
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
- if(!spellInfo || !IsPassiveSpell(itr->first))
- continue;
- if(spellInfo->CasterAuraState == uint32(flag))
- CastSpell(this, itr->first, true, NULL);
- }
- }
- else if(Pet* pet = ToCreature()->ToPet())
- {
- for(PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
- {
- if(itr->second.state == PETSPELL_REMOVED)
- continue;
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
- if(!spellInfo || !IsPassiveSpell(itr->first))
- continue;
- if(spellInfo->CasterAuraState == uint32(flag))
- CastSpell(this, itr->first, true, NULL);
- }
- }
- }
- }
- else
- {
- if(HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
- {
- RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
- if(flag != AURA_STATE_ENRAGE) // enrage aura state triggering continues auras
- {
- Unit::AuraApplicationMap& tAuras = GetAppliedAuras();
- for(Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
- {
- SpellEntry const* spellProto = (*itr).second->GetBase()->GetSpellProto();
- if(spellProto->CasterAuraState == uint32(flag))
- RemoveAura(itr);
- else
- ++itr;
- }
- }
- }
- }
- }
- uint32 Unit::BuildAuraStateUpdateForTarget(Unit* target) const
- {
- uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
- for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
- if((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
- if(itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
- auraStates |= (1<<(itr->first-1));
- return auraStates;
- }
- bool Unit::HasAuraState(AuraState flag, SpellEntry const* spellProto, Unit const* Caster) const
- {
- if(Caster)
- {
- if(spellProto)
- {
- AuraEffectList const& stateAuras = Caster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for(AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
- if((*j)->IsAffectedOnSpell(spellProto))
- return true;
- }
- // Check per caster aura state
- // If aura with aurastate by caster not found return false
- if((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
- {
- for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.lower_bound(flag); itr != m_auraStateAuras.upper_bound(flag); ++itr)
- if(itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
- return true;
- return false;
- }
- }
- return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
- }
- Unit* Unit::GetOwner() const
- {
- if(uint64 ownerid = GetOwnerGUID())
- {
- return ObjectAccessor::GetUnit(*this, ownerid);
- }
- return NULL;
- }
- Unit* Unit::GetCharmer() const
- {
- if(uint64 charmerid = GetCharmerGUID())
- return ObjectAccessor::GetUnit(*this, charmerid);
- return NULL;
- }
- Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const
- {
- uint64 guid = GetCharmerOrOwnerGUID();
- if(IS_PLAYER_GUID(guid))
- return ObjectAccessor::GetPlayer(*this, guid);
- return GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL;
- }
- Minion *Unit::GetFirstMinion() const
- {
- if(uint64 pet_guid = GetMinionGUID())
- {
- if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
- if(pet->HasUnitTypeMask(UNIT_MASK_MINION))
- return (Minion*)pet;
- sLog->outError("Unit::GetFirstMinion: Minion %u not exist.", GUID_LOPART(pet_guid));
- const_cast<Unit*>(this)->SetMinionGUID(0);
- }
- return NULL;
- }
- Guardian* Unit::GetGuardianPet() const
- {
- if(uint64 pet_guid = GetPetGUID())
- {
- if(Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
- if(pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
- return (Guardian*)pet;
- sLog->outCrash("Unit::GetGuardianPet: Guardian " UI64FMTD " not exist.", pet_guid);
- const_cast<Unit*>(this)->SetPetGUID(0);
- }
- return NULL;
- }
- Unit* Unit::GetCharm() const
- {
- if(uint64 charm_guid = GetCharmGUID())
- {
- if(Unit* pet = ObjectAccessor::GetUnit(*this, charm_guid))
- return pet;
- sLog->outError("Unit::GetCharm: Charmed creature %u not exist.", GUID_LOPART(charm_guid));
- const_cast<Unit*>(this)->SetUInt64Value(UNIT_FIELD_CHARM, 0);
- }
- return NULL;
- }
- void Unit::SetMinion(Minion *minion, bool apply)
- {
- sLog->outDebug(LOG_FILTER_UNITS, "SetMinion %u for %u, apply %u", minion->GetEntry(), GetEntry(), apply);
- if(apply)
- {
- if(!minion->AddUInt64Value(UNIT_FIELD_SUMMONEDBY, GetGUID()))
- {
- sLog->outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
- return;
- }
- m_Controlled.insert(minion);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- minion->m_ControlledByPlayer = true;
- minion->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
- }
- // Can only have one pet. If a new one is summoned, dismiss the old one.
- if(minion->IsGuardianPet())
- {
- if(Guardian* pPet = GetGuardianPet())
- {
- if(pPet && pPet != minion && (pPet->isPet() || minion->isPet() || pPet->GetEntry() != minion->GetEntry()))
- { // Remove / UnSummon Existing Minion or Pet
- if(pPet->isPet())
- ((Pet*)pPet)->Remove(PET_SAVE_AS_CURRENT);
- else
- pPet->UnSummon();
- SetPetGUID(minion->GetGUID());
- SetMinionGUID(0);
- }
- } else {
- SetPetGUID(minion->GetGUID());
- SetMinionGUID(0);
- }
- }
- if(minion->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
- AddUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID());
- if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
- SetCritterGUID(minion->GetGUID());
- // PvP, FFAPvP
- minion->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
- // FIXME: hack, speed must be set only at follow
- if(GetTypeId() == TYPEID_PLAYER && minion->isPet())
- for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
- minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
- // Ghoul pets have energy instead of mana (is anywhere better place for this code?)
- if(minion->IsPetGhoul() || minion->GetEntry() == 30230)
- minion->setPowerType(POWER_ENERGY);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- if(spellInfo && (spellInfo->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE))
- ToPlayer()->AddSpellAndCategoryCooldowns(spellInfo, 0, NULL, true);
- }
- }
- else
- {
- if(minion->GetOwnerGUID() != GetGUID())
- {
- sLog->outCrash("SetMinion: Minion %u is not the minion of owner %u", minion->GetEntry(), GetEntry());
- return;
- }
- m_Controlled.erase(minion);
- if(minion->m_Properties && minion->m_Properties->Type == SUMMON_TYPE_MINIPET)
- {
- if(GetCritterGUID() == minion->GetGUID())
- SetCritterGUID(0);
- }
- if(minion->IsGuardianPet())
- {
- if(GetPetGUID() == minion->GetGUID())
- SetPetGUID(0);
- }
- else if(minion->isTotem())
- {
- // All summoned by totem minions must disappear when it is removed.
- if(SpellEntry const* spInfo = sSpellStore.LookupEntry(minion->ToTotem()->GetSpell()))
- for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- if(spInfo->Effect[i] != SPELL_EFFECT_SUMMON)
- continue;
- RemoveAllMinionsByEntry(spInfo->EffectMiscValue[i]);
- }
- }
- if(GetTypeId() == TYPEID_PLAYER)
- {
- if(getDeathState() == GHOULED)
- {
- RemoveAurasDueToSpell(46619);
- RemoveAurasDueToSpell(62218);
- }
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
- // Remove infinity cooldown
- if(spellInfo && (spellInfo->Attributes & SPELL_ATTR0_DISABLED_WHILE_ACTIVE))
- ToPlayer()->SendCooldownEvent(spellInfo);
- }
- //if(minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
- {
- if(RemoveUInt64Value(UNIT_FIELD_SUMMON, minion->GetGUID()))
- {
- // Check if there is another minion
- for(ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- {
- // do not use this check, creature do not have charm guid
- if(GetGUID() == (*itr)->GetCharmerGUID())
- continue;
- if((*itr)->GetOwnerGUID() != GetGUID())
- {
- OutDebugInfo();
- (*itr)->OutDebugInfo();
- ASSERT(false);
- }
- ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
- if(!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
- continue;
- if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
- {
- // show another pet bar if there is no charm bar
- if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID())
- {
- if((*itr)->isPet())
- ToPlayer()->PetSpellInitialize();
- else
- ToPlayer()->CharmSpellInitialize();
- }
- }
- break;
- }
- }
- }
- }
- }
- void Unit::GetAllMinionsByEntry(std::list<Creature*>& Minions, uint32 entry)
- {
- for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
- {
- Unit* unit = *itr;
- ++itr;
- if(unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
- && unit->ToCreature()->isSummon()) // minion, actually
- Minions.push_back(unit->ToCreature());
- }
- }
- void Unit::RemoveAllMinionsByEntry(uint32 entry)
- {
- for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
- {
- Unit* unit = *itr;
- ++itr;
- if(unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
- && unit->ToCreature()->isSummon()) // minion, actually
- unit->ToTempSummon()->UnSummon();
- // i think this is safe because i have never heard that a despawned minion will trigger a same minion
- }
- }
- void Unit::SetCharm(Unit* charm, bool apply)
- {
- if(apply)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- if(!AddUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
- sLog->outCrash("Player %s is trying to charm unit %u, but it already has a charmed unit " UI64FMTD "", GetName(), charm->GetEntry(), GetCharmGUID());
- charm->m_ControlledByPlayer = true;
- // TODO: maybe we can use this flag to check if controlled by player
- charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
- }
- else
- charm->m_ControlledByPlayer = false;
- // PvP, FFAPvP
- charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
- if(!charm->AddUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
- sLog->outCrash("Unit %u is being charmed, but it already has a charmer " UI64FMTD "", charm->GetEntry(), charm->GetCharmerGUID());
- if(charm->HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
- {
- charm->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
- charm->SendMovementFlagUpdate();
- }
- m_Controlled.insert(charm);
- }
- else
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- if(!RemoveUInt64Value(UNIT_FIELD_CHARM, charm->GetGUID()))
- sLog->outCrash("Player %s is trying to uncharm unit %u, but it has another charmed unit " UI64FMTD "", GetName(), charm->GetEntry(), GetCharmGUID());
- }
- if(!charm->RemoveUInt64Value(UNIT_FIELD_CHARMEDBY, GetGUID()))
- sLog->outCrash("Unit %u is being uncharmed, but it has another charmer " UI64FMTD "", charm->GetEntry(), charm->GetCharmerGUID());
- if(charm->GetTypeId() == TYPEID_PLAYER)
- {
- charm->m_ControlledByPlayer = true;
- charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
- charm->ToPlayer()->UpdatePvPState();
- }
- else if(Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
- {
- charm->m_ControlledByPlayer = true;
- charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
- charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, player->GetByteValue(UNIT_FIELD_BYTES_2, 1));
- }
- else
- {
- charm->m_ControlledByPlayer = false;
- charm->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
- charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0);
- }
- if(charm->GetTypeId() == TYPEID_PLAYER
- || !charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_MINION)
- || charm->GetOwnerGUID() != GetGUID())
- m_Controlled.erase(charm);
- }
- }
- int32 Unit::DealHeal(Unit* victim, uint32 addhealth)
- {
- int32 gain = 0;
- if(victim->IsAIEnabled)
- victim->GetAI()->HealReceived(this, addhealth);
- if(IsAIEnabled)
- GetAI()->HealDone(victim, addhealth);
- if(addhealth)
- gain = victim->ModifyHealth(int32(addhealth));
- Unit* unit = this;
- if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
- unit = GetOwner();
- if(Player* player = unit->ToPlayer())
- {
- if(Battleground* pBG = player->GetBattleground())
- pBG->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
- // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
- if(gain)
- player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
- player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
- }
- if(Player* player = victim->ToPlayer())
- {
- player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
- player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
- }
- return gain;
- }
- Unit* Unit::SelectMagnetTarget(Unit* victim, SpellEntry const* spellInfo)
- {
- if(!victim)
- return NULL;
- // Magic case
- if(spellInfo && (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC))
- {
- // Patch 1.2 notes: Spell Reflection no longer reflects abilities
- if(spellInfo->Attributes & SPELL_ATTR0_ABILITY || spellInfo->AttributesEx & SPELL_ATTR1_CANT_BE_REDIRECTED || spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
- return victim;
- // I am not sure if this should be redirected.
- if(spellInfo->DmgClass == SPELL_DAMAGE_CLASS_NONE)
- return victim;
- Unit::AuraEffectList const& magnetAuras = victim->GetAuraEffectsByType(SPELL_AURA_SPELL_MAGNET);
- for(Unit::AuraEffectList::const_iterator itr = magnetAuras.begin(); itr != magnetAuras.end(); ++itr)
- if(Unit* magnet = (*itr)->GetBase()->GetUnitOwner())
- if(magnet->isAlive() && IsWithinLOSInMap(magnet))
- {
- (*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
- return magnet;
- }
- }
- // Melee && ranged case
- else
- {
- AuraEffectList const& hitTriggerAuras = victim->GetAuraEffectsByType(SPELL_AURA_ADD_CASTER_HIT_TRIGGER);
- for(AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
- if(Unit* magnet = (*i)->GetBase()->GetCaster())
- if(magnet->isAlive() && magnet->IsWithinLOSInMap(this))
- if(roll_chance_i((*i)->GetAmount()))
- {
- (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
- return magnet;
- }
- }
- return victim;
- }
- Unit* Unit::GetFirstControlled() const
- {
- // Sequence: charmed, pet, other guardians
- Unit* unit = GetCharm();
- if(!unit)
- if(uint64 guid = GetUInt64Value(UNIT_FIELD_SUMMON))
- unit = ObjectAccessor::GetUnit(*this, guid);
- return unit;
- }
- void Unit::RemoveAllControlled()
- {
- // possessed pet and vehicle
- if(GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->StopCastingCharm();
- while(!m_Controlled.empty())
- {
- Unit* target = *m_Controlled.begin();
- m_Controlled.erase(m_Controlled.begin());
- if(target->GetCharmerGUID() == GetGUID())
- target->RemoveCharmAuras();
- else if(target->GetOwnerGUID() == GetGUID() && target->isSummon())
- target->ToTempSummon()->UnSummon();
- else
- sLog->outError("Unit %u is trying to release unit %u which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
- }
- if(GetPetGUID())
- sLog->outCrash("Unit %u is not able to release its pet " UI64FMTD, GetEntry(), GetPetGUID());
- if(GetMinionGUID())
- sLog->outCrash("Unit %u is not able to release its minion " UI64FMTD, GetEntry(), GetMinionGUID());
- if(GetCharmGUID())
- sLog->outCrash("Unit %u is not able to release its charm " UI64FMTD, GetEntry(), GetCharmGUID());
- }
- Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
- {
- Player* player = NULL;
- if(GetTypeId() == TYPEID_PLAYER)
- player = ToPlayer();
- // Should we enable this also for charmed units?
- else if(GetTypeId() == TYPEID_UNIT && ToCreature()->isPet())
- player = GetOwner()->ToPlayer();
- if(!player)
- return NULL;
- Group* pGroup = player->GetGroup();
- // When there is no group check pet presence
- if(!pGroup)
- {
- // We are pet now, return owner
- if(player != this)
- return IsWithinDistInMap(player, radius) ? player : NULL;
- Unit* pet = GetGuardianPet();
- // No pet, no group, nothing to return
- if(!pet)
- return NULL;
- // We are owner now, return pet
- return IsWithinDistInMap(pet, radius) ? pet : NULL;
- }
- std::vector<Unit*> nearMembers;
- // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
- nearMembers.reserve(pGroup->GetMembersCount() * 2);
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
- if(Player* Target = itr->getSource())
- {
- // IsHostileTo check duel and controlled by enemy
- if(Target != this && Target->isAlive() && IsWithinDistInMap(Target, radius) && !IsHostileTo(Target))
- nearMembers.push_back(Target);
- // Push player's pet to vector
- if(Unit* pet = Target->GetGuardianPet())
- if(pet != this && pet->isAlive() && IsWithinDistInMap(pet, radius) && !IsHostileTo(pet))
- nearMembers.push_back(pet);
- }
- if(nearMembers.empty())
- return NULL;
- uint32 randTarget = urand(0, nearMembers.size()-1);
- return nearMembers[randTarget];
- }
- // only called in Player::SetSeer
- // so move it to Player?
- void Unit::AddPlayerToVision(Player* plr)
- {
- if(m_sharedVision.empty())
- {
- setActive(true);
- SetWorldObject(true);
- }
- m_sharedVision.push_back(plr);
- }
- // only called in Player::SetSeer
- void Unit::RemovePlayerFromVision(Player* plr)
- {
- m_sharedVision.remove(plr);
- if(m_sharedVision.empty())
- {
- setActive(false);
- SetWorldObject(false);
- }
- }
- void Unit::RemoveBindSightAuras()
- {
- RemoveAurasByType(SPELL_AURA_BIND_SIGHT);
- }
- void Unit::RemoveCharmAuras()
- {
- RemoveAurasByType(SPELL_AURA_MOD_CHARM);
- RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET);
- RemoveAurasByType(SPELL_AURA_MOD_POSSESS);
- RemoveAurasByType(SPELL_AURA_AOE_CHARM);
- }
- void Unit::UnsummonAllTotems()
- {
- for(uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
- {
- if(!m_SummonSlot[i])
- continue;
- if(Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
- if(OldTotem->isSummon())
- OldTotem->ToTempSummon()->UnSummon();
- }
- }
- void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical)
- {
- // we guess size
- WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+4+4+1+1));
- data.append(victim->GetPackGUID());
- data.append(GetPackGUID());
- data << uint32(SpellID);
- data << uint32(Damage);
- data << uint32(OverHeal);
- data << uint32(Absorb); // Absorb amount
- data << uint8(critical ? 1 : 0);
- data << uint8(0); // unused
- SendMessageToSet(&data, true);
- }
- int32 Unit::HealBySpell(Unit* victim, SpellEntry const* spellInfo, uint32 addHealth, bool critical)
- {
- uint32 absorb = 0;
- // calculate heal absorb and reduce healing
- CalcHealAbsorb(victim, spellInfo, addHealth, absorb);
- int32 gain = DealHeal(victim, addHealth);
- SendHealSpellLog(victim, spellInfo->Id, addHealth, uint32(addHealth - gain), absorb, critical);
- return gain;
- }
- void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Powers powerType)
- {
- WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
- data.append(victim->GetPackGUID());
- data.append(GetPackGUID());
- data << uint32(spellID);
- data << uint32(powerType);
- data << uint32(damage);
- SendMessageToSet(&data, true);
- }
- void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType)
- {
- SendEnergizeSpellLog(victim, spellID, damage, powerType);
- // needs to be called after sending spell log
- victim->ModifyPower(powerType, damage);
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID);
- victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo);
- }
- uint32 Unit::SpellDamageBonus(Unit* victim, SpellEntry const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
- {
- if(!spellProto || !victim || damagetype == DIRECT_DAMAGE)
- return pdamage;
- // small exception for Deep Wounds, can't find any general rule
- // should ignore ALL damage mods, they already calculated in trigger spell
- if(spellProto->Id == 12721) // Deep Wounds
- return pdamage;
- // For totems get damage bonus from owner
- if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
- if(Unit* owner = GetOwner())
- return owner->SpellDamageBonus(victim, spellProto, pdamage, damagetype);
- // Taken/Done total percent damage auras
- float DoneTotalMod = 1.0f;
- float ApCoeffMod = 1.0f;
- int32 DoneTotal = 0;
- int32 TakenTotal = 0;
- // ..done
- // Pet damage?
- if(GetTypeId() == TYPEID_UNIT && !ToCreature()->isPet())
- DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureInfo()->rank);
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
- if ((*i)->GetMiscValue() & GetSpellSchoolMask(spellProto) && !(GetSpellSchoolMask(spellProto) & SPELL_SCHOOL_MASK_NORMAL))
- {
- if((*i)->GetSpellProto()->EquippedItemClass == -1)
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- else if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
- {
- if((*i)->GetSpellProto()->EquippedItemClass & spellProto->EquippedItemClass)
- if(((*i)->GetSpellProto()->EquippedItemSubClassMask == 0) ||
- ((*i)->GetSpellProto()->EquippedItemSubClassMask & spellProto->EquippedItemSubClassMask))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- else if(ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- // Add flat bonus from spell damage versus
- DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
- AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- // bonus against aurastate
- AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
- for(AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
- if(victim->HasAuraState(AuraState((*i)->GetMiscValue())))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- // done scripted mod (take it from owner)
- Unit* owner = GetOwner() ? GetOwner() : this;
- AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
- {
- if(!(*i)->IsAffectedOnSpell(spellProto))
- continue;
- switch((*i)->GetMiscValue())
- {
- case 4920: // Molten Fury
- case 4919:
- case 6917: // Death's Embrace
- case 6926:
- case 6928:
- {
- if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- // Soul Siphon
- case 4992:
- case 4993:
- {
- // effect 1 m_amount
- int32 maxPercent = (*i)->GetAmount();
- // effect 0 m_amount
- int32 stepPercent = CalculateSpellDamage(this, (*i)->GetSpellProto(), 0);
- // count affliction effects and calc additional damage in percentage
- int32 modPercent = 0;
- AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
- for(AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- SpellEntry const* m_spell = aura->GetSpellProto();
- if(m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(m_spell->SpellFamilyFlags[1] & 0x0004071B || m_spell->SpellFamilyFlags[0] & 0x8044C402))
- continue;
- modPercent += stepPercent * aura->GetStackAmount();
- if(modPercent >= maxPercent)
- {
- modPercent = maxPercent;
- break;
- }
- }
- AddPctN(DoneTotalMod, modPercent);
- break;
- }
- case 6916: // Death's Embrace
- case 6925:
- case 6927:
- if(HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- case 5481: // Starfire Bonus
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0, 0))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- case 4418: // Increased Shock Damage
- case 4554: // Increased Lightning Damage
- case 4555: // Improved Moonfire
- case 5142: // Increased Lightning Damage
- case 5147: // Improved Consecration / Libram of Resurgence
- case 5148: // Idol of the Shooting Star
- case 6008: // Increased Lightning Damage
- case 8627: // Totem of Hex
- {
- DoneTotal += (*i)->GetAmount();
- break;
- }
- // Tundra Stalker
- // Merciless Combat
- case 7277:
- {
- // Merciless Combat
- if((*i)->GetSpellProto()->SpellIconID == 2656)
- {
- if(!victim->HealthAbovePct(35))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- // Tundra Stalker
- else
- {
- // Frost Fever (target debuff)
- if(victim->HasAura(55095))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- break;
- }
- // Rage of Rivendare
- case 7293:
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0))
- {
- if(SpellChainNode const* chain = sSpellMgr->GetSpellChainNode((*i)->GetId()))
- AddPctF(DoneTotalMod, chain->rank * 2.0f);
- }
- break;
- }
- // Twisted Faith
- case 7377:
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- // Marked for Death
- case 7598:
- case 7599:
- case 7600:
- case 7601:
- case 7602:
- {
- if(victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- // Dirty Deeds
- case 6427:
- case 6428:
- case 6579:
- case 6580:
- {
- if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
- {
- // effect 0 have expected value but in negative state
- int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
- AddPctN(DoneTotalMod, bonus);
- }
- break;
- }
- }
- }
- // Custom scripted damage
- switch(spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_MAGE:
- // Ice Lance
- if(spellProto->SpellIconID == 186) {
- if(victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this)) {
- // Glyph of Ice Lance
- if(owner->HasAura(56377) && victim->getLevel() > owner->getLevel())
- DoneTotalMod *= 4.0f;
- else
- DoneTotalMod *= 3.0f;
- }
- } // Torment the weak
- if(spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000) {
- if(victim->HasAuraWithMechanic((1<<MECHANIC_SNARE)|(1<<MECHANIC_SLOW_ATTACK))) {
- AuraEffectList const& mDumyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i) {
- if((*i)->GetSpellProto()->SpellIconID == 3263) {
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- }
- }
- }
- break;
- case SPELLFAMILY_PRIEST:
- // Mind Flay
- if(spellProto->SpellFamilyFlags[0] & 0x800000) {
- // Glyph of Shadow Word: Pain
- if(AuraEffect* aurEff = GetAuraEffect(55687, 0))
- // Increase Mind Flay damage if Shadow Word: Pain present on target
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- // Twisted Faith - Mind Flay part
- if(AuraEffect* aurEff = GetAuraEffect(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, SPELLFAMILY_PRIEST, 2848, 1))
- // Increase Mind Flay damage if Shadow Word: Pain present on target
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetGUID()))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- } // Smite
- else if(spellProto->SpellFamilyFlags[0] & 0x80)
- {
- // Glyph of Smite
- if(AuraEffect* aurEff = GetAuraEffect(55692, 0))
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, GetGUID()))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- } // Shadow Word: Death
- else if(spellProto->SpellFamilyFlags[1] & 0x2)
- { // Glyph of Shadow Word: Death
- if(AuraEffect* aurEff = GetAuraEffect(55682, 1))
- if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- }
- break;
- case SPELLFAMILY_PALADIN:
- // Judgement of Vengeance/Judgement of Corruption
- if((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID == 2292) {
- // Get stack of Holy Vengeance/Blood Corruption on the target added by caster
- uint32 stacks = 0;
- Unit::AuraEffectList const& auras = victim->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
- for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) {
- if(((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID() == GetGUID())
- {
- stacks = (*itr)->GetBase()->GetStackAmount();
- break;
- }
- }
- // + 10% for each application of Holy Vengeance/Blood Corruption on the target
- if(stacks)
- AddPctU(DoneTotalMod, 10 * stacks);
- }
- break;
- case SPELLFAMILY_DRUID:
- // Thorns
- if(spellProto->SpellFamilyFlags[0] & 0x100) {
- // Brambles
- if(AuraEffect* aurEff = GetAuraEffectOfRankedSpell(16836, 0))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- }
- break;
- case SPELLFAMILY_WARLOCK:
- // Fire and Brimstone
- if(spellProto->SpellFamilyFlags[1] & 0x00020040) {
- if(victim->HasAuraState(AURA_STATE_CONFLAGRATE)) {
- AuraEffectList const& mDumyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i) {
- if((*i)->GetSpellProto()->SpellIconID == 3173) {
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- }
- }
- } // Drain Soul - increased damage for targets under 25 % HP
- if(spellProto->SpellFamilyFlags[0] & 0x00004000) {
- if(HasAura(100001))
- DoneTotalMod *= 4;
- } // Shadow Bite (15% increase from each dot)
- if(spellProto->SpellFamilyFlags[1] & 0x00400000 && isPet()) {
- if(uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
- AddPctN(DoneTotalMod, 15 * count);
- }
- break;
- case SPELLFAMILY_HUNTER:
- // Steady Shot
- if(spellProto->SpellFamilyFlags[1] & 0x1) {
- if(AuraEffect* aurEff = GetAuraEffect(56826, 0)) { // Glyph of Steady Shot
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, 0x00004000, 0, 0, GetGUID()))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- }
- }
- break;
- case SPELLFAMILY_DEATHKNIGHT:
- // Improved Icy Touch
- if(spellProto->SpellFamilyFlags[0] & 0x2) {
- if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2721, 0))
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- } // Glacier Rot
- if(spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) {
- if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0)) {
- if(victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- }
- } // Impurity (dummy effect)
- if(GetTypeId() == TYPEID_PLAYER) {
- PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap();
- for(PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled)
- continue;
- switch(itr->first)
- {
- case 49220:
- case 49633:
- case 49635:
- case 49636:
- case 49638:
- {
- if(SpellEntry const* proto = sSpellStore.LookupEntry(itr->first))
- AddPctN(ApCoeffMod, SpellMgr::CalculateSpellEffectAmount(proto, 0));
- }
- break;
- }
- }
- } // Sigil of the Vengeful Heart
- if(spellProto->SpellFamilyFlags[0] & 0x2000)
- {
- if(AuraEffect* aurEff = GetAuraEffect(64962, EFFECT_1))
- DoneTotal += aurEff->GetAmount();
- }
- break;
- }
- // ..taken
- float TakenTotalMod = 1.0f;
- // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
- // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
- TakenTotalMod *= victim->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, GetSpellSchoolMask(spellProto));
- // .. taken pct: dummy auras
- AuraEffectList const& mDummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
- {
- switch((*i)->GetSpellProto()->SpellIconID)
- {
- // Cheat Death
- case 2109:
- if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
- {
- if(victim->GetTypeId() != TYPEID_PLAYER)
- continue;
- float mod = victim->ToPlayer()->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE) * (-8.0f);
- AddPctF(TakenTotalMod, mod);
- }
- break;
- // Ebon Plague
- case 1933:
- if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- break;
- }
- }
- // From caster spells
- AuraEffectList const& mOwnerTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
- for(AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
- if((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- // Mod damage from spell mechanic
- if(uint32 mechanicMask = GetAllSpellMechanicMask(spellProto))
- {
- AuraEffectList const& mDamageDoneMechanic = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
- for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin(); i != mDamageDoneMechanic.end(); ++i)
- if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- }
- // Taken/Done fixed damage bonus auras
- int32 DoneAdvertisedBenefit = SpellBaseDamageBonus(GetSpellSchoolMask(spellProto));
- int32 TakenAdvertisedBenefit = SpellBaseDamageBonusForVictim(GetSpellSchoolMask(spellProto), victim);
- // Pets just add their bonus damage to their spell damage
- // note that their spell damage is just gain of their own auras
- if(HasUnitTypeMask(UNIT_MASK_GUARDIAN))
- DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
- // Check for table values
- float coeff = 0;
- SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id);
- if(bonus)
- {
- if(damagetype == DOT)
- {
- coeff = bonus->dot_damage;
- if(bonus->ap_dot_bonus > 0)
- {
- WeaponAttackType attType = (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
- float APbonus = (float) victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
- APbonus += GetTotalAttackPowerValue(attType);
- DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
- }
- }
- else
- {
- coeff = bonus->direct_damage;
- if(bonus->ap_bonus > 0)
- {
- WeaponAttackType attType = (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
- float APbonus = (float) victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
- APbonus += GetTotalAttackPowerValue(attType);
- DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
- }
- }
- }
- // Default calculation
- if(DoneAdvertisedBenefit || TakenAdvertisedBenefit)
- {
- if(!bonus || coeff < 0)
- {
- // Damage Done from spell damage bonus
- int32 CastingTime = IsChanneledSpell(spellProto) ? GetSpellDuration(spellProto) : GetSpellCastTime(spellProto);
- // Damage over Time spells bonus calculation
- float DotFactor = 1.0f;
- if(damagetype == DOT)
- {
- int32 DotDuration = GetSpellDuration(spellProto);
- // 200% limit
- if(DotDuration > 0)
- {
- if(DotDuration > 30000)
- DotDuration = 30000;
- if(!IsChanneledSpell(spellProto))
- DotFactor = DotDuration / 15000.0f;
- uint8 x = 0;
- for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
- {
- if(spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
- {
- x = j;
- break;
- }
- }
- int32 DotTicks = 6;
- if(spellProto->EffectAmplitude[x] != 0)
- DotTicks = DotDuration / spellProto->EffectAmplitude[x];
- if(DotTicks)
- {
- DoneAdvertisedBenefit /= DotTicks;
- TakenAdvertisedBenefit /= DotTicks;
- }
- }
- }
- // Distribute Damage over multiple effects, reduce by AoE
- CastingTime = GetCastingTimeForBonus(spellProto, damagetype, CastingTime);
- // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
- for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
- {
- if(spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
- (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
- {
- CastingTime /= 2;
- break;
- }
- }
- if(spellProto->SchoolMask != SPELL_SCHOOL_MASK_NORMAL)
- coeff = (CastingTime / 3500.0f) * DotFactor;
- else
- coeff = DotFactor;
- }
- float coeff2 = CalculateLevelPenalty(spellProto) * stack;
- if(spellProto->SpellFamilyName) // TODO: fix this
- TakenTotal+= int32(TakenAdvertisedBenefit * coeff * coeff2);
- if(Player* modOwner = GetSpellModOwner())
- {
- coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
- coeff /= 100.0f;
- if(isPet())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_ALL_EFFECTS, DoneAdvertisedBenefit);
- }
- DoneTotal += (int32)(DoneAdvertisedBenefit * coeff * coeff2);
- }
- // Some spells don't benefit from done mods
- if(spellProto->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)
- {
- DoneTotal = 0;
- DoneTotalMod = 1.0f;
- }
- // Some spells don't benefit from pct done mods
- // maybe should be implemented like SPELL_ATTR3_NO_DONE_BONUS,
- // but then it may break spell power coeffs work on spell 31117
- if(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)
- DoneTotalMod = 1.0f;
- float tmpDamage = (int32(pdamage) + DoneTotal) * DoneTotalMod;
- // apply spellmod to Done damage (flat and pct)
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
- tmpDamage = (tmpDamage + TakenTotal) * TakenTotalMod;
- return uint32(std::max(tmpDamage, 0.0f));
- }
- int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
- {
- int32 DoneAdvertisedBenefit = 0;
- // ..done
- AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
- for(AuraEffectList::const_iterator i = mDamageDone.begin(); i != mDamageDone.end(); ++i)
- if(((*i)->GetMiscValue() & schoolMask) != 0 &&
- (*i)->GetSpellProto()->EquippedItemClass == -1 &&
- // -1 == any item class (not wand then)
- (*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0)
- // 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetAmount();
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // Base value
- DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
- // Damage bonus from stats
- AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
- for(AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
- {
- if((*i)->GetMiscValue() & schoolMask)
- {
- // stat used stored in miscValueB for this aura
- Stats usedStat = Stats((*i)->GetMiscValueB());
- DoneAdvertisedBenefit += int32(CalculatePctN(GetStat(usedStat), (*i)->GetAmount()));
- }
- }
- // ... and attack power
- AuraEffectList const& mDamageDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
- for(AuraEffectList::const_iterator i =mDamageDonebyAP.begin(); i != mDamageDonebyAP.end(); ++i)
- if((*i)->GetMiscValue() & schoolMask)
- DoneAdvertisedBenefit += int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
- }
- return DoneAdvertisedBenefit > 0 ? DoneAdvertisedBenefit : 0;
- }
- int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit* victim)
- {
- uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- int32 TakenAdvertisedBenefit = 0;
- // ..done (for creature type by mask) in taken
- AuraEffectList const& mDamageDoneCreature = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
- for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- TakenAdvertisedBenefit += (*i)->GetAmount();
- // ..taken
- AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if(((*i)->GetMiscValue() & schoolMask) != 0)
- TakenAdvertisedBenefit += (*i)->GetAmount();
- return TakenAdvertisedBenefit > 0 ? TakenAdvertisedBenefit : 0;
- }
- bool Unit::isSpellCrit(Unit* victim, SpellEntry const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const
- {
- // Mobs can't crit with spells but creatures owned by a player CAN crit.
- if(IS_CREATURE_GUID(GetGUID()) && !(GetOwner() && GetOwner()->GetTypeId() == TYPEID_PLAYER))
- return false;
- // not critting spell
- if((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT))
- return false;
- float crit_chance = 0.0f;
- switch(spellProto->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_NONE:
- // We need more spells to find a general way (if there is any)
- switch(spellProto->Id)
- {
- case 379: // Earth Shield
- case 33778: // Lifebloom Final Bloom
- case 64844: // Divine Hymn
- break;
- default:
- return false;
- }
- case SPELL_DAMAGE_CLASS_MAGIC:
- {
- if(schoolMask & SPELL_SCHOOL_MASK_NORMAL)
- crit_chance = 0.0f;
- // For other schools
- else if(GetTypeId() == TYPEID_PLAYER)
- crit_chance = GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + GetFirstSchoolInMask(schoolMask));
- else
- {
- crit_chance = (float)m_baseSpellCritChance;
- crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
- }
- // taken
- if(victim)
- {
- if(!IsPositiveSpell(spellProto->Id))
- {
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
- crit_chance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE, schoolMask);
- // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
- crit_chance += victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE);
- ApplyResilience(victim, &crit_chance, NULL, false, CR_CRIT_TAKEN_SPELL);
- }
- // scripted (increase crit chance ... against ... target by x%
- AuraEffectList const& mOverrideClassScript = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
- {
- if(!((*i)->IsAffectedOnSpell(spellProto)))
- continue;
- int32 modChance = 0;
- switch((*i)->GetMiscValue())
- {
- // Shatter
- case 911: modChance+= 16;
- case 910: modChance+= 17;
- case 849: modChance+= 17;
- if(!victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
- break;
- crit_chance+=modChance;
- break;
- case 7917: // Glyph of Shadowburn
- if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
- crit_chance+=(*i)->GetAmount();
- break;
- default:
- break;
- }
- }
- // Custom crit by class
- switch(spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- // Improved Faerie Fire
- if(victim->HasAuraState(AURA_STATE_FAERIE_FIRE)) {
- if(AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
- crit_chance += aurEff->GetAmount();
- }
- // cumulative effect - don't break
- // Starfire
- if(spellProto->SpellFamilyFlags[0] & 0x4 && spellProto->SpellIconID == 1485) {
- // Improved Insect Swarm
- if(AuraEffect const* aurEff = GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0)) {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00000002, 0, 0))
- crit_chance += aurEff->GetAmount();
- }
- }
- break;
- case SPELLFAMILY_ROGUE:
- // Shiv-applied poisons can't crit
- if(FindCurrentSpellBySpellId(5938))
- crit_chance = 0.0f;
- break;
- case SPELLFAMILY_PALADIN:
- // Flash of light
- if(spellProto->SpellFamilyFlags[0] & 0x40000000) {
- // Sacred Shield
- if(AuraEffect const* aura = victim->GetAuraEffect(58597, 1, GetGUID()))
- crit_chance += aura->GetAmount();
- break;
- }
- // Exorcism
- else if(spellProto->Category == 19) {
- if(victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
- return true;
- break;
- }
- break;
- case SPELLFAMILY_SHAMAN:
- // Lava Burst
- if(spellProto->SpellFamilyFlags[1] & 0x00001000)
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID()))
- if(victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100)
- return true;
- break;
- }
- break;
- }
- }
- break;
- }
- case SPELL_DAMAGE_CLASS_MELEE:
- if(victim)
- {
- // Custom crit by class
- switch(spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- // Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets
- if(spellProto->SpellFamilyFlags[0] & 0x00800000
- && spellProto->SpellIconID == 1680
- && victim->HasAuraState(AURA_STATE_BLEEDING))
- {
- if(AuraEffect const* rendAndTear = GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
- crit_chance += rendAndTear->GetAmount();
- break;
- }
- break;
- case SPELLFAMILY_WARRIOR:
- // Victory Rush
- if(spellProto->SpellFamilyFlags[1] & 0x100)
- {
- // Glyph of Victory Rush
- if(AuraEffect const* aurEff = GetAuraEffect(58382, 0))
- crit_chance += aurEff->GetAmount();
- break;
- }
- break;
- }
- }
- case SPELL_DAMAGE_CLASS_RANGED:
- {
- if(victim)
- {
- crit_chance += GetUnitCriticalChance(attackType, victim);
- crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
- }
- break;
- }
- default:
- return false;
- }
- // percent done
- // only players use intelligence for critical chance computations
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
- crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f;
- if(roll_chance_f(crit_chance) && (victim && !victim->HasAura(53480)))
- return true;
- return false;
- }
- uint32 Unit::SpellCriticalDamageBonus(SpellEntry const* spellProto, uint32 damage, Unit* victim)
- {
- // Calculate critical bonus
- int32 crit_bonus = damage;
- float crit_mod = 0.0f;
- switch(spellProto->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
- case SPELL_DAMAGE_CLASS_RANGED:
- // TODO: write here full calculation for melee/ranged spells
- crit_bonus += damage;
- break;
- default:
- crit_bonus += damage / 2; // for spells is 50%
- break;
- }
- crit_mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, GetSpellSchoolMask(spellProto)) - 1.0f) * 100;
- if(victim)
- crit_mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, victim->GetCreatureTypeMask());
- if(crit_bonus != 0)
- AddPctF(crit_bonus, crit_mod);
- crit_bonus -= damage;
- // adds additional damage to crit_bonus (from talents)
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
- crit_bonus += damage;
- return crit_bonus;
- }
- uint32 Unit::SpellCriticalHealingBonus(SpellEntry const* spellProto, uint32 damage, Unit* victim)
- {
- // Calculate critical bonus
- int32 crit_bonus;
- switch(spellProto->DmgClass)
- {
- case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
- case SPELL_DAMAGE_CLASS_RANGED:
- // TODO: write here full calculation for melee/ranged spells
- crit_bonus = damage;
- break;
- default:
- crit_bonus = damage / 2; // for spells is 50%
- break;
- }
- if(victim)
- {
- uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- crit_bonus = int32(crit_bonus * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
- }
- if(crit_bonus > 0)
- damage += crit_bonus;
- damage = int32(float(damage) * GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
- return damage;
- }
- uint32 Unit::SpellHealingBonus(Unit* victim, SpellEntry const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack)
- {
- // For totems get healing bonus from owner (statue isn't totem in fact)
- if(GetTypeId() == TYPEID_UNIT && ToCreature()->isTotem())
- if(Unit* owner = GetOwner())
- return owner->SpellHealingBonus(victim, spellProto, healamount, damagetype, stack);
- // no bonus for heal potions/bandages
- if(spellProto->SpellFamilyName == SPELLFAMILY_POTION)
- return healamount;
- // and Warlock's Healthstones
- if(spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellProto->SpellFamilyFlags[0] & 0x10000))
- return healamount;
- // Healing Done
- // Taken/Done total percent damage auras
- float DoneTotalMod = 1.0f;
- float TakenTotalMod = 1.0f;
- int32 DoneTotal = 0;
- int32 TakenTotal = 0;
- // Healing done percent
- AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
- for(AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i)
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- // done scripted mod (take it from owner)
- Unit* owner = GetOwner() ? GetOwner() : this;
- AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
- {
- if(!(*i)->IsAffectedOnSpell(spellProto))
- continue;
- switch((*i)->GetMiscValue())
- {
- case 4415: // Increased Rejuvenation Healing
- case 4953:
- case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
- DoneTotal += (*i)->GetAmount();
- break;
- case 7997: // Renewed Hope
- case 7998:
- if(victim->HasAura(6788))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- case 21: // Test of Faith
- case 6935:
- case 6918:
- if(victim->HealthBelowPct(50))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- case 7798: // Glyph of Regrowth
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- case 8477: // Nourish Heal Boost
- {
- int32 stepPercent = (*i)->GetAmount();
- int32 modPercent = 0;
- AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
- for(AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- if(aura->GetCasterGUID() != GetGUID())
- continue;
- SpellEntry const* m_spell = aura->GetSpellProto();
- if(m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
- !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
- continue;
- modPercent += stepPercent * aura->GetStackAmount();
- }
- AddPctN(DoneTotalMod, modPercent);
- break;
- }
- case 7871: // Glyph of Lesser Healing Wave
- {
- if(victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- default:
- break;
- }
- }
- // Taken/Done fixed damage bonus auras
- int32 DoneAdvertisedBenefit = SpellBaseHealingBonus(GetSpellSchoolMask(spellProto));
- int32 TakenAdvertisedBenefit = SpellBaseHealingBonusForVictim(GetSpellSchoolMask(spellProto), victim);
- bool scripted = false;
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- switch(spellProto->EffectApplyAuraName[i])
- {
- // These auras do not use healing coeff
- case SPELL_AURA_PERIODIC_LEECH:
- case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
- scripted = true;
- break;
- }
- if(spellProto->Effect[i] == SPELL_EFFECT_HEALTH_LEECH)
- scripted = true;
- }
- // Check for table values
- SpellBonusEntry const* bonus = !scripted ? sSpellMgr->GetSpellBonusData(spellProto->Id) : NULL;
- float coeff = 0;
- float factorMod = 1.0f;
- if(bonus)
- {
- if(damagetype == DOT)
- {
- coeff = bonus->dot_damage;
- if(bonus->ap_dot_bonus > 0)
- DoneTotal += int32(bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue(
- (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK));
- }
- else
- {
- coeff = bonus->direct_damage;
- if(bonus->ap_bonus > 0)
- DoneTotal += int32(bonus->ap_bonus * stack * GetTotalAttackPowerValue(
- (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK));
- }
- }
- else // scripted bonus
- {
- // Gift of the Naaru
- if(spellProto->SpellFamilyFlags[2] & 0x80000000 && spellProto->SpellIconID == 329)
- {
- scripted = true;
- int32 apBonus = int32(std::max(GetTotalAttackPowerValue(BASE_ATTACK), GetTotalAttackPowerValue(RANGED_ATTACK)));
- if(apBonus > DoneAdvertisedBenefit)
- DoneTotal += int32(apBonus * 0.22f); // 22% of AP per tick
- else
- DoneTotal += int32(DoneAdvertisedBenefit * 0.377f); // 37.7% of BH per tick
- }
- // Earthliving - 0.45% of normal hot coeff
- else if(spellProto->SpellFamilyName == SPELLFAMILY_SHAMAN && spellProto->SpellFamilyFlags[1] & 0x80000)
- factorMod *= 0.45f;
- // Already set to scripted? so not uses healing bonus coefficient
- // No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default
- else if(scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
- {
- scripted = true;
- coeff = 0.0f;
- }
- }
- // Default calculation
- if(DoneAdvertisedBenefit || TakenAdvertisedBenefit)
- {
- if((!bonus && !scripted) || coeff < 0)
- {
- // Damage Done from spell damage bonus
- int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
- // Damage over Time spells bonus calculation
- float DotFactor = 1.0f;
- if(damagetype == DOT)
- {
- int32 DotDuration = GetSpellDuration(spellProto);
- // 200% limit
- if(DotDuration > 0)
- {
- if(DotDuration > 30000) DotDuration = 30000;
- if(!IsChanneledSpell(spellProto)) DotFactor = DotDuration / 15000.0f;
- uint32 x = 0;
- for(uint8 j = 0; j < MAX_SPELL_EFFECTS; j++)
- {
- if(spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && (
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_DAMAGE ||
- spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
- {
- x = j;
- break;
- }
- }
- int32 DotTicks = 6;
- if(spellProto->EffectAmplitude[x] != 0)
- DotTicks = DotDuration / spellProto->EffectAmplitude[x];
- if(DotTicks)
- {
- DoneAdvertisedBenefit = DoneAdvertisedBenefit * int32(stack) / DotTicks;
- TakenAdvertisedBenefit = TakenAdvertisedBenefit * int32(stack) / DotTicks;
- }
- }
- }
- // Distribute Damage over multiple effects, reduce by AoE
- CastingTime = GetCastingTimeForBonus(spellProto, damagetype, CastingTime);
- // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
- for(uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
- {
- if(spellProto->Effect[j] == SPELL_EFFECT_HEALTH_LEECH ||
- (spellProto->Effect[j] == SPELL_EFFECT_APPLY_AURA && spellProto->EffectApplyAuraName[j] == SPELL_AURA_PERIODIC_LEECH))
- {
- CastingTime /= 2;
- break;
- }
- }
- // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
- coeff = (CastingTime / 3500.0f) * DotFactor * 1.88f;
- }
- factorMod *= CalculateLevelPenalty(spellProto) * stack;
- TakenTotal += int32(TakenAdvertisedBenefit * coeff * factorMod);
- if(Player* modOwner = GetSpellModOwner())
- {
- coeff *= 100.0f;
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
- coeff /= 100.0f;
- }
- DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
- }
- // use float as more appropriate for negative values and percent applying
- float heal = (int32(healamount) + DoneTotal) * DoneTotalMod;
- // apply spellmod to Done amount
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
- // Nourish cast
- if(spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
- {
- // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x50, 0x4000010, 0))
- // increase healing by 20%
- TakenTotalMod *= 1.2f;
- }
- // Taken mods
- // Tenacity increase healing % taken
- if(AuraEffect const* Tenacity = victim->GetAuraEffect(58549, 0))
- AddPctN(TakenTotalMod, Tenacity->GetAmount());
- // Healing taken percent
- float minval = (float)victim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
- if(minval)
- AddPctF(TakenTotalMod, minval);
- float maxval = (float)victim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT);
- if(maxval)
- AddPctF(TakenTotalMod, maxval);
- if(damagetype == DOT)
- {
- // Healing over time taken percent
- float minval_hot = (float)victim->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT);
- if(minval_hot)
- AddPctF(TakenTotalMod, minval_hot);
- float maxval_hot = (float)victim->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT);
- if(maxval_hot)
- AddPctF(TakenTotalMod, maxval_hot);
- }
- AuraEffectList const& mHealingGet= victim->GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_RECEIVED);
- for(AuraEffectList::const_iterator i = mHealingGet.begin(); i != mHealingGet.end(); ++i)
- if(GetGUID() == (*i)->GetCasterGUID() && (*i)->IsAffectedOnSpell(spellProto))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- heal = (int32(heal) + TakenTotal) * TakenTotalMod;
- return uint32(std::max(heal, 0.0f));
- }
- int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
- {
- int32 AdvertisedBenefit = 0;
- AuraEffectList const& mHealingDone = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE);
- for(AuraEffectList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i)
- if(!(*i)->GetMiscValue() || ((*i)->GetMiscValue() & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetAmount();
- // Healing bonus of spirit, intellect and strength
- if(GetTypeId() == TYPEID_PLAYER)
- {
- // Base value
- AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
- // Healing bonus from stats
- AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
- for(AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
- {
- // stat used dependent from misc value (stat index)
- Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
- AdvertisedBenefit += int32(CalculatePctN(GetStat(usedStat), (*i)->GetAmount()));
- }
- // ... and attack power
- AuraEffectList const& mHealingDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
- for(AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i)
- if((*i)->GetMiscValue() & schoolMask)
- AdvertisedBenefit += int32(CalculatePctN(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
- }
- return AdvertisedBenefit;
- }
- int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit* victim)
- {
- int32 AdvertisedBenefit = 0;
- AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_HEALING);
- for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if(((*i)->GetMiscValue() & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetAmount();
- return AdvertisedBenefit;
- }
- bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask)
- {
- // If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if(itr->type & shoolMask)
- return true;
- // If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for(SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if(itr->type & shoolMask)
- return true;
- return false;
- }
- bool Unit::IsImmunedToDamage(SpellEntry const* spellInfo)
- {
- if(spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
- return false;
- uint32 shoolMask = GetSpellSchoolMask(spellInfo);
- if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
- {
- // If m_immuneToSchool type contain this school type, IMMUNE damage.
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if(itr->type & shoolMask && !CanSpellPierceImmuneAura(spellInfo, sSpellStore.LookupEntry(itr->spellId)))
- return true;
- }
- // If m_immuneToDamage type contain magic, IMMUNE damage.
- SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
- for(SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- if(itr->type & shoolMask)
- return true;
- return false;
- }
- bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo)
- {
- if(!spellInfo)
- return false;
- // Single spell immunity.
- SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
- for(SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
- if(itr->type == spellInfo->Id)
- return true;
- if(spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
- return false;
- if(spellInfo->Dispel)
- {
- SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
- for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
- if(itr->type == spellInfo->Dispel)
- return true;
- }
- if(spellInfo->Mechanic)
- {
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if(itr->type == spellInfo->Mechanic)
- return true;
- }
- for(int i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- // State/effect immunities applied by aura expect full spell immunity
- // Ignore effects with mechanic, they are supposed to be checked separately
- if(!spellInfo->EffectMechanic[i] && spellInfo->Effect[i] != SPELL_EFFECT_KNOCK_BACK)
- if(IsImmunedToSpellEffect(spellInfo, i))
- return true;
- }
- if(spellInfo->Id != 42292 && spellInfo->Id !=59752)
- {
- SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
- for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
- if((itr->type & GetSpellSchoolMask(spellInfo))
- && !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id))
- && !CanSpellPierceImmuneAura(spellInfo, sSpellStore.LookupEntry(itr->spellId)))
- return true;
- }
- return false;
- }
- bool Unit::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const
- {
- if(!spellInfo)
- return false;
- // If m_immuneToEffect type contain this effect type, IMMUNE effect.
- uint32 effect = spellInfo->Effect[index];
- SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
- for(SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
- if(itr->type == effect)
- return true;
- if(uint32 mechanic = spellInfo->EffectMechanic[index])
- {
- SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
- if(itr->type == mechanic)
- return true;
- }
- if(uint32 aura = spellInfo->EffectApplyAuraName[index])
- {
- SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
- for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
- if(itr->type == aura)
- return true;
- // Check for immune to application of harmful magical effects
- AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
- for(AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
- {
- //if(spellInfo->Dispel == DISPEL_MAGIC && // Magic debuff
- // ((*iter)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) && // Check school
- // !IsPositiveEffect(spellInfo->Id, index)) // Harmful
- if((spellInfo->Dispel == DISPEL_MAGIC || spellInfo->Dispel == DISPEL_CURSE ||
- spellInfo->Dispel == DISPEL_DISEASE || spellInfo->Dispel == DISPEL_POISON) // Magic or curse debuff
- // && ((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) // Check school
- // && !spellInfo->IsPositiveEffect(index)) // Harmful
- && ((*iter)->GetMiscValue() & GetSpellSchoolMask(spellInfo)) // Check school
- && !IsPositiveEffect(spellInfo->Id, index)) // Harmful
- return true;
- }
- }
- if(GetTypeId() == TYPEID_PLAYER && spellInfo->Id != 49560)
- {
- if(spellInfo->Effect[index] == SPELL_EFFECT_ATTACK_ME)
- return true;
- if(spellInfo->EffectApplyAuraName[index] == SPELL_AURA_MOD_TAUNT)
- return true;
- }
- return false;
- }
- void Unit::MeleeDamageBonus(Unit* victim, uint32 *pdamage, WeaponAttackType attType, SpellEntry const* spellProto)
- {
- if(!victim)
- return;
- if(*pdamage == 0)
- return;
- uint32 creatureTypeMask = victim->GetCreatureTypeMask();
- // Taken/Done fixed damage bonus auras
- int32 DoneFlatBenefit = 0;
- int32 TakenFlatBenefit = 0;
- // ..done (for creature type by mask) in taken
- AuraEffectList const& mDamageDoneCreature = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
- for(AuraEffectList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- DoneFlatBenefit += (*i)->GetAmount();
- // ..done
- // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
- // ..done (base at attack power for marked target and base at attack power for creature type)
- int32 APbonus = 0;
- if(attType == RANGED_ATTACK)
- {
- APbonus += victim->GetTotalAuraModifier(SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS);
- // ..done (base at attack power and creature type)
- AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
- for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- APbonus += (*i)->GetAmount();
- }
- else
- {
- APbonus += victim->GetTotalAuraModifier(SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS);
- // ..done (base at attack power and creature type)
- AuraEffectList const& mCreatureAttackPower = GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
- for(AuraEffectList::const_iterator i = mCreatureAttackPower.begin(); i != mCreatureAttackPower.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- APbonus += (*i)->GetAmount();
- }
- if(APbonus != 0) // Can be negative
- {
- bool normalized = false;
- if(spellProto)
- for(uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- if(spellProto->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
- {
- normalized = true;
- break;
- }
- DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType, normalized));
- }
- // ..taken
- AuraEffectList const& mDamageTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
- for(AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i)
- if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
- TakenFlatBenefit += (*i)->GetAmount();
- if(attType != RANGED_ATTACK)
- TakenFlatBenefit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
- else
- TakenFlatBenefit += victim->GetTotalAuraModifier(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN);
- Player* player = ToPlayer();
- // Done/Taken total percent damage auras
- float DoneTotalMod = 1.0f;
- float TakenTotalMod = 1.0f;
- // ..done
- AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
- for(AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i)
- if(spellProto)
- {
- if((*i)->GetMiscValue() & GetSpellSchoolMask(spellProto))
- {
- if((*i)->GetSpellProto()->EquippedItemClass == -1)
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- else if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
- {
- if((*i)->GetSpellProto()->EquippedItemClass & spellProto->EquippedItemClass)
- if(((*i)->GetSpellProto()->EquippedItemSubClassMask == 0) ||
- ((*i)->GetSpellProto()->EquippedItemSubClassMask & spellProto->EquippedItemSubClassMask))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- else if(ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- }
- else if(player)
- {
- if(!((*i)->GetSpellProto()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK))
- {
- EquipmentSlots slot;
- switch(attType)
- {
- case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
- case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
- default: return;
- }
- Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
- if(item && !item->IsBroken() && item->IsFitToSpellRequirements((*i)->GetSpellProto()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- else if(player->HasItemFitToSpellRequirements((*i)->GetSpellProto()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- // Creatures' melee
- else if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
- if(!HasUnitTypeMask(UNIT_MASK_GUARDIAN))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
- for(AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
- if(creatureTypeMask & uint32((*i)->GetMiscValue()))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- // bonus against aurastate
- AuraEffectList const& mDamageDoneVersusAurastate = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE);
- for(AuraEffectList::const_iterator i = mDamageDoneVersusAurastate.begin(); i != mDamageDoneVersusAurastate.end(); ++i)
- if(victim->HasAuraState(AuraState((*i)->GetMiscValue())))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- // done scripted mod (take it from owner)
- Unit* owner = GetOwner() ? GetOwner() : this;
- AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
- {
- if(!(*i)->IsAffectedOnSpell(spellProto))
- continue;
- switch((*i)->GetMiscValue())
- {
- // Tundra Stalker
- // Merciless Combat
- case 7277:
- {
- // Merciless Combat
- if((*i)->GetSpellProto()->SpellIconID == 2656)
- {
- if(!victim->HealthAbovePct(35))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- // Tundra Stalker
- else
- {
- // Frost Fever (target debuff)
- if(victim->HasAura(55095))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- }
- break;
- }
- // Rage of Rivendare
- case 7293:
- {
- if(victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0x02000000, 0))
- if(SpellChainNode const* chain = sSpellMgr->GetSpellChainNode((*i)->GetId()))
- AddPctF(DoneTotalMod, chain->rank * 2.0f);
- break;
- }
- // Marked for Death
- case 7598:
- case 7599:
- case 7600:
- case 7601:
- case 7602:
- {
- if(victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
- AddPctN(DoneTotalMod, (*i)->GetAmount());
- break;
- }
- // Dirty Deeds
- case 6427:
- case 6428:
- {
- if(victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
- {
- // effect 0 have expected value but in negative state
- int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
- AddPctN(DoneTotalMod, bonus);
- }
- break;
- }
- }
- }
- // Custom scripted damage
- if(spellProto)
- switch(spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_DEATHKNIGHT:
- // Glacier Rot
- if(spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
- if(AuraEffect* aurEff = GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 196, 0))
- if(victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
- AddPctN(DoneTotalMod, aurEff->GetAmount());
- break;
- }
- // ..taken
- TakenTotalMod *= victim->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, GetMeleeDamageSchoolMask());
- // From caster spells
- AuraEffectList const& mOwnerTaken = victim->GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_FROM_CASTER);
- for(AuraEffectList::const_iterator i = mOwnerTaken.begin(); i != mOwnerTaken.end(); ++i)
- if((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectedOnSpell(spellProto))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- // .. taken pct (special attacks)
- if(spellProto)
- {
- // Mod damage from spell mechanic
- uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
- // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
- if(spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
- mechanicMask |= (1<<MECHANIC_BLEED);
- if(mechanicMask)
- {
- AuraEffectList const& mDamageDoneMechanic = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
- for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin(); i != mDamageDoneMechanic.end(); ++i)
- if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- }
- }
- // .. taken pct: dummy auras
- AuraEffectList const& mDummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
- for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
- {
- switch((*i)->GetSpellProto()->SpellIconID)
- {
- // Cheat Death
- case 2109:
- if((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
- {
- if(victim->GetTypeId() != TYPEID_PLAYER)
- continue;
- float mod = victim->ToPlayer()->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE) * (-8.0f);
- AddPctF(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
- }
- break;
- // Blessing of Sanctuary
- // Greater Blessing of Sanctuary
- case 19:
- case 1804:
- {
- if((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_PALADIN)
- continue;
- if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- break;
- }
- // Ebon Plague
- case 1933:
- if((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0))
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- break;
- }
- }
- // .. taken pct: class scripts
- /*AuraEffectList const& mclassScritAuras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
- for(AuraEffectList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
- {
- switch((*i)->GetMiscValue()) { }
- }*/
- if(attType != RANGED_ATTACK)
- {
- AuraEffectList const& mModMeleeDamageTakenPercent = victim->GetAuraEffectsByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
- for(AuraEffectList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- }
- else
- {
- AuraEffectList const& mModRangedDamageTakenPercent = victim->GetAuraEffectsByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
- for(AuraEffectList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
- AddPctN(TakenTotalMod, (*i)->GetAmount());
- }
- float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
- // apply spellmod to Done damage
- if(spellProto)
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_DAMAGE, tmpDamage);
- tmpDamage = (tmpDamage + TakenFlatBenefit) * TakenTotalMod;
- // bonus result can be negative
- *pdamage = uint32(std::max(tmpDamage, 0.0f));
- }
- void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
- {
- if(apply)
- {
- for(SpellImmuneList::iterator itr = m_spellImmune[op].begin(), next; itr != m_spellImmune[op].end(); itr = next)
- {
- next = itr; ++next;
- if(itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- next = m_spellImmune[op].begin();
- }
- }
- SpellImmune Immune;
- Immune.spellId = spellId;
- Immune.type = type;
- m_spellImmune[op].push_back(Immune);
- }
- else
- {
- for(SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
- {
- if(itr->spellId == spellId && itr->type == type)
- {
- m_spellImmune[op].erase(itr);
- break;
- }
- }
- }
- }
- void Unit::ApplySpellDispelImmunity(const SpellEntry * spellProto, DispelType type, bool apply)
- {
- ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
- if(apply && spellProto->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY)
- {
- // Create dispel mask by dispel type
- uint32 dispelMask = GetDispelMask(type);
- // Dispel all existing auras vs current dispel type
- AuraApplicationMap& auras = GetAppliedAuras();
- for(AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();)
- {
- SpellEntry const* spell = itr->second->GetBase()->GetSpellProto();
- if((1<<spell->Dispel) & dispelMask)
- {
- // Dispel aura
- RemoveAura(itr);
- }
- else
- ++itr;
- }
- }
- }
- float Unit::GetWeaponProcChance() const
- {
- // normalized proc chance for weapon attack speed
- // (odd formula...)
- if(isAttackReady(BASE_ATTACK))
- return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
- else if(haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
- return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
- return 0;
- }
- float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * spellProto) const
- {
- // proc per minute chance calculation
- if(PPM <= 0) return 0.0f;
- // Apply chance modifer aura
- if(spellProto)
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
- return floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
- }
- void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
- {
- if(mount)
- SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, mount);
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT);
- if(Player* pPlayer = ToPlayer())
- {
- // mount as a vehicle
- if(VehicleId)
- {
- if(CreateVehicleKit(VehicleId, creatureEntry))
- {
- GetVehicleKit()->Reset();
- // Send others that we now have a vehicle
- WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, GetPackGUID().size()+4);
- data.appendPackGUID(GetGUID());
- data << uint32(VehicleId);
- SendMessageToSet(&data, true);
- data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- pPlayer->GetSession()->SendPacket(&data);
- // mounts can also have accessories
- GetVehicleKit()->InstallAllAccessories(false);
- }
- }
- // unsummon pet
- if(Pet* pPet = pPlayer->GetPet())
- {
- Battleground* pBG = ToPlayer()->GetBattleground();
- // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface
- if(pBG && pBG->isArena())
- pPet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- else
- pPlayer->UnsummonPetTemporaryIfAny();
- }
- }
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT);
- }
- void Unit::Unmount()
- {
- if(!IsMounted())
- return;
- SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT);
- WorldPacket data(SMSG_DISMOUNT, 8);
- data.appendPackGUID(GetGUID());
- SendMessageToSet(&data, true);
- // unmount as a vehicle
- if(GetTypeId() == TYPEID_PLAYER && GetVehicleKit())
- {
- // Send other players that we are no longer a vehicle
- WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, 8+4);
- data.appendPackGUID(GetGUID());
- data << uint32(0);
- ToPlayer()->SendMessageToSet(&data, true);
- // Remove vehicle from player
- RemoveVehicleKit();
- }
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED);
- // only resummon old pet if the player is already added to a map
- // this prevents adding a pet to a not created map which would otherwise cause a crash
- // (it could probably happen when logging in after a previous crash)
- if(Player* plr = ToPlayer())
- {
- if(Pet* pPet = plr->GetPet())
- {
- if(pPet->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STAT_STUNNED))
- pPet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
- }
- else
- plr->ResummonPetTemporaryUnSummonedIfAny();
- }
- }
- void Unit::SetInCombatWith(Unit* enemy)
- {
- Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf();
- if(eOwner->IsPvP())
- {
- SetInCombatState(true, enemy);
- return;
- }
- // check for duel
- if(eOwner->GetTypeId() == TYPEID_PLAYER && eOwner->ToPlayer()->duel)
- {
- Unit const* myOwner = GetCharmerOrOwnerOrSelf();
- if(((Player const*)eOwner)->duel->opponent == myOwner)
- {
- SetInCombatState(true, enemy);
- return;
- }
- }
- SetInCombatState(false, enemy);
- }
- void Unit::CombatStart(Unit* target, bool initialAggro)
- {
- if(initialAggro)
- {
- if(!target->IsStandState())
- target->SetStandState(UNIT_STAND_STATE_STAND);
- if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
- && !target->ToCreature()->HasReactState(REACT_PASSIVE) && target->ToCreature()->IsAIEnabled)
- {
- target->ToCreature()->AI()->AttackStart(this);
- }
- SetInCombatWith(target);
- target->SetInCombatWith(this);
- }
- Unit* who = target->GetCharmerOrOwnerOrSelf();
- if(who->GetTypeId() == TYPEID_PLAYER)
- SetContestedPvP(who->ToPlayer());
- Player* me = GetCharmerOrOwnerPlayerOrPlayerItself();
- if(me && who->IsPvP()
- && (who->GetTypeId() != TYPEID_PLAYER
- || !me->duel || me->duel->opponent != who))
- {
- me->UpdatePvP(true);
- me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
- }
- }
- void Unit::SetInCombatState(bool PvP, Unit* enemy)
- {
- // only alive units can be in combat
- if(!isAlive())
- return;
- if(PvP)
- m_CombatTimer = 5000;
- if(isInCombat() || HasUnitState(UNIT_STAT_EVADE))
- return;
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(Creature* creature = ToCreature())
- {
- // Set home position at place of engaging combat for escorted creatures
- if((IsAIEnabled && creature->AI()->IsEscorted()) ||
- GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE ||
- GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
- creature->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
- if(enemy)
- {
- if(IsAIEnabled)
- {
- creature->AI()->EnterCombat(enemy);
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); // always remove Out of Combat Non Attackable flag if we enter combat and AI is enabled
- }
- if(creature->GetFormation())
- creature->GetFormation()->MemberAttackStart(creature, enemy);
- }
- if(isPet())
- {
- UpdateSpeed(MOVE_RUN, true);
- UpdateSpeed(MOVE_SWIM, true);
- UpdateSpeed(MOVE_FLIGHT, true);
- }
- if(!(creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_MOUNTED_COMBAT))
- Unmount();
- }
- for(Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
- {
- (*itr)->SetInCombatState(PvP, enemy);
- (*itr)->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
- }
- }
- void Unit::ClearInCombat()
- {
- m_CombatTimer = 0;
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- // Player's state will be cleared in Player::UpdateContestedPvP
- if(Creature* creature = ToCreature())
- {
- if(creature->GetCreatureInfo() && creature->GetCreatureInfo()->unit_flags & UNIT_FLAG_OOC_NOT_ATTACKABLE)
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); // re-apply Out of Combat Non Attackable flag if we leave combat, can be overriden in scripts in EnterEvadeMode()
- ClearUnitState(UNIT_STAT_ATTACK_PLAYER);
- if(HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED))
- SetUInt32Value(UNIT_DYNAMIC_FLAGS, creature->GetCreatureInfo()->dynamicflags);
- if(creature->isPet())
- {
- if(Unit* owner = GetOwner())
- for(uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
- if(owner->GetSpeedRate(UnitMoveType(i)) > GetSpeedRate(UnitMoveType(i)))
- SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true);
- }
- else if(!isCharmed())
- return;
- }
- else
- ToPlayer()->UpdatePotionCooldown();
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
- }
- // TODO: remove this function
- bool Unit::isTargetableForAttack() const
- {
- return isAttackableByAOE() && !HasUnitState(UNIT_STAT_DIED);
- }
- bool Unit::canAttack(Unit const* target, bool force) const
- {
- ASSERT(target);
- if(force)
- {
- if(IsFriendlyTo(target))
- return false;
- if(GetTypeId() != TYPEID_PLAYER)
- {
- if(isPet())
- {
- if(Unit* owner = GetOwner())
- if(!(owner->canAttack(target)))
- return false;
- }
- else if(!IsHostileTo(target))
- return false;
- }
- }
- else if(!IsHostileTo(target))
- return false;
- if(!target->isAttackableByAOE())
- return false;
- if(target->HasUnitState(UNIT_STAT_DIED) && GetTypeId() != TYPEID_PLAYER)
- {
- if(!ToCreature() || !ToCreature()->isGuard())
- return false;
- // guards can detect fake death
-