From d552c656681c1c8d1a260832b0cf43cfb74d1ae6 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 25 Oct 2017 17:07:28 -0400 Subject: [PATCH] Misc Fixes --- Framework/Realm/RealmManager.cs | 13 +- Game/AI/CoreAI/CreatureAI.cs | 3 + Game/Arenas/ArenaTeam.cs | 12 +- Game/Chat/Commands/MiscCommands.cs | 19 +- Game/Entities/Player/Player.Quest.cs | 12 +- Game/Entities/Player/Player.cs | 17 +- Game/Entities/Unit/Unit.Combat.cs | 210 +++++++++--------- Game/Entities/Unit/Unit.Spells.cs | 16 +- Game/Globals/ObjectManager.cs | 6 +- Game/Spells/Auras/Aura.cs | 9 + Game/Spells/Auras/AuraEffect.cs | 49 ++-- Game/Spells/Spell.cs | 18 +- Game/Spells/SpellEffects.cs | 22 +- Scripts/Kalimdor/ZoneAshenvale.cs | 27 ++- .../TrialOfTheCrusader/NorthrendBeasts.cs | 9 +- 15 files changed, 248 insertions(+), 194 deletions(-) diff --git a/Framework/Realm/RealmManager.cs b/Framework/Realm/RealmManager.cs index 9e017ecb9..0764b74c4 100644 --- a/Framework/Realm/RealmManager.cs +++ b/Framework/Realm/RealmManager.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Timers; +using System.Collections.Concurrent; public class RealmManager : Singleton { @@ -48,14 +49,8 @@ public class RealmManager : Singleton void UpdateRealm(Realm realm) { var oldRealm = _realms.LookupByKey(realm.Id); - if (oldRealm == null) - { - _realms[realm.Id] = realm; - return; - } - - if (oldRealm == realm) - return; + if (oldRealm != null && oldRealm == realm) + return; _realms[realm.Id] = realm; } @@ -323,7 +318,7 @@ public class RealmManager : Singleton public List GetRealms() { return _realms.Values.ToList(); } List GetSubRegions() { return _subRegions; } - Dictionary _realms = new Dictionary(); + ConcurrentDictionary _realms = new ConcurrentDictionary(); List _subRegions = new List(); Timer _updateTimer; } diff --git a/Game/AI/CoreAI/CreatureAI.cs b/Game/AI/CoreAI/CreatureAI.cs index 1e3876033..320cc7e60 100644 --- a/Game/AI/CoreAI/CreatureAI.cs +++ b/Game/AI/CoreAI/CreatureAI.cs @@ -432,6 +432,9 @@ namespace Game.AI public virtual void MovementInform(MovementGeneratorType type, uint id) { } + // Called when a spell cast gets interrupted + public virtual void OnSpellCastInterrupt(SpellInfo spell) { } + // Called at reaching home after evade public virtual void JustReachedHome() { } diff --git a/Game/Arenas/ArenaTeam.cs b/Game/Arenas/ArenaTeam.cs index 2862b0419..0308a1f14 100644 --- a/Game/Arenas/ArenaTeam.cs +++ b/Game/Arenas/ArenaTeam.cs @@ -718,6 +718,10 @@ namespace Game.Arenas foreach (var member in Members) { + // Save the effort and go + if (member.WeekGames == 0) + continue; + stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_MEMBER); stmt.AddValue(0, member.PersonalRating); stmt.AddValue(1, member.WeekGames); @@ -738,8 +742,12 @@ namespace Game.Arenas DB.Characters.CommitTransaction(trans); } - public void FinishWeek() + public bool FinishWeek() { + // No need to go further than this + if (stats.WeekGames == 0) + return false; + // Reset team stats stats.WeekGames = 0; stats.WeekWins = 0; @@ -750,6 +758,8 @@ namespace Game.Arenas member.WeekGames = 0; member.WeekWins = 0; } + + return true; } public bool IsFighting() diff --git a/Game/Chat/Commands/MiscCommands.cs b/Game/Chat/Commands/MiscCommands.cs index 044853d70..eeb329599 100644 --- a/Game/Chat/Commands/MiscCommands.cs +++ b/Game/Chat/Commands/MiscCommands.cs @@ -2055,19 +2055,20 @@ namespace Game.Chat // melee damage by specific school if (string.IsNullOrEmpty(spellStr)) { - uint absorb = 0; - uint resist = 0; + Player attacker = handler.GetSession().GetPlayer(); + DamageInfo dmgInfo = new DamageInfo(attacker, target, damage_, null, schoolmask, DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); + attacker.CalcAbsorbResist(dmgInfo); - handler.GetSession().GetPlayer().CalcAbsorbResist(target, schoolmask, DamageEffectType.SpellDirect, damage_, ref absorb, ref resist); - - if (damage_ <= absorb + resist) + if (dmgInfo.GetDamage() == 0) return true; - damage_ -= absorb + resist; + damage_ = dmgInfo.GetDamage(); - handler.GetSession().GetPlayer().DealDamageMods(target, ref damage_, ref absorb); - handler.GetSession().GetPlayer().DealDamage(target, damage_, null, DamageEffectType.Direct, schoolmask, null, false); - handler.GetSession().GetPlayer().SendAttackStateUpdate(HitInfo.AffectsVictim, target, schoolmask, damage_, absorb, resist, VictimState.Hit, 0); + uint absorb = dmgInfo.GetAbsorb(); + uint resist = dmgInfo.GetResist(); + attacker.DealDamageMods(target, ref damage_, ref absorb); + attacker.DealDamage(target, damage_, null, DamageEffectType.Direct, schoolmask, null, false); + attacker.SendAttackStateUpdate(HitInfo.AffectsVictim, target, schoolmask, damage_, absorb, resist, VictimState.Hit, 0); return true; } diff --git a/Game/Entities/Player/Player.Quest.cs b/Game/Entities/Player/Player.Quest.cs index f4cfc30d3..04166fd10 100644 --- a/Game/Entities/Player/Player.Quest.cs +++ b/Game/Entities/Player/Player.Quest.cs @@ -1045,7 +1045,10 @@ namespace Game.Entities if (quest.RewardSpell > 0) { SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell); - if (questGiver.isTypeMask(TypeMask.Unit) && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.LearnSpell) && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.CreateItem) && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.ApplyAura)) + if (questGiver && questGiver.isTypeMask(TypeMask.Unit) + && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.LearnSpell) + && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.CreateItem) + && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.ApplyAura)) { Unit unit = questGiver.ToUnit(); if (unit) @@ -1061,7 +1064,9 @@ namespace Game.Entities if (quest.RewardDisplaySpell[i] > 0) { SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardDisplaySpell[i]); - if (questGiver.IsTypeId(TypeId.Unit) && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.LearnSpell) && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.CreateItem)) + if (questGiver && questGiver.IsTypeId(TypeId.Unit) + && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.LearnSpell) + && !spellInfo.HasEffect(Difficulty.None, SpellEffectName.CreateItem)) { Unit unit = questGiver.ToUnit(); if (unit) @@ -2639,7 +2644,10 @@ namespace Game.Entities public void SetQuestObjectiveData(QuestObjective objective, int data) { if (objective.StorageIndex < 0) + { Log.outError(LogFilter.Player, "SetQuestObjectiveData: called for quest {0} with invalid StorageIndex {1} (objective data is not tracked)", objective.QuestID, objective.StorageIndex); + return; + } var status = m_QuestStatus.LookupByKey(objective.QuestID); if (status == null) diff --git a/Game/Entities/Player/Player.cs b/Game/Entities/Player/Player.cs index 7149bf29b..0bc1f8209 100644 --- a/Game/Entities/Player/Player.cs +++ b/Game/Entities/Player/Player.cs @@ -4157,12 +4157,17 @@ namespace Game.Entities // Absorb, resist some environmental damage type uint absorb = 0; uint resist = 0; - if (type == EnviromentalDamage.Lava) - CalcAbsorbResist(this, SpellSchoolMask.Fire, DamageEffectType.Direct, damage, ref absorb, ref resist); - else if (type == EnviromentalDamage.Slime) - CalcAbsorbResist(this, SpellSchoolMask.Nature, DamageEffectType.Direct, damage, ref absorb, ref resist); - - damage -= absorb + resist; + switch (type) + { + case EnviromentalDamage.Lava: + case EnviromentalDamage.Slime: + DamageInfo dmgInfo = new DamageInfo(this, this, damage, null, type == EnviromentalDamage.Lava ? SpellSchoolMask.Fire : SpellSchoolMask.Nature, DamageEffectType.Direct, WeaponAttackType.BaseAttack); + CalcAbsorbResist(dmgInfo); + absorb = dmgInfo.GetAbsorb(); + resist = dmgInfo.GetResist(); + damage = dmgInfo.GetDamage(); + break; + } DealDamageMods(this, ref damage, ref absorb); diff --git a/Game/Entities/Unit/Unit.Combat.cs b/Game/Entities/Unit/Unit.Combat.cs index ea47916de..26f320bf3 100644 --- a/Game/Entities/Unit/Unit.Combat.cs +++ b/Game/Entities/Unit/Unit.Combat.cs @@ -844,9 +844,9 @@ namespace Game.Entities damage = SpellDamageBonusTaken(caster, i_spellProto, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); } - uint absorb = 0; - uint resist = 0; - victim.CalcAbsorbResist(this, i_spellProto.SchoolMask, DamageEffectType.SpellDirect, damage, ref absorb, ref resist, i_spellProto); + DamageInfo damageInfo1 = new DamageInfo(this, victim, damage, i_spellProto, i_spellProto.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); + victim.CalcAbsorbResist(damageInfo1); + damage = damageInfo1.GetDamage(); // No Unit.CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that victim.DealDamageMods(this, ref damage); @@ -857,7 +857,7 @@ namespace Game.Entities damageShield.TotalDamage = damage; damageShield.OverKill = (uint)Math.Max(damage - GetHealth(), 0); damageShield.SchoolMask = (uint)i_spellProto.SchoolMask; - damageShield.LogAbsorbed = absorb; + damageShield.LogAbsorbed = damageInfo1.GetAbsorb(); victim.DealDamage(this, damage, null, DamageEffectType.SpellDirect, i_spellProto.GetSchoolMask(), i_spellProto, true); damageShield.LogData.Initialize(this); @@ -1924,15 +1924,17 @@ namespace Game.Entities { damageInfo.procVictim |= ProcFlags.TakenDamage; // Calculate absorb & resists - CalcAbsorbResist(damageInfo.target, (SpellSchoolMask)damageInfo.damageSchoolMask, DamageEffectType.Direct, damageInfo.damage, ref damageInfo.absorb, ref damageInfo.resist); + DamageInfo dmgInfo = new DamageInfo(damageInfo); + CalcAbsorbResist(dmgInfo); + damageInfo.absorb = dmgInfo.GetAbsorb(); + damageInfo.resist = dmgInfo.GetResist(); + damageInfo.damage = dmgInfo.GetDamage(); if (damageInfo.absorb != 0) damageInfo.HitInfo |= (damageInfo.damage - damageInfo.absorb == 0 ? HitInfo.FullAbsorb : HitInfo.PartialAbsorb); if (damageInfo.resist != 0) damageInfo.HitInfo |= (damageInfo.damage - damageInfo.resist == 0 ? HitInfo.FullResist : HitInfo.PartialResist); - - damageInfo.damage -= damageInfo.absorb + damageInfo.resist; } else // Impossible get negative result but.... damageInfo.damage = 0; @@ -2314,105 +2316,51 @@ namespace Game.Entities return resistance * 10; } - public void CalcAbsorbResist(Unit victim, SpellSchoolMask schoolMask, DamageEffectType damagetype, uint damage, ref uint absorb, ref uint resist, SpellInfo spellInfo = null) + public void CalcAbsorbResist(DamageInfo damageInfo) { - if (victim == null || !victim.IsAlive() || damage == 0) + if (!damageInfo.GetVictim() || !damageInfo.GetVictim().IsAlive() || damageInfo.GetDamage() == 0) return; - DamageInfo dmgInfo = new DamageInfo(this, victim, damage, spellInfo, schoolMask, damagetype, WeaponAttackType.BaseAttack); - - uint spellResistance = CalcSpellResistance(victim, schoolMask, spellInfo); - dmgInfo.ResistDamage(MathFunctions.CalculatePct(damage, spellResistance)); + uint spellResistance = CalcSpellResistance(damageInfo.GetVictim(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo()); + damageInfo.ResistDamage(MathFunctions.CalculatePct(damageInfo.GetDamage(), spellResistance)); // Ignore Absorption Auras - float auraAbsorbMod = 0; - var AbsIgnoreAurasA = GetAuraEffectsByType(AuraType.ModTargetAbsorbSchool); - foreach (var eff in AbsIgnoreAurasA) + float auraAbsorbMod = GetMaxPositiveAuraModifierByMiscMask(AuraType.ModTargetAbsorbSchool, (uint)damageInfo.GetSchoolMask()); + + var abilityAbsorbAuras = GetAuraEffectsByType(AuraType.ModTargetAbilityAbsorbSchool); + foreach (AuraEffect aurEff in abilityAbsorbAuras) { - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) + if (!Convert.ToBoolean(aurEff.GetMiscValue() & (int)damageInfo.GetSchoolMask())) continue; - if (eff.GetAmount() > auraAbsorbMod) - auraAbsorbMod = eff.GetAmount(); - } - - var AbsIgnoreAurasB = GetAuraEffectsByType(AuraType.ModTargetAbilityAbsorbSchool); - foreach (var eff in AbsIgnoreAurasB) - { - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) + if (!aurEff.IsAffectingSpell(damageInfo.GetSpellInfo())) continue; - if ((eff.GetAmount() > auraAbsorbMod) && eff.IsAffectingSpell(spellInfo)) - auraAbsorbMod = eff.GetAmount(); + if ((aurEff.GetAmount() > auraAbsorbMod)) + auraAbsorbMod = aurEff.GetAmount(); } + MathFunctions.RoundToInterval(ref auraAbsorbMod, 0.0f, 100.0f); - int absorbIgnoringDamage = (int)MathFunctions.CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod); - dmgInfo.ModifyDamage(-absorbIgnoringDamage); + int absorbIgnoringDamage = (int)MathFunctions.CalculatePct(damageInfo.GetDamage(), auraAbsorbMod); + damageInfo.ModifyDamage(-absorbIgnoringDamage); // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation - var vSchoolAbsorbCopy = victim.GetAuraEffectsByType(AuraType.SchoolAbsorb); + var vSchoolAbsorbCopy = damageInfo.GetVictim().GetAuraEffectsByType(AuraType.SchoolAbsorb); vSchoolAbsorbCopy.Sort(new AbsorbAuraOrderPred()); // absorb without mana cost - foreach (var eff in vSchoolAbsorbCopy) + foreach (var absorbAurEff in vSchoolAbsorbCopy) { - // Check if aura was removed during iteration - we don't need to work on such auras - AuraApplication aurApp = eff.GetBase().GetApplicationOfTarget(victim.GetGUID()); - if (aurApp == null) - continue; - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) - continue; - - // get amount which can be still absorbed by the aura - int currentAbsorb = eff.GetAmount(); - // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety - if (currentAbsorb < 0) - currentAbsorb = 0; - - uint tempAbsorb = (uint)currentAbsorb; - - bool defaultPrevented = false; - - eff.GetBase().CallScriptEffectAbsorbHandlers(eff, aurApp, dmgInfo, ref tempAbsorb, ref defaultPrevented); - currentAbsorb = (int)tempAbsorb; - - if (defaultPrevented) - continue; - - // absorb must be smaller than the damage itself - MathFunctions.RoundToInterval(ref currentAbsorb, 0, dmgInfo.GetDamage()); - - dmgInfo.AbsorbDamage((uint)currentAbsorb); - - tempAbsorb = (uint)currentAbsorb; - eff.GetBase().CallScriptEffectAfterAbsorbHandlers(eff, aurApp, dmgInfo, ref tempAbsorb); - - // Check if our aura is using amount to count damage - if (eff.GetAmount() >= 0) - { - // Reduce shield amount - eff.ChangeAmount(eff.GetAmount() - currentAbsorb); - // Aura cannot absorb anything more - remove it - if (eff.GetAmount() <= 0) - eff.GetBase().Remove(AuraRemoveMode.EnemySpell); - } - } - - // absorb by mana cost - var vManaShieldCopy = victim.GetAuraEffectsByType(AuraType.ManaShield); - foreach (var absorbAurEff in vManaShieldCopy) - { - if (dmgInfo.GetDamage() <= 0) + if (damageInfo.GetDamage() == 0) break; // Check if aura was removed during iteration - we don't need to work on such auras - AuraApplication aurApp = absorbAurEff.GetBase().GetApplicationOfTarget(victim.GetGUID()); + AuraApplication aurApp = absorbAurEff.GetBase().GetApplicationOfTarget(damageInfo.GetVictim().GetGUID()); if (aurApp == null) continue; - // check damage school mask - if (!Convert.ToBoolean(absorbAurEff.GetMiscValue() & (int)schoolMask)) + if (!Convert.ToBoolean(absorbAurEff.GetMiscValue() & (int)damageInfo.GetSchoolMask())) continue; // get amount which can be still absorbed by the aura @@ -2425,14 +2373,64 @@ namespace Game.Entities bool defaultPrevented = false; - absorbAurEff.GetBase().CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, ref tempAbsorb, defaultPrevented); + absorbAurEff.GetBase().CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, ref tempAbsorb, ref defaultPrevented); currentAbsorb = (int)tempAbsorb; if (defaultPrevented) continue; // absorb must be smaller than the damage itself - MathFunctions.RoundToInterval(ref currentAbsorb, 0, dmgInfo.GetDamage()); + currentAbsorb = MathFunctions.RoundToInterval(ref currentAbsorb, 0, damageInfo.GetDamage()); + + damageInfo.AbsorbDamage((uint)currentAbsorb); + + tempAbsorb = (uint)currentAbsorb; + absorbAurEff.GetBase().CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, ref tempAbsorb); + + // Check if our aura is using amount to count damage + if (absorbAurEff.GetAmount() >= 0) + { + // Reduce shield amount + absorbAurEff.ChangeAmount(absorbAurEff.GetAmount() - currentAbsorb); + // Aura cannot absorb anything more - remove it + if (absorbAurEff.GetAmount() <= 0) + absorbAurEff.GetBase().Remove(AuraRemoveMode.EnemySpell); + } + } + + // absorb by mana cost + var vManaShieldCopy = damageInfo.GetVictim().GetAuraEffectsByType(AuraType.ManaShield); + foreach (var absorbAurEff in vManaShieldCopy) + { + if (damageInfo.GetDamage() == 0) + break; + + // Check if aura was removed during iteration - we don't need to work on such auras + AuraApplication aurApp = absorbAurEff.GetBase().GetApplicationOfTarget(damageInfo.GetVictim().GetGUID()); + if (aurApp == null) + continue; + // check damage school mask + if (!Convert.ToBoolean(absorbAurEff.GetMiscValue() & (int)damageInfo.GetSchoolMask())) + continue; + + // get amount which can be still absorbed by the aura + int currentAbsorb = absorbAurEff.GetAmount(); + // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety + if (currentAbsorb < 0) + currentAbsorb = 0; + + uint tempAbsorb = (uint)currentAbsorb; + + bool defaultPrevented = false; + + absorbAurEff.GetBase().CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, ref tempAbsorb, defaultPrevented); + currentAbsorb = (int)tempAbsorb; + + if (defaultPrevented) + continue; + + // absorb must be smaller than the damage itself + currentAbsorb = MathFunctions.RoundToInterval(ref currentAbsorb, 0, damageInfo.GetDamage()); int manaReduction = currentAbsorb; @@ -2441,15 +2439,15 @@ namespace Game.Entities if (manaMultiplier != 0) manaReduction = (int)(manaReduction * manaMultiplier); - int manaTaken = -victim.ModifyPower(PowerType.Mana, -manaReduction); + int manaTaken = -damageInfo.GetVictim().ModifyPower(PowerType.Mana, -manaReduction); // take case when mana has ended up into account - currentAbsorb = currentAbsorb != 0 ? currentAbsorb * manaTaken / manaReduction : 0; + currentAbsorb = currentAbsorb != 0 ? (currentAbsorb * (manaTaken / manaReduction)) : 0; - dmgInfo.AbsorbDamage((uint)currentAbsorb); + damageInfo.AbsorbDamage((uint)currentAbsorb); tempAbsorb = (uint)currentAbsorb; - absorbAurEff.GetBase().CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, dmgInfo, ref tempAbsorb); + absorbAurEff.GetBase().CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, ref tempAbsorb); // Check if our aura is using amount to count damage if (absorbAurEff.GetAmount() >= 0) @@ -2460,67 +2458,63 @@ namespace Game.Entities } } - dmgInfo.ModifyDamage(absorbIgnoringDamage); + damageInfo.ModifyDamage(absorbIgnoringDamage); // split damage auras - only when not damaging self - if (victim != this) + if (damageInfo.GetVictim() != this) { // We're going to call functions which can modify content of the list during iteration over it's elements // Let's copy the list so we can prevent iterator invalidation - var vSplitDamagePctCopy = victim.GetAuraEffectsByType(AuraType.SplitDamagePct); - foreach (var eff in vSplitDamagePctCopy) + var vSplitDamagePctCopy = damageInfo.GetVictim().GetAuraEffectsByType(AuraType.SplitDamagePct); + foreach (var itr in vSplitDamagePctCopy) { - if (dmgInfo.GetDamage() <= 0) + if (damageInfo.GetDamage() == 0) break; // Check if aura was removed during iteration - we don't need to work on such auras - AuraApplication aurApp = eff.GetBase().GetApplicationOfTarget(victim.GetGUID()); + AuraApplication aurApp = itr.GetBase().GetApplicationOfTarget(damageInfo.GetVictim().GetGUID()); if (aurApp == null) continue; // check damage school mask - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) + if (!Convert.ToBoolean(itr.GetMiscValue() & (int)damageInfo.GetSchoolMask())) continue; // Damage can be splitted only if aura has an alive caster - Unit caster = eff.GetCaster(); - if (caster == null || (caster == victim) || !caster.IsInWorld || !caster.IsAlive()) + Unit caster = itr.GetCaster(); + if (!caster || (caster == damageInfo.GetVictim()) || !caster.IsInWorld || !caster.IsAlive()) continue; - uint splitDamage = MathFunctions.CalculatePct(dmgInfo.GetDamage(), eff.GetAmount()); + uint splitDamage = MathFunctions.CalculatePct(damageInfo.GetDamage(), itr.GetAmount()); - eff.GetBase().CallScriptEffectSplitHandlers(eff, aurApp, dmgInfo, splitDamage); + itr.GetBase().CallScriptEffectSplitHandlers(itr, aurApp, damageInfo, splitDamage); // absorb must be smaller than the damage itself - MathFunctions.RoundToInterval(ref splitDamage, 0, dmgInfo.GetDamage()); + splitDamage = MathFunctions.RoundToInterval(ref splitDamage, 0, damageInfo.GetDamage()); - dmgInfo.AbsorbDamage(splitDamage); + damageInfo.AbsorbDamage(splitDamage); // check if caster is immune to damage - if (caster.IsImmunedToDamage(schoolMask)) + if (caster.IsImmunedToDamage(damageInfo.GetSchoolMask())) { - victim.SendSpellMiss(caster, eff.GetSpellInfo().Id, SpellMissInfo.Immune); + damageInfo.GetVictim().SendSpellMiss(caster, itr.GetSpellInfo().Id, SpellMissInfo.Immune); continue; } uint split_absorb = 0; DealDamageMods(caster, ref splitDamage, ref split_absorb); - SpellNonMeleeDamage log = new SpellNonMeleeDamage(this, caster, eff.GetSpellInfo().Id, eff.GetBase().GetSpellXSpellVisualId(), schoolMask, eff.GetBase().GetCastGUID()); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(this, caster, itr.GetSpellInfo().Id, itr.GetBase().GetSpellXSpellVisualId(), damageInfo.GetSchoolMask(), itr.GetBase().GetCastGUID()); CleanDamage cleanDamage = new CleanDamage(splitDamage, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal); - DealDamage(caster, splitDamage, cleanDamage, DamageEffectType.Direct, schoolMask, eff.GetSpellInfo(), false); + DealDamage(caster, splitDamage, cleanDamage, DamageEffectType.Direct, damageInfo.GetSchoolMask(), itr.GetSpellInfo(), false); log.damage = splitDamage; log.absorb = split_absorb; SendSpellNonMeleeDamageLog(log); // break 'Fear' and similar auras - DamageInfo damageInfo = new DamageInfo(caster, this, splitDamage, eff.GetSpellInfo(), schoolMask, DamageEffectType.Direct, WeaponAttackType.BaseAttack); ProcSkillsAndAuras(caster, ProcFlags.None, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null); } } - - resist = dmgInfo.GetResist(); - absorb = dmgInfo.GetAbsorb(); } public void CalcHealAbsorb(HealInfo healInfo) diff --git a/Game/Entities/Unit/Unit.Spells.cs b/Game/Entities/Unit/Unit.Spells.cs index 790fe3c0b..085fe29c3 100644 --- a/Game/Entities/Unit/Unit.Spells.cs +++ b/Game/Entities/Unit/Unit.Spells.cs @@ -2439,15 +2439,13 @@ namespace Game.Entities Global.ScriptMgr.ModifySpellDamageTaken(damageInfo.target, damageInfo.attacker, ref damage); // Calculate absorb resist - if (damage > 0) - { - CalcAbsorbResist(victim, damageSchoolMask, DamageEffectType.SpellDirect, (uint)damage, ref damageInfo.absorb, ref damageInfo.resist, spellInfo); - damage -= (int)(damageInfo.absorb + damageInfo.resist); - } - else + if (damage < 0) damage = 0; damageInfo.damage = (uint)damage; + DamageInfo dmgInfo = new DamageInfo(damageInfo, DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack, ProcFlagsHit.None); + CalcAbsorbResist(dmgInfo); + damageInfo.damage = dmgInfo.GetDamage(); } public void DealSpellDamage(SpellNonMeleeDamage damageInfo, bool durabilityLoss) { @@ -2664,9 +2662,6 @@ namespace Game.Entities if (diminish.HitCount == 0) return DiminishingLevels.Level1; - if (diminish.HitTime == 0) - return DiminishingLevels.Level1; - // If last spell was cast more than 18 seconds ago - reset the count. if (diminish.Stack == 0 && Time.GetMSTimeDiffToNow(diminish.HitTime) > 18 * Time.InMilliseconds) { @@ -2861,6 +2856,9 @@ namespace Game.Entities if (spell.getState() != SpellState.Finished) spell.cancel(); + if (IsCreature() && IsAIEnabled) + ToCreature().GetAI().OnSpellCastInterrupt(spell.GetSpellInfo()); + m_currentSpells[spellType] = null; spell.SetReferencedFromCurrent(false); } diff --git a/Game/Globals/ObjectManager.cs b/Game/Globals/ObjectManager.cs index 2c306fd38..87344b329 100644 --- a/Game/Globals/ObjectManager.cs +++ b/Game/Globals/ObjectManager.cs @@ -2482,11 +2482,13 @@ namespace Game } if (!CliDB.FactionTemplateStorage.ContainsKey(cInfo.Faction)) - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has non-existing faction template ({1}).", cInfo.Entry, cInfo.Faction); + { + Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has non-existing faction template ({1}). This can lead to crashes, set to faction 35", cInfo.Entry, cInfo.Faction); + cInfo.Faction = 35; + } // used later for scale CreatureDisplayInfoRecord displayScaleEntry = null; - if (cInfo.ModelId1 != 0) { CreatureDisplayInfoRecord displayEntry = CliDB.CreatureDisplayInfoStorage.LookupByKey(cInfo.ModelId1); diff --git a/Game/Spells/Auras/Aura.cs b/Game/Spells/Auras/Aura.cs index c70cdfd6b..77ddc8e82 100644 --- a/Game/Spells/Auras/Aura.cs +++ b/Game/Spells/Auras/Aura.cs @@ -1711,6 +1711,15 @@ namespace Game.Spells if (!Global.SpellMgr.CanSpellTriggerProcOnEvent(procEntry, eventInfo)) return 0; + // check don't break stealth attr present + if (m_spellInfo.HasAura(Difficulty.None, AuraType.ModStealth)) + { + SpellInfo spell = eventInfo.GetSpellInfo(); + if (spell != null) + if (spell.HasAttribute(SpellCustomAttributes.DontBreakStealth)) + return 0; + } + // check if aura can proc when spell is triggered (exception for hunter auto shot & wands) if (!procEntry.AttributesMask.HasAnyFlag(ProcAttributes.TriggeredCanProc) && !eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.AutoAttackMask)) { diff --git a/Game/Spells/Auras/AuraEffect.cs b/Game/Spells/Auras/AuraEffect.cs index 4bf061ba8..2856b74b1 100644 --- a/Game/Spells/Auras/AuraEffect.cs +++ b/Game/Spells/Auras/AuraEffect.cs @@ -674,15 +674,12 @@ namespace Game.Spells return false; // Spell own damage at apply won't break CC - if (spellInfo != null) + if (spellInfo != null && spellInfo == GetSpellInfo()) { - if (spellInfo == GetSpellInfo()) - { - Aura aura = GetBase(); - // called from spellcast, should not have ticked yet - if (aura.GetDuration() == aura.GetMaxDuration()) - return false; - } + Aura aura = GetBase(); + // called from spellcast, should not have ticked yet + if (aura.GetDuration() == aura.GetMaxDuration()) + return false; } break; } @@ -5544,8 +5541,6 @@ namespace Game.Spells } } - uint absorb = 0; - uint resist = 0; CleanDamage cleanDamage = new CleanDamage(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal); // AOE spells are not affected by the new periodic system. @@ -5615,14 +5610,21 @@ namespace Game.Spells if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage)) caster.ApplyResilience(target, ref damage); - caster.CalcAbsorbResist(target, GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, damage, ref absorb, ref resist, GetSpellInfo()); + DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack); + caster.CalcAbsorbResist(damageInfo); + damage = damageInfo.GetDamage(); + + uint absorb = damageInfo.GetAbsorb(); + uint resist = damageInfo.GetResist(); caster.DealDamageMods(target, ref damage, ref absorb); // Set trigger flag ProcFlags procAttacker = ProcFlags.DonePeriodic; ProcFlags procVictim = ProcFlags.TakenPeriodic; - ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; - damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist); + ProcFlagsHit hitMask = damageInfo.GetHitMask(); + if (hitMask == 0) + hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; + if (damage != 0) procVictim |= ProcFlags.TakenDamage; @@ -5632,7 +5634,6 @@ namespace Game.Spells SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, damage, overkill, absorb, resist, 0.0f, crit); - DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack); caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null); caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), true); @@ -5654,8 +5655,6 @@ namespace Game.Spells caster.SpellHitResult(target, GetSpellInfo(), false) != SpellMissInfo.None) return; - uint absorb = 0; - uint resist = 0; CleanDamage cleanDamage = new CleanDamage(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal); bool isAreaAura = GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura); @@ -5698,10 +5697,15 @@ namespace Game.Spells if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage)) caster.ApplyResilience(target, ref damage); - caster.CalcAbsorbResist(target, GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, damage, ref absorb, ref resist, m_spellInfo); + DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack); + caster.CalcAbsorbResist(damageInfo); + uint absorb = damageInfo.GetAbsorb(); + uint resist = damageInfo.GetResist(); + + // SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage SpellNonMeleeDamage log = new SpellNonMeleeDamage(caster, target, GetId(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().GetSchoolMask(), GetBase().GetCastGUID()); - log.damage = damage - absorb - resist; + log.damage = damage; log.absorb = absorb; log.resist = resist; log.periodicLog = true; @@ -5711,16 +5715,15 @@ namespace Game.Spells // Set trigger flag ProcFlags procAttacker = ProcFlags.DonePeriodic; ProcFlags procVictim = ProcFlags.TakenPeriodic; - ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; - damage = (damage <= absorb + resist) ? 0 : (damage - absorb - resist); + ProcFlagsHit hitMask = damageInfo.GetHitMask(); + if (hitMask == 0) + hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; + if (damage != 0) procVictim |= ProcFlags.TakenDamage; if (caster.IsAlive()) - { - DamageInfo damageInfo = new DamageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack); caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null); - } int new_damage = (int)caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false); if (caster.IsAlive()) diff --git a/Game/Spells/Spell.cs b/Game/Spells/Spell.cs index ae0fac36c..10804702e 100644 --- a/Game/Spells/Spell.cs +++ b/Game/Spells/Spell.cs @@ -1891,7 +1891,19 @@ namespace Game.Spells if (m_damage > 0) positive = false; else if (m_healing == 0) - positive = m_spellInfo.IsPositive(); + { + for (byte i = 0; i < SpellConst.MaxEffects; ++i) + { + if (!Convert.ToBoolean(target.effectMask & (1 << i))) + continue; + + if (!m_spellInfo.IsPositiveEffect(i)) + { + positive = false; + break; + } + } + } switch (m_spellInfo.DmgClass) { @@ -2077,11 +2089,7 @@ namespace Game.Spells return SpellMissInfo.Evade; if (m_caster._IsValidAttackTarget(unit, m_spellInfo)) - { unit.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Hitbyspell); - if (!m_spellInfo.HasAttribute(SpellCustomAttributes.DontBreakStealth)) - unit.RemoveAurasByType(AuraType.ModStealth); - } else if (m_caster.IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets diff --git a/Game/Spells/SpellEffects.cs b/Game/Spells/SpellEffects.cs index d35f8ddc2..134d8dba6 100644 --- a/Game/Spells/SpellEffects.cs +++ b/Game/Spells/SpellEffects.cs @@ -126,19 +126,21 @@ namespace Game.Spells if (unitTarget == null || !unitTarget.IsAlive()) return; - uint absorb = 0; - uint resist = 0; - - m_caster.CalcAbsorbResist(unitTarget, m_spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, (uint)damage, ref absorb, ref resist, m_spellInfo); - - SpellNonMeleeDamage log = new SpellNonMeleeDamage(m_caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId); - log.damage = (uint)(damage - absorb - resist); - log.absorb = absorb; - log.resist = resist; + // CalcAbsorbResist already in Player::EnvironmentalDamage if (unitTarget.IsTypeId(TypeId.Player)) unitTarget.ToPlayer().EnvironmentalDamage(EnviromentalDamage.Fire, (uint)damage); + else + { + DamageInfo damageInfo = new DamageInfo(m_caster, unitTarget, (uint)damage, m_spellInfo, m_spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); + m_caster.CalcAbsorbResist(damageInfo); - m_caster.SendSpellNonMeleeDamageLog(log); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(m_caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId); + log.damage = (uint)damage; + log.absorb = damageInfo.GetAbsorb(); + log.resist = damageInfo.GetResist(); + + m_caster.SendSpellNonMeleeDamageLog(log); + } } [SpellEffectHandler(SpellEffectName.SchoolDamage)] diff --git a/Scripts/Kalimdor/ZoneAshenvale.cs b/Scripts/Kalimdor/ZoneAshenvale.cs index 9ad99b609..c1c65e47e 100644 --- a/Scripts/Kalimdor/ZoneAshenvale.cs +++ b/Scripts/Kalimdor/ZoneAshenvale.cs @@ -1,13 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +/* + * Copyright (C) 2012-2017 CypherCore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Framework.Constants; +using Game; using Game.AI; using Game.Entities; -using Framework.Constants; using Game.Scripting; -using Game; +using System; namespace Scripts.Kalimdor.ZoneAshenvale { diff --git a/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/NorthrendBeasts.cs b/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/NorthrendBeasts.cs index d079a988b..91e654561 100644 --- a/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/NorthrendBeasts.cs +++ b/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/NorthrendBeasts.cs @@ -399,9 +399,12 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader switch (eventId) { case Events.FireBomb: - Unit target = SelectTarget(SelectAggroTarget.Random, 0, -me.GetVehicleBase().GetCombatReach(), true); - if (target) - me.CastSpell(target, SpellIds.FireBomb); + if (me.GetVehicleBase()) + { + Unit target = SelectTarget(SelectAggroTarget.Random, 0, -me.GetVehicleBase().GetCombatReach(), true); + if (target) + me.CastSpell(target, SpellIds.FireBomb); + } _events.Repeat(TimeSpan.FromSeconds(20)); break; case Events.HeadCrack: