aboutsummaryrefslogtreecommitdiff
path: root/src/game/Unit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Unit.cpp')
-rw-r--r--src/game/Unit.cpp1487
1 files changed, 947 insertions, 540 deletions
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index e107eb90f55..74eda6482d0 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -60,7 +60,7 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
{
2.5f, // MOVE_WALK
7.0f, // MOVE_RUN
- 1.25f, // MOVE_RUN_BACK
+ 3.0f, // MOVE_RUN_BACK
4.722222f, // MOVE_SWIM
4.5f, // MOVE_SWIM_BACK
3.141594f, // MOVE_TURN_RATE
@@ -211,13 +211,20 @@ void Unit::Update( uint32 p_time )
m_Events.Update( p_time );
_UpdateSpells( p_time );
- // update combat timer only for players and pets
- if (isInCombat() && IsControlledByPlayer())
+ // If this is set during update SetCantProc(false) call is missing somewhere in the code
+ // Having this would prevent spells from being proced, so let's crash
+ assert(!m_procDeep);
+
+ if (CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time))
+ SendThreatListUpdate();
+
+ // update combat timer only for players and pets (only pets with PetAI)
+ if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || (((Creature *)this)->isPet() && IsControlledByPlayer())))
{
// Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away
// targets without stopping half way there and running off.
// These flags are reset after target dies or another command is given.
- if( m_HostilRefManager.isEmpty() )
+ if( m_HostilRefManager.isEmpty())
{
// m_CombatTimer set at aura start and it will be freeze until aura removing
if ( m_CombatTimer <= p_time )
@@ -546,6 +553,22 @@ void Unit::RemoveAurasWithFamily(uint32 family, uint32 familyFlag1, uint32 famil
}
}
+void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, uint32 except)
+{
+ for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)
+ {
+ if (!except || iter->second->GetId() != except)
+ {
+ if(GetAllSpellMechanicMask(iter->second->GetSpellProto()) & mechanic_mask)
+ {
+ RemoveAura(iter, AURA_REMOVE_BY_ENEMY_SPELL);
+ continue;
+ }
+ }
+ ++iter;
+ }
+}
+
void Unit::UpdateInterruptMask()
{
m_interruptMask = 0;
@@ -570,29 +593,6 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint
return false;
}
-/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */
-void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell)
-{
- // The chance to dispel an aura depends on the damage taken with respect to the casters level.
- uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50;
- float chance = float(damage) / max_dmg * 100.0f;
-
- std::queue < std::pair < uint32, uint64 > > remove_list;
-
- for (AuraList::iterator iter = m_ccAuras.begin(); iter != m_ccAuras.end();++iter)
- {
- if((!spell || (*iter)->GetId() != spell) && roll_chance_f(chance))
- {
- remove_list.push(std::make_pair((*iter)->GetId(), (*iter)->GetCasterGUID() ) );
- }
- }
-
- for(;remove_list.size();remove_list.pop())
- {
- RemoveAura(remove_list.front().first, remove_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL);
- }
-}
-
void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
{
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -605,10 +605,10 @@ void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
+ if(area && area->IsSanctuary()) //sanctuary
{
if(absorb)
absorb += damage;
@@ -639,14 +639,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
{
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto ? spellProto->Id : 0);
- pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
}
if(!damage)
{
- // Rage from physical damage received .
- if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE))
- ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false);
+ // Rage from absorbed damage
+ if(cleanDamage && cleanDamage->absorbed_damage && pVictim->getPowerType() == POWER_RAGE)
+ pVictim->RewardRage(cleanDamage->absorbed_damage, 0, false);
return 0;
}
@@ -666,7 +665,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// some critters required for quests
if(GetTypeId() == TYPEID_PLAYER)
- ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID());
+ ((Player*)this)->KilledMonster(cInfo ,pVictim->GetGUID());
}
else
pVictim->ModifyHealth(- (int32)damage);
@@ -691,9 +690,10 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
// Rage from Damage made (only from direct weapon damage)
- if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE))
+ if(cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE)
{
uint32 weaponSpeedHitFactor;
+ uint32 rage_damage = damage + cleanDamage->absorbed_damage;
switch(cleanDamage->attackType)
{
@@ -704,7 +704,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
else
weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f);
- ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
+ RewardRage(rage_damage, weaponSpeedHitFactor, true);
break;
}
@@ -715,7 +715,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
else
weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f);
- ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true);
+ RewardRage(rage_damage, weaponSpeedHitFactor, true);
break;
}
@@ -865,7 +865,11 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if(!cVictim->isPet())
{
cVictim->DeleteThreatList();
- cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ // only lootable if it has loot or can drop gold
+ if(cVictim->GetCreatureInfo()->lootid || cVictim->GetCreatureInfo()->maxgold > 0)
+ cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ else
+ cVictim->lootForBody = true; // needed for skinning
}
// Call creature just died function
if (cVictim->AI())
@@ -949,13 +953,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
else // victim is a player
{
- // Rage from damage received
- if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
- {
- uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0);
- ((Player*)pVictim)->RewardRage(rage_damage, 0, false);
- }
-
// random durability for items (HIT TAKEN)
if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE)))
{
@@ -964,6 +961,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
+ // Rage from damage received
+ if(this != pVictim && pVictim->getPowerType() == POWER_RAGE)
+ {
+ uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
+ pVictim->RewardRage(rage_damage, 0, false);
+ }
+
if(GetTypeId()==TYPEID_PLAYER)
{
// random durability for items (HIT DONE)
@@ -1200,7 +1204,7 @@ void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit*
}
// used for scripting
-void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster)
+void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId );
@@ -1220,6 +1224,8 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered,
SpellCastTargets targets;
targets.setDestination(x, y, z);
+ if(OriginalVictim)
+ targets.setUnitTarget(OriginalVictim);
spell->m_CastItem = castItem;
spell->prepare(&targets, triggeredByAura);
}
@@ -1276,6 +1282,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama
if (damage < 0)
return;
+ if(spellInfo->AttributesEx4 & SPELL_ATTR_EX4_FIXED_DAMAGE)
+ return;
+
Unit *pVictim = damageInfo->target;
if(!pVictim || !pVictim->isAlive())
return;
@@ -1380,7 +1389,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
Unit *pVictim = damageInfo->target;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -1395,15 +1404,15 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
+ if(area && area->IsSanctuary()) // sanctuary
return;
}
// Call default DealDamage
- CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
}
@@ -1427,7 +1436,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
damageInfo->procEx = PROC_EX_NONE;
damageInfo->hitOutCome = MELEE_HIT_EVADE;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if(!this->isAlive() || !pVictim->isAlive())
return;
@@ -1436,12 +1445,12 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da
switch (attackType)
{
case BASE_ATTACK:
- damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT;
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT;
damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;
damageInfo->HitInfo = HITINFO_NORMALSWING2;
break;
case OFF_ATTACK:
- damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used
damageInfo->HitInfo = HITINFO_LEFTSWING;
break;
@@ -1623,7 +1632,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
if (damageInfo==0) return;
Unit *pVictim = damageInfo->target;
- if(!this || !pVictim)
+ if(!pVictim)
return;
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
@@ -1631,10 +1640,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
//You don't lose health from damage taken from another player while in a sanctuary
//You still see it in the combat log though
- if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer())
{
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
- if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary
+ if(area && area->IsSanctuary()) // sanctuary
return;
}
@@ -1681,7 +1690,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
}
// Call default DealDamage
- CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
+ CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->absorb,damageInfo->attackType,damageInfo->hitOutCome);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
// If this is a creature and it attacks from behind it has a probability to daze it's victim
@@ -1709,34 +1718,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
CastSpell(pVictim, 1604, true);
}
- if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
- {
- for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
- {
- // If usable, try to cast item spell
- if (Item * item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0,i))
- if(!item->IsBroken())
- if (ItemPrototype const *proto = item->GetProto())
- {
- // Additional check for weapons
- if (proto->Class==ITEM_CLASS_WEAPON)
- {
- // offhand item cannot proc from main hand hit etc
- EquipmentSlots slot;
- switch (damageInfo->attackType)
- {
- case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
- case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
- case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
- default: slot = EQUIPMENT_SLOT_END; break;
- }
- if (slot != i)
- continue;
- }
- ((Player*)this)->CastItemCombatSpell(item, damageInfo, proto);
- }
- }
- }
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player *)this)->CastItemCombatSpell(pVictim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx);
// Do effect if any damage done to target
if (damageInfo->damage)
@@ -1903,6 +1886,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Reflect damage spells (not cast any damage spell in aura lookup)
uint32 reflectSpell = 0;
int32 reflectDamage = 0;
+ AuraEffect* reflectTriggeredBy = NULL; // expected as not expired at reflect as in current cases
uint32 healSpell = 0;
int32 healAmount = 0;
Unit * healCaster = NULL;
@@ -1968,6 +1952,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
else
reflectDamage = currentAbsorb / 2;
reflectSpell = 33619;
+ reflectTriggeredBy = *i;
break;
}
if (spellProto->Id == 39228 || // Argussian Compass
@@ -2037,13 +2022,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
{
case 5065: // Rank 1
case 5064: // Rank 2
- case 5063: // Rank 3
{
if(RemainingDamage >= currentAbsorb)
reflectDamage = (*k)->GetAmount() * currentAbsorb/100;
else
reflectDamage = (*k)->GetAmount() * RemainingDamage/100;
reflectSpell = 33619;
+ reflectTriggeredBy = *i;
} break;
}
}
@@ -2064,9 +2049,20 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
}
case SPELLFAMILY_DEATHKNIGHT:
{
- // Shadow of Death
- if (spellProto->Id == 49157)
+ // Unbreakable Armor
+ if (spellProto->Id == 51271)
{
+ Unit* caster = (*i)->GetCaster();
+ if (!caster)
+ continue;
+
+ uint32 absorbed = uint32( currentAbsorb * caster->GetArmor() * 0.01f );
+
+ // Glyph of Unbreakable Armor
+ if (AuraEffect *aurEff = caster->GetAuraEffect(58635, 0))
+ absorbed += uint32( absorbed * aurEff->GetAmount() / 100 );
+
+ RemainingDamage -= absorbed;
continue;
}
// Anti-Magic Shell (on self)
@@ -2146,7 +2142,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
// Cast back reflect damage spell
if (reflectSpell)
- pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true);
+ pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true, NULL, reflectTriggeredBy);
// absorb by mana cost
AuraEffectList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD);
@@ -2217,7 +2213,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
@@ -2244,7 +2240,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
- CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
+ CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
}
}
@@ -2364,6 +2360,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
// Send log damage message to client
DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb);
SendAttackStateUpdate(&damageInfo);
+
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
DealMeleeDamage(&damageInfo,true);
@@ -2795,6 +2792,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
bool canDodge = true;
bool canParry = true;
+ bool canBlock = spell->AttributesEx3 & SPELL_ATTR_EX3_BLOCKABLE_SPELL;
// Same spells cannot be parry/dodge
if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK)
@@ -2805,11 +2803,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
tmp += resist_chance;
if (roll < tmp)
return SPELL_MISS_RESIST;
-
- // Ranged attack cannot be parry/dodge only deflect
- // Check damage class instead of attack type to correctly handle judgements
- // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
- if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
+
+ // Ranged attacks can only miss, resist and deflect
+ if (attType == RANGED_ATTACK)
{
// only if in front
if (pVictim->HasInArc(M_PI,this))
@@ -2826,10 +2822,11 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
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)
+ if (pVictim->GetTypeId() == TYPEID_PLAYER)
canDodge = false;
- // Can`t parry
+ // Can`t parry or block
canParry = false;
+ canBlock = false;
}
// Check creatures flags_extra for disable parry
if(pVictim->GetTypeId()==TYPEID_UNIT)
@@ -2837,6 +2834,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra;
if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY )
canParry = false;
+ // Check creatures flags_extra for disable block
+ if( flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK )
+ canBlock = false;
}
// Ignore combat result aura
AuraEffectList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
@@ -2847,7 +2847,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
switch((*i)->GetMiscValue())
{
case MELEE_HIT_DODGE: canDodge = false; break;
- case MELEE_HIT_BLOCK: break; // Block check in hit step
+ case MELEE_HIT_BLOCK: canBlock = false; break;
case MELEE_HIT_PARRY: canParry = false; break;
default:
DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue());
@@ -2888,6 +2888,17 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
return SPELL_MISS_PARRY;
}
+ if (canBlock)
+ {
+ int32 blockChance = int32(pVictim->GetUnitBlockChance()*100.0f) - skillDiff * 4;
+ if ( blockChance < 0 )
+ blockChance = 0;
+ tmp += blockChance;
+
+ if (roll < tmp)
+ return SPELL_MISS_BLOCK;
+ }
+
return SPELL_MISS_NONE;
}
@@ -3002,7 +3013,7 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (reflectchance > 0 && roll_chance_i(reflectchance))
{
// Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
- ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 0, BASE_ATTACK, spell);
+ ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL, PROC_EX_REFLECT , 1, BASE_ATTACK, spell);
return SPELL_MISS_REFLECT;
}
}
@@ -3491,8 +3502,8 @@ void Unit::InterruptSpell(uint32 spellType, bool withDelayed, bool withInstant)
// send autorepeat cancel message for autorepeat spells
if (spellType == CURRENT_AUTOREPEAT_SPELL)
{
- if(GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->SendAutoRepeatCancel();
+ if(GetTypeId() == TYPEID_PLAYER)
+ ((Player*)this)->SendAutoRepeatCancel(this);
}
if (spell->getState() != SPELL_STATE_FINISHED)
@@ -3510,15 +3521,17 @@ bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skip
if ( m_currentSpells[CURRENT_GENERIC_SPELL] &&
(m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
(withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
+ {
if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT))
return(true);
-
+ }
// channeled spells may be delayed, but they are still considered casted
else if ( !skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
(m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) )
+ {
if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT))
return(true);
-
+ }
// autorepeat spells may be finished or delayed, but they are still considered casted
else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] )
return(true);
@@ -3549,6 +3562,13 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
return NULL;
}
+int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
+{
+ if (Spell const * spell = FindCurrentSpellBySpellId(spell_id))
+ return spell->GetCastTime();
+ return 0;
+}
+
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
{
return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
@@ -3779,8 +3799,11 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
return false;
}
+ SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
+
// ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
- if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 &&
+ if( !isAlive() && !IsDeathPersistentSpell(aurSpellInfo) &&
+ //Aur->GetId() != 2584 && // Waiting to Resurrect (not have death persistence flag)
(GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) )
{
delete Aur;
@@ -3796,7 +3819,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
return false;
}
- SpellEntry const* aurSpellInfo = Aur->GetSpellProto();
uint32 aurId = aurSpellInfo->Id;
// passive and persistent and Incanter's Absorption auras can stack with themselves any number of times
@@ -3890,6 +3912,16 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
// add aura, register in lists and arrays
Aur->_AddAura();
+
+ //*****************************************************
+ // Update target aura state flag
+ //*****************************************************
+ if(AuraState aState = GetSpellAuraState(Aur->GetSpellProto()))
+ {
+ m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, Aur));
+ ModifyAuraState(aState, true);
+ }
+
m_Auras.insert(AuraMap::value_type(aurId, Aur));
if(aurSpellInfo->AuraInterruptFlags)
@@ -3897,12 +3929,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects)
m_interruptableAuras.push_back(Aur);
AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
}
- if((aurSpellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
- && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- || ((GetAllSpellMechanicMask(aurSpellInfo) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
- {
- m_ccAuras.push_back(Aur);
- }
if (handleEffects)
Aur->HandleEffects(true);
@@ -4173,13 +4199,24 @@ void Unit::RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell)
}
}
-void Unit::RemoveNotOwnSingleTargetAuras()
+void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
{
// single target auras from other casters
for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
{
if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto()))
- RemoveAura(iter);
+ {
+ if(!newPhase)
+ RemoveAura(iter);
+ else
+ {
+ Unit* caster = iter->second->GetCaster();
+ if(!caster || !caster->InSamePhase(newPhase))
+ RemoveAura(iter);
+ else
+ ++iter;
+ }
+ }
else
++iter;
}
@@ -4188,12 +4225,12 @@ void Unit::RemoveNotOwnSingleTargetAuras()
AuraList& scAuras = GetSingleCastAuras();
for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
{
- Aura * aur=*iter;
+ Aura * aura=*iter;
++iter;
- if (aur->GetTarget()!=this)
+ if (aura->GetTarget() != this && !aura->GetTarget()->InSamePhase(newPhase))
{
uint32 removedAuras = m_removedAurasCount;
- aur->GetTarget()->RemoveAura(aur->GetId(),aur->GetCasterGUID());
+ aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetCasterGUID());
if (removedAuras+1<m_removedAurasCount)
iter=scAuras.begin();
}
@@ -4217,13 +4254,6 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
UpdateInterruptMask();
}
- if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE
- && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable
- || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN)))
- {
- m_ccAuras.remove(Aur);
- }
-
Aur->SetRemoveMode(mode);
sLog.outDebug("Aura %u now is remove mode %d", Aur->GetId(), mode);
@@ -4234,8 +4264,30 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
Aur->_RemoveAura();
+ bool auraStateFound = false;
+ if (AuraState auraState = GetSpellAuraState(Aur->GetSpellProto()))
+ {
+ bool canBreak = false;
+ // Get mask of all aurastates from remaining auras
+ for(AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
+ {
+ if (itr->second == Aur)
+ {
+ m_auraStateAuras.erase(itr);
+ itr = m_auraStateAuras.lower_bound(auraState);
+ canBreak = true;
+ continue;
+ }
+ auraStateFound = true;
+ ++itr;
+ }
+ // Remove only aurastates which were not found
+ if (!auraStateFound)
+ ModifyAuraState(auraState, false);
+ }
+
// Remove totem at next update if totem looses its aura
- if (GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID())
+ if (Aur->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID())
{
if (((Totem*)this)->GetSpell()==Aur->GetId() && ((Totem*)this)->GetTotemType()==TOTEM_PASSIVE)
((Totem*)this)->setDeathState(JUST_DIED);
@@ -4401,6 +4453,18 @@ AuraEffect* Unit::GetAura(AuraType type, uint32 family, uint32 familyFlag1, uint
return NULL;
}
+AuraEffect * Unit::IsScriptOverriden(SpellEntry const * spell, int32 script) const
+{
+ AuraEffectList const& auras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
+ for(AuraEffectList::const_iterator i = auras.begin();i != auras.end(); ++i)
+ {
+ if ((*i)->GetMiscValue() == script)
+ if ((*i)->isAffectedOnSpell(spell))
+ return (*i);
+ }
+ return NULL;
+}
+
uint32 Unit::GetDiseasesByCaster(uint64 casterGUID, bool remove)
{
static const AuraType diseaseAuraTypes[] =
@@ -4685,13 +4749,13 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
data << uint32(GetSpellSchoolMask(aura->GetSpellProto()));
data << uint32(pInfo->absorb); // absorb
data << uint32(pInfo->resist); // resist
- data << uint8(0); // new 3.1.2
+ data << uint8(pInfo->critical); // new 3.1.2 critical tick
break;
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
data << uint32(pInfo->damage); // damage
data << uint32(pInfo->overDamage); // overheal?
- data << uint8(0); // new 3.1.2
+ data << uint8(pInfo->critical); // new 3.1.2 critical tick
break;
case SPELL_AURA_OBS_MOD_ENERGY:
case SPELL_AURA_PERIODIC_ENERGIZE:
@@ -4827,7 +4891,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
case 33735:
{
target = SelectNearbyTarget();
- if(!target)
+ if(!target || target == pVictim)
return false;
basepoints0 = damage;
triggered_spell_id = 22482;
@@ -4851,7 +4915,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
@@ -4880,6 +4944,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
uint32 triggered_spell_id = 0;
Unit* target = pVictim;
int32 basepoints0 = 0;
+ uint64 originalCaster = 0;
// Master of subtlety (checked here because ranks have different spellfamilynames)
if (dummySpell->Id == 31223 || dummySpell->Id == 31221 || dummySpell->Id == 31222)
@@ -4898,6 +4963,18 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
{
switch (dummySpell->Id)
{
+ // BloodWorms Health Leech
+ case 50453:
+ {
+ if (Unit *owner = this->GetOwner())
+ {
+ basepoints0 = int32(damage*1.50);
+ target = owner;
+ triggered_spell_id = 50454;
+ break;
+ }
+ return false;
+ }
// Improved Divine Spirit
case 33174:
case 33182:
@@ -4939,14 +5016,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
break;
}
// Sweeping Strikes
- case 12328:
case 18765:
case 35429:
{
- // prevent chain of triggered spell from same triggered spell
- if(procSpell && procSpell->Id==26654)
- return false;
-
target = SelectNearbyTarget();
if(!target)
return false;
@@ -5411,11 +5483,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
switch(dummySpell->Id)
{
+ // Glyph of Polymorph
+ case 56375:
+ {
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
+ target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
+ return true;
+ }
// Glyph of Icy Veins
case 56374:
+ {
RemoveAurasByType(SPELL_AURA_MOD_HASTE, 0, 0, true, false);
RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
- return true;
+ return true;
+ }
// Ignite
case 11119:
case 11120:
@@ -5474,6 +5555,28 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
case SPELLFAMILY_WARRIOR:
{
+ switch(dummySpell->Id)
+ {
+ // Sweeping Strikes
+ case 12328:
+ {
+ target = SelectNearbyTarget();
+ if(!target)
+ return false;
+
+ triggered_spell_id = 26654;
+ break;
+ }
+ // Improved Spell Reflection
+ case 59088:
+ case 59089:
+ {
+ triggered_spell_id = 59725;
+ target = this;
+ break;
+ }
+ }
+
// Retaliation
if(dummySpell->SpellFamilyFlags.IsEqual(0, 0x8, 0))
{
@@ -5484,14 +5587,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 22858;
break;
}
- // Improved Spell Reflection
- if(dummySpell->Id==59088
- || dummySpell->Id==59089)
- {
- triggered_spell_id = 59725;
- target = this;
- break;
- }
// Second Wind
if (dummySpell->SpellIconID == 1697)
{
@@ -5613,6 +5708,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
{
if ((*i)->GetId()==54117 || (*i)->GetId()==54118)
{
+ if ((*i)->GetEffIndex() != 0)
+ continue;
basepoints0 = int32((*i)->GetAmount());
if (target = GetGuardianPet())
{
@@ -5621,6 +5718,15 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// regen mana for caster
CastCustomSpell(this,59117,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ // Get second aura of spell for replenishment effect on party
+ if (AuraEffect const * aurEff = (*i)->GetParentAura()->GetPartAura(1))
+ {
+ // Replenishment - roll chance
+ if (roll_chance_i(aurEff->GetAmount()))
+ {
+ CastSpell(this,57669,true, castItem, triggeredByAura);
+ }
+ }
break;
}
}
@@ -5806,22 +5912,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
break;
}
- // Psychic Horror
- case 47571:
- {
- if(!pVictim || !pVictim->isAlive())
- return false;
- pVictim->CastSpell(pVictim, 59980,true, castItem, triggeredByAura);
- return true;
- }
- // Psychic Horror (Rank 2)
- case 47572:
- {
- if(!pVictim || !pVictim->isAlive())
- return false;
- pVictim->CastSpell(pVictim, 59981,true, castItem, triggeredByAura);
- return true;
- }
// Glyph of Dispel Magic
case 55677:
{
@@ -5884,10 +5974,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
basepoints0 = triggerAmount * GetMaxHealth() / 100;
target = this;
triggered_spell_id = 34299;
- if (triggeredByAura->GetCaster() != this)
+ if (triggeredByAura->GetCasterGUID() != GetGUID())
break;
int32 basepoints1 = triggerAmount * 2;
- CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura);
+ // Improved Leader of the Pack
+ // Check cooldown of heal spell cooldown
+ if (GetTypeId()==TYPEID_PLAYER && !((Player *)this)->HasSpellCooldown(34299))
+ CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura);
break;
}
// Healing Touch (Dreamwalker Raiment set)
@@ -5940,7 +6033,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 40446;
chance = 25.0f;
}
- // Mangle (cat/bear)
+ // Mangle (Bear) and Mangle (Cat)
else if( procSpell->SpellFamilyFlags[1] & 0x00000440)
{
triggered_spell_id = 40452;
@@ -5998,6 +6091,30 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
basepoints0 = triggerAmount * damage / 100;
break;
}
+ // King of the Jungle
+ else if (dummySpell->SpellIconID == 2850)
+ {
+ // Effect 0 - mod damage while having Enrage
+ if (effIndex==0)
+ {
+ if (!(procSpell->SpellFamilyFlags[0] & 0x00080000))
+ return false;
+ triggered_spell_id = 51185;
+ basepoints0 = triggerAmount;
+ target = this;
+ break;
+ }
+ // Effect 1 - Tiger's Fury restore energy
+ else if (effIndex==1)
+ {
+ if (!(procSpell->SpellFamilyFlags[2] & 0x00000800))
+ return false;
+ triggered_spell_id = 51178;
+ basepoints0 = triggerAmount;
+ target = this;
+ break;
+ }
+ }
break;
}
case SPELLFAMILY_ROGUE:
@@ -6114,36 +6231,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// Light's Beacon - Beacon of Light
if ( dummySpell->Id == 53651 )
{
- if (Unit * caster = triggeredByAura->GetCaster())
+ if (Unit * source = triggeredByAura->GetSource())
{
// do not proc when target of beacon of light is healed
- if (caster == pVictim)
+ if (source == this)
return false;
- if (Aura const* aur = caster->GetAura(53563))
+ if (Unit * caster = triggeredByAura->GetCaster())
{
- if (Unit * paladin = aur->GetCaster())
- {
- if (paladin != this)
- return false;
- basepoints0 = damage;
- triggered_spell_id = 53654;
- target = caster;
- break;
- }
- else
- {
- pVictim->RemoveAura(triggeredByAura->GetParentAura());
+ if (caster != pVictim)
return false;
- }
+ basepoints0 = damage;
+ triggered_spell_id = 53654;
+ target = source;
+ break;
}
}
- else return false;
+ return false;
}
// Judgements of the Wise
if (dummySpell->SpellIconID == 3017)
{
- // hardcoded amount
- basepoints0 = 15 * GetCreatePowers(POWER_MANA)/100;
target = this;
triggered_spell_id = 31930;
// replenishment
@@ -6184,17 +6291,19 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
switch(dummySpell->Id)
{
+ // Heart of the Crusader
+ case 20335: // rank 1
+ triggered_spell_id = 21183;
+ break;
+ case 20336: // rank 2
+ triggered_spell_id = 54498;
+ break;
+ case 20337: // rank 3
+ triggered_spell_id = 54499;
+ break;
// Judgement of Light
case 20185:
{
- // Get judgement caster
- Unit *caster = triggeredByAura->GetCaster();
- if (!caster)
- return false;
- float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
- int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) +
- caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this);
- basepoints0 = int32(ap*0.10f + 0.10f*holy);
pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura);
return true;
}
@@ -6269,7 +6378,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// heal amount
basepoints0 = triggerAmount*damage/100;
target = this;
- triggered_spell_id = 31786;
+
+ if(basepoints0)
+ triggered_spell_id = 31786;
break;
}
// Seal of Blood do damage trigger
@@ -6320,8 +6431,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 40471;
chance = 15.0f;
}
- // Judgement
- else if( procSpell->SpellFamilyFlags[0] & 0x800000 )
+ // Judgement (any)
+ else if (GetSpellSpecific(procSpell->Id)==SPELL_JUDGEMENT)
{
triggered_spell_id = 40472;
chance = 50.0f;
@@ -6433,6 +6544,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id))
return false;
+ if(triggeredByAura->GetParentAura() && castItem->GetGUID() != triggeredByAura->GetParentAura()->GetCastItemGUID())
+ return false;
+
// Now amount of extra power stored in 1 effect of Enchant spell
// Get it by item enchant id
uint32 spellId;
@@ -6463,20 +6577,21 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim);
- // Off-Hand case
- if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) )
- {
- // Value gained from additional AP
- basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
- triggered_spell_id = 33750;
- }
// Main-Hand case
- else if ( isAttackReady(BASE_ATTACK) )
+ if ( castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK) )
{
// Value gained from additional AP
basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000);
triggered_spell_id = 25504;
}
+ // Off-Hand case
+ else if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) )
+ {
+ // Value gained from additional AP
+ basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2);
+ triggered_spell_id = 33750;
+ }
+
else
return false;
@@ -6543,6 +6658,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 58879;
break;
}
+ // Shaman T8 Elemental 4P Bonus
+ case 64928:
+ {
+ basepoints0 = int32( triggerAmount * damage / 100 );
+ triggered_spell_id = 64930; // Electrified
+ break;
+ }
}
// Storm, Earth and Fire
if (dummySpell->SpellIconID == 3063)
@@ -6569,6 +6691,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
// Earth Shield
if(dummySpell->SpellFamilyFlags[1] & 0x00000400)
{
+ // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
+ originalCaster = triggeredByAura->GetCasterGUID();
basepoints0 = triggerAmount;
target = this;
triggered_spell_id = 379;
@@ -6816,13 +6940,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
triggered_spell_id = 50526;
break;
}
- // Death Strike healing effect
- if (dummySpell->Id == 45469)
- {
- int32 heal=pVictim->GetDiseasesByCaster(GetGUID()) * GetMaxHealth()* 5 /100;
- CastCustomSpell(this,45470,&heal,NULL,NULL,true);
- return true;
- }
// Sudden Doom
if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER)
{
@@ -6925,23 +7042,22 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
return false;
if(basepoints0)
- CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura, originalCaster);
else
- CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura);
+ CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura, originalCaster);
if( cooldown && GetTypeId()==TYPEID_PLAYER )
((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
return true;
}
-
bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
@@ -6964,7 +7080,6 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
{
uint32 maxmana = GetMaxPower(POWER_MANA);
basepoints0 = maxmana* GetAttackTime(RANGED_ATTACK)/1000.0f/100.0f;
-
target = this;
triggered_spell_id = 34075;
break;
@@ -6978,6 +7093,7 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id);
+ // Try handle unknown trigger spells
if(!triggerEntry)
{
sLog.outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id);
@@ -6985,12 +7101,11 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
return false;
-
if(basepoints0)
CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
else
@@ -6998,10 +7113,8 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect*
if( cooldown && GetTypeId()==TYPEID_PLAYER )
((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown);
-
return true;
}
-
bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
@@ -7025,8 +7138,6 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff
switch (getPowerType())
{
case POWER_MANA: triggered_spell_id = 57319; break;
- case POWER_RAGE: triggered_spell_id = 57320; break;
- case POWER_RUNIC_POWER: triggered_spell_id = 57321; break;
default:
return false;
}
@@ -7047,7 +7158,7 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff
}
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id))
@@ -7074,12 +7185,66 @@ bool Unit::HandleAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, S
{
case SPELLFAMILY_DEATHKNIGHT:
{
+ // Blood of the North
+ // Reaping
+ // Death Rune Mastery
+ if (dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622)
+ {
+ *handled = true;
+ // Convert recently used Blood Rune to Death Rune
+ if (GetTypeId() == TYPEID_PLAYER)
+ {
+ if(((Player*)this)->getClass() != CLASS_DEATH_KNIGHT)
+ return false;
+ RuneType rune = ((Player*)this)->GetLastUsedRune();
+ // can't proc from death rune use
+ if (rune == RUNE_DEATH)
+ return false;
+ AuraEffect * aurEff = triggeredByAura->GetPartAura(0);
+ if (!aurEff)
+ return false;
+ // Reset amplitude - set death rune remove timer to 30s
+ aurEff->ResetPeriodicTimer();
+ uint32 runesLeft;
+
+ if (dummySpell->SpellIconID == 2622)
+ runesLeft = 2;
+ else
+ runesLeft = 1;
+
+ for (uint8 i=0;i<MAX_RUNES && runesLeft;++i)
+ {
+ if (dummySpell->SpellIconID == 2622)
+ {
+ if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH ||
+ ((Player*)this)->GetBaseRune(i) == RUNE_BLOOD )
+ continue;
+ }
+ else
+ {
+ if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH ||
+ ((Player*)this)->GetBaseRune(i) != RUNE_BLOOD )
+ continue;
+ }
+ if (((Player*)this)->GetRuneCooldown(i) != RUNE_COOLDOWN)
+ continue;
+
+ --runesLeft;
+ // Mark aura as used
+ aurEff->SetAmount(aurEff->GetAmount() | (1<<i));
+ ((Player*)this)->ConvertRune(i,RUNE_DEATH);
+ }
+ return true;
+ }
+ return false;
+ }
+
switch(dummySpell->Id)
{
// Hungering Cold aura drop
case 51209:
*handled = true;
- // Drop only in disease case
+ // Drop only in not disease case
if (procSpell && procSpell->Dispel == DISPEL_DISEASE)
return false;
return true;
@@ -7273,38 +7438,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
break;
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;
-
- // Hellfire have 15 tick
- if (procSpell->SpellFamilyFlags[0]&0x40)
- tick = 15;
- // Rain of Fire have 4 tick
- else if (procSpell->SpellFamilyFlags[0]&0x20)
- tick = 4;
- else
- tick = 1;
-
- // 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;
- }
// Improved Drain Soul
- else if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
+ if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000)
{
Unit::AuraEffectList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
@@ -7387,7 +7522,28 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
break;
}
case SPELLFAMILY_HUNTER:
+ {
+ if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 53234: // Rank 1
+ case 53237: // Rank 2
+ case 53238: // Rank 3
+ trigger_spell_id = 63468;
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots",auraSpellInfo->Id);
+ return false;
+ }
+ SpellEntry const *TriggerPS = sSpellStore.LookupEntry(trigger_spell_id);
+ if(!TriggerPS)
+ return false;
+ basepoints0 = int32(damage * triggerAmount / 100 / (GetSpellMaxDuration(TriggerPS) / TriggerPS->EffectAmplitude[0]));
+ target = pVictim;
+ }
break;
+ }
case SPELLFAMILY_PALADIN:
{
/*
@@ -7462,9 +7618,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// stacking
CastSpell(this, 37658, true, NULL, triggeredByAura);
- AuraEffect * dummy = GetDummyAura(37658);
+ Aura * dummy = GetAura(37658);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
+ if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(37658);
@@ -7480,9 +7636,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
CastSpell(this, 54842, true, NULL, triggeredByAura);
// counting
- AuraEffect * dummy = GetDummyAura(54842);
+ Aura * dummy = GetAura(54842);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
- if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount)
+ if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(54842);
@@ -7580,8 +7736,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
return false;
}
}
- // Blood Presence
- else if (auraSpellInfo->Id == 48266)
+ // Blood Presence (Improved)
+ else if (auraSpellInfo->Id == 63611)
{
if (GetTypeId() != TYPEID_PLAYER)
return false;
@@ -7761,7 +7917,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
case 22959:
{
// Glyph of Improved Scorch
- if (AuraEffect * aurEff = GetDummyAura(56371))
+ if (AuraEffect * aurEff = GetAuraEffect(56371,0))
{
for (int32 count = aurEff->GetAmount();count>0;count--)
CastSpell(pVictim, 22959, true);
@@ -7795,10 +7951,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
if (Unit * owner = GetOwner())
{
- if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220))
+ if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220, 0))
{
- if (owner->GetTypeId() == TYPEID_PLAYER)
- basepoints0 = (aurEff->GetAmount() * ((Player*)owner)->GetBaseSpellDamageBonus() + 100.0f) / 100;
+ basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonus(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f);
CastCustomSpell(this,trigger_spell_id,&basepoints0,&basepoints0,NULL,true,castItem,triggeredByAura);
return true;
}
@@ -7808,14 +7963,20 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// Sword and Board
case 50227:
{
- // remove cooldown of Shield Slam
+ // Remove cooldown on Shield Slam
if (GetTypeId()==TYPEID_PLAYER)
- ((Player*)this)->RemoveCategoryCooldown(1209);
+ ((Player*)this)->RemoveSpellCategoryCooldown(1209, true);
break;
}
- case 63375: // Improved Stormstrike
+ // Maelstrom Weapon
+ case 53817:
{
- basepoints0 = GetCreateMana() * 0.20f;
+ // have rank dependent proc chance, ignore too often cases
+ // PPM = 2.5 * (rank of talent),
+ uint32 rank = spellmgr.GetSpellRank(auraSpellInfo->Id);
+ // 5 rank -> 100% 4 rank -> 80% and etc from full rate
+ if(!roll_chance_i(20*rank))
+ return false;
break;
}
// Brain Freeze
@@ -7867,7 +8028,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
case 56453:
{
// Proc only from trap activation (from periodic proc another aura of this spell)
- if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION))
+ if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount))
+ return false;
+ break;
+ }
+ // Glyph of Death's Embrace
+ case 58679:
+ {
+ // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags
+ if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000))
return false;
break;
}
@@ -7879,6 +8048,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
((Player*)this)->RemoveCategoryCooldown(82);
return true;
}
+ // Savage Defense
+ case 62606:
+ {
+ basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100.0f);
+ break;
+ }
}
if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
@@ -7886,16 +8061,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
// try detect target manually if not set
if ( target == NULL )
- target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
+ target = !(procFlags & (PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT)) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
// default case
- if(!target || target!=this && !target->isAlive())
+ if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive()))
return false;
if(basepoints0)
CastCustomSpell(target,trigger_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
- //else if(spellmgr.GetSpellCustomAttr(trigger_spell_id) & SPELL_ATTR_CU_AURA_SPELL)
- // AddAura(trigger_spell_id, target);
else
CastSpell(target,trigger_spell_id,true,castItem,triggeredByAura);
@@ -7982,6 +8155,21 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, AuraE
CastCustomSpell(this, 47762, &basepoints0, 0, 0, true, 0, triggeredByAura);
return true;
}
+ case 7010: // Revitalize - can proc on full hp target
+ case 7011:
+ case 7012:
+ {
+ if (!roll_chance_i(triggeredByAura->GetAmount()))
+ return false;
+ switch(pVictim->getPowerType())
+ {
+ case POWER_MANA: triggered_spell_id = 48542; break;
+ case POWER_RAGE: triggered_spell_id = 48541; break;
+ case POWER_ENERGY: triggered_spell_id = 48540; break;
+ case POWER_RUNIC_POWER: triggered_spell_id = 48543; break;
+ }
+ break;
+ }
}
// not processed
@@ -8329,7 +8517,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
return false;
// dead units can neither attack nor be attacked
- if(!isAlive() || !victim->isAlive())
+ if(!isAlive() || !victim->IsInWorld() || !victim->isAlive())
return false;
// player cannot attack in mount state
@@ -8388,7 +8576,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
//if(GetTypeId()==TYPEID_UNIT)
// ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
- if(GetTypeId()==TYPEID_UNIT && !IsControlledByPlayer())
+ if(GetTypeId()==TYPEID_UNIT)
{
// should not let player enter combat by right clicking target
SetInCombatWith(victim);
@@ -8529,14 +8717,6 @@ void Unit::ModifyAuraState(AuraState flag, bool apply)
SpellEntry const* spellProto = (*itr).second->GetSpellProto();
if (spellProto->CasterAuraState == flag)
{
- // exceptions (applied at state but not removed at state change)
- // Rampage
- if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags[0]==0x100000)
- {
- ++itr;
- continue;
- }
-
RemoveAura(itr);
}
else
@@ -8547,15 +8727,42 @@ void Unit::ModifyAuraState(AuraState flag, bool apply)
}
}
+uint32 Unit::BuildAuraStateUpdateForTarget(Unit * target) const
+{
+ uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK);
+ for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end();++itr)
+ {
+ if ((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK)
+ {
+ if (itr->second->GetCasterGUID() == target->GetGUID())
+ auraStates |= (1<<(itr->first-1));
+ }
+ }
+ return auraStates;
+}
+
bool Unit::HasAuraState(AuraState flag, SpellEntry const *spellProto, Unit * Caster) const
{
- if (Caster && spellProto)
+ if (Caster)
{
- AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
- for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
- if((*j)->isAffectedOnSpell(spellProto))
- return true;
+ if(spellProto)
+ {
+ AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
+ for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j)
+ if((*j)->isAffectedOnSpell(spellProto))
+ return true;
+ }
+ // Check per caster aura state
+ // If aura with aurastate by caster not found return false
+ if ((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK)
+ {
+ for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.lower_bound(flag); itr != m_auraStateAuras.upper_bound(flag);++itr)
+ if (itr->second->GetCasterGUID() == Caster->GetGUID())
+ return true;
+ return false;
+ }
}
+
return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
}
@@ -8741,13 +8948,13 @@ void Unit::SetMinion(Minion *minion, bool apply)
assert((*itr)->GetOwnerGUID() == GetGUID());
assert((*itr)->GetTypeId() == TYPEID_UNIT);
- if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
continue;
if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
{
//show another pet bar if there is no charm bar
- if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN))
+ if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))
{
if(((Creature*)(*itr))->isPet())
((Player*)this)->PetSpellInitialize();
@@ -8835,19 +9042,24 @@ int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellPro
{
int32 gain = pVictim->ModifyHealth(int32(addhealth));
- if (GetTypeId()==TYPEID_PLAYER)
+ Unit* unit = this;
+
+ if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem())
+ unit = GetOwner();
+
+ if (unit->GetTypeId()==TYPEID_PLAYER)
{
// overheal = addhealth - gain
- SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth > gain ? addhealth - gain : 0, critical);
+ unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical);
- if (BattleGround *bg = ((Player*)this)->GetBattleGround())
- bg->UpdatePlayerScore((Player*)this, SCORE_HEALING_DONE, gain);
+ if (BattleGround *bg = ((Player*)unit)->GetBattleGround())
+ bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain);
// use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
if (gain)
- ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim);
- ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
+ ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth);
}
if (pVictim->GetTypeId()==TYPEID_PLAYER)
@@ -8926,9 +9138,7 @@ void Unit::RemoveAllControlled()
&& target->GetTypeId() == TYPEID_UNIT
&& ((Creature*)target)->HasSummonMask(SUMMON_MASK_SUMMON))
{
-
- if(!((TempSummon*)target)->isPet())
- ((TempSummon*)target)->UnSummon();
+ ((TempSummon*)target)->UnSummon();
}
else
{
@@ -9073,7 +9283,7 @@ void Unit::EnergizeBySpell(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers
{
SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype);
// needs to be called after sending spell log
- ModifyPower(powertype, Damage);
+ pVictim->ModifyPower(powertype, Damage);
}
uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack)
@@ -9202,7 +9412,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
}
else // Tundra Stalker
{
- if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT,0, 0x4000000,0))
+ // Frost Fever (target debuff)
+ if (pVictim->GetAura(SPELL_AURA_MOD_HASTE, SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x2))
DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
break;
}
@@ -9265,13 +9476,12 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
}
}
break;
-
// Glyph of Shadow Word: Pain
case SPELLFAMILY_PRIEST:
if (spellProto->SpellFamilyFlags[0] & 0x800000)
{
// Increase Mind Flay damage
- if (AuraEffect * aurEff = GetDummyAura(55687))
+ if (AuraEffect * aurEff = GetAuraEffect(55687, 0))
// if Shadow Word: Pain present
if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0,0, GetGUID()))
DoneTotalMod *= (aurEff->GetAmount() + 100.0f) / 100.f;
@@ -9300,17 +9510,17 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
// Improved Icy Touch
if (spellProto->SpellFamilyFlags[0] & 0x2)
{
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721, 0))
DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f ;
}
// Glacier Rot
if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
{
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196, 0))
DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f;
}
// This is not a typo - Impurity has SPELLFAMILY_DRUID
- if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986))
+ if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0))
ApCoeffMod *= (100.0f + aurEff->GetAmount()) / 100.0f;
break;
}
@@ -9325,7 +9535,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
if (pVictim->GetTypeId() == TYPEID_PLAYER)
{
//Cheat Death
- if (AuraEffect *dummy = pVictim->GetDummyAura(45182))
+ if (AuraEffect *dummy = pVictim->GetAuraEffect(45182, 0))
{
float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4;
if (mod < dummy->GetAmount())
@@ -9341,14 +9551,11 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
// Mod damage from spell mechanic
- uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
- if (mechanicMask)
+ if (uint32 mechanicMask = GetAllSpellMechanicMask(spellProto))
{
AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
- if((mechanicMask & uint32(1<<((*i)->GetMiscValue())))
- // Shred - "Effects which increase Bleed damage also increase Shred damage"
- || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000))
+ if(mechanicMask & uint32(1<<((*i)->GetMiscValue())))
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
}
@@ -9361,21 +9568,29 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage();
// Check for table values
- float coeff;
+ float coeff = 0;
SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id);
if (bonus)
{
if (damagetype == DOT)
+ {
coeff = bonus->dot_damage;
+ if (bonus->ap_dot_bonus > 0)
+ DoneTotal+=bonus->ap_dot_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK);
+ }
else
+ {
coeff = bonus->direct_damage;
- if (bonus->ap_bonus)
- DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack * ApCoeffMod;
+ if (bonus->ap_bonus > 0)
+ DoneTotal+=bonus->ap_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
}
// Default calculation
if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
- if(!bonus)
+ if(!bonus || coeff < 0)
{
// Damage Done from spell damage bonus
int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
@@ -9520,8 +9735,9 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
float crit_chance = 0.0f;
switch(spellProto->DmgClass)
{
- case SPELL_DAMAGE_CLASS_NONE:
- return false;
+ case SPELL_DAMAGE_CLASS_NONE: // Exception for earth shield
+ if (spellProto->Id != 379) // We need more spells to find a general way (if there is any)
+ return false;
case SPELL_DAMAGE_CLASS_MAGIC:
{
if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
@@ -9590,11 +9806,18 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
// Sacred Shield
if (spellProto->SpellFamilyFlags[0] & 0x40000000)
{
- AuraEffect const* aura = pVictim->GetDummyAura(58597);
+ AuraEffect const* aura = pVictim->GetAuraEffect(58597,1);
if (aura && aura->GetCasterGUID() == GetGUID())
crit_chance+=aura->GetAmount();
break;
}
+ // Exorcism
+ else if (spellProto->Category == 19)
+ {
+ if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD)
+ return true;
+ break;
+ }
break;
case SPELLFAMILY_SHAMAN:
// Lava Burst
@@ -9616,12 +9839,30 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM
break;
}
case SPELL_DAMAGE_CLASS_MELEE:
+ if (pVictim)
+ {
+ // Custom crit by class
+ switch(spellProto->SpellFamilyName)
+ {
+ case SPELLFAMILY_DRUID:
+ // Rend and Tear - bonus crit chance for bleeding targets of Ferocious Bite
+ if (spellProto->SpellFamilyFlags[0] & 0x00800000 && pVictim->HasAuraState(AURA_STATE_BLEEDING, spellProto, this))
+ {
+ if (AuraEffect const* rendAndTear = GetDummyAura(SPELLFAMILY_DRUID, 2859, 1))
+ {
+ crit_chance += rendAndTear->GetAmount();
+ }
+ break;
+ }
+ break;
+ }
+ }
case SPELL_DAMAGE_CLASS_RANGED:
{
if (pVictim)
{
- crit_chance = GetUnitCriticalChance(attackType, pVictim);
- crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
+ crit_chance += GetUnitCriticalChance(attackType, pVictim);
+ crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask);
}
break;
}
@@ -9801,16 +10042,24 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// Check for table values
SpellBonusEntry const* bonus = !scripted ? spellmgr.GetSpellBonusData(spellProto->Id) : NULL;
- float coeff;
+ float coeff = 0;
float factorMod = 1.0f;
if (bonus)
{
if (damagetype == DOT)
+ {
coeff = bonus->dot_damage;
+ if (bonus->ap_dot_bonus > 0)
+ DoneTotal+=bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
else
+ {
coeff = bonus->direct_damage;
- if (bonus->ap_bonus)
- DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack;
+ if (bonus->ap_bonus > 0)
+ DoneTotal+=bonus->ap_bonus * stack * GetTotalAttackPowerValue(
+ (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK);
+ }
}
else // scripted bonus
{
@@ -9836,6 +10085,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default
else if (scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
{
+ scripted = true;
coeff = 0.0f;
}
}
@@ -9843,7 +10093,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint
// Default calculation
if (DoneAdvertisedBenefit || TakenAdvertisedBenefit)
{
- if(!bonus && !scripted)
+ if((!bonus && !scripted) || coeff < 0)
{
// Damage Done from spell damage bonus
int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto);
@@ -10204,6 +10454,9 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
}
}
}
+ // This is not a typo - Impurity has SPELLFAMILY_DRUID
+ if (AuraEffect const * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0))
+ APbonus *= (100.0f + aurEff->GetAmount()) / 100.0f;
DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized));
}
@@ -10238,6 +10491,22 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask())
TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ // .. taken pct (special attacks)
+ if (spellProto)
+ {
+ // Mod damage from spell mechanic
+ uint32 mechanicMask = GetAllSpellMechanicMask(spellProto);
+ if (mechanicMask)
+ {
+ AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT);
+ for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i)
+ if((mechanicMask & uint32(1<<((*i)->GetMiscValue())))
+ // Shred - "Effects which increase Bleed damage also increase Shred damage"
+ || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000))
+ TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f;
+ }
+ }
+
// .. taken pct: dummy auras
AuraEffectList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
@@ -10256,14 +10525,6 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
TakenTotalMod *= (mod+100.0f)/100.0f;
}
break;
- //Mangle
- case 2312:
- if(spellProto==NULL)
- break;
- // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG)
- if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags.IsEqual (0x00008000,0,0))
- TakenTotalMod *= (100.0f+(*i)->GetAmount())/100.0f;
- break;
}
}
@@ -10394,8 +10655,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * s
if(Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_PROC_PER_MINUTE,PPM);
- uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
- return result;
+ return uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
}
void Unit::Mount(uint32 mount)
@@ -10471,20 +10731,22 @@ void Unit::SetInCombatWith(Unit* enemy)
SetInCombatState(false,enemy);
}
-void Unit::CombatStart(Unit* target)
+void Unit::CombatStart(Unit* target, bool initialAggro)
{
- if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/)
- target->SetStandState(UNIT_STAND_STATE_STAND);
-
- if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
- && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled)
+ if (initialAggro)
{
- ((Creature*)target)->AI()->AttackStart(this);
- }
+ if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/)
+ target->SetStandState(UNIT_STAND_STATE_STAND);
- SetInCombatWith(target);
- target->SetInCombatWith(this);
+ if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
+ && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled)
+ {
+ ((Creature*)target)->AI()->AttackStart(this);
+ }
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
+ }
Unit *who = target->GetCharmerOrOwnerOrSelf();
if(who->GetTypeId() == TYPEID_PLAYER)
SetContestedPvP((Player*)who);
@@ -10515,8 +10777,10 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
if(GetTypeId() != TYPEID_PLAYER)
{
- //if(GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != IDLE_MOTION_TYPE)
- ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
+ // Set home position at place of engaging combat for escorted creatures
+ if(((Creature*)this)->IsAIEnabled)
+ if (((Creature *)this)->AI()->IsEscorted())
+ ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
if(enemy)
{
if(((Creature*)this)->IsAIEnabled)
@@ -10581,6 +10845,9 @@ bool Unit::canAttack(Unit const* target, bool force) const
else if(!IsHostileTo(target))
return false;
+ //if(m_Vehicle && m_Vehicle == target->m_Vehicle)
+ // return true;
+
if(!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED))
return false;
@@ -10782,6 +11049,7 @@ bool Unit::canDetectStealthOf(Unit const* target, float distance) const
//-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
//based on wowwiki every 5 mod we have 1 more level diff in calculation
visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f;
+ visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance;
return distance < visibleDistance;
}
@@ -10823,6 +11091,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
switch(mtype)
{
+ // Only apply debuffs
+ case MOVE_FLIGHT_BACK:
+ case MOVE_RUN_BACK:
+ case MOVE_SWIM_BACK:
+ break;
case MOVE_WALK:
return;
case MOVE_RUN:
@@ -10841,15 +11114,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
}
break;
}
- case MOVE_RUN_BACK:
- return;
case MOVE_SWIM:
{
main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED);
break;
}
- case MOVE_SWIM_BACK:
- return;
case MOVE_FLIGHT:
{
if (GetTypeId()==TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
@@ -10881,14 +11150,13 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
vehicle->UpdateSpeed(MOVE_FLIGHT, true);
break;
}
- case MOVE_FLIGHT_BACK:
- return;
default:
sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype);
return;
}
float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus;
+
// now we ready for speed calculation
float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus;
@@ -10898,6 +11166,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
case MOVE_SWIM:
case MOVE_FLIGHT:
{
+ // Set creature speed rate from CreatureInfo
+ if (GetTypeId() == TYPEID_UNIT)
+ speed *= ((Creature*)this)->GetCreatureInfo()->speed;
+
// Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
// TODO: possible affect only on MOVE_RUN
if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
@@ -11089,6 +11361,8 @@ void Unit::setDeathState(DeathState s)
if (m_deathState != ALIVE && s == ALIVE)
{
//_ApplyAllAuraMods();
+ // Reset display id on resurection - needed by corpse explosion to cleanup after display change
+ SetDisplayId(GetNativeDisplayId());
}
m_deathState = s;
}
@@ -11116,8 +11390,8 @@ bool Unit::CanHaveThreatList() const
//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()) )
+ // summons can not have a threat list, unless they are controlled by a creature
+ if( ((Creature*)this)->HasSummonMask(SUMMON_MASK_MINION | SUMMON_MASK_GUARDIAN | SUMMON_MASK_CONTROLABLE_GUARDIAN) && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) )
return false;
return true;
@@ -11148,6 +11422,8 @@ void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, Sp
void Unit::DeleteThreatList()
{
+ if(CanHaveThreatList() && !m_ThreatManager.isThreatListEmpty())
+ SendClearThreatListOpcode();
m_ThreatManager.clearReferences();
}
@@ -11222,10 +11498,6 @@ Unit* Creature::SelectVictim()
//next-victim-selection algorithm and evade mode are called
//threat list sorting etc.
- //This should not be called by unit who does not have a threatlist
- //or who does not have threat (totem/pet/critter)
- //otherwise enterevademode every update
-
Unit* target = NULL;
// First checking if we have some taunt on us
const AuraEffectList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT);
@@ -11258,9 +11530,38 @@ Unit* Creature::SelectVictim()
target = getVictim();
}
- if ( !target && !m_ThreatManager.isThreatListEmpty() )
- // No taunt aura or taunt aura caster is dead standart target selection
- target = m_ThreatManager.getHostilTarget();
+ if (CanHaveThreatList())
+ {
+ if ( !target && !m_ThreatManager.isThreatListEmpty() )
+ // No taunt aura or taunt aura caster is dead standart target selection
+ target = m_ThreatManager.getHostilTarget();
+ }
+ else if(!HasReactState(REACT_PASSIVE))
+ {
+ // We have player pet probably
+ target = getAttackerForHelper();
+ if (!target && isSummon())
+ {
+ if (Unit * owner = ((TempSummon*)this)->GetOwner())
+ {
+ if (owner->isInCombat())
+ target = owner->getAttackerForHelper();
+ if (!target)
+ {
+ for(ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr)
+ {
+ if ((*itr)->isInCombat())
+ {
+ target = (*itr)->getAttackerForHelper();
+ if (target) break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ return NULL;
if(target)
{
@@ -11273,16 +11574,11 @@ Unit* Creature::SelectVictim()
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
// for example at owner command to pet attack some far away creature
// Note: creature not have targeted movement generator but have attacker in this case
- if(m_attackers.size())
- return NULL;
- /*if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE )
+ for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
{
- for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr)
- {
- if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) )
- return NULL;
- }
- }*/
+ if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) && ((*itr)->GetTypeId() != TYPEID_PLAYER && (!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN))))
+ return NULL;
+ }
// search nearby enemy before enter evade mode
if(HasReactState(REACT_AGGRESSIVE))
@@ -11368,8 +11664,8 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde
spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_INCREASE_SPEED &&
spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED)
//there are many more: slow speed, -healing pct
- //value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
- value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1));
+ value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f));
+ //value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1));
return value;
}
@@ -11509,29 +11805,29 @@ void Unit::IncrDiminishing(DiminishingGroup group)
m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2));
}
-void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level)
+void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level, int32 limitduration)
{
if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) )
return;
- // test pet/charm masters instead pets/charmeds
+ // test pet/charm masters instead pets/charmeds
Unit const* targetOwner = GetCharmerOrOwner();
Unit const* casterOwner = caster->GetCharmerOrOwner();
// Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
- if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group))
+ if(limitduration > 0 && duration > limitduration)
{
Unit const* target = targetOwner ? targetOwner : this;
Unit const* source = casterOwner ? casterOwner : caster;
if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER)
- duration = 10000;
+ duration = limitduration;
}
float mod = 1.0f;
// Some diminishings applies to mobs too (for example, Stun)
- if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? targetOwner->GetTypeId():GetTypeId()) == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
+ if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? (targetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL)
{
DiminishingLevels diminish = Level;
switch(diminish)
@@ -11884,6 +12180,8 @@ void Unit::SetHealth(uint32 val)
void Unit::SetMaxHealth(uint32 val)
{
+ if(!val) val = 1;
+
uint32 health = GetHealth();
SetUInt32Value(UNIT_FIELD_MAXHEALTH, val);
@@ -12066,7 +12364,7 @@ void Unit::RemoveFromWorld()
if(m_NotifyListPos >= 0)
{
- GetMap()->RemoveUnitFromNotify(m_NotifyListPos);
+ GetMap()->RemoveUnitFromNotify(this, m_NotifyListPos);
m_NotifyListPos = -1;
}
@@ -12148,11 +12446,9 @@ void Unit::DeleteCharmInfo()
CharmInfo::CharmInfo(Unit* unit)
: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_petnumber(0), m_barInit(false)
{
- for(uint8 i =0; i<MAX_SPELL_CHARM; ++i)
- {
- m_charmspells[i].spellId = 0;
- m_charmspells[i].active = ACT_DISABLED;
- }
+ for(uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
+ m_charmspells[i].SetActionAndType(0,ACT_DISABLED);
+
if(m_unit->GetTypeId() == TYPEID_UNIT)
{
m_oldReactState = ((Creature*)m_unit)->GetReactState();
@@ -12229,18 +12525,21 @@ void CharmInfo::InitCharmCreateSpells()
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
spellId = 0;
- m_charmspells[x].spellId = spellId;
-
if(!spellId)
+ {
+ m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED);
continue;
+ }
if (IsPassiveSpell(spellId))
{
m_unit->CastSpell(m_unit, spellId, true);
- m_charmspells[x].active = ACT_PASSIVE;
+ m_charmspells[x].SetActionAndType(spellId,ACT_PASSIVE);
}
else
{
+ m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED);
+
ActiveStates newstate;
if(spellInfo)
{
@@ -12275,11 +12574,11 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
// new spell rank can be already listed
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (uint32 action = PetActionBar[i].GetAction())
{
- if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
+ if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id)
{
- PetActionBar[i].SpellOrAction = spell_id;
+ PetActionBar[i].SetAction(spell_id);
return true;
}
}
@@ -12288,7 +12587,7 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
// or use empty slot in other case
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
SetActionBar(i,spell_id,newstate == ACT_DECIDE ? IsAutocastableSpell(spell_id) ? ACT_DISABLED : ACT_PASSIVE : newstate);
return true;
@@ -12303,9 +12602,9 @@ bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if (uint32 action = PetActionBar[i].GetAction())
{
- if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
+ if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id)
{
SetActionBar(i,0,ACT_PASSIVE);
return true;
@@ -12322,12 +12621,8 @@ void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply)
return;
for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
- {
- if(spellid == m_charmspells[x].spellId)
- {
- m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED;
- }
- }
+ if(spellid == m_charmspells[x].GetAction())
+ m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
}
void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
@@ -12353,17 +12648,19 @@ void CharmInfo::LoadPetActionBar(const std::string& data )
for(iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index )
{
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
- PetActionBar[index].Type = atol((*iter).c_str());
+ uint8 type = atol((*iter).c_str());
++iter;
- PetActionBar[index].SpellOrAction = atol((*iter).c_str());
+ uint32 action = atol((*iter).c_str());
+
+ PetActionBar[index].SetActionAndType(action,ActiveStates(type));
// check correctness
if(PetActionBar[index].IsActionBarForSpell())
{
- if(!sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction))
+ if(!sSpellStore.LookupEntry(PetActionBar[index].GetAction()))
SetActionBar(index,0,ACT_PASSIVE);
- else if(!IsAutocastableSpell(PetActionBar[index].SpellOrAction))
- SetActionBar(index,PetActionBar[index].SpellOrAction,ACT_PASSIVE);
+ else if(!IsAutocastableSpell(PetActionBar[index].GetAction()))
+ SetActionBar(index,PetActionBar[index].GetAction(),ACT_PASSIVE);
}
}
}
@@ -12371,19 +12668,16 @@ void CharmInfo::LoadPetActionBar(const std::string& data )
void CharmInfo::BuildActionBar( WorldPacket* data )
{
for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- *data << uint16(PetActionBar[i].SpellOrAction);
- *data << uint16(PetActionBar[i].Type);
- }
+ *data << uint32(PetActionBar[i].packedData);
}
void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state )
{
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
- if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
+ if(spell_id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
- PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED;
+ PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED);
break;
}
}
@@ -12427,8 +12721,10 @@ bool InitTriggerAuraData()
isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
- isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; // Aura not have charges but need remove him on trigger
+ isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
+ isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura not have charges but need remove him on trigger
isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_TRANSFORM] = true;
isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
@@ -12499,8 +12795,11 @@ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missC
void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage , SpellEntry const * procAura)
{
- // For melee/ranged based attack need update skills and set some Aura states
- if (procFlag & MELEE_BASED_TRIGGER_MASK)
+ // Player is loaded now - do not allow passive spell casts to proc
+ if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetSession()->PlayerLoading())
+ return;
+ // For melee/ranged based attack need update skills and set some Aura states if victim present
+ if (procFlag & MELEE_BASED_TRIGGER_MASK && pTarget)
{
// Update skills here for players
if (GetTypeId() == TYPEID_PLAYER)
@@ -12616,6 +12915,9 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown)
cooldown = i->spellProcEvent->cooldown;
+ if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC)
+ SetCantProc(true);
+
// This bool is needed till separate aura effect procs are still here
bool handled = false;
if (HandleAuraProc(pTarget, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled))
@@ -12640,8 +12942,8 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
{
sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
// Don`t drop charge or add cooldown for not started trigger
- if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
+ if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ takeCharges=true;
break;
}
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
@@ -12653,53 +12955,64 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
+ takeCharges=true;
break;
}
case SPELL_AURA_MANA_SHIELD:
case SPELL_AURA_DUMMY:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 1)
- sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 1;
+ if (HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 1)
+ sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 1;
+ }
break;
}
case SPELL_AURA_OBS_MOD_ENERGY:
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 2)
- sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 2;
+ if (HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 2)
+ sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 2;
+ }
break;
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 16)
- sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 16;
+ if (HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 16)
+ sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 16;
+ }
break;
case SPELL_AURA_MOD_HASTE:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- continue;
- if (procDebug & 4)
- sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 4;
+ if (HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 4)
+ sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 4;
+ }
break;
}
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
{
sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (!HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown))
- continue;
- if (procDebug & 8)
- sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id);
- procDebug |= 8;
+ if (HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown))
+ {
+ takeCharges=true;
+ if (procDebug & 8)
+ sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id);
+ procDebug |= 8;
+ }
break;
}
case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE:
@@ -12708,6 +13021,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
HandleAuraRaidProcFromChargeWithValue(triggeredByAura);
+ takeCharges=true;
break;
}
case SPELL_AURA_RAID_PROC_FROM_CHARGE:
@@ -12716,68 +13030,92 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
HandleAuraRaidProcFromCharge(triggeredByAura);
+ takeCharges=true;
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;
+ if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ takeCharges=true;
break;
}
case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK:
// Skip melee hits or instant cast spells
- if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
- continue;
+ if (procSpell && GetSpellCastTime(procSpell) != 0)
+ takeCharges=true;
break;
case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
// Skip Melee hits and spells ws wrong school
- if (procSpell == NULL || (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0)
- continue;
+ if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check
+ takeCharges=true;
break;
case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
case SPELL_AURA_MOD_POWER_COST_SCHOOL:
// Skip melee hits and spells ws wrong school or zero cost
- if (procSpell == NULL ||
- (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
+ if (procSpell &&
+ (procSpell->manaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check
(triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0) // School check
- continue;
+ takeCharges=true;
break;
case SPELL_AURA_MECHANIC_IMMUNITY:
// Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
- continue;
+ if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
// Compare mechanic
- if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue())
- continue;
+ if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_DAMAGE_FROM_CASTER:
// Compare casters
- if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID())
- continue;
+ if (triggeredByAura->GetCasterGUID() == pTarget->GetGUID())
+ takeCharges=true;
break;
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- if (!procSpell)
- continue;
+ if (procSpell)
+ takeCharges=true;
break;
- /*case SPELL_AURA_ADD_FLAT_MODIFIER:
- case SPELL_AURA_ADD_PCT_MODIFIER:
+ // CC Auras which use their amount amount to drop
+ // Are there any more auras which need this?
+ case SPELL_AURA_MOD_CONFUSE:
+ case SPELL_AURA_MOD_FEAR:
+ case SPELL_AURA_MOD_STUN:
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_TRANSFORM:
+ if (isVictim && damage)
+ {
+ // Damage is dealt after proc system - lets ignore auras which wasn't updated yet
+ // to make spell not remove its own aura
+ if (i->aura->GetAuraDuration() == i->aura->GetAuraMaxDuration())
+ break;
+ int32 damageLeft = triggeredByAura->GetAmount();
+ // No damage left
+ if (damageLeft < damage )
+ RemoveAura(i->aura);
+ else
+ triggeredByAura->SetAmount(damageLeft-damage);
+ }
+ break;
+ //case SPELL_AURA_ADD_FLAT_MODIFIER:
+ //case SPELL_AURA_ADD_PCT_MODIFIER:
// HandleSpellModAuraProc
- break;*/
+ //break;
default:
// nothing do, just charges counter
+ takeCharges=true;
break;
}
- takeCharges=true;
}
// Remove charge (aura can be removed by triggers)
if(useCharges && takeCharges)
{
i->aura->DropAuraCharge();
}
+ if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC)
+ SetCantProc(false);
}
// Cleanup proc requirements
@@ -12845,33 +13183,6 @@ void Unit::SendPetTalk (uint32 pettalk)
((Player*)owner)->GetSession()->SendPacket(&data);
}
-void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime)
-{
- Unit* owner = GetOwner();
- if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4);
- data << uint64(GetGUID());
- data << uint8(0x0); // flags (0x1, 0x2)
- data << uint32(spellid);
- data << uint32(cooltime);
-
- ((Player*)owner)->GetSession()->SendPacket(&data);
-}
-
-void Unit::SendPetClearCooldown (uint32 spellid)
-{
- Unit* owner = GetOwner();
- if(!owner || owner->GetTypeId() != TYPEID_PLAYER)
- return;
-
- WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8);
- data << uint32(spellid);
- data << uint64(GetGUID());
- ((Player*)owner)->GetSession()->SendPacket(&data);
-}
-
void Unit::SendPetAIReaction(uint64 guid)
{
Unit* owner = GetOwner();
@@ -13312,21 +13623,13 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized)
}
}
-AuraEffect* Unit::GetDummyAura( uint32 spell_id ) const
-{
- Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
- if ((*itr)->GetId() == spell_id)
- return *itr;
-
- return NULL;
-}
-
-AuraEffect* Unit::GetDummyAura(SpellFamilyNames name, uint32 iconId) const
+AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
{
- Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY);
+ Unit::AuraEffectList const& mDummy = GetAurasByType(type);
for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
+ if (effIndex != (*itr)->GetEffIndex())
+ continue;
SpellEntry const * spell = (*itr)->GetSpellProto();
if (spell->SpellIconID == iconId && spell->SpellFamilyName == name
&& !spell->SpellFamilyFlags)
@@ -13368,12 +13671,6 @@ void Unit::AddPetAura(PetAura const* petSpell)
if(GetTypeId() != TYPEID_PLAYER)
return;
- // Aura already added - not need to add it twice
- // This check is to prevent existing pet having aura applied twice (passive auras can stack)
- // if aura has more than 1 dummy effect
- if (m_petAuras.find(petSpell)!= m_petAuras.end())
- return;
-
m_petAuras.insert(petSpell);
if(Pet* pet = ((Player*)this)->GetPet())
pet->CastPetAura(petSpell);
@@ -13445,15 +13742,15 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if (!EventProcFlag)
return false;
- // Additional checks for triggered spells
- if (procExtra & PROC_EX_INTERNAL_TRIGGERED)
+ // Additional checks for triggered spells (ignore trap casts)
+ if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_ON_TRAP_ACTIVATION))
{
if (!(spellProto->AttributesEx3 & SPELL_ATTR_EX3_CAN_PROC_TRIGGERED))
return false;
}
// Check spellProcEvent data requirements
- if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra))
+ if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
return false;
// In most cases req get honor or XP from kill
if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER)
@@ -13465,7 +13762,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if (!allow)
return false;
}
- // Aura added by spell can`t trogger from self (prevent drop charges/do triggers)
+ // Aura added by spell can`t trigger from self (prevent drop charges/do triggers)
// But except periodic and kill triggers (can triggered from self)
if(procSpell && procSpell->Id == spellProto->Id
&& !(spellProto->procFlags&(PROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_KILL)))
@@ -13504,10 +13801,18 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co
if(spellProcEvent && spellProcEvent->customChance)
chance = spellProcEvent->customChance;
// If PPM exist calculate chance from PPM
- if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
+ if(spellProcEvent && spellProcEvent->ppmRate != 0)
{
- uint32 WeaponSpeed = GetAttackTime(attType);
- chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ if(!isVictim)
+ {
+ uint32 WeaponSpeed = GetAttackTime(attType);
+ chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ }
+ else
+ {
+ uint32 WeaponSpeed = pVictim->GetAttackTime(attType);
+ chance = pVictim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto);
+ }
}
// Apply chance modifer aura
if(Player* modOwner = GetSpellModOwner())
@@ -13583,7 +13888,7 @@ bool Unit::HandleAuraRaidProcFromCharge( AuraEffect* triggeredByAura )
damageSpellId=43594;
break;
default:
- sLog.outDebug("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id);
+ sLog.outError("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id);
return false;
}
@@ -13664,6 +13969,9 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0);
}
+ // Proc auras on death - must be before aura/combat remove
+ pVictim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
+
// if talent known but not triggered (check priest class for speedup check)
bool SpiritOfRedemption = false;
if(pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST )
@@ -13705,10 +14013,10 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
((Player*)pVictim)->SetPvPDeath(player!=NULL);
// only if not player and not controlled by player pet. And not at BG
- if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround())
+ if ( (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) || ( player && sWorld.getConfig(CONFIG_DURABILITY_LOSS_IN_PVP) ) )
{
- DEBUG_LOG("We are dead, loosing 10 percents durability");
- ((Player*)pVictim)->DurabilityLossAll(0.10f,false);
+ DEBUG_LOG("We are dead, losing %u percent durability", sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH));
+ ((Player*)pVictim)->DurabilityLossAll(sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH),false);
// durability lost message
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
((Player*)pVictim)->GetSession()->SendPacket(&data);
@@ -13912,27 +14220,22 @@ void Unit::SetRooted(bool apply)
{
AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
- if(GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
- data.append(GetPackGUID());
- data << (uint32)2;
- SendMessageToSet(&data,true);
- }
- else
+ WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
+ data.append(GetPackGUID());
+ data << (uint32)2;
+ SendMessageToSet(&data,true);
+
+ if(GetTypeId() != TYPEID_PLAYER)
((Creature *)this)->StopMoving();
}
else
{
if(!hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
{
- if(GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
- data.append(GetPackGUID());
- data << (uint32)2;
- SendMessageToSet(&data,true);
- }
+ WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
+ data.append(GetPackGUID());
+ data << (uint32)2;
+ SendMessageToSet(&data,true);
RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
}
@@ -13990,22 +14293,28 @@ void Unit::SetConfused(bool apply)
((Player*)this)->SetClientControl(this, !apply);
}
-void Unit::SetCharmedBy(Unit* charmer, CharmType type)
+bool Unit::SetCharmedBy(Unit* charmer, CharmType type)
{
if(!charmer)
- return;
+ return false;
assert(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
assert(type != CHARM_TYPE_VEHICLE || GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isVehicle());
+ sLog.outDebug("SetCharmedBy: charmer %u, charmed %u, type %u.", charmer->GetEntry(), GetEntry(), (uint32)type);
+
if(this == charmer)
- return;
+ return false;
- if(hasUnitState(UNIT_STAT_UNATTACKABLE))
- return;
+ //if(hasUnitState(UNIT_STAT_UNATTACKABLE))
+ // return false;
if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport())
- return;
+ return false;
+
+ // Already charmed
+ if(GetCharmerGUID())
+ return false;
CastStop();
CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells)
@@ -14027,7 +14336,7 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type)
// StopCastingCharm may remove a possessed pet?
if(!IsInWorld())
- return;
+ return false;
// Set charmed
setFaction(charmer->getFaction());
@@ -14096,7 +14405,8 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type)
case CHARM_TYPE_CONVERT:
break;
}
- }
+ }
+ return true;
}
void Unit::RemoveCharmedBy(Unit *charmer)
@@ -14106,8 +14416,13 @@ void Unit::RemoveCharmedBy(Unit *charmer)
if(!charmer)
charmer = GetCharmer();
- else if(charmer != GetCharmer()) // one aura overrides another?
+ if(charmer != GetCharmer()) // one aura overrides another?
+ {
+// sLog.outCrash("Unit::RemoveCharmedBy: this: " UI64FMTD " true charmer: " UI64FMTD " false charmer: " UI64FMTD,
+// GetGUID(), GetCharmerGUID(), charmer->GetGUID());
+// assert(false);
return;
+ }
CharmType type;
if(hasUnitState(UNIT_STAT_POSSESSED))
@@ -14525,6 +14840,12 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType,
void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
{
+ if(newPhaseMask==GetPhaseMask())
+ return;
+
+ if(IsInWorld())
+ RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target
+
WorldObject::SetPhaseMask(newPhaseMask,update);
if(!IsInWorld())
@@ -14626,7 +14947,6 @@ void Unit::EnterVehicle(Vehicle *vehicle, int8 seatId)
return;
}
- addUnitState(UNIT_STAT_ONVEHICLE);
SetControlled(true, UNIT_STAT_ROOT);
//movementInfo is set in AddPassenger
//packets are sent in AddPassenger
@@ -14671,7 +14991,6 @@ void Unit::ExitVehicle()
Vehicle *vehicle = m_Vehicle;
m_Vehicle = NULL;
- clearUnitState(UNIT_STAT_ONVEHICLE);
SetControlled(false, UNIT_STAT_ROOT);
RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
@@ -14682,6 +15001,8 @@ void Unit::ExitVehicle()
m_movementInfo.t_time = 0;
m_movementInfo.t_seat = 0;
+ Relocate(vehicle->GetPositionX(), vehicle->GetPositionY(), vehicle->GetPositionZ(), GetOrientation());
+
//Send leave vehicle, not correct
if(GetTypeId() == TYPEID_PLAYER)
{
@@ -14830,3 +15151,89 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
//SendMessageToSet(&data, false);
}
}
+
+void Unit::SendThreatListUpdate()
+{
+ if (uint32 count = getThreatManager().getThreatList().size())
+ {
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_UPDATE Message" );
+ WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8);
+ data.append(GetPackGUID());
+ data << uint32(count);
+ std::list<HostilReference*>& tlist = getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr)
+ {
+ data.appendPackGUID((*itr)->getUnitGuid());
+ data << uint32((*itr)->getThreat());
+ }
+ SendMessageToSet(&data, false);
+ }
+}
+
+
+void Unit::SendChangeCurrentVictimOpcode(HostilReference* pHostilReference)
+{
+ if (uint32 count = getThreatManager().getThreatList().size())
+ {
+ sLog.outDebug( "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message" );
+ WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8);
+ data.append(GetPackGUID());
+ data.appendPackGUID(pHostilReference->getUnitGuid());
+ data << uint32(count);
+ std::list<HostilReference*>& tlist = getThreatManager().getThreatList();
+ for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr)
+ {
+ data.appendPackGUID((*itr)->getUnitGuid());
+ data << uint32((*itr)->getThreat());
+ }
+ SendMessageToSet(&data, false);
+ }
+}
+
+void Unit::SendClearThreatListOpcode()
+{
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_CLEAR Message" );
+ WorldPacket data(SMSG_THREAT_CLEAR, 8);
+ data.append(GetPackGUID());
+ SendMessageToSet(&data, false);
+}
+
+void Unit::SendRemoveFromThreatListOpcode(HostilReference* pHostilReference)
+{
+ sLog.outDebug( "WORLD: Send SMSG_THREAT_REMOVE Message" );
+ WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8);
+ data.append(GetPackGUID());
+ data.appendPackGUID(pHostilReference->getUnitGuid());
+ SendMessageToSet(&data, false);
+}
+
+void Unit::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker )
+{
+ float addRage;
+
+ float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911;
+
+ // Unknown if correct, but lineary adjust rage conversion above level 70
+ if (getLevel() > 70)
+ rageconversion += 13.27f*(getLevel()-70);
+
+ if(attacker)
+ {
+ addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2);
+
+ // talent who gave more rage on attack
+ addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f;
+ }
+ else
+ {
+ addRage = damage/rageconversion*2.5;
+
+ // Berserker Rage effect
+ if(HasAura(18499))
+ addRage *= 2.0;
+ }
+
+ addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME);
+
+ ModifyPower(POWER_RAGE, uint32(addRage*10));
+}