mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 09:17:18 +00:00
fix(Core/Spells): several improvements to cooldowns (#7559)
- Reworked spell category cooldowns. - Implemented category cooldowns for pets. - Properly shows pet spell cooldowns in player's UI. - Corrected pet spell cooldowns with infinity duration. - Do not add/remove infinity spell cooldown on aura apply/remove if casted by item. - Closes #5263
This commit is contained in:
@@ -2707,7 +2707,7 @@ void Player::SendInitialSpells()
|
||||
data << uint32(itr->first);
|
||||
|
||||
data << uint16(itr->second.itemid); // cast item id
|
||||
data << uint16(sEntry->GetCategory()); // spell category
|
||||
data << uint16(itr->second.category); // spell category
|
||||
|
||||
// send infinity cooldown in special format
|
||||
if (itr->second.end >= infTime)
|
||||
@@ -2718,17 +2718,8 @@ void Player::SendInitialSpells()
|
||||
}
|
||||
|
||||
uint32 cooldown = itr->second.end > curTime ? itr->second.end - curTime : 0;
|
||||
|
||||
if (!sEntry->GetCategory() || (sEntry->CategoryRecoveryTime != sEntry->RecoveryTime && sEntry->RecoveryTime && sEntry->CategoryRecoveryTime)) // may be wrong, but anyway better than nothing...
|
||||
{
|
||||
data << cooldown; // cooldown
|
||||
data << uint32(0); // category cooldown
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint32(0); // cooldown
|
||||
data << cooldown; // category cooldown
|
||||
}
|
||||
data << uint32(itr->second.category ? 0 : cooldown); // cooldown
|
||||
data << uint32(itr->second.category ? cooldown : 0); // category cooldown
|
||||
}
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
@@ -3406,13 +3397,12 @@ void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)
|
||||
SendClearCooldown(spell_id, this);
|
||||
}
|
||||
|
||||
// I am not sure which one is more efficient
|
||||
void Player::RemoveCategoryCooldown(uint32 cat)
|
||||
{
|
||||
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
|
||||
if (i_scstore != sSpellsByCategoryStore.end())
|
||||
for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
|
||||
RemoveSpellCooldown(*i_scset, true);
|
||||
RemoveSpellCooldown(i_scset->second, true);
|
||||
}
|
||||
|
||||
void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
|
||||
@@ -3467,7 +3457,7 @@ void Player::_LoadSpellCooldowns(PreparedQueryResult result)
|
||||
{
|
||||
// some cooldowns can be already set at aura loading...
|
||||
|
||||
//QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUID().GetCounter()());
|
||||
//QueryResult* result = CharacterDatabase.PQuery("SELECT spell, category, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUID().GetCounter()());
|
||||
|
||||
if (result)
|
||||
{
|
||||
@@ -3477,9 +3467,10 @@ void Player::_LoadSpellCooldowns(PreparedQueryResult result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 spell_id = fields[0].GetUInt32();
|
||||
uint32 item_id = fields[1].GetUInt32();
|
||||
uint32 db_time = fields[2].GetUInt32();
|
||||
bool needSend = fields[3].GetBool();
|
||||
uint16 category = fields[1].GetUInt16();
|
||||
uint32 item_id = fields[2].GetUInt32();
|
||||
uint32 db_time = fields[3].GetUInt32();
|
||||
bool needSend = fields[4].GetBool();
|
||||
|
||||
if (!sSpellMgr->GetSpellInfo(spell_id))
|
||||
{
|
||||
@@ -3491,7 +3482,7 @@ void Player::_LoadSpellCooldowns(PreparedQueryResult result)
|
||||
if (db_time <= curTime)
|
||||
continue;
|
||||
|
||||
AddSpellCooldown(spell_id, item_id, (db_time - curTime)*IN_MILLISECONDS, needSend);
|
||||
_AddSpellCooldown(spell_id, category, item_id, (db_time - curTime) * IN_MILLISECONDS, needSend);
|
||||
|
||||
LOG_DEBUG("entities.player.loading", "Player (%s) spell %u, item %u cooldown loaded (%u secs).", GetGUID().ToString().c_str(), spell_id, item_id, uint32(db_time - curTime));
|
||||
} while (result->NextRow());
|
||||
@@ -3527,7 +3518,7 @@ void Player::_SaveSpellCooldowns(CharacterDatabaseTransaction trans, bool logout
|
||||
{
|
||||
if (first_round)
|
||||
{
|
||||
ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time, needSend) VALUES ";
|
||||
ss << "INSERT INTO character_spell_cooldown (guid, spell, category, item, time, needSend) VALUES ";
|
||||
first_round = false;
|
||||
}
|
||||
// next new/changed record prefix
|
||||
@@ -3535,7 +3526,7 @@ void Player::_SaveSpellCooldowns(CharacterDatabaseTransaction trans, bool logout
|
||||
ss << ',';
|
||||
|
||||
uint64 cooldown = uint64(((itr->second.end - curMSTime) / IN_MILLISECONDS) + curTime);
|
||||
ss << '(' << GetGUID().GetCounter() << ',' << itr->first << ',' << itr->second.itemid << ',' << cooldown << ',' << (itr->second.needSendToClient ? '1' : '0') << ')';
|
||||
ss << '(' << GetGUID().GetCounter() << ',' << itr->first << ',' << itr->second.category << "," << itr->second.itemid << ',' << cooldown << ',' << (itr->second.needSendToClient ? '1' : '0') << ')';
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
@@ -8862,15 +8853,26 @@ void Player::PetSpellInitialize()
|
||||
data << uint8(cooldownsCount);
|
||||
|
||||
uint32 curTime = World::GetGameTimeMS();
|
||||
uint32 infTime = World::GetGameTimeMS() + infinityCooldownDelayCheck;
|
||||
|
||||
for (CreatureSpellCooldowns::const_iterator itr = pet->m_CreatureSpellCooldowns.begin(); itr != pet->m_CreatureSpellCooldowns.end(); ++itr)
|
||||
{
|
||||
uint32 cooldown = (itr->second > curTime) ? itr->second - curTime : 0;
|
||||
uint16 category = itr->second.category;
|
||||
uint32 cooldown = (itr->second.end > curTime) ? itr->second.end - curTime : 0;
|
||||
|
||||
data << uint32(itr->first); // spellid
|
||||
data << uint16(0); // spell category?
|
||||
data << uint32(cooldown); // cooldown
|
||||
data << uint32(0); // category cooldown
|
||||
data << uint16(itr->second.category); // spell category
|
||||
|
||||
// send infinity cooldown in special format
|
||||
if (itr->second.end >= infTime)
|
||||
{
|
||||
data << uint32(1); // cooldown
|
||||
data << uint32(0x80000000); // category cooldown
|
||||
continue;
|
||||
}
|
||||
|
||||
data << uint32(category ? 0 : cooldown); // cooldown
|
||||
data << uint32(category ? cooldown : 0); // category cooldown
|
||||
}
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
@@ -8954,14 +8956,26 @@ void Player::VehicleSpellInitialize()
|
||||
data << uint8(cooldownCount);
|
||||
|
||||
uint32 curTime = World::GetGameTimeMS();
|
||||
uint32 infTime = World::GetGameTimeMS() + infinityCooldownDelayCheck;
|
||||
|
||||
for (CreatureSpellCooldowns::const_iterator itr = vehicle->m_CreatureSpellCooldowns.begin(); itr != vehicle->m_CreatureSpellCooldowns.end(); ++itr)
|
||||
{
|
||||
uint32 cooldown = (itr->second > curTime) ? itr->second - curTime : 0;
|
||||
data << uint32(itr->first); // SpellId
|
||||
data << uint16(0); // unk
|
||||
data << uint32(cooldown); // spell cooldown
|
||||
data << uint32(0); // category cooldown
|
||||
uint16 category = itr->second.category;
|
||||
uint32 cooldown = (itr->second.end > curTime) ? itr->second.end - curTime : 0;
|
||||
|
||||
data << uint32(itr->first); // spellid
|
||||
data << uint16(itr->second.category); // spell category
|
||||
|
||||
// send infinity cooldown in special format
|
||||
if (itr->second.end >= infTime)
|
||||
{
|
||||
data << uint32(1); // cooldown
|
||||
data << uint32(0x80000000); // category cooldown
|
||||
continue;
|
||||
}
|
||||
|
||||
data << uint32(category ? 0 : cooldown); // cooldown
|
||||
data << uint32(category ? cooldown : 0); // category cooldown
|
||||
}
|
||||
|
||||
GetSession()->SendPacket(&data);
|
||||
@@ -10152,59 +10166,79 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
|
||||
recTime = rec ? rec : catrecTime;
|
||||
}
|
||||
|
||||
// self spell cooldown
|
||||
if (recTime > 0)
|
||||
{
|
||||
AddSpellCooldown(spellInfo->Id, itemId, recTime, true, true);
|
||||
|
||||
if (needsCooldownPacket)
|
||||
{
|
||||
WorldPacket data;
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
// category spells
|
||||
if (cat && catrec > 0)
|
||||
{
|
||||
_AddSpellCooldown(spellInfo->Id, cat, itemId, catrecTime, true, true);
|
||||
if (needsCooldownPacket)
|
||||
{
|
||||
WorldPacket data;
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, catrecTime);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(cat);
|
||||
if (i_scstore != sSpellsByCategoryStore.end())
|
||||
{
|
||||
for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
|
||||
{
|
||||
if (*i_scset == spellInfo->Id) // skip main spell, already handled above
|
||||
continue;
|
||||
|
||||
// Only within the same spellfamily
|
||||
SpellInfo const* categorySpellInfo = sSpellMgr->GetSpellInfo(*i_scset);
|
||||
if (!categorySpellInfo || categorySpellInfo->SpellFamilyName != spellInfo->SpellFamilyName)
|
||||
if (i_scset->second == spellInfo->Id) // skip main spell, already handled above
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddSpellCooldown(*i_scset, itemId, catrecTime, !spellInfo->IsCooldownStartedOnEvent() && spellInfo->CategoryRecoveryTime != spellInfo->RecoveryTime && spellInfo->RecoveryTime && spellInfo->CategoryRecoveryTime); // Xinef: send category cooldowns on login if category cooldown is different from base cooldown
|
||||
// If spell category is applied by item, then other spells should be exists in item templates
|
||||
if ((itemId > 0) != i_scset->first)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_AddSpellCooldown(i_scset->second, cat, itemId, catrecTime, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// self spell cooldown
|
||||
if (recTime > 0)
|
||||
{
|
||||
_AddSpellCooldown(spellInfo->Id, 0, itemId, recTime, true, true);
|
||||
|
||||
if (needsCooldownPacket)
|
||||
{
|
||||
WorldPacket data;
|
||||
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, rec);
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, uint32 end_time, bool needSendToClient, bool forceSendToSpectator)
|
||||
void Player::_AddSpellCooldown(uint32 spellid, uint16 categoryId, uint32 itemid, uint32 end_time, bool needSendToClient, bool forceSendToSpectator)
|
||||
{
|
||||
SpellCooldown sc;
|
||||
sc.end = World::GetGameTimeMS() + end_time;
|
||||
sc.category = categoryId;
|
||||
sc.itemid = itemid;
|
||||
sc.maxduration = end_time;
|
||||
sc.sendToSpectator = false;
|
||||
sc.needSendToClient = needSendToClient;
|
||||
|
||||
if (end_time >= SPECTATOR_COOLDOWN_MIN * IN_MILLISECONDS && end_time <= SPECTATOR_COOLDOWN_MAX * IN_MILLISECONDS)
|
||||
{
|
||||
if (NeedSendSpectatorData() && forceSendToSpectator && (itemid || HasActiveSpell(spellid)))
|
||||
{
|
||||
sc.sendToSpectator = true;
|
||||
ArenaSpectator::SendCommand_Cooldown(FindMap(), GetGUID(), "ACD", spellid, end_time / IN_MILLISECONDS, end_time / IN_MILLISECONDS);
|
||||
}
|
||||
m_spellCooldowns[spellid] = sc;
|
||||
}
|
||||
|
||||
m_spellCooldowns[spellid] = std::move(sc);
|
||||
}
|
||||
|
||||
void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, uint32 end_time, bool needSendToClient, bool forceSendToSpectator)
|
||||
{
|
||||
_AddSpellCooldown(spellid, 0, itemid, end_time, needSendToClient, forceSendToSpectator);
|
||||
}
|
||||
|
||||
void Player::ModifySpellCooldown(uint32 spellId, int32 cooldown)
|
||||
|
||||
Reference in New Issue
Block a user