diff options
Diffstat (limited to 'src/game/Unit.cpp')
| -rw-r--r-- | src/game/Unit.cpp | 2026 | 
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);  }  | 
