Apply procPatch

This commit is contained in:
DiSlord 2008-11-26 22:23:10 +03:00
parent bdf7fb8394
commit 4a07c0c6c2
9 changed files with 2298 additions and 421 deletions

View file

@ -4727,6 +4727,7 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence) void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence)
{ {
/* Not need, this checked on call this func from trigger system
switch(outcome) switch(outcome)
{ {
case MELEE_HIT_CRIT: case MELEE_HIT_CRIT:
@ -4739,7 +4740,7 @@ void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHi
default: default:
break; break;
} }
*/
uint32 plevel = getLevel(); // if defense than pVictim == attacker uint32 plevel = getLevel(); // if defense than pVictim == attacker
uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel); uint32 greylevel = MaNGOS::XP::GetGrayLevel(plevel);
uint32 moblevel = pVictim->getLevelForTarget(this); uint32 moblevel = pVictim->getLevelForTarget(this);

View file

@ -306,6 +306,8 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType); m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType);
} }
} }
// Set health leech amount to zero
m_healthLeech = 0;
if(originalCasterGUID) if(originalCasterGUID)
m_originalCasterGUID = originalCasterGUID; m_originalCasterGUID = originalCasterGUID;
@ -666,6 +668,77 @@ void Spell::FillTargetMap()
} }
} }
void Spell::prepareDataForTriggerSystem()
{
//==========================================================================================
// Now fill data for trigger system, need know:
// Ñan spell trigger another or not ( m_canTrigger )
// Create base triggers flags for Attacker and Victim ( m_procAttacker and m_procVictim)
//==========================================================================================
// Fill flag can spell trigger or not
if (!m_IsTriggeredSpell)
m_canTrigger = true; // Normal cast - can trigger
else if (!m_triggeredByAuraSpell)
m_canTrigger = true; // Triggered from SPELL_EFFECT_TRIGGER_SPELL - can trigger
else // Exceptions (some periodic triggers)
{
m_canTrigger = false; // Triggered spells can`t trigger another
switch (m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_MAGE: // Arcane Missles triggers need do it
if (m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL) m_canTrigger = true;
break;
case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it
if (m_spellInfo->SpellFamilyFlags & 0x0000800000000060LL) m_canTrigger = true;
break;
case SPELLFAMILY_HUNTER: // Hunter Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect
if (m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) m_canTrigger = true;
break;
case SPELLFAMILY_PALADIN: // For Holy Shock triggers need do it
if (m_spellInfo->SpellFamilyFlags & 0x0001000000200000LL) m_canTrigger = true;
break;
}
}
// Do not trigger from item cast spell
if (m_CastItem)
m_canTrigger = false;
// Get data for type of attack and fill base info for trigger
switch (m_spellInfo->DmgClass)
{
case SPELL_DAMAGE_CLASS_MELEE:
m_procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;
break;
case SPELL_DAMAGE_CLASS_RANGED:
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
break;
default:
if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
}
else if (m_spellInfo->Id == 5019) // Wands
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
}
else
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
}
break;
}
// Hunter traps spells (for Entrapment trigger)
// Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap ....
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL)
m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION;
}
void Spell::CleanupTargetList() void Spell::CleanupTargetList()
{ {
m_UniqueTargetInfo.clear(); m_UniqueTargetInfo.clear();
@ -821,7 +894,7 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex)
target.effectMask = 1<<effIndex; target.effectMask = 1<<effIndex;
m_UniqueItemInfo.push_back(target); m_UniqueItemInfo.push_back(target);
} }
/*
void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit) void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit)
{ {
// Do triggers depends from hit result (triggers on hit do in effects) // Do triggers depends from hit result (triggers on hit do in effects)
@ -897,7 +970,7 @@ void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask da
break; break;
} }
} }
} }*/
void Spell::DoAllEffectOnTarget(TargetInfo *target) void Spell::DoAllEffectOnTarget(TargetInfo *target)
{ {
@ -914,11 +987,27 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if (!unit) if (!unit)
return; return;
// Get original caster (if exist) and calculate damage/healing from him data
Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
// Skip if m_originalCaster not avaiable
if (!caster)
return;
SpellMissInfo missInfo = target->missCondition; SpellMissInfo missInfo = target->missCondition;
// Need init unitTarget by default unit (can changed in code on reflect) // 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) // Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
unitTarget = unit; unitTarget = unit;
// Reset damage/healing counter
m_damage = 0;
m_healing = 0;
// Fill base trigger info
uint32 procAttacker = m_procAttacker;
uint32 procVictim = m_procVictim;
uint32 procEx = PROC_EX_NONE;
if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
DoSpellHitOnUnit(unit, mask); DoSpellHitOnUnit(unit, mask);
else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
@ -927,9 +1016,103 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
DoSpellHitOnUnit(m_caster, mask); DoSpellHitOnUnit(m_caster, mask);
} }
// Do triggers only on miss/resist/parry/dodge // All calculated do it!
if (missInfo!=SPELL_MISS_NONE) // Do healing and triggers
doTriggers(missInfo); if (m_healing)
{
bool crit = caster->isSpellCrit(NULL, m_spellInfo, m_spellSchoolMask);
uint32 addhealth = m_healing;
if (crit)
{
procEx |= PROC_EX_CRITICAL_HIT;
addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, NULL);
}
else
procEx |= PROC_EX_NORMAL_HIT;
caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo);
int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
unitTarget->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
if(caster->GetTypeId()==TYPEID_PLAYER)
if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
}
// Do damage and triggers
else if (m_damage)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
// Add bonuses and fill damageInfo struct
caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo);
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
procEx = createProcExtendMask(&damageInfo, missInfo);
procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo);
caster->DealSpellDamage(&damageInfo, true);
// Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL &&
caster != unitTarget && unitTarget->isAlive())
{
// Redirect damage to caster if victim Alive
damageInfo.target = caster;
damageInfo.absorb = 0;
damageInfo.resist = 0;
damageInfo.blocked = 0;
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
caster->DealSpellDamage(&damageInfo, true);
}
// Judgement of Blood
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153)
{
int32 damagePoint = damageInfo.damage * 33 / 100;
m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
}
// Bloodthirst
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
{
uint32 BTAura = 0;
switch(m_spellInfo->Id)
{
case 23881: BTAura = 23885; break;
case 23892: BTAura = 23886; break;
case 23893: BTAura = 23887; break;
case 23894: BTAura = 23888; break;
case 25251: BTAura = 25252; break;
case 30335: BTAura = 30339; break;
default:
sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
break;
}
if (BTAura)
m_caster->CastSpell(m_caster,BTAura,true);
}
}
// Passive spell hits/misses or active spells only misses (only triggers)
else
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
procEx = createProcExtendMask(&damageInfo, missInfo);
// Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo);
}
// Call scripted function for AI if this spell is casted upon a creature (except pets) // Call scripted function for AI if this spell is casted upon a creature (except pets)
if(IS_CREATURE_GUID(target->targetGUID)) if(IS_CREATURE_GUID(target->targetGUID))
@ -1951,6 +2134,9 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
return; return;
} }
// Prepare data for triggers
prepareDataForTriggerSystem();
// calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail)
m_casttime = GetSpellCastTime(m_spellInfo, this); m_casttime = GetSpellCastTime(m_spellInfo, this);
@ -2096,15 +2282,6 @@ void Spell::cast(bool skipCheck)
SendCastResult(castResult); SendCastResult(castResult);
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
// Pass cast spell event to handler (not send triggered by aura spells)
if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAuraSpell)
{
m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, SPELL_SCHOOL_MASK_NONE, m_spellInfo, m_IsTriggeredSpell);
// update pointers base at GUIDs to prevent access to non-existed already object
UpdatePointers(); // pointers can be invalidate at triggered spell casting
}
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
if (m_spellInfo->speed > 0.0f) if (m_spellInfo->speed > 0.0f)
{ {
@ -2516,6 +2693,13 @@ void Spell::finish(bool ok)
} }
} }
// Heal caster for all health leech from all targets
if (m_healthLeech)
{
m_caster->ModifyHealth(m_healthLeech);
m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(m_healthLeech));
}
if (IsMeleeAttackResetSpell()) if (IsMeleeAttackResetSpell())
{ {
m_caster->resetAttackTimer(BASE_ATTACK); m_caster->resetAttackTimer(BASE_ATTACK);
@ -3478,8 +3662,9 @@ uint8 Spell::CanCast(bool strict)
} }
} }
if(uint8 castResult = CheckRange(strict)) if(!m_triggeredByAuraSpell)
return castResult; if(uint8 castResult = CheckRange(strict))
return castResult;
{ {
if(uint8 castResult = CheckPower()) if(uint8 castResult = CheckPower())

View file

@ -453,10 +453,18 @@ class Spell
// ------------------------------------------- // -------------------------------------------
GameObject* focusObject; GameObject* focusObject;
// Damage and healing in effects need just calculate
int32 m_damage; // Damge in effects count here
int32 m_healing; // Healing in effects count here
int32 m_healthLeech; // Health leech in effects for all targets count here
//****************************************** //******************************************
// Spell trigger system // Spell trigger system
//****************************************** //******************************************
void doTriggers(SpellMissInfo missInfo, uint32 damage=0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, uint32 block=0, uint32 absorb=0, bool crit=false); bool m_canTrigger; // Can start trigger (m_IsTriggeredSpell can`t use for this)
uint32 m_procAttacker; // Attacker trigger flags
uint32 m_procVictim; // Victim trigger flags
void prepareDataForTriggerSystem();
//***************************************** //*****************************************
// Spell target subsystem // Spell target subsystem

View file

@ -253,8 +253,8 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::GiveXP &Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::GiveXP
&Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode... &Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
&Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst &Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
&Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::DoAttackDamage &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
&Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::DoAttackDamage &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
&Aura::HandleNULL, //205 vulnerable to school dmg? &Aura::HandleNULL, //205 vulnerable to school dmg?
&Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED &Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED
&Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED &Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@ -5610,11 +5610,15 @@ void Aura::PeriodicTick()
Unit* target = m_target; // aura can be deleted in DealDamage Unit* target = m_target; // aura can be deleted in DealDamage
SpellEntry const* spellProto = GetSpellProto(); SpellEntry const* spellProto = GetSpellProto();
pCaster->DealDamage(m_target, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); // Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
if (pdamage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
// DO NOT ACCESS MEMBERS OF THE AURA FROM NOW ON (DealDamage can delete aura) pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, true);
pCaster->ProcDamageAndSpell(target, PROC_FLAG_NONE, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), GetSpellSchoolMask(spellProto), spellProto);
break; break;
} }
case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_PERIODIC_LEECH:
@ -5723,11 +5727,15 @@ void Aura::PeriodicTick()
SpellEntry const* spellProto = GetSpellProto(); SpellEntry const* spellProto = GetSpellProto();
float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1; float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1;
uint32 new_damage = pCaster->DealDamage(m_target, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), false); // Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
if (pdamage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
int32 new_damage = pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, false);
// DO NOT ACCESS MEMBERS OF THE AURA FROM NOW ON (DealDamage can delete aura)
pCaster->ProcDamageAndSpell(target, PROC_FLAG_HEALED, PROC_FLAG_TAKE_DAMAGE, new_damage, GetSpellSchoolMask(spellProto), spellProto);
if (!target->isAlive() && pCaster->IsNonMeleeSpellCasted(false)) if (!target->isAlive() && pCaster->IsNonMeleeSpellCasted(false))
{ {
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
@ -5828,9 +5836,11 @@ void Aura::PeriodicTick()
} }
} }
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HEAL;
uint32 procVictim = 0;//ROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_TAKEN_HEAL;
// ignore item heals // ignore item heals
if(procSpell && !haveCastItem) // if(procSpell && !haveCastItem)
pCaster->ProcDamageAndSpell(target,PROC_FLAG_NONE, PROC_FLAG_HEALED, pdamage, SPELL_SCHOOL_MASK_NONE, spellProto); // pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
break; break;
} }
case SPELL_AURA_PERIODIC_MANA_LEECH: case SPELL_AURA_PERIODIC_MANA_LEECH:
@ -5989,8 +5999,22 @@ void Aura::PeriodicTick()
gain = uint32(gain * GetSpellProto()->EffectMultipleValue[GetEffIndex()]); gain = uint32(gain * GetSpellProto()->EffectMultipleValue[GetEffIndex()]);
SpellEntry const* spellProto = GetSpellProto();
//maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG //maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
pCaster->SpellNonMeleeDamageLog(m_target, GetId(), gain); SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE);
if (damageInfo.damage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
pCaster->DealSpellDamage(&damageInfo, true);
break; break;
} }
// Here tick dummy auras // Here tick dummy auras

View file

@ -541,61 +541,7 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
} }
if(damage >= 0) if(damage >= 0)
{ m_damage+= damage;
uint32 finalDamage;
if(m_originalCaster) // m_caster only passive source of cast
finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
else
finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
// post effects
switch(m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
{
// Bloodthirst
if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
{
uint32 BTAura = 0;
switch(m_spellInfo->Id)
{
case 23881: BTAura = 23885; break;
case 23892: BTAura = 23886; break;
case 23893: BTAura = 23887; break;
case 23894: BTAura = 23888; break;
case 25251: BTAura = 25252; break;
case 30335: BTAura = 30339; break;
default:
sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
break;
}
if (BTAura)
m_caster->CastSpell(m_caster,BTAura,true);
}
break;
}
case SPELLFAMILY_PRIEST:
{
// Shadow Word: Death
if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
// deals damage equal to damage done to caster if victim is not killed
m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
break;
}
case SPELLFAMILY_PALADIN:
{
// Judgement of Blood
if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
{
int32 damagePoint = finalDamage * 33 / 100;
m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
}
break;
}
}
}
} }
} }
@ -1355,7 +1301,7 @@ void Spell::EffectDummy(uint32 i)
} }
if(found) if(found)
m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true); m_damage+= damage;
return; return;
} }
// Kill command // Kill command
@ -2308,7 +2254,7 @@ void Spell::EffectPowerBurn(uint32 i)
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
new_damage = int32(new_damage*multiplier); new_damage = int32(new_damage*multiplier);
m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true); m_damage+=new_damage;
} }
void Spell::EffectHeal( uint32 /*i*/ ) void Spell::EffectHeal( uint32 /*i*/ )
@ -2376,27 +2322,7 @@ void Spell::EffectHeal( uint32 /*i*/ )
else else
addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget); addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType); m_healing+=addhealth;
if (crit)
addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
if(caster->GetTypeId()==TYPEID_PLAYER)
if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
// ignore item heals
if(m_CastItem)
return;
uint32 procHealer = PROC_FLAG_HEAL;
if (crit)
procHealer |= PROC_FLAG_CRIT_HEAL;
m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
} }
} }
@ -2473,6 +2399,8 @@ void Spell::EffectHealthLeech(uint32 i)
if(m_caster->GetTypeId() == TYPEID_PLAYER) if(m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage)); m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
} }
// m_healthLeech+=tmpvalue;
// m_damage+=new_damage;
} }
void Spell::DoCreateItem(uint32 i, uint32 itemtype) void Spell::DoCreateItem(uint32 i, uint32 itemtype)
@ -4317,35 +4245,9 @@ void Spell::EffectWeaponDmg(uint32 i)
// prevent negative damage // prevent negative damage
uint32 eff_damage = uint32(bonus > 0 ? bonus : 0); uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS; // Add melee damage bonuses (also check for negative)
m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
uint32 hitInfo = 0; m_damage+= eff_damage;
VictimState victimState = VICTIMSTATE_NORMAL;
uint32 blocked_dmg = 0;
uint32 absorbed_dmg = 0;
uint32 resisted_dmg = 0;
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
{
eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
}
else
{
cleanDamage.damage += eff_damage;
eff_damage = 0;
}
// SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
// Hemorrhage // Hemorrhage
if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000)) if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
@ -4409,10 +4311,7 @@ void Spell::EffectHealMaxHealth(uint32 /*i*/)
uint32 heal = m_caster->GetMaxHealth(); uint32 heal = m_caster->GetMaxHealth();
int32 gain = unitTarget->ModifyHealth(heal); m_healing+=heal;
unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
} }
void Spell::EffectInterruptCast(uint32 /*i*/) void Spell::EffectInterruptCast(uint32 /*i*/)

View file

@ -530,6 +530,17 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
return false; return false;
} }
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
{
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false;
for (int i = 0; i < 3; i++)
if (spellproto->EffectApplyAuraName[i] == auraType)
return true;
return false;
}
uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
{ {
// talents that learn spells can have stance requirements that need ignore // talents that learn spells can have stance requirements that need ignore
@ -806,8 +817,8 @@ void SpellMgr::LoadSpellProcEvents()
uint32 count = 0; uint32 count = 0;
// 0 1 2 3 4 5 6 7 8 // 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown FROM spell_proc_event"); QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if( !result ) if( !result )
{ {
@ -821,7 +832,7 @@ void SpellMgr::LoadSpellProcEvents()
} }
barGoLink bar( result->GetRowCount() ); barGoLink bar( result->GetRowCount() );
uint32 customProc = 0;
do do
{ {
Field *fields = result->Fetch(); Field *fields = result->Fetch();
@ -830,7 +841,8 @@ void SpellMgr::LoadSpellProcEvents()
uint16 entry = fields[0].GetUInt16(); uint16 entry = fields[0].GetUInt16();
if (!sSpellStore.LookupEntry(entry)) const SpellEntry *spell = sSpellStore.LookupEntry(entry);
if (!spell)
{ {
sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry); sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
continue; continue;
@ -839,23 +851,35 @@ void SpellMgr::LoadSpellProcEvents()
SpellProcEventEntry spe; SpellProcEventEntry spe;
spe.schoolMask = fields[1].GetUInt32(); spe.schoolMask = fields[1].GetUInt32();
spe.category = fields[2].GetUInt32(); spe.spellFamilyName = fields[2].GetUInt32();
spe.skillId = fields[3].GetUInt32(); spe.spellFamilyMask = fields[3].GetUInt64();
spe.spellFamilyName = fields[4].GetUInt32(); spe.procFlags = fields[4].GetUInt32();
spe.spellFamilyMask = fields[5].GetUInt64(); spe.procEx = fields[5].GetUInt32();
spe.procFlags = fields[6].GetUInt32(); spe.ppmRate = fields[6].GetFloat();
spe.ppmRate = fields[7].GetFloat(); spe.customChance = fields[7].GetFloat();
spe.cooldown = fields[8].GetUInt32(); spe.cooldown = fields[8].GetUInt32();
mSpellProcEventMap[entry] = spe; mSpellProcEventMap[entry] = spe;
if (spell->procFlags==0)
{
if (spe.procFlags == 0)
{
sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", entry);
continue;
}
customProc++;
}
++count; ++count;
} while( result->NextRow() ); } while( result->NextRow() );
delete result; delete result;
sLog.outString(); sLog.outString();
sLog.outString( ">> Loaded %u spell proc event conditions", count ); if (customProc)
sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom", count, customProc );
else
sLog.outString( ">> Loaded %u spell proc event conditions", count );
/* /*
// Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event) // Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event)
@ -887,6 +911,7 @@ void SpellMgr::LoadSpellProcEvents()
*/ */
} }
/*
bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags ) bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
{ {
if((procFlags & spellProcEvent->procFlags) == 0) if((procFlags & spellProcEvent->procFlags) == 0)
@ -925,6 +950,73 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spell
return true; return true;
} }
*/
bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
{
// No extra req need
uint32 procEvent_procEx = PROC_EX_NONE;
// check prockFlags for condition
if((procFlags & EventProcFlag) == 0)
return false;
// Always trigger for this
if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL_AND_GET_XP))
return true;
if (spellProcEvent) // Exist event data
{
// Store extra req
procEvent_procEx = spellProcEvent->procEx;
// For melee triggers
if (procSpell == NULL)
{
// Check (if set) for school (melee attack have Normal school)
if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
return false;
}
else // For spells need check school/spell family/family mask
{
// Check (if set) for school
if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
return false;
// Check (if set) for spellFamilyName
if(spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
return false;
// spellFamilyName is Ok need check for spellFamilyMask if present
if(spellProcEvent->spellFamilyMask)
{
if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0)
return false;
active = true; // Spell added manualy -> so its active spell
}
}
}
// Check for extra req (if none) and hit/crit
if (procEvent_procEx == PROC_EX_NONE)
{
// No extra req, so can trigger only for active (damage/healing present) and hit/crit
if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
return true;
}
else // Passive spells hits here only if resist/reflect/immune/evade
{
// Exist req for PROC_EX_EX_TRIGGER_ALWAYS
if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
return true;
// Passive spells can`t trigger if need hit
if ((procEvent_procEx & PROC_EX_NORMAL_HIT) && !active)
return false;
// Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
if (procEvent_procEx & procExtra)
return true;
}
return false;
}
void SpellMgr::LoadSpellElixirs() void SpellMgr::LoadSpellElixirs()
{ {

View file

@ -323,6 +323,8 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB);
bool IsSingleTargetSpell(SpellEntry const *spellInfo); bool IsSingleTargetSpell(SpellEntry const *spellInfo);
bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2); bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2);
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id); bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id);
inline bool IsAreaEffectTarget( Targets target ) inline bool IsAreaEffectTarget( Targets target )
@ -441,50 +443,86 @@ typedef std::map<uint32, uint64> SpellAffectMap;
// Spell proc event related declarations (accessed using SpellMgr functions) // Spell proc event related declarations (accessed using SpellMgr functions)
enum ProcFlags enum ProcFlags
{ {
PROC_FLAG_NONE = 0x00000000, // None PROC_FLAG_NONE = 0x00000000,
PROC_FLAG_HIT_MELEE = 0x00000001, // On melee hit
PROC_FLAG_STRUCK_MELEE = 0x00000002, // On being struck melee PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor
PROC_FLAG_KILL_XP_GIVER = 0x00000004, // On kill target giving XP or honor PROC_FLAG_KILL_AND_GET_XP = 0x00000002, // 01 Kill that yields experience or honor
PROC_FLAG_SPECIAL_DROP = 0x00000008, //
PROC_FLAG_DODGE = 0x00000010, // On dodge melee attack PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee attack
PROC_FLAG_PARRY = 0x00000020, // On parry melee attack PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee strike hit
PROC_FLAG_BLOCK = 0x00000040, // On block attack
PROC_FLAG_TOUCH = 0x00000080, // On being touched (for bombs, probably?) PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon
PROC_FLAG_TARGET_LOW_HEALTH = 0x00000100, // On deal damage to enemy with 20% or less health PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon
PROC_FLAG_LOW_HEALTH = 0x00000200, // On health dropped below 20%
PROC_FLAG_STRUCK_RANGED = 0x00000400, // On being struck ranged PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged attack (all ranged attack deal as spell so newer set :( )
PROC_FLAG_HIT_SPECIAL = 0x00000800, // (!)Removed, may be reassigned in future PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged attack (all ranged attack deal as spell so newer set :( )
PROC_FLAG_CRIT_MELEE = 0x00001000, // On crit melee
PROC_FLAG_STRUCK_CRIT_MELEE = 0x00002000, // On being critically struck in melee PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon
PROC_FLAG_CAST_SPELL = 0x00004000, // On cast spell PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon
PROC_FLAG_TAKE_DAMAGE = 0x00008000, // On take damage
PROC_FLAG_CRIT_SPELL = 0x00010000, // On crit spell PROC_FLAG_SUCCESSFUL_POSITIVE_AOE_HIT = 0x00000400, // 10 Successful AoE (not 100% shure unused)
PROC_FLAG_HIT_SPELL = 0x00020000, // On hit spell PROC_FLAG_TAKEN_POSITIVE_AOE = 0x00000800, // 11 Taken AoE (not 100% shure unused)
PROC_FLAG_STRUCK_CRIT_SPELL = 0x00040000, // On being critically struck by a spell
PROC_FLAG_HIT_RANGED = 0x00080000, // On getting ranged hit PROC_FLAG_SUCCESSFUL_AOE_SPELL_HIT = 0x00001000, // 12 Successful AoE damage spell hit (not 100% shure unused)
PROC_FLAG_STRUCK_SPELL = 0x00100000, // On being struck by a spell PROC_FLAG_TAKEN_AOE_SPELL_HIT = 0x00002000, // 13 Taken AoE damage spell hit (not 100% shure unused)
PROC_FLAG_TRAP = 0x00200000, // On trap activation (?)
PROC_FLAG_CRIT_RANGED = 0x00400000, // On getting ranged crit PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL = 0x00004000, // 14 Successful cast positive spell (by default only on healing)
PROC_FLAG_STRUCK_CRIT_RANGED = 0x00800000, // On being critically struck by a ranged attack PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00008000, // 15 Taken positive spell hit (by default only on healing)
PROC_FLAG_RESIST_SPELL = 0x01000000, // On resist enemy spell
PROC_FLAG_TARGET_RESISTS = 0x02000000, // On enemy resisted spell PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00010000, // 16 Successful negative spell cast (by default only on damage)
PROC_FLAG_TARGET_DODGE_OR_PARRY = 0x04000000, // On enemy dodges/parries PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00020000, // 17 Taken negative spell (by default only on damage)
PROC_FLAG_HEAL = 0x08000000, // On heal
PROC_FLAG_CRIT_HEAL = 0x10000000, // On critical healing effect PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14-17 flags)
PROC_FLAG_HEALED = 0x20000000, // On healing PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 14-17 flags)
PROC_FLAG_TARGET_BLOCK = 0x40000000, // On enemy blocks
PROC_FLAG_MISS = 0x80000000 // On miss melee attack PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage
PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation
PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used)
PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000 // 23 Successful off-hand melee attacks
};
#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MILEE_HIT | \
PROC_FLAG_TAKEN_MELEE_HIT | \
PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT | \
PROC_FLAG_TAKEN_MELEE_SPELL_HIT | \
PROC_FLAG_SUCCESSFUL_RANGED_HIT | \
PROC_FLAG_TAKEN_RANGED_HIT | \
PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT | \
PROC_FLAG_TAKEN_RANGED_SPELL_HIT)
enum ProcFlagsEx
{
PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
PROC_EX_CRITICAL_HIT = 0x0000002,
PROC_EX_MISS = 0x0000004,
PROC_EX_RESIST = 0x0000008,
PROC_EX_DODGE = 0x0000010,
PROC_EX_PARRY = 0x0000020,
PROC_EX_BLOCK = 0x0000040,
PROC_EX_EVADE = 0x0000080,
PROC_EX_IMMUNE = 0x0000100,
PROC_EX_DEFLECT = 0x0000200,
PROC_EX_ABSORB = 0x0000400,
PROC_EX_REFLECT = 0x0000800,
PROC_EX_INTERRUPT = 0x0001000, // Melle hit result can be Interrupt (not used)
PROC_EX_RESERVED1 = 0x0002000,
PROC_EX_RESERVED2 = 0x0004000,
PROC_EX_RESERVED3 = 0x0008000,
PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges
PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000 // If set trigger always but only one time
}; };
struct SpellProcEventEntry struct SpellProcEventEntry
{ {
uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2 uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
uint32 category; // if nonzero - match proc condition based on candidate spell's category
uint32 skillId; // if nonzero - for matching proc condition based on candidate spell's skillId from SkillLineAbility.dbc (Shadow Bolt = Destruction)
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
uint64 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do) uint64 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
uint32 procFlags; // bitmask for matching proc event uint32 procFlags; // bitmask for matching proc event
uint32 procEx; // proc Extend info (see ProcFlagsEx)
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
float customChance; // Owerride chance (in most cases for debug only)
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_ uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
}; };
@ -683,7 +721,7 @@ class SpellMgr
return NULL; return NULL;
} }
static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags ); static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
// Spell target coordinates // Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const

File diff suppressed because it is too large Load diff

View file

@ -578,6 +578,50 @@ struct CleanDamage
MeleeHitOutcome hitOutCome; MeleeHitOutcome hitOutCome;
}; };
// Struct for use in Unit::CalculateMeleeDamage
// Need create structure like in SMSG_ATTACKERSTATEUPDATE opcode
struct CalcDamageInfo
{
Unit *attacker; // Attacker
Unit *target; // Target for damage
uint32 damageSchoolMask;
uint32 damage;
uint32 absorb;
uint32 resist;
uint32 blocked_amount;
uint32 HitInfo;
uint32 TargetState;
// Helper
WeaponAttackType attackType; //
uint32 procAttacker;
uint32 procVictim;
uint32 procEx;
uint32 cleanDamage; // Used only fo rage calcultion
MeleeHitOutcome hitOutCome; // TODO: remove this field (need use TargetState)
};
// Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode
struct SpellNonMeleeDamage{
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) :
attacker(_attacker), target(_target), SpellID(_SpellID), damage(0), schoolMask(_schoolMask),
absorb(0), resist(0), phusicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) {}
Unit *target;
Unit *attacker;
uint32 SpellID;
uint32 damage;
uint32 schoolMask;
uint32 absorb;
uint32 resist;
bool phusicalLog;
bool unused;
uint32 blocked;
uint32 HitInfo;
// Used for help
uint32 cleanDamage;
};
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
struct UnitActionBarEntry struct UnitActionBarEntry
{ {
uint32 Type; uint32 Type;
@ -684,6 +728,8 @@ enum ReactiveType
// delay time next attack to prevent client attack animation problems // delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200 #define ATTACK_DISPLAY_DELAY 200
struct SpellProcEventEntry; // used only privately
class MANGOS_DLL_SPEC Unit : public WorldObject class MANGOS_DLL_SPEC Unit : public WorldObject
{ {
public: public:
@ -834,15 +880,23 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss); uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss);
void DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false);
void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false); void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL);
void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage = 0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK); void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage );
void HandleEmoteCommand(uint32 anim_id); void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false ); void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false );
float MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const; float MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const;
void CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss);
void CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss);
float MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell);
SpellMissInfo MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell);
SpellMissInfo MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell); SpellMissInfo MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell);
SpellMissInfo SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool canReflect = false); SpellMissInfo SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool canReflect = false);
@ -857,7 +911,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const; uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const;
float GetWeaponProcChance() const; float GetWeaponProcChance() const;
float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const; float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const;
MeleeHitOutcome RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo);
MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const; MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const;
MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const; MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const;
@ -931,7 +985,9 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void DeMorph(); void DeMorph();
void SendAttackStateUpdate(CalcDamageInfo *damageInfo);
void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount); void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount);
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log);
void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo); void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo);
@ -1178,7 +1234,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim); int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim);
uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype); uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype);
uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim); uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim);
bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType); bool isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType = BASE_ATTACK);
bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK);
uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim); uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);
void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; } void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; }
@ -1316,12 +1373,11 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendAttackStop(Unit* victim); // only from AttackStop(Unit*) void SendAttackStop(Unit* victim); // only from AttackStop(Unit*)
void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*) void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*)
void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask ); bool IsTriggeredAtSpellProcEvent( Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent );
bool IsTriggeredAtSpellProcEvent( SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown ); bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown); bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, uint32 cooldown); bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown); bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggredByAura, SpellEntry const *procSpell, uint32 cooldown);
bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 cooldown);
bool HandleMeandingAuraProc(Aura* triggeredByAura); bool HandleMeandingAuraProc(Aura* triggeredByAura);
uint32 m_state; // Even derived shouldn't modify uint32 m_state; // Even derived shouldn't modify