From bb6a8ac297872bf5557c8148467855632ab59c9d Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Sat, 14 Jun 2025 19:13:44 +0200 Subject: [PATCH] Core/Units: moved CharmInfo class to an own file --- src/server/game/AI/CoreAI/PetAI.cpp | 1 + .../game/Entities/Creature/Creature.cpp | 1 + .../Entities/Creature/TemporarySummon.cpp | 1 + src/server/game/Entities/Pet/Pet.cpp | 1 + src/server/game/Entities/Player/Player.cpp | 1 + src/server/game/Entities/Unit/CharmInfo.cpp | 283 ++++++++++++++++++ src/server/game/Entities/Unit/CharmInfo.h | 157 ++++++++++ src/server/game/Entities/Unit/Unit.cpp | 263 +--------------- src/server/game/Entities/Unit/Unit.h | 131 +------- src/server/game/Entities/Unit/UnitDefines.h | 2 +- src/server/game/Entities/Vehicle/Vehicle.cpp | 1 + src/server/game/Handlers/NPCHandler.cpp | 1 + src/server/game/Handlers/PetHandler.cpp | 1 + .../game/Spells/Auras/SpellAuraEffects.cpp | 1 + src/server/game/Spells/SpellEffects.cpp | 1 + src/server/game/Spells/SpellHistory.cpp | 1 + src/server/scripts/Commands/cs_pet.cpp | 1 + .../the_scarlet_enclave_chapter_1.cpp | 1 + src/server/scripts/World/npcs_special.cpp | 1 + 19 files changed, 458 insertions(+), 392 deletions(-) create mode 100644 src/server/game/Entities/Unit/CharmInfo.cpp create mode 100644 src/server/game/Entities/Unit/CharmInfo.h 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"