aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWyrserth <wyrserth@protonmail.com>2019-06-26 18:08:19 +0200
committerGitHub <noreply@github.com>2019-06-26 18:08:19 +0200
commit7a71127da92bd833caf4188aee2d5e88c61ae772 (patch)
tree6601010e7f424952c6f559899a6122fe77071d79
parent8967cc96df4c1c5c7465e9fd1fa66400f3e992b3 (diff)
Core/SAI: allow creatures to handle gameobject spellhit SAI events. (#23492)
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp10
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h2
-rw-r--r--src/server/game/Spells/Spell.cpp295
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