[9784] Move damage and crit calculation for certain effects of spells with delayed hit to spell launch

This commit is contained in:
Laise 2010-04-23 19:52:47 +03:00
parent 8ec81caabf
commit 10b65dcf8f
7 changed files with 128 additions and 22 deletions

View file

@ -927,6 +927,17 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
uint32 procVictim = m_procVictim;
uint32 procEx = PROC_EX_NONE;
if (m_spellInfo->speed > 0)
{
// mark effects that were already handled in Spell::HandleDelayedSpellLaunch on spell launch as processed
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (IsEffectHandledOnDelayedSpellLaunch(m_spellInfo, SpellEffectIndex(i)))
mask &= ~(1<<i);
// maybe used in effects that are handled on hit
m_damage += target->damage;
}
if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
DoSpellHitOnUnit(unit, mask);
else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
@ -966,8 +977,16 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
if (m_spellInfo->speed > 0)
{
damageInfo.damage = m_damage;
damageInfo.HitInfo = target->HitInfo;
}
// Add bonuses and fill damageInfo struct
caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType);
else
caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType);
unitTarget->CalculateAbsorbResistBlock(caster, &damageInfo, m_spellInfo);
caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
@ -1184,6 +1203,56 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)
HandleEffects(NULL, target->item, NULL, SpellEffectIndex(effectNumber));
}
void Spell::HandleDelayedSpellLaunch(TargetInfo *target)
{
// Get mask of effects for target
uint32 mask = target->effectMask;
Unit* unit = m_caster->GetObjectGuid() == target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target->targetGUID);
if (!unit)
return;
// Get original caster (if exist) and calculate damage/healing from him data
Unit *real_caster = GetAffectiveCaster();
// FIXME: in case wild GO heal/damage spells will be used target bonuses
Unit *caster = real_caster ? real_caster : m_caster;
SpellMissInfo missInfo = target->missCondition;
// Need init unitTarget by default unit (can changed in code on reflect)
// Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
unitTarget = unit;
// Reset damage/healing counter
m_damage = 0;
m_healing = 0; // healing maybe not needed at this point
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
for (int32 effectNumber = 0; effectNumber < MAX_EFFECT_INDEX; ++effectNumber)
{
if (mask & (1 << effectNumber) && IsEffectHandledOnDelayedSpellLaunch(m_spellInfo, SpellEffectIndex(effectNumber)))
{
HandleEffects(unit, NULL, NULL, SpellEffectIndex(effectNumber), m_damageMultipliers[effectNumber]);
if ( m_applyMultiplierMask & (1 << effectNumber) )
{
// Get multiplier
float multiplier = m_spellInfo->DmgMultiplier[effectNumber];
// Apply multiplier mods
if (real_caster)
if(Player* modOwner = real_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier, this);
m_damageMultipliers[effectNumber] *= multiplier;
}
}
}
caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo, m_attackType);
target->damage = damageInfo.damage;
target->HitInfo = damageInfo.HitInfo;
}
bool Spell::IsAliveUnitPresentInTargetList()
{
// Not need check return true
@ -2658,6 +2727,10 @@ void Spell::cast(bool skipCheck)
// in case delayed spell remove item at cast delay start
TakeCastItem();
// fill initial spell damage from caster for delayed casted spells
for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
HandleDelayedSpellLaunch(&(*ihit));
// Okay, maps created, now prepare flags
m_immediateHandled = false;
m_spellState = SPELL_STATE_DELAYED;

View file

@ -573,6 +573,8 @@ class Spell
{
ObjectGuid targetGUID;
uint64 timeDelay;
uint32 HitInfo;
uint32 damage;
SpellMissInfo missCondition:8;
SpellMissInfo reflectResult:8;
uint8 effectMask:8;
@ -603,6 +605,7 @@ class Spell
void AddGOTarget(uint64 goGUID, SpellEffectIndex effIndex);
void AddItemTarget(Item* target, SpellEffectIndex effIndex);
void DoAllEffectOnTarget(TargetInfo *target);
void HandleDelayedSpellLaunch(TargetInfo *target);
void DoSpellHitOnUnit(Unit *unit, uint32 effectMask);
void DoAllEffectOnTarget(GOTargetInfo *target);
void DoAllEffectOnTarget(ItemTargetInfo *target);

View file

@ -7478,6 +7478,8 @@ void Aura::PeriodicTick()
SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
damageInfo.target->CalculateAbsorbResistBlock(pCaster, &damageInfo, spellProto);
pCaster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);

View file

@ -136,6 +136,21 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
return false;
}
inline bool IsEffectHandledOnDelayedSpellLaunch(SpellEntry const *spellInfo, SpellEffectIndex effecIdx)
{
switch (spellInfo->Effect[effecIdx])
{
case SPELL_EFFECT_SCHOOL_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
return true;
default:
return false;
}
}
inline bool IsSpellHaveAura(SpellEntry const *spellInfo, AuraType aura)
{
for(int i = 0; i < MAX_EFFECT_INDEX; ++i)

View file

@ -1186,6 +1186,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
CalculateSpellDamage(&damageInfo, damage, spellInfo);
damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo);
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
@ -1207,7 +1208,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
// Check spell crit chance
bool crit = IsSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
bool blocked = false;
// damage bonus (per damage class)
switch (spellInfo->DmgClass)
@ -1218,8 +1218,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
{
//Calculate damage bonus
damage = MeleeDamageBonus(pVictim, damage, attackType, spellInfo, SPELL_DIRECT_DAMAGE);
// Get blocked status
blocked = pVictim->IsSpellBlocked(this, spellInfo, attackType);
// if crit add critical bonus
if (crit)
@ -1270,19 +1268,6 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
uint32 armor_affected_damage = CalcNotIgnoreDamageRedunction(damage,damageSchoolMask);
damage = damage - armor_affected_damage + CalcArmorReducedDamage(pVictim, armor_affected_damage);
}
// block (only for damage class ranged and -melee, also non-physical damage possible)
if (blocked)
{
damageInfo->blocked = pVictim->GetShieldBlockValue();
if (damage < (int32)damageInfo->blocked)
damageInfo->blocked = damage;
damage-=damageInfo->blocked;
}
uint32 absorb_affected_damage = CalcNotIgnoreAbsorbDamage(damage,damageSchoolMask,spellInfo);
pVictim->CalculateAbsorbAndResist(this, damageSchoolMask, SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellInfo->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED));
damage-= damageInfo->absorb + damageInfo->resist;
}
else
damage = 0;
@ -1319,7 +1304,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
}
// Call default DealDamage (send critical in hit info for threat calculation)
CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL);
CleanDamage cleanDamage(0, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
}
@ -2332,6 +2317,34 @@ void Unit::CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, D
*absorb = damage - RemainingDamage - *resist;
}
void Unit::CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damageInfo, SpellEntry const* spellProto, WeaponAttackType attType)
{
bool blocked = false;
// Get blocked status
switch (spellProto->DmgClass)
{
// Melee and Ranged Spells
case SPELL_DAMAGE_CLASS_RANGED:
case SPELL_DAMAGE_CLASS_MELEE:
blocked = IsSpellBlocked(pCaster, spellProto, attType);
break;
default:
break;
}
if (blocked)
{
damageInfo->blocked = GetShieldBlockValue();
if (damageInfo->damage < (int32)damageInfo->blocked)
damageInfo->blocked = damageInfo->damage;
damageInfo->damage-=damageInfo->blocked;
}
uint32 absorb_affected_damage = pCaster->CalcNotIgnoreAbsorbDamage(damageInfo->damage,GetSpellSchoolMask(spellProto),spellProto);
CalculateAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), SPELL_DIRECT_DAMAGE, absorb_affected_damage, &damageInfo->absorb, &damageInfo->resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED));
damageInfo->damage-= damageInfo->absorb + damageInfo->resist;
}
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
{
if(hasUnitState(UNIT_STAT_CAN_NOT_REACT) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED) )
@ -12439,6 +12452,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);
damageInfo.target->CalculateAbsorbResistBlock(this, &damageInfo, spellInfo);
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);

View file

@ -877,7 +877,7 @@ struct CalcDamageInfo
struct SpellNonMeleeDamage{
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask)
: target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask),
absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0)
{}
Unit *target;
@ -892,8 +892,6 @@ struct SpellNonMeleeDamage{
bool unused;
uint32 blocked;
uint32 HitInfo;
// Used for help
uint32 cleanDamage;
};
struct SpellPeriodicAuraLogInfo
@ -1742,6 +1740,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 CalcArmorReducedDamage(Unit* pVictim, const uint32 damage);
void CalculateAbsorbAndResist(Unit *pCaster, SpellSchoolMask schoolMask, DamageEffectType damagetype, const uint32 damage, uint32 *absorb, uint32 *resist, bool canReflect = false);
void CalculateAbsorbResistBlock(Unit *pCaster, SpellNonMeleeDamage *damageInfo, SpellEntry const* spellProto, WeaponAttackType attType = BASE_ATTACK);
void UpdateWalkMode(Unit* source, bool self = true);
void UpdateSpeed(UnitMoveType mtype, bool forced, float ratio = 1.0f);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "9783"
#define REVISION_NR "9784"
#endif // __REVISION_NR_H__