rendered paste bodystatic 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--;}