aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/characters_database.sql4
-rw-r--r--sql/updates/characters/2015_10_29_00_characters_335.sql7
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp8
-rw-r--r--src/server/game/DataStores/DBCStores.cpp7
-rw-r--r--src/server/game/DataStores/DBCStores.h1
-rw-r--r--src/server/game/DataStores/DBCStructure.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp9
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp2
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellHistory.cpp219
-rw-r--r--src/server/game/Spells/SpellHistory.h29
12 files changed, 155 insertions, 139 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index 9f32e0f6fcb..d8f3c792c2e 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -1154,6 +1154,8 @@ CREATE TABLE `character_spell_cooldown` (
`spell` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell Identifier',
`item` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Item Identifier',
`time` int(10) unsigned NOT NULL DEFAULT '0',
+ `categoryId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell category Id',
+ `categoryEnd` int(10) unsigned NOT NULL DEFAULT '0';
PRIMARY KEY (`guid`,`spell`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2301,6 +2303,8 @@ CREATE TABLE `pet_spell_cooldown` (
`guid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier, Low part',
`spell` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell Identifier',
`time` int(10) unsigned NOT NULL DEFAULT '0',
+ `categoryId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell category Id',
+ `categoryEnd` int(10) unsigned NOT NULL DEFAULT '0';
PRIMARY KEY (`guid`,`spell`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/sql/updates/characters/2015_10_29_00_characters_335.sql b/sql/updates/characters/2015_10_29_00_characters_335.sql
new file mode 100644
index 00000000000..94c9066c6ae
--- /dev/null
+++ b/sql/updates/characters/2015_10_29_00_characters_335.sql
@@ -0,0 +1,7 @@
+ALTER TABLE `character_spell_cooldown`
+ ADD `categoryId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell category Id' AFTER `time`,
+ ADD `categoryEnd` int(10) unsigned NOT NULL DEFAULT '0' AFTER `categoryId`;
+
+ALTER TABLE `pet_spell_cooldown`
+ ADD `categoryId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Spell category Id' AFTER `time`,
+ ADD `categoryEnd` int(10) unsigned NOT NULL DEFAULT '0' AFTER `categoryId`;
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 4557dcab996..afc8c783ca6 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -105,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_SOCIALLIST, "SELECT friend, flags, note FROM character_social JOIN characters ON characters.guid = character_social.friend WHERE character_social.guid = ? AND deleteinfos_name IS NULL LIMIT 255", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time, categoryId, categoryEnd FROM character_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gr.rid, gm.pnote, gm.offnote "
@@ -498,7 +498,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET knownTitles = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE, "UPDATE characters SET chosenTitle = 0 WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS, "DELETE FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHAR_SPELL_COOLDOWN, "INSERT INTO character_spell_cooldown (guid, spell, item, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHARACTER, "DELETE FROM characters WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_ACTION, "DELETE FROM character_action WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_AURA, "DELETE FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
@@ -578,12 +578,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PET_SPELL_COOLDOWNS, "DELETE FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_BOTH);
- PrepareStatement(CHAR_INS_PET_SPELL_COOLDOWN, "INSERT INTO pet_spell_cooldown (guid, spell, time) VALUES (?, ?, ?)", CONNECTION_BOTH);
+ PrepareStatement(CHAR_INS_PET_SPELL_COOLDOWN, "INSERT INTO pet_spell_cooldown (guid, spell, time, categoryId, categoryEnd) VALUES (?, ?, ?, ?, ?)", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE guid = ? and spell = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH);
PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, "
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index e268b376b34..14e4631548e 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -163,7 +163,6 @@ DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
-SpellCategoryStore sSpellsByCategoryStore;
PetFamilySpellsStore sPetFamilySpellsStore;
DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore(SpellCastTimefmt);
@@ -430,12 +429,6 @@ void LoadDBCStores(const std::string& dataPath)
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex);
- for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
- {
- SpellEntry const* spell = sSpellStore.LookupEntry(i);
- if (spell && spell->Category)
- sSpellsByCategoryStore[spell->Category].insert(i);
- }
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
{
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index d955e9581ab..858cd33f8fc 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -165,7 +165,6 @@ extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
extern DBCStorage <SpellFocusObjectEntry> sSpellFocusObjectStore;
extern DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore;
extern DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore;
-extern SpellCategoryStore sSpellsByCategoryStore;
extern PetFamilySpellsStore sPetFamilySpellsStore;
extern DBCStorage <SpellRadiusEntry> sSpellRadiusStore;
extern DBCStorage <SpellRangeEntry> sSpellRangeStore;
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 092ef714145..72317a196cb 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -1737,8 +1737,6 @@ struct SpellEntry
//uint32 SpellDifficultyId; // 233 3.3.0
};
-typedef std::set<uint32> SpellCategorySet;
-typedef std::map<uint32, SpellCategorySet > SpellCategoryStore;
typedef std::set<uint32> PetFamilySpellsSet;
typedef std::map<uint32, PetFamilySpellsSet > PetFamilySpellsStore;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 5df5fa90578..26f2e912725 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -15912,7 +15912,7 @@ bool Player::GetQuestRewardStatus(uint32 quest_id) const
uint16 eventId = sGameEventMgr->GetEventIdForQuest(qInfo);
if (m_seasonalquests.find(eventId) != m_seasonalquests.end())
return m_seasonalquests.find(eventId)->second.find(quest_id) != m_seasonalquests.find(eventId)->second.end();
-
+
return false;
}
@@ -22723,7 +22723,7 @@ void Player::ApplyEquipCooldown(Item* pItem)
continue;
// Don't replace longer cooldowns by equip cooldown if we have any.
- if (GetSpellHistory()->GetRemainingCooldown(spellData.SpellId) > 30 * IN_MILLISECONDS)
+ if (GetSpellHistory()->GetRemainingCooldown(sSpellMgr->EnsureSpellInfo(spellData.SpellId)) > 30 * IN_MILLISECONDS)
continue;
GetSpellHistory()->AddCooldown(spellData.SpellId, pItem->GetEntry(), std::chrono::seconds(30));
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index db352ec80dd..b9547070a76 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -2715,15 +2715,6 @@ void ObjectMgr::LoadItemTemplates()
TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has broken spell in spellid_%d (%d)", entry, j+1, itemTemplate.Spells[j].SpellId);
itemTemplate.Spells[j].SpellId = 0;
}
-
- if (spellInfo && itemTemplate.Spells[j].SpellCategory
- && itemTemplate.Spells[j].SpellCategory != SPELL_CATEGORY_FOOD)
- {
- bool added = sSpellsByCategoryStore[itemTemplate.Spells[j].SpellCategory].insert(itemTemplate.Spells[j].SpellId).second;
- if (added)
- TC_LOG_DEBUG("sql.sql", "Item(Entry: %u) spellid_%d (%d) category %u added to sSpellsByCategoryStore",
- entry, j + 1, itemTemplate.Spells[j].SpellId, itemTemplate.Spells[j].SpellCategory);
- }
}
}
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index e42f66c6ffb..9313301832a 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1487,7 +1487,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
{
// This additional check is needed to add a minimal delay before cooldown in in effect
// to allow all bubbles broken by a single damage source proc mana return
- if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetId()) <= 11)
+ if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetSpellInfo()) <= 11)
break;
}
else // and add if needed
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index e1302d48d2f..4e98efe10d4 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4668,7 +4668,7 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_NOT_READY;
}
- if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo))
+ if (!m_caster->GetSpellHistory()->IsReady(m_spellInfo, m_castItemEntry))
{
if (m_triggeredByAuraSpell)
return SPELL_FAILED_DONT_REPORT;
diff --git a/src/server/game/Spells/SpellHistory.cpp b/src/server/game/Spells/SpellHistory.cpp
index ca0e8cc6238..13d1c6f50b2 100644
--- a/src/server/game/Spells/SpellHistory.cpp
+++ b/src/server/game/Spells/SpellHistory.cpp
@@ -43,6 +43,8 @@ struct SpellHistory::PersistenceHelper<Player>
cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[2].GetUInt32()));
cooldownEntry->ItemId = fields[1].GetUInt32();
+ cooldownEntry->CategoryId = fields[3].GetUInt32();
+ cooldownEntry->CategoryEnd = Clock::from_time_t(time_t(fields[4].GetUInt32()));
return true;
}
@@ -51,6 +53,8 @@ struct SpellHistory::PersistenceHelper<Player>
stmt->setUInt32(index++, cooldown.first);
stmt->setUInt32(index++, cooldown.second.ItemId);
stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ stmt->setUInt32(index++, cooldown.second.CategoryId);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CategoryEnd)));
}
};
@@ -70,6 +74,8 @@ struct SpellHistory::PersistenceHelper<Pet>
cooldownEntry->CooldownEnd = Clock::from_time_t(time_t(fields[1].GetUInt32()));
cooldownEntry->ItemId = 0;
+ cooldownEntry->CategoryId = fields[2].GetUInt32();
+ cooldownEntry->CategoryEnd = Clock::from_time_t(time_t(fields[3].GetUInt32()));
return true;
}
@@ -77,6 +83,8 @@ struct SpellHistory::PersistenceHelper<Pet>
{
stmt->setUInt32(index++, cooldown.first);
stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CooldownEnd)));
+ stmt->setUInt32(index++, cooldown.second.CategoryId);
+ stmt->setUInt32(index++, uint32(Clock::to_time_t(cooldown.second.CategoryEnd)));
}
};
@@ -92,7 +100,11 @@ void SpellHistory::LoadFromDB(PreparedQueryResult cooldownsResult)
uint32 spellId;
CooldownEntry cooldown;
if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown))
+ {
_spellCooldowns[spellId] = cooldown;
+ if (cooldown.CategoryId)
+ _categoryCooldowns[cooldown.CategoryId] = &_spellCooldowns[spellId];
+ }
} while (cooldownsResult->NextRow());
}
@@ -125,10 +137,18 @@ void SpellHistory::Update()
{
SQLTransaction t;
Clock::time_point now = Clock::now();
+ for (auto itr = _categoryCooldowns.begin(); itr != _categoryCooldowns.end();)
+ {
+ if (itr->second->CategoryEnd < now)
+ itr = _categoryCooldowns.erase(itr);
+ else
+ ++itr;
+ }
+
for (auto itr = _spellCooldowns.begin(); itr != _spellCooldowns.end();)
{
if (itr->second.CooldownEnd < now)
- itr = _spellCooldowns.erase(itr);
+ itr = EraseCooldown(itr);
else
++itr;
}
@@ -136,29 +156,37 @@ void SpellHistory::Update()
void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell /*= nullptr*/)
{
+ HandleCooldowns(spellInfo, item ? item->GetEntry() : 0, spell);
+}
+
+void SpellHistory::HandleCooldowns(SpellInfo const* spellInfo, uint32 itemID, Spell* spell /*= nullptr*/)
+{
if (Player* player = _owner->ToPlayer())
{
// potions start cooldown until exiting combat
- if (item && (item->IsPotion() || spellInfo->IsCooldownStartedOnEvent()))
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemID))
{
- player->SetLastPotionId(item->GetEntry());
- return;
+ if (itemTemplate->IsPotion() || spellInfo->IsCooldownStartedOnEvent())
+ {
+ player->SetLastPotionId(itemID);
+ return;
+ }
}
}
if (spellInfo->IsCooldownStartedOnEvent() || spellInfo->IsPassive() || (spell && spell->IsIgnoringCooldowns()))
return;
- StartCooldown(spellInfo, item ? item->GetEntry() : 0, spell);
+ StartCooldown(spellInfo, itemID, spell);
}
-bool SpellHistory::IsReady(SpellInfo const* spellInfo) const
+bool SpellHistory::IsReady(SpellInfo const* spellInfo, uint32 itemId /*= 0*/) const
{
if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
if (IsSchoolLocked(spellInfo->GetSchoolMask()))
return false;
- if (HasCooldown(spellInfo->Id))
+ if (HasCooldown(spellInfo->Id, itemId))
return false;
return true;
@@ -168,42 +196,33 @@ template<>
void SpellHistory::WritePacket<Pet>(WorldPacket& packet) const
{
Clock::time_point now = Clock::now();
-
+
uint8 cooldownsCount = _spellCooldowns.size();
packet << uint8(cooldownsCount);
for (auto const& spellCooldown : _spellCooldowns)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellCooldown.first);
- if (!spellInfo)
- {
- packet << uint32(0);
- packet << uint16(0);
- packet << uint32(0);
- packet << uint32(0);
- continue;
- }
-
- packet << uint32(spellCooldown.first); // spell ID
- packet << uint16(spellInfo->GetCategory()); // spell category
+ packet << uint32(spellCooldown.first); // spell ID
+ packet << uint16(spellCooldown.second.CategoryId); // spell category
if (!spellCooldown.second.OnHold)
{
- uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
- if (cooldownDuration <= 0)
+ std::chrono::milliseconds cooldownDuration = std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now);
+ if (cooldownDuration.count() <= 0)
{
packet << uint32(0);
packet << uint32(0);
continue;
}
- if (spellInfo->GetCategory())
+ std::chrono::milliseconds categoryDuration = std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CategoryEnd - now);
+ if (categoryDuration.count() > 0)
{
packet << uint32(0);
- packet << uint32(cooldownDuration);
+ packet << uint32(categoryDuration.count());
}
else
{
- packet << uint32(cooldownDuration);
+ packet << uint32(cooldownDuration.count());
packet << uint32(0);
}
}
@@ -216,23 +235,13 @@ void SpellHistory::WritePacket<Player>(WorldPacket& packet) const
Clock::time_point now = Clock::now();
Clock::time_point infTime = now + InfinityCooldownDelayCheck;
- uint16 cooldownsCount = _spellCooldowns.size();
- size_t dataPos = packet.wpos();
- packet << uint16(cooldownsCount);
+ packet << uint16(_spellCooldowns.size());
for (auto const& spellCooldown : _spellCooldowns)
{
- SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(spellCooldown.first);
- if (!sEntry)
- {
- --cooldownsCount;
- continue;
- }
-
packet << uint32(spellCooldown.first);
-
packet << uint16(spellCooldown.second.ItemId); // cast item id
- packet << uint16(sEntry->GetCategory()); // spell category
+ packet << uint16(spellCooldown.second.CategoryId); // spell category
// send infinity cooldown in special format
if (spellCooldown.second.CooldownEnd >= infTime)
@@ -242,21 +251,26 @@ void SpellHistory::WritePacket<Player>(WorldPacket& packet) const
continue;
}
- uint32 cooldownDuration = spellCooldown.second.CooldownEnd > now ? std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now).count() : 0;
+ std::chrono::milliseconds cooldownDuration = std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CooldownEnd - now);
+ if (cooldownDuration.count() <= 0)
+ {
+ packet << uint32(0);
+ packet << uint32(0);
+ continue;
+ }
- if (sEntry->GetCategory()) // may be wrong, but anyway better than nothing...
+ std::chrono::milliseconds categoryDuration = std::chrono::duration_cast<std::chrono::milliseconds>(spellCooldown.second.CategoryEnd - now);
+ if (categoryDuration.count() >= 0)
{
packet << uint32(0); // cooldown
- packet << uint32(cooldownDuration); // category cooldown
+ packet << uint32(categoryDuration.count()); // category cooldown
}
else
{
- packet << uint32(cooldownDuration); // cooldown
+ packet << uint32(cooldownDuration.count()); // cooldown
packet << uint32(0); // category cooldown
}
}
-
- packet.put<uint16>(dataPos, cooldownsCount);
}
void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spell* spell /*= nullptr*/, bool onHold /*= false*/)
@@ -351,7 +365,7 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel
// self spell cooldown
if (recTime != curTime)
{
- AddCooldown(spellInfo->Id, itemId, recTime, onHold);
+ AddCooldown(spellInfo->Id, itemId, recTime, categoryId, catrecTime, onHold);
if (needsCooldownPacket)
{
@@ -363,22 +377,6 @@ void SpellHistory::StartCooldown(SpellInfo const* spellInfo, uint32 itemId, Spel
}
}
}
-
- // category spells
- if (categoryId && catrecTime != curTime)
- {
- SpellCategoryStore::const_iterator i_scstore = sSpellsByCategoryStore.find(categoryId);
- 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;
-
- AddCooldown(*i_scset, itemId, catrecTime, onHold);
- }
- }
- }
}
void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /*= 0*/, Spell* spell /*= nullptr*/, bool startCooldown /*= true*/)
@@ -387,49 +385,27 @@ void SpellHistory::SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId /
if (startCooldown)
StartCooldown(spellInfo, itemId, spell);
+ // Send activate cooldown timer (possible 0) at client side
if (Player* player = GetPlayerOwner())
{
- // Send activate cooldown timer (possible 0) at client side
WorldPacket data(SMSG_COOLDOWN_EVENT, 4 + 8);
data << uint32(spellInfo->Id);
data << uint64(_owner->GetGUID());
player->SendDirectMessage(&data);
-
- uint32 category = spellInfo->GetCategory();
- if (category && spellInfo->CategoryRecoveryTime)
- {
- SpellCategoryStore::const_iterator ct = sSpellsByCategoryStore.find(category);
- if (ct != sSpellsByCategoryStore.end())
- {
- for (auto const& cooldownPair : _spellCooldowns)
- {
- uint32 categorySpell = cooldownPair.first;
- if (!ct->second.count(categorySpell))
- continue;
-
- if (categorySpell == spellInfo->Id) // skip main spell, already handled above
- continue;
-
- SpellInfo const* spellInfo2 = sSpellMgr->EnsureSpellInfo(categorySpell);
- if (!spellInfo2->IsCooldownStartedOnEvent())
- continue;
-
- data.Initialize(SMSG_COOLDOWN_EVENT, 4 + 8);
- data << uint32(categorySpell);
- data << uint64(_owner->GetGUID());
- player->SendDirectMessage(&data);
- }
- }
- }
}
}
-void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold /*= false*/)
+void SpellHistory::AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, uint32 categoryId, Clock::time_point categoryEnd, bool onHold /*= false*/)
{
CooldownEntry& cooldownEntry = _spellCooldowns[spellId];
cooldownEntry.CooldownEnd = cooldownEnd;
cooldownEntry.ItemId = itemId;
+ cooldownEntry.CategoryId = categoryId;
+ cooldownEntry.CategoryEnd = categoryEnd;
cooldownEntry.OnHold = onHold;
+
+ if (categoryId)
+ _categoryCooldowns[categoryId] = &cooldownEntry;
}
void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs)
@@ -443,7 +419,7 @@ void SpellHistory::ModifyCooldown(uint32 spellId, int32 cooldownModMs)
if (itr->second.CooldownEnd + offset > now)
itr->second.CooldownEnd += offset;
else
- _spellCooldowns.erase(itr);
+ EraseCooldown(itr);
if (Player* playerOwner = GetPlayerOwner())
{
@@ -477,7 +453,7 @@ void SpellHistory::ResetCooldown(CooldownStorageType::iterator& itr, bool update
}
}
- itr = _spellCooldowns.erase(itr);
+ itr = EraseCooldown(itr);
}
void SpellHistory::ResetAllCooldowns()
@@ -492,31 +468,69 @@ void SpellHistory::ResetAllCooldowns()
SendClearCooldowns(cooldowns);
}
+ _categoryCooldowns.clear();
_spellCooldowns.clear();
}
-bool SpellHistory::HasCooldown(uint32 spellId) const
+bool SpellHistory::HasCooldown(SpellInfo const* spellInfo, uint32 itemId /*= 0*/) const
{
- return _spellCooldowns.count(spellId) != 0;
+ if (_spellCooldowns.count(spellInfo->Id) != 0)
+ return true;
+
+ uint32 category = 0;
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId))
+ {
+ for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
+ {
+ if (itemTemplate->Spells[i].SpellId == spellInfo->Id)
+ {
+ category = itemTemplate->Spells[i].SpellCategory;
+ break;
+ }
+ }
+ }
+
+ if (!category)
+ category = spellInfo->GetCategory();
+
+ if (!category)
+ return false;
+
+ return _categoryCooldowns.count(category) != 0;
}
-uint32 SpellHistory::GetRemainingCooldown(uint32 spellId) const
+bool SpellHistory::HasCooldown(uint32 spellId, uint32 itemId /*= 0*/) const
{
- auto itr = _spellCooldowns.find(spellId);
- if (itr == _spellCooldowns.end())
- return 0;
+ return HasCooldown(sSpellMgr->EnsureSpellInfo(spellId), itemId);
+}
+
+uint32 SpellHistory::GetRemainingCooldown(SpellInfo const* spellInfo) const
+{
+ Clock::time_point end;
+ auto itr = _spellCooldowns.find(spellInfo->Id);
+ if (itr != _spellCooldowns.end())
+ end = itr->second.CooldownEnd;
+ else
+ {
+ auto catItr = _categoryCooldowns.find(spellInfo->GetCategory());
+ if (catItr == _categoryCooldowns.end())
+ return 0;
+
+ end = catItr->second->CategoryEnd;
+ }
Clock::time_point now = Clock::now();
- if (itr->second.CooldownEnd < now)
+ if (end < now)
return 0;
- Clock::duration remaining = itr->second.CooldownEnd - now;
+ Clock::duration remaining = end - now;
return uint32(std::chrono::duration_cast<std::chrono::milliseconds>(remaining).count());
}
void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime)
{
- Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime));
+ Clock::time_point now = Clock::now();
+ Clock::time_point lockoutEnd = now + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime));
for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
if (SpellSchoolMask(1 << i) & schoolMask)
_schoolLockouts[i] = lockoutEnd;
@@ -553,10 +567,10 @@ void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTim
if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE)
continue;
- if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime)
+ if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellInfo) < lockoutTime)
{
cooldowns[spellId] = lockoutTime;
- AddCooldown(spellId, 0, lockoutEnd);
+ AddCooldown(spellId, 0, lockoutEnd, 0, now);
}
}
@@ -644,6 +658,7 @@ void SpellHistory::SaveCooldownStateBeforeDuel()
void SpellHistory::RestoreCooldownStateAfterDuel()
{
+ // category cooldows are not preserved.
if (Player* player = _owner->ToPlayer())
{
// add all profession CDs created while in duel (if any)
diff --git a/src/server/game/Spells/SpellHistory.h b/src/server/game/Spells/SpellHistory.h
index 86737ec7da9..572f407da96 100644
--- a/src/server/game/Spells/SpellHistory.h
+++ b/src/server/game/Spells/SpellHistory.h
@@ -38,15 +38,15 @@ public:
struct CooldownEntry
{
- CooldownEntry() : ItemId(0), OnHold(false) { }
- CooldownEntry(Clock::time_point endTime, uint32 itemId) : CooldownEnd(endTime), ItemId(itemId), OnHold(false) { }
-
Clock::time_point CooldownEnd;
- uint32 ItemId;
- bool OnHold;
+ uint32 ItemId = 0;
+ uint32 CategoryId = 0;
+ Clock::time_point CategoryEnd;
+ bool OnHold = false;
};
typedef std::unordered_map<uint32 /*spellId*/, CooldownEntry> CooldownStorageType;
+ typedef std::unordered_map<uint32 /*categoryId*/, CooldownEntry*> CategoryCooldownStorageType;
typedef std::unordered_map<uint32 /*categoryId*/, Clock::time_point> GlobalCooldownStorageType;
explicit SpellHistory(Unit* owner) : _owner(owner), _schoolLockouts() { }
@@ -60,7 +60,8 @@ public:
void Update();
void HandleCooldowns(SpellInfo const* spellInfo, Item const* item, Spell* spell = nullptr);
- bool IsReady(SpellInfo const* spellInfo) const;
+ void HandleCooldowns(SpellInfo const* spellInfo, uint32 itemID, Spell* spell = nullptr);
+ bool IsReady(SpellInfo const* spellInfo, uint32 itemId = 0) const;
template<class OwnerType>
void WritePacket(WorldPacket& packet) const;
@@ -74,10 +75,11 @@ public:
template<class Type, class Period>
void AddCooldown(uint32 spellId, uint32 itemId, std::chrono::duration<Type, Period> cooldownDuration)
{
- AddCooldown(spellId, itemId, Clock::now() + std::chrono::duration_cast<Clock::duration>(cooldownDuration));
+ Clock::time_point now = Clock::now();
+ AddCooldown(spellId, itemId, now + std::chrono::duration_cast<Clock::duration>(cooldownDuration), 0, now);
}
- void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, bool onHold = false);
+ void AddCooldown(uint32 spellId, uint32 itemId, Clock::time_point cooldownEnd, uint32 categoryId, Clock::time_point categoryEnd, bool onHold = false);
void ModifyCooldown(uint32 spellId, int32 cooldownModMs);
void ResetCooldown(uint32 spellId, bool update = false);
void ResetCooldown(CooldownStorageType::iterator& itr, bool update = false);
@@ -102,8 +104,9 @@ public:
}
void ResetAllCooldowns();
- bool HasCooldown(uint32 spellId) const;
- uint32 GetRemainingCooldown(uint32 spellId) const;
+ bool HasCooldown(SpellInfo const* spellInfo, uint32 itemId = 0) const;
+ bool HasCooldown(uint32 spellId, uint32 itemId = 0) const;
+ uint32 GetRemainingCooldown(SpellInfo const* spellInfo) const;
// School lockouts
void LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime);
@@ -123,6 +126,11 @@ public:
private:
Player* GetPlayerOwner() const;
void SendClearCooldowns(std::vector<int32> const& cooldowns) const;
+ CooldownStorageType::iterator EraseCooldown(CooldownStorageType::iterator itr)
+ {
+ _categoryCooldowns.erase(itr->second.CategoryId);
+ return _spellCooldowns.erase(itr);
+ }
typedef std::unordered_map<uint32, uint32> PacketCooldowns;
void BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns const& cooldowns) const;
@@ -130,6 +138,7 @@ private:
Unit* _owner;
CooldownStorageType _spellCooldowns;
CooldownStorageType _spellCooldownsBeforeDuel;
+ CategoryCooldownStorageType _categoryCooldowns;
Clock::time_point _schoolLockouts[MAX_SPELL_SCHOOL];
GlobalCooldownStorageType _globalCooldowns;