Core/Spells: Implementation of QAston proc system

- Move checks from Unit::IsTriggeredAtSpellProcEvent (old system) to Aura::IsProcTriggeredOnEvent (new system)
- Templatize SpellModOp param of Player::ApplySpellMod, also killed charge counter from SpellModifier and Player system for handling charges... no point in having 3 different systems doing the same thing
- Automatically add default entries to spellProcMap, based on spellinfo (else auras won't proc without an entry) Based on old Unit::ProcDamageAndSpellFor
- Old Unit::ProcDamageAndSpellFor renamed to Unit::ProcSkillsAndReactives and made private, will no longer handle auras.
- Start making use of HealInfo::AbsorbHeal in unit calculations, add effective healing info to HealInfo struct
- Changes in spell reflection system, emulates old behaviour, delaying aura drop
- Removed old charge count hacks in SpellMgr::LoadSpellInfoCorrections
- Removed bogus error log when procChance is 0: Some auras have initial 0 procChance but modified by SPELLMOD_CHANCE_OF_SUCCESS
- Fixed TriggerAurasProcOnEvent logic that tried to trigger twice from actor.
- Allow non damaging spells with DamageClass Melee or Ranged to proc character enchants. Ref issue #17034:

  * http://web.archive.org/web/20110309092008/http://elitistjerks.com/f47/t49865-paladin_retribution_pve/
  * When an auto-attack lands (does not dodge/parry/miss) that can proc a seal the of the following things happen independently of each other (see 2 roll system).

  * 1) A "hidden strike" which uses melee combat mechanics occurs. If it lands it refreshes/stacks SoV DoT. Only white swings can trigger a refresh or stack. (This hidden strike mechanic can also proc things like berserking..)
  * 2) A weapon damage based proc will occur if you used a special (CS/DS/judge) or if you have a 5 stack (from auto attacks). This attack can not be avoided.

  * Holy Vengeance is the "hidden strike" it has an apply aura effect and damage class melee.
- Fixed Blood Tap interaction with Death Runes (btw, don't know what was going on with those MiscValueB, spell 45529 doesn't have any MiscValueB in SPELL_EFFECT_ACTIVATE_RUNE)
- Ported some AuraEffect checks from old Unit.cpp function. added new AuraScript hook to check procs of an specific effect
- Allow only AuraEffects that passed the check to proc, this won't block whole aura from proccing (and lose charges) if at least one of the effects procs, though
- Changes in spell mod system (for SPELLMOD_CASTING_TIME). fixes #17558.
- Added an exception for SPELLMOD_CRITICAL_CHANCE too, fixes #15193
This commit is contained in:
Aokromes committed 2016-10-05 13:19:51 +02:00
1 parent eb745277cd
commit a70e4e26b3
22 files changed
+1192 -3882

No files matched your search

+63 -106
View File
@@ -8184,8 +8184,10 @@ void Player::UpdateEquipSpellsAtFormChange()
}
}
}
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
void Player::CastItemCombatSpell(DamageInfo const& damageInfo)
{
Unit* target = damageInfo.GetVictim();
if (!target || !target->IsAlive() || target == this)
return;
@@ -8193,7 +8195,9 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// If usable, try to cast item spell
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (!item->IsBroken() && CanUseAttackType(attType))
{
if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
{
if (ItemTemplate const* proto = item->GetTemplate())
{
// Additional check for weapons
@@ -8201,31 +8205,42 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
{
// offhand item cannot proc from main hand hit etc
EquipmentSlots slot;
switch (attType)
switch (damageInfo.GetAttackType())
{
case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
default: slot = EQUIPMENT_SLOT_END; break;
case BASE_ATTACK:
slot = EQUIPMENT_SLOT_MAINHAND;
break;
case OFF_ATTACK:
slot = EQUIPMENT_SLOT_OFFHAND;
break;
case RANGED_ATTACK:
slot = EQUIPMENT_SLOT_RANGED;
break;
default:
slot = EQUIPMENT_SLOT_END;
break;
}
if (slot != i)
continue;
// Check if item is useable (forms or disarm)
if (attType == BASE_ATTACK)
if (damageInfo.GetAttackType() == BASE_ATTACK)
if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
continue;
}
CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
CastItemCombatSpell(damageInfo, item, proto);
}
}
}
}
}
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
{
// Can do effect if any damage done to target
if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
//if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
{
// for done procs allow normal + critical + absorbs by default
bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
if (canTrigger) {
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -8254,14 +8269,14 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (proto->SpellPPMRate)
{
uint32 WeaponSpeed = GetAttackTime(attType);
uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType());
chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
chance = GetWeaponProcChance();
if (roll_chance_f(chance))
CastSpell(target, spellInfo->Id, true, item);
CastSpell(damageInfo.GetVictim(), spellInfo->Id, true, item);
}
}
@@ -8282,18 +8297,17 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
continue;
SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
if (entry && entry->procEx)
{
// Check hit/crit/dodge/parry requirement
if ((entry->procEx & procEx) == 0)
if ((entry->procEx & damageInfo.GetHitMask()) == 0)
continue;
}
else
{
// Can do effect if any damage done to target
if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
//if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
// for done procs allow normal + critical + absorbs by default
if (!canTrigger)
continue;
}
@@ -8306,7 +8320,6 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
}
float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
if (entry)
{
if (entry->PPMChance)
@@ -8316,7 +8329,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
}
// Apply spell mods
ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance);
ApplySpellMod<SPELLMOD_CHANCE_OF_SUCCESS>(pEnchant->spellid[s], chance);
// Shiv has 100% chance to apply the poison
if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
@@ -8327,7 +8340,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
if (spellInfo->IsPositive())
CastSpell(this, spellInfo, true, item);
else
CastSpell(target, spellInfo, true, item);
CastSpell(damageInfo.GetVictim(), spellInfo, true, item);
}
}
}
@@ -21188,8 +21201,8 @@ bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier* mod
if (!mod || !spellInfo)
return false;
// Mod out of charges
if (spell && mod->charges == -1 && spell->m_appliedMods.find(mod->ownerAura) == spell->m_appliedMods.end())
// First time this aura applies a mod to us and is out of charges
if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
return false;
// +duration to infinite duration spells making them limited
@@ -21212,18 +21225,18 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
size_t writePos = data.wpos();
data << uint32(modTypeCount);
data << uint8(mod->op);
for (int eff = 0; eff < 96; ++eff)
for (int32 eff = 0; eff < 96; ++eff)
{
if (eff != 0 && (eff % 32) == 0)
_mask[i++] = 0;
_mask[i] = uint32(1) << (eff - (32 * i));
if (mod->mask & _mask)
if ((mod->mask & _mask))
{
int32 val = 0;
for (SpellModList::iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
if ((*itr)->type == mod->type && (*itr)->mask & _mask)
val += (*itr)->value;
for (SpellModifier* spellMod : m_spellMods[mod->op])
if (spellMod->type == mod->type && (spellMod->mask & _mask))
val += spellMod->value;
val += apply ? mod->value : -(mod->value);
data << uint8(eff);
@@ -21234,36 +21247,31 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
data.put<uint32>(writePos, modTypeCount);
SendDirectMessage(&data);
if (apply)
m_spellMods[mod->op].push_back(mod);
m_spellMods[mod->op].insert(mod);
else
{
m_spellMods[mod->op].remove(mod);
// mods bound to aura will be removed in AuraEffect::~AuraEffect
if (!mod->ownerAura)
delete mod;
}
m_spellMods[mod->op].erase(mod);
}
// Restore spellmods in case of failed cast
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
if (!spell || spell->m_appliedMods.empty())
return;
std::list<Aura*> aurasQueue;
for (uint8 i=0; i<MAX_SPELLMOD; ++i)
for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
{
for (SpellModList::iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
for (auto itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr)
{
SpellModifier* mod = *itr;
// Spellmods without aura set cannot be charged
if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
// Spellmods without charged aura cannot be charged
if (!mod->ownerAura->IsUsingCharges())
continue;
// Restore only specific owner aura mods
if (ownerAuraId && (ownerAuraId != mod->ownerAura->GetSpellInfo()->Id))
if (ownerAuraId && mod->spellId != ownerAuraId)
continue;
if (aura && mod->ownerAura != aura)
@@ -21284,84 +21292,33 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura)
// only see the first of its modifier restored)
aurasQueue.push_back(mod->ownerAura);
// add mod charges back to mod
if (mod->charges == -1)
mod->charges = 1;
else
mod->charges++;
// Do not set more spellmods than available
if (mod->ownerAura->GetCharges() < mod->charges)
mod->charges = mod->ownerAura->GetCharges();
// Skip this check for now - aura charges may change due to various reason
/// @todo track these changes correctly
//ASSERT (mod->ownerAura->GetCharges() <= mod->charges);
// add charges back to aura
mod->ownerAura->ModCharges(1);
}
}
for (std::list<Aura*>::iterator itr = aurasQueue.begin(); itr != aurasQueue.end(); ++itr)
{
Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(*itr);
if (iterMod != spell->m_appliedMods.end())
spell->m_appliedMods.erase(iterMod);
}
for (Aura* aura : aurasQueue)
spell->m_appliedMods.erase(aura);
}
void Player::RestoreAllSpellMods(uint32 ownerAuraId, Aura* aura)
void Player::RestoreAllSpellMods(uint32 ownerAuraId /*= 0*/, Aura* aura /*= nullptr*/)
{
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
if (m_currentSpells[i])
RestoreSpellMods(m_currentSpells[i], ownerAuraId, aura);
if (Spell* spell = m_currentSpells[i])
RestoreSpellMods(spell, ownerAuraId, aura);
}
void Player::RemoveSpellMods(Spell* spell)
void Player::ApplyModToSpell(SpellModifier* mod, Spell* spell)
{
if (!spell)
return;
if (spell->m_appliedMods.empty())
// don't do anything with no charges
if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
return;
for (uint8 i=0; i<MAX_SPELLMOD; ++i)
{
for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();)
{
SpellModifier* mod = *itr;
++itr;
// spellmods without aura set cannot be charged
if (!mod->ownerAura || !mod->ownerAura->IsUsingCharges())
continue;
// check if mod affected this spell
Spell::UsedSpellMods::iterator iterMod = spell->m_appliedMods.find(mod->ownerAura);
if (iterMod == spell->m_appliedMods.end())
continue;
// remove from list
spell->m_appliedMods.erase(iterMod);
if (mod->ownerAura->DropCharge(AURA_REMOVE_BY_EXPIRE))
itr = m_spellMods[i].begin();
}
}
}
void Player::DropModCharge(SpellModifier* mod, Spell* spell)
{
// don't handle spells with proc_event entry defined
// this is a temporary workaround, because all spellmods should be handled like that
if (sSpellMgr->GetSpellProcEvent(mod->spellId))
return;
if (spell && mod->ownerAura && mod->charges > 0)
{
if (--mod->charges == 0)
mod->charges = -1;
spell->m_appliedMods.insert(mod->ownerAura);
}
// register inside spell, proc system uses this to drop charges
spell->m_appliedMods.insert(mod->ownerAura);
}
void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
@@ -21372,7 +21329,7 @@ void Player::SetSpellModTakingSpell(Spell* spell, bool apply)
if (apply && spell->getState() == SPELL_STATE_FINISHED)
return;
m_spellModTakingSpell = apply ? spell : NULL;
m_spellModTakingSpell = apply ? spell : nullptr;
}
// send Proficiency