Ported .Net Core commits:

hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
+443
View File
@@ -0,0 +1,443 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Collections;
using Framework.Constants;
using Framework.GameMath;
using Game.Network;
using Game.Spells;
using System;
namespace Game.Entities
{
public class CharmInfo
{
public CharmInfo(Unit unit)
{
_unit = unit;
_CommandState = CommandStates.Follow;
_petnumber = 0;
_oldReactState = ReactStates.Passive;
for (byte i = 0; i < SharedConst.MaxSpellCharm; ++i)
{
_charmspells[i] = new UnitActionBarEntry();
_charmspells[i].SetActionAndType(0, ActiveStates.Disabled);
}
for (var i = 0; i < SharedConst.ActionBarIndexMax; ++i)
PetActionBar[i] = new UnitActionBarEntry();
if (_unit.IsTypeId(TypeId.Unit))
{
_oldReactState = _unit.ToCreature().GetReactState();
_unit.ToCreature().SetReactState(ReactStates.Passive);
}
}
public void RestoreState()
{
if (_unit.IsTypeId(TypeId.Unit))
{
Creature creature = _unit.ToCreature();
if (creature)
creature.SetReactState(_oldReactState);
}
}
public void InitPetActionBar()
{
// the first 3 SpellOrActions are attack, follow and stay
for (byte i = 0; i < SharedConst.ActionBarIndexPetSpellStart - SharedConst.ActionBarIndexStart; ++i)
SetActionBar((byte)(SharedConst.ActionBarIndexStart + i), (uint)CommandStates.Attack - i, ActiveStates.Command);
// middle 4 SpellOrActions are spells/special attacks/abilities
for (byte i = 0; i < SharedConst.ActionBarIndexPetSpellEnd - SharedConst.ActionBarIndexPetSpellStart; ++i)
SetActionBar((byte)(SharedConst.ActionBarIndexPetSpellStart + i), 0, ActiveStates.Passive);
// last 3 SpellOrActions are reactions
for (byte i = 0; i < SharedConst.ActionBarIndexEnd - SharedConst.ActionBarIndexPetSpellEnd; ++i)
SetActionBar((byte)(SharedConst.ActionBarIndexPetSpellEnd + i), (uint)CommandStates.Attack - i, ActiveStates.Reaction);
}
public void InitEmptyActionBar(bool withAttack = true)
{
if (withAttack)
SetActionBar(SharedConst.ActionBarIndexStart, (uint)CommandStates.Attack, ActiveStates.Command);
else
SetActionBar(SharedConst.ActionBarIndexStart, 0, ActiveStates.Passive);
for (byte x = SharedConst.ActionBarIndexStart + 1; x < SharedConst.ActionBarIndexEnd; ++x)
SetActionBar(x, 0, ActiveStates.Passive);
}
public void InitPossessCreateSpells()
{
if (_unit.IsTypeId(TypeId.Unit))
{
// Adding switch until better way is found. Malcrom
// Adding entrys to this switch will prevent COMMAND_ATTACK being added to pet bar.
switch (_unit.GetEntry())
{
case 23575: // Mindless Abomination
case 24783: // Trained Rock Falcon
case 27664: // Crashin' Thrashin' Racer
case 40281: // Crashin' Thrashin' Racer
break;
default:
InitEmptyActionBar();
break;
}
for (byte i = 0; i < SharedConst.MaxCreatureSpells; ++i)
{
uint spellId = _unit.ToCreature().m_spells[i];
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
if (spellInfo != null)
{
if (spellInfo.IsPassive())
_unit.CastSpell(_unit, spellInfo, true);
else
AddSpellToActionBar(spellInfo, ActiveStates.Passive, i % SharedConst.ActionBarIndexMax);
}
}
}
else
InitEmptyActionBar();
}
public void InitCharmCreateSpells()
{
if (_unit.IsTypeId(TypeId.Player)) // charmed players don't have spells
{
InitEmptyActionBar();
return;
}
InitPetActionBar();
for (uint x = 0; x < SharedConst.MaxSpellCharm; ++x)
{
uint spellId = _unit.ToCreature().m_spells[x];
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
if (spellInfo == null)
{
_charmspells[x].SetActionAndType(spellId, ActiveStates.Disabled);
continue;
}
if (spellInfo.IsPassive())
{
_unit.CastSpell(_unit, spellInfo, true);
_charmspells[x].SetActionAndType(spellId, ActiveStates.Passive);
}
else
{
_charmspells[x].SetActionAndType(spellId, ActiveStates.Disabled);
ActiveStates newstate = ActiveStates.Passive;
if (!spellInfo.IsAutocastable())
newstate = ActiveStates.Passive;
else
{
if (spellInfo.NeedsExplicitUnitTarget())
{
newstate = ActiveStates.Enabled;
ToggleCreatureAutocast(spellInfo, true);
}
else
newstate = ActiveStates.Disabled;
}
AddSpellToActionBar(spellInfo, newstate);
}
}
}
public bool AddSpellToActionBar(SpellInfo spellInfo, ActiveStates newstate = ActiveStates.Decide, int preferredSlot = 0)
{
uint spell_id = spellInfo.Id;
uint first_id = spellInfo.GetFirstRankSpell().Id;
// new spell rank can be already listed
for (byte i = 0; i < SharedConst.ActionBarIndexMax; ++i)
{
uint action = PetActionBar[i].GetAction();
if (action != 0)
{
if (PetActionBar[i].IsActionBarForSpell() && Global.SpellMgr.GetFirstSpellInChain(action) == first_id)
{
PetActionBar[i].SetAction(spell_id);
return true;
}
}
}
// or use empty slot in other case
for (byte i = 0; i < SharedConst.ActionBarIndexMax; ++i)
{
byte j = (byte)((preferredSlot + i) % SharedConst.ActionBarIndexMax);
if (PetActionBar[j].GetAction() == 0 && PetActionBar[j].IsActionBarForSpell())
{
SetActionBar(j, spell_id, newstate == ActiveStates.Decide ? spellInfo.IsAutocastable() ? ActiveStates.Disabled : ActiveStates.Passive : newstate);
return true;
}
}
return false;
}
public bool RemoveSpellFromActionBar(uint spell_id)
{
uint first_id = Global.SpellMgr.GetFirstSpellInChain(spell_id);
for (byte i = 0; i < SharedConst.ActionBarIndexMax; ++i)
{
uint action = PetActionBar[i].GetAction();
if (action != 0)
{
if (PetActionBar[i].IsActionBarForSpell() && Global.SpellMgr.GetFirstSpellInChain(action) == first_id)
{
SetActionBar(i, 0, ActiveStates.Passive);
return true;
}
}
}
return false;
}
public void ToggleCreatureAutocast(SpellInfo spellInfo, bool apply)
{
if (spellInfo.IsPassive())
return;
for (uint x = 0; x < SharedConst.MaxSpellCharm; ++x)
if (spellInfo.Id == _charmspells[x].GetAction())
_charmspells[x].SetType(apply ? ActiveStates.Enabled : ActiveStates.Disabled);
}
public void SetPetNumber(uint petnumber, bool statwindow)
{
_petnumber = petnumber;
if (statwindow)
_unit.SetUInt32Value(UnitFields.PetNumber, _petnumber);
else
_unit.SetUInt32Value(UnitFields.PetNumber, 0);
}
public void LoadPetActionBar(string data)
{
InitPetActionBar();
var tokens = new StringArray(data, ' ');
if (tokens.Length != (SharedConst.ActionBarIndexEnd - SharedConst.ActionBarIndexStart) * 2)
return; // non critical, will reset to default
byte index = 0;
for (byte i = 0; i < tokens.Length && index < SharedConst.ActionBarIndexEnd; ++i, ++index)
{
ActiveStates type = tokens[i++].ToEnum<ActiveStates>();
uint action = uint.Parse(tokens[i]);
PetActionBar[index].SetActionAndType(action, type);
// check correctness
if (PetActionBar[index].IsActionBarForSpell())
{
SpellInfo spelInfo = Global.SpellMgr.GetSpellInfo(PetActionBar[index].GetAction());
if (spelInfo == null)
SetActionBar(index, 0, ActiveStates.Passive);
else if (!spelInfo.IsAutocastable())
SetActionBar(index, PetActionBar[index].GetAction(), ActiveStates.Passive);
}
}
}
public void BuildActionBar(WorldPacket data)
{
for (int i = 0; i < SharedConst.ActionBarIndexMax; ++i)
data.WriteUInt32(PetActionBar[i].packedData);
}
public void SetSpellAutocast(SpellInfo spellInfo, bool state)
{
for (byte i = 0; i < SharedConst.ActionBarIndexMax; ++i)
{
if (spellInfo.Id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
{
PetActionBar[i].SetType(state ? ActiveStates.Enabled : ActiveStates.Disabled);
break;
}
}
}
public void SetIsCommandAttack(bool val)
{
_isCommandAttack = val;
}
public bool IsCommandAttack()
{
return _isCommandAttack;
}
public void SetIsCommandFollow(bool val)
{
_isCommandFollow = val;
}
public bool IsCommandFollow()
{
return _isCommandFollow;
}
public void SaveStayPosition()
{
//! At this point a new spline destination is enabled because of Unit.StopMoving()
Vector3 stayPos = _unit.moveSpline.FinalDestination();
if (_unit.moveSpline.onTransport)
{
float o = 0;
ITransport transport = _unit.GetDirectTransport();
if (transport != null)
transport.CalculatePassengerPosition(ref stayPos.X, ref stayPos.Y, ref stayPos.Z, ref o);
}
_stayX = stayPos.X;
_stayY = stayPos.Y;
_stayZ = stayPos.Z;
}
public void GetStayPosition(out float x, out float y, out float z)
{
x = _stayX;
y = _stayY;
z = _stayZ;
}
public void SetIsAtStay(bool val)
{
_isAtStay = val;
}
public bool IsAtStay()
{
return _isAtStay;
}
public void SetIsFollowing(bool val)
{
_isFollowing = val;
}
public bool IsFollowing()
{
return _isFollowing;
}
public void SetIsReturning(bool val)
{
_isReturning = val;
}
public bool IsReturning()
{
return _isReturning;
}
public uint GetPetNumber() { return _petnumber; }
public void SetCommandState(CommandStates st) { _CommandState = st; }
public CommandStates GetCommandState() { return _CommandState; }
public bool HasCommandState(CommandStates state) { return (_CommandState == state); }
public void SetActionBar(byte index, uint spellOrAction, ActiveStates type)
{
PetActionBar[index].SetActionAndType(spellOrAction, type);
}
public UnitActionBarEntry GetActionBarEntry(byte index) { return PetActionBar[index]; }
public UnitActionBarEntry GetCharmSpell(byte index) { return _charmspells[index]; }
Unit _unit;
UnitActionBarEntry[] PetActionBar = new UnitActionBarEntry[SharedConst.ActionBarIndexMax];
UnitActionBarEntry[] _charmspells = new UnitActionBarEntry[4];
CommandStates _CommandState;
uint _petnumber;
ReactStates _oldReactState;
bool _isCommandAttack;
bool _isCommandFollow;
bool _isAtStay;
bool _isFollowing;
bool _isReturning;
float _stayX;
float _stayY;
float _stayZ;
}
public class UnitActionBarEntry
{
public UnitActionBarEntry()
{
packedData = (uint)ActiveStates.Disabled << 24;
}
public ActiveStates GetActiveState() { return (ActiveStates)UNIT_ACTION_BUTTON_TYPE(packedData); }
public uint GetAction() { return UNIT_ACTION_BUTTON_ACTION(packedData); }
public bool IsActionBarForSpell()
{
ActiveStates Type = GetActiveState();
return Type == ActiveStates.Disabled || Type == ActiveStates.Enabled || Type == ActiveStates.Passive;
}
public void SetActionAndType(uint action, ActiveStates type)
{
packedData = MAKE_UNIT_ACTION_BUTTON(action, (uint)type);
}
public void SetType(ActiveStates type)
{
packedData = MAKE_UNIT_ACTION_BUTTON(UNIT_ACTION_BUTTON_ACTION(packedData), (uint)type);
}
public void SetAction(uint action)
{
packedData = (packedData & 0xFF000000) | UNIT_ACTION_BUTTON_ACTION(action);
}
public uint packedData;
public static uint MAKE_UNIT_ACTION_BUTTON(uint action, uint type)
{
return (action | (type << 24));
}
public static uint UNIT_ACTION_BUTTON_ACTION(uint packedData)
{
return (packedData & 0x00FFFFFF);
}
public static uint UNIT_ACTION_BUTTON_TYPE(uint packedData)
{
return ((packedData & 0xFF000000) >> 24);
}
}
}
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using System;
using System.Collections.Generic;
namespace Game.Entities
{
public class PowerPctOrderPred : IComparer<WorldObject>
{
public PowerPctOrderPred(PowerType power, bool ascending = true)
{
m_power = power;
m_ascending = ascending;
}
public int Compare(WorldObject objA, WorldObject objB)
{
Unit a = objA.ToUnit();
Unit b = objB.ToUnit();
float rA = a.GetMaxPower(m_power) != 0 ? a.GetPower(m_power) / (float)a.GetMaxPower(m_power) : 0.0f;
float rB = b.GetMaxPower(m_power) != 0 ? b.GetPower(m_power) / (float)b.GetMaxPower(m_power) : 0.0f;
return Convert.ToInt32(m_ascending ? rA < rB : rA > rB);
}
PowerType m_power;
bool m_ascending;
}
public class HealthPctOrderPred : IComparer<WorldObject>
{
public HealthPctOrderPred(bool ascending = true)
{
m_ascending = ascending;
}
public int Compare(WorldObject objA, WorldObject objB)
{
Unit a = objA.ToUnit();
Unit b = objB.ToUnit();
float rA = a.GetMaxHealth() != 0 ? a.GetHealth() / (float)a.GetMaxHealth() : 0.0f;
float rB = b.GetMaxHealth() != 0 ? b.GetHealth() / (float)b.GetMaxHealth() : 0.0f;
return Convert.ToInt32(m_ascending ? rA < rB : rA > rB);
}
bool m_ascending;
}
public class ObjectDistanceOrderPred : IComparer<WorldObject>
{
public ObjectDistanceOrderPred(WorldObject pRefObj, bool ascending = true)
{
m_refObj = pRefObj;
m_ascending = ascending;
}
public int Compare(WorldObject pLeft, WorldObject pRight)
{
return (m_ascending ? m_refObj.GetDistanceOrder(pLeft, pRight) : !m_refObj.GetDistanceOrder(pLeft, pRight)) ? 1 : 0;
}
WorldObject m_refObj;
bool m_ascending;
}
}
File diff suppressed because it is too large Load Diff
+646
View File
@@ -0,0 +1,646 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Collections;
using Framework.Constants;
using Framework.Dynamic;
using Game.AI;
using Game.Combat;
using Game.DataStorage;
using Game.Maps;
using Game.Movement;
using Game.Network.Packets;
using Game.Spells;
using System;
using System.Collections.Generic;
namespace Game.Entities
{
public partial class Unit
{
//AI
protected UnitAI i_AI;
protected UnitAI i_disabledAI;
public bool IsAIEnabled { get; set; }
public bool NeedChangeAI { get; set; }
//Movement
protected float[] m_speed_rate = new float[(int)UnitMoveType.Max];
RefManager<Unit, TargetedMovementGeneratorBase> m_FollowingRefManager;
public MoveSpline moveSpline { get; set; }
MotionMaster i_motionMaster;
public uint m_movementCounter; //< Incrementing counter used in movement packets
TimeTrackerSmall movesplineTimer;
public Player m_playerMovingMe;
//Combat
protected List<Unit> attackerList = new List<Unit>();
Dictionary<ReactiveType, uint> m_reactiveTimer = new Dictionary<ReactiveType, uint>();
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 m_HostileRefManager;
RedirectThreatInfo _redirectThreatInfo;
protected Unit m_attacking;
public float m_modMeleeHitChance { get; set; }
public float m_modRangedHitChance { get; set; }
public float m_modSpellHitChance { get; set; }
long _lastDamagedTime;
bool m_canDualWield;
public int m_baseSpellCritChance { get; set; }
public uint m_regenTimer { get; set; }
uint m_CombatTimer;
public uint m_extraAttacks { get; set; }
//Charm
public List<Unit> m_Controlled = new List<Unit>();
List<Player> m_sharedVision = new List<Player>();
CharmInfo m_charmInfo;
protected bool m_ControlledByPlayer;
public ObjectGuid LastCharmerGUID { get; set; }
uint _oldFactionId; // faction before charm
bool _isWalkingBeforeCharm; // Are we walking before we were charmed?
//Spells
protected Dictionary<CurrentSpellTypes, Spell> m_currentSpells = new Dictionary<CurrentSpellTypes, Spell>((int)CurrentSpellTypes.Max);
Dictionary<SpellValueMod, int> CustomSpellValueMod = new Dictionary<SpellValueMod, int>();
MultiMap<SpellImmunity, SpellImmune> m_spellImmune = new MultiMap<SpellImmunity, SpellImmune>();
uint m_interruptMask;
protected int m_procDeep;
bool m_AutoRepeatFirstCast;
SpellHistory _spellHistory;
//Auras
public List<PetAura> m_petAuras = new List<PetAura>();
List<AuraEffect> AuraEffectList = new List<AuraEffect>();
MultiMap<AuraType, AuraEffect> m_modAuras = new MultiMap<AuraType, AuraEffect>();
List<Aura> m_removedAuras = new List<Aura>();
List<AuraApplication> m_interruptableAuras = new List<AuraApplication>(); // auras which have interrupt mask applied on unit
MultiMap<AuraStateType, AuraApplication> m_auraStateAuras = new MultiMap<AuraStateType, AuraApplication>(); // Used for improve performance of aura state checks on aura apply/remove
SortedSet<AuraApplication> m_visibleAuras = new SortedSet<AuraApplication>(new VisibleAuraSlotCompare());
SortedSet<AuraApplication> m_visibleAurasToUpdate = new SortedSet<AuraApplication>(new VisibleAuraSlotCompare());
MultiMap<uint, AuraApplication> m_appliedAuras = new MultiMap<uint, AuraApplication>();
MultiMap<uint, Aura> m_ownedAuras = new MultiMap<uint, Aura>();
List<Aura> m_scAuras = new List<Aura>();
protected float[][] m_auraModifiersGroup = new float[(int)UnitMods.End][];
uint m_removedAurasCount;
//General
Array<DiminishingReturn> m_Diminishing = new Array<DiminishingReturn>((int)DiminishingGroup.Max);
protected List<GameObject> m_gameObj = new List<GameObject>();
List<AreaTrigger> m_areaTrigger = new List<AreaTrigger>();
protected List<DynamicObject> m_dynObj = new List<DynamicObject>();
protected float[] CreateStats = new float[(int)Stats.Max];
public ObjectGuid[] m_SummonSlot = new ObjectGuid[7];
public ObjectGuid[] m_ObjectSlot = new ObjectGuid[4];
public EventSystem m_Events = new EventSystem();
public UnitTypeMask m_unitTypeMask { get; set; }
UnitState m_state;
protected LiquidTypeRecord _lastLiquid;
protected DeathState m_deathState;
public Vehicle m_vehicle { get; set; }
public Vehicle m_vehicleKit { get; set; }
bool canModifyStats;
public uint m_lastSanctuaryTime { get; set; }
uint m_transform;
bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
ushort _aiAnimKitId;
ushort _movementAnimKitId;
ushort _meleeAnimKitId;
}
public struct SpellImmune
{
public uint spellType;
public uint spellId;
}
public class DiminishingReturn
{
public DiminishingReturn(uint hitTime, DiminishingLevels hitCount)
{
Stack = 0;
HitTime = hitTime;
HitCount = hitCount;
}
public void Clear()
{
Stack = 0;
HitTime = 0;
HitCount = DiminishingLevels.Level1;
}
public uint Stack;
public uint HitTime;
public DiminishingLevels HitCount;
}
public class ProcEventInfo
{
public ProcEventInfo(Unit actor, Unit actionTarget, Unit procTarget, ProcFlags typeMask, ProcFlagsSpellType spellTypeMask,
ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo)
{
_actor = actor;
_actionTarget = actionTarget;
_procTarget = procTarget;
_typeMask = typeMask;
_spellTypeMask = spellTypeMask;
_spellPhaseMask = spellPhaseMask;
_hitMask = hitMask;
_spell = spell;
_damageInfo = damageInfo;
_healInfo = healInfo;
}
public Unit GetActor() { return _actor; }
public Unit GetActionTarget() { return _actionTarget; }
public Unit GetProcTarget() { return _procTarget; }
public ProcFlags GetTypeMask() { return _typeMask; }
public ProcFlagsSpellType GetSpellTypeMask() { return _spellTypeMask; }
public ProcFlagsSpellPhase GetSpellPhaseMask() { return _spellPhaseMask; }
public ProcFlagsHit GetHitMask() { return _hitMask; }
public SpellInfo GetSpellInfo()
{
if (_spell)
return _spell.GetSpellInfo();
if (_damageInfo != null)
return _damageInfo.GetSpellInfo();
if (_healInfo != null)
return _healInfo.GetSpellInfo();
return null;
}
public SpellSchoolMask GetSchoolMask()
{
if (_spell)
return _spell.GetSpellInfo().GetSchoolMask();
if (_damageInfo != null)
return _damageInfo.GetSchoolMask();
if (_healInfo != null)
return _healInfo.GetSchoolMask();
return SpellSchoolMask.None;
}
public DamageInfo GetDamageInfo() { return _damageInfo; }
public HealInfo GetHealInfo() { return _healInfo; }
public Spell GetProcSpell() { return _spell; }
Unit _actor;
Unit _actionTarget;
Unit _procTarget;
ProcFlags _typeMask;
ProcFlagsSpellType _spellTypeMask;
ProcFlagsSpellPhase _spellPhaseMask;
ProcFlagsHit _hitMask;
Spell _spell;
DamageInfo _damageInfo;
HealInfo _healInfo;
}
public class DamageInfo
{
public DamageInfo(Unit attacker, Unit victim, uint damage, SpellInfo spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
{
m_attacker = attacker;
m_victim = victim;
m_damage = damage;
m_spellInfo = spellInfo;
m_schoolMask = schoolMask;
m_damageType = damageType;
m_attackType = attackType;
}
public DamageInfo(CalcDamageInfo dmgInfo)
{
m_attacker = dmgInfo.attacker;
m_victim = dmgInfo.target;
m_damage = dmgInfo.damage;
m_spellInfo = null;
m_schoolMask = (SpellSchoolMask)dmgInfo.damageSchoolMask;
m_damageType = DamageEffectType.Direct;
m_attackType = dmgInfo.attackType;
m_absorb = dmgInfo.absorb;
m_resist = dmgInfo.resist;
m_block = dmgInfo.blocked_amount;
switch (dmgInfo.TargetState)
{
case VictimState.Immune:
m_hitMask |= ProcFlagsHit.Immune;
break;
case VictimState.Blocks:
m_hitMask |= ProcFlagsHit.FullBlock;
break;
}
if (m_absorb != 0)
m_hitMask |= ProcFlagsHit.Absorb;
if (dmgInfo.HitInfo.HasAnyFlag(HitInfo.FullResist))
m_hitMask |= ProcFlagsHit.FullResist;
if (m_block != 0)
m_hitMask |= ProcFlagsHit.Block;
switch (dmgInfo.hitOutCome)
{
case MeleeHitOutcome.Miss:
m_hitMask |= ProcFlagsHit.Miss;
break;
case MeleeHitOutcome.Dodge:
m_hitMask |= ProcFlagsHit.Dodge;
break;
case MeleeHitOutcome.Parry:
m_hitMask |= ProcFlagsHit.Parry;
break;
case MeleeHitOutcome.Evade:
m_hitMask |= ProcFlagsHit.Evade;
break;
case MeleeHitOutcome.Crushing:
case MeleeHitOutcome.Glancing:
case MeleeHitOutcome.Normal:
m_hitMask |= ProcFlagsHit.Normal;
break;
case MeleeHitOutcome.Crit:
m_hitMask |= ProcFlagsHit.Critical;
break;
default:
break;
}
}
public DamageInfo(SpellNonMeleeDamage spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, ProcFlagsHit hitMask)
{
m_attacker = spellNonMeleeDamage.attacker;
m_victim = spellNonMeleeDamage.target;
m_damage = spellNonMeleeDamage.damage;
m_spellInfo = Global.SpellMgr.GetSpellInfo(spellNonMeleeDamage.SpellId);
m_schoolMask = spellNonMeleeDamage.schoolMask;
m_damageType = damageType;
m_attackType = attackType;
m_absorb = spellNonMeleeDamage.absorb;
m_resist = spellNonMeleeDamage.resist;
m_block = spellNonMeleeDamage.blocked;
m_hitMask = hitMask;
if (spellNonMeleeDamage.blocked != 0)
m_hitMask |= ProcFlagsHit.Block;
if (spellNonMeleeDamage.absorb != 0)
m_hitMask |= ProcFlagsHit.Absorb;
}
public void ModifyDamage(int amount)
{
amount = Math.Min(amount, (int)GetDamage());
m_damage += (uint)amount;
}
public void AbsorbDamage(uint amount)
{
amount = Math.Min(amount, GetDamage());
m_absorb += amount;
m_damage -= amount;
m_hitMask |= ProcFlagsHit.Absorb;
}
public void ResistDamage(uint amount)
{
amount = Math.Min(amount, GetDamage());
m_resist += amount;
m_damage -= amount;
if (m_damage == 0)
m_hitMask |= ProcFlagsHit.FullResist;
}
void BlockDamage(uint amount)
{
amount = Math.Min(amount, GetDamage());
m_block += amount;
m_damage -= amount;
m_hitMask |= ProcFlagsHit.Block;
if (m_damage == 0)
m_hitMask |= ProcFlagsHit.FullBlock;
}
public Unit GetAttacker() { return m_attacker; }
public Unit GetVictim() { return m_victim; }
public SpellInfo GetSpellInfo() { return m_spellInfo; }
public SpellSchoolMask GetSchoolMask() { return m_schoolMask; }
DamageEffectType GetDamageType() { return m_damageType; }
public WeaponAttackType GetAttackType() { return m_attackType; }
public uint GetDamage() { return m_damage; }
public uint GetAbsorb() { return m_absorb; }
public uint GetResist() { return m_resist; }
uint GetBlock() { return m_block; }
public ProcFlagsHit GetHitMask() { return m_hitMask; }
Unit m_attacker;
Unit m_victim;
uint m_damage;
SpellInfo m_spellInfo;
SpellSchoolMask m_schoolMask;
DamageEffectType m_damageType;
WeaponAttackType m_attackType;
uint m_absorb;
uint m_resist;
uint m_block;
ProcFlagsHit m_hitMask;
}
public class HealInfo
{
public HealInfo(Unit healer, Unit target, uint heal, SpellInfo spellInfo, SpellSchoolMask schoolMask)
{
_healer = healer;
_target = target;
_heal = heal;
_spellInfo = spellInfo;
_schoolMask = schoolMask;
}
public void AbsorbHeal(uint amount)
{
amount = Math.Min(amount, GetHeal());
_absorb += amount;
_heal -= amount;
amount = Math.Min(amount, GetEffectiveHeal());
_effectiveHeal -= amount;
_hitMask |= ProcFlagsHit.Absorb;
}
public void SetEffectiveHeal(uint amount) { _effectiveHeal = amount; }
public Unit GetHealer() { return _healer; }
public Unit GetTarget() { return _target; }
public uint GetHeal() { return _heal; }
public uint GetEffectiveHeal() { return _effectiveHeal; }
public uint GetAbsorb() { return _absorb; }
public SpellInfo GetSpellInfo() { return _spellInfo; }
public SpellSchoolMask GetSchoolMask() { return _schoolMask; }
ProcFlagsHit GetHitMask() { return _hitMask; }
Unit _healer;
Unit _target;
uint _heal;
uint _effectiveHeal;
uint _absorb;
SpellInfo _spellInfo;
SpellSchoolMask _schoolMask;
ProcFlagsHit _hitMask;
}
public class CalcDamageInfo
{
public Unit attacker { get; set; } // Attacker
public Unit target { get; set; } // Target for damage
public uint damageSchoolMask { get; set; }
public uint damage;
public uint absorb;
public uint resist;
public uint blocked_amount { get; set; }
public HitInfo HitInfo { get; set; }
public VictimState TargetState { get; set; }
// Helper
public WeaponAttackType attackType { get; set; }
public ProcFlags procAttacker { get; set; }
public ProcFlags procVictim { get; set; }
public uint cleanDamage { get; set; } // Used only for rage calculation
public MeleeHitOutcome hitOutCome { get; set; } // TODO: remove this field (need use TargetState)
}
public class SpellNonMeleeDamage
{
public SpellNonMeleeDamage(Unit _attacker, Unit _target, uint _SpellID, uint _SpellXSpellVisualID, SpellSchoolMask _schoolMask, ObjectGuid _castId = default(ObjectGuid))
{
target = _target;
attacker = _attacker;
SpellId = _SpellID;
SpellXSpellVisualID = _SpellXSpellVisualID;
schoolMask = _schoolMask;
castId = _castId;
preHitHealth = (uint)_target.GetHealth();
}
public Unit target;
public Unit attacker;
public ObjectGuid castId;
public uint SpellId;
public uint SpellXSpellVisualID;
public uint damage;
public SpellSchoolMask schoolMask;
public uint absorb;
public uint resist;
public bool periodicLog;
public uint blocked;
public SpellHitType HitInfo;
// Used for help
public uint cleanDamage;
public uint preHitHealth;
}
public class CleanDamage
{
public CleanDamage(uint mitigated, uint absorbed, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome)
{
absorbed_damage = absorbed;
mitigated_damage = mitigated;
attackType = _attackType;
hitOutCome = _hitOutCome;
}
public uint absorbed_damage { get; set; }
public uint mitigated_damage { get; set; }
public WeaponAttackType attackType { get; set; }
public MeleeHitOutcome hitOutCome { get; set; }
}
public class DispelInfo
{
public DispelInfo(Unit dispeller, uint dispellerSpellId, byte chargesRemoved)
{
_dispellerUnit = dispeller;
_dispellerSpell = dispellerSpellId;
_chargesRemoved = chargesRemoved;
}
public Unit GetDispeller() { return _dispellerUnit; }
uint GetDispellerSpellId() { return _dispellerSpell; }
public byte GetRemovedCharges() { return _chargesRemoved; }
void SetRemovedCharges(byte amount)
{
_chargesRemoved = amount;
}
Unit _dispellerUnit;
uint _dispellerSpell;
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, int _overDamage, uint _absorb, uint _resist, float _multiplier, bool _critical)
{
auraEff = _auraEff;
damage = _damage;
overDamage = _overDamage;
absorb = _absorb;
resist = _resist;
multiplier = _multiplier;
critical = _critical;
}
public AuraEffect auraEff;
public uint damage;
public int overDamage; // overkill/overheal
public uint absorb;
public uint resist;
public float multiplier;
public bool critical;
}
class VisibleAuraSlotCompare : IComparer<AuraApplication>
{
public int Compare(AuraApplication x, AuraApplication y)
{
return x.GetSlot().CompareTo(y.GetSlot());
}
}
public class DeclinedName
{
public StringArray name = new StringArray(SharedConst.MaxDeclinedNameCases);
}
class CombatLogSender : Notifier
{
public CombatLogSender(WorldObject src, CombatLogServerPacket msg, float dist)
{
i_source = src;
i_message = msg;
i_distSq = dist * dist;
}
bool IsInRangeHelper(WorldObject obj)
{
if (!obj.IsInPhase(i_source))
return false;
return obj.GetExactDist2dSq(i_source) <= i_distSq;
}
public override void Visit(ICollection<Player> objs)
{
foreach (var target in objs)
{
if (!IsInRangeHelper(target))
continue;
// Send packet to all who are sharing the player's vision
if (target.HasSharedVision())
{
foreach (var visionTarget in target.GetSharedVisionList())
if (visionTarget.seerView == target)
SendPacket(visionTarget);
}
if (target.seerView == target || target.GetVehicle())
SendPacket(target);
}
}
public override void Visit(ICollection<Creature> objs)
{
foreach (var target in objs)
{
if (!IsInRangeHelper(target))
continue;
// Send packet to all who are sharing the creature's vision
if (target.HasSharedVision())
{
foreach (var visionTarget in target.GetSharedVisionList())
if (visionTarget.seerView == target)
SendPacket(visionTarget);
}
}
}
public override void Visit(ICollection<DynamicObject> objs)
{
foreach (var target in objs)
{
if (!IsInRangeHelper(target))
continue;
Unit caster = target.GetCaster();
if (caster)
{
// Send packet back to the caster if the caster has vision of dynamic object
Player player = caster.ToPlayer();
if (player && player.seerView == target)
SendPacket(player);
}
}
}
void SendPacket(Player player)
{
if (!player.HaveAtClient(i_source))
return;
if (!player.IsAdvancedCombatLoggingEnabled())
i_message.DisableAdvancedCombatLogging();
player.SendPacket(i_message);
}
WorldObject i_source;
CombatLogServerPacket i_message;
float i_distSq;
}
}
File diff suppressed because it is too large Load Diff
+796
View File
@@ -0,0 +1,796 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.AI;
using Game.Network.Packets;
using Game.Spells;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
namespace Game.Entities
{
public partial class Unit
{
public void AddPetAura(PetAura petSpell)
{
if (!IsTypeId(TypeId.Player))
return;
m_petAuras.Add(petSpell);
Pet pet = ToPlayer().GetPet();
if (pet)
pet.CastPetAura(petSpell);
}
public void RemovePetAura(PetAura petSpell)
{
if (!IsTypeId(TypeId.Player))
return;
m_petAuras.Remove(petSpell);
Pet pet = ToPlayer().GetPet();
if (pet)
pet.RemoveAurasDueToSpell(petSpell.GetAura(pet.GetEntry()));
}
public CharmInfo GetCharmInfo() { return m_charmInfo; }
public CharmInfo InitCharmInfo()
{
if (m_charmInfo == null)
m_charmInfo = new CharmInfo(this);
return m_charmInfo;
}
void DeleteCharmInfo()
{
if (m_charmInfo == null)
return;
m_charmInfo.RestoreState();
m_charmInfo = null;
}
public void UpdateCharmAI()
{
switch (GetTypeId())
{
case TypeId.Unit:
if (i_disabledAI != null) // disabled AI must be primary AI
{
if (!IsCharmed())
{
i_AI = i_disabledAI;
i_disabledAI = null;
if (IsTypeId(TypeId.Unit))
ToCreature().GetAI().OnCharmed(false);
}
}
else
{
if (IsCharmed())
{
i_disabledAI = i_AI;
if (isPossessed() || IsVehicle())
i_AI = new PossessedAI(ToCreature());
else
i_AI = new PetAI(ToCreature());
}
}
break;
case TypeId.Player:
{
if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI
{
i_disabledAI = i_AI;
UnitAI newAI = null;
// first, we check if the creature's own AI specifies an override playerai for its owned players
Unit charmer = GetCharmer();
if (charmer)
{
Creature creatureCharmer = charmer.ToCreature();
if (creatureCharmer)
{
PlayerAI charmAI = creatureCharmer.IsAIEnabled ? creatureCharmer.GetAI().GetAIForCharmedPlayer(ToPlayer()) : null;
if (charmAI != null)
newAI = charmAI;
}
else
{
Log.outError(LogFilter.Misc, "Attempt to assign charm AI to player {0} who is charmed by non-creature {1}.", GetGUID().ToString(), GetCharmerGUID().ToString());
}
}
if (newAI == null) // otherwise, we default to the generic one
newAI = new SimpleCharmedPlayerAI(ToPlayer());
i_AI = newAI;
newAI.OnCharmed(true);
}
else
{
if (i_AI != null)
{
// we allow the charmed PlayerAI to clean up
i_AI.OnCharmed(false);
}
else
{
Log.outError(LogFilter.Misc, "Attempt to remove charm AI from player {0} who doesn't currently have charm AI.", GetGUID().ToString());
}
// and restore our previous PlayerAI (if we had one)
i_AI = i_disabledAI;
i_disabledAI = null;
// IsAIEnabled gets handled in the caller
}
break;
}
default:
Log.outError(LogFilter.Misc, "Attempt to update charm AI for unit {0}, which is neither player nor creature.", GetGUID().ToString());
break;
}
}
public void SetMinion(Minion minion, bool apply)
{
Log.outDebug(LogFilter.Unit, "SetMinion {0} for {1}, apply {2}", minion.GetEntry(), GetEntry(), apply);
if (apply)
{
if (!minion.GetOwnerGUID().IsEmpty())
{
Log.outFatal(LogFilter.Unit, "SetMinion: Minion {0} is not the minion of owner {1}", minion.GetEntry(), GetEntry());
return;
}
minion.SetOwnerGUID(GetGUID());
m_Controlled.Add(minion);
if (IsTypeId(TypeId.Player))
{
minion.m_ControlledByPlayer = true;
minion.SetFlag(UnitFields.Flags, UnitFlags.PvpAttackable);
}
// Can only have one pet. If a new one is summoned, dismiss the old one.
if (minion.IsGuardianPet())
{
Guardian oldPet = GetGuardianPet();
if (oldPet)
{
if (oldPet != minion && (oldPet.IsPet() || minion.IsPet() || oldPet.GetEntry() != minion.GetEntry()))
{
// remove existing minion pet
if (oldPet.IsPet())
((Pet)oldPet).Remove(PetSaveMode.AsCurrent);
else
oldPet.UnSummon();
SetPetGUID(minion.GetGUID());
SetMinionGUID(ObjectGuid.Empty);
}
}
else
{
SetPetGUID(minion.GetGUID());
SetMinionGUID(ObjectGuid.Empty);
}
}
if (minion.HasUnitTypeMask(UnitTypeMask.Guardian))
AddGuidValue(UnitFields.Summon, minion.GetGUID());
if (minion.m_Properties != null && minion.m_Properties.Type == SummonType.Minipet)
SetCritterGUID(minion.GetGUID());
// PvP, FFAPvP
minion.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag));
// FIXME: hack, speed must be set only at follow
if (IsTypeId(TypeId.Player) && minion.IsPet())
for (UnitMoveType i = 0; i < UnitMoveType.Max; ++i)
minion.SetSpeedRate(i, m_speed_rate[(int)i]);
// Ghoul pets have energy instead of mana (is anywhere better place for this code?)
if (minion.IsPetGhoul())
minion.setPowerType(PowerType.Energy);
// Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.GetUInt32Value(UnitFields.CreatedBySpell));
if (spellInfo != null && spellInfo.IsCooldownStartedOnEvent())
GetSpellHistory().StartCooldown(spellInfo, 0, null, true);
}
else
{
if (minion.GetOwnerGUID() != GetGUID())
{
Log.outFatal(LogFilter.Unit, "SetMinion: Minion {0} is not the minion of owner {1}", minion.GetEntry(), GetEntry());
return;
}
m_Controlled.Remove(minion);
if (minion.m_Properties != null && minion.m_Properties.Type == SummonType.Minipet)
{
if (GetCritterGUID() == minion.GetGUID())
SetCritterGUID(ObjectGuid.Empty);
}
if (minion.IsGuardianPet())
{
if (GetPetGUID() == minion.GetGUID())
SetPetGUID(ObjectGuid.Empty);
}
else if (minion.IsTotem())
{
// All summoned by totem minions must disappear when it is removed.
SpellInfo spInfo = Global.SpellMgr.GetSpellInfo(minion.ToTotem().GetSpell());
if (spInfo != null)
{
foreach (SpellEffectInfo effect in spInfo.GetEffectsForDifficulty(Difficulty.None))
{
if (effect == null || effect.Effect != SpellEffectName.Summon)
continue;
RemoveAllMinionsByEntry((uint)effect.MiscValue);
}
}
}
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.GetUInt32Value(UnitFields.CreatedBySpell));
// Remove infinity cooldown
if (spellInfo != null && spellInfo.IsCooldownStartedOnEvent())
GetSpellHistory().SendCooldownEvent(spellInfo);
if (RemoveGuidValue(UnitFields.Summon, minion.GetGUID()))
{
// Check if there is another minion
foreach (var unit in m_Controlled)
{
// do not use this check, creature do not have charm guid
if (GetGUID() == unit.GetCharmerGUID())
continue;
Contract.Assert(unit.GetOwnerGUID() == GetGUID());
if (unit.GetOwnerGUID() != GetGUID())
{
Contract.Assert(false);
}
Contract.Assert(unit.IsTypeId(TypeId.Unit));
if (!unit.HasUnitTypeMask(UnitTypeMask.Guardian))
continue;
if (AddGuidValue(UnitFields.Summon, unit.GetGUID()))
{
// show another pet bar if there is no charm bar
if (IsTypeId(TypeId.Player) && GetCharmGUID().IsEmpty())
{
if (unit.IsPet())
ToPlayer().PetSpellInitialize();
else
ToPlayer().CharmSpellInitialize();
}
}
break;
}
}
}
}
public bool SetCharmedBy(Unit charmer, CharmType type, AuraApplication aurApp = null)
{
if (!charmer)
return false;
// dismount players when charmed
if (IsTypeId(TypeId.Player))
RemoveAurasByType(AuraType.Mounted);
if (charmer.IsTypeId(TypeId.Player))
charmer.RemoveAurasByType(AuraType.Mounted);
Contract.Assert(type != CharmType.Possess || charmer.IsTypeId(TypeId.Player));
Contract.Assert((type == CharmType.Vehicle) == IsVehicle());
Log.outDebug(LogFilter.Unit, "SetCharmedBy: charmer {0} (GUID {1}), charmed {2} (GUID {3}), type {4}.", charmer.GetEntry(), charmer.GetGUID().ToString(), GetEntry(), GetGUID().ToString(), type);
if (this == charmer)
{
Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Unit {0} (GUID {1}) is trying to charm itself!", GetEntry(), GetGUID().ToString());
return false;
}
if (IsTypeId(TypeId.Player) && ToPlayer().GetTransport())
{
Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Player on transport is trying to charm {0} (GUID {1})", GetEntry(), GetGUID().ToString());
return false;
}
// Already charmed
if (!GetCharmerGUID().IsEmpty())
{
Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) has already been charmed but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString());
return false;
}
CastStop();
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
DeleteThreatList();
Player playerCharmer = charmer.ToPlayer();
// Charmer stop charming
if (playerCharmer)
{
playerCharmer.StopCastingCharm();
playerCharmer.StopCastingBindSight();
}
// Charmed stop charming
if (IsTypeId(TypeId.Player))
{
ToPlayer().StopCastingCharm();
ToPlayer().StopCastingBindSight();
}
// StopCastingCharm may remove a possessed pet?
if (!IsInWorld)
{
Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) is not in world but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString());
return false;
}
// charm is set by aura, and aura effect remove handler was called during apply handler execution
// prevent undefined behaviour
if (aurApp != null && aurApp.GetRemoveMode() != 0)
return false;
_oldFactionId = getFaction();
SetFaction(charmer.getFaction());
// Set charmed
charmer.SetCharm(this, true);
Player player;
if (IsTypeId(TypeId.Unit))
{
ToCreature().GetAI().OnCharmed(true);
GetMotionMaster().MoveIdle();
}
else if (player = ToPlayer())
{
if (player.isAFK())
player.ToggleAFK();
Creature creatureCharmer = charmer.ToCreature();
if (charmer.IsTypeId(TypeId.Unit)) // we are charmed by a creature
{
// change AI to charmed AI on next Update tick
NeedChangeAI = true;
if (IsAIEnabled)
{
IsAIEnabled = false;
player.GetAI().OnCharmed(true);
}
}
player.SetClientControl(this, false);
}
// charm is set by aura, and aura effect remove handler was called during apply handler execution
// prevent undefined behaviour
if (aurApp != null && aurApp.GetRemoveMode() != 0)
return false;
// Pets already have a properly initialized CharmInfo, don't overwrite it.
if (type != CharmType.Vehicle && GetCharmInfo() == null)
{
InitCharmInfo();
if (type == CharmType.Possess)
GetCharmInfo().InitPossessCreateSpells();
else
GetCharmInfo().InitCharmCreateSpells();
}
if (playerCharmer)
{
switch (type)
{
case CharmType.Vehicle:
SetFlag(UnitFields.Flags, UnitFlags.PlayerControlled);
playerCharmer.SetClientControl(this, true);
playerCharmer.VehicleSpellInitialize();
break;
case CharmType.Possess:
AddUnitState(UnitState.Possessed);
SetFlag(UnitFields.Flags, UnitFlags.PlayerControlled);
charmer.SetFlag(UnitFields.Flags, UnitFlags.RemoveClientControl);
playerCharmer.SetClientControl(this, true);
playerCharmer.PossessSpellInitialize();
break;
case CharmType.Charm:
if (IsTypeId(TypeId.Unit) && charmer.GetClass() == Class.Warlock)
{
CreatureTemplate cinfo = ToCreature().GetCreatureTemplate();
if (cinfo != null && cinfo.CreatureType == CreatureType.Demon)
{
// to prevent client crash
SetByteValue(UnitFields.Bytes0, 1, (byte)Class.Mage);
// just to enable stat window
if (GetCharmInfo() != null)
GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true);
// if charmed two demons the same session, the 2nd gets the 1st one's name
SetUInt32Value(UnitFields.PetNameTimestamp, (uint)Time.UnixTime); // cast can't be helped
}
}
playerCharmer.CharmSpellInitialize();
break;
default:
case CharmType.Convert:
break;
}
}
return true;
}
public void RemoveCharmedBy(Unit charmer)
{
if (!IsCharmed())
return;
if (!charmer)
charmer = GetCharmer();
if (charmer != GetCharmer()) // one aura overrides another?
return;
CharmType type;
if (HasUnitState(UnitState.Possessed))
type = CharmType.Possess;
else if (charmer && charmer.IsOnVehicle(this))
type = CharmType.Vehicle;
else
type = CharmType.Charm;
CastStop();
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
getHostileRefManager().deleteReferences();
DeleteThreatList();
if (_oldFactionId != 0)
{
SetFaction(_oldFactionId);
_oldFactionId = 0;
}
else
RestoreFaction();
GetMotionMaster().InitDefault();
Creature creature = ToCreature();
if (creature)
{
// Creature will restore its old AI on next update
if (creature.GetAI() != null)
creature.GetAI().OnCharmed(false);
// Vehicle should not attack its passenger after he exists the seat
if (type != CharmType.Vehicle)
LastCharmerGUID = charmer ? charmer.GetGUID() : ObjectGuid.Empty;
}
// If charmer still exists
if (!charmer)
return;
Contract.Assert(type != CharmType.Possess || charmer.IsTypeId(TypeId.Player));
Contract.Assert(type != CharmType.Vehicle || (IsTypeId(TypeId.Unit) && IsVehicle()));
charmer.SetCharm(this, false);
Player playerCharmer = charmer.ToPlayer();
if (playerCharmer)
{
switch (type)
{
case CharmType.Vehicle:
playerCharmer.SetClientControl(this, false);
playerCharmer.SetClientControl(charmer, true);
RemoveFlag(UnitFields.Flags, UnitFlags.PlayerControlled);
break;
case CharmType.Possess:
playerCharmer.SetClientControl(this, false);
playerCharmer.SetClientControl(charmer, true);
charmer.RemoveFlag(UnitFields.Flags, UnitFlags.RemoveClientControl);
RemoveFlag(UnitFields.Flags, UnitFlags.PlayerControlled);
ClearUnitState(UnitState.Possessed);
break;
case CharmType.Charm:
if (IsTypeId(TypeId.Unit) && charmer.GetClass() == Class.Warlock)
{
CreatureTemplate cinfo = ToCreature().GetCreatureTemplate();
if (cinfo != null && cinfo.CreatureType == CreatureType.Demon)
{
SetByteValue(UnitFields.Bytes0, 1, (byte)cinfo.UnitClass);
if (GetCharmInfo() != null)
GetCharmInfo().SetPetNumber(0, true);
else
Log.outError(LogFilter.Unit, "Aura:HandleModCharm: target={0} with typeid={1} has a charm aura but no charm info!", GetGUID(), GetTypeId());
}
}
break;
case CharmType.Convert:
break;
}
}
Player player = ToPlayer();
if (player)
{
if (charmer.IsTypeId(TypeId.Unit)) // charmed by a creature, this means we had PlayerAI
{
NeedChangeAI = true;
IsAIEnabled = false;
}
player.SetClientControl(this, true);
}
// a guardian should always have charminfo
if (playerCharmer && this != charmer.GetFirstControlled())
playerCharmer.SendRemoveControlBar();
else if (IsTypeId(TypeId.Player) || (IsTypeId(TypeId.Unit) && !IsGuardian()))
DeleteCharmInfo();
}
public void GetAllMinionsByEntry(List<TempSummon> Minions, uint entry)
{
foreach (var unit in m_Controlled)
{
if (unit.GetEntry() == entry && unit.IsSummon()) // minion, actually
Minions.Add(unit.ToTempSummon());
}
}
void RemoveAllMinionsByEntry(uint entry)
{
foreach (var unit in m_Controlled.ToList())
{
if (unit.GetEntry() == entry && unit.IsTypeId(TypeId.Unit)
&& unit.ToCreature().IsSummon()) // minion, actually
unit.ToTempSummon().UnSummon();
// i think this is safe because i have never heard that a despawned minion will trigger a same minion
}
}
public void SetCharm(Unit charm, bool apply)
{
if (apply)
{
if (IsTypeId(TypeId.Player))
{
if (!AddGuidValue(UnitFields.Charm, charm.GetGUID()))
Log.outFatal(LogFilter.Unit, "Player {0} is trying to charm unit {1}, but it already has a charmed unit {2}", GetName(), charm.GetEntry(), GetCharmGUID());
charm.m_ControlledByPlayer = true;
// @todo maybe we can use this flag to check if controlled by player
charm.SetFlag(UnitFields.Flags, UnitFlags.PvpAttackable);
}
else
charm.m_ControlledByPlayer = false;
// PvP, FFAPvP
charm.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag));
if (!charm.AddGuidValue(UnitFields.CharmedBy, GetGUID()))
Log.outFatal(LogFilter.Unit, "Unit {0} is being charmed, but it already has a charmer {1}", charm.GetEntry(), charm.GetCharmerGUID());
_isWalkingBeforeCharm = charm.IsWalking();
if (_isWalkingBeforeCharm)
charm.SetWalk(false);
m_Controlled.Add(charm);
}
else
{
if (IsTypeId(TypeId.Player))
{
if (!RemoveGuidValue(UnitFields.Charm, charm.GetGUID()))
Log.outFatal(LogFilter.Unit, "Player {0} is trying to uncharm unit {1}, but it has another charmed unit {2}", GetName(), charm.GetEntry(), GetCharmGUID());
}
if (!charm.RemoveGuidValue(UnitFields.CharmedBy, GetGUID()))
Log.outFatal(LogFilter.Unit, "Unit {0} is being uncharmed, but it has another charmer {1}", charm.GetEntry(), charm.GetCharmerGUID());
Player player = charm.GetCharmerOrOwnerPlayerOrPlayerItself();
if (charm.IsTypeId(TypeId.Player))
{
charm.m_ControlledByPlayer = true;
charm.SetFlag(UnitFields.Flags, UnitFlags.PvpAttackable);
charm.ToPlayer().UpdatePvPState();
}
else if (player)
{
charm.m_ControlledByPlayer = true;
charm.SetFlag(UnitFields.Flags, UnitFlags.PvpAttackable);
charm.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, player.GetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag));
}
else
{
charm.m_ControlledByPlayer = false;
charm.RemoveFlag(UnitFields.Flags, UnitFlags.PvpAttackable);
charm.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, 0);
}
if (charm.IsWalking() != _isWalkingBeforeCharm)
charm.SetWalk(_isWalkingBeforeCharm);
if (charm.IsTypeId(TypeId.Player) || !charm.ToCreature().HasUnitTypeMask(UnitTypeMask.Minion)
|| charm.GetOwnerGUID() != GetGUID())
{
m_Controlled.Remove(charm);
}
}
}
public Unit GetFirstControlled()
{
// Sequence: charmed, pet, other guardians
Unit unit = GetCharm();
if (!unit)
{
ObjectGuid guid = GetMinionGUID();
if (!guid.IsEmpty())
unit = Global.ObjAccessor.GetUnit(this, guid);
}
return unit;
}
public void RemoveCharmAuras()
{
RemoveAurasByType(AuraType.ModCharm);
RemoveAurasByType(AuraType.ModPossessPet);
RemoveAurasByType(AuraType.ModPossess);
RemoveAurasByType(AuraType.AoeCharm);
}
public void RemoveAllControlled()
{
// possessed pet and vehicle
if (IsTypeId(TypeId.Player))
ToPlayer().StopCastingCharm();
while (!m_Controlled.Empty())
{
Unit target = m_Controlled.First();
m_Controlled.RemoveAt(0);
if (target.GetCharmerGUID() == GetGUID())
target.RemoveCharmAuras();
else if (target.GetOwnerGUID() == GetGUID() && target.IsSummon())
target.ToTempSummon().UnSummon();
else
Log.outError(LogFilter.Unit, "Unit {0} is trying to release unit {1} which is neither charmed nor owned by it", GetEntry(), target.GetEntry());
}
if (!GetPetGUID().IsEmpty())
Log.outFatal(LogFilter.Unit, "Unit {0} is not able to release its pet {1}", GetEntry(), GetPetGUID());
if (!GetMinionGUID().IsEmpty())
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());
}
public void SendPetActionFeedback(uint spellId, ActionFeedback msg)
{
Unit owner = GetOwner();
if (!owner || !owner.IsTypeId(TypeId.Player))
return;
PetActionFeedback petActionFeedback = new PetActionFeedback();
petActionFeedback.SpellID = spellId;
petActionFeedback.Response = msg;
owner.ToPlayer().SendPacket(petActionFeedback);
}
public void SendPetTalk(PetTalk pettalk)
{
Unit owner = GetOwner();
if (!owner || !owner.IsTypeId(TypeId.Player))
return;
PetActionSound petActionSound = new PetActionSound();
petActionSound.UnitGUID = GetGUID();
petActionSound.Action = pettalk;
owner.ToPlayer().SendPacket(petActionSound);
}
public void SendPetAIReaction(ObjectGuid guid)
{
Unit owner = GetOwner();
if (!owner || !owner.IsTypeId(TypeId.Player))
return;
AIReaction packet = new AIReaction();
packet.UnitGUID = guid;
packet.Reaction = AiReaction.Hostile;
owner.ToPlayer().SendPacket(packet);
}
public Pet CreateTamedPetFrom(Creature creatureTarget, uint spell_id = 0)
{
if (!IsTypeId(TypeId.Player))
return null;
Pet pet = new Pet(ToPlayer(), PetType.Hunter);
if (!pet.CreateBaseAtCreature(creatureTarget))
return null;
uint level = creatureTarget.GetLevelForTarget(this) + 5 < getLevel() ? (getLevel() - 5) : creatureTarget.GetLevelForTarget(this);
InitTamedPet(pet, level, spell_id);
return pet;
}
public Pet CreateTamedPetFrom(uint creatureEntry, uint spell_id = 0)
{
if (!IsTypeId(TypeId.Player))
return null;
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(creatureEntry);
if (creatureInfo == null)
return null;
Pet pet = new Pet(ToPlayer(), PetType.Hunter);
if (!pet.CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, getLevel(), spell_id))
return null;
return pet;
}
bool InitTamedPet(Pet pet, uint level, uint spell_id)
{
pet.SetCreatorGUID(GetGUID());
pet.SetFaction(getFaction());
pet.SetUInt32Value(UnitFields.CreatedBySpell, spell_id);
if (IsTypeId(TypeId.Player))
pet.SetUInt32Value(UnitFields.Flags, (uint)UnitFlags.PvpAttackable);
if (!pet.InitStatsForLevel(level))
{
Log.outError(LogFilter.Unit, "Pet:InitStatsForLevel() failed for creature (Entry: {0})!", pet.GetEntry());
return false;
}
pet.CopyPhaseFrom(this);
pet.GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true);
// this enables pet details window (Shift+P)
pet.InitPetCreateSpells();
pet.SetFullHealth();
return true;
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff