diff options
Diffstat (limited to 'src/game/Unit.cpp')
-rw-r--r-- | src/game/Unit.cpp | 3624 |
1 files changed, 1043 insertions, 2581 deletions
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 210060982a4..65689a71e84 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -60,92 +60,17 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = 3.141594f, // MOVE_TURN_RATE 7.0f, // MOVE_FLIGHT 4.5f, // MOVE_FLIGHT_BACK + 3.14f // MOVE_PITCH_RATE }; -void InitTriggerAuraData(); - -// auraTypes contains attacker auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - auraTypes.insert(SPELL_AURA_MOD_HASTE); - auraTypes.insert(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - return auraTypes; -} - -// auraTypes contains victim auras capable of proc'ing cast auras -static Unit::AuraTypeSet GenerateVictimProcCastAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_DUMMY); - auraTypes.insert(SPELL_AURA_PRAYER_OF_MENDING); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_SPELL); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for attacker -static Unit::AuraTypeSet GenerateAttakerProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_DONE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_CASTING_SPEED); - auraTypes.insert(SPELL_AURA_MOD_RATING); - return auraTypes; -} - -// auraTypes contains auras capable of proc effect/damage (but not cast) for victim -static Unit::AuraTypeSet GenerateVictimProcEffectAuraTypes() -{ - static Unit::AuraTypeSet auraTypes; - auraTypes.insert(SPELL_AURA_MOD_RESISTANCE); - auraTypes.insert(SPELL_AURA_PROC_TRIGGER_DAMAGE); - auraTypes.insert(SPELL_AURA_MOD_PARRY_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_BLOCK_PERCENT); - auraTypes.insert(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); - return auraTypes; -} - -static Unit::AuraTypeSet attackerProcCastAuraTypes = GenerateAttakerProcCastAuraTypes(); -static Unit::AuraTypeSet attackerProcEffectAuraTypes = GenerateAttakerProcEffectAuraTypes(); - -static Unit::AuraTypeSet victimProcCastAuraTypes = GenerateVictimProcCastAuraTypes(); -static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectAuraTypes(); - -// 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()); - auraTypes.insert(victimProcCastAuraTypes.begin(),victimProcCastAuraTypes.end()); - auraTypes.insert(victimProcEffectAuraTypes.begin(),victimProcEffectAuraTypes.end()); - return auraTypes; -} - -static Unit::AuraTypeSet procAuraTypes = GenerateProcAuraTypes(); - -bool IsPassiveStackableSpell( uint32 spellId ) -{ - if(!IsPassiveSpell(spellId)) - return false; - - SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId); - if(!spellProto) - return false; - - for(int j = 0; j < 3; ++j) - { - if(std::find(procAuraTypes.begin(),procAuraTypes.end(),spellProto->EffectApplyAuraName[j])!=procAuraTypes.end()) - return false; - } - - return true; -} +// Used for prepare can/can`t triggr aura +static bool InitTriggerAuraData(); +// Define can trigger auras +static bool isTriggerAura[TOTAL_AURAS]; +// Define can`t trigger auras (need for disable second trigger) +static bool isNonTriggerAura[TOTAL_AURAS]; +// Prepare lists +static bool procPrepared = InitTriggerAuraData(); Unit::Unit() : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this) @@ -154,7 +79,7 @@ Unit::Unit() m_objectType |= TYPEMASK_UNIT; m_objectTypeId = TYPEID_UNIT; // 2.3.2 - 0x70 - m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HASPOSITION); + m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION); m_attackTimer[BASE_ATTACK] = 0; m_attackTimer[OFF_ATTACK] = 0; @@ -721,6 +646,167 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa { DEBUG_LOG("DealDamage: victim just died"); Kill(pVictim, durabilityLoss); + + /*// find player: owner of controlled `this` or `this` itself maybe + Player *player = GetCharmerOrOwnerPlayerOrPlayerItself(); + + if(pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->GetLootRecipient()) + player = ((Creature*)pVictim)->GetLootRecipient(); + // 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) + { + player->RewardPlayerAndGroupAtKill(pVictim); + player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); + } + + DEBUG_LOG("DealDamageAttackStop"); + + // stop combat + pVictim->CombatStop(); + pVictim->getHostilRefManager().deleteReferences(); + + bool damageFromSpiritOfRedemtionTalent = spellProto && spellProto->Id == 27795; + + // if talent known but not triggered (check priest class for speedup check) + Aura* spiritOfRedemtionTalentReady = NULL; + if( !damageFromSpiritOfRedemtionTalent && // not called from SPELL_AURA_SPIRIT_OF_REDEMPTION + pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST ) + { + AuraList const& vDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + if((*itr)->GetSpellProto()->SpellIconID==1654) + { + spiritOfRedemtionTalentReady = *itr; + break; + } + } + } + + DEBUG_LOG("SET JUST_DIED"); + if(!spiritOfRedemtionTalentReady) + pVictim->setDeathState(JUST_DIED); + + DEBUG_LOG("DealDamageHealth1"); + + if(spiritOfRedemtionTalentReady) + { + // save value before aura remove + uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL); + if(!ressSpellId) + ressSpellId = ((Player*)pVictim)->GetResurrectionSpellId(); + + //Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers) + pVictim->RemoveAllAurasOnDeath(); + + // restore for use at real death + pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL,ressSpellId); + + // FORM_SPIRITOFREDEMPTION and related auras + pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady); + } + else + pVictim->SetHealth(0); + + // remember victim PvP death for corpse type and corpse reclaim delay + // at original death (not at SpiritOfRedemtionTalent timeout) + if( pVictim->GetTypeId()==TYPEID_PLAYER && !damageFromSpiritOfRedemtionTalent ) + ((Player*)pVictim)->SetPvPDeath(player!=NULL); + + // Call KilledUnit for creatures + if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->AI()) + ((Creature*)this)->AI()->KilledUnit(pVictim); + + // achievement stuff + if ( pVictim->GetTypeId() == TYPEID_PLAYER) + { + if(GetTypeId() == TYPEID_UNIT) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); + else if(GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1); + } + + // 10% durability loss on death + // clean InHateListOf + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + // only if not player and not controlled by player pet. And not at BG + if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) + { + DEBUG_LOG("We are dead, loosing 10 percents durability"); + ((Player*)pVictim)->DurabilityLossAll(0.10f,false); + // durability lost message + WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); + ((Player*)pVictim)->GetSession()->SendPacket(&data); + } + } + else // creature died + { + DEBUG_LOG("DealDamageNotPlayer"); + Creature *cVictim = (Creature*)pVictim; + + if(!cVictim->isPet()) + { + cVictim->DeleteThreatList(); + cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + // Call creature just died function + if (cVictim->AI()) + cVictim->AI()->JustDied(this); + + // Dungeon specific stuff, only applies to players killing creatures + if(cVictim->GetInstanceId()) + { + Map *m = cVictim->GetMap(); + Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); + // TODO: do instance binding anyway if the charmer/owner is offline + + if(m->IsDungeon() && creditedPlayer) + { + if(m->IsRaid() || m->IsHeroic()) + { + if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) + ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer); + } + else + { + // the reset time is set but not added to the scheduler + // until the players leave the instance + time_t resettime = cVictim->GetRespawnTimeEx() + 2 * HOUR; + if(InstanceSave *save = sInstanceSaveManager.GetInstanceSave(cVictim->GetInstanceId())) + if(save->GetResetTime() < resettime) save->SetResetTime(resettime); + } + } + } + } + + // last damage from non duel opponent or opponent controlled creature + if(duel_hasEnded) + { + assert(pVictim->GetTypeId()==TYPEID_PLAYER); + Player *he = (Player*)pVictim; + + assert(he->duel); + + he->duel->opponent->CombatStopWithPets(true); + he->CombatStopWithPets(true); + + he->DuelComplete(DUEL_INTERUPTED); + } + + // 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()) + { + Player *killed = ((Player*)pVictim); + if(BattleGround *bg = killed->GetBattleGround()) + if(player) + bg->HandleKillPlayer(killed, player); + //later we can add support for creature->player kills here i'm + //not sure, but i guess those kills also get counted in av + //else if(GetTypeId() == TYPEID_UNIT) + // bg->HandleKillPlayer(killed,(Creature*)this); + }*/ } else // if (health <= damage) { @@ -751,7 +837,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa //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) { if(spellProto && IsDamageToThreatSpell(spellProto)) @@ -1060,419 +1145,6 @@ void Unit::CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castI 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 - DEBUG_LOG("DealFlatDamage (BEFORE) >> DMG:%u", *damage); - - // Per-damage class calculation - switch (spellInfo->DmgClass) - { - // Melee and Ranged Spells - case SPELL_DAMAGE_CLASS_RANGED: - case SPELL_DAMAGE_CLASS_MELEE: - { - // Calculate physical outcome - MeleeHitOutcome outcome = RollPhysicalOutcomeAgainst(pVictim, BASE_ATTACK, spellInfo); - - //Used to store the Hit Outcome - cleanDamage->hitOutCome = outcome; - - // Return miss/evade first (sends miss message) - switch(outcome) - { - case MELEE_HIT_EVADE: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_EVADES,0); - *damage = 0; - return; - } - case MELEE_HIT_MISS: - { - SendAttackStateUpdate(HITINFO_MISS, pVictim, 1, GetSpellSchoolMask(spellInfo), 0, 0,0,VICTIMSTATE_NORMAL,0); - *damage = 0; - - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(BASE_ATTACK); - - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,MELEE_HIT_MISS,spellInfo,isTriggeredSpell); - return; - } - } - - // Hitinfo, Victimstate - uint32 hitInfo = HITINFO_NORMALSWING; - VictimState victimState = VICTIMSTATE_NORMAL; - - // Physical Damage - if ( GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_NORMAL ) - { - // apply spellmod to Done damage - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DAMAGE, *damage); - - //Calculate armor mitigation - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); - - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); - - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; - } - // Magical Damage - else - { - // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); - } - - // Classify outcome - switch (outcome) - { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - { - uint32 bonusDmg = *damage; - - // Apply crit_damage bonus - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, bonusDmg); - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - 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)->GetModifierValue()+100.0f)/100.0f); - - *damage += bonusDmg; - - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - cleanDamage->damage += resilienceReduction; - *damage -= resilienceReduction; - } - - *crit = true; - hitInfo |= HITINFO_CRITICALHIT; - - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); - - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } - - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - } - break; - } - case MELEE_HIT_PARRY: - { - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - victimState = VICTIMSTATE_PARRY; - - // Counter-attack ( explained in Unit::DoAttackDamage() ) - if(pVictim->GetTypeId()==TYPEID_PLAYER || !(((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN) ) - { - // 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)); - } - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } - - // Set parry flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - // Mongoose bite - set only Counterattack here - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_DODGE: - { - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); - - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_DODGE; - - // Set dodge flags - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - // Riposte - if (pVictim->getClass() != CLASS_ROGUE) - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - break; - } - case MELEE_HIT_BLOCK: - { - uint32 blocked_amount = uint32(pVictim->GetShieldBlockValue()); - if (blocked_amount >= *damage) - { - hitInfo |= HITINFO_SWINGNOHITSOUND; - victimState = VICTIMSTATE_BLOCKS; - cleanDamage->damage += *damage; // To Help Calculate Rage - *damage = 0; - } - else - { - // To Help Calculate Rage - cleanDamage->damage += blocked_amount; - *damage = *damage - blocked_amount; - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - break; - } - case MELEE_HIT_EVADE: // already processed early - case MELEE_HIT_MISS: // already processed early - case MELEE_HIT_GLANCING: - case MELEE_HIT_CRUSHING: - case MELEE_HIT_NORMAL: - break; - } - - // do all damage=0 cases here - if(*damage == 0) - CastMeleeProcDamageAndSpell(pVictim,0,GetSpellSchoolMask(spellInfo),BASE_ATTACK,outcome,spellInfo,isTriggeredSpell); - - break; - } - // Magical Attacks - case SPELL_DAMAGE_CLASS_NONE: - case SPELL_DAMAGE_CLASS_MAGIC: - { - // Calculate damage bonus - *damage = SpellDamageBonus(pVictim, spellInfo, *damage, SPELL_DIRECT_DAMAGE); - - *crit = isSpellCrit(pVictim, spellInfo, GetSpellSchoolMask(spellInfo), BASE_ATTACK); - if (*crit) - { - *damage = SpellCriticalBonus(spellInfo, *damage, pVictim); - - // Resilience - reduce crit damage - if (pVictim && pVictim->GetTypeId()==TYPEID_PLAYER) - { - uint32 damage_reduction = ((Player *)pVictim)->GetSpellCritDamageReduction(*damage); - if(*damage > damage_reduction) - *damage -= damage_reduction; - else - *damage = 0; - } - - cleanDamage->hitOutCome = MELEE_HIT_CRIT; - } - // spell proc all magic damage==0 case in this function - if(*damage == 0) - { - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); - - ProcDamageAndSpell(pVictim, procAttacker, procVictim, 0, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); - } - - break; - } - } - - // TODO this in only generic way, check for exceptions - DEBUG_LOG("DealFlatDamage (AFTER) >> DMG:%u", *damage); -} - -uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage) -{ - if(!this || !pVictim) - return 0; - if(!isAlive() || !pVictim->isAlive()) - return 0; - - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID); - if(!spellInfo) - return 0; - - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL); - bool crit = false; - - if (useSpellDamage) - DealFlatDamage(pVictim, spellInfo, &damage, &cleanDamage, &crit, isTriggeredSpell); - - // If we actually dealt some damage (spell proc's for 0 damage (normal and magic) called in DealFlatDamage) - if(damage > 0) - { - // Calculate absorb & resists - uint32 absorb = 0; - uint32 resist = 0; - - CalcAbsorbResist(pVictim,GetSpellSchoolMask(spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); - - //No more damage left, target absorbed and/or resisted all damage - if (damage > absorb + resist) - damage -= absorb + resist; //Remove Absorbed and Resisted from damage actually dealt - else - { - uint32 HitInfo = HITINFO_SWINGNOHITSOUND; - - if (absorb) - HitInfo |= HITINFO_ABSORB; - if (resist) - { - HitInfo |= HITINFO_RESIST; - ProcDamageAndSpell(pVictim, PROC_FLAG_TARGET_RESISTS, PROC_FLAG_RESIST_SPELL, 0, GetSpellSchoolMask(spellInfo), spellInfo,isTriggeredSpell); - } - - //Send resist - SendAttackStateUpdate(HitInfo, pVictim, 1, GetSpellSchoolMask(spellInfo), damage, absorb,resist,VICTIMSTATE_NORMAL,0); - return 0; - } - - // Deal damage done - damage = DealDamage(pVictim, damage, &cleanDamage, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellInfo), spellInfo, true); - - // Send damage log - sLog.outDetail("SpellNonMeleeDamageLog: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u,absorb is %u,resist is %u", - GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist); - - // Actual log sent to client - SendSpellNonMeleeDamageLog(pVictim, spellID, damage + resist, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit); - - // Procflags - uint32 procAttacker = PROC_FLAG_HIT_SPELL; - uint32 procVictim = (PROC_FLAG_STRUCK_SPELL|PROC_FLAG_TAKE_DAMAGE); - - if (crit) - { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; - } - - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, GetSpellSchoolMask(spellInfo), spellInfo, isTriggeredSpell); - - return damage; - } - else - { - // all spell proc for 0 normal and magic damage called in DealFlatDamage - - //Check for rage - if(cleanDamage.damage) - // Rage from damage received. - if(pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage.damage, 0, false); - - 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) { @@ -1635,7 +1307,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID())) { (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->UpdateAuraDuration(); + (*itr).second->SendAuraUpdate(false); } } } @@ -1794,6 +1466,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da case MELEE_HIT_BLOCK: { damageInfo->TargetState = VICTIMSTATE_NORMAL; + damageInfo->HitInfo |= HITINFO_BLOCK; damageInfo->procEx|=PROC_EX_BLOCK; damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue(); if (damageInfo->blocked_amount >= damageInfo->damage) @@ -1951,7 +1624,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID())) { (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->UpdateAuraDuration(); + (*itr).second->SendAuraUpdate(false); } } } @@ -1985,11 +1658,13 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); //damage-=absorb + resist; - WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4)); + WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4)); data << uint64(pVictim->GetGUID()); data << uint64(GetGUID()); + data << uint32(spellProto->Id); + data << uint32(damage); // Damage + data << uint32(0); // Overkill data << uint32(spellProto->SchoolMask); - data << uint32(damage); pVictim->SendMessageToSet(&data, true ); pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true); @@ -2008,9 +1683,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) void Unit::HandleEmoteCommand(uint32 anim_id) { WorldPacket data( SMSG_EMOTE, 12 ); - data << anim_id << GetGUID(); - WPAssert(data.size() == 12); - + data << uint32(anim_id); + data << uint64(GetGUID()); SendMessageToSet(&data, true); } @@ -2021,15 +1695,18 @@ uint32 Unit::CalcArmorReducedDamage(Unit* pVictim, const uint32 damage) // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura armor += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, SPELL_SCHOOL_MASK_NORMAL); - if (armor<0.0f) armor=0.0f; + // Apply Player CR_ARMOR_PENETRATION rating + if (GetTypeId()==TYPEID_PLAYER) + armor *= 1.0f - ((Player*)this)->GetRatingBonusValue(CR_ARMOR_PENETRATION) / 100.0f; + + if (armor < 0.0f) armor=0.0f; + + float levelModifier = getLevel(); + if ( levelModifier > 59 ) + levelModifier = levelModifier + (4.5f * (levelModifier-59)); - float tmpvalue = 0.0f; - if(getLevel() <= 59) //Level 1-59 - tmpvalue = armor / (armor + 400.0f + 85.0f * getLevel()); - else if(getLevel() < 70) //Level 60-69 - tmpvalue = armor / (armor - 22167.5f + 467.5f * getLevel()); - else //Level 70+ - tmpvalue = armor / (armor + 10557.5f); + float tmpvalue = 0.1f * armor / (8.5f * levelModifier + 40); + tmpvalue = tmpvalue/(1.0f + tmpvalue); if(tmpvalue < 0.0f) tmpvalue = 0.0f; @@ -2116,7 +1793,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe int32 currentAbsorb; - //Reflective Shield + // Reflective Shield if ((pVictim != this) && (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && (*i)->GetSpellProto()->SpellFamilyFlags == 0x1) { if(Unit* caster = (*i)->GetCaster()) @@ -2262,407 +1939,6 @@ 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; - - // If is casted Melee spell, calculate like physical - if(!spellCasted) - outcome = RollMeleeOutcomeAgainst (pVictim, attType); - else - outcome = RollPhysicalOutcomeAgainst (pVictim, attType, spellCasted); - - if(outcome == MELEE_HIT_MISS ||outcome == MELEE_HIT_DODGE ||outcome == MELEE_HIT_BLOCK ||outcome == MELEE_HIT_PARRY) - pVictim->AddThreat(this, 0.0f); - switch(outcome) - { - case MELEE_HIT_EVADE: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - return; - } - case MELEE_HIT_MISS: - { - *hitInfo |= HITINFO_MISS; - *damage = 0; - cleanDamage->damage = 0; - if(GetTypeId()== TYPEID_PLAYER) - ((Player*)this)->UpdateWeaponSkill(attType); - return; - } - } - - /// If this is a creature and it attacks from behind it has a probability to daze it's victim - if( (outcome==MELEE_HIT_CRIT || outcome==MELEE_HIT_CRUSHING || outcome==MELEE_HIT_NORMAL || outcome==MELEE_HIT_GLANCING) && - GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) - && pVictim->GetTypeId() == TYPEID_PLAYER) - { - // -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(this); - uint32 AttackerMeleeSkill=GetUnitMeleeSkill(pVictim); - - Probability *= AttackerMeleeSkill/(float)VictimDefense; - - if(Probability > 40.0f) - Probability = 40.0f; - - if(roll_chance_f(Probability)) - CastSpell(pVictim, 1604, true); - } - - //Calculate the damage after armor mitigation if SPELL_SCHOOL_NORMAL - if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) - { - uint32 damageAfterArmor = CalcArmorReducedDamage(pVictim, *damage); - - // random durability for main hand weapon (ABSORB) - if(damageAfterArmor < *damage) - if(pVictim->GetTypeId() == TYPEID_PLAYER) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_ABSORB))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EquipmentSlots(urand(EQUIPMENT_SLOT_START,EQUIPMENT_SLOT_BACK))); - - cleanDamage->damage += *damage - damageAfterArmor; - *damage = damageAfterArmor; - } - - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateCombatSkills(pVictim, attType, outcome, false); - - if(GetTypeId() != TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateCombatSkills(this, attType, outcome, true); - - switch (outcome) - { - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - { - //*hitInfo = 0xEA; - // 0xEA - *hitInfo = HITINFO_CRITICALHIT | HITINFO_NORMALSWING2 | 0x8; - - // Crit bonus calc - uint32 crit_bonus; - crit_bonus = *damage; - - // Apply crit_damage bonus for melee spells - if (spellCasted) - { - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellCasted->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus); - - uint32 creatureTypeMask = pVictim->GetCreatureTypeMask(); - 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)->GetModifierValue()+100.0f)/100.0f); - } - - *damage += crit_bonus; - - uint32 resilienceReduction = 0; - - if(attType == RANGED_ATTACK) - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetRangedCritDamageReduction(*damage); - } - else - { - int32 mod = pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE); - mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE); - *damage = int32((*damage) * float((100.0f + mod)/100.0f)); - // Resilience - reduce crit damage - if (pVictim->GetTypeId()==TYPEID_PLAYER) - resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(*damage); - } - - *damage -= resilienceReduction; - cleanDamage->damage += resilienceReduction; - - if(GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() != TYPEID_PLAYER && pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER ) - ((Player*)this)->UpdateWeaponSkill(attType); - - ModifyAuraState(AURA_STATE_CRIT, true); - StartReactiveTimer( REACTIVE_CRIT ); - - if(getClass()==CLASS_HUNTER) - { - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true); - StartReactiveTimer( REACTIVE_HUNTER_CRIT ); - } - - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - *blocked_amount = pVictim->GetShieldBlockValue(); - - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - break; - } - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL); - break; - } - case MELEE_HIT_PARRY: - { - if(attType == RANGED_ATTACK) //range attack - no parry - { - outcome = MELEE_HIT_NORMAL; - break; - } - - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_PARRY; - - // instant (maybe with small delay) counter attack - { - float offtime = float(pVictim->getAttackTimer(OFF_ATTACK)); - float basetime = float(pVictim->getAttackTimer(BASE_ATTACK)); - - // after parry nearest next attack time will reduced at %40 from full attack time. - // The delay cannot be reduced to less than 20% of your weapon base swing delay. - if (pVictim->haveOffhandWeapon() && offtime < basetime) - { - float percent20 = pVictim->GetAttackTime(OFF_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(offtime > percent20 && offtime <= percent60) - { - pVictim->setAttackTimer(OFF_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(offtime > percent60) - { - offtime -= 2*percent20; - pVictim->setAttackTimer(OFF_ATTACK,uint32(offtime)); - } - // ELSE not changed - } - else - { - float percent20 = pVictim->GetAttackTime(BASE_ATTACK)*0.20; - float percent60 = 3*percent20; - // set to 20% if in range 20%...20+40% of full time - if(basetime > percent20 && basetime <= percent60) - { - pVictim->setAttackTimer(BASE_ATTACK,uint32(percent20)); - } - // decrease at %40 from full time - else if(basetime > percent60) - { - basetime -= 2*percent20; - pVictim->setAttackTimer(BASE_ATTACK,uint32(basetime)); - } - // ELSE not changed - } - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update victim defense ? - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (PARRY) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_PARRY))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_MAINHAND); - } - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - if (pVictim->getClass() == CLASS_HUNTER) - { - pVictim->ModifyAuraState(AURA_STATE_HUNTER_PARRY,true); - pVictim->StartReactiveTimer( REACTIVE_HUNTER_PARRY ); - } - else - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - case MELEE_HIT_DODGE: - { - if(attType == RANGED_ATTACK) //range attack - no dodge - { - outcome = MELEE_HIT_NORMAL; - break; - } - - cleanDamage->damage += *damage; - *damage = 0; - *victimState = VICTIMSTATE_DODGE; - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - ((Player*)pVictim)->UpdateDefense(); - - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - if (pVictim->getClass() != CLASS_ROGUE) // Riposte - { - pVictim->ModifyAuraState(AURA_STATE_DEFENSE, true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - } - - // Overpower - if (GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR) - { - ((Player*)this)->AddComboPoints(pVictim, 1); - StartReactiveTimer( REACTIVE_OVERPOWER ); - } - - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - case MELEE_HIT_BLOCK: - { - *blocked_amount = pVictim->GetShieldBlockValue(); - - if (pVictim->GetUnitBlockChance()) - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD); - else - pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYUNARMED); - - //Only set VICTIMSTATE_BLOCK on a full block - if (*blocked_amount >= uint32(*damage)) - { - *victimState = VICTIMSTATE_BLOCKS; - *blocked_amount = uint32(*damage); - } - - if(pVictim->GetTypeId() == TYPEID_PLAYER) - { - // Update defense - ((Player*)pVictim)->UpdateDefense(); - - // random durability for main hand weapon (BLOCK) - if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_BLOCK))) - ((Player*)pVictim)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_OFFHAND); - } - - pVictim->ModifyAuraState(AURA_STATE_DEFENSE,true); - pVictim->StartReactiveTimer( REACTIVE_DEFENSE ); - - break; - } - case MELEE_HIT_GLANCING: - { - int32 leveldif = int32(pVictim->getLevel()) - int32(getLevel()); - if (leveldif > 3) leveldif = 3; - *damage *= (1 - leveldif * 0.1f); - cleanDamage->damage = *damage; - *hitInfo |= HITINFO_GLANCING; - break; - } - case MELEE_HIT_CRUSHING: - { - // 150% normal damage - *damage += (*damage / 2); - cleanDamage->damage = *damage; - *hitInfo |= HITINFO_CRUSHING; - // TODO: victimState, victim animation? - break; - } - default: - break; - } - - // apply melee damage bonus and absorb only if base damage not fully blocked to prevent negative damage or damage with full block - if(*victimState != VICTIMSTATE_BLOCKS) - { - MeleeDamageBonus(pVictim, damage,attType,spellCasted); - CalcAbsorbResist(pVictim, damageSchoolMask, DIRECT_DAMAGE, *damage-*blocked_amount, absorbDamage, resistDamage); - } - - if (*absorbDamage) *hitInfo |= HITINFO_ABSORB; - if (*resistDamage) *hitInfo |= HITINFO_RESIST; - - cleanDamage->damage += *blocked_amount; - - if (*damage <= *absorbDamage + *resistDamage + *blocked_amount) - { - //*hitInfo = 0x00010020; - //*hitInfo |= HITINFO_SWINGNOHITSOUND; - //*damageType = 0; - CastMeleeProcDamageAndSpell(pVictim, 0, damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell); - return; - } - - // update at damage Judgement aura duration that applied by attacker at victim - if(*damage) - { - AuraMap const& vAuras = pVictim->GetAuras(); - for(AuraMap::const_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() && (!spellCasted || spellCasted->Id == 35395)) ) - { - (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration()); - (*itr).second->UpdateAuraDuration(); - } - } - } - - 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; - 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); - pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifierValue(), false, false); - if (pVictim->m_removedAuras > removedAuras) - { - removedAuras = pVictim->m_removedAuras; - next = vDamageShields.begin(); - } - } - } -}*/ - void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra ) { if(hasUnitState(UNIT_STAT_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) ) @@ -2729,67 +2005,6 @@ 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 - float miss_chance = MeleeMissChanceCalc(pVictim, attType); - - // Critical hit chance - float crit_chance = GetUnitCriticalChance(attType, pVictim); - // this is to avoid compiler issue when declaring variables inside if - float block_chance, parry_chance, dodge_chance; - - // cannot be dodged/parried/blocked - if(spellInfo->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) - { - block_chance = 0.0f; - parry_chance = 0.0f; - dodge_chance = 0.0f; - } - else - { - // parry can be avoided only by some abilities - parry_chance = pVictim->GetUnitParryChance(); - // block might be bypassed by it as well - block_chance = pVictim->GetUnitBlockChance(); - // stunned target cannot dodge and this is check in GetUnitDodgeChance() - dodge_chance = pVictim->GetUnitDodgeChance(); - } - - // Only players can have Talent&Spell bonuses - if (GetTypeId() == TYPEID_PLAYER) - { - // Increase from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL aura - crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, spellInfo->SchoolMask); - - if( dodge_chance != 0.0f ) // if dodge chance is already 0, ignore talents for speed - { - AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) - { - // can't be dodged rogue finishing move - if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) - { - if(spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) - { - dodge_chance = 0.0f; - break; - } - } - } - } - } - - // Spellmods - if(Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance); - - 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 { // This is only wrapper @@ -2809,10 +2024,10 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackT // Useful if want to specify crit & miss chances for melee, else it could be removed DEBUG_LOG("MELEE 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), false); + return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100), int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100)); } -MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const +MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const { if(pVictim->GetTypeId()==TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) return MELEE_HIT_EVADE; @@ -2825,7 +2040,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack // bonus from skills is 0.04% int32 skillBonus = 4 * ( attackerWeaponSkill - victimMaxSkillValueForLevel ); - int32 skillBonus2 = 4 * ( attackerMaxSkillValueForLevel - victimDefenseSkill ); int32 sum = 0, tmp = 0; int32 roll = urand (0, 10000); @@ -2906,16 +2120,6 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack && ((tmp -= skillBonus) > 0) && (roll < (sum += tmp))) { - // Critical chance - tmp = crit_chance + skillBonus2; - if ( GetTypeId() == TYPEID_PLAYER && SpellCasted && tmp > 0 ) - { - if ( roll_chance_i(tmp/100)) - { - DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCKED CRIT"); - return MELEE_HIT_BLOCK_CRIT; - } - } DEBUG_LOG ("RollMeleeOutcomeAgainst: BLOCK <%d, %d)", sum-tmp, sum); return MELEE_HIT_BLOCK; } @@ -2923,7 +2127,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack } // Critical chance - tmp = crit_chance + skillBonus2; + tmp = crit_chance; if (tmp > 0 && roll < (sum += tmp)) { @@ -2932,7 +2136,7 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack } // Max 40% chance to score a glancing blow against mobs that are higher level (can do only players and pets and not with ranged weapon) - if( attType != RANGED_ATTACK && !SpellCasted && + if( attType != RANGED_ATTACK && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet()) && pVictim->GetTypeId() != TYPEID_PLAYER && !((Creature*)pVictim)->isPet() && getLevel() < pVictim->getLevelForTarget(this) ) @@ -2951,10 +2155,14 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttack } } - if(GetTypeId()!=TYPEID_PLAYER && !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) && !((Creature*)this)->isPet() && !SpellCasted /*Only autoattack can be crushing blow*/ ) + // mobs can score crushing blows if they're 4 or more levels above victim + if (getLevelForTarget(pVictim) >= pVictim->getLevelForTarget(this) + 4 && + // can be from by creature (if can) or from controlled player that considered as creature + (GetTypeId()!=TYPEID_PLAYER && !((Creature*)this)->isPet() && + !(((Creature*)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSH) || + GetTypeId()==TYPEID_PLAYER && GetCharmerOrOwnerGUID())) { - // mobs can score crushing blows if they're 3 or more levels above victim - // or when their weapon skill is 15 or more above victim's defense skill + // when their weapon skill is 15 or more above victim's defense skill tmp = victimDefenseSkill; int32 tmpmax = victimMaxSkillValueForLevel; // having defense above your maximum (from items, talents etc.) has no effect @@ -3064,6 +2272,23 @@ bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAtt { if (pVictim->HasInArc(M_PI,this)) { + /* Currently not exist spells with ignore block + // Ignore combat result aura (parry/dodge check on prepare) + AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) + { + if (!(*i)->isAffectedOnSpell(spellProto)) + continue; + if ((*i)->GetModifier()->m_miscvalue == ) + return false; + } + */ + + // Check creatures flags_extra for disable block + if(pVictim->GetTypeId()==TYPEID_UNIT && + ((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_BLOCK ) + return false; + float blockChance = GetUnitBlockChance(); blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04; if (roll_chance_f(blockChance)) @@ -3074,22 +2299,18 @@ bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAtt // 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(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const +/*float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell) { // Calculate hit chance (more correct for chance mod) int32 HitChance; // PvP - PvE melee chances - /*int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; + int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); if(leveldif < 3) HitChance = 95 - leveldif; else - HitChance = 93 - (leveldif - 2) * lchance;*/ - if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon()) - HitChance = 95.0f; - else - HitChance = 76.0f; + HitChance = 93 - (leveldif - 2) * lchance; // Hit chance depends from victim auras if(attType == RANGED_ATTACK) @@ -3098,11 +2319,8 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); // Spellmod from SPELLMOD_RESIST_MISS_CHANCE - if(spellId) - { - if(Player *modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance); - } + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, HitChance); // Miss = 100 - hit float miss_chance= 100.0f - HitChance; @@ -3114,12 +2332,7 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, miss_chance -= m_modMeleeHitChance; // bonus from skills is 0.04% - //miss_chance -= skillDiff * 0.04f; - int32 diff = -skillDiff; - if(pVictim->GetTypeId()==TYPEID_PLAYER) - miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02; - else - miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1; + miss_chance -= skillDiff * 0.04f; // Limit miss chance from 0 to 60% if (miss_chance < 0.0f) @@ -3127,7 +2340,7 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, if (miss_chance > 60.0f) return 60.0f; return miss_chance; -} +}*/ // Melee based spells hit result calculations SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) @@ -3143,68 +2356,88 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) int32 fullSkillDiff = attackerWeaponSkill - int32(pVictim->GetDefenseSkillValue(this)); uint32 roll = urand (0, 10000); - uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f); + uint32 missChance = uint32(MeleeSpellMissChance(pVictim, attType, fullSkillDiff, spell->Id)*100.0f); // Roll miss uint32 tmp = missChance; if (roll < tmp) return SPELL_MISS_MISS; + bool canDodge = true; + bool canParry = true; + // Same spells cannot be parry/dodge if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) return SPELL_MISS_NONE; - // Ranged attack can`t miss too + // Ranged attack cannot be parry/dodge if (attType == RANGED_ATTACK) return SPELL_MISS_NONE; - bool attackFromBehind = !pVictim->HasInArc(M_PI,this); - - // Roll dodge - int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; - // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE - dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); - - // Reduce dodge chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - if (dodgeChance < 0) - dodgeChance = 0; - - // Can`t dodge from behind in PvP (but its possible in PvE) - if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER && attackFromBehind) - dodgeChance = 0; - - // Rogue talent`s cant be dodged - AuraList const& mCanNotBeDodge = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); - for(AuraList::const_iterator i = mCanNotBeDodge.begin(); i != mCanNotBeDodge.end(); ++i) + // Check for attack from behind + if (!pVictim->HasInArc(M_PI,this)) + { + // Can`t dodge from behind in PvP (but its possible in PvE) + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + canDodge = false; + // Can`t parry + canParry = false; + } + // Check creatures flags_extra for disable parry + if(pVictim->GetTypeId()==TYPEID_UNIT) + { + uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra; + if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY ) + canParry = false; + } + // Ignore combat result aura + AuraList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); + for(AuraList::const_iterator i = ignore.begin(); i != ignore.end(); ++i) { - if((*i)->GetModifier()->m_miscvalue == VICTIMSTATE_DODGE) // can't be dodged rogue finishing move + if (!(*i)->isAffectedOnSpell(spell)) + continue; + switch((*i)->GetModifier()->m_miscvalue) { - if(spell->SpellFamilyName==SPELLFAMILY_ROGUE && (spell->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE)) - { - dodgeChance = 0; + case MELEE_HIT_DODGE: canDodge = false; break; + case MELEE_HIT_BLOCK: break; // Block check in hit step + case MELEE_HIT_PARRY: canParry = false; break; + default: + DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetModifier()->m_miscvalue); break; - } } } - tmp += dodgeChance; - if (roll < tmp) - return SPELL_MISS_DODGE; + if (canDodge) + { + // Roll dodge + int32 dodgeChance = int32(pVictim->GetUnitDodgeChance()*100.0f) - skillDiff * 4; + // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE + dodgeChance+= GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_COMBAT_RESULT_CHANCE, VICTIMSTATE_DODGE); + // Reduce dodge chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + dodgeChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + if (dodgeChance < 0) + dodgeChance = 0; - // Roll parry - int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; - // Reduce parry chance by attacker expertise rating - if (GetTypeId() == TYPEID_PLAYER) - parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); - // Can`t parry from behind - if (parryChance < 0 || attackFromBehind) - parryChance = 0; + tmp += dodgeChance; + if (roll < tmp) + return SPELL_MISS_DODGE; + } - tmp += parryChance; - if (roll < tmp) - return SPELL_MISS_PARRY; + if (canParry) + { + // Roll parry + int32 parryChance = int32(pVictim->GetUnitParryChance()*100.0f) - skillDiff * 4; + // Reduce parry chance by attacker expertise rating + if (GetTypeId() == TYPEID_PLAYER) + parryChance-=int32(((Player*)this)->GetExpertiseDodgeOrParryReduction(attType) * 100.0f); + if (parryChance < 0) + parryChance = 0; + + tmp += parryChance; + if (roll < tmp) + return SPELL_MISS_PARRY; + } return SPELL_MISS_NONE; } @@ -3560,6 +2793,9 @@ float Unit::GetUnitCriticalChance(WeaponAttackType attackType, const Unit *pVict crit -= ((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_MELEE); } + // Apply crit chance from defence skill + crit += (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f; + if (crit < 0.0f) crit = 0.0f; return crit; @@ -3687,7 +2923,7 @@ void Unit::_UpdateAutoRepeatSpell() if ( (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->isMoving()) || IsNonMeleeSpellCasted(false,false,true) ) { // cancel wand shoot - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); m_AutoRepeatFirstCast = true; return; @@ -3740,7 +2976,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell ) if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) { // break autorepeat if not Auto Shot - if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351) + if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); m_AutoRepeatFirstCast = true; } @@ -3755,7 +2991,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell ) // it also does break autorepeat if not Auto Shot if ( m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Category == 351 ) + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id != SPELL_ID_AUTOSHOT ) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); addUnitState(UNIT_STAT_CASTING); } break; @@ -3763,7 +2999,7 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell ) case CURRENT_AUTOREPEAT_SPELL: { // only Auto Shoot does not break anything - if (pSpell->m_spellInfo->Category == 351) + if (pSpell->m_spellInfo->Id != SPELL_ID_AUTOSHOT) { // generic autorepeats break generic non-delayed and channeled non-delayed spells InterruptSpell(CURRENT_GENERIC_SPELL,false); @@ -4176,9 +3412,8 @@ bool Unit::AddAura(Aura *Aur) } } - // passive auras stack with all (except passive spell proc auras) - if ((!Aur->IsPassive() || !IsPassiveStackableSpell(Aur->GetId())) && - !(Aur->GetId() == 20584 || Aur->GetId() == 8326)) + // passive auras not stacable with other ranks + if (!IsPassiveSpellStackableWithRanks(aurSpellInfo)) { if (!RemoveNoStackAurasDueToAura(Aur)) { @@ -4282,6 +3517,14 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) return false; uint32 spellId = Aur->GetId(); + + // passive spell special case (only non stackable with ranks) + if(IsPassiveSpell(spellId)) + { + if(IsPassiveSpellStackableWithRanks(spellProto)) + return true; + } + uint32 effIndex = Aur->GetEffIndex(); SpellSpecific spellId_spec = GetSpellSpecific(spellId); @@ -4300,9 +3543,11 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) uint32 i_spellId = i_spellProto->Id; + // early checks that spellId is passive non stackable spell if(IsPassiveSpell(i_spellId)) { - if(IsPassiveStackableSpell(i_spellId)) + // passive non-stackable spells not stackable only for same caster + if(Aur->GetCasterGUID()!=i->second->GetCasterGUID()) continue; // passive non-stackable spells not stackable only with another rank of same spell @@ -4742,7 +3987,7 @@ void Unit::DelayAura(uint32 spellId, uint32 effindex, int32 delaytime) iter->second->SetAuraDuration(0); else iter->second->SetAuraDuration(iter->second->GetAuraDuration() - delaytime); - iter->second->UpdateAuraDuration(); + iter->second->SendAuraUpdate(false); sLog.outDebug("Aura %u partially interrupted on unit %u, new duration: %u ms",iter->second->GetModifier()->m_auraname, GetGUIDLow(), iter->second->GetAuraDuration()); } } @@ -4771,6 +4016,17 @@ Aura* Unit::GetAura(uint32 spellId, uint32 effindex) return NULL; } +bool Unit::HasAura(uint32 spellId) const +{ + for (int i = 0; i < 3 ; ++i) + { + AuraMap::const_iterator iter = m_Auras.find(spellEffectPair(spellId, i)); + if (iter != m_Auras.end()) + return true; + } + return false; +} + void Unit::AddDynObject(DynamicObject* dynObj) { m_dynObjGUIDs.push_back(dynObj->GetGUID()); @@ -4915,6 +4171,7 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log) data.append(log->attacker->GetPackGUID()); data << uint32(log->SpellID); data << uint32(log->damage); //damage amount + data << uint32(0); data << uint8 (log->schoolMask); //damage school data << uint32(log->absorb); //AbsorbedDamage data << uint32(log->resist); //resist @@ -4934,6 +4191,7 @@ void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, data.append(GetPackGUID()); data << uint32(SpellID); data << uint32(Damage-AbsorbedDamage-Resist-Blocked); + data << uint32(0); // wotlk data << uint8(damageSchoolMask); // spell school data << uint32(AbsorbedDamage); // AbsorbedDamage data << uint32(Resist); // resist @@ -4972,25 +4230,65 @@ void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo) void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo) { - WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+84)); // we guess size + uint32 count = 1; + WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size data << (uint32)damageInfo->HitInfo; data.append(GetPackGUID()); data.append(damageInfo->target->GetPackGUID()); data << (uint32)(damageInfo->damage); // Full damage + data << uint32(0); // overkill value + + data << (uint8)count; // Sub damage count + + for(int i = 0; i < count; ++i) + { + data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage + data << (float)damageInfo->damage; // sub damage + data << (uint32)damageInfo->damage; // Sub Damage + } + + if(damageInfo->HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) + { + for(int i = 0; i < count; ++i) + data << (uint32)damageInfo->absorb; // Absorb + } + + if(damageInfo->HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) + { + for(int i = 0; i < count; ++i) + data << (uint32)damageInfo->resist; // Resist + } - 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 );/**/ + + if(damageInfo->HitInfo & HITINFO_BLOCK) + data << (uint32)damageInfo->blocked_amount; + + if(damageInfo->HitInfo & HITINFO_UNK3) + data << uint32(0); + + if(damageInfo->HitInfo & HITINFO_UNK1) + { + data << uint32(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + for(uint8 i = 0; i < 5; ++i) + { + data << float(0); + data << float(0); + } + data << uint32(0); + } + + SendMessageToSet( &data, true ); } void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount) @@ -4998,169 +4296,69 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE"); WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+45)); // we guess size - data << (uint32)HitInfo; + data << uint32(HitInfo); // flags data.append(GetPackGUID()); data.append(target->GetPackGUID()); - data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); + data << uint32(Damage-AbsorbDamage-Resist-BlockedAmount);// damage + data << uint32(0); // overkill value data << (uint8)SwingType; // count? // for(i = 0; i < SwingType; ++i) data << (uint32)damageSchoolMask; data << (float)(Damage-AbsorbDamage-Resist-BlockedAmount); - // still need to double check damage data << (uint32)(Damage-AbsorbDamage-Resist-BlockedAmount); - data << (uint32)AbsorbDamage; - data << (uint32)Resist; // end loop - data << (uint32)TargetState; - - if( AbsorbDamage == 0 ) //also 0x3E8 = 0x3E8, check when that happens - data << (uint32)0; - else - data << (uint32)-1; - - data << (uint32)0; - data << (uint32)BlockedAmount; - - 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); - if(procSpell) - sLog.outDebug("ProcDamageAndSpell: invoked due to spell id %u %s", procSpell->Id, (isTriggeredSpell?"(triggered)":"")); - - // Assign melee/ranged proc flags for magic attacks, that are actually melee/ranged abilities - // not assign for spell proc triggered spell to prevent infinity (or unexpected 2-3 times) melee damage spell proc call with melee damage effect - // That is the question though if it's fully correct - if(procSpell && !isTriggeredSpell) + if(HitInfo & (HITINFO_ABSORB | HITINFO_ABSORB2)) { - if(procSpell->DmgClass == SPELL_DAMAGE_CLASS_MELEE) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_MELEE; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_MELEE; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_MELEE; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_MELEE; - attType = BASE_ATTACK; // Melee abilities are assumed to be dealt with mainhand weapon - } - else if (procSpell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - { - if(procAttacker & PROC_FLAG_HIT_SPELL) procAttacker |= PROC_FLAG_HIT_RANGED; - if(procAttacker & PROC_FLAG_CRIT_SPELL) procAttacker |= PROC_FLAG_CRIT_RANGED; - if(procVictim & PROC_FLAG_STRUCK_SPELL) procVictim |= PROC_FLAG_STRUCK_RANGED; - if(procVictim & PROC_FLAG_STRUCK_CRIT_SPELL) procVictim |= PROC_FLAG_STRUCK_CRIT_RANGED; - attType = RANGED_ATTACK; - } + // for(i = 0; i < SwingType; ++i) + data << uint32(AbsorbDamage); + // end loop } - if(damage && (procVictim & (PROC_FLAG_STRUCK_MELEE|PROC_FLAG_STRUCK_RANGED|PROC_FLAG_STRUCK_SPELL))) - procVictim |= (PROC_FLAG_TAKE_DAMAGE|PROC_FLAG_TOUCH); - // Not much to do if no flags are set. - if (procAttacker) + if(HitInfo & (HITINFO_RESIST | HITINFO_RESIST2)) { - // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcEffectAuraTypes,attType, procSpell, damage, damageSchoolMask); - ProcDamageAndSpellFor(false,pVictim,procAttacker,attackerProcCastAuraTypes,attType, procSpell, damage, damageSchoolMask); + // for(i = 0; i < SwingType; ++i) + data << uint32(Resist); + // end loop } - // 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) + data << (uint8)TargetState; + data << (uint32)0; + data << (uint32)0; + + if(HitInfo & HITINFO_BLOCK) { - // processing auras that not generate casts at proc event before auras that generate casts to prevent proc aura added at prev. proc aura execute in set - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcEffectAuraTypes,attType,procSpell, damage, damageSchoolMask); - pVictim->ProcDamageAndSpellFor(true,this,procVictim,victimProcCastAuraTypes,attType,procSpell, damage, damageSchoolMask); + data << uint32(BlockedAmount); } -} - -void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted, bool isTriggeredSpell) -{ - if(!pVictim) - return; - - uint32 procAttacker = PROC_FLAG_NONE; - uint32 procVictim = PROC_FLAG_NONE; - switch(outcome) + if(HitInfo & HITINFO_UNK3) { - case MELEE_HIT_EVADE: - return; - case MELEE_HIT_MISS: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_MISS; - } - break; - case MELEE_HIT_BLOCK_CRIT: - case MELEE_HIT_CRIT: - if(spellCasted && attType == BASE_ATTACK) - { - procAttacker |= PROC_FLAG_CRIT_SPELL; - procVictim |= PROC_FLAG_STRUCK_CRIT_SPELL; - if ( outcome == MELEE_HIT_BLOCK_CRIT ) - { - procVictim |= PROC_FLAG_BLOCK; - procAttacker |= PROC_FLAG_TARGET_BLOCK; - } - } - else if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - case MELEE_HIT_PARRY: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_PARRY; - break; - case MELEE_HIT_BLOCK: - procAttacker = PROC_FLAG_TARGET_BLOCK; - procVictim = PROC_FLAG_BLOCK; - break; - case MELEE_HIT_DODGE: - procAttacker = PROC_FLAG_TARGET_DODGE_OR_PARRY; - procVictim = PROC_FLAG_DODGE; - break; - case MELEE_HIT_CRUSHING: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE | PROC_FLAG_CRIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE | PROC_FLAG_STRUCK_CRIT_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED | PROC_FLAG_CRIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED | PROC_FLAG_STRUCK_CRIT_RANGED; - } - break; - default: - if(attType == BASE_ATTACK || attType == OFF_ATTACK) - { - procAttacker = PROC_FLAG_HIT_MELEE; - procVictim = PROC_FLAG_STRUCK_MELEE; - } - else - { - procAttacker = PROC_FLAG_HIT_RANGED; - procVictim = PROC_FLAG_STRUCK_RANGED; - } - break; + data << uint32(0); } - if(damage > 0) - procVictim |= PROC_FLAG_TAKE_DAMAGE; + if(HitInfo & HITINFO_UNK1) + { + data << uint32(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + for(uint8 i = 0; i < 5; ++i) + { + data << float(0); + data << float(0); + } + data << uint32(0); + } - if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE) - ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType); -}*/ + SendMessageToSet( &data, true ); +} bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) { @@ -5243,7 +4441,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu { switch (dummySpell->Id) { - // Eye of Eye + // Eye for an Eye case 9799: case 25988: { @@ -5860,7 +5058,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu triggered_spell_id = 39373; break; } - // Vestments of Faith (Priest Tier 3) - 4 pieces bonus + // Greater Heal (Vestments of Faith (Priest Tier 3) - 4 pieces bonus) case 28809: { triggered_spell_id = 28810; @@ -5997,6 +5195,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu } case SPELLFAMILY_PALADIN: { + // TODO: spell list, formula change in 3.0.3 // Seal of Righteousness - melee proc dummy if (dummySpell->SpellFamilyFlags&0x000000008000000LL && triggeredByAura->GetEffIndex()==0) { @@ -6093,7 +5292,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu } break; } - //Seal of Vengeance + // TODO: fix basepoint calculation (changed in 3.0.3) + // Seal of Vengeance case 31801: { if(effIndex != 0) // effect 1,2 used by seal unleashing code @@ -6102,7 +5302,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu triggered_spell_id = 31803; break; } - // Spiritual Att. + // Spiritual Attunement case 31785: case 33776: { @@ -6286,7 +5486,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu } // Earth Shield - if(dummySpell->SpellFamilyFlags==0x40000000000LL) + if(dummySpell->SpellFamilyFlags & 0x0000040000000000LL) { if(GetTypeId() != TYPEID_PLAYER) return false; @@ -6324,6 +5524,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 15208: spellId = 45294; break; // Rank 10 case 25448: spellId = 45295; break; // Rank 11 case 25449: spellId = 45296; break; // Rank 12 + case 49237: spellId = 49239; break; // Rank 13 + case 49238: spellId = 49240; break; // Rank 14 // Chain Lightning case 421: spellId = 45297; break; // Rank 1 case 930: spellId = 45298; break; // Rank 2 @@ -6331,6 +5533,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 10605: spellId = 45300; break; // Rank 4 case 25439: spellId = 45301; break; // Rank 5 case 25442: spellId = 45302; break; // Rank 6 + case 49268: spellId = 49270; break; // Rank 7 + case 49269: spellId = 49271; break; // Rank 8 default: sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); return false; @@ -6341,21 +5545,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu mod->value = -100; mod->type = SPELLMOD_PCT; mod->spellId = dummySpell->Id; - mod->effectId = 0; - mod->lastAffected = NULL; mod->mask = 0x0000000000000003LL; - mod->charges = 0; + mod->mask2= 0LL; ((Player*)this)->AddSpellMod(mod, true); // Remove cooldown (Chain Lightning - have Category Recovery time) if (procSpell->SpellFamilyFlags & 0x0000000000000002LL) ((Player*)this)->RemoveSpellCooldown(spellId); - // Hmmm.. in most case spells already set half basepoints but... - // Lightning Bolt (2-10 rank) have full basepoint and half bonus from level - // As on wiki: - // BUG: Rank 2 to 10 (and maybe 11) of Lightning Bolt will proc another Bolt with FULL damage (not halved). This bug is known and will probably be fixed soon. - // So - no add changes :) CastSpell(pVictim, spellId, true, castItem, triggeredByAura); ((Player*)this)->AddSpellMod(mod, false); @@ -6400,1172 +5597,520 @@ 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) + +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; + + if(triggeredByAura->GetModifier()->m_auraname == SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE) + basepoints0 = triggerAmount; + Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL; - uint32 triggered_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()]; - Unit* target = !(procFlags & PROC_FLAG_HEAL) && IsPositiveSpell(triggered_spell_id) ? this : pVictim; - int32 basepoints0 = 0; - - switch(auraSpellInfo->SpellFamilyName) + // Try handle uncnown trigger spells + if (sSpellStore.LookupEntry(trigger_spell_id)==NULL) { - case SPELLFAMILY_GENERIC: - { - switch(auraSpellInfo->Id) - { - // Aegis of Preservation - case 23780: - //Aegis Heal (instead non-existed triggered spell) - triggered_spell_id = 23781; - target = this; - break; - // Elune's Touch (moonkin mana restore) - case 24905: - { - // Elune's Touch (instead non-existed triggered spell) - triggered_spell_id = 33926; - basepoints0 = int32(0.3f * GetTotalAttackPowerValue(BASE_ATTACK)); - target = this; + switch (auraSpellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + //if (auraSpellInfo->Id==59532) // Abandon Passengers on Poly + //if (auraSpellInfo->Id==54775) // Abandon Vehicle on Poly + //if (auraSpellInfo->Id==34082) // Advantaged State (DND) + 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 + //else if (auraSpellInfo->Id == 48876) // Beast's Mark + //{ + // trigger_spell_id = 48877; + //} + //else if (auraSpellInfo->Id == 59237) // Beast's Mark + //{ + // trigger_spell_id = 59233; + //} + //else if (auraSpellInfo->Id==46939) // Black Bow of the Betrayer + //{ + // trigger_spell_id = 29471; // gain mana + // 27526; // drain mana if possible + //} + //else if (auraSpellInfo->Id==50844) // Blood Mirror + //else if (auraSpellInfo->Id==54476) // Blood Presence + //else if (auraSpellInfo->Id==50689) // Blood Presence (Rank 1) + //else if (auraSpellInfo->Id==37030) // Chaotic Temperament + //else if (auraSpellInfo->Id==52856) // Charge + 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; } - // Enlightenment - case 29601: - { - // only for cast with mana price - if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0) - return false; - break; // fall through to normal cast + //else if (auraSpellInfo->Id==41248) // Consuming Strikes + // trigger_spell_id = 41249; + //else if (auraSpellInfo->Id==45205) // Copy Offhand Weapon + //else if (auraSpellInfo->Id==57594) // Copy Ranged Weapon + //else if (auraSpellInfo->Id==41054) // Copy Weapon + // trigger_spell_id = 41055; + //else if (auraSpellInfo->Id==45343) // Dark Flame Aura + //else if (auraSpellInfo->Id==47300) // Dark Flame Aura + else if (auraSpellInfo->Id==57345) // Darkmoon Card: Greatness + { + uint32 stat = 0; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229;stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 60233;stat = GetStat(STAT_AGILITY); } + // intellect + if (GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234;stat = GetStat(STAT_INTELLECT);} + // spirit + if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235;stat = GetStat(STAT_SPIRIT); } } - // Health Restore - case 33510: + //else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1) + //else if (auraSpellInfo->Id==5301) // Defensive State (DND) + //else if (auraSpellInfo->Id==13358) // Defensive State (DND) + //else if (auraSpellInfo->Id==16092) // Defensive State (DND) + //else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND) + //else if (auraSpellInfo->Id==40329) // Demo Shout Sensor + else if (auraSpellInfo->Id == 33896) // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher) + trigger_spell_id = 33898; + //else if (auraSpellInfo->Id==18943) // Double Attack + //else if (auraSpellInfo->Id==19194) // Double Attack + //else if (auraSpellInfo->Id==19817) // Double Attack + //else if (auraSpellInfo->Id==19818) // Double Attack + //else if (auraSpellInfo->Id==22835) // Drunken Rage + // trigger_spell_id = 14822; + /* + else if (auraSpellInfo->SpellIconID==191) // Elemental Response { - // at melee hit call std triggered spell - if(procFlags & PROC_FLAG_HIT_MELEE) - break; // fall through to normal cast - - // Mark of Conquest - else (at range hit) called custom case - triggered_spell_id = 39557; - target = this; - break; + 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; + case SPELL_SCHOOL_FROST: trigger_spell_id = 34193; break; + case SPELL_SCHOOL_ARCANE:trigger_spell_id = 34194; break; + case SPELL_SCHOOL_NATURE:trigger_spell_id = 34195; break; + case SPELL_SCHOOL_SHADOW:trigger_spell_id = 34196; break; + case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197; break; + case SPELL_SCHOOL_NORMAL:trigger_spell_id = 34198; break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id); + return false; + } } - // Shaleskin - case 36576: - return true; // nothing to do - // Forgotten Knowledge (Blade of Wizardry) - case 38319: - // only for harmful enemy targeted spell - if(!pVictim || pVictim==this || !procSpell || IsPositiveSpell(procSpell->Id)) - return false; - break; // fall through to normal cast - // Aura of Wrath (Darkmoon Card: Wrath trinket bonus) - case 39442: - { - // proc only at non-crit hits - if(procFlags & (PROC_FLAG_CRIT_MELEE|PROC_FLAG_CRIT_RANGED|PROC_FLAG_CRIT_SPELL)) - return false; - break; // fall through to normal cast + */ + //else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor + //else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget + //else if (auraSpellInfo->Id==50051) // Ethereal Pet Aura + //else if (auraSpellInfo->Id==35321) // Gushing Wound + //else if (auraSpellInfo->Id==38363) // Gushing Wound + //else if (auraSpellInfo->Id==39215) // Gushing Wound + //else if (auraSpellInfo->Id==44527) // Hate Monster (Spar Buddy) (30 sec) + //else if (auraSpellInfo->Id==44819) // Hate Monster (Spar Buddy) (>30% Health) + //else if (auraSpellInfo->Id==44526) // Hate Monster (Spar) (30 sec) + //else if (auraSpellInfo->Id==44820) // Hate Monster (Spar) (<30%) + //else if (auraSpellInfo->Id==49059) // Horde, Hate Monster (Spar Buddy) (>30% Health) + //else if (auraSpellInfo->Id==40250) // Improved Duration + //else if (auraSpellInfo->Id==59288) // Infra-Green Shield + //else if (auraSpellInfo->Id==54072) // Knockback Ball Passive + else if (auraSpellInfo->Id==27522 || auraSpellInfo->Id==40336) + // 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; } - // Augment Pain (Timbal's Focusing Crystal trinket bonus) - case 45054: + //else if (auraSpellInfo->Id==55580) // Mana Link + //else if (auraSpellInfo->Id==45903) // Offensive State + //else if (auraSpellInfo->Id==44326) // Pure Energy Passive + //else if (auraSpellInfo->Id==43453) // Rune Ward + //else if (auraSpellInfo->Id== 7137) // Shadow Charge (Rank 1) + //else if (auraSpellInfo->Id==36576) // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger + //else if (auraSpellInfo->Id==34783) // Spell Reflection + //else if (auraSpellInfo->Id==36096) // Spell Reflection + //else if (auraSpellInfo->Id==57587) // Steal Ranged () + //else if (auraSpellInfo->Id==36207) // Steal Weapon + //else if (auraSpellInfo->Id== 7377) // Take Immune Periodic Damage <Not Working> + //else if (auraSpellInfo->Id==35205) // Vanish + //else if (auraSpellInfo->Id==42730) // Woe Strike + //else if (auraSpellInfo->Id==59735) // Woe Strike + //else if (auraSpellInfo->Id==46146) // [PH] Ahune Spanky Hands + break; + case SPELLFAMILY_MAGE: + if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed { - if(!procSpell) - return false; - - //only periodic damage can trigger spell - bool found = false; - for(int j = 0; j < 3; ++j) + switch (auraSpellInfo->Id) { - if( procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT || - procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_LEECH ) - { - found = true; + 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; } - if(!found) - return false; - - break; // fall through to normal cast - } - // Evasive Maneuvers (Commendation of Kael'thas) - case 45057: - { - // damage taken that reduces below 35% health - // does NOT mean you must have been >= 35% before - if (int32(GetHealth())-int32(damage) >= int32(GetMaxHealth()*0.35f)) - return false; - break; // fall through to normal cast } - } - - switch(triggered_spell_id) + break; + case SPELLFAMILY_WARRIOR: + if (auraSpellInfo->Id == 50421) // Scent of Blood + trigger_spell_id = 50422; + break; + case SPELLFAMILY_WARLOCK: { - // Setup - case 15250: + // Pyroclasm + if (auraSpellInfo->SpellIconID == 1137) { - // applied only for main target - if(!pVictim || pVictim != getVictim()) + 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; - // continue normal case - break; - } - // Shamanistic Rage triggered spell - case 30824: - basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK)*triggeredByAura->GetModifier()->m_amount/100); - break; - } - break; - } - case SPELLFAMILY_MAGE: - { - switch(auraSpellInfo->SpellIconID) - { - // Blazing Speed - case 2127: - //Blazing Speed (instead non-existed triggered spell) - triggered_spell_id = 31643; - target = this; - break; - } - switch(auraSpellInfo->Id) - { - // Persistent Shield (Scarab Brooch) - case 26467: - basepoints0 = int32(damage * 0.15f); - break; - } - break; - } - case SPELLFAMILY_WARRIOR: - { - //Rampage - if((auraSpellInfo->SpellFamilyFlags & 0x100000) && auraSpellInfo->SpellIconID==2006) - { - //all ranks have effect[0]==AURA (Proc Trigger Spell, non-existed) - //and effect[1]==TriggerSpell - if(auraSpellInfo->Effect[1]!=SPELL_EFFECT_TRIGGER_SPELL) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have wrong effect in RM",triggeredByAura->GetSpellProto()->Id); - return false; - } - triggered_spell_id = auraSpellInfo->EffectTriggerSpell[1]; - break; // fall through to normal cast - } - break; - } - case SPELLFAMILY_WARLOCK: - { - // Pyroclasm - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000 && auraSpellInfo->SpellIconID==1137) - { - // last case for Hellfire that damage caster also but don't must stun caster - if( pVictim == this ) - 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; - // custom chance - float chance = 0; - switch (triggeredByAura->GetId()) - { - case 18096: chance = 13.0f; break; - case 18073: chance = 26.0f; break; + trigger_spell_id = 18093; } - if (!roll_chance_f(chance)) - return false; - - // Pyroclasm (instead non-existed triggered spell) - triggered_spell_id = 18093; - target = pVictim; - break; - } - // Drain Soul - if(auraSpellInfo->SpellFamilyFlags & 0x0000000000004000) - { - bool found = false; - Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); - for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) + // Drain Soul + else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000004000LL) { - //Improved Drain Soul - if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) + Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); + for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) { - int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); - basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100; - // Drain Soul - CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - break; + if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113) + { + int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this); + // Drain Soul + CastCustomSpell(this, 18371, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); + break; + } } + // Not remove charge (aura removed on death in any cases) + // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura + return false; } - // Not remove charge (aura removed on death in any cases) - // Need for correct work Drain Soul SPELL_AURA_CHANNEL_DEATH_ITEM aura - return false; - } - break; - } - case SPELLFAMILY_PRIEST: - { - //Blessed Recovery - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL && auraSpellInfo->SpellIconID==1875) - { - switch (triggeredByAura->GetSpellProto()->Id) + // Nether Protection + else if (auraSpellInfo->SpellIconID == 1985) { - case 27811: triggered_spell_id = 27813; break; - case 27815: triggered_spell_id = 27817; break; - case 27816: triggered_spell_id = 27818; break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR",triggeredByAura->GetSpellProto()->Id); + if (!procSpell) return false; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + case SPELL_SCHOOL_HOLY: + return false; // ignore + case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break; + case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break; + case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break; + case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break; + case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; + default: + return false; + } } - - int32 heal_amount = damage * triggeredByAura->GetModifier()->m_amount / 100; - basepoints0 = heal_amount/3; - target = this; break; } - // Shadowguard - if((auraSpellInfo->SpellFamilyFlags & 0x80000000LL) && auraSpellInfo->SpellVisual==7958) + case SPELLFAMILY_PRIEST: { - switch(triggeredByAura->GetSpellProto()->Id) + // Greater Heal Refund + if (auraSpellInfo->Id==37594) + trigger_spell_id = 37595; + // Blessed Recovery + else if (auraSpellInfo->SpellIconID == 1875) { - case 18137: - triggered_spell_id = 28377; break; // Rank 1 - case 19308: - triggered_spell_id = 28378; break; // Rank 2 - case 19309: - triggered_spell_id = 28379; break; // Rank 3 - case 19310: - triggered_spell_id = 28380; break; // Rank 4 - case 19311: - triggered_spell_id = 28381; break; // Rank 5 - case 19312: - triggered_spell_id = 28382; break; // Rank 6 - case 25477: - triggered_spell_id = 28385; break; // Rank 7 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG",triggeredByAura->GetSpellProto()->Id); + 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; } - target = pVictim; break; } - break; - } - case SPELLFAMILY_DRUID: - { - switch(auraSpellInfo->Id) + case SPELLFAMILY_DRUID: { - // Leader of the Pack (triggering Improved Leader of the Pack heal) - case 24932: - { - if (triggeredByAura->GetModifier()->m_amount == 0) - return false; - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - triggered_spell_id = 34299; - break; - }; - // Druid Forms Trinket (Druid Tier5 Trinket, triggers different spells per Form) - case 37336: + // Druid Forms Trinket + if (auraSpellInfo->Id==37336) { switch(m_form) { + case FORM_NONE: trigger_spell_id = 37344;break; + case FORM_CAT: trigger_spell_id = 37341;break; case FORM_BEAR: - case FORM_DIREBEAR: - triggered_spell_id=37340; break;// Ursine Blessing - case FORM_CAT: - triggered_spell_id=37341; break;// Feline Blessing - case FORM_TREE: - triggered_spell_id=37342; break;// Slyvan Blessing - case FORM_MOONKIN: - triggered_spell_id=37343; break;// Lunar Blessing - case FORM_NONE: - triggered_spell_id=37344; break;// Cenarion Blessing (for caster form, except FORM_MOONKIN) + 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; } - - target = this; - break; } - } - break; - } - case SPELLFAMILY_ROGUE: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000LL) - { - switch(auraSpellInfo->SpellIconID) + //else if (auraSpellInfo->Id==40363)// Entangling Roots () + // trigger_spell_id = ????; + // Leader of the Pack + else if (auraSpellInfo->Id == 24932) { - // Combat Potency - case 2260: - { - // skip non offhand attacks - if(attackType!=OFF_ATTACK) - return false; - break; // fall through to normal cast - } + if (triggerAmount == 0) + return false; + basepoints0 = triggerAmount * GetMaxHealth() / 100; + trigger_spell_id = 34299; } + break; } - break; - } - case SPELLFAMILY_PALADIN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x00000000LL) + case SPELLFAMILY_HUNTER: + break; + case SPELLFAMILY_PALADIN: { - switch(auraSpellInfo->Id) + /* + // Blessed Life + if (auraSpellInfo->SpellIconID == 2137) { - // Lightning Capacitor - case 37657: + switch (auraSpellInfo->Id) { - // trinket ProcTriggerSpell but for safe checks for player - if(!castItem || !pVictim || !pVictim->isAlive() || GetTypeId()!=TYPEID_PLAYER) - return false; - - if(((Player*)this)->HasSpellCooldown(37657)) - return false; - - // stacking - CastSpell(this, 37658, true, castItem, triggeredByAura); - // 2.5s cooldown before it can stack again, current system allow 1 sec step in cooldown - ((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3)); - - // counting - Aura * dummy = GetDummyAura(37658); - if (!dummy) + 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; - - // release at 3 aura in stack - if(dummy->GetStackAmount() <= 2) - return true; // main triggered spell casted anyway - - RemoveAurasDueToSpell(37658); - CastSpell(pVictim, 37661, true, castItem, triggeredByAura); - return true; - } - // Healing Discount - case 37705: - // Healing Trance (instead non-existed triggered spell) - triggered_spell_id = 37706; - target = this; - break; - // HoTs on Heals (Fel Reaver's Piston trinket) - case 38299: - { - // at direct heal effect - if(!procSpell || !IsSpellHaveEffect(procSpell,SPELL_EFFECT_HEAL)) - return false; - - // single proc at time - AuraList const& scAuras = GetSingleCastAuras(); - for(AuraList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) - if((*itr)->GetId()==triggered_spell_id) - return false; - - // positive cast at victim instead self - target = pVictim; - break; } } - switch(auraSpellInfo->SpellIconID) + */ + // Healing Discount + if (auraSpellInfo->Id==37705) { - case 241: - { - switch(auraSpellInfo->EffectTriggerSpell[0]) - { - //Illumination - case 18350: - { - 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->SpellFamilyName == SPELLFAMILY_PALADIN) - { - if(procSpell->SpellFamilyFlags & 0x0001000000000000LL) - { - 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 - int32 percent = auraSpellInfo->EffectBasePoints[1]+1; - - basepoints0 = originalSpell->manaCost*percent/100; - triggered_spell_id = 20272; - target = this; - break; - } - } - break; - } + trigger_spell_id = 37706; + target = this; } - } - if(auraSpellInfo->SpellFamilyFlags & 0x00080000) - { - switch(auraSpellInfo->SpellIconID) + // Soul Preserver + if (auraSpellInfo->Id==60510) { - //Judgement of Wisdom (overwrite non existing triggered spell call in spell.dbc - case 206: + trigger_spell_id = 60515; + target = this; + } + // 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) { - if(!pVictim || !pVictim->isAlive()) - return false; - - switch(triggeredByAura->GetSpellProto()->Id) + switch(procSpell->Id) { - case 20186: - triggered_spell_id = 20268; // Rank 1 - break; - case 20354: - triggered_spell_id = 20352; // Rank 2 - break; - case 20355: - triggered_spell_id = 20353; // Rank 3 - break; - case 27164: - triggered_spell_id = 27165; // Rank 4 - break; + 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 JoW",triggeredByAura->GetSpellProto()->Id); - return false; + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id); + return false; } - - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown } - //Judgement of Light - case 299: + SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId); + if(!originalSpell) { - if(!pVictim || !pVictim->isAlive()) - return false; - - // overwrite non existing triggered spell call in spell.dbc - switch(triggeredByAura->GetSpellProto()->Id) - { - case 20185: - triggered_spell_id = 20267; // Rank 1 - break; - case 20344: - triggered_spell_id = 20341; // Rank 2 - break; - case 20345: - triggered_spell_id = 20342; // Rank 3 - break; - case 20346: - triggered_spell_id = 20343; // Rank 4 - break; - case 27162: - triggered_spell_id = 27163; // Rank 5 - break; - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in JoL",triggeredByAura->GetSpellProto()->Id); - return false; - } - pVictim->CastSpell(pVictim,triggered_spell_id,true,castItem,triggeredByAura,GetGUID()); - return true; // no hidden cooldown + 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; } - } - // custom check for proc spell - switch(auraSpellInfo->Id) - { - // Bonus Healing (item spell) - case 40971: + // Lightning Capacitor + else if (auraSpellInfo->Id==37657) { if(!pVictim || !pVictim->isAlive()) return false; - - // bonus if health < 50% - if(pVictim->GetHealth() >= pVictim->GetMaxHealth()*triggeredByAura->GetModifier()->m_amount/100) + // 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() < triggerAmount) return false; - // cast at target positive spell + RemoveAurasDueToSpell(37658); + trigger_spell_id = 37661; target = pVictim; - break; } - } - switch(triggered_spell_id) - { - // Seal of Command - case 20424: - // prevent chain of triggered spell from same triggered spell - if(procSpell && procSpell->Id==20424) + // Thunder Capacitor + else if (auraSpellInfo->Id == 54841) + { + if(!pVictim || !pVictim->isAlive()) return false; - break; + // stacking + CastSpell(this, 54842, true, NULL, triggeredByAura); + // counting + uint32 count = 0; + AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr) + if((*itr)->GetId()==54842) + ++count; + // release at 3 aura in stack (cont contain in basepoint of trigger aura) + if(count < triggerAmount) + return false; + + RemoveAurasDueToSpell(54842); + trigger_spell_id = 54843; + target = pVictim; + } + break; } - break; - } - case SPELLFAMILY_SHAMAN: - { - if(auraSpellInfo->SpellFamilyFlags == 0x0000000000000000) + case SPELLFAMILY_SHAMAN: { - switch(auraSpellInfo->SpellIconID) + // Lightning Shield (overwrite non existing triggered spell call in spell.dbc + if(auraSpellInfo->SpellFamilyFlags & 0x0000000000000400) { - case 19: - { - switch(auraSpellInfo->Id) - { - case 23551: // Lightning Shield - Tier2: 8 pieces proc shield - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 23552; - target = pVictim; - break; - } - case 23552: // Lightning Shield - trigger shield damage - { - // Lightning Shield (overwrite non existing triggered spell call in spell.dbc) - triggered_spell_id = 27635; - target = pVictim; - break; - } - } - break; - } - // Mana Surge (Shaman T1 bonus) - case 87: + switch(auraSpellInfo->Id) { - if(!procSpell) - return false; - - basepoints0 = procSpell->manaCost * 35/100; - triggered_spell_id = 23571; - target = this; - break; + case 324: // Rank 1 + trigger_spell_id = 26364; break; + case 325: // Rank 2 + trigger_spell_id = 26365; break; + case 905: // Rank 3 + trigger_spell_id = 26366; break; + case 945: // Rank 4 + trigger_spell_id = 26367; break; + case 8134: // Rank 5 + trigger_spell_id = 26369; break; + case 10431: // Rank 6 + trigger_spell_id = 26370; break; + case 10432: // Rank 7 + trigger_spell_id = 26363; break; + case 25469: // Rank 8 + trigger_spell_id = 26371; break; + case 25472: // Rank 9 + trigger_spell_id = 26372; break; + case 49280: // Rank 10 + trigger_spell_id = 49278; break; + case 49281: // Rank 11 + trigger_spell_id = 49279; break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id); + return false; } - //Nature's Guardian - case 2013: - { - if(GetTypeId()!=TYPEID_PLAYER) - return false; - - // damage taken that reduces below 30% health - // does NOT mean you must have been >= 30% before - if (10*(int32(GetHealth())-int32(damage)) >= 3*GetMaxHealth()) - return false; - - triggered_spell_id = 31616; + } + // 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; + } + // Nature's Guardian + else if (auraSpellInfo->SpellIconID == 2013) + { + // Check health condition - should drop to less 30% (damage deal after this!) + if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth())) + return false; - // need check cooldown now - if( cooldown && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; + if(pVictim && pVictim->isAlive()) + pVictim->getThreatManager().modifyThreatPercent(this,-10); - basepoints0 = triggeredByAura->GetModifier()->m_amount * GetMaxHealth() / 100; - target = this; - if(pVictim && pVictim->isAlive()) - pVictim->getThreatManager().modifyThreatPercent(this,-10); - break; - } + basepoints0 = triggerAmount * GetMaxHealth() / 100; + trigger_spell_id = 31616; + target = this; } - } - - // Water Shield (we can't set cooldown for main spell - it's player casted spell - if((auraSpellInfo->SpellFamilyFlags & 0x0000002000000000LL) && auraSpellInfo->SpellVisual==7358) - { - target = this; break; } - - // Lightning Shield - if((auraSpellInfo->SpellFamilyFlags & 0x00000400) && auraSpellInfo->SpellVisual==37) + case SPELLFAMILY_DEATHKNIGHT: { - // overwrite non existing triggered spell call in spell.dbc - switch(triggeredByAura->GetSpellProto()->Id) + // Acclimation + if (auraSpellInfo->SpellIconID == 1930) { - case 324: - triggered_spell_id = 26364; break; // Rank 1 - case 325: - triggered_spell_id = 26365; break; // Rank 2 - case 905: - triggered_spell_id = 26366; break; // Rank 3 - case 945: - triggered_spell_id = 26367; break; // Rank 4 - case 8134: - triggered_spell_id = 26369; break; // Rank 5 - case 10431: - triggered_spell_id = 26370; break; // Rank 6 - case 10432: - triggered_spell_id = 26363; break; // Rank 7 - case 25469: - triggered_spell_id = 26371; break; // Rank 8 - case 25472: - triggered_spell_id = 26372; break; // Rank 9 - default: - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield",triggeredByAura->GetSpellProto()->Id); + if (!procSpell) + return false; + switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) + { + case SPELL_SCHOOL_NORMAL: + return false; // ignore + case SPELL_SCHOOL_HOLY: trigger_spell_id = 50490; break; + case SPELL_SCHOOL_FIRE: trigger_spell_id = 50362; break; + case SPELL_SCHOOL_NATURE: trigger_spell_id = 50488; break; + case SPELL_SCHOOL_FROST: trigger_spell_id = 50485; break; + case SPELL_SCHOOL_SHADOW: trigger_spell_id = 50489; break; + case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; + default: + return false; + } + } + // Blood Presence + else if (auraSpellInfo->Id == 48266) + { + if (GetTypeId() != TYPEID_PLAYER) return false; + if (!((Player*)this)->isHonorOrXPTarget(pVictim)) + return false; + trigger_spell_id = 50475; + basepoints0 = damage * triggerAmount / 100; } - - target = pVictim; break; } - break; - } - } - - // standard non-dummy case - if(!triggered_spell_id) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex()); - return false; - } - - SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - - if(!triggerEntry) - { - sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have not existed EffectTriggered[%d]=%u, not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex(),triggered_spell_id); - return false; - } - - // not allow proc extra attack spell at extra attack - if( m_extraAttacks && IsSpellHaveEffect(triggerEntry,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) - return false; - - if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) - return false; - - // default case - if(!target || target!=this && !target->isAlive()) - return false; - - if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); - - if( cooldown && GetTypeId()==TYPEID_PLAYER ) - ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - - 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 + default: 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 @@ -7724,21 +6269,21 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAur { case 836: // Improved Blizzard (Rank 1) { - if (!procSpell || procSpell->SpellVisual!=9487) + if (!procSpell || procSpell->SpellVisual[0]!=9487) return false; triggered_spell_id = 12484; break; } case 988: // Improved Blizzard (Rank 2) { - if (!procSpell || procSpell->SpellVisual!=9487) + if (!procSpell || procSpell->SpellVisual[0]!=9487) return false; triggered_spell_id = 12485; break; } case 989: // Improved Blizzard (Rank 3) { - if (!procSpell || procSpell->SpellVisual!=9487) + if (!procSpell || procSpell->SpellVisual[0]!=9487) return false; triggered_spell_id = 12486; break; @@ -7916,11 +6461,11 @@ bool Unit::IsHostileTo(Unit const* unit) const return false; // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return false; // PvP FFA state - if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) + if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP)) return true; //= PvP states @@ -8025,11 +6570,11 @@ bool Unit::IsFriendlyTo(Unit const* unit) const return true; // Sanctuary - if(pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY) && pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_SANCTUARY)) + if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return true; // PvP FFA state - if(pTester->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && pTarget->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP)) + if(pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP) && pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP)) return false; //= PvP states @@ -8393,6 +6938,9 @@ void Unit::SetPet(Pet* pet) void Unit::SetCharm(Unit* pet) { SetUInt64Value(UNIT_FIELD_CHARM, pet ? pet->GetGUID() : 0); + + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->m_mover = pet ? pet : this; } void Unit::AddPlayerToVision(Player* plr) @@ -8471,6 +7019,7 @@ void Unit::SendHealSpellLog(Unit *pVictim, uint32 SpellID, uint32 Damage, bool c data.append(GetPackGUID()); data << uint32(SpellID); data << uint32(Damage); + data << uint32(0); // over healing? data << uint8(critical ? 1 : 0); data << uint8(0); // unused in client? SendMessageToSet(&data, true); @@ -8657,7 +7206,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 CastingTime = 0; } // Darkmoon Card: Vengeance - 0.1% - else if (spellProto->SpellVisual == 9850 && spellProto->SpellIconID == 2230) + else if (spellProto->SpellVisual[0] == 9850 && spellProto->SpellIconID == 2230) { CastingTime = 3.5; } @@ -8925,14 +7474,8 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask) { if((*i)->GetModifier()->m_miscvalue & schoolMask) { - SpellEntry const* iSpellProto = (*i)->GetSpellProto(); - uint8 eff = (*i)->GetEffIndex(); - - // stat used dependent from next effect aura SPELL_AURA_MOD_SPELL_HEALING presence and misc value (stat index) - Stats usedStat = STAT_INTELLECT; - if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT) - usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]); - + // stat used stored in miscValueB for this aura + Stats usedStat = Stats((*i)->GetMiscBValue()); DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f); } } @@ -9024,7 +7567,6 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM if (pVictim) { crit_chance = GetUnitCriticalChance(attackType, pVictim); - crit_chance+= (int32(GetMaxSkillValueForLevel(pVictim)) - int32(pVictim->GetDefenseSkillValue(this))) * 0.04f; crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); } break; @@ -9104,7 +7646,7 @@ uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) { - if((*i)->GetSpellProto()->SpellVisual == 9180) + if((*i)->GetSpellProto()->SpellVisual[0] == 9180) { // Flash of Light if ((spellProto->SpellFamilyFlags & 0x0000000040000000LL) && (*i)->GetEffIndex() == 1) @@ -9684,7 +8226,7 @@ void Unit::Unmount() if(GetTypeId() == TYPEID_PLAYER && IsInWorld() && ((Player*)this)->GetTemporaryUnsummonedPetNumber() && isAlive()) { Pet* NewPet = new Pet; - if(!NewPet->LoadPetFromDB(this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) + if(!NewPet->LoadPetFromDB((Player*)this, 0, ((Player*)this)->GetTemporaryUnsummonedPetNumber(), true)) delete NewPet; ((Player*)this)->SetTemporaryUnsummonedPetNumber(0); @@ -10124,38 +8666,37 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) propagateSpeedChange(); - // Send speed change packet only for player - if (GetTypeId()!=TYPEID_PLAYER) - return; - WorldPacket data; if(!forced) { switch(mtype) { case MOVE_WALK: - data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_RUN: - data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_RUN_BACK: - data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_SWIM: - data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_SWIM_BACK: - data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_TURN_RATE: - data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_TURN_RATE, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_FLIGHT: - data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8+4+2+4+4+4+4+4+4+4); break; case MOVE_FLIGHT_BACK: - data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+1+4+4+4+4+4+4+4); + data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8+4+2+4+4+4+4+4+4+4); + break; + case MOVE_PITCH_RATE: + data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8+4+2+4+4+4+4+4+4+4); break; default: sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); @@ -10163,22 +8704,26 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) } data.append(GetPackGUID()); - data << uint32(0); //movement flags - data << uint8(0); //unk + data << uint32(0); // movement flags + data << uint16(0); // unk flags data << uint32(getMSTime()); data << float(GetPositionX()); data << float(GetPositionY()); data << float(GetPositionZ()); data << float(GetOrientation()); - data << uint32(0); //flag unk + data << uint32(0); // fall time data << float(GetSpeed(mtype)); SendMessageToSet( &data, true ); } else { - // register forced speed changes for WorldSession::HandleForceSpeedChangeAck - // and do it only for real sent packets and use run for run/mounted as client expected - ++((Player*)this)->m_forced_speed_changes[mtype]; + if(GetTypeId() == TYPEID_PLAYER) + { + // register forced speed changes for WorldSession::HandleForceSpeedChangeAck + // and do it only for real sent packets and use run for run/mounted as client expected + ++((Player*)this)->m_forced_speed_changes[mtype]; + } + switch(mtype) { case MOVE_WALK: @@ -10205,6 +8750,9 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced) case MOVE_FLIGHT_BACK: data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16); break; + case MOVE_PITCH_RATE: + data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16); + break; default: sLog.outError("Unit::SetSpeed: Unsupported move type (%d), data not sent to client.",mtype); return; @@ -10294,6 +8842,10 @@ bool Unit::CanHaveThreatList() const if( ((Creature*)this)->isTotem() ) return false; + // vehicles can not have threat list + if( ((Creature*)this)->isVehicle() ) + return false; + // pets can not have a threat list, unless they are controlled by a creature if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) ) return false; @@ -10487,8 +9039,11 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde int32 randomPoints = int32(spellProto->EffectDieSides[effect_index] + level * randomPointsPerLevel); float comboDamage = spellProto->EffectPointsPerComboPoint[effect_index]; - // prevent random generator from getting confused by spells casted with Unit::CastCustomSpell - int32 randvalue = spellProto->EffectBaseDice[effect_index] >= randomPoints ? spellProto->EffectBaseDice[effect_index]:irand(spellProto->EffectBaseDice[effect_index], randomPoints); + // range can have possitive and negative values, so order its for irand + int32 randvalue = int32(spellProto->EffectBaseDice[effect_index]) >= randomPoints + ? irand(randomPoints, int32(spellProto->EffectBaseDice[effect_index])) + : irand(int32(spellProto->EffectBaseDice[effect_index]), randomPoints); + int32 value = basePoints + randvalue; //random damage if(comboDamage != 0 && unitPlayer /*&& target && (target->GetGUID() == unitPlayer->GetComboTarget())*/) @@ -10542,6 +9097,8 @@ int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, uint8 effect_in int32 mechanic = GetEffectMechanic(spellProto, effect_index); // Find total mod value (negative bonus) int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic); + // Modify from SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL aura (stack always ?) + durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel); // Find max mod (negative bonus) int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic); @@ -10743,7 +9300,9 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f case UNIT_MOD_RAGE: case UNIT_MOD_FOCUS: case UNIT_MOD_ENERGY: - case UNIT_MOD_HAPPINESS: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; + case UNIT_MOD_HAPPINESS: + case UNIT_MOD_RUNE: + case UNIT_MOD_RUNIC_POWER: UpdateMaxPower(GetPowerTypeByAuraGroup(unitMod)); break; case UNIT_MOD_RESISTANCE_HOLY: case UNIT_MOD_RESISTANCE_FIRE: @@ -10856,21 +9415,18 @@ Stats Unit::GetStatByAuraGroup(UnitMods unitMod) const Powers Unit::GetPowerTypeByAuraGroup(UnitMods unitMod) const { - Powers power = POWER_MANA; - switch(unitMod) { - case UNIT_MOD_MANA: power = POWER_MANA; break; - case UNIT_MOD_RAGE: power = POWER_RAGE; break; - case UNIT_MOD_FOCUS: power = POWER_FOCUS; break; - case UNIT_MOD_ENERGY: power = POWER_ENERGY; break; - case UNIT_MOD_HAPPINESS: power = POWER_HAPPINESS; break; - - default: - break; + case UNIT_MOD_MANA: return POWER_MANA; + case UNIT_MOD_RAGE: return POWER_RAGE; + case UNIT_MOD_FOCUS: return POWER_FOCUS; + case UNIT_MOD_ENERGY: return POWER_ENERGY; + case UNIT_MOD_HAPPINESS: return POWER_HAPPINESS; + case UNIT_MOD_RUNE: return POWER_RUNE; + case UNIT_MOD_RUNIC_POWER:return POWER_RUNIC_POWER; } - return power; + return POWER_MANA; } float Unit::GetTotalAttackPowerValue(WeaponAttackType attType) const @@ -10969,6 +9525,12 @@ void Unit::SetPower(Powers power, uint32 val) SetStatInt32Value(UNIT_FIELD_POWER1 + power, val); + WorldPacket data(SMSG_POWER_UPDATE); + data.append(GetPackGUID()); + data << uint8(power); + data << uint32(val); + SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER ? true : false); + // group update if(GetTypeId() == TYPEID_PLAYER) { @@ -11082,6 +9644,7 @@ uint32 Unit::GetCreatePowers( Powers power ) const case POWER_FOCUS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 100); case POWER_ENERGY: return 100; case POWER_HAPPINESS: return (GetTypeId()==TYPEID_PLAYER || !((Creature const*)this)->isPet() || ((Pet const*)this)->getPetType()!=HUNTER_PET ? 0 : 1050000); + case POWER_RUNIC_POWER: return 1000; } return 0; @@ -11169,7 +9732,7 @@ void CharmInfo::InitEmptyActionBar(bool withAttack) for(uint32 x = 0; x < 10; ++x) { - PetActionBar[x].Type = ACT_CAST; + PetActionBar[x].Type = ACT_PASSIVE; PetActionBar[x].SpellOrAction = 0; } if (withAttack) @@ -11185,13 +9748,20 @@ void CharmInfo::InitPossessCreateSpells() InitEmptyActionBar(); if(m_unit->GetTypeId() == TYPEID_UNIT) { - for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + /*for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) { uint32 spellid = ((Creature*)m_unit)->m_spells[i]; if(IsPassiveSpell(spellid)) m_unit->CastSpell(m_unit, spellid, true); else AddSpellToAB(0, spellid, ACT_CAST); + }*/ + for(uint32 x = 0; x < CREATURE_MAX_SPELLS; ++x) + { + if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) + m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); + else + AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); } } } @@ -11235,7 +9805,7 @@ void CharmInfo::InitCharmCreateSpells() if(onlyselfcast || !IsPositiveSpell(spellId)) //only self cast and spells versus enemies are autocastable newstate = ACT_DISABLED; else - newstate = ACT_CAST; + newstate = ACT_PASSIVE; AddSpellToAB(0, spellId, newstate); } @@ -11246,7 +9816,7 @@ bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) { for(uint8 i = 0; i < 10; i++) { - if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_CAST) && PetActionBar[i].SpellOrAction == oldid) + if((PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) && PetActionBar[i].SpellOrAction == oldid) { PetActionBar[i].SpellOrAction = newid; if(!oldid) @@ -11295,181 +9865,6 @@ bool Unit::isFrozen() const return false; } -/* -struct ProcTriggeredData -{ - ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown) - : triggeredByAura(_triggeredByAura), - triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex())), - cooldown(_cooldown) - {} - - Aura* triggeredByAura; // triggred aura, can be invalidate at triggered aura proccessing - Unit::spellEffectPair triggeredByAura_SpellPair; // spell pair, used for re-find aura (by pointer comparison in range) - uint32 cooldown; // possible hidden cooldown -}; - -typedef std::list< ProcTriggeredData > ProcTriggeredList; - -void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ) -{ - for(AuraTypeSet::const_iterator aur = procAuraTypes.begin(); aur != procAuraTypes.end(); ++aur) - { - // List of spells (effects) that proceed. Spell prototype and aura-specific value (damage for TRIGGER_DAMAGE) - ProcTriggeredList procTriggered; - - AuraList const& auras = GetAurasByType(*aur); - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - - Aura* i_aura = *i; - - uint32 cooldown; // returned at next line - if(!IsTriggeredAtSpellProcEvent(i_aura->GetSpellProto(), procSpell, procFlag,attType,isVictim,cooldown)) - continue; - - procTriggered.push_back( ProcTriggeredData(i_aura, cooldown) ); - } - - // 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 auras 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.outError("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler",*aur,i->triggeredByAura_SpellPair.first,i->triggeredByAura_SpellPair.second); - sLog.outError("It can be deleted one from early processed auras:"); - for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2) - sLog.outError(" Spell aura %u (id:%u effect:%u)",*aur,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second); - sLog.outError(" <end of list>"); - continue; - } - } - - /// this is aura triggering code call - Aura* triggeredByAura = i->triggeredByAura; - - /// save charges existence before processing to prevent crash at access to deleted triggered aura after - /// used in speedup code check before check aura existance. - bool triggeredByAuraWithCharges = triggeredByAura->m_procCharges > 0; - - /// success in event proccesing - /// used in speedup code check before check aura existance. - bool casted = false; - - /// process triggered code - switch(*aur) - { - case SPELL_AURA_PROC_TRIGGER_SPELL: - { - sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s proc aura of spell %u)", - (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - casted = HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, attType, i->cooldown); - break; - } - case SPELL_AURA_PROC_TRIGGER_DAMAGE: - { - uint32 triggered_damage = triggeredByAura->GetModifier()->m_amount; - sLog.outDebug("ProcDamageAndSpell: doing %u damage (triggered by %s aura of spell %u)", - triggered_damage, (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - SpellNonMeleeDamageLog(pTarget, triggeredByAura->GetId(), triggered_damage, true, true); - casted = true; - break; - } - case SPELL_AURA_DUMMY: - { - uint32 effect = triggeredByAura->GetEffIndex(); - sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s dummy aura of spell %u)", - (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - casted = HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown); - 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()); - - casted = HandleMeandingAuraProc(triggeredByAura); - break; - } - case SPELL_AURA_MOD_HASTE: - { - sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s haste aura of spell %u)", - (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - casted = HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag,i->cooldown); - break; - } - case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - { - // nothing do, just charges counter - // but count only in case appropriate school damage - casted = triggeredByAura->GetModifier()->m_miscvalue & damageSchoolMask; - break; - } - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - { - sLog.outDebug("ProcDamageAndSpell: casting spell (triggered by %s class script aura of spell %u)", - (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); - casted = HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell,i->cooldown); - break; - } - default: - { - // nothing do, just charges counter - casted = true; - break; - } - } - - /// Update charge (aura can be removed by triggers) - if(casted && triggeredByAuraWithCharges) - { - /// need re-found aura (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 == triggeredByAura) // pointer still valid - { - if(triggeredByAura->m_procCharges > 0) - triggeredByAura->m_procCharges -= 1; - - triggeredByAura->UpdateAuraCharges(); - break; - } - } - } - } - - /// Safely remove auras with zero charges - for(AuraList::const_iterator i = auras.begin(), next; i != auras.end(); i = next) - { - next = i; ++next; - if((*i)->m_procCharges == 0) - { - RemoveAurasDueToSpell((*i)->GetId()); - next = auras.begin(); - } - } - } -} -*/ struct ProcTriggeredData { ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura) @@ -11488,15 +9883,14 @@ typedef std::list< uint32> RemoveSpellList; // 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() +bool InitTriggerAuraData() { for (int i=0;i<TOTAL_AURAS;i++) { isTriggerAura[i]=false; isNonTriggerAura[i] = false; } + isTriggerAura[SPELL_AURA_PERIODIC_DAMAGE] = true; isTriggerAura[SPELL_AURA_DUMMY] = true; isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; isTriggerAura[SPELL_AURA_MOD_THREAT] = true; @@ -11524,9 +9918,12 @@ void InitTriggerAuraData() isTriggerAura[SPELL_AURA_MOD_HASTE] = true; isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE]=true; isTriggerAura[SPELL_AURA_PRAYER_OF_MENDING] = true; + isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true; isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true; isNonTriggerAura[SPELL_AURA_RESIST_PUSHBACK]=true; + + return true; } uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition) @@ -11567,18 +9964,8 @@ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missC 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) { @@ -11641,17 +10028,6 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag ((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 ); - } - } } } } @@ -11662,7 +10038,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag 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)) + if(!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent)) continue; procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) ); @@ -11757,6 +10133,14 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag HandleMeandingAuraProc(triggeredByAura); break; } + case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: + { + sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + + if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + continue; + break; + } case SPELL_AURA_MOD_STUN: // Remove by default, but if charge exist drop it if (triggeredByAura->m_procCharges == 0) @@ -11833,7 +10217,6 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++) RemoveAurasDueToSpell(*i); } - deep--; } SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const @@ -11862,8 +10245,11 @@ void Unit::SendPetCastFail(uint32 spellid, uint8 msg) return; WorldPacket data(SMSG_PET_CAST_FAILED, (4+1)); + data << uint8(0); // cast count? data << uint32(spellid); data << uint8(msg); + // uint32 for some reason + // uint32 for some reason ((Player*)owner)->GetSession()->SendPacket(&data); } @@ -12085,7 +10471,6 @@ void Unit::ClearComboPointHolders() void Unit::ClearAllReactives() { - for(int i=0; i < MAX_REACTIVE; ++i) m_reactiveTimer[i] = 0; @@ -12093,11 +10478,6 @@ void Unit::ClearAllReactives() ModifyAuraState(AURA_STATE_DEFENSE, false); if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_PARRY)) ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); - if (HasAuraState( AURA_STATE_CRIT)) - ModifyAuraState(AURA_STATE_CRIT, false); - if (getClass() == CLASS_HUNTER && HasAuraState( AURA_STATE_HUNTER_CRIT_STRIKE) ) - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); - if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) ((Player*)this)->ClearComboPoints(); } @@ -12125,14 +10505,6 @@ void Unit::UpdateReactives( uint32 p_time ) if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_PARRY)) ModifyAuraState(AURA_STATE_HUNTER_PARRY, false); break; - case REACTIVE_CRIT: - if (HasAuraState(AURA_STATE_CRIT)) - ModifyAuraState(AURA_STATE_CRIT, false); - break; - case REACTIVE_HUNTER_CRIT: - if ( getClass() == CLASS_HUNTER && HasAuraState(AURA_STATE_HUNTER_CRIT_STRIKE) ) - ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, false); - break; case REACTIVE_OVERPOWER: if(getClass() == CLASS_WARRIOR && GetTypeId() == TYPEID_PLAYER) ((Player*)this)->ClearComboPoints(); @@ -12185,6 +10557,16 @@ Unit* Unit::SelectNearbyTarget(float dist) const return *tcIter; } +bool Unit::hasNegativeAuraWithInterruptFlag(uint32 flag) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ++iter) + { + if (!iter->second->IsPositive() && iter->second->GetSpellProto()->AuraInterruptFlags & flag) + return true; + } + return false; +} + void Unit::ApplyAttackTimePercentMod( WeaponAttackType att,float val, bool apply ) { float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]); @@ -12417,7 +10799,13 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id) pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, spell_id); - if(!pet->InitStatsForLevel(creatureTarget->getLevel())) + if(GetTypeId()==TYPEID_PLAYER) + pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + + uint32 level = (creatureTarget->getLevel() < (getLevel() - 5)) ? (getLevel() - 5) : creatureTarget->getLevel(); + pet->SetFreeTalentPoints(pet->GetMaxTalentPointsForLevel(level)); + + if(!pet->InitStatsForLevel(level)) { sLog.outError("ERROR: Pet::InitStatsForLevel() failed for creature (Entry: %u)!",creatureTarget->GetEntry()); delete pet; @@ -12433,7 +10821,7 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id) return pet; } -bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ) +bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent ) { SpellEntry const* spellProto = aura->GetSpellProto (); @@ -12463,7 +10851,17 @@ bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell, 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) + // In most cases req get honor or XP from kill + if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER) + { + bool allow = ((Player*)this)->isHonorOrXPTarget(pVictim); + // Shadow Word: Death - can trigger from every kill + if (aura->GetId() == 32409) + allow = true; + if (!allow) + return false; + } + // Aura added by spell can`t trogger from self (prevent drop charges/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; @@ -12548,10 +10946,8 @@ bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura ) mod->value = jumps-5; // negative mod->type = SPELLMOD_FLAT; mod->spellId = spellProto->Id; - mod->effectId = effIdx; - mod->lastAffected = NULL; - mod->mask = spellProto->SpellFamilyFlags; - mod->charges = 0; + mod->mask = spellProto->SpellFamilyFlags; + mod->mask2 = spellProto->SpellFamilyFlags2; caster->AddSpellMod(mod, true); CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID()); @@ -12607,7 +11003,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) if(player && player!=pVictim) { if(player->RewardPlayerAndGroupAtKill(pVictim)) - player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED, PROC_EX_NONE, 0); + player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); else player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0); } @@ -12739,6 +11135,15 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) bg->HandleKillUnit((Creature*)pVictim, player); } } + + // achievement stuff + if ( pVictim->GetTypeId() == TYPEID_PLAYER) + { + if(GetTypeId() == TYPEID_UNIT) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry()); + else if(GetTypeId() == TYPEID_PLAYER) + ((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1); + } } void Unit::SetControlled(bool apply, UnitState state) @@ -12808,7 +11213,7 @@ void Unit::SetStunned(bool apply) if(apply) { SetUInt64Value(UNIT_FIELD_TARGET, 0); - SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE); + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); CastStop(); // Creature specific @@ -12826,7 +11231,7 @@ void Unit::SetStunned(bool apply) { if(isAlive() && getVictim()) SetUInt64Value(UNIT_FIELD_TARGET, getVictim()->GetGUID()); - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE); + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); if(!hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect { @@ -13047,4 +11452,61 @@ void Unit::AddAura(uint32 spellId, Unit* target) } } } -}
\ No newline at end of file +} + +// 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(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const +{ + // Calculate hit chance (more correct for chance mod) + int32 HitChance; + + // PvP - PvE melee chances + /*int32 lchance = pVictim->GetTypeId() == TYPEID_PLAYER ? 5 : 7; + int32 leveldif = pVictim->getLevelForTarget(this) - getLevelForTarget(pVictim); + if(leveldif < 3) + HitChance = 95 - leveldif; + else + HitChance = 93 - (leveldif - 2) * lchance;*/ + if (spellId || attType == RANGED_ATTACK || !haveOffhandWeapon()) + HitChance = 95.0f; + else + HitChance = 76.0f; + + // Hit chance depends from victim auras + if(attType == RANGED_ATTACK) + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE); + else + HitChance += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE); + + // Spellmod from SPELLMOD_RESIST_MISS_CHANCE + if(spellId) + { + if(Player *modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, HitChance); + } + + // Miss = 100 - hit + float miss_chance= 100.0f - HitChance; + + // Bonuses from attacker aura and ratings + if (attType == RANGED_ATTACK) + miss_chance -= m_modRangedHitChance; + else + miss_chance -= m_modMeleeHitChance; + + // bonus from skills is 0.04% + //miss_chance -= skillDiff * 0.04f; + int32 diff = -skillDiff; + if(pVictim->GetTypeId()==TYPEID_PLAYER) + miss_chance += diff > 0 ? diff * 0.04 : diff * 0.02; + else + miss_chance += diff > 10 ? 2 + (diff - 10) * 0.4 : diff * 0.1; + + // Limit miss chance from 0 to 60% + if (miss_chance < 0.0f) + return 0.0f; + if (miss_chance > 60.0f) + return 60.0f; + return miss_chance; +} |