[7049] Work vs Auras

Allow stack some auras from some caster in one
Move apply/remove aura state on apply/remove aura (on 1 add / on last remove)
Correctly fill aura flag and send duration update to client
Not use m_procCharges for store satack amount, used m_stackAmount
Fixes in HandlePeriodicDamage (use m_stackAmount, fix formulas to 303, optimisation)
Fixes in Spell::EffectSchoolDMG (use m_stackAmount, fix formulas to 303)
Remove unused uint32 m_PeriodicEventId from aura struct
Add Unit::RemoveSingleSpellAurasFromStack for remove one Spell auras from stack
Add Aura::RefreshAura() for refresh aura duration

Signed-off-by: DiSlord <dislord@nomail.com>
This commit is contained in:
DiSlord 2009-01-08 01:12:22 +03:00
parent 32a7c35a95
commit c2741b50e7
6 changed files with 352 additions and 346 deletions

View file

@ -337,14 +337,16 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
};
Aura::Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem) :
m_procCharges(0), m_spellmod(NULL), m_effIndex(eff), m_caster_guid(0), m_target(target),
m_timeCla(1000), m_castItemGuid(castItem?castItem->GetGUID():0), m_auraSlot(MAX_AURAS),
m_positive(false), m_permanent(false), m_isPeriodic(false), m_isTrigger(false), m_isAreaAura(false),
m_isPersistent(false), m_updated(false), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_isRemovedOnShapeLost(true), m_in_use(false),
m_periodicTimer(0), m_PeriodicEventId(0), m_AuraDRGroup(DIMINISHING_NONE)
m_spellmod(NULL), m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target),
m_timeCla(1000), m_periodicTimer(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE),
m_effIndex(eff), m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),
m_positive(false), m_permanent(false), m_isPeriodic(false), m_isTrigger(false), m_isAreaAura(false), m_isPersistent(false),
m_updated(false), m_isRemovedOnShapeLost(true), m_in_use(false)
{
assert(target);
int32 size = sizeof(Aura);
assert(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
m_spellProto = spellproto;
@ -889,12 +891,12 @@ void Aura::_AddAura()
if(!m_target)
return;
// we can found aura in NULL_AURA_SLOT and then need store state instead check slot != NULL_AURA_SLOT
bool samespell = false;
// Second aura if some spell
bool secondaura = false;
// Try find slot for aura
uint8 slot = NULL_AURA_SLOT;
for(uint8 i = 0; i < 3; i++)
// Lookup for some spell auras (and get slot from it)
for(uint8 i = 0; i < m_effIndex; i++)
{
Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
@ -902,18 +904,30 @@ void Aura::_AddAura()
// allow use single slot only by auras from same caster
if(itr->second->GetCasterGUID()==GetCasterGUID())
{
samespell = true;
if (m_effIndex > itr->second->GetEffIndex())
secondaura = true;
slot = itr->second->GetAuraSlot();
secondaura = true;
break;
}
}
if(samespell)
if (secondaura)
break;
}
// Lookup free slot
if (!secondaura && m_target->GetVisibleAurasCount() < MAX_AURAS)
{
Unit::VisibleAuraMap const *visibleAuras = m_target->GetVisibleAuras();
for(uint8 i = 0; i < MAX_AURAS; ++i)
{
Unit::VisibleAuraMap::const_iterator itr = visibleAuras->find(i);
if(itr == visibleAuras->end())
{
slot = i;
// update for out of range group members (on 1 slot use)
m_target->UpdateAuraForGroup(slot);
break;
}
}
}
// not call total regen auras at adding
switch (m_modifier.m_auraname)
{
@ -939,59 +953,44 @@ void Aura::_AddAura()
if((!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) &&
(m_spellProto->Effect[GetEffIndex()] != SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || m_target != caster))
{
if(!samespell) // new slot need
SetAuraSlot( slot );
if(slot < MAX_AURAS) // slot found send data to client
{
if(m_target->GetVisibleAurasCount() < MAX_AURAS)
{
Unit::VisibleAuraMap const *visibleAuras = m_target->GetVisibleAuras();
for(uint8 i = 0; i < MAX_AURAS; ++i)
{
Unit::VisibleAuraMap::const_iterator itr = visibleAuras->find(i);
if(itr == visibleAuras->end())
{
slot = i;
break;
}
}
}
SetAuraSlot( slot );
// Not update fields for not first spell's aura, all data already in fields
if(!secondaura)
{
if(slot < MAX_AURAS) // slot found
{
SetAura(false);
SetAuraFlags((1 << GetEffIndex()) | AFLAG_NOT_CASTER | ((GetAuraMaxDuration() > 0) ? AFLAG_DURATION : AFLAG_NONE) | (IsPositive() ? AFLAG_POSITIVE : AFLAG_NEGATIVE));
SetAuraLevel(caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
SendAuraUpdate(false);
// update for out of range group members
m_target->UpdateAuraForGroup(slot);
}
}
}
else // use found slot
{
SetAuraSlot( slot );
// Not recalculate stack count for second aura of the same spell
if (!secondaura)
UpdateSlotCounterAndDuration(true);
SetAura(false);
SetAuraFlags((1 << GetEffIndex()) | AFLAG_NOT_CASTER | ((GetAuraMaxDuration() > 0) ? AFLAG_DURATION : AFLAG_NONE) | (IsPositive() ? AFLAG_POSITIVE : AFLAG_NEGATIVE));
SetAuraLevel(caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
SendAuraUpdate(false);
}
// Update Seals information
if( IsSealSpell(GetSpellProto()) )
m_target->ModifyAuraState(AURA_STATE_JUDGEMENT, true);
// Conflagrate aura state
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
m_target->ModifyAuraState(AURA_STATE_IMMOLATE, true);
if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
&& (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
//*****************************************************
// Update target aura state flag (at 1 aura apply)
// TODO: Make it easer
//*****************************************************
if (!secondaura)
{
m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
// Update Seals information
if( IsSealSpell(GetSpellProto()) )
m_target->ModifyAuraState(AURA_STATE_JUDGEMENT, true);
// Conflagrate aura state on Immolate
if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags & 4)
m_target->ModifyAuraState(AURA_STATE_IMMOLATE, true);
// Faerie Fire (druid versions)
if( m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags & 0x0000000000000400LL)
m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE, true);
// Victorious
if( m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags & 0x0004000000000000LL)
m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, true);
// Swiftmend state on Regrowth & Rejuvenation
if(m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags & 0x50 )
m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
// Deadly poison aura state
if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags & 0x10000)
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON, true);
}
}
}
@ -1029,8 +1028,7 @@ void Aura::_RemoveAura()
if(m_target->GetVisibleAura(slot) == 0)
return;
bool samespell = false;
bool sameaura = false;
bool lastaura = true;
// find other aura in same slot (current already removed from list)
for(uint8 i = 0; i < 3; i++)
@ -1040,30 +1038,30 @@ void Aura::_RemoveAura()
{
if(itr->second->GetAuraSlot()==slot)
{
samespell = true;
if(GetEffIndex()==i)
sameaura = true;
lastaura = false;
break;
}
}
if(samespell)
if(!lastaura)
break;
}
// only remove icon when the last aura of the spell is removed (current aura already removed from list)
if (!samespell)
if (lastaura)
{
SetAura(true);
SetAuraFlags(AFLAG_NONE);
SetAuraLevel(0);
SetAuraCharges(0);
SendAuraUpdate(true);
// update for out of range group members
m_target->UpdateAuraForGroup(slot);
//*****************************************************
// Update target aura state flag (at last aura remove)
// TODO: Make it easer
//*****************************************************
// Update Seals information
if( IsSealSpell(GetSpellProto()) )
m_target->ModifyAuraState(AURA_STATE_JUDGEMENT,false);
@ -1071,16 +1069,22 @@ void Aura::_RemoveAura()
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
m_target->ModifyAuraState(AURA_STATE_IMMOLATE, false);
// Faerie Fire (druid versions)
if( m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags & 0x0000000000000400LL)
m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE, false);
// Victorious
if( m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags & 0x0004000000000000LL)
m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
// Swiftmend aura state
if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
&& (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID && GetSpellProto()->SpellFamilyFlags & 0x50)
{
bool found = false;
Unit::AuraList const& RejorRegr = m_target->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{
if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
&& ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID && (*i)->GetSpellProto()->SpellFamilyFlags & 0x50 )
{
found = true;
break;
@ -1090,6 +1094,26 @@ void Aura::_RemoveAura()
m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, false);
}
// Deadly poison aura state
if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags & 0x10000)
{
// current aura already removed, search present of another
bool found = false;
Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const* itr_spell = (*itr)->GetSpellProto();
if(itr_spell && itr_spell->SpellFamilyName==SPELLFAMILY_ROGUE && itr_spell->SpellFamilyFlags & 0x10000)
{
found = true;
break;
}
}
// this has been last deadly poison aura
if(!found)
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON,false);
}
// reset cooldown state for spells
if(caster && caster->GetTypeId() == TYPEID_PLAYER)
{
@ -1097,8 +1121,6 @@ void Aura::_RemoveAura()
((Player*)caster)->SendCooldownEvent(GetSpellProto());
}
}
else if(sameaura) // decrease count for spell, only for same aura effect, or this spell auras in remove process.
UpdateSlotCounterAndDuration(false);
}
void Aura::SendAuraUpdate(bool remove)
@ -1117,7 +1139,7 @@ void Aura::SendAuraUpdate(bool remove)
uint8 auraFlags = GetAuraFlags();
data << uint8(auraFlags);
data << uint8(GetAuraLevel());
data << uint8(GetAuraCharges());
data << uint8(m_procCharges ? m_procCharges : m_stackAmount);
if(!(auraFlags & AFLAG_NOT_CASTER))
{
@ -1133,35 +1155,51 @@ void Aura::SendAuraUpdate(bool remove)
m_target->SendMessageToSet(&data, true);
}
void Aura::UpdateSlotCounterAndDuration(bool add)
void Aura::SetStackAmount(uint8 stackAmount)
{
uint8 slot = GetAuraSlot();
if(slot >= MAX_AURAS)
return;
// calculate amount of similar auras by same effect index (similar different spells)
int8 count = 0;
// calculate auras and update durations in case aura adding
Unit::AuraList const& aura_list = m_target->GetAurasByType(GetModifier()->m_auraname);
for(Unit::AuraList::const_iterator i = aura_list.begin();i != aura_list.end(); ++i)
if (stackAmount != m_stackAmount)
{
if( (*i)->GetId()==GetId() && (*i)->GetEffIndex()==m_effIndex &&
(*i)->GetCasterGUID()==GetCasterGUID() )
Unit *target = GetTarget();
Unit *caster = GetCaster();
if (!target || !caster)
return;
m_stackAmount = stackAmount;
int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, target);
// Reapply if amount change
if (amount!=m_modifier.m_amount)
{
++count;
if(add)
(*i)->SetAuraDuration(GetAuraDuration());
ApplyModifier(false, true);
m_modifier.m_amount = amount;
ApplyModifier(true, true);
}
}
RefreshAura();
}
// at aura add aura not added yet, at aura remove aura already removed
// in field stored (count-1)
if(!add)
--count;
bool Aura::modStackAmount(int32 num)
{
// Can`t mod
if (!m_spellProto->StackAmount)
return true;
SetAuraCharges(count);
// Modify stack but limit it
int32 stackAmount = m_stackAmount + num;
if (stackAmount > m_spellProto->StackAmount)
stackAmount = m_spellProto->StackAmount;
else if (stackAmount <=0) // Last aura from stack removed
{
m_stackAmount = 0;
return true; // need remove aura
}
// Update stack amount
SetStackAmount(stackAmount);
return false;
}
void Aura::RefreshAura()
{
m_duration = m_maxduration;
SendAuraUpdate(false);
}
@ -2148,12 +2186,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_target->RemoveAurasDueToSpell(spellId);
return;
}
// Victorious
if(GetId()==32216 && m_target->getClass()==CLASS_WARRIOR)
{
m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, apply);
return;
}
//Summon Fire Elemental
if (GetId() == 40133 && caster)
{
@ -2213,8 +2245,11 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
return;
// final heal
if(m_target->IsInWorld())
m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
if(m_target->IsInWorld() && m_stackAmount > 0)
{
int32 amount = m_modifier.m_amount / m_stackAmount;
m_target->CastCustomSpell(m_target,33778,&amount,NULL,NULL,true,NULL,this,GetCasterGUID());
}
}
return;
}
@ -3593,15 +3628,11 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
return;
// Search Mana Tap auras on caster
int32 energy = 0;
Unit::AuraList const& m_dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
if ((*i)->GetId() == 28734)
++energy;
if (energy)
Aura * dummy = caster->GetDummyAura(28734);
if (dummy)
{
energy *= 10;
caster->CastCustomSpell(caster, 25048, &energy, NULL, NULL, true);
int32 bp = dummy->GetStackAmount() * 10;
caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true);
caster->RemoveAurasDueToSpell(28734);
}
}
@ -4089,6 +4120,10 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
Unit *caster = GetCaster();
// Custom damage calculation after
if (!apply || loading || !caster)
return;
switch (m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
@ -4097,8 +4132,7 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual[0] == 0 )
{
// $AP*0.18/6 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
return;
}
break;
@ -4108,16 +4142,12 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
// Rend
if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
{
// 0.00743*(($MWB+$mwb)/2+$AP/14*$MWS) bonus per tick
if (apply && !loading && caster)
{
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 mws = caster->GetAttackTime(BASE_ATTACK);
float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
// WARNING! in 3.0 multiplier 0.00743f change to 0.6
m_modifier.m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.00743f);
}
// $0.2*(($MWB+$mwb)/2+$AP/14*$MWS) bonus per tick
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 mws = caster->GetAttackTime(BASE_ATTACK);
float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
m_modifier.m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.2f);
return;
}
break;
@ -4127,90 +4157,77 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
// Rake
if (m_spellProto->SpellFamilyFlags & 0x0000000000001000LL)
{
// $AP*0.06/3 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 / 100);
// $AP*0.06 bonus per tick
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 6 / 100);
return;
}
// Lacerate
if (m_spellProto->SpellFamilyFlags & 0x000000010000000000LL)
{
// $AP*0.05/5 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
return;
}
// Rip
if (m_spellProto->SpellFamilyFlags & 0x000000000000800000LL)
{
// $AP * min(0.06*$cp, 0.24)/6 [Yes, there is no difference, whether 4 or 5 CPs are being used]
if (apply && !loading && caster && caster->GetTypeId() == TYPEID_PLAYER)
// 0.01*$AP*cp
if (caster->GetTypeId() != TYPEID_PLAYER)
return;
uint8 cp = ((Player*)caster)->GetComboPoints();
// Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
uint8 cp = ((Player*)caster)->GetComboPoints();
// Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
if((*itr)->GetId()==34241)
{
if((*itr)->GetId()==34241)
{
m_modifier.m_amount += cp * (*itr)->GetModifier()->m_amount;
break;
}
m_modifier.m_amount += cp * (*itr)->GetModifier()->m_amount;
break;
}
if (cp > 4) cp = 4;
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
}
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
return;
}
// Lock Jaw
if (m_spellProto->SpellFamilyFlags & 0x1000000000000000LL)
{
// 0.15*$AP
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 15 / 100);
return;
}
break;
}
case SPELLFAMILY_ROGUE:
{
// Deadly poison aura state
if((m_spellProto->SpellFamilyFlags & 0x10000) && m_spellProto->SpellVisual[0]==5100)
{
if(apply)
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON,true);
else
{
// current aura already removed, search present of another
bool found = false;
Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const* itr_spell = (*itr)->GetSpellProto();
if(itr_spell && itr_spell->SpellFamilyName==SPELLFAMILY_ROGUE && (itr_spell->SpellFamilyFlags & 0x10000) && itr_spell->SpellVisual[0]==5100)
{
found = true;
break;
}
}
// this has been last deadly poison aura
if(!found)
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON,false);
}
return;
}
// Rupture
if (m_spellProto->SpellFamilyFlags & 0x000000000000100000LL)
{
// Dmg/tick = $AP*min(0.01*$cp, 0.03) [Like Rip: only the first three CP increase the contribution from AP]
if (apply && !loading && caster && caster->GetTypeId() == TYPEID_PLAYER)
{
uint8 cp = ((Player*)caster)->GetComboPoints();
if (cp > 3) cp = 3;
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
}
if (caster->GetTypeId() != TYPEID_PLAYER)
return;
//1 point : ${($m1+$b1*1+0.015*$AP)*4} damage over 8 secs
//2 points: ${($m1+$b1*2+0.024*$AP)*5} damage over 10 secs
//3 points: ${($m1+$b1*3+0.03*$AP)*6} damage over 12 secs
//4 points: ${($m1+$b1*4+0.03428571*$AP)*7} damage over 14 secs
//5 points: ${($m1+$b1*5+0.0375*$AP)*8} damage over 16 secs
float AP_per_combo[] = {0, 0.015f, 0.024, 0.03, 0.03428571, 0.0375};
uint8 cp = ((Player*)caster)->GetComboPoints();
if (cp > 5) cp = 5;
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]);
return;
}
// Garrote
if (m_spellProto->SpellFamilyFlags & 0x000000000000000100LL)
{
// $AP*0.18/6 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
// $AP*0.07 bonus per tick
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 7 / 100);
return;
}
if (m_spellProto->SpellFamilyFlags & 0x0000000000010000)
{
// 0.08*$AP / 4 * amount of stack
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 * GetStackAmount() * / 100);
return;
}
break;
@ -4221,16 +4238,14 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
if (m_spellProto->SpellFamilyFlags & 0x0000000000004000LL)
{
// $RAP*0.1/5 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
return;
}
// Immolation Trap
if (m_spellProto->SpellFamilyFlags & 0x0000000000000004LL && m_spellProto->SpellIconID == 678)
{
// $RAP*0.1/5 bonus per tick
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
return;
}
break;
@ -4240,34 +4255,35 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real)
// Consecration
if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
{
if (apply && !loading && caster)
// ($m1+0.04*$SPH+0.04*$AP)
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) +
caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellProto), m_target);
m_modifier.m_amount += int32(0.04f*holy + 0.04f*ap);
// Improved Consecration - Libram of the Eternal Rest
Unit::AuraList const& classScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for(Unit::AuraList::const_iterator k = classScripts.begin(); k != classScripts.end(); ++k)
{
Unit::AuraList const& classScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for(Unit::AuraList::const_iterator k = classScripts.begin(); k != classScripts.end(); ++k)
switch((*k)->GetModifier()->m_miscvalue)
{
int32 tickcount = GetSpellDuration(m_spellProto) / m_spellProto->EffectAmplitude[m_effIndex];
switch((*k)->GetModifier()->m_miscvalue)
case 5147:
{
case 5147: // Improved Consecration - Libram of the Eternal Rest
{
m_modifier.m_amount += (*k)->GetModifier()->m_amount / tickcount;
break;
}
int32 tickcount = GetSpellDuration(m_spellProto) / m_spellProto->EffectAmplitude[m_effIndex];
m_modifier.m_amount += (*k)->GetModifier()->m_amount / tickcount;
break;
}
}
}
return;
}
// Seal of Vengeance 0.013*$SPH+0.025*$AP per tick
// Seal of Vengeance 0.013*$SPH+0.025*$AP per tick (also can stack)
if(m_spellProto->SpellFamilyFlags & 0x0000080000000000LL)
{
if (apply && !loading && caster)
{
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) +
caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellProto), m_target);
m_modifier.m_amount += int32(ap * 0.025f) + int32(holy * 13 / 1000);
}
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) +
caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellProto), m_target);
m_modifier.m_amount += int32((0.013f*holy + 0.025f*ap) * GetStackAmount());
return;
}
break;
@ -4333,14 +4349,6 @@ void Aura::HandleAuraModResistance(bool apply, bool Real)
m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,m_modifier.m_amount, apply);
}
}
// Faerie Fire (druid versions)
if( m_spellProto->SpellIconID == 109 &&
m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID &&
m_spellProto->SpellFamilyFlags & 0x0000000000000400LL )
{
m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE,apply);
}
}
void Aura::HandleAuraModBaseResistancePCT(bool apply, bool Real)

View file

@ -275,6 +275,11 @@ class MANGOS_DLL_SPEC Aura
void SetAura(bool remove) { m_target->SetVisibleAura(m_auraSlot, remove ? 0 : GetId()); }
void SendAuraUpdate(bool remove);
int8 GetStackAmount() {return m_stackAmount;}
void SetStackAmount(uint8 num);
bool modStackAmount(int32 num); // return true if last charge dropped
void RefreshAura();
bool IsPositive() { return m_positive; }
void SetNegative() { m_positive = false; }
void SetPositive() { m_positive = true; }
@ -320,23 +325,28 @@ class MANGOS_DLL_SPEC Aura
Modifier m_modifier;
SpellModifier *m_spellmod;
uint32 m_effIndex;
SpellEntry const *m_spellProto;
int32 m_currentBasePoints; // cache SpellEntry::EffectBasePoints and use for set custom base points
uint64 m_caster_guid;
Unit* m_target;
int32 m_maxduration;
int32 m_duration;
int32 m_timeCla;
uint64 m_caster_guid;
uint64 m_castItemGuid; // it is NOT safe to keep a pointer to the item because it may get deleted
time_t m_applyTime;
AuraRemoveMode m_removeMode;
int32 m_currentBasePoints; // cache SpellEntry::EffectBasePoints and use for set custom base points
int32 m_maxduration; // Max aura duration
int32 m_duration; // Current time
int32 m_timeCla; // Timer for power per sec calcultion
int32 m_periodicTimer; // Timer for periodic auras
uint8 m_auraSlot;
uint8 m_auraFlags;
uint8 m_auraLevel;
int8 m_procCharges;
AuraRemoveMode m_removeMode:8; // Store info for know remove aura reason
DiminishingGroup m_AuraDRGroup:8; // Diminishing
uint8 m_effIndex; // Aura effect index in spell
uint8 m_auraSlot; // Aura slot on unit (for show in client)
uint8 m_auraFlags; // Aura info flag (for send data to client)
uint8 m_auraLevel; // Aura level (store caster level for correct show level dep amount)
uint8 m_procCharges; // Aura charges (0 for infinite)
uint8 m_stackAmount; // Aura stack amount
bool m_positive:1;
bool m_permanent:1;
@ -347,14 +357,10 @@ class MANGOS_DLL_SPEC Aura
bool m_isPersistent:1;
bool m_isDeathPersist:1;
bool m_isRemovedOnShapeLost:1;
bool m_updated:1;
bool m_updated:1; // Prevent remove aura by stack if set
bool m_in_use:1; // true while in Aura::ApplyModifier call
int32 m_periodicTimer;
uint32 m_PeriodicEventId;
DiminishingGroup m_AuraDRGroup;
private:
void UpdateSlotCounterAndDuration(bool add);
void CleanupTriggeredSpells();
};

View file

@ -480,31 +480,29 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
// consume from stack dozes not more that have combo-points
if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
// count consumed deadly poison doses at target
uint32 doses = 0;
// remove consumed poison doses
Aura *poison = 0;
// Lookup for Deadly poison (only attacker applied)
Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
{
// Deadly poison (only attacker applied)
if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
(*itr)->GetSpellProto()->SpellVisual[0]==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
(*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
(*itr)->GetCasterGUID()==m_caster->GetGUID() )
{
--combo;
++doses;
unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
itr = auras.begin();
poison = *itr;
break;
}
else
++itr;
// count consumed deadly poison doses at target
if (poison)
{
uint32 spellId = poison->GetId();
uint32 doses = poison->GetStackAmount();
if (doses > combo)
doses = combo;
for (int i=0; i< doses; i++)
unitTarget->RemoveSingleSpellAurasFromStack(spellId);
damage *= doses;
damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
}
damage *= doses;
damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
// Eviscerate and Envenom Bonus Damage (item set effect)
if(m_caster->GetDummyAura(37169))
damage += ((Player*)m_caster)->GetComboPoints()*40;
@ -572,19 +570,25 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
}
case SPELLFAMILY_PALADIN:
{
// Judgement of Vengeance
// Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
// Get stack of Holy Vengeance on the target added by caster
uint32 stacks = 0;
Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
++stacks;
if(!stacks)
//No damage if the target isn't affected by this
damage = -1;
else
damage *= stacks;
{
stacks = (*itr)->GetStackAmount();
break;
}
// + 10% for each application of Holy Vengeance on the target
if(stacks)
damage += damage * stacks * 10 /100;
}
// Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
@ -943,16 +947,12 @@ void Spell::EffectDummy(uint32 i)
}
case 28730: // Arcane Torrent (Mana)
{
int32 count = 0;
Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
if ((*i)->GetId() == 28734)
++count;
if (count)
Aura * dummy = m_caster->GetDummyAura(28734);
if (dummy)
{
m_caster->RemoveAurasDueToSpell(28734);
int32 bp = damage * count;
int32 bp = damage * dummy->GetStackAmount();
m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
m_caster->RemoveAurasDueToSpell(28734);
}
return;
}
@ -4217,21 +4217,22 @@ void Spell::EffectWeaponDmg(uint32 i)
// Devastate bonus and sunder armor refresh
else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
{
customBonusDamagePercentMod = true;
bonusDamagePercentMod = 0.0f; // only applied if auras found
Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
uint32 stack = 0;
// Need refresh all Sunder Armor auras from this caster
Unit::AuraMap& suAuras = unitTarget->GetAuras();
for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
{
SpellEntry const *proto = (*itr)->GetSpellProto();
if(proto->SpellVisual[0] == 406 && proto->SpellIconID == 565)
SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
(*itr).second->GetCasterGUID() == m_caster->GetGUID())
{
int32 duration = GetSpellDuration(proto);
(*itr)->SetAuraDuration(duration);
(*itr)->SendAuraUpdate(false);
bonusDamagePercentMod += 1.0f; // +100%
(*itr).second->RefreshAura();
stack = (*itr).second->GetStackAmount();
}
}
if (stack)
spell_bonus += stack * CalculateDamage(2, unitTarget);
}
break;
}
@ -4644,12 +4645,11 @@ void Spell::EffectScriptEffect(uint32 effIndex)
}
// Brittle Armor - need remove one 24575 Brittle Armor aura
case 24590:
unitTarget->RemoveSingleAuraFromStack(24575, 0);
unitTarget->RemoveSingleAuraFromStack(24575, 1);
unitTarget->RemoveSingleSpellAurasFromStack(24575);
return;
// Mercurial Shield - need remove one 26464 Mercurial Shield aura
case 26465:
unitTarget->RemoveSingleAuraFromStack(26464, 0);
unitTarget->RemoveSingleSpellAurasFromStack(26464);
return;
// Orb teleport spells
case 25140:
@ -4900,8 +4900,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
if (!(familyFlag & 0x000000800000C000LL))
continue;
// Refresh aura duration
aura->SetAuraDuration(aura->GetAuraMaxDuration());
aura->SendAuraUpdate(false);
aura->RefreshAura();
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)

View file

@ -1131,10 +1131,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
{
SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
{
(*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
(*itr).second->SendAuraUpdate(false);
}
(*itr).second->RefreshAura();
}
}
// Call default DealDamage
@ -1490,10 +1487,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
{
SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
{
(*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
(*itr).second->SendAuraUpdate(false);
}
(*itr).second->RefreshAura();
}
}
@ -3195,48 +3189,45 @@ bool Unit::AddAura(Aura *Aur)
// passive and persistent auras can stack with themselves any number of times
if (!Aur->IsPassive() && !Aur->IsPersistent())
{
// replace aura if next will > spell StackAmount
if(aurSpellInfo->StackAmount)
for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2)
{
if(m_Auras.count(spair) >= aurSpellInfo->StackAmount)
RemoveAura(i,AURA_REMOVE_BY_STACK);
}
// if StackAmount==0 not allow auras from same caster
else
{
for(AuraMap::iterator i2 = m_Auras.lower_bound(spair); i2 != m_Auras.upper_bound(spair); ++i2)
if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
{
if(i2->second->GetCasterGUID()==Aur->GetCasterGUID())
// Aura can stack on self -> Stack it;
if(aurSpellInfo->StackAmount)
{
i2->second->modStackAmount(1);
delete Aur;
return false;
}
// can be only single (this check done at _each_ aura add
RemoveAura(i2,AURA_REMOVE_BY_STACK);
break;
}
bool stop = false;
switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()])
{
// DoT/HoT/etc
case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_PERIODIC_MANA_LEECH:
case SPELL_AURA_PERIODIC_ENERGIZE:
case SPELL_AURA_OBS_MOD_MANA:
case SPELL_AURA_POWER_BURN_MANA:
break;
default: // not allow
// can be only single (this check done at _each_ aura add
RemoveAura(i2,AURA_REMOVE_BY_STACK);
break;
}
bool stop = false;
switch(aurSpellInfo->EffectApplyAuraName[Aur->GetEffIndex()])
{
// DoT/HoT/etc
case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_PERIODIC_MANA_LEECH:
case SPELL_AURA_PERIODIC_ENERGIZE:
case SPELL_AURA_OBS_MOD_MANA:
case SPELL_AURA_POWER_BURN_MANA:
break;
default: // not allow
// can be only single (this check done at _each_ aura add
RemoveAura(i2,AURA_REMOVE_BY_STACK);
stop = true;
break;
}
if(stop)
stop = true;
break;
}
if(stop)
break;
}
}
}
@ -3591,7 +3582,16 @@ void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
{
AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
if(iter != m_Auras.end())
RemoveAura(iter);
{
if (iter->second->modStackAmount(-1))
RemoveAura(iter);
}
}
void Unit::RemoveSingleSpellAurasFromStack(uint32 spellId)
{
for (int i=0; i<3; ++i)
RemoveSingleAuraFromStack(spellId, i);
}
void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
@ -4265,15 +4265,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if (!procSpell || procSpell->Id == 24659)
return false;
// Need remove one 24659 aura
RemoveSingleAuraFromStack(24659, 0);
RemoveSingleAuraFromStack(24659, 1);
RemoveSingleSpellAurasFromStack(24659);
return true;
}
// Restless Strength
case 24661:
{
// Need remove one 24662 aura
RemoveSingleAuraFromStack(24662, 0);
RemoveSingleSpellAurasFromStack(24662);
return true;
}
// Adaptive Warding (Frostfire Regalia set)
@ -5851,14 +5850,10 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false;
// stacking
CastSpell(this, 37658, true, NULL, triggeredByAura);
// counting
uint32 count = 0;
AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
if((*itr)->GetId()==37658)
++count;
Aura * dummy = GetDummyAura(37658);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
if(count < triggerAmount)
if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(37658);
@ -5872,17 +5867,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return false;
// stacking
CastSpell(this, 54842, true, NULL, triggeredByAura);
// counting
uint32 count = 0;
AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
if((*itr)->GetId()==54842)
++count;
Aura * dummy = GetDummyAura(54842);
// release at 3 aura in stack (cont contain in basepoint of trigger aura)
if(count < triggerAmount)
if(!dummy || dummy->GetStackAmount() < triggerAmount)
return false;
RemoveAurasDueToSpell(54842);
RemoveAurasDueToSpell(54842);
trigger_spell_id = 54843;
target = pVictim;
}

View file

@ -1087,6 +1087,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL);
void RemoveSingleSpellAurasFromStack(uint32 spellId);
void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex);
void RemoveAurasDueToSpell(uint32 spellId, Aura* except = NULL);
void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "7048"
#define REVISION_NR "7049"
#endif // __REVISION_NR_H__