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.cpp2026
1 files changed, 1810 insertions, 216 deletions
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 571ff991147..c40f37ec48f 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());
@@ -675,8 +679,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");
@@ -847,18 +855,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())
@@ -875,8 +871,12 @@ 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
+ //if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
+ }
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
@@ -914,10 +914,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->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)
@@ -1095,6 +1115,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
@@ -1505,6 +1526,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)
{
@@ -1763,6 +2355,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;
@@ -2163,7 +2756,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
}
}
}
-}
+}*/
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
{
@@ -2207,65 +2800,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)
@@ -2279,6 +2826,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
@@ -2337,7 +2885,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
{
@@ -2608,7 +3156,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)
@@ -2732,7 +3291,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)
@@ -2802,6 +3361,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
@@ -2829,62 +3396,24 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
// 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)->GetModifier()->m_amount;
+ 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:
@@ -4386,6 +4915,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");
@@ -4405,6 +4952,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));
@@ -4419,6 +4977,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");
@@ -4452,7 +5033,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);
@@ -4586,9 +5167,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();
@@ -4651,7 +5232,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 ();
@@ -4764,19 +5345,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:
@@ -5042,6 +5610,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
@@ -5070,14 +5648,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;
@@ -5094,6 +5672,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:
@@ -5103,7 +5709,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
@@ -5447,16 +6052,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;
@@ -5804,7 +6407,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();
@@ -6470,6 +7073,652 @@ 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
+ 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;
+ // release at 3 aura in stack (cont contain in basepoint of trigger aura)
+ if(count < triggerAmount)
+ 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)
{
@@ -8044,38 +9293,17 @@ int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVi
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;
}
@@ -8085,8 +9313,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 )
{
@@ -8094,7 +9320,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)
@@ -8102,7 +9327,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)) &&
@@ -8110,30 +9334,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;
}
}
@@ -9990,6 +11195,7 @@ bool Unit::isFrozen() const
return false;
}
+/*
struct ProcTriggeredData
{
ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
@@ -10163,6 +11369,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
{
@@ -10769,60 +12340,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 (!((Player*)this)->IsUseEquipedWeapon(attType==BASE_ATTACK))
+ return false;
- if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
+ 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);
}