[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
This commit is contained in:
VladimirMangos 2009-05-27 19:24:12 +04:00
parent 1abe4c0d79
commit 4d8adefe70
7 changed files with 175 additions and 122 deletions

View file

@ -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();

View file

@ -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

View file

@ -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 )

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "7900"
#define REVISION_NR "7901"
#endif // __REVISION_NR_H__