diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index 0a35e19546..8163f646eb 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -17,6 +17,7 @@
#include "PetAI.h"
#include "AIException.h"
+#include "CharmInfo.h"
#include "Creature.h"
#include "Errors.h"
#include "Group.h"
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 871de42ffb..ca406f001a 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -18,6 +18,7 @@
#include "Creature.h"
#include "BattlegroundMgr.h"
#include "CellImpl.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "Containers.h"
#include "CreatureAI.h"
diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp
index b644a69faf..9a5233a9b1 100644
--- a/src/server/game/Entities/Creature/TemporarySummon.cpp
+++ b/src/server/game/Entities/Creature/TemporarySummon.cpp
@@ -16,6 +16,7 @@
*/
#include "TemporarySummon.h"
+#include "CharmInfo.h"
#include "CreatureAI.h"
#include "DBCStructure.h"
#include "Log.h"
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 9cb8e71f7f..e5d9d7b4b0 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "CharmInfo.h"
#include "Common.h"
#include "DatabaseEnv.h"
#include "Log.h"
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index f616fc4ff6..cbee7da6fd 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -33,6 +33,7 @@
#include "CharacterCache.h"
#include "CharacterDatabaseCleaner.h"
#include "CharacterPackets.h"
+#include "CharmInfo.h"
#include "Chat.h"
#include "CinematicMgr.h"
#include "CombatPackets.h"
diff --git a/src/server/game/Entities/Unit/CharmInfo.cpp b/src/server/game/Entities/Unit/CharmInfo.cpp
new file mode 100644
index 0000000000..1019c5c546
--- /dev/null
+++ b/src/server/game/Entities/Unit/CharmInfo.cpp
@@ -0,0 +1,283 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 2 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 .
+ */
+
+#include "CharmInfo.h"
+#include "Creature.h"
+#include "SpellInfo.h"
+#include "SpellMgr.h"
+
+CharmInfo::CharmInfo(Unit* unit)
+: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE),
+ _isCommandAttack(false), _isCommandFollow(false), _isAtStay(false), _isFollowing(false), _isReturning(false),
+ _stayX(0.0f), _stayY(0.0f), _stayZ(0.0f)
+{
+ for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
+ _charmspells[i].SetActionAndType(0, ACT_DISABLED);
+
+ if (Creature* creature = _unit->ToCreature())
+ {
+ _oldReactState = creature->GetReactState();
+ creature->SetReactState(REACT_PASSIVE);
+ }
+}
+
+CharmInfo::~CharmInfo() { }
+
+void CharmInfo::RestoreState()
+{
+ if (Creature* creature = _unit->ToCreature())
+ creature->SetReactState(_oldReactState);
+}
+
+void CharmInfo::InitPetActionBar()
+{
+ // the first 3 SpellOrActions are attack, follow and moveTo
+ SetActionBar(ACTION_BAR_INDEX_ATTACK, COMMAND_ATTACK, ACT_COMMAND);
+ SetActionBar(ACTION_BAR_INDEX_FOLLOW, COMMAND_FOLLOW, ACT_COMMAND);
+ SetActionBar(ACTION_BAR_INDEX_MOVE_TO, COMMAND_MOVE_TO, ACT_COMMAND);
+
+ // middle 4 SpellOrActions are spells/special attacks/abilities
+ for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START; ++i)
+ SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i, 0, ACT_PASSIVE);
+
+ // last 3 SpellOrActions are reactions
+ SetActionBar(ACTION_BAR_INDEX_ASSIST, REACT_ASSIST, ACT_REACTION);
+ SetActionBar(ACTION_BAR_INDEX_DEFENSIVE, REACT_DEFENSIVE, ACT_REACTION);
+ SetActionBar(ACTION_BAR_INDEX_PASSIVE, REACT_PASSIVE, ACT_REACTION);
+}
+
+void CharmInfo::InitEmptyActionBar(bool withAttack)
+{
+ if (withAttack)
+ SetActionBar(ACTION_BAR_INDEX_START, COMMAND_ATTACK, ACT_COMMAND);
+ else
+ SetActionBar(ACTION_BAR_INDEX_START, 0, ACT_PASSIVE);
+ for (uint32 x = ACTION_BAR_INDEX_START+1; x < ACTION_BAR_INDEX_END; ++x)
+ SetActionBar(x, 0, ACT_PASSIVE);
+}
+
+void CharmInfo::InitPossessCreateSpells()
+{
+ if (_unit->GetTypeId() == 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
+ case 28511: // Eye of Acherus
+ break;
+ default:
+ InitEmptyActionBar();
+ break;
+ }
+
+ for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
+ {
+ uint32 spellId = _unit->ToCreature()->m_spells[i];
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
+ if (spellInfo)
+ {
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED))
+ continue;
+
+ if (spellInfo->IsPassive())
+ _unit->CastSpell(_unit, spellInfo->Id, true);
+ else
+ AddSpellToActionBar(spellInfo, ACT_PASSIVE, i % MAX_UNIT_ACTION_BAR_INDEX);
+ }
+ }
+ }
+ else
+ InitEmptyActionBar();
+}
+
+void CharmInfo::InitCharmCreateSpells()
+{
+ if (_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
+ {
+ InitEmptyActionBar();
+ return;
+ }
+
+ InitPetActionBar();
+
+ for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
+ {
+ uint32 spellId = _unit->ToCreature()->m_spells[x];
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
+
+ if (!spellInfo)
+ {
+ _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
+ continue;
+ }
+
+ if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED))
+ continue;
+
+ if (spellInfo->IsPassive())
+ {
+ _unit->CastSpell(_unit, spellInfo->Id, true);
+ _charmspells[x].SetActionAndType(spellId, ACT_PASSIVE);
+ }
+ else
+ {
+ _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
+
+ ActiveStates newstate = ACT_PASSIVE;
+
+ if (!spellInfo->IsAutocastable())
+ newstate = ACT_PASSIVE;
+ else
+ {
+ if (spellInfo->NeedsExplicitUnitTarget())
+ {
+ newstate = ACT_ENABLED;
+ ToggleCreatureAutocast(spellInfo, true);
+ }
+ else
+ newstate = ACT_DISABLED;
+ }
+
+ AddSpellToActionBar(spellInfo, newstate);
+ }
+ }
+}
+
+bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate, uint8 preferredSlot)
+{
+ uint32 spell_id = spellInfo->Id;
+ uint32 first_id = spellInfo->GetFirstRankSpell()->Id;
+
+ ASSERT(preferredSlot < MAX_UNIT_ACTION_BAR_INDEX);
+ // new spell rank can be already listed
+ for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
+ {
+ if (uint32 action = PetActionBar[i].GetAction())
+ {
+ if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
+ {
+ PetActionBar[i].SetAction(spell_id);
+ return true;
+ }
+ }
+ }
+
+ // or use empty slot in other case
+ for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
+ {
+ uint8 j = (preferredSlot + i) % MAX_UNIT_ACTION_BAR_INDEX;
+ if (!PetActionBar[j].GetAction() && PetActionBar[j].IsActionBarForSpell())
+ {
+ SetActionBar(j, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_ENABLED : ACT_PASSIVE : newstate);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
+{
+ uint32 first_id = sSpellMgr->GetFirstSpellInChain(spell_id);
+
+ for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
+ {
+ if (uint32 action = PetActionBar[i].GetAction())
+ {
+ if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
+ {
+ SetActionBar(i, 0, ACT_PASSIVE);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void CharmInfo::ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply)
+{
+ if (spellInfo->IsPassive())
+ return;
+
+ for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
+ if (spellInfo->Id == _charmspells[x].GetAction())
+ _charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
+}
+
+void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
+{
+ _petnumber = petnumber;
+ if (statwindow)
+ _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, _petnumber);
+ else
+ _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
+}
+
+void CharmInfo::LoadPetActionBar(const std::string& data)
+{
+ InitPetActionBar();
+
+ Tokenizer tokens(data, ' ');
+
+ if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2)
+ return; // non critical, will reset to default
+
+ uint8 index = ACTION_BAR_INDEX_START;
+ Tokenizer::const_iterator iter = tokens.begin();
+ for (; index < ACTION_BAR_INDEX_END; ++iter, ++index)
+ {
+ // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
+ ActiveStates type = ActiveStates(atol(*iter));
+ ++iter;
+ uint32 action = atoul(*iter);
+
+ PetActionBar[index].SetActionAndType(action, type);
+
+ // check correctness
+ if (PetActionBar[index].IsActionBarForSpell())
+ {
+ SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction());
+ if (!spelInfo)
+ SetActionBar(index, 0, ACT_PASSIVE);
+ else if (!spelInfo->IsAutocastable())
+ SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE);
+ }
+ }
+}
+
+void CharmInfo::BuildActionBar(WorldPacket* data)
+{
+ for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
+ *data << uint32(PetActionBar[i].packedData);
+}
+
+void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state)
+{
+ for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
+ {
+ if (spellInfo->Id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
+ {
+ PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED);
+ break;
+ }
+ }
+}
diff --git a/src/server/game/Entities/Unit/CharmInfo.h b/src/server/game/Entities/Unit/CharmInfo.h
new file mode 100644
index 0000000000..2388b869d3
--- /dev/null
+++ b/src/server/game/Entities/Unit/CharmInfo.h
@@ -0,0 +1,157 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 2 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 .
+ */
+
+#ifndef _CharmInfo_h__
+#define _CharmInfo_h__
+
+#include "Define.h"
+#include "UnitDefines.h"
+
+class SpellInfo;
+class Unit;
+class WorldPacket;
+
+#define UNIT_ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF)
+#define UNIT_ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24)
+#define MAKE_UNIT_ACTION_BUTTON(A, T) (uint32(A) | (uint32(T) << 24))
+
+struct UnitActionBarEntry
+{
+ UnitActionBarEntry() : packedData(uint32(ACT_DISABLED) << 24) { }
+
+ uint32 packedData;
+
+ // helper
+ ActiveStates GetType() const { return ActiveStates(UNIT_ACTION_BUTTON_TYPE(packedData)); }
+ uint32 GetAction() const { return UNIT_ACTION_BUTTON_ACTION(packedData); }
+ bool IsActionBarForSpell() const
+ {
+ ActiveStates Type = GetType();
+ return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE;
+ }
+
+ void SetActionAndType(uint32 action, ActiveStates type)
+ {
+ packedData = MAKE_UNIT_ACTION_BUTTON(action, type);
+ }
+
+ void SetType(ActiveStates type)
+ {
+ packedData = MAKE_UNIT_ACTION_BUTTON(UNIT_ACTION_BUTTON_ACTION(packedData), type);
+ }
+
+ void SetAction(uint32 action)
+ {
+ packedData = (packedData & 0xFF000000) | UNIT_ACTION_BUTTON_ACTION(action);
+ }
+};
+
+enum CharmType : uint8
+{
+ CHARM_TYPE_CHARM,
+ CHARM_TYPE_POSSESS,
+ CHARM_TYPE_VEHICLE,
+ CHARM_TYPE_CONVERT
+};
+
+typedef UnitActionBarEntry CharmSpellInfo;
+
+enum ActionBarIndex
+{
+ ACTION_BAR_INDEX_START = 0,
+ ACTION_BAR_INDEX_ATTACK = ACTION_BAR_INDEX_START,
+ ACTION_BAR_INDEX_FOLLOW = 1,
+ ACTION_BAR_INDEX_MOVE_TO = 2,
+ ACTION_BAR_INDEX_PET_SPELL_START = 3,
+ ACTION_BAR_INDEX_PET_SPELL_END = 7,
+ ACTION_BAR_INDEX_ASSIST = ACTION_BAR_INDEX_PET_SPELL_END,
+ ACTION_BAR_INDEX_DEFENSIVE = 8,
+ ACTION_BAR_INDEX_PASSIVE = 9,
+ ACTION_BAR_INDEX_END = 10
+};
+
+#define MAX_UNIT_ACTION_BAR_INDEX (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START)
+
+struct TC_GAME_API CharmInfo
+{
+ public:
+ explicit CharmInfo(Unit* unit);
+ ~CharmInfo();
+ void RestoreState();
+ uint32 GetPetNumber() const { return _petnumber; }
+ void SetPetNumber(uint32 petnumber, bool statwindow);
+
+ void SetCommandState(CommandStates st) { _CommandState = st; }
+ CommandStates GetCommandState() const { return _CommandState; }
+ bool HasCommandState(CommandStates state) const { return (_CommandState == state); }
+
+ void InitPossessCreateSpells();
+ void InitCharmCreateSpells();
+ void InitPetActionBar();
+ void InitEmptyActionBar(bool withAttack = true);
+
+ //return true if successful
+ bool AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate = ACT_DECIDE, uint8 preferredSlot = 0);
+ bool RemoveSpellFromActionBar(uint32 spell_id);
+ void LoadPetActionBar(const std::string& data);
+ void BuildActionBar(WorldPacket* data);
+ void SetSpellAutocast(SpellInfo const* spellInfo, bool state);
+ void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
+ {
+ PetActionBar[index].SetActionAndType(spellOrAction, type);
+ }
+ UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); }
+
+ void ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply);
+
+ CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
+
+ void SetIsCommandAttack(bool val);
+ bool IsCommandAttack();
+ void SetIsCommandFollow(bool val);
+ bool IsCommandFollow();
+ void SetIsAtStay(bool val);
+ bool IsAtStay();
+ void SetIsFollowing(bool val);
+ bool IsFollowing();
+ void SetIsReturning(bool val);
+ bool IsReturning();
+ void SaveStayPosition();
+ void GetStayPosition(float &x, float &y, float &z);
+
+ private:
+
+ Unit* _unit;
+ UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX];
+ CharmSpellInfo _charmspells[4];
+ CommandStates _CommandState;
+ uint32 _petnumber;
+
+ //for restoration after charmed
+ ReactStates _oldReactState;
+
+ bool _isCommandAttack;
+ bool _isCommandFollow;
+ bool _isAtStay;
+ bool _isFollowing;
+ bool _isReturning;
+ float _stayX;
+ float _stayY;
+ float _stayZ;
+};
+
+#endif // _CharmInfo_h__
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e11673f241..7907d3af5a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -24,6 +24,7 @@
#include "BattlegroundScore.h"
#include "CellImpl.h"
#include "CharacterCache.h"
+#include "CharmInfo.h"
#include "Chat.h"
#include "ChatTextBuilder.h"
#include "ChatPackets.h"
@@ -9705,268 +9706,6 @@ void Unit::DeleteCharmInfo()
m_charmInfo.reset();
}
-CharmInfo::CharmInfo(Unit* unit)
-: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE),
- _isCommandAttack(false), _isCommandFollow(false), _isAtStay(false), _isFollowing(false), _isReturning(false),
- _stayX(0.0f), _stayY(0.0f), _stayZ(0.0f)
-{
- for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
- _charmspells[i].SetActionAndType(0, ACT_DISABLED);
-
- if (Creature* creature = _unit->ToCreature())
- {
- _oldReactState = creature->GetReactState();
- creature->SetReactState(REACT_PASSIVE);
- }
-}
-
-CharmInfo::~CharmInfo() { }
-
-void CharmInfo::RestoreState()
-{
- if (Creature* creature = _unit->ToCreature())
- creature->SetReactState(_oldReactState);
-}
-
-void CharmInfo::InitPetActionBar()
-{
- // the first 3 SpellOrActions are attack, follow and moveTo
- SetActionBar(ACTION_BAR_INDEX_ATTACK, COMMAND_ATTACK, ACT_COMMAND);
- SetActionBar(ACTION_BAR_INDEX_FOLLOW, COMMAND_FOLLOW, ACT_COMMAND);
- SetActionBar(ACTION_BAR_INDEX_MOVE_TO, COMMAND_MOVE_TO, ACT_COMMAND);
-
- // middle 4 SpellOrActions are spells/special attacks/abilities
- for (uint32 i = 0; i < ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START; ++i)
- SetActionBar(ACTION_BAR_INDEX_PET_SPELL_START + i, 0, ACT_PASSIVE);
-
- // last 3 SpellOrActions are reactions
- SetActionBar(ACTION_BAR_INDEX_ASSIST, REACT_ASSIST, ACT_REACTION);
- SetActionBar(ACTION_BAR_INDEX_DEFENSIVE, REACT_DEFENSIVE, ACT_REACTION);
- SetActionBar(ACTION_BAR_INDEX_PASSIVE, REACT_PASSIVE, ACT_REACTION);
-}
-
-void CharmInfo::InitEmptyActionBar(bool withAttack)
-{
- if (withAttack)
- SetActionBar(ACTION_BAR_INDEX_START, COMMAND_ATTACK, ACT_COMMAND);
- else
- SetActionBar(ACTION_BAR_INDEX_START, 0, ACT_PASSIVE);
- for (uint32 x = ACTION_BAR_INDEX_START+1; x < ACTION_BAR_INDEX_END; ++x)
- SetActionBar(x, 0, ACT_PASSIVE);
-}
-
-void CharmInfo::InitPossessCreateSpells()
-{
- if (_unit->GetTypeId() == 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
- case 28511: // Eye of Acherus
- break;
- default:
- InitEmptyActionBar();
- break;
- }
-
- for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
- {
- uint32 spellId = _unit->ToCreature()->m_spells[i];
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (spellInfo)
- {
- if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED))
- continue;
-
- if (spellInfo->IsPassive())
- _unit->CastSpell(_unit, spellInfo->Id, true);
- else
- AddSpellToActionBar(spellInfo, ACT_PASSIVE, i % MAX_UNIT_ACTION_BAR_INDEX);
- }
- }
- }
- else
- InitEmptyActionBar();
-}
-
-void CharmInfo::InitCharmCreateSpells()
-{
- if (_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
- {
- InitEmptyActionBar();
- return;
- }
-
- InitPetActionBar();
-
- for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
- {
- uint32 spellId = _unit->ToCreature()->m_spells[x];
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
-
- if (!spellInfo)
- {
- _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
- continue;
- }
-
- if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED))
- continue;
-
- if (spellInfo->IsPassive())
- {
- _unit->CastSpell(_unit, spellInfo->Id, true);
- _charmspells[x].SetActionAndType(spellId, ACT_PASSIVE);
- }
- else
- {
- _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
-
- ActiveStates newstate = ACT_PASSIVE;
-
- if (!spellInfo->IsAutocastable())
- newstate = ACT_PASSIVE;
- else
- {
- if (spellInfo->NeedsExplicitUnitTarget())
- {
- newstate = ACT_ENABLED;
- ToggleCreatureAutocast(spellInfo, true);
- }
- else
- newstate = ACT_DISABLED;
- }
-
- AddSpellToActionBar(spellInfo, newstate);
- }
- }
-}
-
-bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate, uint8 preferredSlot)
-{
- uint32 spell_id = spellInfo->Id;
- uint32 first_id = spellInfo->GetFirstRankSpell()->Id;
-
- ASSERT(preferredSlot < MAX_UNIT_ACTION_BAR_INDEX);
- // new spell rank can be already listed
- for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- if (uint32 action = PetActionBar[i].GetAction())
- {
- if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
- {
- PetActionBar[i].SetAction(spell_id);
- return true;
- }
- }
- }
-
- // or use empty slot in other case
- for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- uint8 j = (preferredSlot + i) % MAX_UNIT_ACTION_BAR_INDEX;
- if (!PetActionBar[j].GetAction() && PetActionBar[j].IsActionBarForSpell())
- {
- SetActionBar(j, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_ENABLED : ACT_PASSIVE : newstate);
- return true;
- }
- }
- return false;
-}
-
-bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
-{
- uint32 first_id = sSpellMgr->GetFirstSpellInChain(spell_id);
-
- for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- if (uint32 action = PetActionBar[i].GetAction())
- {
- if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
- {
- SetActionBar(i, 0, ACT_PASSIVE);
- return true;
- }
- }
- }
-
- return false;
-}
-
-void CharmInfo::ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply)
-{
- if (spellInfo->IsPassive())
- return;
-
- for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
- if (spellInfo->Id == _charmspells[x].GetAction())
- _charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
-}
-
-void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
-{
- _petnumber = petnumber;
- if (statwindow)
- _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, _petnumber);
- else
- _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
-}
-
-void CharmInfo::LoadPetActionBar(const std::string& data)
-{
- InitPetActionBar();
-
- Tokenizer tokens(data, ' ');
-
- if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2)
- return; // non critical, will reset to default
-
- uint8 index = ACTION_BAR_INDEX_START;
- Tokenizer::const_iterator iter = tokens.begin();
- for (; index < ACTION_BAR_INDEX_END; ++iter, ++index)
- {
- // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
- ActiveStates type = ActiveStates(atol(*iter));
- ++iter;
- uint32 action = atoul(*iter);
-
- PetActionBar[index].SetActionAndType(action, type);
-
- // check correctness
- if (PetActionBar[index].IsActionBarForSpell())
- {
- SpellInfo const* spelInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction());
- if (!spelInfo)
- SetActionBar(index, 0, ACT_PASSIVE);
- else if (!spelInfo->IsAutocastable())
- SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE);
- }
- }
-}
-
-void CharmInfo::BuildActionBar(WorldPacket* data)
-{
- for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- *data << uint32(PetActionBar[i].packedData);
-}
-
-void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state)
-{
- for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
- {
- if (spellInfo->Id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
- {
- PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED);
- break;
- }
- }
-}
-
bool Unit::isFrozen() const
{
return HasAuraState(AURA_STATE_FROZEN);
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 0fa7a902ce..7a0c839dfb 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -73,6 +73,7 @@ struct SpellValue;
class Aura;
class AuraApplication;
class AuraEffect;
+class CharmInfo;
class Creature;
class DynamicObject;
class GameClient;
@@ -95,6 +96,7 @@ class Vehicle;
class VehicleJoinEvent;
enum ZLiquidStatus : uint32;
+enum CharmType : uint8;
namespace Movement
{
@@ -598,137 +600,8 @@ enum CurrentSpellTypes : uint8
#define CURRENT_FIRST_NON_MELEE_SPELL 1
#define CURRENT_MAX_SPELL 4
-#define UNIT_ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF)
-#define UNIT_ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24)
-#define MAKE_UNIT_ACTION_BUTTON(A, T) (uint32(A) | (uint32(T) << 24))
-
-struct UnitActionBarEntry
-{
- UnitActionBarEntry() : packedData(uint32(ACT_DISABLED) << 24) { }
-
- uint32 packedData;
-
- // helper
- ActiveStates GetType() const { return ActiveStates(UNIT_ACTION_BUTTON_TYPE(packedData)); }
- uint32 GetAction() const { return UNIT_ACTION_BUTTON_ACTION(packedData); }
- bool IsActionBarForSpell() const
- {
- ActiveStates Type = GetType();
- return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE;
- }
-
- void SetActionAndType(uint32 action, ActiveStates type)
- {
- packedData = MAKE_UNIT_ACTION_BUTTON(action, type);
- }
-
- void SetType(ActiveStates type)
- {
- packedData = MAKE_UNIT_ACTION_BUTTON(UNIT_ACTION_BUTTON_ACTION(packedData), type);
- }
-
- void SetAction(uint32 action)
- {
- packedData = (packedData & 0xFF000000) | UNIT_ACTION_BUTTON_ACTION(action);
- }
-};
-
typedef std::list SharedVisionList;
-enum CharmType
-{
- CHARM_TYPE_CHARM,
- CHARM_TYPE_POSSESS,
- CHARM_TYPE_VEHICLE,
- CHARM_TYPE_CONVERT
-};
-
-typedef UnitActionBarEntry CharmSpellInfo;
-
-enum ActionBarIndex
-{
- ACTION_BAR_INDEX_START = 0,
- ACTION_BAR_INDEX_ATTACK = ACTION_BAR_INDEX_START,
- ACTION_BAR_INDEX_FOLLOW = 1,
- ACTION_BAR_INDEX_MOVE_TO = 2,
- ACTION_BAR_INDEX_PET_SPELL_START = 3,
- ACTION_BAR_INDEX_PET_SPELL_END = 7,
- ACTION_BAR_INDEX_ASSIST = ACTION_BAR_INDEX_PET_SPELL_END,
- ACTION_BAR_INDEX_DEFENSIVE = 8,
- ACTION_BAR_INDEX_PASSIVE = 9,
- ACTION_BAR_INDEX_END = 10
-};
-
-#define MAX_UNIT_ACTION_BAR_INDEX (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START)
-
-struct TC_GAME_API CharmInfo
-{
- public:
- explicit CharmInfo(Unit* unit);
- ~CharmInfo();
- void RestoreState();
- uint32 GetPetNumber() const { return _petnumber; }
- void SetPetNumber(uint32 petnumber, bool statwindow);
-
- void SetCommandState(CommandStates st) { _CommandState = st; }
- CommandStates GetCommandState() const { return _CommandState; }
- bool HasCommandState(CommandStates state) const { return (_CommandState == state); }
-
- void InitPossessCreateSpells();
- void InitCharmCreateSpells();
- void InitPetActionBar();
- void InitEmptyActionBar(bool withAttack = true);
-
- //return true if successful
- bool AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate = ACT_DECIDE, uint8 preferredSlot = 0);
- bool RemoveSpellFromActionBar(uint32 spell_id);
- void LoadPetActionBar(const std::string& data);
- void BuildActionBar(WorldPacket* data);
- void SetSpellAutocast(SpellInfo const* spellInfo, bool state);
- void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
- {
- PetActionBar[index].SetActionAndType(spellOrAction, type);
- }
- UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); }
-
- void ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply);
-
- CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
-
- void SetIsCommandAttack(bool val);
- bool IsCommandAttack();
- void SetIsCommandFollow(bool val);
- bool IsCommandFollow();
- void SetIsAtStay(bool val);
- bool IsAtStay();
- void SetIsFollowing(bool val);
- bool IsFollowing();
- void SetIsReturning(bool val);
- bool IsReturning();
- void SaveStayPosition();
- void GetStayPosition(float &x, float &y, float &z);
-
- private:
-
- Unit* _unit;
- UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX];
- CharmSpellInfo _charmspells[4];
- CommandStates _CommandState;
- uint32 _petnumber;
-
- //for restoration after charmed
- ReactStates _oldReactState;
-
- bool _isCommandAttack;
- bool _isCommandFollow;
- bool _isAtStay;
- bool _isFollowing;
- bool _isReturning;
- float _stayX;
- float _stayY;
- float _stayZ;
-};
-
// for clearing special attacks
#define REACTIVE_TIMER_START 4000
diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h
index a820aa1606..45dfd865c7 100644
--- a/src/server/game/Entities/Unit/UnitDefines.h
+++ b/src/server/game/Entities/Unit/UnitDefines.h
@@ -388,7 +388,7 @@ struct DeclinedName
std::string name[MAX_DECLINED_NAME_CASES];
};
-enum ActiveStates
+enum ActiveStates : uint8
{
ACT_PASSIVE = 0x01, // 0x01 - passive
ACT_DISABLED = 0x81, // 0x80 - castable
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 33a73654a0..31c167abdd 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -17,6 +17,7 @@
#include "Vehicle.h"
#include "Battleground.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "CreatureAI.h"
#include "DBCStores.h"
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index d51f6a884b..cd4399516e 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -18,6 +18,7 @@
#include "WorldSession.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "Creature.h"
#include "CreatureAI.h"
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 1a3d67269b..974c089fe3 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -16,6 +16,7 @@
*/
#include "WorldSession.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "CreatureAI.h"
#include "DatabaseEnv.h"
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index b60cb3b356..bdc19ea62a 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -20,6 +20,7 @@
#include "BattlefieldMgr.h"
#include "Battleground.h"
#include "CellImpl.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "DBCStores.h"
#include "GridNotifiersImpl.h"
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index ab052d5fdb..cabdae3bde 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -20,6 +20,7 @@
#include "AreaTrigger.h"
#include "Battleground.h"
#include "CellImpl.h"
+#include "CharmInfo.h"
#include "Common.h"
#include "Creature.h"
#include "CreatureAI.h"
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index 1e64f92840..b9cb812bf8 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -16,6 +16,7 @@
*/
#include "SpellHistory.h"
+#include "CharmInfo.h"
#include "DatabaseEnv.h"
#include "DBCStores.h"
#include "Item.h"
diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp
index f6937dff69..11f28b4400 100644
--- a/src/server/scripts/Commands/cs_pet.cpp
+++ b/src/server/scripts/Commands/cs_pet.cpp
@@ -16,6 +16,7 @@
*/
#include "ScriptMgr.h"
+#include "CharmInfo.h"
#include "Chat.h"
#include "Language.h"
#include "Log.h"
diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp
index 8df3d96e44..0b83d65b84 100644
--- a/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp
+++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/the_scarlet_enclave_chapter_1.cpp
@@ -16,6 +16,7 @@
*/
#include "ScriptMgr.h"
+#include "CharmInfo.h"
#include "CombatAI.h"
#include "CreatureAIImpl.h"
#include "GameObject.h"
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 4f60e17cb7..a1f9b8d018 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "CellImpl.h"
+#include "CharmInfo.h"
#include "CombatAI.h"
#include "Containers.h"
#include "CreatureTextMgr.h"