aboutsummaryrefslogtreecommitdiff
path: root/src/game/Unit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Unit.cpp')
-rw-r--r--src/game/Unit.cpp2419
1 files changed, 2059 insertions, 360 deletions
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index a78f1ca2c29..6dc5e6201a5 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -61,6 +61,8 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
4.5f, // MOVE_FLYBACK
};
+void InitTriggerAuraData();
+
// auraTypes contains attacker auras capable of proc'ing cast auras
static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes()
{
@@ -114,6 +116,8 @@ static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectA
// auraTypes contains auras capable of proc'ing for attacker and victim
static Unit::AuraTypeSet GenerateProcAuraTypes()
{
+ InitTriggerAuraData();
+
Unit::AuraTypeSet auraTypes;
auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end());
auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end());
@@ -144,6 +148,7 @@ bool IsPassiveStackableSpell( uint32 spellId )
Unit::Unit()
: WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
+, m_IsInNotifyList(false), m_Notified(false)
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
@@ -283,7 +288,8 @@ void Unit::Update( uint32 p_time )
}
}
- if(!hasUnitState(UNIT_STAT_CASTING))
+ //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) );
@@ -472,7 +478,7 @@ void Unit::RemoveSpellsCausingAura(AuraType auraType)
}
}
-void Unit::RemoveAurasWithInterruptFlags(uint32 flag)
+void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except)
{
if(!(m_interruptMask & flag))
return;
@@ -487,18 +493,27 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flag)
//sLog.outDetail("auraflag:%u flag:%u = %u",(*iter)->GetSpellProto()->AuraInterruptFlags,flag,(*iter)->GetSpellProto()->AuraInterruptFlags & flag);
if(*iter && ((*iter)->GetSpellProto()->AuraInterruptFlags & flag))
{
- RemoveAurasDueToSpell((*iter)->GetId());
- if (!m_interruptableAuras.empty())
- next = m_interruptableAuras.begin();
- else
- break;
+ if((*iter)->IsInUse())
+ sLog.outError("Aura %u is trying to remove itself! Flag %u. May cause crash!", (*iter)->GetId(), flag);
+ else if(!except || (*iter)->GetId() != except)
+ {
+ RemoveAurasDueToSpell((*iter)->GetId());
+ if (!m_interruptableAuras.empty())
+ next = m_interruptableAuras.begin();
+ else
+ break;
+ }
}
}
// interrupt channeled spell
if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if(spell->getState() == SPELL_STATE_CASTING && (spell->m_spellInfo->ChannelInterruptFlags & flag))
+ if(spell->getState() == SPELL_STATE_CASTING
+ && (spell->m_spellInfo->ChannelInterruptFlags & flag)
+ && spell->m_spellInfo->Id != except)
InterruptNonMeleeSpells(false);
+
+ UpdateInterruptMask();
}
void Unit::UpdateInterruptMask()
@@ -666,6 +681,8 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
{
DEBUG_LOG("DealDamage: victim just died");
+ pVictim->SetHealth(0);
+
// find player: owner of controlled `this` or `this` itself maybe
Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
@@ -674,8 +691,12 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// Reward player, his pets, and group/raid members
// call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
if(player && player!=pVictim)
+ {
if(player->RewardPlayerAndGroupAtKill(pVictim))
- player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ else
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0);
+ }
DEBUG_LOG("DealDamageAttackStop");
@@ -744,7 +765,8 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// FORM_SPIRITOFREDEMPTION and related auras
pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady);
}
- else
+ else //without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
+ //do not why since in IncreaseMaxHealth currenthealth is checked
pVictim->SetHealth(0);
// remember victim PvP death for corpse type and corpse reclaim delay
@@ -829,22 +851,15 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
// battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
- if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
+ if(player && player->InBattleGround())
{
- Player *killed = ((Player*)pVictim);
- Player *killer = NULL;
- if(GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)this);
- else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
+ if(BattleGround *bg = player->GetBattleGround())
{
- Unit *owner = GetOwner();
- if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)owner);
+ if(pVictim->GetTypeId() == TYPEID_PLAYER)
+ bg->HandleKillPlayer((Player*)pVictim, player);
+ else
+ bg->HandleKillUnit((Creature*)pVictim, player);
}
-
- if(killer)
- if(BattleGround *bg = killed->GetBattleGround())
- bg->HandleKillPlayer(killed, killer); // drop flags and etc
}
}
else // if (health <= damage)
@@ -853,18 +868,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
pVictim->ModifyHealth(- (int32)damage);
- // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
- if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
- {
- uint32 procVictim = PROC_FLAG_NONE;
-
- // if just dropped below 20% (for CheatDeath)
- if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
- procVictim = PROC_FLAG_LOW_HEALTH;
-
- ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
- }
-
if(damagetype != DOT)
{
if(getVictim())
@@ -881,8 +884,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
- if(damagetype == DIRECT_DAMAGE|| damagetype == SPELL_DIRECT_DAMAGE)
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
+ if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
+ {
+ //TODO: This is from procflag, I do not know which spell needs this
+ //Maim?
+ //if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
+ }
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
@@ -920,10 +928,30 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if (damagetype != NODAMAGE && damage)// && pVictim->GetTypeId() == TYPEID_PLAYER)
{
- //if (se->procFlags & (1<<3))
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE);
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE, spellProto ? spellProto->Id : 0);
pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
+ /*const SpellEntry *se = i->second->GetSpellProto();
+ next = i; ++next;
+ if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self
+ continue;
+ if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
+ {
+ bool remove = true;
+ if (se->procFlags & (1<<3))
+ {
+ if (!roll_chance_i(se->procChance))
+ remove = false;
+ }
+ if (remove)
+ {
+ pVictim->RemoveAurasDueToSpell(i->second->GetId());
+ // FIXME: this may cause the auras with proc chance to be rerolled several times
+ next = vAuras.begin();
+ }
+ }
+ }*/
+
if(pVictim != this && pVictim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
{
if(damagetype != DOT)
@@ -1101,6 +1129,7 @@ void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, boo
spell->prepare(&targets, triggeredByAura);
}
+/*
void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
{
// TODO this in only generic way, check for exceptions
@@ -1187,7 +1216,7 @@ void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *da
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- bonusDmg = uint32(bonusDmg * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
+ bonusDmg = uint32(bonusDmg * ((*i)->GetModifierValue()+100.0f)/100.0f);
*damage += bonusDmg;
@@ -1482,7 +1511,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
// Actual log sent to client
- SendSpellNonMeleeDamageLog(pVictim, spellID, damage, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
+ SendSpellNonMeleeDamageLog(pVictim, spellID, damage + resist, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
// Procflags
uint32 procAttacker = PROC_FLAG_HIT_SPELL;
@@ -1511,6 +1540,577 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
return 0;
}
}
+*/
+
+// Obsolete func need remove, here only for comotability vs another patches
+uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
+{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
+ SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
+ CalculateSpellDamage(&damageInfo, damage, spellInfo);
+ SendSpellNonMeleeDamageLog(&damageInfo);
+ DealSpellDamage(&damageInfo, true);
+ return damageInfo.damage;
+}
+
+void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
+{
+ SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
+ Unit *pVictim = damageInfo->target;
+
+ if (damage < 0)
+ return;
+
+ if(!this || !pVictim)
+ return;
+ if(!this->isAlive() || !pVictim->isAlive())
+ return;
+
+ uint32 crTypeMask = pVictim->GetCreatureTypeMask();
+ // Check spell crit chance
+ bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, 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 )
+ {
+ //Calculate armor mitigation
+ damage = CalcArmorReducedDamage(pVictim, damage);
+ // Get blocked status
+ blocked = isSpellBlocked(pVictim, spellInfo, attackType);
+ }
+ // Magical Damage
+ else
+ {
+ // Calculate damage bonus
+ damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ }
+ 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
+ int32 critPctDamageMod=0;
+ if(attackType == RANGED_ATTACK)
+ critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
+ else
+ {
+ critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
+ critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
+ }
+ // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
+ critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
+
+ if (critPctDamageMod!=0)
+ damage = int32((damage) * float((100.0f + critPctDamageMod)/100.0f));
+
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ damage -= ((Player*)pVictim)->GetMeleeCritDamageReduction(damage);
+ }
+ // Spell weapon based damage CAN BE crit & blocked at same time
+ if (blocked)
+ {
+ damageInfo->blocked = uint32(pVictim->GetShieldBlockValue());
+ if (damage < damageInfo->blocked)
+ damageInfo->blocked = damage;
+ damage-=damageInfo->blocked;
+ }
+ }
+ break;
+ // Magical Attacks
+ case SPELL_DAMAGE_CLASS_NONE:
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ {
+ // Calculate damage bonus
+ damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ // If crit add critical bonus
+ if (crit)
+ {
+ damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
+ damage = SpellCriticalBonus(spellInfo, damage, pVictim);
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage);
+ }
+ }
+ break;
+ }
+
+ // Calculate absorb resist
+ if(damage > 0)
+ {
+ CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist);
+ damage-= damageInfo->absorb + damageInfo->resist;
+ }
+ else
+ damage = 0;
+ damageInfo->damage = damage;
+}
+
+void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
+{
+ if (damageInfo==0)
+ return;
+
+ Unit *pVictim = damageInfo->target;
+
+ if(!this || !pVictim)
+ return;
+
+ if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return;
+
+ SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if (spellProto == NULL)
+ {
+ sLog.outDebug("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID);
+ return;
+ }
+
+ //You don't lose health from damage taken from another player while in a sanctuary
+ //You still see it in the combat log though
+ if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
+ if(area && area->flags & 0x800) //sanctuary
+ return;
+ }
+
+ // update at damage Judgement aura duration that applied by attacker at victim
+ if(damageInfo->damage && spellProto->Id == 35395)
+ {
+ AuraMap& vAuras = pVictim->GetAuras();
+ for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
+ {
+ SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
+ if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
+ {
+ (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
+ (*itr).second->UpdateAuraDuration();
+ }
+ }
+ }
+ // Call default DealDamage
+ CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
+ DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
+}
+
+//TODO for melee need create structure as in
+void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType)
+{
+ damageInfo->attacker = this;
+ damageInfo->target = pVictim;
+ damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
+ damageInfo->attackType = attackType;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ damageInfo->absorb = 0;
+ damageInfo->resist = 0;
+ damageInfo->blocked_amount = 0;
+
+ damageInfo->TargetState = 0;
+ damageInfo->HitInfo = 0;
+ damageInfo->procAttacker = PROC_FLAG_NONE;
+ damageInfo->procVictim = PROC_FLAG_NONE;
+ damageInfo->procEx = PROC_EX_NONE;
+ damageInfo->hitOutCome = MELEE_HIT_EVADE;
+
+ if(!this || !pVictim)
+ return;
+ if(!this->isAlive() || !pVictim->isAlive())
+ return;
+
+ // Select HitInfo/procAttacker/procVictim flag based on attack type
+ switch (attackType)
+ {
+ case BASE_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;
+ damageInfo->HitInfo = HITINFO_NORMALSWING2;
+ break;
+ case OFF_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used
+ damageInfo->HitInfo = HITINFO_LEFTSWING;
+ break;
+ case RANGED_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
+ damageInfo->HitInfo = 0x08;// test
+ break;
+ default:
+ break;
+ }
+
+ // Physical Immune check
+ if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask),true))
+ {
+ damageInfo->HitInfo |= HITINFO_NORMALSWING;
+ damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
+
+ damageInfo->procEx |=PROC_EX_IMMUNE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ damage += CalculateDamage (damageInfo->attackType, false);
+ // Add melee damage bonus
+ MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
+ // Calculate armor reduction
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->cleanDamage += damage - damageInfo->damage;
+
+ damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
+
+ // Disable parry or dodge for ranged attack
+ if(damageInfo->attackType == RANGED_ATTACK)
+ {
+ if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL;
+ if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS;
+ }
+
+ switch(damageInfo->hitOutCome)
+ {
+ case MELEE_HIT_EVADE:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
+ damageInfo->TargetState = VICTIMSTATE_EVADES;
+
+ damageInfo->procEx|=PROC_EX_EVADE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ case MELEE_HIT_MISS:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_EX_MISS;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ break;
+ }
+ case MELEE_HIT_NORMAL:
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ break;
+ case MELEE_HIT_CRIT:
+ {
+ damageInfo->HitInfo |= HITINFO_CRITICALHIT;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_EX_CRITICAL_HIT;
+ // Crit bonus calc
+ damageInfo->damage += damageInfo->damage;
+ int32 mod=0;
+ // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
+ if(damageInfo->attackType == RANGED_ATTACK)
+ mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
+ else
+ {
+ mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
+ mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
+ }
+
+ uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
+
+ // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
+ mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
+ if (mod!=0)
+ damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f));
+
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ {
+ uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(damageInfo->damage);
+ damageInfo->damage -= resilienceReduction;
+ damageInfo->cleanDamage += resilienceReduction;
+ }
+ break;
+ }
+ case MELEE_HIT_PARRY:
+ damageInfo->TargetState = VICTIMSTATE_PARRY;
+ damageInfo->procEx|=PROC_EX_PARRY;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+
+ case MELEE_HIT_DODGE:
+ damageInfo->TargetState = VICTIMSTATE_DODGE;
+ damageInfo->procEx|=PROC_EX_DODGE;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+ case MELEE_HIT_BLOCK:
+ {
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_BLOCK;
+ damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
+ if (damageInfo->blocked_amount >= damageInfo->damage)
+ {
+ damageInfo->TargetState = VICTIMSTATE_BLOCKS;
+ damageInfo->blocked_amount = damageInfo->damage;
+ }
+ damageInfo->damage -= damageInfo->blocked_amount;
+ damageInfo->cleanDamage += damageInfo->blocked_amount;
+ break;
+ }
+ case MELEE_HIT_GLANCING:
+ {
+ damageInfo->HitInfo |= HITINFO_GLANCING;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ float reducePercent = 1.0f; //damage factor
+ // calculate base values and mods
+ float baseLowEnd = 1.3;
+ float baseHighEnd = 1.2;
+ switch(getClass()) // lowering base values for casters
+ {
+ case CLASS_SHAMAN:
+ case CLASS_PRIEST:
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ case CLASS_DRUID:
+ baseLowEnd -= 0.7;
+ baseHighEnd -= 0.3;
+ break;
+ }
+
+ float maxLowEnd = 0.6;
+ switch(getClass()) // upper for melee classes
+ {
+ case CLASS_WARRIOR:
+ case CLASS_ROGUE:
+ maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
+ }
+
+ // calculate values
+ int32 diff = damageInfo->target->GetDefenseSkillValue() - GetWeaponSkillValue(damageInfo->attackType);
+ float lowEnd = baseLowEnd - ( 0.05f * diff );
+ float highEnd = baseHighEnd - ( 0.03f * diff );
+
+ // apply max/min bounds
+ if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
+ lowEnd = 0.01f;
+ else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
+ lowEnd = maxLowEnd;
+
+ if ( highEnd < 0.2f ) //high end limits
+ highEnd = 0.2f;
+ if ( highEnd > 0.99f )
+ highEnd = 0.99f;
+
+ if(lowEnd > highEnd) // prevent negative range size
+ lowEnd = highEnd;
+
+ reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
+
+ damageInfo->cleanDamage += damageInfo->damage-uint32(reducePercent * damageInfo->damage);
+ damageInfo->damage = uint32(reducePercent * damageInfo->damage);
+ break;
+ }
+ case MELEE_HIT_CRUSHING:
+ {
+ damageInfo->HitInfo |= HITINFO_CRUSHING;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ // 150% normal damage
+ damageInfo->damage += (damageInfo->damage / 2);
+ break;
+ }
+ default:
+
+ break;
+ }
+
+ // Calculate absorb resist
+ if(int32(damageInfo->damage) > 0)
+ {
+ damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+ // Calculate absorb & resists
+ CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
+ damageInfo->damage-=damageInfo->absorb + damageInfo->resist;
+ if (damageInfo->absorb)
+ {
+ damageInfo->HitInfo|=HITINFO_ABSORB;
+ damageInfo->procEx|=PROC_EX_ABSORB;
+ }
+ if (damageInfo->resist)
+ damageInfo->HitInfo|=HITINFO_RESIST;
+
+ }
+ else // Umpossible get negative result but....
+ damageInfo->damage = 0;
+}
+
+void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
+{
+ if (damageInfo==0) return;
+ Unit *pVictim = damageInfo->target;
+
+ if(!this || !pVictim)
+ return;
+
+ if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return;
+
+ //You don't lose health from damage taken from another player while in a sanctuary
+ //You still see it in the combat log though
+ if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
+ if(area && area->flags & 0x800) //sanctuary
+ return;
+ }
+
+ // Hmmmm dont like this emotes cloent must by self do all animations
+ if (damageInfo->HitInfo&HITINFO_CRITICALHIT)
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
+ if(damageInfo->blocked_amount && damageInfo->TargetState!=VICTIMSTATE_BLOCKS)
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
+
+ if(damageInfo->TargetState == VICTIMSTATE_PARRY)
+ {
+ // Get attack timers
+ float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
+ float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
+ // Reduce attack time
+ if (pVictim->haveOffhandWeapon() && offtime < basetime)
+ {
+ float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
+ float percent60 = 3 * percent20;
+ if(offtime > percent20 && offtime <= percent60)
+ {
+ pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
+ }
+ else if(offtime > percent60)
+ {
+ offtime -= 2 * percent20;
+ pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
+ }
+ }
+ else
+ {
+ float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
+ float percent60 = 3 * percent20;
+ if(basetime > percent20 && basetime <= percent60)
+ {
+ pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
+ }
+ else if(basetime > percent60)
+ {
+ basetime -= 2 * percent20;
+ pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
+ }
+ }
+ }
+
+ // Call default DealDamage
+ CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
+ DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
+
+ // If this is a creature and it attacks from behind it has a probability to daze it's victim
+ if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) &&
+ GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
+ {
+ // -probability is between 0% and 40%
+ // 20% base chance
+ float Probability = 20;
+
+ //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
+ if( pVictim->getLevel() < 30 )
+ Probability = 0.65f*pVictim->getLevel()+0.5;
+
+ uint32 VictimDefense=pVictim->GetDefenseSkillValue();
+ uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
+
+ Probability *= AttackerMeleeSkill/(float)VictimDefense;
+
+ if(Probability > 40)
+ Probability = 40;
+
+ if(roll_chance_f(Probability))
+ CastSpell(pVictim, 1604, true);
+ }
+
+ // update at damage Judgement aura duration that applied by attacker at victim
+ if(damageInfo->damage)
+ {
+ AuraMap& vAuras = pVictim->GetAuras();
+ for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
+ {
+ SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
+ if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
+ {
+ (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
+ (*itr).second->UpdateAuraDuration();
+ }
+ }
+ }
+
+ // If not miss
+ if (!(damageInfo->HitInfo & HITINFO_MISS))
+ {
+ if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
+ {
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), pVictim, damageInfo->attackType);
+ }
+
+ // victim's damage shield
+ std::set<Aura*> alreadyDone;
+ uint32 removedAuras = pVictim->m_removedAuras;
+ AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
+ for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
+ {
+ next++;
+ if (alreadyDone.find(*i) == alreadyDone.end())
+ {
+ alreadyDone.insert(*i);
+ uint32 damage=(*i)->GetModifier()->m_amount;
+ SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId());
+ if(!spellProto)
+ continue;
+ //Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist?
+ //uint32 absorb;
+ //uint32 resist;
+ //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
+ //damage-=absorb + resist;
+
+ WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4));
+ data << uint64(pVictim->GetGUID());
+ data << uint64(GetGUID());
+ data << uint32(spellProto->SchoolMask);
+ data << uint32(damage);
+ pVictim->SendMessageToSet(&data, true );
+
+ pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
+
+ if (pVictim->m_removedAuras > removedAuras)
+ {
+ removedAuras = pVictim->m_removedAuras;
+ next = vDamageShields.begin();
+ }
+ }
+ }
+ }
+}
+
void Unit::HandleEmoteCommand(uint32 anim_id)
{
@@ -1769,6 +2369,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
*absorb = damage - RemainingDamage - *resist;
}
+/*
void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
{
MeleeHitOutcome outcome;
@@ -1870,7 +2471,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- crit_bonus = uint32(crit_bonus * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
+ crit_bonus = uint32(crit_bonus * ((*i)->GetModifierValue()+100.0f)/100.0f);
}
*damage += crit_bonus;
@@ -2148,9 +2749,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
}
}
- CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
-
- // victim's damage shield
+ CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);eld
// yet another hack to fix crashes related to the aura getting removed during iteration
std::set<Aura*> alreadyDone;
uint32 removedAuras = pVictim->m_removedAuras;
@@ -2161,7 +2760,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
if (alreadyDone.find(*i) == alreadyDone.end())
{
alreadyDone.insert(*i);
- pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
+ pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifierValue(), false, false);
if (pVictim->m_removedAuras > removedAuras)
{
removedAuras = pVictim->m_removedAuras;
@@ -2169,7 +2768,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
}
}
}
-}
+}*/
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
{
@@ -2183,6 +2782,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
return;
CombatStart(pVictim);
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK);
uint32 hitInfo;
if (attType == BASE_ATTACK)
@@ -2213,65 +2813,19 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
return;
}
- VictimState victimState = VICTIMSTATE_NORMAL;
-
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- uint32 blocked_dmg = 0;
- uint32 absorbed_dmg = 0;
- uint32 resisted_dmg = 0;
-
- SpellSchoolMask meleeSchoolMask = GetMeleeDamageSchoolMask();
-
- if(pVictim->IsImmunedToDamage(meleeSchoolMask,true)) // use charges
- {
- SendAttackStateUpdate (HITINFO_NORMALSWING, pVictim, 1, meleeSchoolMask, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
-
- // not recent extra attack only at any non extra attack (miss case)
- if(!extra && extraAttacks)
- {
- while(m_extraAttacks)
- {
- AttackerStateUpdate(pVictim, BASE_ATTACK, true);
- if(m_extraAttacks > 0)
- --m_extraAttacks;
- }
- }
-
- return;
- }
-
- uint32 damage = CalculateDamage (attType, false);
-
- DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
-
- if (hitInfo & HITINFO_MISS)
- //send miss
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
- else
- {
- //do animation
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
-
- if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
- damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
- else
- damage = 0;
-
- DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchoolMask, NULL, true);
-
- if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
- {
- for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
- ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim,attType);
- }
- }
+ CalcDamageInfo damageInfo;
+ CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
+ // Send log damage message to client
+ SendAttackStateUpdate(&damageInfo);
+ ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
+ DealMeleeDamage(&damageInfo,true);
if (GetTypeId() == TYPEID_PLAYER)
DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
- GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
else
DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
- GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
// extra attack only at any non extra attack (normal case)
if(!extra && extraAttacks)
@@ -2285,6 +2839,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
}
}
+/*
MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
{
// Miss chance based on melee
@@ -2343,7 +2898,7 @@ MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAtt
DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance);
return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true);
-}
+}*/
MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const
{
@@ -2614,7 +3169,18 @@ void Unit::SendAttackStop(Unit* victim)
((Creature*)victim)->AI().EnterEvadeMode(this);*/
}
-/*
+bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType)
+{
+ if (pVictim->HasInArc(M_PI,this))
+ {
+ float blockChance = GetUnitBlockChance();
+ blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04;
+ if (roll_chance_f(blockChance))
+ return true;
+ }
+ return false;
+}
+
// Melee based spells can be miss, parry or dodge on this step
// Crit or block - determined on damage calculation phase! (and can be both in some time)
float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
@@ -2738,7 +3304,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
return SPELL_MISS_PARRY;
return SPELL_MISS_NONE;
-}*/
+}
// TODO need use unit spell resistances in calculations
SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
@@ -2808,6 +3374,14 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
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 *spell, bool CanReflect)
{
// Return evade for units in evade mode
@@ -2832,65 +3406,30 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true))
return SPELL_MISS_IMMUNE;
+ if(this == pVictim)
+ return SPELL_MISS_NONE;
+
// Try victim reflect spell
if (CanReflect)
{
- // specialized first
+ int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- {
if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
- {
- int32 reflectchance = (*i)->GetModifier()->m_amount;
- if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- if((*i)->m_procCharges > 0)
- {
- --(*i)->m_procCharges;
- if((*i)->m_procCharges==0)
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
- }
- return SPELL_MISS_REFLECT;
- }
- }
- }
-
- // generic reflection
- Unit::AuraList const& mReflectSpells = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS);
- for(Unit::AuraList::const_iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i)
+ reflectchance = (*i)->GetModifierValue();
+ if (reflectchance > 0 && roll_chance_i(reflectchance))
{
- int32 reflectchance = (*i)->GetModifier()->m_amount;
- if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- if((*i)->m_procCharges > 0)
- {
- --(*i)->m_procCharges;
- if((*i)->m_procCharges==0)
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
- }
- return SPELL_MISS_REFLECT;
- }
+ // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
+ ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell);
+ return SPELL_MISS_REFLECT;
}
}
- // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
- for (int i=0;i<3;i++)
- {
- if (spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE ||
- spell->Effect[i] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE ||
- spell->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG ||
- spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL)
- return SPELL_MISS_NONE;
- }
-
- // TODO need use this code for spell hit result calculation
- // now code commented for computability
switch (spell->DmgClass)
{
case SPELL_DAMAGE_CLASS_RANGED:
case SPELL_DAMAGE_CLASS_MELEE:
-// return MeleeSpellHitResult(pVictim, spell);
- return SPELL_MISS_NONE;
+ return MeleeSpellHitResult(pVictim, spell);
case SPELL_DAMAGE_CLASS_NONE:
return SPELL_MISS_NONE;
case SPELL_DAMAGE_CLASS_MAGIC:
@@ -3486,7 +4025,7 @@ int32 Unit::GetTotalAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- modifier += (*i)->GetModifier()->m_amount;
+ modifier += (*i)->GetModifierValue();
return modifier;
}
@@ -3497,7 +4036,7 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- multiplier *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
return multiplier;
}
@@ -3508,8 +4047,11 @@ int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- if ((*i)->GetModifier()->m_amount > modifier)
- modifier = (*i)->GetModifier()->m_amount;
+ {
+ int32 amount = (*i)->GetModifierValue();
+ if (amount > modifier)
+ modifier = amount;
+ }
return modifier;
}
@@ -3520,8 +4062,11 @@ int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- if ((*i)->GetModifier()->m_amount < modifier)
- modifier = (*i)->GetModifier()->m_amount;
+ {
+ int32 amount = (*i)->GetModifierValue();
+ if (amount < modifier)
+ modifier = amount;
+ }
return modifier;
}
@@ -3535,7 +4080,7 @@ int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask)
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue & misc_mask)
- modifier += mod->m_amount;
+ modifier += (*i)->GetModifierValue();
}
return modifier;
}
@@ -3549,7 +4094,7 @@ float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue & misc_mask)
- multiplier *= (100.0f + mod->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
}
return multiplier;
}
@@ -3562,8 +4107,9 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue & misc_mask && amount > modifier)
+ modifier = amount;
}
return modifier;
@@ -3577,8 +4123,9 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue & misc_mask && amount < modifier)
+ modifier = amount;
}
return modifier;
@@ -3593,7 +4140,7 @@ int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value)
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue == misc_value)
- modifier += mod->m_amount;
+ modifier += (*i)->GetModifierValue();
}
return modifier;
}
@@ -3607,7 +4154,7 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue == misc_value)
- multiplier *= (100.0f + mod->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
}
return multiplier;
}
@@ -3620,8 +4167,9 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value && mod->m_amount > modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue == misc_value && amount > modifier)
+ modifier = amount;
}
return modifier;
@@ -3635,8 +4183,9 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value && mod->m_amount < modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue == misc_value && amount < modifier)
+ modifier = amount;
}
return modifier;
@@ -3675,8 +4224,10 @@ bool Unit::AddAura(Aura *Aur)
// replace aura if next will > spell StackAmount
if(aurSpellInfo->StackAmount)
{
- if(m_Auras.count(spair) >= aurSpellInfo->StackAmount)
- RemoveAura(i,AURA_REMOVE_BY_STACK);
+ Aur->SetStackAmount(i->second->GetStackAmount());
+ if(Aur->GetStackAmount() < aurSpellInfo->StackAmount)
+ Aur->SetStackAmount(Aur->GetStackAmount()+1);
+ RemoveAura(i,AURA_REMOVE_BY_STACK);
}
// if StackAmount==0 not allow auras from same caster
else
@@ -3895,32 +4446,18 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
if(!is_triggered_by_spell)
{
- SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
-
- bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec);
-
- if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() )
+ bool sameCaster = Aur->GetCasterGUID() == (*i).second->GetCasterGUID();
+ if( spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId, sameCaster) )
{
- // cannot remove higher rank
- if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
- if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
- return false;
-
- // Its a parent aura (create this aura in ApplyModifier)
- if ((*i).second->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
- RemoveAurasDueToSpell(i_spellId);
+ //some spells should be not removed by lower rank of them
+ // what is this spell?
+ if (!sameCaster
+ &&(spellProto->Effect[effIndex]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
+ &&(spellProto->DurationIndex==21)
+ &&(spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
+ &&(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0))
+ return false;
- if( m_Auras.empty() )
- break;
- else
- next = m_Auras.begin();
- }
- else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) )
- {
// Its a parent aura (create this aura in ApplyModifier)
if ((*i).second->IsInUse())
{
@@ -3934,24 +4471,6 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
else
next = m_Auras.begin();
}
- // Potions stack aura by aura (elixirs/flask already checked)
- else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION )
- {
- if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
- {
- if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
- return false; // cannot remove higher rank
-
- // Its a parent aura (create this aura in ApplyModifier)
- if ((*i).second->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
- RemoveAura(i);
- next = i;
- }
- }
}
}
return true;
@@ -4064,11 +4583,48 @@ void Unit::RemoveAurasWithDispelType( DispelType type )
}
}
+void Unit::RemoveSingleAuraFromStackByDispel(uint32 spellId)
+{
+ for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
+ {
+ Aura *aur = iter->second;
+ if (aur->GetId() == spellId)
+ {
+ if(iter->second->GetStackAmount() > 1)
+ {
+ // reapply modifier with reduced stack amount
+ iter->second->ApplyModifier(false,true);
+ iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
+ iter->second->ApplyModifier(true,true);
+
+ iter->second->UpdateSlotCounterAndDuration();
+ return; // not remove aura if stack amount > 1
+ }
+ else
+ RemoveAura(iter,AURA_REMOVE_BY_DISPEL);
+ }
+ else
+ ++iter;
+ }
+}
+
void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
{
AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
if(iter != m_Auras.end())
+ {
+ if(iter->second->GetStackAmount() > 1)
+ {
+ // reapply modifier with reduced stack amount
+ iter->second->ApplyModifier(false,true);
+ iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
+ iter->second->ApplyModifier(true,true);
+
+ iter->second->UpdateSlotCounterAndDuration();
+ return; // not remove aura if stack amount > 1
+ }
RemoveAura(iter);
+ }
}
void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
@@ -4193,7 +4749,11 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
}
sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode);
+ assert(!Aur->IsInUse());
Aur->ApplyModifier(false,true);
+
+ Aur->SetStackAmount(0);
+
Aur->_RemoveAura();
delete Aur;
@@ -4423,6 +4983,24 @@ void Unit::RemoveAllGameObjects()
}
}
+void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
+{
+ WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+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
+ data << uint8 (log->schoolMask); //damage school
+ data << uint32(log->absorb); //AbsorbedDamage
+ data << uint32(log->resist); //resist
+ data << uint8 (log->phusicalLog); // damsge type? flag
+ 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)
{
sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
@@ -4442,6 +5020,17 @@ void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage,
SendMessageToSet( &data, true );
}
+void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell)
+{
+ // Not much to do if no flags are set.
+ if (procAttacker)
+ ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, amount);
+ // 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(pVictim && pVictim->isAlive() && procVictim)
+ pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra, attType, procSpell, amount);
+}
+
void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
{
WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
@@ -4456,6 +5045,29 @@ void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
SendMessageToSet(&data, true);
}
+void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
+{
+ WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+84)); // we guess size
+ data << (uint32)damageInfo->HitInfo;
+ data.append(GetPackGUID());
+ data.append(damageInfo->target->GetPackGUID());
+ data << (uint32)(damageInfo->damage); // Full damage
+
+ data << (uint8)1; // Sub damage count
+ //=== Sub damage description
+ data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage
+ data << (float)damageInfo->damage; // sub damage
+ data << (uint32)damageInfo->damage; // Sub Damage
+ data << (uint32)damageInfo->absorb; // Absorb
+ data << (uint32)damageInfo->resist; // Resist
+ //=================================================
+ data << (uint32)damageInfo->TargetState;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)damageInfo->blocked_amount;
+ SendMessageToSet( &data, true );/**/
+}
+
void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
{
sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
@@ -4489,7 +5101,7 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType,
SendMessageToSet( &data, true );
}
-
+/*
void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
{
sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
@@ -4623,9 +5235,9 @@ void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchool
if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType);
-}
+}*/
-bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown)
+bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
{
SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
@@ -4688,7 +5300,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown)
+bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
uint32 effIndex = triggeredByAura->GetEffIndex ();
@@ -4801,19 +5413,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if(!procSpell)
return false;
- // not from DoT
- bool found = false;
- for(int j = 0; j < 3; ++j)
- {
- if(procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE||procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
- {
- found = true;
- break;
- }
- }
- if(found)
- return false;
-
switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
{
case SPELL_SCHOOL_NORMAL:
@@ -5079,6 +5678,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 29077;
break;
}
+ // Incanter's Regalia set (add trigger chance to Mana Shield)
+ if (dummySpell->SpellFamilyFlags & 0x0000000000008000LL)
+ {
+ if(GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ target = this;
+ triggered_spell_id = 37436;
+ break;
+ }
switch(dummySpell->Id)
{
// Ignite
@@ -5107,14 +5716,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 11129:
{
//last charge and crit
- if( triggeredByAura->m_procCharges <= 1 && (procFlag & PROC_FLAG_CRIT_SPELL) )
+ if (triggeredByAura->m_procCharges <= 1 && (procEx & PROC_EX_CRITICAL_HIT) )
{
RemoveAurasDueToSpell(28682); //-> remove Combustion auras
return true; // charge counting (will removed)
}
CastSpell(this, 28682, true, castItem, triggeredByAura);
- return(procFlag & PROC_FLAG_CRIT_SPELL);// charge update only at crit hits, no hidden cooldowns
+ return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns
}
}
break;
@@ -5131,6 +5740,34 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 22858;
break;
}
+ else if (dummySpell->SpellIconID == 1697) // Second Wind
+ {
+ // 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 == pVictim)
+ return false;
+ // Need stun or root mechanic
+ if (procSpell->Mechanic != MECHANIC_ROOT && procSpell->Mechanic != MECHANIC_STUN)
+ {
+ int32 i;
+ for (i=0; i<3; i++)
+ if (procSpell->EffectMechanic[i] == MECHANIC_ROOT || procSpell->EffectMechanic[i] == MECHANIC_STUN)
+ break;
+ if (i == 3)
+ return false;
+ }
+
+ switch (dummySpell->Id)
+ {
+ case 29838: triggered_spell_id=29842; break;
+ case 29834: triggered_spell_id=29841; break;
+ default:
+ sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id);
+ return false;
+ }
+
+ target = this;
+ break;
+ }
break;
}
case SPELLFAMILY_WARLOCK:
@@ -5140,7 +5777,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
Modifier* mod = triggeredByAura->GetModifier();
// if damage is more than need or target die from damage deal finish spell
- // FIX ME: not triggered currently at death
if( mod->m_amount <= damage || GetHealth() <= damage )
{
// remember guid before aura delete
@@ -5484,16 +6120,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
switch(triggeredByAura->GetEffIndex())
{
case 0:
- // prevent chain triggering
- if(procSpell && procSpell->Id==31893 )
- return false;
-
triggered_spell_id = 31893;
break;
case 1:
{
// damage
- basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
+ damage += CalculateDamage(BASE_ATTACK, false) * 35 / 100; // add spell damage from prev effect (35%)
+ basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
+
target = this;
triggered_spell_id = 32221;
break;
@@ -5841,7 +6475,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-
+/*
bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown)
{
SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
@@ -6178,14 +6812,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3));
// counting
- uint32 count = 0;
- AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
- if((*itr)->GetId()==37658)
- ++count;
+ Aura * dummy = GetDummyAura(37658);
+ if (!dummy)
+ return false;
// release at 3 aura in stack
- if(count <= 2)
+ if(dummy->GetStackAmount() <= 2)
return true; // main triggered spell casted anyway
RemoveAurasDueToSpell(37658);
@@ -6507,6 +7139,650 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return true;
}
+*/
+
+bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* 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->GetModifier()->m_amount;
+
+ // Set trigger spell id, target, custom basepoints
+ uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
+ Unit* target = NULL;
+ int32 basepoints0 = 0;
+
+ Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+
+ // Try handle uncnown trigger spells
+ if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
+ switch (auraSpellInfo->SpellFamilyName)
+ {
+ //=====================================================================
+ // Generic class
+ // ====================================================================
+ // .....
+ //=====================================================================
+ case SPELLFAMILY_GENERIC:
+// if (auraSpellInfo->Id==34082) // Advantaged State (DND)
+// trigger_spell_id = ???;
+ if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket)
+ trigger_spell_id = 23781;
+// else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==37030) // Chaotic Temperament
+// trigger_spell_id = ;
+ else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
+ {
+ // Pct value stored in dummy
+ basepoints0 = pVictim->GetCreateHealth() * auraSpellInfo->EffectBasePoints[1] / 100;
+ target = pVictim;
+ break;
+ }
+// else if (auraSpellInfo->Id==41248) // Consuming Strikes
+// trigger_spell_id = 41249;
+// else if (auraSpellInfo->Id==41054) // Copy Weapon
+// trigger_spell_id = 41055;
+// else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==5301) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==13358) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==16092) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40329) // Demo Shout Sensor
+// trigger_spell_id = ;
+ // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
+ else if (auraSpellInfo->Id == 33896)
+ trigger_spell_id = 33898;
+// else if (auraSpellInfo->Id==18943) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19194) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19817) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19818) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==22835) // Drunken Rage
+// trigger_spell_id = 14822;
+ /*
+ else if (auraSpellInfo->SpellIconID==191) // Elemental Response
+ {
+ switch (auraSpellInfo->Id && auraSpellInfo->AttributesEx==0)
+ {
+ case 34191:
+ case 34329:
+ case 34524:
+ case 34582:
+ case 36733:break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",auraSpellInfo->Id);
+ return false;
+ }
+ //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
+ switch (procSpell->School)
+ {
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192;break;//Fire: 34192
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 34193;break;//Frost: 34193
+ case SPELL_SCHOOL_ARCANE: trigger_spell_id = 34194;break;//Arcane: 34194
+ case SPELL_SCHOOL_NATURE: trigger_spell_id = 34195;break;//Nature: 34195
+ case SPELL_SCHOOL_SHADOW: trigger_spell_id = 34196;break;//Shadow: 34196
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197;break;//Holy: 34197
+ case SPELL_SCHOOL_NORMAL: trigger_spell_id = 34198;break;//Physical: 34198
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id);
+ return false;
+ }
+ }*/
+// else if (auraSpellInfo->Id==6542) // Enraged Defense
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==35321) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==38363) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==39215) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40250) // Improved Duration
+// trigger_spell_id = ;
+ else if (auraSpellInfo->Id==27522) // Mana Drain Trigger
+ {
+ // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
+ if (this && this->isAlive())
+ CastSpell(this, 29471, true, castItem, triggeredByAura);
+ if (pVictim && pVictim->isAlive())
+ CastSpell(pVictim, 27526, true, castItem, triggeredByAura);
+ return true;
+ }
+ else if (auraSpellInfo->Id==24905) // Moonkin Form (Passive)
+ {
+ // Elune's Touch (instead non-existed triggered spell) 30% from AP
+ trigger_spell_id = 33926;
+ basepoints0 = GetTotalAttackPowerValue(BASE_ATTACK) * 30 / 100;
+ target = this;
+ }
+// else if (auraSpellInfo->Id==43453) // Rune Ward
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==7137) // Shadow Charge (Rank 1)
+// trigger_spell_id = ;
+ // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger
+// else if (auraSpellInfo->Id==36576)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==34783) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36096) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36207) // Steal Weapon
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==35205) // Vanish
+ break;
+ //=====================================================================
+ // Mage
+ //=====================================================================
+ // Blazing Speed (Rank 1,2) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_MAGE:
+ // Blazing Speed
+ if (auraSpellInfo->SpellIconID == 2127)
+ {
+ 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;
+ //=====================================================================
+ // Warrior
+ //=====================================================================
+ // Rampage (Rank 1-3) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_WARRIOR:
+ // Rampage
+ if (auraSpellInfo->SpellIconID == 2006 && auraSpellInfo->SpellFamilyFlags==0x100000)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 29801: trigger_spell_id = 30029; break; // Rank 1
+ case 30030: trigger_spell_id = 30031; break; // Rank 2
+ case 30033: trigger_spell_id = 30032; break; // Rank 3
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in Rampage",auraSpellInfo->Id);
+ return false;
+ }
+ }
+ break;
+ //=====================================================================
+ // Warlock
+ //=====================================================================
+ // Pyroclasm trigger = 18350
+ // Drain Soul (Rank 1-5) trigger = 0
+ //=====================================================================
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Pyroclasm
+ if (auraSpellInfo->SpellIconID == 1137)
+ {
+ if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
+ return false;
+ // Calculate spell tick count for spells
+ uint32 tick = 1; // Default tick = 1
+
+ // Hellfire have 15 tick
+ if (procSpell->SpellFamilyFlags&0x0000000000000040LL)
+ tick = 15;
+ // Rain of Fire have 4 tick
+ else if (procSpell->SpellFamilyFlags&0x0000000000000020LL)
+ tick = 4;
+ else
+ return false;
+
+ // Calculate chance = baseChance / tick
+ float chance = 0;
+ switch (auraSpellInfo->Id)
+ {
+ case 18096: chance = 13.0f / tick; break;
+ case 18073: chance = 26.0f / tick; break;
+ }
+ // Roll chance
+ if (!roll_chance_f(chance))
+ return false;
+
+ trigger_spell_id = 18093;
+ }
+ // Drain Soul
+ else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000004000LL)
+ {
+ Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
+ for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
+ {
+ if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
+ {
+ int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
+ basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100;
+ }
+ }
+ if ( basepoints0 == 0 )
+ return false;
+ trigger_spell_id = 18371;
+ }
+ break;
+ }
+ //=====================================================================
+ // Priest
+ //=====================================================================
+ // Greater Heal Refund trigger = 18350
+ // Blessed Recovery (Rank 1-3) trigger = 18350
+ // Shadowguard (1-7) trigger = 28376
+ //=====================================================================
+ case SPELLFAMILY_PRIEST:
+ {
+ // Greater Heal Refund
+ if (auraSpellInfo->Id==37594)
+ trigger_spell_id = 37595;
+ // Shadowguard
+ else if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL && auraSpellInfo->SpellVisual==7958)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 18137: trigger_spell_id = 28377; break; // Rank 1
+ case 19308: trigger_spell_id = 28378; break; // Rank 2
+ case 19309: trigger_spell_id = 28379; break; // Rank 3
+ case 19310: trigger_spell_id = 28380; break; // Rank 4
+ case 19311: trigger_spell_id = 28381; break; // Rank 5
+ case 19312: trigger_spell_id = 28382; break; // Rank 6
+ case 25477: trigger_spell_id = 28385; break; // Rank 7
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG", auraSpellInfo->Id);
+ return false;
+ }
+ }
+ // 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 = damage * triggerAmount / 100 / 3;
+ target = this;
+ }
+ break;
+ }
+ //=====================================================================
+ // Druid
+ // ====================================================================
+ // Druid Forms Trinket trigger = 18350
+ // Entangling Roots trigger = 30023
+ // Leader of the Pack trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_DRUID:
+ {
+ // Druid Forms Trinket
+ if (auraSpellInfo->Id==37336)
+ {
+ switch(m_form)
+ {
+ case 0: 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;
+ }
+ }
+// else if (auraSpellInfo->Id==40363)// Entangling Roots ()
+// trigger_spell_id = ????;
+ // Leader of the Pack
+ else if (auraSpellInfo->Id == 24932)
+ {
+ if (triggerAmount == 0)
+ return false;
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ trigger_spell_id = 34299;
+ }
+ break;
+ }
+ //=====================================================================
+ // Hunter
+ // ====================================================================
+ // ......
+ //=====================================================================
+ case SPELLFAMILY_HUNTER:
+ break;
+ //=====================================================================
+ // Paladin
+ // ====================================================================
+ // Blessed Life trigger = 31934
+ // Healing Discount trigger = 18350
+ // Illumination (Rank 1-5) trigger = 18350
+ // Judgement of Light (Rank 1-5) trigger = 5373
+ // Judgement of Wisdom (Rank 1-4) trigger = 1826
+ // Lightning Capacitor trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_PALADIN:
+ {
+ /* // Blessed Life
+ if (auraSpellInfo->SpellIconID == 2137)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 31828: // Rank 1
+ case 31829: // Rank 2
+ case 31830: // Rank 3
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life", auraSpellInfo->Id);
+ return false;
+ }
+ }*/
+ // Healing Discount
+ if (auraSpellInfo->Id==37705)
+ {
+ trigger_spell_id = 37706;
+ target = this;
+ }
+ // Judgement of Light and Judgement of Wisdom
+ else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000080000LL)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ // Judgement of Light
+ case 20185: trigger_spell_id = 20267;break; // Rank 1
+ case 20344: trigger_spell_id = 20341;break; // Rank 2
+ case 20345: trigger_spell_id = 20342;break; // Rank 3
+ case 20346: trigger_spell_id = 20343;break; // Rank 4
+ case 27162: trigger_spell_id = 27163;break; // Rank 5
+ // Judgement of Wisdom
+ case 20186: trigger_spell_id = 20268;break; // Rank 1
+ case 20354: trigger_spell_id = 20352;break; // Rank 2
+ case 20355: trigger_spell_id = 20353;break; // Rank 3
+ case 27164: trigger_spell_id = 27165;break; // Rank 4
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Light/Wisdom", auraSpellInfo->Id);
+ return false;
+ }
+ pVictim->CastSpell(pVictim, trigger_spell_id, true, castItem, triggeredByAura);
+ return true; // no hidden cooldown
+ }
+ // Illumination
+ else 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
+ if(procSpell->SpellFamilyFlags & 0x00200000)
+ {
+ 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;
+ 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
+ basepoints0 = originalSpell->manaCost*(auraSpellInfo->EffectBasePoints[1]+1)/100;
+ trigger_spell_id = 20272;
+ target = this;
+ }
+ // Lightning Capacitor
+ else if (auraSpellInfo->Id==37657)
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ // stacking
+ CastSpell(this, 37658, true, NULL, triggeredByAura);
+ // counting
+ Aura * dummy = GetDummyAura(37658);
+ if (!dummy)
+ return false;
+ // release at 3 aura in stack (cont contain in basepoint of trigger aura)
+ if(dummy->GetStackAmount() <= 2)
+ return false;
+
+ RemoveAurasDueToSpell(37658);
+ trigger_spell_id = 37661;
+ target = pVictim;
+ }
+ break;
+ }
+ //=====================================================================
+ // Shaman
+ //====================================================================
+ // Lightning Shield trigger = 18350
+ // Mana Surge trigger = 18350
+ // Nature's Guardian (Rank 1-5) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_SHAMAN:
+ {
+ //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
+ if(auraSpellInfo->SpellFamilyFlags==0x00000400 && auraSpellInfo->SpellVisual==37)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 324: trigger_spell_id = 26364; break; // Rank 1
+ case 325: trigger_spell_id = 26365; break; // Rank 2
+ case 905: trigger_spell_id = 26366; break; // Rank 3
+ case 945: trigger_spell_id = 26367; break; // Rank 4
+ case 8134: trigger_spell_id = 26369; break; // Rank 5
+ case 10431: trigger_spell_id = 26370; break; // Rank 6
+ case 10432: trigger_spell_id = 26363; break; // Rank 7
+ case 25469: trigger_spell_id = 26371; break; // Rank 8
+ case 25472: trigger_spell_id = 26372; break; // Rank 9
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id);
+ return false;
+ }
+ }
+ // Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23551)
+ {
+ trigger_spell_id = 23552;
+ target = pVictim;
+ }
+ // Damage from Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23552)
+ trigger_spell_id = 27635;
+ // Mana Surge (The Earthfury set)
+ else if (auraSpellInfo->Id == 23572)
+ {
+ if(!procSpell)
+ return false;
+ basepoints0 = procSpell->manaCost * 35 / 100;
+ trigger_spell_id = 23571;
+ target = this;
+ }
+ else if (auraSpellInfo->SpellIconID == 2013) //Nature's Guardian
+ {
+ // Check health condition - should drop to less 30% (damage deal after this!)
+ if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth()))
+ return false;
+
+ if(pVictim && pVictim->isAlive())
+ pVictim->getThreatManager().modifyThreatPercent(this,-10);
+
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ trigger_spell_id = 31616;
+ target = this;
+ }
+ break;
+ }
+ // default
+ 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;
+
+ // Costum requirements (not listed in procEx) Warning! damage dealing after this
+ // Custom triggered spells
+ switch (auraSpellInfo->Id)
+ {
+ // Persistent Shield (Scarab Brooch trinket)
+ // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
+ case 26467:
+ {
+ basepoints0 = damage * 15 / 100;
+ target = pVictim;
+ trigger_spell_id = 26470;
+ break;
+ }
+ // Cheat Death
+ case 28845:
+ {
+ // When your health drops below 20% ....
+ if (GetHealth() - damage > GetMaxHealth() / 5 || GetHealth() < GetMaxHealth() / 5)
+ return false;
+ break;
+ }
+ // Deadly Swiftness (Rank 1)
+ case 31255:
+ {
+ // whenever you deal damage to a target who is below 20% health.
+ if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5)
+ return false;
+
+ target = this;
+ trigger_spell_id = 22588;
+ }
+ // Greater Heal Refund (Avatar Raiment set)
+ case 37594:
+ {
+ // Not give if target alredy have full health
+ if (pVictim->GetHealth() == pVictim->GetMaxHealth())
+ return false;
+ // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
+ if (pVictim->GetHealth() + damage < pVictim->GetMaxHealth())
+ return false;
+ break;
+ }
+ // Bonus Healing (Crystal Spire of Karabor mace)
+ case 40971:
+ {
+ // If your target is below $s1% health
+ if (pVictim->GetHealth() > pVictim->GetMaxHealth() * triggerAmount / 100)
+ return false;
+ break;
+ }
+ // Evasive Maneuvers (Commendation of Kael`thas trinket)
+ case 45057:
+ {
+ // reduce you below $s1% health
+ if (GetHealth() - damage > GetMaxHealth() * triggerAmount / 100)
+ return false;
+ break;
+ }
+ }
+
+ // Costum basepoints/target for exist spell
+ // dummy basepoints or other customs
+ switch(trigger_spell_id)
+ {
+ // Cast positive spell on enemy target
+ case 7099: // Curse of Mending
+ case 39647: // Curse of Mending
+ case 29494: // Temptation
+ case 20233: // Improved Lay on Hands (cast on target)
+ {
+ target = pVictim;
+ break;
+ }
+ // Combo points add triggers (need add combopoint only for main tatget, and after possible combopoints reset)
+ case 15250: // Rogue Setup
+ {
+ if(!pVictim || pVictim != getVictim()) // applied only for main target
+ return false;
+ break; // continue normal case
+ }
+ // Finish movies that add combo
+ case 14189: // Seal Fate (Netherblade set)
+ case 14157: // Ruthlessness
+ {
+ // Need add combopoint AFTER finish movie (or they dropped in finish phase)
+ break;
+ }
+ // Shamanistic Rage triggered spell
+ case 30824:
+ {
+ basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100);
+ trigger_spell_id = 30824;
+ 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;
+ }
+ }
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
+ return false;
+
+ // try detect target manually if not set
+ if ( target == NULL )
+ target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
+
+ // default case
+ if(!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 )
+ ((Player*)this)->AddSpellCooldown(trigger_spell_id,0,time(NULL) + cooldown);
+
+ return true;
+}
bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
{
@@ -6971,7 +8247,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
data << uint32(AI_REACTION_AGGRO); // Aggro sound
((WorldObject*)this)->SendMessageToSet(&data, true);
- ((Creature*)this)->CallAssistence();
+ ((Creature*)this)->CallAssistance();
((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
}
@@ -7005,7 +8281,7 @@ bool Unit::AttackStop()
if( GetTypeId()==TYPEID_UNIT )
{
// reset call assistance
- ((Creature*)this)->SetNoCallAssistence(false);
+ ((Creature*)this)->SetNoCallAssistance(false);
}
SendAttackStop(victim);
@@ -7364,7 +8640,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
{
- DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
}
}
@@ -7372,13 +8648,13 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
// .. taken pct: scripted (increases damage of * against targets *)
AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
@@ -7559,7 +8835,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
// Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292)
{
- DotFactor = 0.17f;
+ DotFactor = 0.85f;
CastingTime = 3500;
}
// Holy shield - 5% of Holy Damage
@@ -7691,7 +8967,7 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ DoneAdvertisedBenefit += (*i)->GetModifierValue();
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -7709,14 +8985,14 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]);
- DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
+ DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
}
}
// ... and attack power
AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
+ DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
}
return DoneAdvertisedBenefit;
@@ -7731,13 +9007,13 @@ int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVic
AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ TakenAdvertisedBenefit += (*i)->GetModifierValue();
// ..taken
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ TakenAdvertisedBenefit += (*i)->GetModifierValue();
return TakenAdvertisedBenefit;
}
@@ -8005,7 +9281,7 @@ uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount,
// Healing done percent
AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
- heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
+ heal *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
// apply spellmod to Done amount
if(Player* modOwner = GetSpellModOwner())
@@ -8046,7 +9322,7 @@ int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ AdvertisedBenefit += (*i)->GetModifierValue();
// Healing bonus of spirit, intellect and strength
if (GetTypeId() == TYPEID_PLAYER)
@@ -8057,14 +9333,14 @@ int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
{
// stat used dependent from misc value (stat index)
Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
- AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
+ AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
}
// ... and attack power
AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
+ AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
}
return AdvertisedBenefit;
}
@@ -8075,44 +9351,23 @@ int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVi
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ AdvertisedBenefit += (*i)->GetModifierValue();
return AdvertisedBenefit;
}
bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges)
{
- // no charges dependent checks
+ //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;
- // charges dependent checks
+ //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)
- {
- if(useCharges)
- {
- AuraList const& auraDamageImmunity = GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY);
- for(AuraList::const_iterator auraItr = auraDamageImmunity.begin(); auraItr != auraDamageImmunity.end(); ++auraItr)
- {
- if((*auraItr)->GetId()==itr->spellId)
- {
- if((*auraItr)->m_procCharges > 0)
- {
- --(*auraItr)->m_procCharges;
- if((*auraItr)->m_procCharges==0)
- RemoveAurasDueToSpell(itr->spellId);
- }
- break;
- }
- }
- }
return true;
- }
- }
return false;
}
@@ -8122,8 +9377,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
if (!spellInfo)
return false;
- // no charges first
-
//FIX ME this hack: don't get feared if stunned
if (spellInfo->Mechanic == MECHANIC_FEAR )
{
@@ -8131,7 +9384,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
return true;
}
- // not have spells with charges currently
SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
if(itr->type == spellInfo->Dispel)
@@ -8139,7 +9391,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && (spellInfo->Id != 42292)) // unaffected by school immunity
{
- // not have spells with charges currently
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) &&
@@ -8147,30 +9398,11 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
return true;
}
- // charges dependent checks
-
SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
{
if(itr->type == spellInfo->Mechanic)
{
- if(useCharges)
- {
- AuraList const& auraMechImmunity = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY);
- for(AuraList::const_iterator auraItr = auraMechImmunity.begin(); auraItr != auraMechImmunity.end(); ++auraItr)
- {
- if((*auraItr)->GetId()==itr->spellId)
- {
- if((*auraItr)->m_procCharges > 0)
- {
- --(*auraItr)->m_procCharges;
- if((*auraItr)->m_procCharges==0)
- RemoveAurasDueToSpell(itr->spellId);
- }
- break;
- }
- }
- }
return true;
}
}
@@ -8228,7 +9460,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneFlatBenefit += (*i)->GetModifier()->m_amount;
+ DoneFlatBenefit += (*i)->GetModifierValue();
// ..done
// SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
@@ -8243,7 +9475,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifier()->m_amount;
+ APbonus += (*i)->GetModifierValue();
}
else
{
@@ -8253,7 +9485,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifier()->m_amount;
+ APbonus += (*i)->GetModifierValue();
}
if (APbonus!=0) // Can be negative
@@ -8278,7 +9510,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenFlatBenefit += (*i)->GetModifier()->m_amount;
+ TakenFlatBenefit += (*i)->GetModifierValue();
if(attType!=RANGED_ATTACK)
TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
@@ -8296,13 +9528,13 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ DoneTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
// .. taken pct: dummy auras
AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
@@ -8360,13 +9592,13 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
{
AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
}
else
{
AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
}
float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
@@ -8523,17 +9755,21 @@ void Unit::CombatStart(Unit* target)
if(!target->IsStandState() && !target->hasUnitState(UNIT_STAT_STUNNED))
target->SetStandState(PLAYER_STATE_NONE);
- if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER && ((Creature*)target)->AI())
+ if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
+ && ((Creature*)target)->isAggressive() && ((Creature*)target)->AI())
+ {
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
((Creature*)target)->AI()->AttackStart(this);
-
- SetInCombatWith(target);
- target->SetInCombatWith(this);
+ }
+ else
+ {
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
+ }
if(Player* attackedPlayer = target->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
-
- if(!isInCombat()) // remove this?
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK);
}
void Unit::SetInCombatState(bool PvP)
@@ -8544,10 +9780,24 @@ void Unit::SetInCombatState(bool PvP)
if(PvP)
m_CombatTimer = 5000;
+
+ if(isInCombat())
+ return;
+
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
+ if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
+
+ if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ {
+ if(Pet *pet = GetPet())
+ {
+ pet->UpdateSpeed(MOVE_RUN, true);
+ pet->UpdateSpeed(MOVE_SWIM, true);
+ pet->UpdateSpeed(MOVE_FLY, true);
+ }
+ }
}
void Unit::ClearInCombat()
@@ -8555,12 +9805,19 @@ void Unit::ClearInCombat()
m_CombatTimer = 0;
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
+ if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
// Player's state will be cleared in Player::UpdateContestedPvP
if(GetTypeId()!=TYPEID_PLAYER)
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
+
+ if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ {
+ if(Pet *pet = GetPet())
+ for(int i = 0; i < MAX_MOVE_TYPE; ++i)
+ pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
+ }
}
//TODO: remove this function
@@ -8569,10 +9826,18 @@ bool Unit::isTargetableForAttack() const
return isAttackableByAOE() && !hasUnitState(UNIT_STAT_DIED);
}
-bool Unit::canAttack(Unit const* target) const
+bool Unit::canAttack(Unit const* target, bool force) const
{
assert(target);
+ if(force)
+ {
+ if(IsFriendlyTo(target))
+ return false;
+ }
+ else if(!IsHostileTo(target))
+ return false;
+
if(!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED))
return false;
@@ -8590,7 +9855,8 @@ bool Unit::isAttackableByAOE() const
if(!isAlive())
return false;
- if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
+ if(HasFlag(UNIT_FIELD_FLAGS,
+ UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NOT_ATTACKABLE_2))
return false;
if(GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
@@ -8951,8 +10217,9 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
data << float(GetSpeed(mtype));
SendMessageToSet( &data, true );
}
- if(Pet* pet = GetPet())
- pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced);
+ if(GetPetGUID() && !isInCombat())
+ if(Pet* pet = GetPet())
+ pet->SetSpeed(mtype, m_speed_rate[mtype], forced);
}
void Unit::SetHover(bool on)
@@ -9130,6 +10397,8 @@ bool Unit::SelectHostilTarget()
{
target = m_ThreatManager.getHostilTarget();
}
+ else
+ target = getVictim();
}
if(target)
@@ -9141,7 +10410,7 @@ bool Unit::SelectHostilTarget()
}
// no target but something prevent go to evade mode
- if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) )
+ if( !isInCombat() /*|| HasAuraType(SPELL_AURA_MOD_TAUNT)*/ )
return false;
// last case when creature don't must go to evade mode:
@@ -9157,6 +10426,25 @@ bool Unit::SelectHostilTarget()
}
}
+ // search nearby enemy before enter evade mode
+ if(Unit *target = ((Creature*)this)->SelectNearestTarget())
+ {
+ ((Creature*)this)->AI()->AttackStart(target);
+ return true;
+ }
+
+ if(m_invisibilityMask)
+ {
+ Unit::AuraList const& iAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
+ for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
+ if((*itr)->IsPermanent())
+ {
+ ((Creature*)this)->AI()->EnterEvadeMode();
+ break;
+ }
+ return false;
+ }
+
// enter in evade mode in other case
((Creature*)this)->AI()->EnterEvadeMode();
@@ -9649,6 +10937,9 @@ void Unit::SetMaxHealth(uint32 val)
void Unit::SetPower(Powers power, uint32 val)
{
+ if(GetPower(power) == val)
+ return;
+
uint32 maxPower = GetMaxPower(power);
if(maxPower < val)
val = maxPower;
@@ -9818,7 +11109,7 @@ CharmInfo* Unit::InitCharmInfo(Unit *charm)
}
CharmInfo::CharmInfo(Unit* unit)
-: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0)
+: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0), m_barInit(false)
{
for(int i =0; i<4; ++i)
{
@@ -9829,6 +11120,9 @@ CharmInfo::CharmInfo(Unit* unit)
void CharmInfo::InitPetActionBar()
{
+ if (m_barInit)
+ return;
+
// the first 3 SpellOrActions are attack, follow and stay
for(uint32 i = 0; i < 3; i++)
{
@@ -9843,17 +11137,25 @@ void CharmInfo::InitPetActionBar()
PetActionBar[i + 3].Type = ACT_DISABLED;
PetActionBar[i + 3].SpellOrAction = 0;
}
+ m_barInit = true;
}
-void CharmInfo::InitEmptyActionBar()
+void CharmInfo::InitEmptyActionBar(bool withAttack)
{
- for(uint32 x = 1; x < 10; ++x)
+ if (m_barInit)
+ return;
+
+ for(uint32 x = 0; x < 10; ++x)
{
PetActionBar[x].Type = ACT_CAST;
PetActionBar[x].SpellOrAction = 0;
}
- PetActionBar[0].Type = ACT_COMMAND;
- PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
+ if (withAttack)
+ {
+ PetActionBar[0].Type = ACT_COMMAND;
+ PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
+ }
+ m_barInit = true;
}
void CharmInfo::InitPossessCreateSpells()
@@ -9971,6 +11273,7 @@ bool Unit::isFrozen() const
return false;
}
+/*
struct ProcTriggeredData
{
ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
@@ -10144,6 +11447,371 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
}
}
}
+*/
+struct ProcTriggeredData
+{
+ ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura)
+ : spellProcEvent(_spellProcEvent), triggeredByAura(_triggeredByAura),
+ triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex()))
+ {}
+ SpellProcEventEntry const *spellProcEvent;
+ Aura* triggeredByAura;
+ Unit::spellEffectPair triggeredByAura_SpellPair;
+};
+
+typedef std::list< ProcTriggeredData > ProcTriggeredList;
+typedef std::list< uint32> RemoveSpellList;
+
+// List of auras that CAN be trigger but may not exist in spell_proc_event
+// in most case need for drop charges
+// in some types of aura need do additional check
+// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
+static bool isTriggerAura[TOTAL_AURAS];
+static bool isNonTriggerAura[TOTAL_AURAS];
+void InitTriggerAuraData()
+{
+ for (int i=0;i<TOTAL_AURAS;i++)
+ {
+ isTriggerAura[i]=false;
+ isNonTriggerAura[i] = false;
+ }
+ isTriggerAura[SPELL_AURA_DUMMY] = true;
+ isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
+ isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
+ isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura not have charges but need remove him on trigger
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
+ isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
+ isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
+ isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
+ isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
+ isTriggerAura[SPELL_AURA_MOD_HASTE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE]=true;
+ isTriggerAura[SPELL_AURA_PRAYER_OF_MENDING] = true;
+
+ isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true;
+ isNonTriggerAura[SPELL_AURA_RESIST_PUSHBACK]=true;
+}
+
+uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
+{
+ uint32 procEx = PROC_EX_NONE;
+ // Check victim state
+ if (missCondition!=SPELL_MISS_NONE)
+ switch (missCondition)
+ {
+ case SPELL_MISS_MISS: procEx|=PROC_EX_MISS; break;
+ case SPELL_MISS_RESIST: procEx|=PROC_EX_RESIST; break;
+ case SPELL_MISS_DODGE: procEx|=PROC_EX_DODGE; break;
+ case SPELL_MISS_PARRY: procEx|=PROC_EX_PARRY; break;
+ case SPELL_MISS_BLOCK: procEx|=PROC_EX_BLOCK; break;
+ case SPELL_MISS_EVADE: procEx|=PROC_EX_EVADE; break;
+ case SPELL_MISS_IMMUNE: procEx|=PROC_EX_IMMUNE; break;
+ case SPELL_MISS_IMMUNE2: procEx|=PROC_EX_IMMUNE; break;
+ case SPELL_MISS_DEFLECT: procEx|=PROC_EX_DEFLECT;break;
+ case SPELL_MISS_ABSORB: procEx|=PROC_EX_ABSORB; break;
+ case SPELL_MISS_REFLECT: procEx|=PROC_EX_REFLECT;break;
+ default:
+ break;
+ }
+ else
+ {
+ // On block
+ if (damageInfo->blocked)
+ procEx|=PROC_EX_BLOCK;
+ // On absorb
+ if (damageInfo->absorb)
+ procEx|=PROC_EX_ABSORB;
+ // On crit
+ if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
+ procEx|=PROC_EX_CRITICAL_HIT;
+ else
+ procEx|=PROC_EX_NORMAL_HIT;
+ }
+ return procEx;
+}
+
+static int deep = 0;
+void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
+{
+ deep ++;
+ if (deep > 5)
+ {
+ sLog.outError("Prevent possible stack owerflow in Unit::ProcDamageAndSpellFor");
+ if (procSpell)
+ sLog.outError(" Spell %u", procSpell->Id);
+ deep--;
+ return;
+ }
+ // For melee/ranged based attack need update skills and set some Aura states
+ if (procFlag & MELEE_BASED_TRIGGER_MASK)
+ {
+ // Update skills here for players
+ if (GetTypeId() == TYPEID_PLAYER)
+ {
+ // On melee based hit/miss/resist need update skill (for victim and attacker)
+ if (procExtra&(PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST))
+ {
+ if (pTarget->GetTypeId() != TYPEID_PLAYER && pTarget->GetCreatureType() != CREATURE_TYPE_CRITTER)
+ ((Player*)this)->UpdateCombatSkills(pTarget, attType, MELEE_HIT_MISS, isVictim);
+ }
+ // Update defence if player is victim and parry/dodge/block
+ if (isVictim && procExtra&(PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK))
+ ((Player*)this)->UpdateDefense();
+ }
+ // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
+ if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK))
+ {
+ // for victim
+ if (isVictim)
+ {
+ // if victim and dodge attack
+ if (procExtra&PROC_EX_DODGE)
+ {
+ //Update AURA_STATE on dodge
+ if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE, true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ // if victim and parry attack
+ if (procExtra & PROC_EX_PARRY)
+ {
+ // For Hunters only Counterattack (skip Mongoose bite)
+ if (getClass() == CLASS_HUNTER)
+ {
+ ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
+ StartReactiveTimer( REACTIVE_HUNTER_PARRY );
+ }
+ else
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE, true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ // if and victim block attack
+ if (procExtra & PROC_EX_BLOCK)
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE,true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ else //For attacker
+ {
+ // Overpower on victim dodge
+ if (procExtra&PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
+ {
+ ((Player*)this)->AddComboPoints(pTarget, 1);
+ StartReactiveTimer( REACTIVE_OVERPOWER );
+ }
+ // Enable AURA_STATE_CRIT on crit
+ if (procExtra & PROC_EX_CRITICAL_HIT)
+ {
+ ModifyAuraState(AURA_STATE_CRIT, true);
+ StartReactiveTimer( REACTIVE_CRIT );
+ if(getClass()==CLASS_HUNTER)
+ {
+ ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
+ StartReactiveTimer( REACTIVE_HUNTER_CRIT );
+ }
+ }
+ }
+ }
+ }
+
+ RemoveSpellList removedSpells;
+ ProcTriggeredList procTriggered;
+ // Fill procTriggered list
+ for(AuraMap::const_iterator itr = GetAuras().begin(); itr!= GetAuras().end(); ++itr)
+ {
+ SpellProcEventEntry const* spellProcEvent = NULL;
+ if(!IsTriggeredAtSpellProcEvent(itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent))
+ continue;
+
+ procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) );
+ }
+ // Handle effects proceed this time
+ for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
+ {
+ // Some auras can be deleted in function called in this loop (except first, ofc)
+ // Until storing auars in std::multimap to hard check deleting by another way
+ if(i != procTriggered.begin())
+ {
+ bool found = false;
+ AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
+ AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
+ for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
+ {
+ if(itr->second==i->triggeredByAura)
+ {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+// sLog.outDebug("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler", i->triggeredByAura->GetModifier()->m_auraname, i->triggeredByAura_SpellPair.first, i->triggeredByAura_SpellPair.second);
+// sLog.outDebug("It can be deleted one from early proccesed auras:");
+// for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
+// sLog.outDebug(" Spell aura %u (id:%u effect:%u)", i->triggeredByAura->GetModifier()->m_auraname,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
+// sLog.outDebug(" <end of list>");
+ continue;
+ }
+ }
+
+ SpellProcEventEntry const *spellProcEvent = i->spellProcEvent;
+ Aura *triggeredByAura = i->triggeredByAura;
+ Modifier *auraModifier = triggeredByAura->GetModifier();
+ SpellEntry const *spellInfo = triggeredByAura->GetSpellProto();
+ uint32 effIndex = triggeredByAura->GetEffIndex();
+ bool useCharges = triggeredByAura->m_procCharges > 0;
+ // For players set spell cooldown if need
+ uint32 cooldown = 0;
+ if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
+ cooldown = spellProcEvent->cooldown;
+
+ switch(auraModifier->m_auraname)
+ {
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ // Don`t drop charge or add cooldown for not started trigger
+ if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ {
+ sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
+ CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);
+ SendSpellNonMeleeDamageLog(&damageInfo);
+ DealSpellDamage(&damageInfo, true);
+ break;
+ }
+ case SPELL_AURA_MANA_SHIELD:
+ case SPELL_AURA_DUMMY:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_MOD_HASTE:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_PRAYER_OF_MENDING:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
+ (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
+
+ HandleMeandingAuraProc(triggeredByAura);
+ break;
+ }
+ case SPELL_AURA_MOD_STUN:
+ // Remove by default, but if charge exist drop it
+ if (triggeredByAura->m_procCharges == 0)
+ removedSpells.push_back(triggeredByAura->GetId());
+ break;
+ case SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS:
+ case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
+ // Hunter's Mark (1-4 Rangs)
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (spellInfo->SpellFamilyFlags&0x0000000000000400LL))
+ {
+ uint32 basevalue = triggeredByAura->GetBasePoints();
+ auraModifier->m_amount += basevalue/10;
+ if (auraModifier->m_amount > basevalue*4)
+ auraModifier->m_amount = basevalue*4;
+ }
+ break;
+ case SPELL_AURA_MOD_CASTING_SPEED:
+ // Skip melee hits or instant cast spells
+ if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
+ continue;
+ break;
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ // Skip Melee hits and spells ws wrong school
+ if (procSpell == NULL || (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0)
+ continue;
+ break;
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL:
+ // Skip melee hits and spells ws wrong school or zero cost
+ if (procSpell == NULL ||
+ (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
+ (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) // School check
+ continue;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
+ continue;
+ break;
+ case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
+ continue;
+ break;
+ default:
+ // nothing do, just charges counter
+ break;
+ }
+ // Remove charge (aura can be removed by triggers)
+ if(useCharges)
+ {
+ // need found aura on drop (can be dropped by triggers)
+ AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
+ AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
+ for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
+ {
+ if(itr->second == i->triggeredByAura)
+ {
+ triggeredByAura->m_procCharges -=1;
+ triggeredByAura->UpdateAuraCharges();
+ if (triggeredByAura->m_procCharges <= 0)
+ removedSpells.push_back(triggeredByAura->GetId());
+ break;
+ }
+ }
+ }
+ }
+ if (removedSpells.size())
+ {
+ // Sort spells and remove dublicates
+ removedSpells.sort();
+ removedSpells.unique();
+ // Remove auras from removedAuras
+ for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++)
+ RemoveAurasDueToSpell(*i);
+ }
+ deep--;
+}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
{
@@ -10455,7 +12123,7 @@ void Unit::UpdateReactives( uint32 p_time )
}
}
-Unit* Unit::SelectNearbyTarget() const
+Unit* Unit::SelectNearbyTarget(float dist) const
{
CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
Cell cell(p);
@@ -10465,7 +12133,7 @@ Unit* Unit::SelectNearbyTarget() const
std::list<Unit *> targets;
{
- Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE);
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
@@ -10695,7 +12363,7 @@ void Unit::SetContestedPvP(Player *attackedPlayer)
player->addUnitState(UNIT_STAT_ATTACK_PLAYER);
player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP);
// call MoveInLineOfSight for nearby contested guards
- SetVisibility(GetVisibility());
+ player->SetVisibility(GetVisibility());
}
if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER))
{
@@ -10750,60 +12418,83 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
return pet;
}
-bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown )
+bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent )
{
- SpellProcEventEntry const * spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
+ SpellEntry const* spellProto = aura->GetSpellProto ();
- if(!spellProcEvent)
- {
- // used to prevent spam in log about same non-handled spells
- static std::set<uint32> nonHandledSpellProcSet;
+ // Get proc Event Entry
+ spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
- if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
- {
- sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
- nonHandledSpellProcSet.insert(spellProto->Id);
- }
+ // Aura info stored here
+ Modifier *mod = aura->GetModifier();
+ // Skip this auras
+ if (isNonTriggerAura[mod->m_auraname])
+ return false;
+ // If not trigger by default and spellProcEvent==NULL - skip
+ if (!isTriggerAura[mod->m_auraname] && spellProcEvent==NULL)
+ return false;
- // spell.dbc use totally different flags, that only can create problems if used.
+ // Get EventProcFlag
+ uint32 EventProcFlag;
+ if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
+ EventProcFlag = spellProcEvent->procFlags;
+ else
+ EventProcFlag = spellProto->procFlags; // else get from spell proto
+ // Continue if no trigger exist
+ if (!EventProcFlag)
return false;
- }
// Check spellProcEvent data requirements
- if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
+ if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
+ return false;
+
+ // Aura added by spell can`t trogger from self (prevent drop cahres/do triggers)
+ // But except periodic triggers (can triggered from self)
+ if(procSpell && procSpell->Id == spellProto->Id && !(spellProto->procFlags&PROC_FLAG_ON_TAKE_PERIODIC))
return false;
// Check if current equipment allows aura to proc
- if(!isVictim && GetTypeId() == TYPEID_PLAYER )
+ if(!isVictim && GetTypeId() == TYPEID_PLAYER)
{
if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
{
- Item *item = ((Player*)this)->GetWeaponForAttack(attType,true);
+ Item *item = NULL;
+ if(attType == BASE_ATTACK)
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ else if (attType == OFF_ATTACK)
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ else
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
- if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
+ if (!((Player*)this)->IsUseEquipedWeapon(attType==BASE_ATTACK))
+ return false;
+
+ if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
- Item *item = ((Player*)this)->GetShield(true);
- if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
+ Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
}
-
+ // Get chance from spell
float chance = (float)spellProto->procChance;
-
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
-
+ // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
+ if(spellProcEvent && spellProcEvent->customChance)
+ chance = spellProcEvent->customChance;
+ // If PPM exist calculate chance from PPM
if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
+ // Apply chance modifer aura
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
- cooldown = spellProcEvent ? spellProcEvent->cooldown : 0;
return roll_chance_f(chance);
}
@@ -10878,3 +12569,11 @@ void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo)
++iter;
}
}
+
+/*-----------------------TRINITY-----------------------------*/
+
+void Unit::SetToNotify()
+{
+ if(Map *map = GetMap())
+ map->AddUnitToNotify(this);
+} \ No newline at end of file