Core/SAI: allow creatures to handle gameobject spellhit SAI events.

Port From (https://github.com/TrinityCore/TrinityCore/commit/83a9222c390110ae082512ed858a5580a958aa21)
This commit is contained in:
hondacrx
2021-12-24 21:05:03 -05:00
parent b3759bb7b0
commit 0f248e2faa
2 changed files with 168 additions and 158 deletions
+10
View File
@@ -662,11 +662,21 @@ namespace Game.AI
GetScript().ProcessEventsFor(SmartEvents.SpellHit, caster, 0, 0, false, spellInfo); GetScript().ProcessEventsFor(SmartEvents.SpellHit, caster, 0, 0, false, spellInfo);
} }
public override void SpellHitByGameObject(GameObject obj, SpellInfo spellInfo)
{
GetScript().ProcessEventsFor(SmartEvents.SpellHit, null, 0, 0, false, spellInfo, obj);
}
public override void SpellHitTarget(Unit target, SpellInfo spellInfo) public override void SpellHitTarget(Unit target, SpellInfo spellInfo)
{ {
GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target, 0, 0, false, spellInfo); GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target, 0, 0, false, spellInfo);
} }
public override void SpellHitTargetGameObject(GameObject target, SpellInfo spellInfo)
{
GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, null, 0, 0, false, spellInfo, target);
}
public override void DamageTaken(Unit attacker, ref uint damage) public override void DamageTaken(Unit attacker, ref uint damage)
{ {
GetScript().ProcessEventsFor(SmartEvents.Damaged, attacker, damage); GetScript().ProcessEventsFor(SmartEvents.Damaged, attacker, damage);
+158 -158
View File
@@ -7862,193 +7862,193 @@ namespace Game.Spells
// Get original caster (if exist) and calculate damage/healing from him data // Get original caster (if exist) and calculate damage/healing from him data
// Skip if m_originalCaster not available // Skip if m_originalCaster not available
Unit caster = spell.GetOriginalCaster() ? spell.GetOriginalCaster() : spell.GetCaster().ToUnit(); Unit caster = spell.GetOriginalCaster() ? spell.GetOriginalCaster() : spell.GetCaster().ToUnit();
if (caster == null) if (caster != null)
return;
// Fill base trigger info
ProcFlags procAttacker = spell.m_procAttacker;
ProcFlags procVictim = spell.m_procVictim;
ProcFlagsSpellType procSpellType = ProcFlagsSpellType.None;
ProcFlagsHit hitMask = ProcFlagsHit.None;
// Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !spell.m_spellInfo.HasAttribute(SpellAttr3.CantTriggerProc) && spell.unitTarget.CanProc() &&
(spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2);
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && procAttacker == 0 && procVictim == 0)
{ {
bool positive = true; // Fill base trigger info
if (spell.m_damage > 0) ProcFlags procAttacker = spell.m_procAttacker;
positive = false; ProcFlags procVictim = spell.m_procVictim;
else if (spell.m_healing == 0) ProcFlagsSpellType procSpellType = ProcFlagsSpellType.None;
{ ProcFlagsHit hitMask = ProcFlagsHit.None;
for (uint i = 0; i < SpellConst.MaxEffects; ++i)
{
// in case of immunity, check all effects to choose correct procFlags, as none has technically hit
if (EffectMask != 0 && (EffectMask & (1 << (int)i)) == 0)
continue;
if (!spell.m_spellInfo.IsPositiveEffect(i)) // Spells with this flag cannot trigger if effect is cast on self
bool canEffectTrigger = !spell.m_spellInfo.HasAttribute(SpellAttr3.CantTriggerProc) && spell.unitTarget.CanProc() &&
(spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2);
// Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
if (canEffectTrigger && procAttacker == 0 && procVictim == 0)
{
bool positive = true;
if (spell.m_damage > 0)
positive = false;
else if (spell.m_healing == 0)
{
for (uint i = 0; i < spell.m_spellInfo.GetEffects().Count; ++i)
{ {
positive = false; // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
break; if (EffectMask != 0 && (EffectMask & (1 << (int)i)) == 0)
continue;
if (!spell.m_spellInfo.IsPositiveEffect(i))
{
positive = false;
break;
}
} }
} }
switch (spell.m_spellInfo.DmgClass)
{
case SpellDmgClass.Magic:
if (positive)
{
procAttacker |= ProcFlags.DoneSpellMagicDmgClassPos;
procVictim |= ProcFlags.TakenSpellMagicDmgClassPos;
}
else
{
procAttacker |= ProcFlags.DoneSpellMagicDmgClassNeg;
procVictim |= ProcFlags.TakenSpellMagicDmgClassNeg;
}
break;
case SpellDmgClass.None:
if (positive)
{
procAttacker |= ProcFlags.DoneSpellNoneDmgClassPos;
procVictim |= ProcFlags.TakenSpellNoneDmgClassPos;
}
else
{
procAttacker |= ProcFlags.DoneSpellNoneDmgClassNeg;
procVictim |= ProcFlags.TakenSpellNoneDmgClassNeg;
}
break;
}
} }
switch (spell.m_spellInfo.DmgClass) // All calculated do it!
// Do healing
DamageInfo spellDamageInfo = null;
HealInfo healInfo = null;
if (spell.m_healing > 0)
{ {
case SpellDmgClass.Magic: int addhealth = spell.m_healing;
if (positive) if (IsCrit)
{ {
procAttacker |= ProcFlags.DoneSpellMagicDmgClassPos; hitMask |= ProcFlagsHit.Critical;
procVictim |= ProcFlags.TakenSpellMagicDmgClassPos; addhealth = Unit.SpellCriticalHealingBonus(caster, spell.m_spellInfo, addhealth, null);
} }
else else
{ hitMask |= ProcFlagsHit.Normal;
procAttacker |= ProcFlags.DoneSpellMagicDmgClassNeg;
procVictim |= ProcFlags.TakenSpellMagicDmgClassNeg; healInfo = new(caster, spell.unitTarget, (uint)addhealth, spell.m_spellInfo, spell.m_spellInfo.GetSchoolMask());
} caster.HealBySpell(healInfo, IsCrit);
break; spell.unitTarget.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, spell.m_spellInfo);
case SpellDmgClass.None: spell.m_healing = (int)healInfo.GetEffectiveHeal();
if (positive)
{ procSpellType |= ProcFlagsSpellType.Heal;
procAttacker |= ProcFlags.DoneSpellNoneDmgClassPos;
procVictim |= ProcFlags.TakenSpellNoneDmgClassPos;
}
else
{
procAttacker |= ProcFlags.DoneSpellNoneDmgClassNeg;
procVictim |= ProcFlags.TakenSpellNoneDmgClassNeg;
}
break;
} }
}
// All calculated do it! // Do damage
// Do healing if (spell.m_damage > 0)
DamageInfo spellDamageInfo = null;
HealInfo healInfo = null;
if (spell.m_healing > 0)
{
int addhealth = spell.m_healing;
if (IsCrit)
{ {
hitMask |= ProcFlagsHit.Critical; // Fill base damage struct (unitTarget - is real spell target)
addhealth = Unit.SpellCriticalHealingBonus(caster, spell.m_spellInfo, addhealth, null); SpellNonMeleeDamage damageInfo = new(caster, spell.unitTarget, spell.m_spellInfo, spell.m_SpellVisual, spell.m_spellSchoolMask, spell.m_castId);
// Check damage immunity
if (spell.unitTarget.IsImmunedToDamage(spell.m_spellInfo))
{
hitMask = ProcFlagsHit.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.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
hitMask |= Unit.CreateProcHitMask(damageInfo, MissCondition);
procVictim |= ProcFlags.TakenDamage;
spell.m_damage = (int)damageInfo.damage;
caster.DealSpellDamage(damageInfo, true);
// Send log damage message to client
caster.SendSpellNonMeleeDamageLog(damageInfo);
}
// Do triggers for unit
if (canEffectTrigger)
{
spellDamageInfo = new(damageInfo, DamageEffectType.SpellDirect, spell.m_attackType, hitMask);
procSpellType |= ProcFlagsSpellType.Damage;
if (caster.IsPlayer() && !spell.m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !spell.m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs) &&
(spell.m_spellInfo.DmgClass == SpellDmgClass.Melee || spell.m_spellInfo.DmgClass == SpellDmgClass.Ranged))
caster.ToPlayer().CastItemCombatSpell(spellDamageInfo);
}
} }
else
hitMask |= ProcFlagsHit.Normal;
healInfo = new(caster, spell.unitTarget, (uint)addhealth, spell.m_spellInfo, spell.m_spellInfo.GetSchoolMask()); // Passive spell hits/misses or active spells only misses (only triggers)
caster.HealBySpell(healInfo, IsCrit); if (spell.m_damage <= 0 && spell.m_healing <= 0)
spell.unitTarget.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, spell.m_spellInfo);
spell.m_healing = (int)healInfo.GetEffectiveHeal();
procSpellType |= ProcFlagsSpellType.Heal;
}
// Do damage
if (spell.m_damage > 0)
{
// Fill base damage struct (unitTarget - is real spell target)
SpellNonMeleeDamage damageInfo = new(caster, spell.unitTarget, spell.m_spellInfo, spell.m_SpellVisual, spell.m_spellSchoolMask, spell.m_castId);
// Check damage immunity
if (spell.unitTarget.IsImmunedToDamage(spell.m_spellInfo))
{ {
hitMask = ProcFlagsHit.Immune; // Fill base damage struct (unitTarget - is real spell target)
spell.m_damage = 0; SpellNonMeleeDamage damageInfo = new(caster, spell.unitTarget, spell.m_spellInfo, spell.m_SpellVisual, spell.m_spellSchoolMask);
// 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.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
hitMask |= Unit.CreateProcHitMask(damageInfo, MissCondition); hitMask |= Unit.CreateProcHitMask(damageInfo, MissCondition);
procVictim |= ProcFlags.TakenDamage; // Do triggers for unit
if (canEffectTrigger)
{
spellDamageInfo = new(damageInfo, DamageEffectType.NoDamage, spell.m_attackType, hitMask);
procSpellType |= ProcFlagsSpellType.NoDmgHeal;
}
spell.m_damage = (int)damageInfo.damage; // Failed Pickpocket, reveal rogue
if (MissCondition == SpellMissInfo.Resist && spell.m_spellInfo.HasAttribute(SpellCustomAttributes.PickPocket) && spell.unitTarget.IsCreature())
caster.DealSpellDamage(damageInfo, true); {
Unit unitCaster = spell.GetCaster().ToUnit();
// Send log damage message to client unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting);
caster.SendSpellNonMeleeDamageLog(damageInfo); spell.unitTarget.ToCreature().EngageWithTarget(unitCaster);
}
} }
// Do triggers for unit // Do triggers for unit
if (canEffectTrigger) if (canEffectTrigger)
{ {
spellDamageInfo = new(damageInfo, DamageEffectType.SpellDirect, spell.m_attackType, hitMask); Unit.ProcSkillsAndAuras(caster, spell.unitTarget, procAttacker, procVictim, procSpellType, ProcFlagsSpellPhase.Hit, hitMask, spell, spellDamageInfo, healInfo);
procSpellType |= ProcFlagsSpellType.Damage;
if (caster.IsPlayer() && !spell.m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !spell.m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs) && // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
(spell.m_spellInfo.DmgClass == SpellDmgClass.Melee || spell.m_spellInfo.DmgClass == SpellDmgClass.Ranged)) if (caster.IsPlayer() && procSpellType.HasAnyFlag(ProcFlagsSpellType.Damage | ProcFlagsSpellType.NoDmgHeal))
caster.ToPlayer().CastItemCombatSpell(spellDamageInfo); {
} if (spell.m_spellInfo.DmgClass == SpellDmgClass.Melee || spell.m_spellInfo.DmgClass == SpellDmgClass.Ranged)
} if (!spell.m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !spell.m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs))
caster.ToPlayer().CastItemCombatSpell(spellDamageInfo);
// 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 = new(caster, spell.unitTarget, spell.m_spellInfo, spell.m_SpellVisual, spell.m_spellSchoolMask);
hitMask |= Unit.CreateProcHitMask(damageInfo, MissCondition);
// Do triggers for unit
if (canEffectTrigger)
{
spellDamageInfo = new(damageInfo, DamageEffectType.NoDamage, spell.m_attackType, hitMask);
procSpellType |= ProcFlagsSpellType.NoDmgHeal;
} }
// Failed Pickpocket, reveal rogue // set hitmask for finish procs
if (MissCondition == SpellMissInfo.Resist && spell.m_spellInfo.HasAttribute(SpellCustomAttributes.PickPocket) && spell.unitTarget.IsCreature()) spell.m_hitMask |= hitMask;
// Do not take combo points on dodge and miss
if (MissCondition != SpellMissInfo.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 != SpellMissInfo.Evade && _spellHitTarget && !spell.GetCaster().IsFriendlyTo(unit) && (!spell.IsPositive() || spell.m_spellInfo.HasEffect(SpellEffectName.Dispel)))
{ {
Unit unitCaster = spell.GetCaster().ToUnit(); Unit unitCaster = spell.GetCaster().ToUnit();
unitCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting); if (unitCaster != null)
spell.unitTarget.ToCreature().EngageWithTarget(unitCaster); unitCaster.AtTargetAttacked(unit, spell.m_spellInfo.HasInitialAggro());
if (!unit.IsStandState())
unit.SetStandState(UnitStandStateType.Stand);
} }
// Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
if (MissCondition == SpellMissInfo.None && spell.m_spellInfo.HasAttribute(SpellAttr7.InterruptOnlyNonplayer) && !unit.IsPlayer())
caster.CastSpell(unit, 32747, new CastSpellExtraArgs(TriggerCastFlags.FullMask).SetOriginalCastId(spell.m_castId));
} }
// Do triggers for unit
if (canEffectTrigger)
{
Unit.ProcSkillsAndAuras(caster, spell.unitTarget, procAttacker, procVictim, procSpellType, ProcFlagsSpellPhase.Hit, hitMask, spell, spellDamageInfo, healInfo);
// item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
if (caster.IsPlayer() && procSpellType.HasAnyFlag(ProcFlagsSpellType.Damage | ProcFlagsSpellType.NoDmgHeal))
{
if (spell.m_spellInfo.DmgClass == SpellDmgClass.Melee || spell.m_spellInfo.DmgClass == SpellDmgClass.Ranged)
if (!spell.m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !spell.m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs))
caster.ToPlayer().CastItemCombatSpell(spellDamageInfo);
}
}
// set hitmask for finish procs
spell.m_hitMask |= hitMask;
// Do not take combo points on dodge and miss
if (MissCondition != SpellMissInfo.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 != SpellMissInfo.Evade && _spellHitTarget && !spell.GetCaster().IsFriendlyTo(unit) && (!spell.IsPositive() || spell.m_spellInfo.HasEffect(SpellEffectName.Dispel)))
{
Unit unitCaster = spell.GetCaster().ToUnit();
if (unitCaster != null)
unitCaster.AtTargetAttacked(unit, spell.m_spellInfo.HasInitialAggro());
if (!unit.IsStandState())
unit.SetStandState(UnitStandStateType.Stand);
}
// Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
if (MissCondition == SpellMissInfo.None && spell.m_spellInfo.HasAttribute(SpellAttr7.InterruptOnlyNonplayer) && !unit.IsPlayer())
caster.CastSpell(unit, 32747, new CastSpellExtraArgs(TriggerCastFlags.FullMask).SetOriginalCastId(spell.m_castId));
if (_spellHitTarget) if (_spellHitTarget)
{ {
//AI functions //AI functions