Core/Auras: removed caster dependency from core

Port From (https://github.com/TrinityCore/TrinityCore/commit/fccf1a8c62820004df92b9ac567ba75f7281e6e2)
This commit is contained in:
hondacrx
2021-06-22 15:01:42 -04:00
parent 1b846fa2c7
commit e98e45cf8b
15 changed files with 822 additions and 842 deletions
+9 -9
View File
@@ -568,7 +568,7 @@ namespace Game.Chat
// flat melee damage without resistence/etc reduction
if (string.IsNullOrEmpty(schoolStr))
{
attacker.DealDamage(target, damage_, null, DamageEffectType.Direct, SpellSchoolMask.Normal, null, false);
Unit.DealDamage(attacker, target, damage_, null, DamageEffectType.Direct, SpellSchoolMask.Normal, null, false);
if (target != attacker)
attacker.SendAttackStateUpdate(HitInfo.AffectsVictim, target, SpellSchoolMask.Normal, damage_, 0, 0, VictimState.Hit, 0);
return true;
@@ -579,8 +579,8 @@ namespace Game.Chat
SpellSchoolMask schoolmask = (SpellSchoolMask)(1 << school);
if (attacker.IsDamageReducedByArmor(schoolmask))
damage_ = attacker.CalcArmorReducedDamage(handler.GetPlayer(), target, damage_, null, WeaponAttackType.BaseAttack);
if (Unit.IsDamageReducedByArmor(schoolmask))
damage_ = Unit.CalcArmorReducedDamage(handler.GetPlayer(), target, damage_, null, WeaponAttackType.BaseAttack);
string spellStr = args.NextString();
@@ -588,7 +588,7 @@ namespace Game.Chat
if (string.IsNullOrEmpty(spellStr))
{
DamageInfo dmgInfo = new(attacker, target, damage_, null, schoolmask, DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack);
attacker.CalcAbsorbResist(dmgInfo);
Unit.CalcAbsorbResist(dmgInfo);
if (dmgInfo.GetDamage() == 0)
return true;
@@ -597,8 +597,8 @@ namespace Game.Chat
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);
Unit.DealDamageMods(attacker, target, ref damage_, ref absorb);
Unit.DealDamage(attacker, target, damage_, null, DamageEffectType.Direct, schoolmask, null, false);
attacker.SendAttackStateUpdate(HitInfo.AffectsVictim, target, schoolmask, damage_, absorb, resist, VictimState.Hit, 0);
return true;
}
@@ -613,9 +613,9 @@ namespace Game.Chat
if (spellInfo == null)
return false;
SpellNonMeleeDamage damageInfo = new(attacker, target, spellInfo, new Networking.Packets.SpellCastVisual(spellInfo.GetSpellXSpellVisualId(attacker), 0), spellInfo.SchoolMask);
SpellNonMeleeDamage damageInfo = new(attacker, target, spellInfo, new SpellCastVisual(spellInfo.GetSpellXSpellVisualId(attacker), 0), spellInfo.SchoolMask);
damageInfo.damage = damage_;
attacker.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
target.DealSpellDamage(damageInfo, true);
target.SendSpellNonMeleeDamageLog(damageInfo);
return true;
@@ -670,7 +670,7 @@ namespace Game.Chat
return false;
if (target.IsAlive())
handler.GetSession().GetPlayer().Kill(target);
Unit.Kill(handler.GetSession().GetPlayer(), target);
return true;
}
+2 -2
View File
@@ -3956,7 +3956,7 @@ namespace Game.Entities
break;
}
DealDamageMods(this, ref damage, ref absorb);
DealDamageMods(null, this, ref damage, ref absorb);
EnvironmentalDamageLog packet = new();
packet.Victim = GetGUID();
@@ -3965,7 +3965,7 @@ namespace Game.Entities
packet.Absorbed = (int)absorb;
packet.Resisted = (int)resist;
uint final_damage = DealDamage(this, damage, null, DamageEffectType.Self, SpellSchoolMask.Normal, null, false);
uint final_damage = DealDamage(this, this, damage, null, DamageEffectType.Self, SpellSchoolMask.Normal, null, false);
packet.LogData.Initialize(this);
SendCombatLogMessage(packet);
+49 -20
View File
@@ -667,7 +667,7 @@ namespace Game.Entities
return 0;
}
public virtual uint GetPowerIndex(PowerType powerType) { return 0; }
public float GetPowerPct(PowerType powerType) { return GetMaxPower(powerType) != 0 ? 100.0f* GetPower(powerType) / GetMaxPower(powerType) : 0.0f; }
public float GetPowerPct(PowerType powerType) { return GetMaxPower(powerType) != 0 ? 100.0f * GetPower(powerType) / GetMaxPower(powerType) : 0.0f; }
void TriggerOnPowerChangeAuras(PowerType power, int oldVal, int newVal)
{
@@ -713,27 +713,43 @@ namespace Game.Entities
}
}
public void ApplyResilience(Unit victim, ref uint damage)
public bool CanApplyResilience()
{
return !IsVehicle() && GetOwnerGUID().IsPlayer();
}
public static void ApplyResilience(Unit victim, ref int damage)
{
// player mounted on multi-passenger mount is also classified as vehicle
if (IsVehicle() || (victim.IsVehicle() && !victim.IsTypeId(TypeId.Player)))
return;
// Don't consider resilience if not in PvP - player or pet
if (!GetCharmerOrOwnerPlayerOrPlayerItself())
if (victim.IsVehicle() && !victim.IsPlayer())
return;
Unit target = null;
if (victim.IsTypeId(TypeId.Player))
if (victim.IsPlayer())
target = victim;
else if (victim.IsTypeId(TypeId.Unit) && victim.GetOwner() && victim.GetOwner().IsTypeId(TypeId.Player))
target = victim.GetOwner();
else // victim->GetTypeId() == TYPEID_UNIT
{
Unit owner = victim.GetOwner();
if (owner != null)
if (owner.IsPlayer())
target = owner;
}
if (!target)
return;
damage -= target.GetDamageReduction(damage);
damage -= (int)target.GetDamageReduction((uint)damage);
}
public int CalculateAOEAvoidance(int damage, uint schoolMask, Unit caster)
{
damage = (int)((float)damage * GetTotalAuraMultiplierByMiscMask(AuraType.ModAoeDamageAvoidance, schoolMask));
if (caster.IsCreature())
damage = (int)((float)damage * GetTotalAuraMultiplierByMiscMask(AuraType.ModCreatureAoeDamageAvoidance, schoolMask));
return damage;
}
// player or player's pet resilience (-1%)
uint GetDamageReduction(uint damage) { return GetCombatRatingDamageReduction(CombatRating.ResiliencePlayerDamage, 1.0f, 100.0f, damage); }
@@ -802,7 +818,7 @@ namespace Game.Entities
return missChance;
}
float GetUnitCriticalChance(WeaponAttackType attackType, Unit victim)
float GetUnitCriticalChanceDone(WeaponAttackType attackType)
{
float chance = 0.0f;
Player thisPlayer = ToPlayer();
@@ -830,25 +846,38 @@ namespace Game.Entities
chance += GetTotalAuraModifier(AuraType.ModCritPct);
}
}
return chance;
}
float GetUnitCriticalChanceTaken(Unit attacker, WeaponAttackType attackType, float critDone)
{
float chance = critDone;
// flat aura mods
if (attackType == WeaponAttackType.RangedAttack)
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerRangedCritChance);
chance += GetTotalAuraModifier(AuraType.ModAttackerRangedCritChance);
else
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerMeleeCritChance);
chance += GetTotalAuraModifier(AuraType.ModAttackerMeleeCritChance);
chance += GetTotalAuraModifier(AuraType.ModCritChanceVersusTargetHealth, aurEff => !victim.HealthBelowPct(aurEff.GetMiscValueB()));
chance += GetTotalAuraModifier(AuraType.ModCritChanceVersusTargetHealth, aurEff => !HealthBelowPct(aurEff.GetMiscValueB()));
chance += victim.GetTotalAuraModifier(AuraType.ModCritChanceForCaster, aurEff => aurEff.GetCasterGUID() == GetGUID());
chance += GetTotalAuraModifier(AuraType.ModCritChanceForCaster, aurEff => aurEff.GetCasterGUID() == attacker.GetGUID());
TempSummon tempSummon = ToTempSummon();
if (tempSummon)
chance += victim.GetTotalAuraModifier(AuraType.ModCritChanceForCasterPet, aurEff => aurEff.GetCasterGUID() == tempSummon.GetSummonerGUID());
TempSummon tempSummon = attacker.ToTempSummon();
if (tempSummon != null)
chance += GetTotalAuraModifier(AuraType.ModCritChanceForCasterPet, aurEff => aurEff.GetCasterGUID() == tempSummon.GetSummonerGUID());
chance += victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
chance += GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
return Math.Max(chance, 0.0f);
}
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit victim)
{
float chance = GetUnitCriticalChanceDone(attackType);
return victim.GetUnitCriticalChanceTaken(this, attackType, chance);
}
float GetUnitDodgeChance(WeaponAttackType attType, Unit victim)
{
int levelDiff = (int)(victim.GetLevelForTarget(this) - GetLevelForTarget(victim));
+72 -117
View File
@@ -46,7 +46,7 @@ namespace Game.Entities
InterruptNonMeleeSpells(false);
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat);
ProcSkillsAndAuras(null, ProcFlags.EnterCombat, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
ProcSkillsAndAuras(this, null, ProcFlags.EnterCombat, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
}
public virtual void AtExitCombat()
@@ -558,13 +558,13 @@ namespace Game.Entities
CalcDamageInfo damageInfo;
CalculateMeleeDamage(victim, 0, out damageInfo, attType);
// Send log damage message to client
DealDamageMods(victim, ref damageInfo.damage, ref damageInfo.absorb);
DealDamageMods(damageInfo.attacker, victim, ref damageInfo.damage, ref damageInfo.absorb);
SendAttackStateUpdate(damageInfo);
DealMeleeDamage(damageInfo, true);
DamageInfo dmgInfo = new(damageInfo);
ProcSkillsAndAuras(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, ProcFlagsSpellType.None, ProcFlagsSpellPhase.None, dmgInfo.GetHitMask(), null, dmgInfo, null);
ProcSkillsAndAuras(damageInfo.attacker, damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, ProcFlagsSpellType.None, ProcFlagsSpellPhase.None, dmgInfo.GetHitMask(), null, dmgInfo, null);
Log.outDebug(LogFilter.Unit, "AttackerStateUpdate: {0} attacked {1} for {2} dmg, absorbed {3}, blocked {4}, resisted {5}.",
GetGUID().ToString(), victim.GetGUID().ToString(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
}
@@ -756,71 +756,6 @@ namespace Game.Entities
}
}
public void SetInCombatState(bool PvP, Unit enemy = null)
{
// only alive units can be in combat
if (!IsAlive())
return;
if (PvP)
{
combatTimer = 5000;
Player me = ToPlayer();
if (me)
me.EnablePvpRules(true);
}
if (IsInCombat() || HasUnitState(UnitState.Evade))
return;
AddUnitFlag(UnitFlags.InCombat);
Creature creature = ToCreature();
if (creature != null)
{
// Set home position at place of engaging combat for escorted creatures
if ((IsAIEnabled && creature.GetAI().IsEscorted()) || GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint ||
GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Point)
creature.SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), Orientation);
if (enemy != null)
{
if (IsAIEnabled)
creature.GetAI().JustEngagedWith(enemy);
if (creature.GetFormation() != null)
creature.GetFormation().MemberEngagingTarget(creature, enemy);
}
if (IsPet())
{
UpdateSpeed(UnitMoveType.Run);
UpdateSpeed(UnitMoveType.Swim);
UpdateSpeed(UnitMoveType.Flight);
}
if (!creature.GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.MountedCombatAllowed))
Dismount();
}
foreach (var unit in m_Controlled)
unit.SetInCombatState(PvP, enemy);
foreach (var pair in GetAppliedAuras())
{
AuraApplication aurApp = pair.Value;
aurApp.GetBase().CallScriptEnterLeaveCombatHandlers(aurApp, true);
}
Spell spell = GetCurrentSpell(CurrentSpellTypes.Generic);
if (spell != null)
if (spell.GetState() == SpellState.Preparing && spell.m_spellInfo.HasAttribute(SpellAttr0.CantUsedInCombat) && spell.m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.Combat))
InterruptNonMeleeSpells(false);
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat);
ProcSkillsAndAuras(enemy, ProcFlags.EnterCombat, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
}
internal void SendCombatLogMessage(CombatLogServerPacket combatLog)
{
CombatLogSender combatLogSender = new(combatLog);
@@ -837,14 +772,20 @@ namespace Game.Entities
return !m_threatManager.IsThreatListEmpty();
}
public void Kill(Unit victim, bool durabilityLoss = true, bool skipSettingDeathState = false)
public static void Kill(Unit attacker, Unit victim, bool durabilityLoss = true, bool skipSettingDeathState = false)
{
// Prevent killing unit twice (and giving reward from kill twice)
if (victim.GetHealth() == 0)
return;
if (attacker != null && !attacker.IsInMap(victim))
attacker = null;
// find player: owner of controlled `this` or `this` itself maybe
Player player = GetCharmerOrOwnerPlayerOrPlayerItself();
Player player = null;
if (attacker != null)
player = attacker.GetCharmerOrOwnerPlayerOrPlayerItself();
Creature creature = victim.ToCreature();
bool isRewardAllowed = true;
@@ -911,7 +852,7 @@ namespace Game.Entities
loot.Clear();
uint lootid = creature.GetCreatureTemplate().LootId;
if (lootid != 0)
loot.FillLoot(lootid, LootStorage.Creature, looter, false, false, creature.GetLootMode(), GetMap().GetDifficultyLootItemContext());
loot.FillLoot(lootid, LootStorage.Creature, looter, false, false, creature.GetLootMode(), creature.GetMap().GetDifficultyLootItemContext());
if (creature.GetLootMode() > 0)
loot.GenerateMoneyLoot(creature.GetCreatureTemplate().MinGold, creature.GetCreatureTemplate().MaxGold);
@@ -933,24 +874,28 @@ namespace Game.Entities
}
// Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
if (IsPet() || IsTotem())
if (attacker != null && (attacker.IsPet() || attacker.IsTotem()))
{
// proc only once for victim
Unit owner = GetOwner();
Unit owner = attacker.GetOwner();
if (owner != null)
owner.ProcSkillsAndAuras(victim, ProcFlags.Kill, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
ProcSkillsAndAuras(owner, victim, ProcFlags.Kill, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
}
if (!victim.IsCritter())
ProcSkillsAndAuras(victim, ProcFlags.Kill, ProcFlags.Killed, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
ProcSkillsAndAuras(attacker, victim, ProcFlags.Kill, ProcFlags.Killed, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
// Proc auras on death - must be before aura/combat remove
victim.ProcSkillsAndAuras(victim, ProcFlags.None, ProcFlags.Death, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
ProcSkillsAndAuras(victim, victim, ProcFlags.None, ProcFlags.Death, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
if (player != null)
player.UpdateCriteria(CriteriaTypes.GetKillingBlows, 1, 0, 0, victim);
if (attacker != null)
{
Player killerPlayer = attacker.GetCharmerOrOwnerPlayerOrPlayerItself();
if (killerPlayer != null)
killerPlayer.UpdateCriteria(CriteriaTypes.GetKillingBlows, 1, 0, 0, victim);
}
if (!skipSettingDeathState)
{
@@ -985,11 +930,11 @@ namespace Game.Entities
// Durability loss is calculated more accurately again for each item in Player.DurabilityLoss
plrVictim.DurabilityLossAll(baseLoss, false);
// durability lost message
SendDurabilityLoss(plrVictim, loss);
plrVictim.SendDurabilityLoss(plrVictim, loss);
}
// Call KilledUnit for creatures
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
ToCreature().GetAI().KilledUnit(victim);
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled)
attacker.ToCreature().GetAI().KilledUnit(victim);
// last damage from non duel opponent or opponent controlled creature
if (plrVictim.duel != null)
@@ -1015,12 +960,12 @@ namespace Game.Entities
}
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
if (IsTypeId(TypeId.Unit) && IsAIEnabled)
ToCreature().GetAI().KilledUnit(victim);
if (attacker != null && attacker.IsCreature() && attacker.IsAIEnabled)
attacker.ToCreature().GetAI().KilledUnit(victim);
// Call creature just died function
if (creature.IsAIEnabled)
creature.GetAI().JustDied(this);
creature.GetAI().JustDied(attacker);
TempSummon summon = creature.ToTempSummon();
if (summon != null)
@@ -1028,22 +973,21 @@ namespace Game.Entities
Unit summoner = summon.GetSummoner();
if (summoner != null)
if (summoner.IsTypeId(TypeId.Unit) && summoner.IsAIEnabled)
summoner.ToCreature().GetAI().SummonedCreatureDies(creature, this);
summoner.ToCreature().GetAI().SummonedCreatureDies(creature, attacker);
}
// Dungeon specific stuff, only applies to players killing creatures
if (creature.GetInstanceId() != 0)
{
Map instanceMap = creature.GetMap();
Player creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
// @todo do instance binding anyway if the charmer/owner is offline
if (instanceMap.IsDungeon() && (creditedPlayer || this == victim))
/// @todo do instance binding anyway if the charmer/owner is offline
if (instanceMap.IsDungeon() && ((attacker != null && attacker.GetCharmerOrOwnerPlayerOrPlayerItself() != null) || attacker == victim))
{
if (instanceMap.IsRaidOrHeroicDungeon())
{
if (creature.GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.InstanceBind))
((InstanceMap)instanceMap).PermBindAllPlayers();
instanceMap.ToInstanceMap().PermBindAllPlayers();
}
else
{
@@ -1061,7 +1005,7 @@ namespace Game.Entities
// outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
// handle player kill only if not suicide (spirit of redemption for example)
if (player != null && this != victim)
if (player != null && attacker != victim)
{
OutdoorPvP pvp = player.GetOutdoorPvP();
if (pvp != null)
@@ -1087,35 +1031,44 @@ namespace Game.Entities
}
// achievement stuff
if (victim.IsTypeId(TypeId.Player))
if (attacker != null && victim.IsPlayer())
{
if (IsTypeId(TypeId.Unit))
victim.ToPlayer().UpdateCriteria(CriteriaTypes.KilledByCreature, GetEntry());
else if (IsTypeId(TypeId.Player) && victim != this)
victim.ToPlayer().UpdateCriteria(CriteriaTypes.KilledByPlayer, 1, (ulong)ToPlayer().GetTeam());
if (attacker.IsCreature())
victim.ToPlayer().UpdateCriteria(CriteriaTypes.KilledByCreature, attacker.GetEntry());
else if (attacker.IsPlayer() && victim != attacker)
victim.ToPlayer().UpdateCriteria(CriteriaTypes.KilledByPlayer, 1, (ulong)attacker.ToPlayer().GetTeam());
}
// Hook for OnPVPKill Event
Player killerPlr = ToPlayer();
Creature killerCre = ToCreature();
if (killerPlr != null)
if (attacker != null)
{
Player killedPlr = victim.ToPlayer();
Creature killedCre = victim.ToCreature();
if (killedPlr != null)
Global.ScriptMgr.OnPVPKill(killerPlr, killedPlr);
else if (killedCre != null)
Global.ScriptMgr.OnCreatureKill(killerPlr, killedCre);
}
else if (killerCre != null)
{
Player killed = victim.ToPlayer();
if (killed != null)
Global.ScriptMgr.OnPlayerKilledByCreature(killerCre, killed);
Player killerPlr = attacker.ToPlayer();
if (killerPlr != null)
{
Player killedPlr = victim.ToPlayer();
if (killedPlr != null)
Global.ScriptMgr.OnPVPKill(killerPlr, killedPlr);
else
{
Creature killedCre = victim.ToCreature();
if (killedCre != null)
Global.ScriptMgr.OnCreatureKill(killerPlr, killedCre);
}
}
else
{
Creature killerCre = attacker.ToCreature();
if (killerCre != null)
{
Player killed = victim.ToPlayer();
if (killed != null)
Global.ScriptMgr.OnPlayerKilledByCreature(killerCre, killed);
}
}
}
}
public void KillSelf(bool durabilityLoss = true, bool skipSettingDeathState = false) { Kill(this, durabilityLoss, skipSettingDeathState); }
public void KillSelf(bool durabilityLoss = true, bool skipSettingDeathState = false) { Kill(this, this, durabilityLoss, skipSettingDeathState); }
public virtual bool CanUseAttackType(WeaponAttackType attacktype)
{
@@ -1289,11 +1242,13 @@ namespace Game.Entities
if (!damageInfo.HitInfo.HasAnyFlag(HitInfo.Miss))
damageInfo.HitInfo |= HitInfo.AffectsVictim;
uint resilienceReduction = damageInfo.damage;
ApplyResilience(victim, ref resilienceReduction);
resilienceReduction = damageInfo.damage - resilienceReduction;
damageInfo.damage -= resilienceReduction;
damageInfo.cleanDamage += resilienceReduction;
int resilienceReduction = (int)damageInfo.damage;
if (CanApplyResilience())
ApplyResilience(victim, ref resilienceReduction);
resilienceReduction = (int)damageInfo.damage - resilienceReduction;
damageInfo.damage -= (uint)resilienceReduction;
damageInfo.cleanDamage += (uint)resilienceReduction;
// Calculate absorb resist
if (damageInfo.damage > 0)
@@ -1326,7 +1281,7 @@ namespace Game.Entities
int miss_chance = (int)(MeleeSpellMissChance(victim, attType, null) * 100.0f);
// Critical hit chance
int crit_chance = (int)(GetUnitCriticalChance(attType, victim) + GetTotalAuraModifier(AuraType.ModAutoAttackCritChance) * 100.0f);
int crit_chance = (int)((GetUnitCriticalChanceAgainst(attType, victim) + GetTotalAuraModifier(AuraType.ModAutoAttackCritChance)) * 100.0f);
int dodge_chance = (int)(GetUnitDodgeChance(attType, victim) * 100.0f);
int block_chance = (int)(GetUnitBlockChance(attType, victim) * 100.0f);
+244 -202
View File
@@ -105,6 +105,7 @@ namespace Game.Entities
}
int DoneTotal = 0;
float DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype);
// Done fixed damage bonus auras
int DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto.GetSchoolMask());
@@ -141,27 +142,21 @@ namespace Game.Entities
float coeff = effect.BonusCoefficient;
if (DoneAdvertisedBenefit != 0)
{
Player modOwner = GetSpellModOwner();
if (modOwner)
Player modOwner1 = GetSpellModOwner();
if (modOwner1)
{
coeff *= 100.0f;
modOwner.ApplySpellMod(spellProto, SpellModOp.BonusCoefficient, ref coeff);
modOwner1.ApplySpellMod(spellProto, SpellModOp.BonusCoefficient, ref coeff);
coeff /= 100.0f;
}
DoneTotal += (int)(DoneAdvertisedBenefit * coeff * stack);
}
// Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura.HandleAuraSpecificMods.
float tmpDamage = ((int)pdamage + DoneTotal) * (damagetype == DamageEffectType.DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype));
float tmpDamage = (float)((int)pdamage + DoneTotal) * DoneTotalMod;
// apply spellmod to Done damage (flat and pct)
Player _modOwner = GetSpellModOwner();
if (_modOwner)
{
if (damagetype == DamageEffectType.DOT)
_modOwner.ApplySpellMod(spellProto, SpellModOp.PeriodicHealingAndDamage, ref tmpDamage);
else
_modOwner.ApplySpellMod(spellProto, SpellModOp.HealingAndDamage, ref tmpDamage);
}
if (_modOwner != null)
_modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref tmpDamage);
return (uint)Math.Max(tmpDamage, 0.0f);
}
@@ -171,13 +166,21 @@ namespace Game.Entities
if (spellProto == null || !victim || damagetype == DamageEffectType.Direct)
return 1.0f;
// Some spells don't benefit from done mods
if (spellProto.HasAttribute(SpellAttr3.NoDoneBonus))
return 1.0f;
// Some spells don't benefit from pct done mods
if (spellProto.HasAttribute(SpellAttr6.IgnoreCasterDamageModifiers))
return 1.0f;
// For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone.
if (IsTypeId(TypeId.Unit) && IsTotem())
return 1.0f;
// For totems get damage bonus from owner
if (IsCreature() && IsTotem())
{
Unit owner = GetOwner();
if (owner != null)
return owner.SpellDamagePctDone(victim, spellProto, damagetype);
}
// Done total percent damage auras
float DoneTotalMod = 1.0f;
@@ -392,19 +395,23 @@ namespace Game.Entities
return GetTotalAuraModifierByMiscMask(AuraType.ModHealing, (int)schoolMask);
}
public int SpellCriticalHealingBonus(SpellInfo spellProto, int damage, Unit victim)
public static int SpellCriticalHealingBonus(Unit caster, SpellInfo spellProto, int damage, Unit victim)
{
// Calculate critical bonus
int crit_bonus = damage;
// adds additional damage to critBonus (from talents)
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellProto, SpellModOp.CritDamageAndHealing, ref crit_bonus);
if (caster != null)
{
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellProto, SpellModOp.CritDamageAndHealing, ref crit_bonus);
}
damage += crit_bonus;
damage = (int)(damage * GetTotalAuraMultiplier(AuraType.ModCriticalHealingAmount));
if (caster != null)
damage = (int)(damage * caster.GetTotalAuraMultiplier(AuraType.ModCriticalHealingAmount));
return damage;
}
@@ -424,19 +431,20 @@ namespace Game.Entities
return healamount;
int DoneTotal = 0;
float DoneTotalMod = SpellHealingPctDone(victim, spellProto);
// done scripted mod (take it from owner)
Unit owner1 = GetOwner() ?? this;
var mOverrideClassScript = owner1.GetAuraEffectsByType(AuraType.OverrideClassScripts);
foreach (var eff in mOverrideClassScript)
foreach (var aurEff in mOverrideClassScript)
{
if (!eff.IsAffectingSpell(spellProto))
if (!aurEff.IsAffectingSpell(spellProto))
continue;
switch (eff.GetMiscValue())
switch (aurEff.GetMiscValue())
{
case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
DoneTotal += eff.GetAmount();
DoneTotal += aurEff.GetAmount();
break;
default:
break;
@@ -491,25 +499,32 @@ namespace Game.Entities
DoneTotal = 0;
}
// use float as more appropriate for negative values and percent applying
float heal = (healamount + DoneTotal) * (damagetype == DamageEffectType.DOT ? 1.0f : SpellHealingPctDone(victim, spellProto));
float heal = (float)((int)healamount + DoneTotal) * DoneTotalMod;
// apply spellmod to Done amount
Player _modOwner = GetSpellModOwner();
if (_modOwner)
{
if (damagetype == DamageEffectType.DOT)
_modOwner.ApplySpellMod(spellProto, SpellModOp.PeriodicHealingAndDamage, ref heal);
else
_modOwner.ApplySpellMod(spellProto, SpellModOp.HealingAndDamage, ref heal);
}
_modOwner.ApplySpellMod(spellProto, damagetype == DamageEffectType.DOT ? SpellModOp.PeriodicHealingAndDamage : SpellModOp.HealingAndDamage, ref heal);
return (uint)Math.Max(heal, 0.0f);
}
public float SpellHealingPctDone(Unit victim, SpellInfo spellProto)
{
// For totems pct done mods are calculated when its calculation is run on the player in SpellHealingBonusDone.
if (IsTypeId(TypeId.Unit) && IsTotem())
// For totems get healing bonus from owner
if (IsCreature() && IsTotem())
{
Unit owner = GetOwner();
if (owner != null)
return owner.SpellHealingPctDone(victim, spellProto);
}
// Some spells don't benefit from done mods
if (spellProto.HasAttribute(SpellAttr3.NoDoneBonus))
return 1.0f;
// Some spells don't benefit from done mods
if (spellProto.HasAttribute(SpellAttr6.IgnoreHealingModifiers))
return 1.0f;
// No bonus healing for potion spells
@@ -647,40 +662,19 @@ namespace Game.Entities
return (uint)Math.Max(heal, 0.0f);
}
public bool IsSpellCrit(Unit victim, Spell spell, AuraEffect aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
public float SpellCritChanceDone(SpellInfo spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{
return RandomHelper.randChance(GetUnitSpellCriticalChance(victim, spell, aurEff, schoolMask, attackType));
}
public float GetUnitSpellCriticalChance(Unit victim, Spell spell, AuraEffect aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{
SpellInfo spellProto = spell?.GetSpellInfo() ?? aurEff?.GetSpellInfo();
//! Mobs can't crit with spells. Player Totems can
//! Fire Elemental (from totem) can too - but this part is a hack and needs more research
if (GetGUID().IsCreatureOrVehicle() && !(IsTotem() && GetOwnerGUID().IsPlayer()) && GetEntry() != 15438)
//! Mobs can't crit with spells. (Except player controlled)
if (IsCreature() && !GetSpellModOwner())
return 0.0f;
// not critting spell
if (spellProto.HasAttribute(SpellAttr2.CantCrit))
if (spellInfo.HasAttribute(SpellAttr2.CantCrit))
return 0.0f;
float crit_chance = 0.0f;
switch (spellProto.DmgClass)
switch (spellInfo.DmgClass)
{
case SpellDmgClass.None:
// We need more spells to find a general way (if there is any)
switch (spellProto.Id)
{
case 379: // Earth Shield
case 33778: // Lifebloom Final Bloom
case 64844: // Divine Hymn
case 71607: // Item - Bauble of True Blood 10m
case 71646: // Item - Bauble of True Blood 25m
break;
default:
return 0.0f;
}
goto case SpellDmgClass.Magic;
case SpellDmgClass.Magic:
{
if (schoolMask.HasAnyFlag(SpellSchoolMask.Normal))
@@ -690,26 +684,58 @@ namespace Game.Entities
crit_chance = ToPlayer().m_activePlayerData.SpellCritPercentage;
else
crit_chance = BaseSpellCritChance;
break;
}
case SpellDmgClass.Melee:
case SpellDmgClass.Ranged:
crit_chance += GetUnitCriticalChanceDone(attackType);
break;
case SpellDmgClass.None:
default:
return 0f;
}
// percent done
// only players use intelligence for critical chance computations
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.CritChance, ref crit_chance);
return Math.Max(crit_chance, 0.0f);
}
public float SpellCritChanceTaken(Unit caster, Spell spell, AuraEffect aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType = WeaponAttackType.BaseAttack)
{
SpellInfo spellInfo = spell != null ? spell.GetSpellInfo() : aurEff.GetSpellInfo();
// not critting spell
if (spellInfo.HasAttribute(SpellAttr2.CantCrit))
return 0.0f;
float crit_chance = doneChance;
switch (spellInfo.DmgClass)
{
case SpellDmgClass.Magic:
{
// taken
if (victim)
if (!spellInfo.IsPositive())
{
// Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
crit_chance += GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
}
if (caster)
{
if (!spellProto.IsPositive())
{
// Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
crit_chance += victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance);
}
// scripted (increase crit chance ... against ... target by x%
var mOverrideClassScript = GetAuraEffectsByType(AuraType.OverrideClassScripts);
var mOverrideClassScript = caster.GetAuraEffectsByType(AuraType.OverrideClassScripts);
foreach (var eff in mOverrideClassScript)
{
if (!eff.IsAffectingSpell(spellProto))
if (!eff.IsAffectingSpell(spellInfo))
continue;
switch (eff.GetMiscValue())
{
case 911: // Shatter
if (victim.HasAuraState(AuraStateType.Frozen, spellProto, this))
if (HasAuraState(AuraStateType.Frozen, spellInfo, this))
{
crit_chance *= 1.5f;
AuraEffect _eff = eff.GetBase().GetEffect(1);
@@ -722,19 +748,19 @@ namespace Game.Entities
}
}
// Custom crit by class
switch (spellProto.SpellFamilyName)
switch (spellInfo.SpellFamilyName)
{
case SpellFamilyNames.Rogue:
// Shiv-applied poisons can't crit
if (FindCurrentSpellBySpellId(5938) != null)
if (caster.FindCurrentSpellBySpellId(5938) != null)
crit_chance = 0.0f;
break;
case SpellFamilyNames.Shaman:
// Lava Burst
if (spellProto.SpellFamilyFlags[1].HasAnyFlag(0x00001000u))
if (spellInfo.SpellFamilyFlags[1].HasAnyFlag(0x00001000u))
{
if (victim.GetAuraEffect(AuraType.PeriodicDamage, SpellFamilyNames.Shaman, new FlagArray128(0x10000000, 0, 0), GetGUID()) != null)
if (victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance) > -100)
if (GetAuraEffect(AuraType.PeriodicDamage, SpellFamilyNames.Shaman, new FlagArray128(0x10000000, 0, 0), caster.GetGUID()) != null)
if (GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance) > -100)
return 100.0f;
break;
}
@@ -742,9 +768,9 @@ namespace Game.Entities
}
// Spell crit suppression
if (victim.GetTypeId() == TypeId.Unit)
if (IsCreature())
{
int levelDiff = (int)(victim.GetLevelForTarget(this) - GetLevel());
int levelDiff = (int)(GetLevelForTarget(this) - caster.GetLevel());
crit_chance -= levelDiff * 1.0f;
}
}
@@ -753,38 +779,34 @@ namespace Game.Entities
case SpellDmgClass.Melee:
case SpellDmgClass.Ranged:
{
if (victim)
crit_chance += GetUnitCriticalChance(attackType, victim);
if (caster != null)
crit_chance += GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
break;
}
case SpellDmgClass.None:
default:
return 0.0f;
return 0f;
}
// percent done
// only players use intelligence for critical chance computations
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellProto, SpellModOp.CritChance, ref crit_chance);
// for this types the bonus was already added in GetUnitCriticalChance, do not add twice
if (spellProto.DmgClass != SpellDmgClass.Melee && spellProto.DmgClass != SpellDmgClass.Ranged)
if (caster != null && spellInfo.DmgClass != SpellDmgClass.Melee && spellInfo.DmgClass != SpellDmgClass.Ranged)
{
crit_chance += victim.GetTotalAuraModifier(AuraType.ModCritChanceForCasterWithAbilities, aurEff => aurEff.GetCasterGUID() == GetGUID() && aurEff.IsAffectingSpell(spellProto));
crit_chance += GetTotalAuraModifier(AuraType.ModCritChanceForCasterWithAbilities, aurEff => aurEff.GetCasterGUID() == caster.GetGUID() && aurEff.IsAffectingSpell(spellInfo));
crit_chance += victim.GetTotalAuraModifier(AuraType.ModCritChanceForCaster, aurEff => aurEff.GetCasterGUID() != GetGUID());
crit_chance += GetTotalAuraModifier(AuraType.ModCritChanceForCaster, aurEff => aurEff.GetCasterGUID() == caster.GetGUID());
crit_chance += GetTotalAuraModifier(AuraType.ModCritChanceVersusTargetHealth, aurEff => !victim.HealthBelowPct(aurEff.GetMiscValueB()));
crit_chance += caster.GetTotalAuraModifier(AuraType.ModCritChanceVersusTargetHealth, aurEff => !HealthBelowPct(aurEff.GetMiscValueB()));
TempSummon tempSummon = ToTempSummon();
TempSummon tempSummon = caster.ToTempSummon();
if (tempSummon != null)
crit_chance += victim.GetTotalAuraModifier(AuraType.ModCritChanceForCasterPet, aurEff => aurEff.GetCasterGUID() == tempSummon.GetSummonerGUID());
crit_chance += GetTotalAuraModifier(AuraType.ModCritChanceForCasterPet, aurEff => aurEff.GetCasterGUID() == tempSummon.GetSummonerGUID());
}
// call script handlers
if (spell)
spell.CallScriptCalcCritChanceHandlers(victim, ref crit_chance);
spell.CallScriptCalcCritChanceHandlers(this, ref crit_chance);
else
aurEff.GetBase().CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff.GetBase().GetApplicationOfTarget(victim.GetGUID()), victim, ref crit_chance);
aurEff.GetBase().CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff.GetBase().GetApplicationOfTarget(GetGUID()), this, ref crit_chance);
return Math.Max(crit_chance, 0.0f);
}
@@ -1752,16 +1774,17 @@ namespace Game.Entities
return false;
}
public void ProcSkillsAndAuras(Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
{
WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack;
if (typeMaskActor != 0)
ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
if (typeMaskActor != 0 && actor != null)
actor.ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
if (typeMaskActionTarget != 0 && actionTarget)
actionTarget.ProcSkillsAndReactives(true, this, typeMaskActionTarget, hitMask, attType);
actionTarget.ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
TriggerAurasProcOnEvent(null, null, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
if (actor != null)
actor.TriggerAurasProcOnEvent(null, null, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
}
void ProcSkillsAndReactives(bool isVictim, Unit procTarget, ProcFlags typeMask, ProcFlagsHit hitMask, WeaponAttackType attType)
@@ -2125,30 +2148,33 @@ namespace Game.Entities
return false;
}
public uint SpellCriticalDamageBonus(SpellInfo spellProto, uint damage, Unit victim = null)
public static uint SpellCriticalDamageBonus(Unit caster, SpellInfo spellProto, uint damage, Unit victim = null)
{
// Calculate critical bonus
int crit_bonus = (int)damage * 2;
float crit_mod = 0.0f;
crit_mod += (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellProto.GetSchoolMask()) - 1.0f) * 100;
if (crit_bonus != 0)
MathFunctions.AddPct(ref crit_bonus, (int)crit_mod);
MathFunctions.AddPct(ref crit_bonus, victim.GetTotalAuraModifier(AuraType.ModCriticalDamageTakenFromCaster, aurEff =>
if (caster != null)
{
return aurEff.GetCasterGUID() == GetGUID();
}));
crit_mod += (caster.GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellProto.GetSchoolMask()) - 1.0f) * 100;
crit_bonus -= (int)damage;
if (crit_bonus != 0)
MathFunctions.AddPct(ref crit_bonus, (int)crit_mod);
// adds additional damage to critBonus (from talents)
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellProto, SpellModOp.CritDamageAndHealing, ref crit_bonus);
MathFunctions.AddPct(ref crit_bonus, victim.GetTotalAuraModifier(AuraType.ModCriticalDamageTakenFromCaster, aurEff =>
{
return aurEff.GetCasterGUID() == caster.GetGUID();
}));
crit_bonus += (int)damage;
crit_bonus -= (int)damage;
// adds additional damage to critBonus (from talents)
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellProto, SpellModOp.CritDamageAndHealing, ref crit_bonus);
crit_bonus += (int)damage;
}
return (uint)crit_bonus;
}
@@ -2197,46 +2223,53 @@ namespace Game.Entities
return spellInfo.GetSpellSpecific() == SpellSpecificType.MagePolymorph;
}
public void DealHeal(HealInfo healInfo)
public static void DealHeal(HealInfo healInfo)
{
int gain = 0;
Unit healer = healInfo.GetHealer();
Unit victim = healInfo.GetTarget();
uint addhealth = healInfo.GetHeal();
if (victim.IsAIEnabled)
victim.GetAI().HealReceived(this, addhealth);
if (healer)
{
if (victim.IsAIEnabled)
victim.GetAI().HealReceived(healer, addhealth);
if (IsAIEnabled)
GetAI().HealDone(victim, addhealth);
if (healer.IsAIEnabled)
healer.GetAI().HealDone(victim, addhealth);
}
if (addhealth != 0)
gain = (int)victim.ModifyHealth(addhealth);
// Hook for OnHeal Event
uint tempGain = (uint)gain;
Global.ScriptMgr.OnHeal(this, victim, ref tempGain);
Global.ScriptMgr.OnHeal(healer, victim, ref tempGain);
gain = (int)tempGain;
Unit unit = this;
Unit unit = healer;
if (healer != null && healer.IsCreature() && healer.IsTotem())
unit = healer.GetOwner();
if (IsTypeId(TypeId.Unit) && IsTotem())
unit = GetOwner();
Player player = unit.ToPlayer();
if (player != null)
if (unit)
{
Battleground bg = player.GetBattleground();
if (bg)
bg.UpdatePlayerScore(player, ScoreType.HealingDone, (uint)gain);
Player bgPlayer = unit.ToPlayer();
if (bgPlayer != null)
{
Battleground bg = bgPlayer.GetBattleground();
if (bg)
bg.UpdatePlayerScore(bgPlayer, ScoreType.HealingDone, (uint)gain);
// use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
if (gain != 0)
player.UpdateCriteria(CriteriaTypes.HealingDone, (uint)gain, 0, 0, victim);
// use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
if (gain != 0)
bgPlayer.UpdateCriteria(CriteriaTypes.HealingDone, (uint)gain, 0, 0, victim);
player.UpdateCriteria(CriteriaTypes.HighestHealCasted, addhealth);
bgPlayer.UpdateCriteria(CriteriaTypes.HighestHealCasted, addhealth);
}
}
if ((player = victim.ToPlayer()) != null)
Player player = victim.ToPlayer();
if (player != null)
{
player.UpdateCriteria(CriteriaTypes.TotalHealingReceived, (uint)gain);
player.UpdateCriteria(CriteriaTypes.HighestHealingReceived, addhealth);
@@ -2267,8 +2300,8 @@ namespace Game.Entities
{
// calculate heal absorb and reduce healing
CalcHealAbsorb(healInfo);
DealHeal(healInfo);
SendHealSpellLog(healInfo, critical);
return healInfo.GetEffectiveHeal();
}
@@ -2329,84 +2362,90 @@ namespace Game.Entities
SpellSchoolMask damageSchoolMask = damageInfo.schoolMask;
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
damage = (int)CalcArmorReducedDamage(damageInfo.attacker, victim, (uint)damage, spellInfo, attackType);
bool blocked = false;
// Per-school calc
switch (spellInfo.DmgClass)
// Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
if (!spellInfo.HasAttribute(SpellAttr4.FixedDamage))
{
// Melee and Ranged Spells
case SpellDmgClass.Ranged:
case SpellDmgClass.Melee:
{
// Physical Damage
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal))
if (IsDamageReducedByArmor(damageSchoolMask, spellInfo))
damage = (int)CalcArmorReducedDamage(damageInfo.attacker, victim, (uint)damage, spellInfo, attackType);
bool blocked = false;
// Per-school calc
switch (spellInfo.DmgClass)
{
// Melee and Ranged Spells
case SpellDmgClass.Ranged:
case SpellDmgClass.Melee:
{
// Spells with this attribute were already calculated in MeleeSpellHitResult
if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell))
// Physical Damage
if (damageSchoolMask.HasAnyFlag(SpellSchoolMask.Normal))
{
// Get blocked status
blocked = IsSpellBlocked(victim, spellInfo, attackType);
// Spells with this attribute were already calculated in MeleeSpellHitResult
if (!spellInfo.HasAttribute(SpellAttr3.BlockableSpell))
{
// Get blocked status
blocked = IsSpellBlocked(victim, spellInfo, attackType);
}
}
}
if (crit)
{
damageInfo.HitInfo |= HitInfo.CriticalHit;
// Calculate crit bonus
uint crit_bonus = (uint)damage;
// Apply crit_damage bonus for melee spells
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus);
damage += (int)crit_bonus;
// Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100;
if (critPctDamageMod != 0)
MathFunctions.AddPct(ref damage, (int)critPctDamageMod);
}
// Spell weapon based damage CAN BE crit & blocked at same time
if (blocked)
{
// double blocked amount if block is critical
float value = victim.GetBlockPercent(GetLevel());
if (victim.IsBlockCritical())
value *= 2; // double blocked percent
damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value);
if (damage <= damageInfo.blocked)
if (crit)
{
damageInfo.blocked = (uint)damage;
damageInfo.fullBlock = true;
damageInfo.HitInfo |= HitInfo.CriticalHit;
// Calculate crit bonus
uint crit_bonus = (uint)damage;
// Apply crit_damage bonus for melee spells
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.CritDamageAndHealing, ref crit_bonus);
damage += (int)crit_bonus;
// Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(AuraType.ModCritDamageBonus, (uint)spellInfo.GetSchoolMask()) - 1.0f) * 100;
if (critPctDamageMod != 0)
MathFunctions.AddPct(ref damage, (int)critPctDamageMod);
}
damage -= (int)damageInfo.blocked;
// Spell weapon based damage CAN BE crit & blocked at same time
if (blocked)
{
// double blocked amount if block is critical
float value = victim.GetBlockPercent(GetLevel());
if (victim.IsBlockCritical())
value *= 2; // double blocked percent
damageInfo.blocked = (uint)MathFunctions.CalculatePct(damage, value);
if (damage <= damageInfo.blocked)
{
damageInfo.blocked = (uint)damage;
damageInfo.fullBlock = true;
}
damage -= (int)damageInfo.blocked;
}
if (CanApplyResilience())
ApplyResilience(victim, ref damage);
break;
}
uint dmg = (uint)damage;
ApplyResilience(victim, ref dmg);
damage = (int)dmg;
break;
}
// Magical Attacks
case SpellDmgClass.None:
case SpellDmgClass.Magic:
{
// If crit add critical bonus
if (crit)
// Magical Attacks
case SpellDmgClass.None:
case SpellDmgClass.Magic:
{
damageInfo.HitInfo |= HitInfo.CriticalHit;
damage = (int)SpellCriticalDamageBonus(spellInfo, (uint)damage, victim);
// If crit add critical bonus
if (crit)
{
damageInfo.HitInfo |= HitInfo.CriticalHit;
damage = (int)SpellCriticalDamageBonus(this, spellInfo, (uint)damage, victim);
}
if (CanApplyResilience())
ApplyResilience(victim, ref damage);
break;
}
uint dmg = (uint)damage;
ApplyResilience(victim, ref dmg);
damage = (int)dmg;
default:
break;
}
default:
break;
}
}
// Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
@@ -2431,6 +2470,7 @@ namespace Game.Entities
damageInfo.damage = dmgInfo.GetDamage();
}
public void DealSpellDamage(SpellNonMeleeDamage damageInfo, bool durabilityLoss)
{
if (damageInfo == null)
@@ -2451,7 +2491,7 @@ namespace Game.Entities
// Call default DealDamage
CleanDamage cleanDamage = new(damageInfo.cleanDamage, damageInfo.absorb, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
DealDamage(victim, damageInfo.damage, cleanDamage, DamageEffectType.SpellDirect, damageInfo.schoolMask, damageInfo.Spell, durabilityLoss);
DealDamage(this, victim, damageInfo.damage, cleanDamage, DamageEffectType.SpellDirect, damageInfo.schoolMask, damageInfo.Spell, durabilityLoss);
}
public void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage log)
@@ -4181,6 +4221,7 @@ namespace Game.Entities
else
aurApp._HandleEffect(effIndex, true);
}
// handles effects of aura application
// should be done after registering aura in lists
public void _ApplyAura(AuraApplication aurApp, uint effMask)
@@ -4219,7 +4260,6 @@ namespace Game.Entities
if (aurApp.HasRemoveMode())
return;
aura.HandleAuraSpecificPeriodics(aurApp, caster);
aura.HandleAuraSpecificMods(aurApp, caster, true, false);
// apply effects of the aura
@@ -4229,6 +4269,7 @@ namespace Game.Entities
aurApp._HandleEffect(i, true);
}
}
public void _AddAura(UnitAura aura, Unit caster)
{
Cypher.Assert(!m_cleanupDone);
@@ -4261,6 +4302,7 @@ namespace Game.Entities
}
}
}
public Aura _TryStackingOrRefreshingExistingAura(SpellInfo newAura, uint effMask, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, uint castItemId = 0, int castItemLevel = -1)
{
Cypher.Assert(!casterGUID.IsEmpty() || caster);
+281 -260
View File
@@ -2388,11 +2388,12 @@ namespace Game.Entities
RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.ChannelObjects), index);
}
public bool IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo spellInfo = null, sbyte effIndex = -1)
public static bool IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo spellInfo = null, sbyte effIndex = -1)
{
// only physical spells damage gets reduced by armor
if ((schoolMask & SpellSchoolMask.Normal) == 0)
return false;
if (spellInfo != null)
{
// there are spells with no specific attribute but they have "ignores armor" in tooltip
@@ -2411,6 +2412,7 @@ namespace Game.Entities
}
}
}
return true;
}
@@ -2542,7 +2544,7 @@ namespace Game.Entities
void StartReactiveTimer(ReactiveType reactive) { m_reactiveTimer[reactive] = 4000; }
void DealDamageMods(Unit victim, ref uint damage)
public static void DealDamageMods(Unit attacker, Unit victim, ref uint damage)
{
if (victim == null || !victim.IsAlive() || victim.HasUnitState(UnitState.InFlight)
|| (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsInEvadeMode()))
@@ -2550,7 +2552,8 @@ namespace Game.Entities
damage = 0;
}
}
public void DealDamageMods(Unit victim, ref uint damage, ref uint absorb)
public static void DealDamageMods(Unit attacker, Unit victim, ref uint damage, ref uint absorb)
{
if (victim == null || !victim.IsAlive() || victim.HasUnitState(UnitState.InFlight)
|| (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks()))
@@ -2560,156 +2563,22 @@ namespace Game.Entities
return;
}
damage = (uint)(damage * GetDamageMultiplierForTarget(victim));
if (attacker != null)
damage *= (uint)attacker.GetDamageMultiplierForTarget(victim);
}
void DealMeleeDamage(CalcDamageInfo damageInfo, bool durabilityLoss)
{
Unit victim = damageInfo.target;
if (!victim.IsAlive() || victim.HasUnitState(UnitState.InFlight) || (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks()))
return;
// Hmmmm dont like this emotes client must by self do all animations
if (damageInfo.HitInfo.HasAnyFlag(HitInfo.CriticalHit))
victim.HandleEmoteCommand(Emote.OneshotWoundCritical);
if (damageInfo.blocked_amount != 0 && damageInfo.TargetState != VictimState.Blocks)
victim.HandleEmoteCommand(Emote.OneshotParryShield);
if (damageInfo.TargetState == VictimState.Parry &&
(!IsTypeId(TypeId.Unit) || !ToCreature().GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoParryHasten)))
{
// Get attack timers
float offtime = victim.GetAttackTimer(WeaponAttackType.OffAttack);
float basetime = victim.GetAttackTimer(WeaponAttackType.BaseAttack);
// Reduce attack time
if (victim.HaveOffhandWeapon() && offtime < basetime)
{
float percent20 = victim.GetBaseAttackTime(WeaponAttackType.OffAttack) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
victim.SetAttackTimer(WeaponAttackType.OffAttack, (uint)percent20);
else if (offtime > percent60)
{
offtime -= 2.0f * percent20;
victim.SetAttackTimer(WeaponAttackType.OffAttack, (uint)offtime);
}
}
else
{
float percent20 = victim.GetBaseAttackTime(WeaponAttackType.BaseAttack) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
victim.SetAttackTimer(WeaponAttackType.BaseAttack, (uint)percent20);
else if (basetime > percent60)
{
basetime -= 2.0f * percent20;
victim.SetAttackTimer(WeaponAttackType.BaseAttack, (uint)basetime);
}
}
}
// Call default DealDamage
CleanDamage cleanDamage = new(damageInfo.cleanDamage, damageInfo.absorb, damageInfo.attackType, damageInfo.hitOutCome);
DealDamage(victim, damageInfo.damage, cleanDamage, DamageEffectType.Direct, (SpellSchoolMask)damageInfo.damageSchoolMask, null, durabilityLoss);
// If this is a creature and it attacks from behind it has a probability to daze it's victim
if ((damageInfo.hitOutCome == MeleeHitOutcome.Crit || damageInfo.hitOutCome == MeleeHitOutcome.Crushing || damageInfo.hitOutCome == MeleeHitOutcome.Normal || damageInfo.hitOutCome == MeleeHitOutcome.Glancing) &&
!IsTypeId(TypeId.Player) && !ToCreature().IsControlledByPlayer() && !victim.HasInArc(MathFunctions.PI, this)
&& (victim.IsTypeId(TypeId.Player) || !victim.ToCreature().IsWorldBoss()) && !victim.IsVehicle())
{
// 20% base chance
float chance = 20.0f;
// there is a newbie protection, at level 10 just 7% base chance; assuming linear function
if (victim.GetLevel() < 30)
chance = 0.65f * victim.GetLevelForTarget(this) + 0.5f;
uint victimDefense = victim.GetMaxSkillValueForLevel(this);
uint attackerMeleeSkill = GetMaxSkillValueForLevel();
chance *= attackerMeleeSkill / (float)victimDefense * 0.16f;
// -probability is between 0% and 40%
MathFunctions.RoundToInterval(ref chance, 0.0f, 40.0f);
if (RandomHelper.randChance(chance))
CastSpell(victim, 1604, true);
}
if (IsTypeId(TypeId.Player))
{
DamageInfo dmgInfo = new(damageInfo);
ToPlayer().CastItemCombatSpell(dmgInfo);
}
// Do effect if any damage done to target
if (damageInfo.damage != 0)
{
// 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 vDamageShieldsCopy = victim.GetAuraEffectsByType(AuraType.DamageShield);
foreach (var dmgShield in vDamageShieldsCopy)
{
SpellInfo spellInfo = dmgShield.GetSpellInfo();
// Damage shield can be resisted...
var missInfo = victim.SpellHitResult(this, spellInfo, false);
if (missInfo != SpellMissInfo.None)
{
victim.SendSpellMiss(this, spellInfo.Id, missInfo);
continue;
}
// ...or immuned
if (IsImmunedToDamage(spellInfo))
{
victim.SendSpellDamageImmune(this, spellInfo.Id, false);
continue;
}
uint damage = (uint)dmgShield.GetAmount();
Unit caster = dmgShield.GetCaster();
if (caster)
{
damage = caster.SpellDamageBonusDone(this, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo());
damage = SpellDamageBonusTaken(caster, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo());
}
DamageInfo damageInfo1 = new(this, victim, damage, spellInfo, spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack);
victim.CalcAbsorbResist(damageInfo1);
damage = damageInfo1.GetDamage();
victim.DealDamageMods(this, ref damage);
SpellDamageShield damageShield = new();
damageShield.Attacker = victim.GetGUID();
damageShield.Defender = GetGUID();
damageShield.SpellID = spellInfo.Id;
damageShield.TotalDamage = damage;
damageShield.OriginalDamage = (int)damageInfo.originalDamage;
damageShield.OverKill = (uint)Math.Max(damage - GetHealth(), 0);
damageShield.SchoolMask = (uint)spellInfo.SchoolMask;
damageShield.LogAbsorbed = damageInfo1.GetAbsorb();
victim.DealDamage(this, damage, null, DamageEffectType.SpellDirect, spellInfo.GetSchoolMask(), spellInfo, true);
damageShield.LogData.Initialize(this);
victim.SendCombatLogMessage(damageShield);
}
}
}
public uint DealDamage(Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true)
public static uint DealDamage(Unit attacker, Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true)
{
if (victim.IsAIEnabled)
victim.GetAI().DamageTaken(this, ref damage);
victim.GetAI().DamageTaken(attacker, ref damage);
if (IsAIEnabled)
GetAI().DamageDealt(victim, ref damage, damagetype);
if (attacker != null && attacker.IsAIEnabled)
attacker.GetAI().DamageDealt(victim, ref damage, damagetype);
// Hook for OnDamage Event
Global.ScriptMgr.OnDamage(this, victim, ref damage);
Global.ScriptMgr.OnDamage(attacker, victim, ref damage);
if (victim.IsTypeId(TypeId.Player) && this != victim)
if (victim.IsTypeId(TypeId.Player) && attacker != victim)
{
// Signal to pets that their owner was attacked - except when DOT.
if (damagetype != DamageEffectType.DOT)
@@ -2719,7 +2588,7 @@ namespace Game.Entities
Creature cControlled = controlled.ToCreature();
if (cControlled != null)
if (cControlled.IsAIEnabled)
cControlled.GetAI().OwnerAttackedBy(this);
cControlled.GetAI().OwnerAttackedBy(attacker);
}
}
@@ -2740,7 +2609,7 @@ namespace Game.Entities
if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0)
{
if (victim != this && victim.IsPlayer())
if (victim != attacker && victim.IsPlayer())
{
Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic);
if (spell != null)
@@ -2772,35 +2641,36 @@ namespace Game.Entities
uint share = MathFunctions.CalculatePct(damage, aura.GetAmount());
// @todo check packets if damage is done by victim, or by attacker of victim
DealDamageMods(shareDamageTarget, ref share);
DealDamage(shareDamageTarget, share, null, DamageEffectType.NoDamage, spell.GetSchoolMask(), spell, false);
DealDamageMods(attacker, shareDamageTarget, ref share);
DealDamage(attacker, shareDamageTarget, share, null, DamageEffectType.NoDamage, spell.GetSchoolMask(), spell, false);
}
}
// Rage from Damage made (only from direct weapon damage)
if (cleanDamage != null && (cleanDamage.attackType == WeaponAttackType.BaseAttack || cleanDamage.attackType == WeaponAttackType.OffAttack) && damagetype == DamageEffectType.Direct && this != victim && GetPowerType() == PowerType.Rage)
if (attacker != null && cleanDamage != null && (cleanDamage.attackType == WeaponAttackType.BaseAttack || cleanDamage.attackType == WeaponAttackType.OffAttack) && damagetype == DamageEffectType.Direct && attacker != victim && attacker.GetPowerType() == PowerType.Rage)
{
uint rage = (uint)(GetBaseAttackTime(cleanDamage.attackType) / 1000.0f * 1.75f);
uint rage = (uint)(attacker.GetBaseAttackTime(cleanDamage.attackType) / 1000.0f * 1.75f);
if (cleanDamage.attackType == WeaponAttackType.OffAttack)
rage /= 2;
RewardRage(rage);
attacker.RewardRage(rage);
}
if (damage == 0)
return 0;
Log.outDebug(LogFilter.Unit, "DealDamageStart");
uint health = (uint)victim.GetHealth();
Log.outDebug(LogFilter.Unit, "Unit {0} dealt {1} damage to unit {2}", GetGUID(), damage, victim.GetGUID());
// duel ends when player has 1 or less hp
bool duel_hasEnded = false;
bool duel_wasMounted = false;
if (victim.IsTypeId(TypeId.Player) && victim.ToPlayer().duel != null && damage >= (health - 1))
if (victim.IsPlayer() && victim.ToPlayer().duel != null && damage >= (health - 1))
{
if (!attacker)
return 0;
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (victim.ToPlayer().duel.opponent == this || victim.ToPlayer().duel.opponent.GetGUID() == GetOwnerGUID())
if (victim.ToPlayer().duel.opponent == attacker || victim.ToPlayer().duel.opponent.GetGUID() == attacker.GetOwnerGUID())
damage = health - 1;
duel_hasEnded = true;
@@ -2810,8 +2680,11 @@ namespace Game.Entities
Player victimRider = victim.GetCharmer().ToPlayer();
if (victimRider != null && victimRider.duel != null && victimRider.duel.isMounted)
{
if (!attacker)
return 0;
// prevent kill only if killed in duel and killed by opponent or opponent controlled creature
if (victimRider.duel.opponent == this || victimRider.duel.opponent.GetGUID() == GetCharmerGUID())
if (victimRider.duel.opponent == attacker || victimRider.duel.opponent.GetGUID() == attacker.GetCharmerGUID())
damage = health - 1;
duel_wasMounted = true;
@@ -2819,35 +2692,36 @@ namespace Game.Entities
}
}
if (IsTypeId(TypeId.Player) && this != victim)
if (attacker != null && attacker != victim)
{
Player killer = ToPlayer();
// in bg, count dmg if victim is also a player
if (victim.IsTypeId(TypeId.Player))
Player killer = attacker.ToPlayer();
if (killer != null)
{
Battleground bg = killer.GetBattleground();
if (bg)
bg.UpdatePlayerScore(killer, ScoreType.DamageDone, damage);
// in bg, count dmg if victim is also a player
if (victim.IsPlayer())
{
Battleground bg = killer.GetBattleground();
if (bg != null)
bg.UpdatePlayerScore(killer, ScoreType.DamageDone, damage);
}
killer.UpdateCriteria(CriteriaTypes.DamageDone, health > damage ? damage : health, 0, 0, victim);
killer.UpdateCriteria(CriteriaTypes.HighestHitDealt, damage);
}
killer.UpdateCriteria(CriteriaTypes.DamageDone, health > damage ? damage : health, 0, 0, victim);
killer.UpdateCriteria(CriteriaTypes.HighestHitDealt, damage);
}
if (victim.IsTypeId(TypeId.Player))
{
if (victim.IsPlayer())
victim.ToPlayer().UpdateCriteria(CriteriaTypes.HighestHitReceived, damage);
}
damage /= (uint)victim.GetHealthMultiplierForTarget(this);
if (attacker != null)
damage /= (uint)victim.GetHealthMultiplierForTarget(attacker);
if (victim.GetTypeId() != TypeId.Player && (!victim.IsControlledByPlayer() || victim.IsVehicle()))
{
if (!victim.ToCreature().HasLootRecipient())
victim.ToCreature().SetLootRecipient(this);
victim.ToCreature().SetLootRecipient(attacker);
if (IsControlledByPlayer())
if (attacker == null || attacker.IsControlledByPlayer())
victim.ToCreature().LowerPlayerDamageReq(health < damage ? health : damage);
}
@@ -2858,15 +2732,13 @@ namespace Game.Entities
{
killed = true;
Log.outDebug(LogFilter.Unit, "DealDamage: victim just died");
if (victim.IsTypeId(TypeId.Player) && victim != this)
if (victim.IsPlayer() && victim != attacker)
victim.ToPlayer().UpdateCriteria(CriteriaTypes.TotalDamageReceived, health);
if (damagetype != DamageEffectType.NoDamage && damagetype != DamageEffectType.Self && victim.HasAuraType(AuraType.SchoolAbsorbOverkill))
{
var vAbsorbOverkill = victim.GetAuraEffectsByType(AuraType.SchoolAbsorbOverkill);
DamageInfo damageInfo = new(this, victim, damage, spellProto, damageSchoolMask, damagetype, cleanDamage != null ? cleanDamage.attackType : WeaponAttackType.BaseAttack);
DamageInfo damageInfo = new(attacker, victim, damage, spellProto, damageSchoolMask, damagetype, cleanDamage != null ? cleanDamage.attackType : WeaponAttackType.BaseAttack);
foreach (var absorbAurEff in vAbsorbOverkill)
{
@@ -2909,7 +2781,7 @@ namespace Game.Entities
if (currentAbsorb != 0)
{
SpellAbsorbLog absorbLog = new();
absorbLog.Attacker = GetGUID();
absorbLog.Attacker = attacker != null ? attacker.GetGUID() : ObjectGuid.Empty;
absorbLog.Victim = victim.GetGUID();
absorbLog.Caster = baseAura.GetCasterGUID();
absorbLog.AbsorbedSpellID = spellProto != null ? spellProto.Id : 0;
@@ -2917,7 +2789,7 @@ namespace Game.Entities
absorbLog.Absorbed = currentAbsorb;
absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
absorbLog.LogData.Initialize(victim);
SendCombatLogMessage(absorbLog);
victim.SendCombatLogMessage(absorbLog);
}
}
@@ -2926,11 +2798,9 @@ namespace Game.Entities
}
if (killed)
Kill(victim, durabilityLoss, skipSettingDeathState);
Kill(attacker, victim, durabilityLoss, skipSettingDeathState);
else
{
Log.outDebug(LogFilter.Unit, "DealDamageAlive");
if (victim.IsTypeId(TypeId.Player))
victim.ToPlayer().UpdateCriteria(CriteriaTypes.TotalDamageReceived, damage);
@@ -2945,7 +2815,8 @@ namespace Game.Entities
if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield)))
victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime);
victim.GetThreatManager().AddThreat(this, damage, spellProto);
if (attacker != null)
victim.GetThreatManager().AddThreat(attacker, damage, spellProto);
}
else // victim is a player
{
@@ -2957,19 +2828,19 @@ namespace Game.Entities
}
}
if (IsTypeId(TypeId.Player))
if (attacker != null && attacker.IsPlayer())
{
// random durability for items (HIT DONE)
if (RandomHelper.randChance(WorldConfig.GetFloatValue(WorldCfg.RateDurabilityLossDamage)))
{
byte slot = (byte)RandomHelper.IRand(0, EquipmentSlot.End - 1);
ToPlayer().DurabilityPointLossForEquipSlot(slot);
attacker.ToPlayer().DurabilityPointLossForEquipSlot(slot);
}
}
if (damagetype != DamageEffectType.NoDamage)
{
if (victim != this && (spellProto == null || !(spellProto.HasAttribute(SpellAttr7.NoPushbackOnDamage) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
if (victim != attacker && (spellProto == null || !(spellProto.HasAttribute(SpellAttr7.NoPushbackOnDamage) || spellProto.HasAttribute(SpellAttr3.TreatAsPeriodic))))
{
if (damagetype != DamageEffectType.DOT)
{
@@ -3044,11 +2915,147 @@ namespace Game.Entities
}
}
Log.outDebug(LogFilter.Unit, "DealDamageEnd returned {0} damage", damage);
return damage;
}
void DealMeleeDamage(CalcDamageInfo damageInfo, bool durabilityLoss)
{
Unit victim = damageInfo.target;
if (!victim.IsAlive() || victim.HasUnitState(UnitState.InFlight) || (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks()))
return;
// Hmmmm dont like this emotes client must by self do all animations
if (damageInfo.HitInfo.HasAnyFlag(HitInfo.CriticalHit))
victim.HandleEmoteCommand(Emote.OneshotWoundCritical);
if (damageInfo.blocked_amount != 0 && damageInfo.TargetState != VictimState.Blocks)
victim.HandleEmoteCommand(Emote.OneshotParryShield);
if (damageInfo.TargetState == VictimState.Parry &&
(!IsTypeId(TypeId.Unit) || !ToCreature().GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoParryHasten)))
{
// Get attack timers
float offtime = victim.GetAttackTimer(WeaponAttackType.OffAttack);
float basetime = victim.GetAttackTimer(WeaponAttackType.BaseAttack);
// Reduce attack time
if (victim.HaveOffhandWeapon() && offtime < basetime)
{
float percent20 = victim.GetBaseAttackTime(WeaponAttackType.OffAttack) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
victim.SetAttackTimer(WeaponAttackType.OffAttack, (uint)percent20);
else if (offtime > percent60)
{
offtime -= 2.0f * percent20;
victim.SetAttackTimer(WeaponAttackType.OffAttack, (uint)offtime);
}
}
else
{
float percent20 = victim.GetBaseAttackTime(WeaponAttackType.BaseAttack) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
victim.SetAttackTimer(WeaponAttackType.BaseAttack, (uint)percent20);
else if (basetime > percent60)
{
basetime -= 2.0f * percent20;
victim.SetAttackTimer(WeaponAttackType.BaseAttack, (uint)basetime);
}
}
}
// Call default DealDamage
CleanDamage cleanDamage = new(damageInfo.cleanDamage, damageInfo.absorb, damageInfo.attackType, damageInfo.hitOutCome);
DealDamage(this, victim, damageInfo.damage, cleanDamage, DamageEffectType.Direct, (SpellSchoolMask)damageInfo.damageSchoolMask, null, durabilityLoss);
// If this is a creature and it attacks from behind it has a probability to daze it's victim
if ((damageInfo.hitOutCome == MeleeHitOutcome.Crit || damageInfo.hitOutCome == MeleeHitOutcome.Crushing || damageInfo.hitOutCome == MeleeHitOutcome.Normal || damageInfo.hitOutCome == MeleeHitOutcome.Glancing) &&
!IsTypeId(TypeId.Player) && !ToCreature().IsControlledByPlayer() && !victim.HasInArc(MathFunctions.PI, this)
&& (victim.IsTypeId(TypeId.Player) || !victim.ToCreature().IsWorldBoss()) && !victim.IsVehicle())
{
// 20% base chance
float chance = 20.0f;
// there is a newbie protection, at level 10 just 7% base chance; assuming linear function
if (victim.GetLevel() < 30)
chance = 0.65f * victim.GetLevelForTarget(this) + 0.5f;
uint victimDefense = victim.GetMaxSkillValueForLevel(this);
uint attackerMeleeSkill = GetMaxSkillValueForLevel();
chance *= attackerMeleeSkill / (float)victimDefense * 0.16f;
// -probability is between 0% and 40%
MathFunctions.RoundToInterval(ref chance, 0.0f, 40.0f);
if (RandomHelper.randChance(chance))
CastSpell(victim, 1604, true);
}
if (IsTypeId(TypeId.Player))
{
DamageInfo dmgInfo = new(damageInfo);
ToPlayer().CastItemCombatSpell(dmgInfo);
}
// Do effect if any damage done to target
if (damageInfo.damage != 0)
{
// 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 vDamageShieldsCopy = victim.GetAuraEffectsByType(AuraType.DamageShield);
foreach (var dmgShield in vDamageShieldsCopy)
{
SpellInfo spellInfo = dmgShield.GetSpellInfo();
// Damage shield can be resisted...
var missInfo = victim.SpellHitResult(this, spellInfo, false);
if (missInfo != SpellMissInfo.None)
{
victim.SendSpellMiss(this, spellInfo.Id, missInfo);
continue;
}
// ...or immuned
if (IsImmunedToDamage(spellInfo))
{
victim.SendSpellDamageImmune(this, spellInfo.Id, false);
continue;
}
uint damage = (uint)dmgShield.GetAmount();
Unit caster = dmgShield.GetCaster();
if (caster)
{
damage = caster.SpellDamageBonusDone(this, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo());
damage = SpellDamageBonusTaken(caster, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo());
}
DamageInfo damageInfo1 = new(this, victim, damage, spellInfo, spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack);
CalcAbsorbResist(damageInfo1);
damage = damageInfo1.GetDamage();
DealDamageMods(victim, this, ref damage);
SpellDamageShield damageShield = new();
damageShield.Attacker = victim.GetGUID();
damageShield.Defender = GetGUID();
damageShield.SpellID = spellInfo.Id;
damageShield.TotalDamage = damage;
damageShield.OriginalDamage = (int)damageInfo.originalDamage;
damageShield.OverKill = (uint)Math.Max(damage - GetHealth(), 0);
damageShield.SchoolMask = (uint)spellInfo.SchoolMask;
damageShield.LogAbsorbed = damageInfo1.GetAbsorb();
DealDamage(victim, this, damage, null, DamageEffectType.SpellDirect, spellInfo.GetSchoolMask(), spellInfo, true);
damageShield.LogData.Initialize(this);
victim.SendCombatLogMessage(damageShield);
}
}
}
public long ModifyHealth(long dVal)
{
long gain = 0;
@@ -3338,7 +3345,7 @@ namespace Game.Entities
RemovePvpFlag(UnitPVPStateFlags.PvP);
}
uint CalcSpellResistedDamage(Unit attacker, Unit victim, uint damage, SpellSchoolMask schoolMask, SpellInfo spellInfo)
static uint CalcSpellResistedDamage(Unit attacker, Unit victim, uint damage, SpellSchoolMask schoolMask, SpellInfo spellInfo)
{
// Magic damage, check for resists
if (!Convert.ToBoolean(schoolMask & SpellSchoolMask.Magic))
@@ -3359,7 +3366,7 @@ namespace Game.Entities
return 0;
}
float averageResist = CalculateAverageResistReduction(schoolMask, victim, spellInfo);
float averageResist = CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
float[] discreteResistProbability = new float[11];
if (averageResist <= 0.1f)
@@ -3387,7 +3394,8 @@ namespace Game.Entities
{
int ignoredResistance = 0;
ignoredResistance += GetTotalAuraModifierByMiscMask(AuraType.ModIgnoreTargetResist, (int)schoolMask);
if (attacker != null)
ignoredResistance += attacker.GetTotalAuraModifierByMiscMask(AuraType.ModIgnoreTargetResist, (int)schoolMask);
ignoredResistance = Math.Min(ignoredResistance, 100);
MathFunctions.ApplyPct(ref damageResisted, 100 - ignoredResistance);
@@ -3407,20 +3415,23 @@ namespace Game.Entities
return (uint)damageResisted;
}
float CalculateAverageResistReduction(SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo)
static float CalculateAverageResistReduction(Unit attacker, SpellSchoolMask schoolMask, Unit victim, SpellInfo spellInfo = null)
{
float victimResistance = (float)victim.GetResistance(schoolMask);
float victimResistance = victim.GetResistance(schoolMask);
// pets inherit 100% of masters penetration
// excluding traps
Player player = GetSpellModOwner();
if (player != null && GetEntry() != SharedConst.WorldTrigger)
if (attacker != null)
{
victimResistance += (float)player.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
victimResistance -= (float)player.GetSpellPenetrationItemMod();
// pets inherit 100% of masters penetration
// excluding traps
Player player = attacker.GetSpellModOwner();
if (player != null && attacker.GetEntry() != SharedConst.WorldTrigger)
{
victimResistance += player.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
victimResistance -= player.GetSpellPenetrationItemMod();
}
else
victimResistance += attacker.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
}
else
victimResistance += (float)GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)schoolMask);
// holy resistance exists in pve and comes from level difference, ignore template values
if (schoolMask.HasAnyFlag(SpellSchoolMask.Holy))
@@ -3433,12 +3444,12 @@ namespace Game.Entities
victimResistance = Math.Max(victimResistance, 0.0f);
// level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
if (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell))
victimResistance += Math.Max(((float)victim.GetLevelForTarget(this) - (float)GetLevelForTarget(victim)) * 5.0f, 0.0f);
if (attacker != null && (spellInfo == null || !spellInfo.HasAttribute(SpellCustomAttributes.BinarySpell)))
victimResistance += Math.Max(((float)victim.GetLevelForTarget(attacker) - (float)attacker.GetLevelForTarget(victim)) * 5.0f, 0.0f);
uint bossLevel = 83;
float bossResistanceConstant = 510.0f;
uint level = victim.GetLevelForTarget(this);
uint level = attacker != null ? victim.GetLevelForTarget(attacker) : attacker.GetLevel();
float resistanceConstant;
if (level == bossLevel)
@@ -3449,7 +3460,7 @@ namespace Game.Entities
return victimResistance / (victimResistance + resistanceConstant);
}
public void CalcAbsorbResist(DamageInfo damageInfo)
public static void CalcAbsorbResist(DamageInfo damageInfo)
{
if (!damageInfo.GetVictim() || !damageInfo.GetVictim().IsAlive() || damageInfo.GetDamage() == 0)
return;
@@ -3458,7 +3469,11 @@ namespace Game.Entities
damageInfo.ResistDamage(resistedDamage);
// Ignore Absorption Auras
float auraAbsorbMod = GetMaxPositiveAuraModifierByMiscMask(AuraType.ModTargetAbsorbSchool, (uint)damageInfo.GetSchoolMask());
float auraAbsorbMod = 0f;
Unit attacker = damageInfo.GetAttacker();
if (attacker != null)
auraAbsorbMod = attacker.GetMaxPositiveAuraModifierByMiscMask(AuraType.ModTargetAbsorbSchool, (uint)damageInfo.GetSchoolMask());
MathFunctions.RoundToInterval(ref auraAbsorbMod, 0.0f, 100.0f);
@@ -3522,7 +3537,7 @@ namespace Game.Entities
if (currentAbsorb != 0)
{
SpellAbsorbLog absorbLog = new();
absorbLog.Attacker = damageInfo.GetAttacker().GetGUID();
absorbLog.Attacker = damageInfo.GetAttacker() != null ? damageInfo.GetAttacker().GetGUID() : ObjectGuid.Empty;
absorbLog.Victim = damageInfo.GetVictim().GetGUID();
absorbLog.Caster = absorbAurEff.GetBase().GetCasterGUID();
absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() != null ? damageInfo.GetSpellInfo().Id : 0;
@@ -3530,7 +3545,7 @@ namespace Game.Entities
absorbLog.Absorbed = currentAbsorb;
absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
absorbLog.LogData.Initialize(damageInfo.GetVictim());
SendCombatLogMessage(absorbLog);
damageInfo.GetVictim().SendCombatLogMessage(absorbLog);
}
}
@@ -3596,7 +3611,7 @@ namespace Game.Entities
if (currentAbsorb != 0)
{
SpellAbsorbLog absorbLog = new();
absorbLog.Attacker = damageInfo.GetAttacker().GetGUID();
absorbLog.Attacker = damageInfo.GetAttacker() != null ? damageInfo.GetAttacker().GetGUID() : ObjectGuid.Empty;
absorbLog.Victim = damageInfo.GetVictim().GetGUID();
absorbLog.Caster = absorbAurEff.GetBase().GetCasterGUID();
absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() != null ? damageInfo.GetSpellInfo().Id : 0;
@@ -3604,14 +3619,14 @@ namespace Game.Entities
absorbLog.Absorbed = currentAbsorb;
absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
absorbLog.LogData.Initialize(damageInfo.GetVictim());
SendCombatLogMessage(absorbLog);
damageInfo.GetVictim().SendCombatLogMessage(absorbLog);
}
}
damageInfo.ModifyDamage(absorbIgnoringDamage);
// split damage auras - only when not damaging self
if (damageInfo.GetVictim() != this)
if (damageInfo.GetVictim() != damageInfo.GetAttacker())
{
// 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
@@ -3652,23 +3667,23 @@ namespace Game.Entities
}
uint split_absorb = 0;
DealDamageMods(caster, ref splitDamage, ref split_absorb);
DealDamageMods(damageInfo.GetAttacker(), caster, ref splitDamage, ref split_absorb);
SpellNonMeleeDamage log = new(this, caster, itr.GetSpellInfo(), itr.GetBase().GetSpellVisual(), damageInfo.GetSchoolMask(), itr.GetBase().GetCastGUID());
SpellNonMeleeDamage log = new(damageInfo.GetAttacker(), caster, itr.GetSpellInfo(), itr.GetBase().GetSpellVisual(), damageInfo.GetSchoolMask(), itr.GetBase().GetCastGUID());
CleanDamage cleanDamage = new(splitDamage, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
DealDamage(caster, splitDamage, cleanDamage, DamageEffectType.Direct, damageInfo.GetSchoolMask(), itr.GetSpellInfo(), false);
DealDamage(damageInfo.GetAttacker(), caster, splitDamage, cleanDamage, DamageEffectType.Direct, damageInfo.GetSchoolMask(), itr.GetSpellInfo(), false);
log.damage = splitDamage;
log.originalDamage = splitDamage;
log.absorb = split_absorb;
SendSpellNonMeleeDamageLog(log);
caster.SendSpellNonMeleeDamageLog(log);
// break 'Fear' and similar auras
ProcSkillsAndAuras(caster, ProcFlags.None, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null);
ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, ProcFlags.None, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null);
}
}
}
public void CalcHealAbsorb(HealInfo healInfo)
public static void CalcHealAbsorb(HealInfo healInfo)
{
if (healInfo.GetHeal() == 0)
return;
@@ -3728,61 +3743,67 @@ namespace Game.Entities
}
}
public uint CalcArmorReducedDamage(Unit attacker, Unit victim, uint damage, SpellInfo spellInfo, WeaponAttackType attackType = WeaponAttackType.Max)
public static uint CalcArmorReducedDamage(Unit attacker, Unit victim, uint damage, SpellInfo spellInfo, WeaponAttackType attackType = WeaponAttackType.Max, uint attackerLevel = 0)
{
float armor = victim.GetArmor();
armor *= victim.GetArmorMultiplierForTarget(attacker);
// bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
int armorBypassPct = 0;
var reductionAuras = victim.GetAuraEffectsByType(AuraType.BypassArmorForCaster);
foreach (var eff in reductionAuras)
if (eff.GetCasterGUID() == GetGUID())
armorBypassPct += eff.GetAmount();
armor = MathFunctions.CalculatePct(armor, 100 - Math.Min(armorBypassPct, 100));
// Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
armor += GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)SpellSchoolMask.Normal);
if (spellInfo != null)
if (attacker != null)
{
Player modOwner = GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.TargetResistance, ref armor);
}
armor *= victim.GetArmorMultiplierForTarget(attacker);
var resIgnoreAuras = GetAuraEffectsByType(AuraType.ModIgnoreTargetResist);
foreach (var eff in resIgnoreAuras)
{
if (eff.GetMiscValue().HasAnyFlag((int)SpellSchoolMask.Normal) && eff.IsAffectingSpell(spellInfo))
armor = (float)Math.Floor(MathFunctions.AddPct(ref armor, -eff.GetAmount()));
}
// bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
int armorBypassPct = 0;
var reductionAuras = victim.GetAuraEffectsByType(AuraType.BypassArmorForCaster);
foreach (var eff in reductionAuras)
if (eff.GetCasterGUID() == attacker.GetGUID())
armorBypassPct += eff.GetAmount();
// Apply Player CR_ARMOR_PENETRATION rating
if (IsTypeId(TypeId.Player))
{
float arpPct = ToPlayer().GetRatingBonusValue(CombatRating.ArmorPenetration);
armor = MathFunctions.CalculatePct(armor, 100 - Math.Min(armorBypassPct, 100));
// no more than 100%
MathFunctions.RoundToInterval(ref arpPct, 0.0f, 100.0f);
// Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
armor += attacker.GetTotalAuraModifierByMiscMask(AuraType.ModTargetResistance, (int)SpellSchoolMask.Normal);
float maxArmorPen;
if (victim.GetLevelForTarget(attacker) < 60)
maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker);
else
maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker) + 4.5f * 85 * (victim.GetLevelForTarget(attacker) - 59);
if (spellInfo != null)
{
Player modOwner = attacker.GetSpellModOwner();
if (modOwner != null)
modOwner.ApplySpellMod(spellInfo, SpellModOp.TargetResistance, ref armor);
}
// Cap armor penetration to this number
maxArmorPen = Math.Min((armor + maxArmorPen) / 3.0f, armor);
// Figure out how much armor do we ignore
armor -= MathFunctions.CalculatePct(maxArmorPen, arpPct);
var resIgnoreAuras = attacker.GetAuraEffectsByType(AuraType.ModIgnoreTargetResist);
foreach (var eff in resIgnoreAuras)
{
if (eff.GetMiscValue().HasAnyFlag((int)SpellSchoolMask.Normal) && eff.IsAffectingSpell(spellInfo))
armor = (float)Math.Floor(MathFunctions.AddPct(ref armor, -eff.GetAmount()));
}
// Apply Player CR_ARMOR_PENETRATION rating
if (attacker.IsPlayer())
{
float arpPct = attacker.ToPlayer().GetRatingBonusValue(CombatRating.ArmorPenetration);
// no more than 100%
MathFunctions.RoundToInterval(ref arpPct, 0.0f, 100.0f);
float maxArmorPen;
if (victim.GetLevelForTarget(attacker) < 60)
maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker);
else
maxArmorPen = 400 + 85 * victim.GetLevelForTarget(attacker) + 4.5f * 85 * (victim.GetLevelForTarget(attacker) - 59);
// Cap armor penetration to this number
maxArmorPen = Math.Min((armor + maxArmorPen) / 3.0f, armor);
// Figure out how much armor do we ignore
armor -= MathFunctions.CalculatePct(maxArmorPen, arpPct);
}
}
if (MathFunctions.fuzzyLe(armor, 0.0f))
return damage;
uint attackerLevel = attacker.GetLevelForTarget(victim);
if (attacker != null)
attackerLevel = attacker.GetLevelForTarget(victim);
// Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
float armorConstant = Global.DB2Mgr.EvaluateExpectedStat(ExpectedStatType.ArmorConstant, attackerLevel, -2, 0, attacker.GetClass());
if ((armor + armorConstant) == 0)
+1 -1
View File
@@ -207,7 +207,7 @@ namespace Game
if (opcode == ClientOpcodes.MoveJump)
{
plrMover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2.Jump); // Mind Control
plrMover.ProcSkillsAndAuras(null, ProcFlags.Jump, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
Unit.ProcSkillsAndAuras(plrMover, null, ProcFlags.Jump, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
}
}
}
+1 -1
View File
@@ -367,7 +367,7 @@ namespace Game.Maps
var playerList = instance.GetPlayers();
foreach (var player in playerList)
if (player.IsAlive())
player.ProcSkillsAndAuras(null, ProcFlags.EncounterStart, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
Unit.ProcSkillsAndAuras(player, null, ProcFlags.EncounterStart, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
break;
}
case EncounterState.Fail:
+14 -55
View File
@@ -347,6 +347,19 @@ namespace Game.Spells
}
}
public float CalcPeriodicCritChance(Unit caster)
{
if (!caster)
return 0.0f;
Player modOwner = caster.GetSpellModOwner();
if (modOwner == null)
return 0.0f;
float critChance = modOwner.SpellCritChanceDone(GetSpellInfo(), GetSpellInfo().GetSchoolMask(), GetSpellInfo().GetAttackType());
return Math.Max(0.0f, critChance);
}
public Unit GetCaster()
{
if (m_owner.GetGUID() == m_casterGuid)
@@ -854,13 +867,8 @@ namespace Game.Spells
effect.ChangeAmount(effect.CalculateAmount(caster), false, true);
foreach (var app in applications)
{
if (!app.HasRemoveMode())
{
HandleAuraSpecificPeriodics(app, caster);
HandleAuraSpecificMods(app, caster, true, true);
}
}
SetNeedClientUpdateForTargets();
}
@@ -1406,55 +1414,6 @@ namespace Game.Spells
}
}
public void HandleAuraSpecificPeriodics(AuraApplication aurApp, Unit caster)
{
Unit target = aurApp.GetTarget();
if (!caster || aurApp.HasRemoveMode())
return;
foreach (AuraEffect effect in GetAuraEffects())
{
if (effect == null || effect.IsAreaAuraEffect() || effect.IsEffect(SpellEffectName.PersistentAreaAura))
continue;
switch (effect.GetSpellEffectInfo().ApplyAuraName)
{
case AuraType.PeriodicDamage:
case AuraType.PeriodicDamagePercent:
case AuraType.PeriodicLeech:
{
// ignore non positive values (can be result apply spellmods to aura damage
uint damage = (uint)Math.Max(effect.GetAmount(), 0);
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
effect.SetDonePct(caster.SpellDamagePctDone(target, m_spellInfo, DamageEffectType.DOT)); // Calculate done percentage first!
effect.SetDamage((int)(caster.SpellDamageBonusDone(target, m_spellInfo, damage, DamageEffectType.DOT, effect.GetSpellEffectInfo(), GetStackAmount()) * effect.GetDonePct()));
effect.SetCritChance(caster.GetUnitSpellCriticalChance(target, null, effect, m_spellInfo.GetSchoolMask()));
break;
}
case AuraType.PeriodicHeal:
case AuraType.ObsModHealth:
{
// ignore non positive values (can be result apply spellmods to aura damage
uint damage = (uint)Math.Max(effect.GetAmount(), 0);
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
effect.SetDonePct(caster.SpellHealingPctDone(target, m_spellInfo)); // Calculate done percentage first!
effect.SetDamage((int)(caster.SpellHealingBonusDone(target, m_spellInfo, damage, DamageEffectType.DOT, effect.GetSpellEffectInfo(), GetStackAmount()) * effect.GetDonePct()));
effect.SetCritChance(caster.GetUnitSpellCriticalChance(target, null, effect, m_spellInfo.GetSchoolMask()));
break;
}
default:
break;
}
}
}
bool CanBeAppliedOn(Unit target)
{
// unit not in world or during remove from world
@@ -1842,7 +1801,7 @@ namespace Game.Spells
public float CalcPPMProcChance(Unit actor)
{
// Formula see http://us.battle.net/wow/en/forum/topic/8197741003#1
float ppm = m_spellInfo.CalcProcPPM(actor, m_castItemLevel);
float ppm = m_spellInfo.CalcProcPPM(actor, GetCastItemLevel());
float averageProcInterval = 60.0f / ppm;
var currentTime = GameTime.GetGameTimeSteadyPoint();
+120 -150
View File
@@ -39,12 +39,11 @@ namespace Game.Spells
m_spellInfo = baseAura.GetSpellInfo();
_effectInfo = spellEfffectInfo;
m_baseAmount = baseAmount.HasValue ? baseAmount.Value : _effectInfo.CalcBaseValue(caster, baseAura.GetAuraType() == AuraObjectType.Unit ? baseAura.GetOwner().ToUnit() : null, baseAura.GetCastItemId(), baseAura.GetCastItemLevel());
m_donePct = 1.0f;
m_canBeRecalculated = true;
m_isPeriodic = false;
CalculatePeriodic(caster, true, false);
m_amount = CalculateAmount(caster);
_amount = CalculateAmount(caster);
CalculateSpellMod();
}
@@ -267,7 +266,7 @@ namespace Game.Spells
if (Convert.ToBoolean(handleMask & AuraEffectHandleModes.ChangeAmount))
{
if (!mark)
m_amount = newAmount;
_amount = newAmount;
else
SetAmount(newAmount);
CalculateSpellMod();
@@ -427,6 +426,11 @@ namespace Game.Spells
}
}
public float GetCritChanceFor(Unit caster, Unit target)
{
return target.SpellCritChanceTaken(caster, null, this, GetSpellInfo().GetSchoolMask(), GetBase().CalcPeriodicCritChance(caster), GetSpellInfo().GetAttackType());
}
public bool IsAffectingSpell(SpellInfo spell)
{
if (spell == null)
@@ -766,9 +770,9 @@ namespace Game.Spells
public int GetMiscValueB() { return GetSpellEffectInfo().MiscValueB; }
public int GetMiscValue() { return GetSpellEffectInfo().MiscValue; }
public AuraType GetAuraType() { return GetSpellEffectInfo().ApplyAuraName; }
public int GetAmount() { return m_amount; }
public bool HasAmount() { return m_amount != 0; }
public void SetAmount(int _amount) { m_amount = _amount; m_canBeRecalculated = false; }
public int GetAmount() { return _amount; }
public bool HasAmount() { return _amount != 0; }
public void SetAmount(int amount) { _amount = amount; m_canBeRecalculated = false; }
public int GetPeriodicTimer() { return _periodicTimer; }
public void SetPeriodicTimer(int periodicTimer) { _periodicTimer = periodicTimer; }
@@ -791,13 +795,6 @@ namespace Game.Spells
public bool CanBeRecalculated() { return m_canBeRecalculated; }
public void SetCanBeRecalculated(bool val) { m_canBeRecalculated = val; }
public void SetDamage(int val) { m_damage = val; }
public int GetDamage() { return m_damage; }
public void SetCritChance(float val) { m_critChance = val; }
public float GetCritChance() { return m_critChance; }
public void SetDonePct(float val) { m_donePct = val; }
public float GetDonePct() { return m_donePct; }
public void ResetTicks() { _ticksDone = 0; }
public uint GetTickNumber() { return _ticksDone; }
public uint GetRemainingTicks() { return GetTotalTicks() - _ticksDone; }
@@ -822,10 +819,7 @@ namespace Game.Spells
SpellModifier m_spellmod;
public int m_baseAmount;
int m_amount;
int m_damage;
float m_critChance;
float m_donePct;
int _amount;
// periodic stuff
int _periodicTimer;
@@ -2518,7 +2512,7 @@ namespace Game.Spells
// so this break such spells or most of them.
// Current formula about m_amount: effect base points + dieside - 1
// TO DO: Reasearch more about 0/0 and fix it.
caster._EnterVehicle(target.GetVehicleKit(), (sbyte)(m_amount - 1), aurApp);
caster._EnterVehicle(target.GetVehicleKit(), (sbyte)(GetAmount() - 1), aurApp);
}
else
{
@@ -2527,7 +2521,7 @@ namespace Game.Spells
if (GetId() == 53111) // Devour Humanoid
{
target.Kill(caster);
Unit.Kill(target, caster);
if (caster.IsTypeId(TypeId.Unit))
caster.ToCreature().DespawnOrUnsummon();
}
@@ -2985,7 +2979,7 @@ namespace Game.Spells
if (GetMiscValue() == i || GetMiscValue() == -1)
{
if (apply)
target.ApplyStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, m_amount);
target.ApplyStatPctModifier(UnitMods.StatStart + i, UnitModifierPctType.Base, GetAmount());
else
{
float amount = target.GetTotalAuraMultiplier(AuraType.ModPercentStat, aurEff =>
@@ -3154,7 +3148,7 @@ namespace Game.Spells
{
if (GetMiscValue() == (int)stat || GetMiscValue() == -1)
{
target.HandleStatFlatModifier(UnitMods.StatStart + (int)stat, UnitModifierFlatType.BasePCTExcludeCreate, m_amount, apply);
target.HandleStatFlatModifier(UnitMods.StatStart + (int)stat, UnitModifierFlatType.BasePCTExcludeCreate, GetAmount(), apply);
target.UpdateStatBuffMod(stat);
}
}
@@ -3170,7 +3164,7 @@ namespace Game.Spells
if (!target)
return;
target.ApplyModOverrideSpellPowerByAPPercent(m_amount, apply);
target.ApplyModOverrideSpellPowerByAPPercent(GetAmount(), apply);
target.UpdateSpellDamageAndHealingBonus();
}
@@ -3184,7 +3178,7 @@ namespace Game.Spells
if (!target)
return;
target.ApplyModOverrideAPBySpellPowerPercent(m_amount, apply);
target.ApplyModOverrideAPBySpellPowerPercent(GetAmount(), apply);
target.UpdateAttackPowerAndDamage();
target.UpdateAttackPowerAndDamage(true);
}
@@ -3730,7 +3724,7 @@ namespace Game.Spells
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, spellGroupVal, !apply);
}
target.ApplyCastTimePercentMod(m_amount, apply);
target.ApplyCastTimePercentMod(GetAmount(), apply);
target.ApplyAttackTimePercentMod(WeaponAttackType.BaseAttack, GetAmount(), apply);
target.ApplyAttackTimePercentMod(WeaponAttackType.OffAttack, GetAmount(), apply);
target.ApplyAttackTimePercentMod(WeaponAttackType.RangedAttack, GetAmount(), apply);
@@ -4443,7 +4437,7 @@ namespace Game.Spells
//Adding items
uint noSpaceForCount;
uint count = (uint)m_amount;
uint count = (uint)GetAmount();
List<ItemPosCount> dest = new();
InventoryResult msg = plCaster.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, GetSpellEffectInfo().ItemType, count, out noSpaceForCount);
@@ -4493,7 +4487,7 @@ namespace Game.Spells
return;
uint factionId = (uint)GetMiscValue();
ReputationRank factionRank = (ReputationRank)m_amount;
ReputationRank factionRank = (ReputationRank)GetAmount();
player.GetReputationMgr().ApplyForceReaction(factionId, factionRank, apply);
player.GetReputationMgr().SendForceReactions();
@@ -4880,7 +4874,10 @@ namespace Game.Spells
void HandlePeriodicDamageAurasTick(Unit target, Unit caster)
{
if (!caster || !target.IsAlive())
// dynobj auras must always have a caster
Cypher.Assert(GetSpellEffectInfo().Effect != SpellEffectName.PersistentAreaAura || caster != null);
if (!target.IsAlive())
return;
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
@@ -4896,38 +4893,28 @@ namespace Game.Spells
CleanDamage cleanDamage = new(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
// AOE spells are not affected by the new periodic system.
bool isAreaAura = GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura);
// ignore non positive values (can be result apply spellmods to aura damage
uint damage = (uint)(isAreaAura ? Math.Max(GetAmount(), 0) : m_damage);
uint damage = (uint)Math.Max(GetAmount(), 0);
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
if (isAreaAura)
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
switch (GetAuraType())
{
case AuraType.PeriodicDamage:
{
if (isAreaAura)
damage = (uint)(caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()) * caster.SpellDamagePctDone(target, m_spellInfo, DamageEffectType.DOT));
if (caster != null)
damage = (uint)caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
// Calculate armor mitigation
if (caster.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo(), (sbyte)GetEffIndex()))
{
uint damageReductedArmor = caster.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo());
cleanDamage.mitigated_damage += damage - damageReductedArmor;
damage = damageReductedArmor;
}
// There is a Chance to make a Soul Shard when Drain soul does damage
if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Warlock && GetSpellInfo().SpellFamilyFlags[0].HasAnyFlag(0x00004000u))
if (caster != null && GetSpellInfo().SpellFamilyName == SpellFamilyNames.Warlock && GetSpellInfo().SpellFamilyFlags[0].HasAnyFlag(0x00004000u))
{
if (caster.IsTypeId(TypeId.Player) && caster.ToPlayer().IsHonorOrXPTarget(target))
caster.CastSpell(caster, 95810, new CastSpellExtraArgs(this));
}
if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Generic)
else if (GetSpellInfo().SpellFamilyName == SpellFamilyNames.Generic)
{
switch (GetId())
{
@@ -4947,48 +4934,54 @@ namespace Game.Spells
{
WeaponAttackType attackType = GetSpellInfo().GetAttackType();
uint weaponDamage = MathFunctions.CalculatePct(caster.CalculateDamage(attackType, false, true), GetAmount());
damage = MathFunctions.CalculatePct(caster.CalculateDamage(attackType, false, true), GetAmount());
// Add melee damage bonuses (also check for negative)
uint damageBonusDone = caster.MeleeDamageBonusDone(target, Math.Max(weaponDamage, 0), attackType, DamageEffectType.DOT, GetSpellInfo());
if (caster != null)
damage = caster.MeleeDamageBonusDone(target, damage, attackType, DamageEffectType.DOT, GetSpellInfo());
damage = target.MeleeDamageBonusTaken(caster, damageBonusDone, attackType, DamageEffectType.DOT, GetSpellInfo());
damage = target.MeleeDamageBonusTaken(caster, damage, attackType, DamageEffectType.DOT, GetSpellInfo());
break;
}
case AuraType.PeriodicDamagePercent:
// ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
damage = (uint)Math.Ceiling(MathFunctions.CalculatePct((float)target.GetMaxHealth(), (float)damage));
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
break;
default:
break;
}
if (!m_spellInfo.HasAttribute(SpellAttr4.FixedDamage))
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
if (crit)
damage = Unit.SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
// Calculate armor mitigation
if (Unit.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo(), (sbyte)GetEffIndex()))
{
if (GetSpellEffectInfo().IsTargetingArea() || isAreaAura)
{
damage = (uint)(damage * target.GetTotalAuraMultiplierByMiscMask(AuraType.ModAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
if (!caster.IsTypeId(TypeId.Player))
damage = (uint)(damage * target.GetTotalAuraMultiplierByMiscMask(AuraType.ModCreatureAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
}
uint damageReductedArmor = Unit.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetAttackType(), GetBase().GetCasterLevel());
cleanDamage.mitigated_damage += damage - damageReductedArmor;
damage = damageReductedArmor;
}
bool crit = RandomHelper.randChance(isAreaAura ? caster.GetUnitSpellCriticalChance(target, null, this, m_spellInfo.GetSchoolMask()) : m_critChance);
if (crit)
damage = caster.SpellCriticalDamageBonus(m_spellInfo, damage, target);
uint dmg = damage;
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
caster.ApplyResilience(target, ref dmg);
damage = dmg;
{
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().Effect == SpellEffectName.PersistentAreaAura)
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, caster);
}
int dmg = (int)damage;
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
Unit.ApplyResilience(target, ref dmg);
damage = (uint)dmg;
DamageInfo damageInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack);
caster.CalcAbsorbResist(damageInfo);
Unit.CalcAbsorbResist(damageInfo);
damage = damageInfo.GetDamage();
uint absorb = damageInfo.GetAbsorb();
uint resist = damageInfo.GetResist();
caster.DealDamageMods(target, ref damage, ref absorb);
Unit.DealDamageMods(caster, target, ref damage, ref absorb);
// Set trigger flag
ProcFlags procAttacker = ProcFlags.DonePeriodic;
@@ -5005,17 +4998,20 @@ namespace Game.Spells
if (overkill < 0)
overkill = 0;
SpellPeriodicAuraLogInfo pInfo = new(this, damage, dmg, (uint)overkill, absorb, resist, 0.0f, crit);
SpellPeriodicAuraLogInfo pInfo = new(this, damage, (uint)dmg, (uint)overkill, absorb, resist, 0.0f, crit);
caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), true);
Unit.DealDamage(caster, target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), true);
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
target.SendPeriodicAuraLog(pInfo);
}
void HandlePeriodicHealthLeechAuraTick(Unit target, Unit caster)
{
if (!caster || !target.IsAlive())
// dynobj auras must always have a caster
Cypher.Assert(GetSpellEffectInfo().Effect != SpellEffectName.PersistentAreaAura || caster != null);
if (!target.IsAlive())
return;
if (target.HasUnitState(UnitState.Isolated) || target.IsImmunedToDamage(GetSpellInfo()))
@@ -5030,47 +5026,40 @@ namespace Game.Spells
CleanDamage cleanDamage = new(0, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal);
bool isAreaAura = GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura);
// ignore negative values (can be result apply spellmods to aura damage
uint damage = (uint)(isAreaAura ? Math.Max(GetAmount(), 0) : m_damage);
uint damage = (uint)Math.Max(GetAmount(), 0);
if (caster)
damage = caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
if (isAreaAura)
{
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
Global.ScriptMgr.ModifyPeriodicDamageAurasTick(target, caster, ref damage);
damage = (uint)(caster.SpellDamageBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()) * caster.SpellDamagePctDone(target, m_spellInfo, DamageEffectType.DOT));
}
damage = target.SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
if (crit)
damage = Unit.SpellCriticalDamageBonus(caster, m_spellInfo, damage, target);
// Calculate armor mitigation
if (caster.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo(), (sbyte)GetEffIndex()))
if (Unit.IsDamageReducedByArmor(GetSpellInfo().GetSchoolMask(), GetSpellInfo(), (sbyte)GetEffIndex()))
{
uint damageReductedArmor = caster.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo());
uint damageReductedArmor = Unit.CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetAttackType(), GetBase().GetCasterLevel());
cleanDamage.mitigated_damage += damage - damageReductedArmor;
damage = damageReductedArmor;
}
if (!m_spellInfo.HasAttribute(SpellAttr4.FixedDamage))
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
{
if (GetSpellEffectInfo().IsTargetingArea() || isAreaAura)
{
damage = (uint)(damage * target.GetTotalAuraMultiplierByMiscMask(AuraType.ModAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
if (!caster.IsTypeId(TypeId.Player))
damage = (uint)(damage * target.GetTotalAuraMultiplierByMiscMask(AuraType.ModCreatureAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
}
if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().Effect == SpellEffectName.PersistentAreaAura)
damage = (uint)target.CalculateAOEAvoidance((int)damage, (uint)m_spellInfo.SchoolMask, caster);
}
bool crit = RandomHelper.randChance(isAreaAura ? caster.GetUnitSpellCriticalChance(target, null, this, m_spellInfo.GetSchoolMask()) : m_critChance);
if (crit)
damage = caster.SpellCriticalDamageBonus(m_spellInfo, damage, target);
int dmg = (int)damage;
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage) && caster != null && caster.CanApplyResilience())
Unit.ApplyResilience(target, ref dmg);
uint dmg = damage;
if (!GetSpellInfo().HasAttribute(SpellAttr4.FixedDamage))
caster.ApplyResilience(target, ref dmg);
damage = dmg;
damage = (uint)dmg;
DamageInfo damageInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask(), DamageEffectType.DOT, WeaponAttackType.BaseAttack);
caster.CalcAbsorbResist(damageInfo);
Unit.CalcAbsorbResist(damageInfo);
uint absorb = damageInfo.GetAbsorb();
uint resist = damageInfo.GetResist();
@@ -5078,7 +5067,7 @@ namespace Game.Spells
// SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage
SpellNonMeleeDamage log = new(caster, target, GetSpellInfo(), GetBase().GetSpellVisual(), GetSpellInfo().GetSchoolMask(), GetBase().GetCastGUID());
log.damage = damage;
log.originalDamage = dmg;
log.originalDamage = (uint)dmg;
log.absorb = absorb;
log.resist = resist;
log.periodicLog = true;
@@ -5096,22 +5085,22 @@ namespace Game.Spells
procVictim |= ProcFlags.TakenDamage;
}
int new_damage = (int)caster.DealDamage(target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false);
if (caster.IsAlive())
{
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
int new_damage = (int)Unit.DealDamage(caster, target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false);
if (!caster || !caster.IsAlive())
return;
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.None, hitMask, null, damageInfo, null);
uint heal = (caster.SpellHealingBonusDone(caster, GetSpellInfo(), (uint)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()));
heal = (caster.SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()));
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
HealInfo healInfo = new(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.HealBySpell(healInfo);
uint heal = (caster.SpellHealingBonusDone(caster, GetSpellInfo(), (uint)(new_damage * gainMultiplier), DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()));
heal = caster.SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
caster.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
caster.ProcSkillsAndAuras(caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
}
HealInfo healInfo = new(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.HealBySpell(healInfo);
caster.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
Unit.ProcSkillsAndAuras(caster, caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
caster.SendSpellNonMeleeDamageLog(log);
}
@@ -5143,12 +5132,15 @@ namespace Game.Spells
HealInfo healInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.HealBySpell(healInfo);
caster.ProcSkillsAndAuras(target, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, ProcFlagsHit.Normal, null, null, healInfo);
Unit.ProcSkillsAndAuras(caster, target, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, ProcFlagsHit.Normal, null, null, healInfo);
}
void HandlePeriodicHealAurasTick(Unit target, Unit caster)
{
if (!caster || !target.IsAlive())
// dynobj auras must always have a caster
Cypher.Assert(GetSpellEffectInfo().Effect != SpellEffectName.PersistentAreaAura || caster != null);
if (!target.IsAlive())
return;
if (target.HasUnitState(UnitState.Isolated))
@@ -5158,51 +5150,28 @@ namespace Game.Spells
}
// heal for caster damage (must be alive)
if (target != caster && GetSpellInfo().HasAttribute(SpellAttr2.HealthFunnel) && !caster.IsAlive())
if (target != caster && GetSpellInfo().HasAttribute(SpellAttr2.HealthFunnel) && (caster == null || !caster.IsAlive()))
return;
// don't regen when permanent aura target has full power
if (GetBase().IsPermanent() && target.IsFullHealth())
return;
bool isAreaAura = GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SpellEffectName.PersistentAreaAura);
// ignore negative values (can be result apply spellmods to aura damage
int damage = isAreaAura ? Math.Max(GetAmount(), 0) : m_damage;
uint damage = (uint)Math.Max(GetAmount(), 0);
if (GetAuraType() == AuraType.ObsModHealth)
{
// Taken mods
float TakenTotalMod = 1.0f;
// Tenacity increase healing % taken
AuraEffect Tenacity = target.GetAuraEffect(58549, 0);
if (Tenacity != null)
MathFunctions.AddPct(ref TakenTotalMod, Tenacity.GetAmount());
// Healing taken percent
float minval = target.GetMaxNegativeAuraModifier(AuraType.ModHealingPct);
if (minval != 0)
MathFunctions.AddPct(ref TakenTotalMod, minval);
float maxval = target.GetMaxPositiveAuraModifier(AuraType.ModHealingPct);
if (maxval != 0)
MathFunctions.AddPct(ref TakenTotalMod, maxval);
TakenTotalMod = Math.Max(TakenTotalMod, 0.0f);
damage = (int)target.CountPctFromMaxHealth(damage);
damage = (int)(damage * TakenTotalMod);
}
else
{
if (isAreaAura)
damage = (int)(caster.SpellHealingBonusDone(target, GetSpellInfo(), (uint)damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount()) * caster.SpellHealingPctDone(target, m_spellInfo));
damage = (int)target.SpellHealingBonusTaken(caster, GetSpellInfo(), (uint)damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
damage = (uint)target.CountPctFromMaxHealth((int)damage);
}
else if (caster != null)
damage = caster.SpellHealingBonusDone(target, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
bool crit = RandomHelper.randChance(isAreaAura ? caster.GetUnitSpellCriticalChance(target, null, this, m_spellInfo.GetSchoolMask()) : m_critChance);
damage = target.SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DamageEffectType.DOT, GetSpellEffectInfo(), GetBase().GetStackAmount());
bool crit = RandomHelper.randChance(GetCritChanceFor(caster, target));
if (crit)
damage = caster.SpellCriticalHealingBonus(m_spellInfo, damage, target);
damage = (uint)Unit.SpellCriticalHealingBonus(caster, m_spellInfo, (int)damage, target);
Log.outDebug(LogFilter.Spells, "PeriodicTick: {0} (TypeId: {1}) heal of {2} (TypeId: {3}) for {4} health inflicted by {5}",
GetCasterGUID().ToString(), GetCaster().GetTypeId(), target.GetGUID().ToString(), target.GetTypeId(), damage, GetId());
@@ -5210,13 +5179,14 @@ namespace Game.Spells
uint heal = (uint)damage;
HealInfo healInfo = new(caster, target, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.CalcHealAbsorb(healInfo);
caster.DealHeal(healInfo);
Unit.CalcHealAbsorb(healInfo);
Unit.DealHeal(healInfo);
SpellPeriodicAuraLogInfo pInfo = new(this, heal, (uint)damage, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target.SendPeriodicAuraLog(pInfo);
target.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
if (caster != null)
target.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
// %-based heal - does not proc auras
if (GetAuraType() == AuraType.ObsModHealth)
@@ -5227,7 +5197,7 @@ namespace Game.Spells
ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal;
// ignore item heals
if (GetBase().GetCastItemGUID().IsEmpty())
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
}
void HandlePeriodicManaLeechAuraTick(Unit target, Unit caster)
@@ -5248,7 +5218,7 @@ namespace Game.Spells
return;
// ignore negative values (can be result apply spellmods to aura damage
int drainAmount = Math.Max(m_amount, 0);
int drainAmount = Math.Max(GetAmount(), 0);
int drainedAmount = -target.ModifyPower(powerType, -drainAmount);
float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster);
@@ -5307,7 +5277,7 @@ namespace Game.Spells
return;
// ignore negative values (can be result apply spellmods to aura damage
int amount = Math.Max(m_amount, 0) * target.GetMaxPower(powerType) / 100;
int amount = Math.Max(GetAmount(), 0) * target.GetMaxPower(powerType) / 100;
SpellPeriodicAuraLogInfo pInfo = new(this, (uint)amount, (uint)amount, 0, 0, 0, 0.0f, false);
@@ -5336,7 +5306,7 @@ namespace Game.Spells
return;
// ignore negative values (can be result apply spellmods to aura damage
int amount = Math.Max(m_amount, 0);
int amount = Math.Max(GetAmount(), 0);
SpellPeriodicAuraLogInfo pInfo = new(this, (uint)amount, (uint)amount, 0, 0, 0, 0.0f, false);
int gain = target.ModifyPower(powerType, amount);
@@ -5361,7 +5331,7 @@ namespace Game.Spells
}
// ignore negative values (can be result apply spellmods to aura damage
int damage = Math.Max(m_amount, 0);
int damage = Math.Max(GetAmount(), 0);
uint gain = (uint)(-target.ModifyPower(powerType, -damage));
@@ -5373,7 +5343,7 @@ namespace Game.Spells
// no SpellDamageBonus for burn mana
caster.CalculateSpellDamageTaken(damageInfo, (int)(gain * dmgMultiplier), spellProto);
caster.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
// Set trigger flag
ProcFlags procAttacker = ProcFlags.DonePeriodic;
@@ -5389,7 +5359,7 @@ namespace Game.Spells
caster.DealSpellDamage(damageInfo, true);
DamageInfo dotDamageInfo = new(damageInfo, DamageEffectType.DOT, WeaponAttackType.BaseAttack, hitMask);
caster.ProcSkillsAndAuras(target, procAttacker, procVictim, spellTypeMask, ProcFlagsSpellPhase.None, hitMask, null, dotDamageInfo, null);
Unit.ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, ProcFlagsSpellPhase.None, hitMask, null, dotDamageInfo, null);
caster.SendSpellNonMeleeDamageLog(damageInfo);
}
@@ -5452,7 +5422,7 @@ namespace Game.Spells
int damage = (int)target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), (uint)GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo());
damage = (int)triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), (uint)damage, DamageEffectType.SpellDirect, GetSpellEffectInfo());
target.CalculateSpellDamageTaken(damageInfo, damage, GetSpellInfo());
target.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
target.DealSpellDamage(damageInfo, true);
target.SendSpellNonMeleeDamageLog(damageInfo);
}
+12 -13
View File
@@ -1947,7 +1947,7 @@ namespace Game.Spells
if (crit)
{
hitMask |= ProcFlagsHit.Critical;
addhealth = (uint)caster.SpellCriticalHealingBonus(m_spellInfo, (int)addhealth, null);
addhealth = (uint)Unit.SpellCriticalHealingBonus(caster, m_spellInfo, (int)addhealth, null);
}
else
hitMask |= ProcFlagsHit.Normal;
@@ -1959,7 +1959,7 @@ namespace Game.Spells
// Do triggers for unit
if (canEffectTrigger)
caster.ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, this, null, healInfo);
Unit.ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, this, null, healInfo);
}
// Do damage and triggers
else if (m_damage > 0)
@@ -1978,7 +1978,7 @@ namespace Game.Spells
{
// Add bonuses and fill damageInfo struct
caster.CalculateSpellDamageTaken(damageInfo, m_damage, m_spellInfo, m_attackType, target.crit);
caster.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
hitMask |= Unit.CreateProcHitMask(damageInfo, missInfo);
procVictim |= ProcFlags.TakenDamage;
@@ -1995,7 +1995,7 @@ namespace Game.Spells
if (canEffectTrigger)
{
DamageInfo spellDamageInfo = new(damageInfo, DamageEffectType.SpellDirect, m_attackType, hitMask);
caster.ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, hitMask, this, spellDamageInfo, null);
Unit.ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, hitMask, this, spellDamageInfo, null);
if (caster.IsPlayer() && !m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs) &&
(m_spellInfo.DmgClass == SpellDmgClass.Melee || m_spellInfo.DmgClass == SpellDmgClass.Ranged))
@@ -2012,7 +2012,7 @@ namespace Game.Spells
if (canEffectTrigger)
{
DamageInfo spellNoDamageInfo = new(damageInfo, DamageEffectType.NoDamage, m_attackType, hitMask);
caster.ProcSkillsAndAuras(unitTarget, procAttacker, procVictim, ProcFlagsSpellType.NoDmgHeal, ProcFlagsSpellPhase.Hit, hitMask, this, spellNoDamageInfo, null);
Unit.ProcSkillsAndAuras(caster, unitTarget, procAttacker, procVictim, ProcFlagsSpellType.NoDmgHeal, ProcFlagsSpellPhase.Hit, hitMask, this, spellNoDamageInfo, null);
if (caster.IsPlayer() && !m_spellInfo.HasAttribute(SpellAttr0.StopAttackTarget) && !m_spellInfo.HasAttribute(SpellAttr4.SuppressWeaponProcs) &&
(m_spellInfo.DmgClass == SpellDmgClass.Melee || m_spellInfo.DmgClass == SpellDmgClass.Ranged))
@@ -2960,7 +2960,7 @@ namespace Game.Spells
if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags))
m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed);
m_originalCaster.ProcSkillsAndAuras(null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null);
// Call CreatureAI hook OnSuccessfulSpellCast
Creature caster = m_originalCaster.ToCreature();
@@ -3187,7 +3187,7 @@ namespace Game.Spells
procAttacker = IsPositive() ? ProcFlags.DoneSpellNoneDmgClassPos : ProcFlags.DoneSpellNoneDmgClassNeg;
}
m_originalCaster.ProcSkillsAndAuras(null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null);
}
void SendSpellCooldown()
@@ -6865,11 +6865,9 @@ namespace Game.Spells
{
if (effect.IsTargetingArea() || effect.IsAreaAuraEffect() || effect.IsEffect(SpellEffectName.PersistentAreaAura))
{
m_damage = (int)(m_damage * unit.GetTotalAuraMultiplierByMiscMask(AuraType.ModAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
if (!m_caster.IsTypeId(TypeId.Player))
m_damage = (int)(m_damage * unit.GetTotalAuraMultiplierByMiscMask(AuraType.ModCreatureAoeDamageAvoidance, (uint)m_spellInfo.SchoolMask));
m_damage = unit.CalculateAOEAvoidance(m_damage, (uint)m_spellInfo.SchoolMask, m_caster);
if (m_caster.IsTypeId(TypeId.Player))
if (m_caster.IsPlayer())
{
long targetAmount = GetUnitTargetCountForEffect(effect.EffectIndex);
if (targetAmount > 20)
@@ -6887,7 +6885,8 @@ namespace Game.Spells
}
}
targetInfo.crit = m_caster.IsSpellCrit(unit, this, null, m_spellSchoolMask, m_attackType);
float critChance = m_caster.SpellCritChanceDone(m_spellInfo, m_spellSchoolMask, m_attackType);
targetInfo.crit = RandomHelper.randChance(unit.SpellCritChanceTaken(m_caster, this, null, m_spellSchoolMask, critChance, m_attackType));
}
SpellCastResult CanOpenLock(uint effIndex, uint lockId, ref SkillType skillId, ref int reqSkillValue, ref int skillValue)
@@ -8163,7 +8162,7 @@ namespace Game.Spells
ProcFlagsSpellPhase spellPhaseMask = ProcFlagsSpellPhase.None;
ProcFlagsHit hitMask = ProcFlagsHit.Reflect;
caster.ProcSkillsAndAuras(_victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, null, null, null);
Unit.ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, null, null, null);
return true;
}
+6 -9
View File
@@ -110,7 +110,7 @@ namespace Game.Spells
data.SpellID = m_spellInfo.Id;
m_caster.SendMessageToSet(data, true);
m_caster.DealDamage(unitTarget, (uint)unitTarget.GetHealth(), null, DamageEffectType.NoDamage, SpellSchoolMask.Normal, null, false);
Unit.DealDamage(m_caster, unitTarget, (uint)unitTarget.GetHealth(), null, DamageEffectType.NoDamage, SpellSchoolMask.Normal, null, false);
}
[SpellEffectHandler(SpellEffectName.EnvironmentalDamage)]
@@ -128,7 +128,7 @@ namespace Game.Spells
else
{
DamageInfo damageInfo = new(m_caster, unitTarget, (uint)damage, m_spellInfo, m_spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack);
m_caster.CalcAbsorbResist(damageInfo);
Unit.CalcAbsorbResist(damageInfo);
SpellNonMeleeDamage log = new(m_caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId);
log.damage = damageInfo.GetDamage();
@@ -908,9 +908,8 @@ namespace Game.Spells
addhealth = (int)caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)caster.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo);
else
{
addhealth = (int)caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo);
uint bonus = caster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo);
damage = (int)(bonus + (bonus * _variance));
addhealth = (int)(bonus + (uint)(bonus * _variance));
}
addhealth = (int)unitTarget.SpellHealingBonusTaken(caster, m_spellInfo, (uint)addhealth, DamageEffectType.Heal, effectInfo);
@@ -937,9 +936,7 @@ namespace Game.Spells
return;
uint heal = m_originalCaster.SpellHealingBonusDone(unitTarget, m_spellInfo, (uint)unitTarget.CountPctFromMaxHealth(damage), DamageEffectType.Heal, effectInfo);
heal = unitTarget.SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, DamageEffectType.Heal, effectInfo);
m_healing += (int)heal;
m_healing += (int)unitTarget.SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, DamageEffectType.Heal, effectInfo);
}
[SpellEffectHandler(SpellEffectName.HealMechanical)]
@@ -2705,9 +2702,9 @@ namespace Game.Spells
int duration = m_spellInfo.GetDuration();
unitTarget.GetSpellHistory().LockSpellSchool(curSpellInfo.GetSchoolMask(), (uint)unitTarget.ModSpellDuration(m_spellInfo, unitTarget, duration, false, (uint)(1 << (int)effIndex)));
if (m_spellInfo.DmgClass == SpellDmgClass.Magic)
m_originalCaster.ProcSkillsAndAuras(unitTarget, ProcFlags.DoneSpellMagicDmgClassNeg, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, unitTarget, ProcFlags.DoneSpellMagicDmgClassNeg, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null);
else if (m_spellInfo.DmgClass == SpellDmgClass.Melee)
m_originalCaster.ProcSkillsAndAuras(unitTarget, ProcFlags.DoneSpellMeleeDmgClass, ProcFlags.TakenSpellMeleeDmgClass, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null);
Unit.ProcSkillsAndAuras(m_originalCaster, unitTarget, ProcFlags.DoneSpellMeleeDmgClass, ProcFlags.TakenSpellMeleeDmgClass, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null);
}
ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo.Id);
unitTarget.InterruptSpell(i, false);
+8
View File
@@ -2986,6 +2986,14 @@ namespace Game.Entities
spellInfo.GetEffect(0).TriggerSpell = 46737;
spellInfo.GetEffect(0).ApplyAuraName = AuraType.PeriodicTriggerSpell;
break;
case 379: // Earth Shield
case 71607: // Item - Bauble of True Blood 10m
case 71646: // Item - Bauble of True Blood 25m
case 71610: // Item - Althor's Abacus trigger 10m
case 71641: // Item - Althor's Abacus trigger 25m
// We need more spells to find a general way (if there is any)
spellInfo.DmgClass = SpellDmgClass.Magic;
break;
case 63026: // Summon Aspirant Test NPC (HACK: Target shouldn't be changed)
case 63137: // Summon Valiant Test (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.DestDb);
+1 -1
View File
@@ -271,7 +271,7 @@ namespace Scripts.Spells.DeathKnight
int amount = (int)damageInfo.GetDamage() / 2;
SpellNonMeleeDamage log = new SpellNonMeleeDamage(drw, drw.GetVictim(), spellInfo, new SpellCastVisual(spellInfo.GetSpellXSpellVisualId(drw), 0), spellInfo.GetSchoolMask());
log.damage = (uint)amount;
drw.DealDamage(drw.GetVictim(), (uint)amount, null, DamageEffectType.SpellDirect, spellInfo.GetSchoolMask(), spellInfo, true);
Unit.DealDamage(drw, drw.GetVictim(), (uint)amount, null, DamageEffectType.SpellDirect, spellInfo.GetSchoolMask(), spellInfo, true);
drw.SendSpellNonMeleeDamageLog(log);
}
+2 -2
View File
@@ -287,7 +287,7 @@ namespace Scripts.Spells.Monk
if (auraEff != null)
{
float total = auraEff.GetAmount();
float tickDamage = aurEff.GetDamage();
float tickDamage = aurEff.GetAmount();
auraEff.ChangeAmount((int)(total - tickDamage));
}
}
@@ -359,7 +359,7 @@ namespace Scripts.Spells.Monk
{
AuraEffect eff = auraDamage.GetEffect(0);
if (eff != null)
eff.SetDamage((int)tickDamage);
eff.ChangeAmount((int)tickDamage);
}
}
}