Core: Combat/threat system rewrite
Port From (https://github.com/TrinityCore/TrinityCore/commit/34c7810fe507eca1b8b9389630db5d5d26d92e77)
This commit is contained in:
@@ -19,6 +19,7 @@ using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.Dynamic;
|
||||
using Game.AI;
|
||||
using Game.Combat;
|
||||
using Game.DataStorage;
|
||||
using Game.Groups;
|
||||
using Game.Loots;
|
||||
@@ -420,6 +421,8 @@ namespace Game.Entities
|
||||
UpdateMovementFlags();
|
||||
LoadCreaturesAddon();
|
||||
LoadTemplateImmunities();
|
||||
|
||||
GetThreatManager().UpdateOnlineStates(true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -511,6 +514,8 @@ namespace Game.Entities
|
||||
if (!IsAlive())
|
||||
break;
|
||||
|
||||
GetThreatManager().Update(diff);
|
||||
|
||||
if (m_shouldReacquireTarget && !IsFocusing(null, true))
|
||||
{
|
||||
SetTarget(m_suppressedTarget);
|
||||
@@ -903,10 +908,110 @@ namespace Game.Entities
|
||||
ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.KnockBackDest, true);
|
||||
}
|
||||
|
||||
GetThreatManager().Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitializeReactState()
|
||||
public Unit SelectVictim()
|
||||
{
|
||||
Unit target = null;
|
||||
|
||||
ThreatManager mgr = GetThreatManager();
|
||||
|
||||
if (mgr.CanHaveThreatList())
|
||||
{
|
||||
target = mgr.SelectVictim();
|
||||
while (!target)
|
||||
{
|
||||
Unit newTarget = null;
|
||||
// nothing found to attack - try to find something we're in combat with (but don't have a threat entry for yet) and start attacking it
|
||||
foreach (var pair in GetCombatManager().GetPvECombatRefs())
|
||||
{
|
||||
newTarget = pair.Value.GetOther(this);
|
||||
if (!mgr.IsThreatenedBy(newTarget, true))
|
||||
{
|
||||
mgr.AddThreat(newTarget, 0.0f, null, true, true);
|
||||
break;
|
||||
}
|
||||
else
|
||||
newTarget = null;
|
||||
}
|
||||
if (!newTarget)
|
||||
break;
|
||||
target = mgr.SelectVictim();
|
||||
}
|
||||
}
|
||||
else if (!HasReactState(ReactStates.Passive))
|
||||
{
|
||||
// We're a player pet, probably
|
||||
target = GetAttackerForHelper();
|
||||
if (!target && IsSummon())
|
||||
{
|
||||
Unit owner = ToTempSummon().GetOwner();
|
||||
if (owner != null)
|
||||
{
|
||||
if (owner.IsInCombat())
|
||||
target = owner.GetAttackerForHelper();
|
||||
if (!target)
|
||||
{
|
||||
foreach (var itr in owner.m_Controlled)
|
||||
{
|
||||
if (itr.IsInCombat())
|
||||
{
|
||||
target = itr.GetAttackerForHelper();
|
||||
if (target)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return null;
|
||||
|
||||
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
||||
{
|
||||
if (!IsFocusing(null, true))
|
||||
SetInFront(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/// @todo a vehicle may eat some mob, so mob should not evade
|
||||
if (GetVehicle())
|
||||
return null;
|
||||
|
||||
// search nearby enemy before enter evade mode
|
||||
if (HasReactState(ReactStates.Passive))
|
||||
{
|
||||
target = SelectNearestTargetInAttackDistance(m_CombatDistance != 0 ? m_CombatDistance : SharedConst.AttackDistance);
|
||||
|
||||
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
||||
return target;
|
||||
}
|
||||
|
||||
var iAuras = GetAuraEffectsByType(AuraType.ModInvisibility);
|
||||
if (!iAuras.Empty())
|
||||
{
|
||||
foreach (var itr in iAuras)
|
||||
{
|
||||
if (itr.GetBase().IsPermanent())
|
||||
{
|
||||
GetAI().EnterEvadeMode(EvadeReason.Other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// enter in evade mode in other case
|
||||
GetAI().EnterEvadeMode(EvadeReason.NoHostiles);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void InitializeReactState()
|
||||
{
|
||||
if (IsTotem() || IsTrigger() || IsCritter() || IsSpiritService())
|
||||
SetReactState(ReactStates.Passive);
|
||||
@@ -994,6 +1099,37 @@ namespace Game.Entities
|
||||
&& !GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoXpAtKill);
|
||||
}
|
||||
|
||||
public override void AtEnterCombat()
|
||||
{
|
||||
base.AtEnterCombat();
|
||||
|
||||
if (!GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.MountedCombatAllowed))
|
||||
Dismount();
|
||||
|
||||
if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
|
||||
{
|
||||
UpdateSpeed(UnitMoveType.Run);
|
||||
UpdateSpeed(UnitMoveType.Swim);
|
||||
UpdateSpeed(UnitMoveType.Flight);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AtExitCombat()
|
||||
{
|
||||
base.AtExitCombat();
|
||||
|
||||
ClearUnitState(UnitState.AttackPlayer);
|
||||
if (HasDynamicFlag(UnitDynFlags.Tapped))
|
||||
SetDynamicFlags((UnitDynFlags)GetCreatureTemplate().DynamicFlags);
|
||||
|
||||
if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
|
||||
{
|
||||
UpdateSpeed(UnitMoveType.Run);
|
||||
UpdateSpeed(UnitMoveType.Swim);
|
||||
UpdateSpeed(UnitMoveType.Flight);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEscortNPC(bool onlyIfActive = true)
|
||||
{
|
||||
if (!IsAIEnabled)
|
||||
@@ -3147,127 +3283,6 @@ namespace Game.Entities
|
||||
// There's many places not ready for dynamic spawns. This allows them to live on for now.
|
||||
void SetRespawnCompatibilityMode(bool mode = true) { m_respawnCompatibilityMode = mode; }
|
||||
public bool GetRespawnCompatibilityMode() { return m_respawnCompatibilityMode; }
|
||||
|
||||
public Unit SelectVictim()
|
||||
{
|
||||
// function provides main threat functionality
|
||||
// next-victim-selection algorithm and evade mode are called
|
||||
// threat list sorting etc.
|
||||
|
||||
Unit target = null;
|
||||
|
||||
// First checking if we have some taunt on us
|
||||
var tauntAuras = GetAuraEffectsByType(AuraType.ModTaunt);
|
||||
if (!tauntAuras.Empty())
|
||||
{
|
||||
Unit caster = tauntAuras.Last().GetCaster();
|
||||
|
||||
// The last taunt aura caster is alive an we are happy to attack him
|
||||
if (caster != null && caster.IsAlive())
|
||||
return GetVictim();
|
||||
else if (tauntAuras.Count > 1)
|
||||
{
|
||||
// We do not have last taunt aura caster but we have more taunt auras,
|
||||
// so find first available target
|
||||
|
||||
// Auras are pushed_back, last caster will be on the end
|
||||
for (var i = tauntAuras.Count - 1; i >= 0; i--)
|
||||
{
|
||||
caster = tauntAuras[i].GetCaster();
|
||||
if (caster != null && CanSeeOrDetect(caster, true) && IsValidAttackTarget(caster) && caster.IsInAccessiblePlaceFor(ToCreature()))
|
||||
{
|
||||
target = caster;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
target = GetVictim();
|
||||
}
|
||||
|
||||
if (CanHaveThreatList())
|
||||
{
|
||||
if (target == null && !GetThreatManager().IsThreatListEmpty())
|
||||
// No taunt aura or taunt aura caster is dead standard target selection
|
||||
target = GetThreatManager().GetHostilTarget();
|
||||
}
|
||||
else if (!HasReactState(ReactStates.Passive))
|
||||
{
|
||||
// We have player pet probably
|
||||
target = GetAttackerForHelper();
|
||||
if (target == null && IsSummon())
|
||||
{
|
||||
Unit owner = ToTempSummon().GetOwner();
|
||||
if (owner != null)
|
||||
{
|
||||
if (owner.IsInCombat())
|
||||
target = owner.GetAttackerForHelper();
|
||||
if (target == null)
|
||||
{
|
||||
foreach (var unit in owner.m_Controlled)
|
||||
{
|
||||
if (unit.IsInCombat())
|
||||
{
|
||||
target = unit.GetAttackerForHelper();
|
||||
if (target)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return null;
|
||||
|
||||
if (target != null && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
||||
{
|
||||
if (!IsFocusing(null, true))
|
||||
SetInFront(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
// last case when creature must not go to evade mode:
|
||||
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
|
||||
// Note: creature does not have targeted movement generator but has attacker in this case
|
||||
foreach (var unit in attackerList)
|
||||
{
|
||||
if (CanCreatureAttack(unit) && !unit.IsTypeId(TypeId.Player)
|
||||
&& !unit.ToCreature().HasUnitTypeMask(UnitTypeMask.ControlableGuardian))
|
||||
return null;
|
||||
}
|
||||
|
||||
// @todo a vehicle may eat some mob, so mob should not evade
|
||||
if (GetVehicle() != null)
|
||||
return null;
|
||||
|
||||
// search nearby enemy before enter evade mode
|
||||
if (HasReactState(ReactStates.Aggressive))
|
||||
{
|
||||
target = SelectNearestTargetInAttackDistance(m_CombatDistance != 0 ? m_CombatDistance : SharedConst.AttackDistance);
|
||||
|
||||
if (target != null && _IsTargetAcceptable(target) && CanCreatureAttack(target))
|
||||
return target;
|
||||
}
|
||||
|
||||
var iAuras = GetAuraEffectsByType(AuraType.ModInvisibility);
|
||||
if (!iAuras.Empty())
|
||||
{
|
||||
foreach (var aura in iAuras)
|
||||
{
|
||||
if (aura.GetBase().IsPermanent())
|
||||
{
|
||||
GetAI().EnterEvadeMode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// enter in evade mode in other case
|
||||
GetAI().EnterEvadeMode(EvadeReason.NoHostiles);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class VendorItemCount
|
||||
|
||||
@@ -1604,6 +1604,11 @@ namespace Game.Entities
|
||||
{
|
||||
return GetPhaseShift().CanSee(obj.GetPhaseShift());
|
||||
}
|
||||
|
||||
public static bool InSamePhase(WorldObject a, WorldObject b)
|
||||
{
|
||||
return a != null && b != null && a.IsInPhase(b);
|
||||
}
|
||||
|
||||
public virtual float GetCombatReach() { return 0.0f; } // overridden (only) in Unit
|
||||
public PhaseShift GetPhaseShift() { return _phaseShift; }
|
||||
|
||||
@@ -1343,6 +1343,8 @@ namespace Game.Entities
|
||||
AddUnitFlag2(UnitFlags2.RegeneratePower);
|
||||
SetSheath(SheathState.Melee);
|
||||
|
||||
GetThreatManager().Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -342,6 +342,20 @@ namespace Game.Entities
|
||||
UpdateDamagePhysical(attType);
|
||||
}
|
||||
|
||||
public override void AtEnterCombat()
|
||||
{
|
||||
base.AtEnterCombat();
|
||||
if (GetCombatManager().HasPvPCombat())
|
||||
EnablePvpRules(true);
|
||||
}
|
||||
|
||||
public override void AtExitCombat()
|
||||
{
|
||||
base.AtExitCombat();
|
||||
UpdatePotionCooldown();
|
||||
m_combatExitTime = Time.GetMSTime();
|
||||
}
|
||||
|
||||
public override float GetBlockPercent(uint attackerLevel)
|
||||
{
|
||||
float blockArmor = (float)m_activePlayerData.ShieldBlock;
|
||||
|
||||
@@ -475,7 +475,7 @@ namespace Game.Entities
|
||||
if (IsInAreaThatActivatesPvpTalents())
|
||||
return;
|
||||
|
||||
if (GetCombatTimer() == 0)
|
||||
if (!GetCombatManager().HasPvPCombat())
|
||||
{
|
||||
RemoveAurasDueToSpell(PlayerConst.SpellPvpRulesEnabled);
|
||||
UpdateItemLevelAreaBasedScaling();
|
||||
|
||||
@@ -316,6 +316,8 @@ namespace Game.Entities
|
||||
SetPrimarySpecialization(defaultSpec.Id);
|
||||
}
|
||||
|
||||
GetThreatManager().Initialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
public override void Update(uint diff)
|
||||
@@ -358,7 +360,7 @@ namespace Game.Entities
|
||||
|
||||
UpdateAfkReport(now);
|
||||
|
||||
if (GetCombatTimer() != 0) // Only set when in pvp combat
|
||||
if (GetCombatManager().HasPvPCombat()) // Only set when in pvp combat
|
||||
{
|
||||
Aura aura = GetAura(PlayerConst.SpellPvpRulesEnabled);
|
||||
if (aura != null)
|
||||
@@ -615,7 +617,7 @@ namespace Game.Entities
|
||||
{
|
||||
m_hostileReferenceCheckTimer = 15 * Time.InMilliseconds;
|
||||
if (!GetMap().IsDungeon())
|
||||
GetHostileRefManager().DeleteReferencesOutOfRange(GetVisibilityRange());
|
||||
GetCombatManager().EndCombatBeyondRange(GetVisibilityRange(), true);
|
||||
}
|
||||
else
|
||||
m_hostileReferenceCheckTimer -= diff;
|
||||
@@ -1908,9 +1910,6 @@ namespace Game.Entities
|
||||
|
||||
// Call base
|
||||
base.SetInWater(inWater);
|
||||
|
||||
// Update threat tables
|
||||
GetHostileRefManager().UpdateThreatTables();
|
||||
}
|
||||
public void ValidateMovementInfo(MovementInfo mi)
|
||||
{
|
||||
@@ -2151,15 +2150,11 @@ namespace Game.Entities
|
||||
|
||||
Pet pet = GetPet();
|
||||
if (pet != null)
|
||||
{
|
||||
pet.SetFaction(35);
|
||||
pet.GetHostileRefManager().SetOnlineOfflineState(false);
|
||||
}
|
||||
|
||||
RemovePvpFlag(UnitPVPStateFlags.FFAPvp);
|
||||
ResetContestedPvP();
|
||||
|
||||
GetHostileRefManager().SetOnlineOfflineState(false);
|
||||
CombatStopWithPets();
|
||||
|
||||
PhasingHandler.SetAlwaysVisible(this, true, false);
|
||||
@@ -2176,10 +2171,7 @@ namespace Game.Entities
|
||||
|
||||
Pet pet = GetPet();
|
||||
if (pet != null)
|
||||
{
|
||||
pet.SetFaction(GetFaction());
|
||||
pet.GetHostileRefManager().SetOnlineOfflineState(true);
|
||||
}
|
||||
|
||||
// restore FFA PvP Server state
|
||||
if (Global.WorldMgr.IsFFAPvPRealm())
|
||||
@@ -2188,7 +2180,6 @@ namespace Game.Entities
|
||||
// restore FFA PvP area state, remove not allowed for GM mounts
|
||||
UpdateArea(m_areaUpdateId);
|
||||
|
||||
GetHostileRefManager().SetOnlineOfflineState(true);
|
||||
m_serverSideVisibilityDetect.SetValue(ServerSideVisibilityType.GM, AccountTypes.Player);
|
||||
}
|
||||
|
||||
@@ -3918,14 +3909,6 @@ namespace Game.Entities
|
||||
public static bool IsValidClass(Class _class) { return Convert.ToBoolean((1 << ((int)_class - 1)) & (int)Class.ClassMaskAllPlayable); }
|
||||
public static bool IsValidRace(Race _race) { return Convert.ToBoolean((ulong)SharedConst.GetMaskForRace(_race) & SharedConst.RaceMaskAllPlayable); }
|
||||
|
||||
public override void OnCombatExit()
|
||||
{
|
||||
base.OnCombatExit();
|
||||
|
||||
UpdatePotionCooldown();
|
||||
m_combatExitTime = Time.GetMSTime();
|
||||
}
|
||||
|
||||
void LeaveLFGChannel()
|
||||
{
|
||||
foreach (var i in m_channels)
|
||||
@@ -6887,7 +6870,6 @@ namespace Game.Entities
|
||||
m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
|
||||
Dismount();
|
||||
RemoveUnitFlag(UnitFlags.RemoveClientControl | UnitFlags.TaxiFlight);
|
||||
GetHostileRefManager().SetOnlineOfflineState(true);
|
||||
}
|
||||
|
||||
public void ContinueTaxiFlight()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,15 +53,14 @@ namespace Game.Entities
|
||||
protected List<Unit> attackerList = new();
|
||||
Dictionary<ReactiveType, uint> m_reactiveTimer = new();
|
||||
protected float[][] m_weaponDamage = new float[(int)WeaponAttackType.Max][];
|
||||
public float[] m_threatModifier = new float[(int)SpellSchools.Max];
|
||||
|
||||
uint[] m_baseAttackSpeed = new uint[(int)WeaponAttackType.Max];
|
||||
float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max];
|
||||
protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max];
|
||||
|
||||
ThreatManager threatManager;
|
||||
HostileRefManager hostileRefManager;
|
||||
RedirectThreatInfo _redirectThreatInfo;
|
||||
CombatManager m_combatManager;
|
||||
ThreatManager m_threatManager;
|
||||
|
||||
protected Unit attacking;
|
||||
|
||||
public float ModMeleeHitChance { get; set; }
|
||||
@@ -520,27 +519,6 @@ namespace Game.Entities
|
||||
byte _chargesRemoved;
|
||||
}
|
||||
|
||||
public struct RedirectThreatInfo
|
||||
{
|
||||
ObjectGuid _targetGUID;
|
||||
uint _threatPct;
|
||||
|
||||
public ObjectGuid GetTargetGUID() { return _targetGUID; }
|
||||
public uint GetThreatPct() { return _threatPct; }
|
||||
|
||||
public void Set(ObjectGuid guid, uint pct)
|
||||
{
|
||||
_targetGUID = guid;
|
||||
_threatPct = pct;
|
||||
}
|
||||
|
||||
public void ModifyThreatPct(int amount)
|
||||
{
|
||||
amount += (int)_threatPct;
|
||||
_threatPct = (uint)(Math.Max(0, amount));
|
||||
}
|
||||
}
|
||||
|
||||
public class SpellPeriodicAuraLogInfo
|
||||
{
|
||||
public SpellPeriodicAuraLogInfo(AuraEffect _auraEff, uint _damage, uint _originalDamage, uint _overDamage, uint _absorb, uint _resist, float _multiplier, bool _critical)
|
||||
|
||||
@@ -58,7 +58,10 @@ namespace Game.Entities
|
||||
return true;
|
||||
if (HasUnitFlag2((UnitFlags2)0x1000000))
|
||||
return false;
|
||||
return HasUnitFlag(UnitFlags.PetInCombat | UnitFlags.Rename | UnitFlags.Unk15);
|
||||
if (IsPet() && HasUnitFlag(UnitFlags.PetInCombat))
|
||||
return true;
|
||||
|
||||
return HasUnitFlag(UnitFlags.Rename | UnitFlags.Unk15);
|
||||
}
|
||||
public virtual bool IsInWater()
|
||||
{
|
||||
|
||||
@@ -274,6 +274,8 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePetCombatState();
|
||||
}
|
||||
|
||||
public bool SetCharmedBy(Unit charmer, CharmType type, AuraApplication aurApp = null)
|
||||
@@ -314,7 +316,6 @@ namespace Game.Entities
|
||||
|
||||
CastStop();
|
||||
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
|
||||
GetThreatManager().ClearAllThreat();
|
||||
|
||||
Player playerCharmer = charmer.ToPlayer();
|
||||
|
||||
@@ -463,8 +464,6 @@ namespace Game.Entities
|
||||
|
||||
CastStop();
|
||||
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
|
||||
GetHostileRefManager().DeleteReferences();
|
||||
GetThreatManager().ClearAllThreat();
|
||||
|
||||
if (_oldFactionId != 0)
|
||||
{
|
||||
@@ -545,6 +544,8 @@ namespace Game.Entities
|
||||
player.SetClientControl(this, true);
|
||||
}
|
||||
|
||||
EngageWithTarget(charmer);
|
||||
|
||||
// a guardian should always have charminfo
|
||||
if (playerCharmer && this != charmer.GetFirstControlled())
|
||||
playerCharmer.SendRemoveControlBar();
|
||||
@@ -651,6 +652,8 @@ namespace Game.Entities
|
||||
m_Controlled.Remove(charm);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePetCombatState();
|
||||
}
|
||||
|
||||
public Unit GetFirstControlled()
|
||||
@@ -698,6 +701,8 @@ namespace Game.Entities
|
||||
Log.outFatal(LogFilter.Unit, "Unit {0} is not able to release its minion {1}", GetEntry(), GetMinionGUID());
|
||||
if (!GetCharmGUID().IsEmpty())
|
||||
Log.outFatal(LogFilter.Unit, "Unit {0} is not able to release its charm {1}", GetEntry(), GetCharmGUID());
|
||||
if (!IsPet()) // pets don't use the flag for this
|
||||
RemoveUnitFlag(UnitFlags.PetInCombat); // m_controlled is now empty, so we know none of our minions are in combat
|
||||
}
|
||||
|
||||
public void SendPetActionFeedback(PetActionFeedback msg, uint spellId)
|
||||
@@ -794,5 +799,25 @@ namespace Game.Entities
|
||||
pet.SetFullHealth();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdatePetCombatState()
|
||||
{
|
||||
Cypher.Assert(!IsPet()); // player pets do not use UNIT_FLAG_PET_IN_COMBAT for this purpose - but player pets should also never have minions of their own to call this
|
||||
|
||||
bool state = false;
|
||||
foreach (Unit minion in m_Controlled)
|
||||
{
|
||||
if (minion.IsInCombat())
|
||||
{
|
||||
state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state)
|
||||
AddUnitFlag(UnitFlags.PetInCombat);
|
||||
else
|
||||
RemoveUnitFlag(UnitFlags.PetInCombat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,14 +1514,7 @@ namespace Game.Entities
|
||||
SendCombatLogMessage(data);
|
||||
}
|
||||
|
||||
public void EnergizeBySpell(Unit victim, uint spellId, int damage, PowerType powerType)
|
||||
{
|
||||
SpellInfo info = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
|
||||
if (info != null)
|
||||
EnergizeBySpell(victim, info, damage, powerType);
|
||||
}
|
||||
|
||||
void EnergizeBySpell(Unit victim, SpellInfo spellInfo, int damage, PowerType powerType)
|
||||
public void EnergizeBySpell(Unit victim, SpellInfo spellInfo, int damage, PowerType powerType)
|
||||
{
|
||||
int gain = victim.ModifyPower(powerType, damage, false);
|
||||
int overEnergize = damage - gain;
|
||||
|
||||
+1567
-66
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user