Fix action buttons sent to client when swapping between talent specs. Storage related parts by Hunuza (MaNGOS), big thanks.

--HG--
branch : trunk
This commit is contained in:
Machiavelli
2010-04-28 16:08:31 +02:00
parent 311d108529
commit ab013e42c9
5 changed files with 172 additions and 101 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ bool LoginQueryHolder::Initialize()
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS,"SELECT quest FROM character_queststatus_weekly WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS,"SELECT quest FROM character_queststatus_weekly WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,text,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT a.button,a.action,a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT a.spec,a.button,a.action,a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.guid = '%u' ORDER BY spec,button", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid));
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
+3 -2
View File
@@ -1020,12 +1020,13 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
uint32 action = ACTION_BUTTON_ACTION(packetData); uint32 action = ACTION_BUTTON_ACTION(packetData);
uint8 type = ACTION_BUTTON_TYPE(packetData); uint8 type = ACTION_BUTTON_TYPE(packetData);
uint8 spec = GetPlayer()->GetActiveSpec();
sLog.outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type); sLog.outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type);
if (!packetData) if (!packetData)
{ {
sLog.outDetail("MISC: Remove action from button %u", button); sLog.outDetail("MISC: Remove action from button %u", button);
GetPlayer()->removeActionButton(button); GetPlayer()->removeActionButton(spec, button);
} }
else else
{ {
@@ -1048,7 +1049,7 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
sLog.outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button); sLog.outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button);
return; return;
} }
GetPlayer()->addActionButton(button,action,type); GetPlayer()->addActionButton(spec, button, action, type);
} }
} }
+131 -60
View File
@@ -734,7 +734,7 @@ bool Player::Create(uint32 guidlow, const std::string& name, uint8 race, uint8 c
// original action bar // original action bar
for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr) for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
addActionButton(action_itr->button,action_itr->action,action_itr->type); addActionButton(0, action_itr->button,action_itr->action, action_itr->type);
// original items // original items
CharStartOutfitEntry const* oEntry = NULL; CharStartOutfitEntry const* oEntry = NULL;
@@ -5940,13 +5940,20 @@ void Player::SendActionButtons(uint32 state) const
sLog.outDetail("Sending Action Buttons for '%u' spec '%u'", GetGUIDLow(), m_activeSpec); sLog.outDetail("Sending Action Buttons for '%u' spec '%u'", GetGUIDLow(), m_activeSpec);
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4)); WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
data << uint8(state); // can be 0, 1, 2 data << uint8(state);
/*
state can be 0, 1, 2
0 - Looks to be sent when initial action buttons get sent, however on Trinity we use 1 since 0 had some difficulties
1 - Used in any SMSG_ACTION_BUTTONS packet with button data on Trinity. Only used after spec swaps on retail.
2 - Clears the action bars client sided. This is sent during spec swap before unlearning and before sending the new buttons
*/
if (state != 2) if (state != 2)
{ {
ActionButtonList const& currentActionButtons = m_actionButtons[m_activeSpec];
for (uint16 button = 0; button < MAX_ACTION_BUTTONS; ++button) for (uint16 button = 0; button < MAX_ACTION_BUTTONS; ++button)
{ {
ActionButtonList::const_iterator itr = m_actionButtons.find(button); ActionButtonList::const_iterator itr = currentActionButtons.find(button);
if (itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED) if (itr != currentActionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED)
data << uint32(itr->second.packedData); data << uint32(itr->second.packedData);
else else
data << uint32(0); data << uint32(0);
@@ -5957,18 +5964,31 @@ void Player::SendActionButtons(uint32 state) const
sLog.outDetail("Action Buttons for '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec); sLog.outDetail("Action Buttons for '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
} }
ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player, bool msg)
{ {
if (button >= MAX_ACTION_BUTTONS) if (button >= MAX_ACTION_BUTTONS)
{ {
sLog.outError("Action %u not added into button %u for player %s: button must be < 144", action, button, GetName()); if (msg)
return NULL; {
if (player)
sLog.outError( "Action %u not added into button %u for player %s: button must be < %u", action, button, player->GetName(), MAX_ACTION_BUTTONS );
else
sLog.outError( "Table `playercreateinfo_action` have action %u into button %u : button must be < %u", action, button, MAX_ACTION_BUTTONS );
}
return false;
} }
if (action >= MAX_ACTION_BUTTON_ACTION_VALUE) if (action >= MAX_ACTION_BUTTON_ACTION_VALUE)
{ {
sLog.outError("Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE); if (msg)
return NULL; {
if (player)
sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, player->GetName(), MAX_ACTION_BUTTON_ACTION_VALUE );
else
sLog.outError( "Table `playercreateinfo_action` have action %u into button %u : action must be < %u", action, button, MAX_ACTION_BUTTON_ACTION_VALUE );
}
return false;
} }
switch (type) switch (type)
@@ -5976,29 +5996,50 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
case ACTION_BUTTON_SPELL: case ACTION_BUTTON_SPELL:
if (!sSpellStore.LookupEntry(action)) if (!sSpellStore.LookupEntry(action))
{ {
sLog.outError("Action %u not added into button %u for player %s: spell not exist", action, button, GetName()); if (msg)
return NULL; {
if (player)
sLog.outError( "Spell action %u not added into button %u for player %s: spell not exist", action, button, player->GetName() );
else
sLog.outError( "Table `playercreateinfo_action` have spell action %u into button %u: spell not exist", action, button );
}
return false;
} }
if (!HasSpell(action)) if (player && !player->HasSpell(action))
{ {
sLog.outError("Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName()); if (msg)
return NULL; sLog.outError( "Spell action %u not added into button %u for player %s: player don't known this spell", action, button, player->GetName() );
return false;
} }
break; break;
case ACTION_BUTTON_ITEM: case ACTION_BUTTON_ITEM:
if (!objmgr.GetItemPrototype(action)) if (!ObjectMgr::GetItemPrototype(action))
{ {
sLog.outError("Action %u not added into button %u for player %s: item not exist", action, button, GetName()); if (msg)
return NULL; {
if (player)
sLog.outError( "Item action %u not added into button %u for player %s: item not exist", action, button, player->GetName() );
else
sLog.outError( "Table `playercreateinfo_action` have item action %u into button %u: item not exist", action, button );
}
return false;
} }
break; break;
default: default:
break; // pther cases not checked at this moment break; // other cases not checked at this moment
} }
return true;
}
ActionButton* Player::addActionButton(uint8 spec, uint8 button, uint32 action, uint8 type)
{
if (spec == GetActiveSpec() && !IsActionButtonDataValid(button, action, type, this))
return NULL;
// it create new button (NEW state) if need or return existed // it create new button (NEW state) if need or return existed
ActionButton& ab = m_actionButtons[button]; ActionButton& ab = m_actionButtons[spec][button];
// set data and update to CHANGED if not NEW // set data and update to CHANGED if not NEW
ab.SetActionAndType(action,ActionButtonType(type)); ab.SetActionAndType(action,ActionButtonType(type));
@@ -6007,25 +6048,31 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
return &ab; return &ab;
} }
void Player::removeActionButton(uint8 button) void Player::removeActionButton(uint8 spec, uint8 button)
{ {
ActionButtonList::iterator buttonItr = m_actionButtons.find(button); ActionButtonList& currentActionButtonList = m_actionButtons[spec];
if (buttonItr == m_actionButtons.end()) ActionButtonList::iterator buttonItr = currentActionButtonList.find(button);
if (buttonItr == currentActionButtonList.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
return; return;
if (!buttonItr->second.canRemoveByClient)
{
buttonItr->second.canRemoveByClient = true;
return;
}
if (buttonItr->second.uState == ACTIONBUTTON_NEW) if (buttonItr->second.uState == ACTIONBUTTON_NEW)
m_actionButtons.erase(buttonItr); // new and not saved currentActionButtonList.erase(buttonItr); // new and not saved
else else
buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save
sLog.outDetail("Action Button '%u' Removed from Player '%u'", button, GetGUIDLow()); sLog.outDetail("Action Button '%u' Removed from Player '%u'", button, GetGUIDLow());
} }
ActionButton const* Player::GetActionButton(uint8 button)
{
ActionButtonList& currentActionButtonList = m_actionButtons[m_activeSpec];
ActionButtonList::iterator buttonItr = currentActionButtonList.find(button);
if (buttonItr == currentActionButtonList.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
return NULL;
return &buttonItr->second;
}
bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport) bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport)
{ {
if (!Unit::SetPosition(x, y, z, orientation, teleport)) if (!Unit::SetPosition(x, y, z, orientation, teleport))
@@ -16235,24 +16282,28 @@ bool Player::isAllowedToLoot(const Creature* creature)
void Player::_LoadActions(QueryResult_AutoPtr result, bool /*startup*/) void Player::_LoadActions(QueryResult_AutoPtr result, bool /*startup*/)
{ {
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
m_actionButtons[i].clear();
if (result) if (result)
{ {
do do
{ {
Field *fields = result->Fetch(); Field *fields = result->Fetch();
uint8 spec = fields[0].GetUInt8();
uint8 button = fields[1].GetUInt8();
uint32 action = fields[2].GetUInt32();
uint8 type = fields[3].GetUInt8();
uint8 button = fields[0].GetUInt8(); sLog.outBasic("SPEC: %u, button: %u, action %u, type %u", spec, button, action, type);
uint32 action = fields[1].GetUInt32(); if (ActionButton* ab = addActionButton(spec, button, action, type))
uint8 type = fields[2].GetUInt8();
if (ActionButton* ab = addActionButton(button, action, type))
ab->uState = ACTIONBUTTON_UNCHANGED; ab->uState = ACTIONBUTTON_UNCHANGED;
else else
{ {
sLog.outError(" ...at loading, and will deleted in DB also"); sLog.outError(" ...at loading, and will deleted in DB also");
// Will deleted in DB at next save (it can create data until save but marked as deleted) // Will deleted in DB at next save (it can create data until save but marked as deleted)
m_actionButtons[button].uState = ACTIONBUTTON_DELETED; m_actionButtons[spec][button].uState = ACTIONBUTTON_DELETED;
} }
} }
while (result->NextRow()); while (result->NextRow());
@@ -17515,31 +17566,34 @@ void Player::SaveGoldToDB()
void Player::_SaveActions() void Player::_SaveActions()
{ {
for (ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end();) for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
{
for (ActionButtonList::iterator itr = m_actionButtons[i].begin(); itr != m_actionButtons[i].end();)
{ {
switch (itr->second.uState) switch (itr->second.uState)
{ {
case ACTIONBUTTON_NEW: case ACTIONBUTTON_NEW:
CharacterDatabase.PExecute("INSERT INTO character_action (guid,spec,button,action,type) VALUES ('%u', '%u', '%u', '%u', '%u')", CharacterDatabase.PExecute("INSERT INTO character_action (guid,spec,button,action,type) VALUES ('%u', '%u', '%u', '%u', '%u')",
GetGUIDLow(), (uint32)m_activeSpec, (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType()); GetGUIDLow(), i, (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType());
itr->second.uState = ACTIONBUTTON_UNCHANGED; itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr; ++itr;
break; break;
case ACTIONBUTTON_CHANGED: case ACTIONBUTTON_CHANGED:
CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid = '%u' AND button = '%u' AND spec = '%u'", CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid = '%u' AND button = '%u' AND spec = '%u'",
(uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first, (uint32)m_activeSpec); (uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first, i);
itr->second.uState = ACTIONBUTTON_UNCHANGED; itr->second.uState = ACTIONBUTTON_UNCHANGED;
++itr; ++itr;
break; break;
case ACTIONBUTTON_DELETED: case ACTIONBUTTON_DELETED:
CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u' and button = '%u' and spec = '%u'", GetGUIDLow(), (uint32)itr->first, (uint32)m_activeSpec); CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u' and button = '%u' and spec = '%u'", GetGUIDLow(), (uint32)itr->first, i);
m_actionButtons.erase(itr++); m_actionButtons[i].erase(itr++);
break; break;
default: default:
++itr; ++itr;
break; break;
} }
} }
}
} }
void Player::_SaveAuras() void Player::_SaveAuras()
@@ -23332,25 +23386,38 @@ void Player::_SaveTalents()
void Player::UpdateSpecCount(uint8 count) void Player::UpdateSpecCount(uint8 count)
{ {
if (GetSpecsCount() == count) uint32 curCount = GetSpecsCount();
if (curCount == count)
return; return;
if (count == MIN_TALENT_SPECS) if (m_activeSpec >= count)
ActivateSpec(0);
// Copy spec data
if (count > curCount)
{ {
_SaveActions(); // make sure the button list is cleaned up ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
// active spec becomes only spec? for (ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ++itr)
CharacterDatabase.PExecute("DELETE FROM character_action WHERE spec<>'%u' AND guid='%u'",m_activeSpec, GetGUIDLow());
m_activeSpec = 0;
}
else if (count == MAX_TALENT_SPECS)
{ {
_SaveActions(); // make sure the button list is cleaned up if (itr->second.uState != ACTIONBUTTON_DELETED)
for (ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end(); ++itr) {
CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,spec) VALUES ('%u', '%u', '%u', '%u', '%u')", for (uint8 spec = curCount; spec < count; ++spec)
GetGUIDLow(), uint32(itr->first), uint32(itr->second.GetAction()), uint32(itr->second.GetType()), 1); addActionButton(spec, itr->first, itr->second.GetAction(), itr->second.GetType());
} }
else }
return; }
// Delete spec data for removed spec.
else if (count < curCount)
{
// Delete action buttons for removed spec
for (uint8 spec = count; spec < curCount; ++spec)
{
// Delete action buttons for removed spec
for (uint8 button = 0; button < MAX_ACTION_BUTTONS; ++button)
removeActionButton(spec,button);
}
}
SetSpecsCount(count); SetSpecsCount(count);
@@ -23362,17 +23429,19 @@ void Player::ActivateSpec(uint8 spec)
if (GetActiveSpec() == spec) if (GetActiveSpec() == spec)
return; return;
if (GetSpecsCount() != MAX_TALENT_SPECS) if (spec > GetSpecsCount())
return; return;
// TODO:
// HACK: this shouldn't be checked at such a low level function but rather at the moment the spell is casted
if (GetMap()->IsBattleGround() && !HasAura(44521)) // In BattleGround with no Preparation buff if (GetMap()->IsBattleGround() && !HasAura(44521)) // In BattleGround with no Preparation buff
return; return;
_SaveActions();
if (IsNonMeleeSpellCasted(false)) if (IsNonMeleeSpellCasted(false))
InterruptNonMeleeSpells(false); InterruptNonMeleeSpells(false);
SetActiveSpec(spec);
UnsummonPetTemporaryIfAny(); UnsummonPetTemporaryIfAny();
ClearComboPointHolders(); ClearComboPointHolders();
ClearAllReactives(); ClearAllReactives();
@@ -23387,7 +23456,6 @@ void Player::ActivateSpec(uint8 spec)
// Let client clear his current Actions // Let client clear his current Actions
SendActionButtons(2); SendActionButtons(2);
m_actionButtons.clear();
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{ {
@@ -23431,7 +23499,6 @@ void Player::ActivateSpec(uint8 spec)
if (GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) if (GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
RemoveAurasDueToSpell(old_gp->SpellId); RemoveAurasDueToSpell(old_gp->SpellId);
SetActiveSpec(spec);
uint32 spentTalents = 0; uint32 spentTalents = 0;
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
@@ -23481,8 +23548,12 @@ void Player::ActivateSpec(uint8 spec)
m_usedTalentCount = spentTalents; m_usedTalentCount = spentTalents;
InitTalentForLevel(); InitTalentForLevel();
if (QueryResult_AutoPtr result = CharacterDatabase.PQuery("SELECT button,action,type FROM character_action WHERE guid = '%u' AND spec = '%u' ORDER BY button", GetGUIDLow(), m_activeSpec)) ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
_LoadActions(result, false); for (ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ++itr)
if (itr->second.uState != ACTIONBUTTON_DELETED)
// remove broken without any output (it can be not correct because talents not copied at spec creating)
if (!IsActionButtonDataValid(itr->first, itr->second.GetAction(), itr->second.GetType(), this, false))
removeActionButton(m_activeSpec, itr->first);
ResummonPetTemporaryUnSummonedIfAny(); ResummonPetTemporaryUnSummonedIfAny();
SendActionButtons(1); SendActionButtons(1);
+8 -11
View File
@@ -167,11 +167,10 @@ enum ActionButtonType
struct ActionButton struct ActionButton
{ {
ActionButton() : packedData(0), uState(ACTIONBUTTON_NEW), canRemoveByClient(true){} ActionButton() : packedData(0), uState(ACTIONBUTTON_NEW) {}
uint32 packedData; uint32 packedData;
ActionButtonUpdateState uState; ActionButtonUpdateState uState;
bool canRemoveByClient;
// helpers // helpers
ActionButtonType GetType() const { return ActionButtonType(ACTION_BUTTON_TYPE(packedData)); } ActionButtonType GetType() const { return ActionButtonType(ACTION_BUTTON_TYPE(packedData)); }
@@ -1665,10 +1664,13 @@ class Player : public Unit, public GridObject<Player>
m_cinematic = cine; m_cinematic = cine;
} }
ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); ActionButton* addActionButton(uint8 spec, uint8 button, uint32 action, uint8 type);
void removeActionButton(uint8 button); void removeActionButton(uint8 spec, uint8 button);
void SendInitialActionButtons() const { SendActionButtons(0); } uint32 GetActionButtonSpell(uint8 button) const;
ActionButton const* GetActionButton(uint8 button);
void SendInitialActionButtons() const { SendActionButtons(1); }
void SendActionButtons(uint32 state) const; void SendActionButtons(uint32 state) const;
bool IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player, bool msg = true);
PvPInfo pvpInfo; PvPInfo pvpInfo;
void UpdatePvPState(bool onlyFFA = false); void UpdatePvPState(bool onlyFFA = false);
@@ -2336,11 +2338,6 @@ class Player : public Unit, public GridObject<Player>
//bool isActiveObject() const { return true; } //bool isActiveObject() const { return true; }
bool canSeeSpellClickOn(Creature const* creature) const; bool canSeeSpellClickOn(Creature const* creature) const;
uint32 GetActionButtonSpell(uint8 button) const
{
ActionButtonList::const_iterator ab = m_actionButtons.find(button);
return ab != m_actionButtons.end() && ab->second.uState != ACTIONBUTTON_DELETED && ab->second.GetType() == ACTION_BUTTON_SPELL ? ab->second.GetAction() : 0;
}
uint32 GetChampioningFaction() const { return m_ChampioningFaction; } uint32 GetChampioningFaction() const { return m_ChampioningFaction; }
void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; } void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; }
@@ -2485,7 +2482,7 @@ class Player : public Unit, public GridObject<Player>
uint32 m_Glyphs[MAX_TALENT_SPECS][MAX_GLYPH_SLOT_INDEX]; uint32 m_Glyphs[MAX_TALENT_SPECS][MAX_GLYPH_SLOT_INDEX];
ActionButtonList m_actionButtons; ActionButtonList m_actionButtons[MAX_TALENT_SPECS];
float m_auraBaseMod[BASEMOD_END][MOD_END]; float m_auraBaseMod[BASEMOD_END][MOD_END];
int16 m_baseRatingValue[MAX_COMBAT_RATING]; int16 m_baseRatingValue[MAX_COMBAT_RATING];
+5 -3
View File
@@ -7602,8 +7602,11 @@ void Spell::EffectCastButtons(uint32 i)
for (; n_buttons; n_buttons--, button_id++) for (; n_buttons; n_buttons--, button_id++)
{ {
if (uint32 spell_id = p_caster->GetActionButtonSpell(button_id)) ActionButton const* ab = p_caster->GetActionButton(button_id);
{ if (!ab || ab->GetAction() != ACTION_BUTTON_SPELL)
continue;;
uint32 spell_id = ab->GetAction();
if (!spell_id) if (!spell_id)
continue; continue;
@@ -7620,7 +7623,6 @@ void Spell::EffectCastButtons(uint32 i)
m_caster->ModifyPower(POWER_MANA, -(int32)cost); m_caster->ModifyPower(POWER_MANA, -(int32)cost);
p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0); p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0);
} }
}
} }
void Spell::EffectRechargeManaGem(uint32 /*i*/) void Spell::EffectRechargeManaGem(uint32 /*i*/)