From af4146dd99afbb7f4fb835e94bcd33dbd048f612 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 27 May 2009 19:24:12 +0400 Subject: [PATCH] [7901] Refactoting pet action bar related code. Fixed some related bugs. * Correctly update action bar at loading and other cases when listed unlearned/not existed spells * Avoid send data by PetSpellInitialize() many times while pet loading --- src/game/Pet.cpp | 79 +++++++++++++++--------------- src/game/Pet.h | 7 +-- src/game/PetHandler.cpp | 15 +++--- src/game/Player.cpp | 15 ++---- src/game/Unit.cpp | 125 +++++++++++++++++++++++++++++++++-------------- src/game/Unit.h | 52 ++++++++++++-------- src/shared/revision_nr.h | 2 +- 7 files changed, 174 insertions(+), 121 deletions(-) diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index c68bb21a5..9244736c2 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -240,23 +240,11 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool if (!is_temporary_summoned) { - // permanent controlled pets store state in DB - Tokens tokens = StrSplit(fields[14].GetString(), " "); - - if (tokens.size() != 20) + if(!m_charmInfo->LoadActionBar(fields[14].GetCppString())) { delete result; return false; } - - int index; - Tokens::iterator iter; - for(iter = tokens.begin(), index = 0; index < 10; ++iter, ++index ) - { - m_charmInfo->GetActionBarEntry(index)->Type = atol((*iter).c_str()); - ++iter; - m_charmInfo->GetActionBarEntry(index)->SpellOrAction = atol((*iter).c_str()); - } } // since last save (in seconds) @@ -299,6 +287,10 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool // Spells should be loaded after pet is added to map, because in CheckCast is check on it _LoadSpells(); + InitLevelupSpellsForLevel(); + + CleanupActionBar(); // remove unknown spells from action bar after load + _LoadSpellCooldowns(); owner->SetPet(this); // in DB stored only full controlled creature @@ -329,8 +321,6 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } } - InitLevelupSpellsForLevel(); - m_loading = false; SynchronizeLevelWithOwner(); @@ -421,8 +411,12 @@ void Pet::SavePetToDB(PetSaveMode mode) << curmana << ", " << GetPower(POWER_HAPPINESS) << ", '"; - for(uint32 i = 0; i < 10; ++i) - ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " + << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + }; + ss << "', " << time(NULL) << ", " << uint32(m_resetTalentsCost) << ", " @@ -1337,7 +1331,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel // skip unknown ranks if(!HasSpell(rankSpellId)) continue; - removeSpell(rankSpellId,false); + removeSpell(rankSpellId,false,false); } } } @@ -1358,7 +1352,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel ToggleAutocast(itr2->first, false); oldspell_id = itr2->first; - unlearnSpell(itr2->first,false); + unlearnSpell(itr2->first,false,false); break; } // ignore new lesser rank @@ -1373,7 +1367,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel if (IsPassiveSpell(spell_id)) CastSpell(this, spell_id, true); else - m_charmInfo->AddSpellToAB(oldspell_id, spell_id); + m_charmInfo->AddSpellToActionBar(spell_id); if(newspell.active == ACT_ENABLED) ToggleAutocast(spell_id, true); @@ -1396,16 +1390,17 @@ bool Pet::learnSpell(uint32 spell_id) if (!addSpell(spell_id)) return false; - Unit* owner = GetOwner(); - if(owner && owner->GetTypeId() == TYPEID_PLAYER) + if(!m_loading) { - if(!m_loading) + Unit* owner = GetOwner(); + if(owner && owner->GetTypeId() == TYPEID_PLAYER) { WorldPacket data(SMSG_PET_LEARNED_SPELL, 2); data << uint16(spell_id); ((Player*)owner)->GetSession()->SendPacket(&data); + + ((Player*)owner)->PetSpellInitialize(); } - ((Player*)owner)->PetSpellInitialize(); } return true; } @@ -1441,7 +1436,7 @@ void Pet::InitLevelupSpellsForLevel() // will called first if level down if(spellEntry->spellLevel > level) - unlearnSpell(spellEntry->Id,false); + unlearnSpell(spellEntry->Id,true); // will called if level up else learnSpell(spellEntry->Id); @@ -1449,9 +1444,9 @@ void Pet::InitLevelupSpellsForLevel() } } -bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev) +bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { - if(removeSpell(spell_id,learn_prev)) + if(removeSpell(spell_id,learn_prev,clear_ab)) { if(GetOwner()->GetTypeId() == TYPEID_PLAYER) { @@ -1467,7 +1462,7 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev) return false; } -bool Pet::removeSpell(uint32 spell_id, bool learn_prev) +bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { PetSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -1498,29 +1493,35 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev) if (learn_prev) { if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id)) - { - // replace to next spell - if(!talentCost && !IsPassiveSpell(prev_id)) - m_charmInfo->AddSpellToAB(spell_id, prev_id); - learnSpell(prev_id); - } else learn_prev = false; } // if remove last rank or non-ranked then update action bar at server and client if need - if(!learn_prev && m_charmInfo->AddSpellToAB(spell_id, 0)) + if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id)) { - // need update action bar for last removed rank - if (Unit* owner = GetOwner()) - if (owner->GetTypeId() == TYPEID_PLAYER) - ((Player*)owner)->PetSpellInitialize(); + if(!m_loading) + { + // need update action bar for last removed rank + if (Unit* owner = GetOwner()) + if (owner->GetTypeId() == TYPEID_PLAYER) + ((Player*)owner)->PetSpellInitialize(); + } } return true; } + +void Pet::CleanupActionBar() +{ + for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + if(UnitActionBarEntry const* ab = m_charmInfo->GetActionBarEntry(i)) + if(ab->SpellOrAction && ab->IsActionBarForSpell() && !HasSpell(ab->SpellOrAction)) + m_charmInfo->SetActionBar(i,0,ACT_DISABLED); +} + void Pet::InitPetCreateSpells() { m_charmInfo->InitPetActionBar(); diff --git a/src/game/Pet.h b/src/game/Pet.h index f8de3ed5e..510738731 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -198,8 +198,9 @@ class Pet : public Creature bool learnSpell(uint32 spell_id); void learnSpellHighRank(uint32 spellid); void InitLevelupSpellsForLevel(); - bool unlearnSpell(uint32 spell_id, bool learn_prev); - bool removeSpell(uint32 spell_id, bool learn_prev); + bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true); + void CleanupActionBar(); PetSpellMap m_spells; AutoSpellList m_autospells; @@ -248,4 +249,4 @@ class Pet : public Creature assert(false); } }; -#endif +#endif \ No newline at end of file diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index eecc938ed..82930fee7 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -357,7 +357,11 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state); - //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add + //ignore invalid position + if(position >= MAX_UNIT_ACTION_BAR_INDEX) + return; + + //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) { //sign for autocast @@ -377,8 +381,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) ((Pet*)pet)->ToggleAutocast(spell_id, false); } - charmInfo->GetActionBarEntry(position)->Type = act_state; - charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id; + charmInfo->SetActionBar(position,spell_id,ActiveStates(act_state)); } } } @@ -560,11 +563,7 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket ) else ((Pet*)pet)->ToggleAutocast(spellid, state); - for(uint8 i = 0; i < 10; ++i) - { - if((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction) - charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED; - } + charmInfo->SetSpellAutocast(spellid,state); } void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 88725e0be..b5c0ebc8a 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -16410,10 +16410,7 @@ void Player::PetSpellInitialize() data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); // action bar loop - for(uint32 i = 0; i < 10; ++i) - { - data << uint32(charmInfo->GetActionBarEntry(i)->Raw); - } + charmInfo->BuildActionBar(&data); size_t spellsCountPos = data.wpos(); @@ -16489,10 +16486,7 @@ void Player::PossessSpellInitialize() data << uint32(0); data << uint32(0); - for(uint32 i = 0; i < 10; ++i) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } + charmInfo->BuildActionBar(&data); //40 data << uint8(addlist); //1 @@ -16543,10 +16537,7 @@ void Player::CharmSpellInitialize() data << uint8(0) << uint8(0); data << uint16(0); - for(uint32 i = 0; i < 10; ++i) //40 - { - data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type); - } + charmInfo->BuildActionBar(&data); //40 data << uint8(addlist); //1 diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index a5a79170d..b7e116e39 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -10328,28 +10328,18 @@ void CharmInfo::InitPetActionBar() // the first 3 SpellOrActions are attack, follow and stay for(uint32 i = 0; i < 3; ++i) { - PetActionBar[i].Type = ACT_COMMAND; - PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i; - - PetActionBar[i + 7].Type = ACT_REACTION; - PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i; - } - for(uint32 i=0; i < 4; ++i) - { - PetActionBar[i + 3].Type = ACT_DISABLED; - PetActionBar[i + 3].SpellOrAction = 0; + SetActionBar(i,COMMAND_ATTACK - i,ACT_COMMAND); + SetActionBar(i + 7,COMMAND_ATTACK - i,ACT_REACTION); } + for(uint32 i = 0; i < 4; ++i) + SetActionBar(i,0,ACT_DISABLED); } void CharmInfo::InitEmptyActionBar() { - for(uint32 x = 1; x < 10; ++x) - { - PetActionBar[x].Type = ACT_PASSIVE; - PetActionBar[x].SpellOrAction = 0; - } - PetActionBar[0].Type = ACT_COMMAND; - PetActionBar[0].SpellOrAction = COMMAND_ATTACK; + SetActionBar(0,COMMAND_ATTACK,ACT_COMMAND); + for(uint32 x = 1; x < MAX_UNIT_ACTION_BAR_INDEX; ++x) + SetActionBar(x,0,ACT_PASSIVE); } void CharmInfo::InitPossessCreateSpells() @@ -10364,7 +10354,7 @@ void CharmInfo::InitPossessCreateSpells() if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); else - AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); + AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); } } @@ -10409,39 +10399,56 @@ void CharmInfo::InitCharmCreateSpells() else newstate = ACT_PASSIVE; - AddSpellToAB(0, spellId, newstate); + AddSpellToActionBar(spellId, newstate); } } } -bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) +bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate) { - // new spell already listed for example in case prepered switch to lesser rank in Pet::removeSpell - for(uint8 i = 0; i < 10; ++i) - if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) - if (newid && PetActionBar[i].SpellOrAction == newid) - return true; + uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id); - // old spell can be leasted for example in case learn high rank - for(uint8 i = 0; i < 10; ++i) + // new spell rank can be already listed + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) + if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) { - if (PetActionBar[i].SpellOrAction == oldid) + if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) { - PetActionBar[i].SpellOrAction = newid; - if (!oldid) - { - if (newstate == ACT_DECIDE) - PetActionBar[i].Type = ACT_DISABLED; - else - PetActionBar[i].Type = newstate; - } + PetActionBar[i].SpellOrAction = spell_id; + return true; + } + } + } + // or use empty slot in other case + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + SetActionBar(i,spell_id,newstate == ACT_DECIDE ? ACT_DISABLED : newstate); + return true; + } + } + return false; +} + +bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id) +{ + uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id); + + for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) + { + SetActionBar(i,0,ACT_DISABLED); return true; } } } + return false; } @@ -10468,6 +10475,50 @@ void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); } +bool CharmInfo::LoadActionBar( std::string data ) +{ + Tokens tokens = StrSplit(data, " "); + + if (tokens.size() != MAX_UNIT_ACTION_BAR_INDEX*2) + return false; + + int index; + Tokens::iterator iter; + for(iter = tokens.begin(), index = 0; index < MAX_UNIT_ACTION_BAR_INDEX; ++iter, ++index ) + { + // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion + PetActionBar[index].Type = atol((*iter).c_str()); + ++iter; + PetActionBar[index].SpellOrAction = atol((*iter).c_str()); + + // check correctness + if(PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction)) + SetActionBar(index,0,ACT_DISABLED); + } + return true; +} + +void CharmInfo::BuildActionBar( WorldPacket* data ) +{ + for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + *data << uint16(PetActionBar[i].SpellOrAction); + *data << uint16(PetActionBar[i].Type); + } +} + +void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state ) +{ + for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) + { + if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + { + PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED; + break; + } + } +} + bool Unit::isFrozen() const { return HasAuraState(AURA_STATE_FROZEN); diff --git a/src/game/Unit.h b/src/game/Unit.h index e79b88493..ccefb8c86 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -678,24 +678,6 @@ struct SpellNonMeleeDamage{ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); -struct UnitActionBarEntry -{ - UnitActionBarEntry() : Raw(0) {} - - union - { - struct - { - uint16 SpellOrAction; - uint16 Type; - }; - struct - { - uint32 Raw; - }; - }; -}; - #define MAX_DECLINED_NAME_CASES 5 struct DeclinedName @@ -738,12 +720,28 @@ enum CommandStates COMMAND_ABANDON = 3 }; +struct UnitActionBarEntry +{ + UnitActionBarEntry() : SpellOrAction(0), Type(ACT_DISABLED) {} + + uint16 SpellOrAction; + uint16 Type; + + // helper + bool IsActionBarForSpell() const + { + return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE; + } +}; + struct CharmSpellEntry { uint16 spellId; uint16 active; }; +#define MAX_UNIT_ACTION_BAR_INDEX 10 + struct CharmInfo { public: @@ -762,15 +760,27 @@ struct CharmInfo void InitCharmCreateSpells(); void InitPetActionBar(); void InitEmptyActionBar(); + //return true if successful - bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); + bool AddSpellToActionBar(uint32 spellid, ActiveStates newstate = ACT_DECIDE); + bool RemoveSpellFromActionBar(uint32 spell_id); + bool LoadActionBar(std::string data); + void BuildActionBar(WorldPacket* data); + void SetSpellAutocast(uint32 spell_id, bool state); + void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type) + { + PetActionBar[index].Type = type; + PetActionBar[index].SpellOrAction = spellOrAction; + } + UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); } + void ToggleCreatureAutocast(uint32 spellid, bool apply); - UnitActionBarEntry* GetActionBarEntry(uint8 index) { return &(PetActionBar[index]); } CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } private: + Unit* m_unit; - UnitActionBarEntry PetActionBar[10]; + UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX]; CharmSpellEntry m_charmspells[4]; CommandStates m_CommandState; ReactStates m_reactState; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b38946ae9..6c8925ca3 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7900" + #define REVISION_NR "7901" #endif // __REVISION_NR_H__ -- 2.11.4.GIT