rendered paste body+static float debugChance = 0.0f;+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)+ {+ SpellEntry const *spellProto = itr->second->GetSpellProto();+ if(spellProto==NULL || spellProto->procFlags==0)+ continue;+ // Aura info stored here+ Modifier *mod = itr->second->GetModifier();+ SpellProcEventEntry const *spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);++ // If not trigger by default and spellProcEvent==NULL - skip+ if (!isTriggerAura[mod->m_auraname] && spellProcEvent==NULL)+ continue;++ // Check spellProcEvent data requirements+ if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, spellProto->procFlags, procSpell, procFlag, procExtra, damage > 0))+ continue;+ // 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))+ continue;+ // Check if current equipment allows aura to proc+ if(!isVictim && GetTypeId() == TYPEID_PLAYER)+ {+ if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)+ {+ 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))+ continue;++ if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))+ continue;+ }+ else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)+ {+ // Check if player is wearing shield+ 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))+ continue;+ }+ }+ // Get chance from spell+ float chance = (float)spellProto->procChance;+ // 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);++ if(roll_chance_f(chance+debugChance))+ 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();+ // For players set spell cooldown if need+ uint32 cooldown = 0;+ if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->Cooldown)+ cooldown = spellProcEvent->Cooldown;++ // For players check spell cooldown+ if (cooldown && ((Player *)this)->HasSpellCooldown(spellInfo->Id))+ continue;++ 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))+ continue;+ // For players add colldown if need+ if (cooldown)+ ((Player *)this)->AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown);+ 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->School);+ CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);+ SendSpellNonMeleeDamageLog(&damageInfo);+ DealSpellDamage(&damageInfo, true);+ break;+ }+ case SPELL_AURA_MANA_SHIELD:+ case SPELL_AURA_MOD_HASTE:+ case SPELL_AURA_DUMMY:+ case SPELL_AURA_DUMMY_3:+ {+ 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());+ HandleDummyAuraProc(pTarget, spellInfo, effIndex, damage, triggeredByAura, procSpell, procFlag, procExtra);+ // For players add colldown if need+ if (cooldown)+ ((Player *)this)->AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown);+ 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_RANGED_ATTACK_POWER_ATTACKER_BONUS:+ // Hunter's Mark (1-4 Rangs)+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (spellInfo->SpellFamilyFlags&0x0000000000000400LL))+ {+ uint32 basevalue = triggeredByAura->GetBasePoints()+1;+ 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(sCastTimesStore.LookupEntry(procSpell->CastingTimeIndex)) == 0)+ continue;+ break;+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:+ // Skip Melee hits and spells ws wrong school+ if (procSpell == NULL || (auraModifier->m_miscvalue & (1<<procSpell->School)) == 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 & (1<<procSpell->School)) == 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)+ // Not validate aura on check (for speed)+ if(triggeredByAura->m_procCharges > 0)+ {+ // 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;+ if (triggeredByAura->m_procCharges == 0) + removedSpells.push_back(triggeredByAura->GetId());+ break;+ }+ }+ }+ }+ // Remove auras from removedAuras+ for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++)+ RemoveAurasDueToSpell(*i);+ deep--;+}