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