diff options
author | Wyrserth <wyrserth@protonmail.com> | 2019-06-26 18:08:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-26 18:08:19 +0200 |
commit | 7a71127da92bd833caf4188aee2d5e88c61ae772 (patch) | |
tree | 6601010e7f424952c6f559899a6122fe77071d79 | |
parent | 8967cc96df4c1c5c7465e9fd1fa66400f3e992b3 (diff) |
Core/SAI: allow creatures to handle gameobject spellhit SAI events. (#23492)
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 10 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 295 |
3 files changed, 160 insertions, 147 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 7165abdc8f2..2856a55a245 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -609,11 +609,21 @@ void SmartAI::SpellHit(Unit* unit, SpellInfo const* spellInfo) GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, unit, 0, 0, false, spellInfo); } +void SmartAI::SpellHitByGameObject(GameObject* object, SpellInfo const* spellInfo) +{ + GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT, nullptr, 0, 0, false, spellInfo, object); +} + void SmartAI::SpellHitTarget(Unit* target, SpellInfo const* spellInfo) { GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, target, 0, 0, false, spellInfo); } +void SmartAI::SpellHitTargetGameObject(GameObject* target, SpellInfo const* spellInfo) +{ + GetScript()->ProcessEventsFor(SMART_EVENT_SPELLHIT_TARGET, nullptr, 0, 0, false, spellInfo, target); +} + void SmartAI::DamageTaken(Unit* doneBy, uint32& damage) { GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index fa3af7b9549..2cf6c0e6b2a 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -99,9 +99,11 @@ class TC_GAME_API SmartAI : public CreatureAI // Called when hit by a spell void SpellHit(Unit* unit, SpellInfo const* spellInfo) override; + void SpellHitByGameObject(GameObject* object, SpellInfo const* spellInfo) override; // Called when spell hits a target void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override; + void SpellHitTargetGameObject(GameObject* object, SpellInfo const* spellInfo) override; // Called at any Damage from any attacker (before damage apply) void DamageTaken(Unit* doneBy, uint32& damage) override; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 75ec6a796b5..dcaa1fd2b2c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2352,191 +2352,192 @@ void Spell::TargetInfo::DoDamageAndTriggers(Spell* spell) // Get original caster (if exist) and calculate damage/healing from him data // Skip if m_originalCaster not available Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit(); - if (!caster) - return; - // Fill base trigger info - uint32 procAttacker = spell->m_procAttacker; - uint32 procVictim = spell->m_procVictim; - uint32 procSpellType = PROC_SPELL_TYPE_NONE; - uint32 hitMask = PROC_HIT_NONE; + if (caster) + { + // Fill base trigger info + uint32 procAttacker = spell->m_procAttacker; + uint32 procVictim = spell->m_procVictim; + uint32 procSpellType = PROC_SPELL_TYPE_NONE; + uint32 hitMask = PROC_HIT_NONE; - // Spells with this flag cannot trigger if effect is cast on self - bool const canEffectTrigger = !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && spell->unitTarget->CanProc() && - (spell->CanExecuteTriggersOnHit(EffectMask) || MissCondition == SPELL_MISS_IMMUNE || MissCondition == SPELL_MISS_IMMUNE2); + // Spells with this flag cannot trigger if effect is cast on self + bool const canEffectTrigger = !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && spell->unitTarget->CanProc() && + (spell->CanExecuteTriggersOnHit(EffectMask) || MissCondition == SPELL_MISS_IMMUNE || MissCondition == SPELL_MISS_IMMUNE2); - // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now - if (canEffectTrigger && !procAttacker && !procVictim) - { - bool positive = true; - if (spell->m_damage > 0) - positive = false; - else if (!spell->m_healing) + // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now + if (canEffectTrigger && !procAttacker && !procVictim) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + bool positive = true; + if (spell->m_damage > 0) + positive = false; + else if (!spell->m_healing) { - // in case of immunity, check all effects to choose correct procFlags, as none has technically hit - if (EffectMask && !(EffectMask & (1 << i))) - continue; - - if (!spell->m_spellInfo->IsPositiveEffect(i)) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { - positive = false; - break; + // in case of immunity, check all effects to choose correct procFlags, as none has technically hit + if (EffectMask && !(EffectMask & (1 << i))) + continue; + + if (!spell->m_spellInfo->IsPositiveEffect(i)) + { + positive = false; + break; + } } } - } - switch (spell->m_spellInfo->DmgClass) - { - case SPELL_DAMAGE_CLASS_MAGIC: - if (positive) - { - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; - procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS; - } - else - { - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; - procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG; - } - break; - case SPELL_DAMAGE_CLASS_NONE: - if (positive) - { - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS; - procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS; - } - else - { - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; - procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG; - } - break; + switch (spell->m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + if (positive) + { + procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; + procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS; + } + else + { + procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; + procVictim |= PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG; + } + break; + case SPELL_DAMAGE_CLASS_NONE: + if (positive) + { + procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS; + procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS; + } + else + { + procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; + procVictim |= PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG; + } + break; + } } - } - // All calculated do it! - // Do healing - std::unique_ptr<DamageInfo> spellDamageInfo; - std::unique_ptr<HealInfo> healInfo; - if (spell->m_healing > 0) - { - uint32 addhealth = spell->m_healing; - if (IsCrit) + // All calculated do it! + // Do healing + std::unique_ptr<DamageInfo> spellDamageInfo; + std::unique_ptr<HealInfo> healInfo; + if (spell->m_healing > 0) { - hitMask |= PROC_HIT_CRITICAL; - addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr); - } - else - hitMask |= PROC_HIT_NORMAL; + uint32 addhealth = spell->m_healing; + if (IsCrit) + { + hitMask |= PROC_HIT_CRITICAL; + addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr); + } + else + hitMask |= PROC_HIT_NORMAL; - healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask()); - caster->HealBySpell(*healInfo, IsCrit); - spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo); - spell->m_healing = healInfo->GetEffectiveHeal(); + healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask()); + caster->HealBySpell(*healInfo, IsCrit); + spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo); + spell->m_healing = healInfo->GetEffectiveHeal(); - procSpellType |= PROC_SPELL_TYPE_HEAL; - } + procSpellType |= PROC_SPELL_TYPE_HEAL; + } - // Do damage - if (spell->m_damage > 0) - { - // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask); - // Check damage immunity - if (spell->unitTarget->IsImmunedToDamage(spell->m_spellInfo)) + // Do damage + if (spell->m_damage > 0) { - hitMask = PROC_HIT_IMMUNE; - spell->m_damage = 0; + // Fill base damage struct (unitTarget - is real spell target) + SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask); + // Check damage immunity + if (spell->unitTarget->IsImmunedToDamage(spell->m_spellInfo)) + { + hitMask = PROC_HIT_IMMUNE; + spell->m_damage = 0; - // no packet found in sniffs - } - else - { - // Add bonuses and fill damageInfo struct - caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit); - Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + // no packet found in sniffs + } + else + { + // Add bonuses and fill damageInfo struct + caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit); + Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - // Send log damage message to client - caster->SendSpellNonMeleeDamageLog(&damageInfo); + // Send log damage message to client + caster->SendSpellNonMeleeDamageLog(&damageInfo); - hitMask |= createProcHitMask(&damageInfo, MissCondition); - procVictim |= PROC_FLAG_TAKEN_DAMAGE; + hitMask |= createProcHitMask(&damageInfo, MissCondition); + procVictim |= PROC_FLAG_TAKEN_DAMAGE; + + spell->m_damage = damageInfo.damage; + caster->DealSpellDamage(&damageInfo, true); + } - spell->m_damage = damageInfo.damage; - caster->DealSpellDamage(&damageInfo, true); + // Do triggers for unit + if (canEffectTrigger) + { + spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, hitMask); + procSpellType |= PROC_SPELL_TYPE_DAMAGE; + + if (caster->GetTypeId() == TYPEID_PLAYER && !spell->m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !spell->m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && + (spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) + caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo); + } } - // Do triggers for unit - if (canEffectTrigger) + // Passive spell hits/misses or active spells only misses (only triggers) + if (spell->m_damage <= 0 && spell->m_healing <= 0) { - spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, hitMask); - procSpellType |= PROC_SPELL_TYPE_DAMAGE; + // Fill base damage struct (unitTarget - is real spell target) + SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask); + hitMask |= createProcHitMask(&damageInfo, MissCondition); + // Do triggers for unit + if (canEffectTrigger) + { + spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, hitMask); + procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL; + } - if (caster->GetTypeId() == TYPEID_PLAYER && !spell->m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !spell->m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS) && - (spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) - caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo); + // Failed Pickpocket, reveal rogue + if (MissCondition == SPELL_MISS_RESIST && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && spell->unitTarget->GetTypeId() == TYPEID_UNIT) + { + Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit()); + unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); + spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster); + } } - } - // Passive spell hits/misses or active spells only misses (only triggers) - if (spell->m_damage <= 0 && spell->m_healing <= 0) - { - // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask); - hitMask |= createProcHitMask(&damageInfo, MissCondition); // Do triggers for unit if (canEffectTrigger) { - spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, hitMask); - procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL; - } + Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, hitMask, spell, spellDamageInfo.get(), healInfo.get()); - // Failed Pickpocket, reveal rogue - if (MissCondition == SPELL_MISS_RESIST && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && spell->unitTarget->GetTypeId() == TYPEID_UNIT) - { - Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit()); - unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); - spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster); + // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit) + if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL))) + { + if (spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED) + if (!spell->m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !spell->m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS)) + caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo); + } } - } - // Do triggers for unit - if (canEffectTrigger) - { - Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, hitMask, spell, spellDamageInfo.get(), healInfo.get()); + // set hitmask for finish procs + spell->m_hitMask |= hitMask; - // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit) - if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL))) - { - if (spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || spell->m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED) - if (!spell->m_spellInfo->HasAttribute(SPELL_ATTR0_STOP_ATTACK_TARGET) && !spell->m_spellInfo->HasAttribute(SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS)) - caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo); - } - } + // Do not take combo points on dodge and miss + if (MissCondition != SPELL_MISS_NONE && spell->m_needComboPoints && spell->m_targets.GetUnitTargetGUID() == TargetGUID) + spell->m_needComboPoints = false; - // set hitmask for finish procs - spell->m_hitMask |= hitMask; - - // Do not take combo points on dodge and miss - if (MissCondition != SPELL_MISS_NONE && spell->m_needComboPoints && spell->m_targets.GetUnitTargetGUID() == TargetGUID) - spell->m_needComboPoints = false; + // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit + if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) + { + if (Unit* unitCaster = spell->m_caster->ToUnit()) + unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro()); - // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit - if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) - { - if (Unit* unitCaster = spell->m_caster->ToUnit()) - unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro()); + if (!unit->IsStandState()) + unit->SetStandState(UNIT_STAND_STATE_STAND); + } - if (!unit->IsStandState()) - unit->SetStandState(UNIT_STAND_STATE_STAND); + // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER + if (MissCondition == SPELL_MISS_NONE && spell->m_spellInfo->HasAttribute(SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER) && unit->GetTypeId() != TYPEID_PLAYER) + caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, true); } - // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER - if (MissCondition == SPELL_MISS_NONE && spell->m_spellInfo->HasAttribute(SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER) && unit->GetTypeId() != TYPEID_PLAYER) - caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, true); - if (_spellHitTarget) { //AI functions |