[11299] Handle aura durations in SpellAuraHolder

- Unit::CalculateSpellDuration split into two functions
    - CalculateSpellDuration taking into account combo points and caster-side spell mods
    - Unit::CalculateAuraDuration taking into account target-side spell mods
- Diminishing is now applied before duration reduction mods
- Implement saving per-effect periodic timers to DB (required for auras affected by haste)
This commit is contained in:
zergtmn 2011-03-30 23:29:01 +06:00
parent 5833d74963
commit 4687fa8cb4
19 changed files with 388 additions and 379 deletions

View file

@ -3489,31 +3489,11 @@ void Unit::_UpdateSpells( uint32 time )
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
{
SpellAuraHolder *holder = iter->second;
if (holder)
{
if (!(holder->IsPermanent() || holder->IsPassive()) )
{
bool removedAura = false;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aura = holder->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
if (!aura->GetAuraDuration())
{
RemoveSingleAuraFromSpellAuraHolder(holder, aura->GetEffIndex(), AURA_REMOVE_BY_EXPIRE);
removedAura = true;
break;
}
}
}
if (!removedAura)
++iter;
else
iter = m_spellAuraHolders.begin();
}
else
++iter;
if (!(holder->IsPermanent() || holder->IsPassive()) && holder->GetAuraDuration() == 0)
{
RemoveSpellAuraHolder(holder, AURA_REMOVE_BY_EXPIRE);
iter = m_spellAuraHolders.begin();
}
else
++iter;
@ -4505,6 +4485,14 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
SpellAuraHolder *new_holder = CreateSpellAuraHolder(spellProto, stealer, this);
// set its duration and maximum duration
// max duration 2 minutes (in msecs)
int32 dur = holder->GetAuraDuration();
int32 max_dur = 2*MINUTE*IN_MILLISECONDS;
int32 new_max_dur = max_dur > dur ? dur : max_dur;
new_holder->SetAuraMaxDuration(new_max_dur);
new_holder->SetAuraDuration(new_max_dur);
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
Aura *aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i));
@ -4517,14 +4505,6 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
// some different constructors
Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, new_holder, stealer, this);
// set its duration and maximum duration
// max duration 2 minutes (in msecs)
int32 dur = aur->GetAuraDuration();
int32 max_dur = 2*MINUTE*IN_MILLISECONDS;
int32 new_max_dur = max_dur > dur ? dur : max_dur;
new_aur->SetAuraMaxDuration( new_max_dur );
new_aur->SetAuraDuration( new_max_dur );
// set periodic to do at least one tick (for case when original aura has been at last tick preparing)
int32 periodic = aur->GetModifier()->periodictime;
new_aur->GetModifier()->periodictime = periodic < new_max_dur ? periodic : new_max_dur;
@ -4885,22 +4865,19 @@ void Unit::DelaySpellAuraHolder(uint32 spellId, int32 delaytime, uint64 casterGU
SpellAuraHolderBounds bounds = GetSpellAuraHolderBounds(spellId);
for (SpellAuraHolderMap::iterator iter = bounds.first; iter != bounds.second; ++iter)
{
if (casterGUID != iter->second->GetCasterGUID())
SpellAuraHolder* holder = iter->second;
if (casterGUID != holder->GetCasterGUID())
continue;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aur = iter->second->GetAuraByEffectIndex(SpellEffectIndex(i)))
{
if (aur->GetAuraDuration() < delaytime)
aur->SetAuraDuration(0);
else
aur->SetAuraDuration(aur->GetAuraDuration() - delaytime);
if (holder->GetAuraDuration() < delaytime)
holder->SetAuraDuration(0);
else
holder->SetAuraDuration(holder->GetAuraDuration() - delaytime);
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u, EffectIndex %u partially interrupted on unit %u, new duration: %u ms",spellId, i, GetGUIDLow(), aur->GetAuraDuration());
}
}
iter->second->SendAuraUpdate(false);
holder->SendAuraUpdate(false);
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted on %s, new duration: %u ms", spellId, GetObjectGuid().GetString().c_str(), holder->GetAuraDuration());
}
}
@ -8729,50 +8706,45 @@ int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProt
return value;
}
int32 Unit::CalculateSpellDuration(SpellEntry const* spellProto, SpellEffectIndex effect_index, Unit const* target)
int32 Unit::CalculateAuraDuration(SpellEntry const* spellProto, uint32 effectMask, int32 duration, Unit const* caster)
{
Player* unitPlayer = (GetTypeId() == TYPEID_PLAYER) ? (Player*)this : NULL;
if (duration <= 0)
return duration;
uint8 comboPoints = unitPlayer ? unitPlayer->GetComboPoints() : 0;
int32 mechanicMod = 0;
uint32 mechanicMask = GetSpellMechanicMask(spellProto, effectMask);
int32 minduration = GetSpellDuration(spellProto);
int32 maxduration = GetSpellMaxDuration(spellProto);
int32 duration;
if( minduration != -1 && minduration != maxduration )
duration = minduration + int32((maxduration - minduration) * comboPoints / 5);
else
duration = minduration;
if (duration > 0)
for(int32 mechanic = MECHANIC_CHARM; mechanic <= MECHANIC_ENRAGED; ++mechanic)
{
int32 mechanic = GetEffectMechanic(spellProto, effect_index);
// Find total mod value (negative bonus)
int32 durationMod_always = target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
// Modify from SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL aura for negative effects (stack always ?)
if (!IsPositiveEffect(spellProto, effect_index))
durationMod_always+=target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
// Find max mod (negative bonus)
int32 durationMod_not_stack = target->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
if (!(mechanicMask & (1 << (mechanic-1))))
continue;
if (!IsPositiveSpell(spellProto->Id))
durationMod_always += target->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->DmgClass);
int32 stackingMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD, mechanic);
int32 nonStackingMod = GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK, mechanic);
int32 durationMod = 0;
// Select strongest negative mod
if (durationMod_always > durationMod_not_stack)
durationMod = durationMod_not_stack;
else
durationMod = durationMod_always;
if (durationMod != 0)
duration = int32(int64(duration) * (100+durationMod) /100);
if (duration < 0) duration = 0;
mechanicMod = std::min(mechanicMod, std::min(stackingMod, nonStackingMod));
}
if (duration > 0 && unitPlayer && target == this)
int32 dispelMod = 0;
int32 dmgClassMod = 0;
if (!IsPositiveSpell(spellProto))
{
dispelMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL, spellProto->Dispel);
dmgClassMod = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS, spellProto->DmgClass);
}
int32 durationMod = std::min(mechanicMod, std::min(dispelMod, dmgClassMod));
if (durationMod != 0)
{
duration = int32(int64(duration) * (100+durationMod) / 100);
if (duration < 0)
duration = 0;
}
if (caster == this)
{
switch(spellProto->SpellFamilyName)
{
@ -9838,7 +9810,7 @@ SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
return SPELL_SCHOOL_MASK_NORMAL;
}
Player* Unit::GetSpellModOwner()
Player* Unit::GetSpellModOwner() const
{
if(GetTypeId()==TYPEID_PLAYER)
return (Player*)this;