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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user