53 cooldownEntry->
SpellId = *spellId;
54 cooldownEntry->
CooldownEnd = time_point_cast<Duration>(Clock::from_time_t(fields[2].GetInt64()));
57 cooldownEntry->
CategoryEnd = time_point_cast<Duration>(Clock::from_time_t(fields[4].GetInt64()));
67 chargeEntry->
RechargeStart = time_point_cast<Duration>(Clock::from_time_t(fields[1].GetInt64()));
68 chargeEntry->
RechargeEnd = time_point_cast<Duration>(Clock::from_time_t(fields[2].GetInt64()));
75 stmt->
setUInt32(index++, cooldown.second.ItemId);
76 stmt->
setInt64(index++, Clock::to_time_t(cooldown.second.CooldownEnd));
77 stmt->
setUInt32(index++, cooldown.second.CategoryId);
78 stmt->
setInt64(index++, Clock::to_time_t(cooldown.second.CategoryEnd));
105 cooldownEntry->
SpellId = *spellId;
106 cooldownEntry->
CooldownEnd = time_point_cast<Duration>(Clock::from_time_t(fields[1].GetInt64()));
107 cooldownEntry->
ItemId = 0;
109 cooldownEntry->
CategoryEnd = time_point_cast<Duration>(Clock::from_time_t(fields[3].GetInt64()));
119 chargeEntry->
RechargeStart = time_point_cast<Duration>(Clock::from_time_t(fields[1].GetInt64()));
120 chargeEntry->
RechargeEnd = time_point_cast<Duration>(Clock::from_time_t(fields[2].GetInt64()));
126 stmt->
setUInt32(index++, cooldown.first);
127 stmt->
setInt64(index++, Clock::to_time_t(cooldown.second.CooldownEnd));
128 stmt->
setUInt32(index++, cooldown.second.CategoryId);
129 stmt->
setInt64(index++, Clock::to_time_t(cooldown.second.CategoryEnd));
134 stmt->
setUInt32(index++, chargeCategory);
146template<
class OwnerType>
157 if (StatementInfo::ReadCooldown(cooldownsResult->Fetch(), &spellId, &cooldown))
164 }
while (cooldownsResult->NextRow());
171 Field* fields = chargesResult->Fetch();
174 if (StatementInfo::ReadCharge(fields, &categoryId, &charges))
177 }
while (chargesResult->NextRow());
181template<
class OwnerType>
188 StatementInfo::SetIdentifier(stmt, index++,
_owner);
193 if (!p.second.OnHold)
196 stmt =
CharacterDatabase.GetPreparedStatement(StatementInfo::CooldownsInsertStatement);
197 StatementInfo::SetIdentifier(stmt, index++,
_owner);
198 StatementInfo::WriteCooldown(stmt, index, p);
203 stmt =
CharacterDatabase.GetPreparedStatement(StatementInfo::ChargesDeleteStatement);
204 StatementInfo::SetIdentifier(stmt, 0,
_owner);
212 stmt =
CharacterDatabase.GetPreparedStatement(StatementInfo::ChargesInsertStatement);
213 StatementInfo::SetIdentifier(stmt, index++,
_owner);
214 StatementInfo::WriteCharge(stmt, index, p.first, charge);
222 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
225 if (itr->second->CategoryEnd < now)
233 if (itr->second.CooldownEnd < now)
240 while (!chargeRefreshTimes.empty() && chargeRefreshTimes.front().RechargeEnd <= now)
241 chargeRefreshTimes.pop_front();
264 player->SetLastPotionId(itemId);
291template<
class PacketType>
294 static_assert(!std::is_same<PacketType, PacketType>::value ,
"This packet is not supported.");
302 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
306 historyEntry.
SpellID = p.first;
307 historyEntry.
ItemID = p.second.ItemId;
310 historyEntry.
OnHold =
true;
313 Milliseconds cooldownDuration = duration_cast<Milliseconds>(p.second.CooldownEnd - now);
314 if (cooldownDuration.count() <= 0)
317 Milliseconds categoryDuration = duration_cast<Milliseconds>(p.second.CategoryEnd - now);
318 if (categoryDuration.count() > 0)
320 historyEntry.
Category = p.second.CategoryId;
324 if (cooldownDuration.count() > categoryDuration.count())
328 sendSpellHistory->
Entries.push_back(historyEntry);
337 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
340 if (!p.second.empty())
342 Milliseconds cooldownDuration = duration_cast<Milliseconds>(p.second.front().RechargeEnd - now);
343 if (cooldownDuration.count() <= 0)
350 sendSpellCharges->
Entries.push_back(chargeEntry);
358 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
364 petSpellCooldown.
SpellID = p.first;
365 petSpellCooldown.
Category = p.second.CategoryId;
367 if (!p.second.OnHold)
369 Milliseconds cooldownDuration = duration_cast<Milliseconds>(p.second.CooldownEnd - now);
370 if (cooldownDuration.count() <= 0)
374 Milliseconds categoryDuration = duration_cast<Milliseconds>(p.second.CategoryEnd - now);
375 if (categoryDuration.count() > 0)
381 petSpells->
Cooldowns.push_back(petSpellCooldown);
387 if (!p.second.empty())
389 Milliseconds cooldownDuration = duration_cast<Milliseconds>(p.second.front().RechargeEnd - now);
390 if (cooldownDuration.count() <= 0)
407 Duration cooldown = Duration::zero();
408 Duration categoryCooldown = Duration::zero();
410 TimePoint curTime = time_point_cast<Duration>(GameTime::GetTime<Clock>());
413 bool needsCooldownPacket =
false;
418 cooldown = *forcedCooldown;
436 int32 intValue = value.count();
441 if (cooldown >= Duration::zero())
442 applySpellMod(cooldown);
445 applySpellMod(categoryCooldown);
464 if (!playerOwner || playerOwner->
HasSpell(spellInfo->
Id))
466 needsCooldownPacket =
true;
477 if (cooldown > Duration::zero())
480 if (categoryCooldown > Duration::zero())
486 categoryCooldown = duration_cast<Milliseconds>(Clock::from_time_t(
sWorld->GetNextDailyQuestsResetTime()) - GameTime::GetTime<Clock>());
490 needsCooldownPacket =
true;
493 if (cooldown < Duration::zero())
494 cooldown = Duration::zero();
496 if (categoryCooldown < Duration::zero())
497 categoryCooldown = Duration::zero();
500 if (cooldown == Duration::zero() && categoryCooldown == Duration::zero())
503 catrecTime = categoryCooldown != Duration::zero() ? curTime + categoryCooldown : curTime;
504 recTime = cooldown != Duration::zero() ? curTime + cooldown : catrecTime;
508 if (recTime != curTime)
510 AddCooldown(spellInfo->
Id, itemId, recTime, categoryId, catrecTime, onHold);
512 if (needsCooldownPacket)
520 playerOwner->SendDirectMessage(spellCooldown.
Write());
557 cooldownEntry.
SpellId = spellId;
559 cooldownEntry.
ItemId = itemId;
562 cooldownEntry.
OnHold = onHold;
580 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
582 itr->second.CooldownEnd += cooldownMod;
584 if (itr->second.CategoryId)
586 if (!withoutCategoryCooldown)
587 itr->second.CategoryEnd += cooldownMod;
590 if (itr->second.CooldownEnd < itr->second.CategoryEnd)
591 itr->second.CooldownEnd = itr->second.CategoryEnd;
598 modifyCooldown.
SpellID = itr->second.SpellId;
599 modifyCooldown.
DeltaTime = duration_cast<Milliseconds>(cooldownMod).count();
601 playerOwner->SendDirectMessage(modifyCooldown.
Write());
604 if (itr->second.CooldownEnd <= now)
616 if (!cooldownMod.count())
642 clearCooldown.
SpellID = itr->first;
644 playerOwner->SendDirectMessage(clearCooldown.
Write());
655 std::vector<int32> cooldowns;
658 cooldowns.push_back(p.first);
696 end = itr->second.CooldownEnd;
701 return Duration::zero();
703 end = catItr->second->CategoryEnd;
706 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
708 return Duration::zero();
710 Clock::duration remaining = end - now;
711 return duration_cast<Milliseconds>(remaining);
719 return Duration::zero();
721 end = catItr->second->CategoryEnd;
723 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
725 return Duration::zero();
727 Clock::duration remaining = end - now;
728 return duration_cast<Milliseconds>(remaining);
738 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
739 TimePoint lockoutEnd = now + lockoutTime;
744 std::set<uint32> knownSpells;
747 for (
auto const& p : plrOwner->GetSpellMap())
749 knownSpells.insert(p.first);
753 for (
auto const& p : petOwner->m_spells)
755 knownSpells.insert(p.first);
762 knownSpells.insert(spell);
768 for (
uint32 spellId : knownSpells)
784 spellCooldown.
SpellCooldowns.emplace_back(spellId, lockoutTime.count());
789 player->SendDirectMessage(spellCooldown.
Write());
794 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
809 if (chargeRecovery > 0 &&
GetMaxCharges(chargeCategoryId) > 0)
814 recoveryStart = time_point_cast<Duration>(GameTime::GetTime<Clock>());
816 recoveryStart = charges.back().RechargeEnd;
818 charges.emplace_back(recoveryStart,
Milliseconds(chargeRecovery));
828 if (!chargeCategoryEntry)
835 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
843 while (!itr->second.empty() && itr->second.front().RechargeEnd < now)
844 itr->second.pop_front();
854 itr->second.pop_back();
871 clearSpellCharges.
Category = chargeCategoryId;
872 player->SendDirectMessage(clearSpellCharges.
Write());
885 player->SendDirectMessage(clearAllSpellCharges.
Write());
906 if (!chargeCategoryEntry)
917 if (!chargeCategoryEntry)
923 float recoveryTimeF = float(recoveryTime);
932 return int32(std::floor(recoveryTimeF));
956 return Duration::zero();
959 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
961 return Duration::zero();
963 Clock::duration remaining = end - now;
964 return duration_cast<Milliseconds>(remaining);
969 _pauseTime = time_point_cast<Duration>(GameTime::GetTime<Clock>());
977 Duration pausedDuration = time_point_cast<Duration>(GameTime::GetTime<Clock>()) - *
_pauseTime;
980 itr->second.CooldownEnd += pausedDuration;
983 for (
ChargeEntry& chargeEntry : chargeRefreshTimes)
984 chargeEntry.RechargeEnd += pausedDuration;
1002 clearCooldowns.
SpellID = cooldowns;
1003 playerOwner->SendDirectMessage(clearCooldowns.
Write());
1012 setSpellCharges.
Category = chargeCategoryId;
1013 if (!chargeCollection.empty())
1014 setSpellCharges.
NextRecoveryTime =
uint32(duration_cast<Milliseconds>(chargeCollection.front().RechargeEnd - GameTime::GetTime<Clock>()).count());
1017 player->SendDirectMessage(setSpellCharges.
Write());
1023 ASSERT(cooldown || categoryId || categoryCooldown);
1024 Duration tmpCooldown = Duration::min();
1025 uint32 tmpCategoryId = 0;
1026 Duration tmpCategoryCooldown = Duration::min();
1047 if (tmpCooldown < Duration::zero() && tmpCategoryCooldown < Duration::zero())
1055 *cooldown = tmpCooldown;
1057 *categoryId = tmpCategoryId;
1058 if (categoryCooldown)
1059 *categoryCooldown = tmpCategoryCooldown;
1084 if (!pair.second.OnHold &&
1097 TimePoint now = time_point_cast<Duration>(GameTime::GetTime<Clock>());
1098 uint32 cooldownDuration =
uint32(c.second.CooldownEnd > now ? duration_cast<Milliseconds>(c.second.CooldownEnd - now).count() : 0);
1104 spellCooldown.
SpellCooldowns.emplace_back(c.first, cooldownDuration);
1107 player->SendDirectMessage(spellCooldown.
Write());
CharacterDatabaseStatements
@ CHAR_DEL_PET_SPELL_CHARGES
@ CHAR_INS_PET_SPELL_CHARGES
@ CHAR_INS_PET_SPELL_COOLDOWN
@ CHAR_DEL_CHAR_SPELL_COOLDOWNS
@ CHAR_INS_CHAR_SPELL_COOLDOWN
@ CHAR_INS_CHAR_SPELL_CHARGES
@ CHAR_DEL_PET_SPELL_COOLDOWNS
@ CHAR_DEL_CHAR_SPELL_CHARGES
DB2Storage< SpellCategoryEntry > sSpellCategoryStore("SpellCategory.db2", &SpellCategoryLoadInfo::Instance)
@ SPELL_CATEGORY_FLAG_COOLDOWN_EXPIRES_AT_DAILY_RESET
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
std::chrono::seconds Seconds
Seconds shorthand typedef.
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
std::optional< T > Optional
Optional helper class to wrap optional values within.
@ SPELL_PREVENTION_TYPE_SILENCE
@ SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS
@ SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN
@ SPELL_AURA_CHARGE_RECOVERY_MOD
@ SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE
@ SPELL_AURA_IGNORE_SPELL_COOLDOWN
@ SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN
@ SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER
@ SPELL_AURA_MOD_COOLDOWN
@ SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE_REGEN
@ SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE
@ SPELL_AURA_MOD_MAX_CHARGES
@ SPELL_COOLDOWN_FLAG_INCLUDE_EVENT_COOLDOWNS
Starts GCD for spells that should start their cooldown on events, requires SPELL_COOLDOWN_FLAG_INCLUD...
@ SPELL_COOLDOWN_FLAG_LOSS_OF_CONTROL_UI
Shows interrupt cooldown in loss of control ui.
@ SPELL_COOLDOWN_FLAG_NONE
uint32 m_spells[MAX_CREATURE_SPELLS]
Class used to access individual fields of database query result.
Difficulty GetDifficultyID() const
LowType GetCounter() const
static Creature * ToCreature(Object *o)
static ObjectGuid GetGUID(Object const *o)
static Player * ToPlayer(Object *o)
bool HasSpell(uint32 spell) const override
void setInt64(const uint8 index, const int64 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt64(const uint8 index, const uint64 value)
void AddCooldown(uint32 spellId, uint32 itemId, Duration cooldownDuration)
Duration GetRemainingGlobalCooldown(SpellInfo const *spellInfo) const
GlobalCooldownStorageType _globalCooldowns
void SendSetSpellCharges(uint32 chargeCategoryId, ChargeEntryCollection const &chargeCollection)
void LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQueryResult chargesResult)
TimePoint _schoolLockouts[MAX_SPELL_SCHOOL]
bool HasGlobalCooldown(SpellInfo const *spellInfo) const
Duration GetRemainingCategoryCooldown(uint32 categoryId) const
int32 GetMaxCharges(uint32 chargeCategoryId) const
void ModifyChargeRecoveryTime(uint32 chargeCategoryId, Duration cooldownMod)
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void ResetCooldown(uint32 spellId, bool update=false)
bool IsReady(SpellInfo const *spellInfo, uint32 itemId=0) const
void AddGlobalCooldown(SpellInfo const *spellInfo, Duration duration)
bool ConsumeCharge(uint32 chargeCategoryId)
void SaveToDB(CharacterDatabaseTransaction trans)
void SendClearCooldowns(std::vector< int32 > const &cooldowns) const
void RestoreCharge(uint32 chargeCategoryId)
static Duration const InfinityCooldownDelay
Optional< TimePoint > _pauseTime
void LockSpellSchool(SpellSchoolMask schoolMask, Duration lockoutTime)
void WritePacket(PacketType *packet) const
std::deque< ChargeEntry > ChargeEntryCollection
Duration GetRemainingCooldown(SpellInfo const *spellInfo) const
SpellHistory(Unit *owner)
CooldownStorageType _spellCooldowns
void ResetCharges(uint32 chargeCategoryId)
static void GetCooldownDurations(SpellInfo const *spellInfo, uint32 itemId, Duration *cooldown, uint32 *categoryId, Duration *categoryCooldown)
void CancelGlobalCooldown(SpellInfo const *spellInfo)
void RestoreCooldownStateAfterDuel()
void ModifyCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown=false)
CooldownStorageType _spellCooldownsBeforeDuel
bool HasCharge(uint32 chargeCategoryId) const
void SaveCooldownStateBeforeDuel()
std::chrono::time_point< Clock, Duration > TimePoint
CooldownStorageType::iterator EraseCooldown(CooldownStorageType::iterator itr)
void HandleCooldowns(SpellInfo const *spellInfo, Item const *item, Spell *spell=nullptr)
void ModifySpellCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown)
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false, Optional< Duration > forcedCooldown={})
Player * GetPlayerOwner() const
int32 GetChargeRecoveryTime(uint32 chargeCategoryId) const
ChargeStorageType _categoryCharges
bool IsSchoolLocked(SpellSchoolMask schoolMask) const
CategoryCooldownStorageType _categoryCooldowns
bool HasCooldown(SpellInfo const *spellInfo, uint32 itemId=0) const
uint32 GetCategory() const
bool IsCooldownStartedOnEvent() const
uint32 CooldownAuraSpellId
uint32 CategoryRecoveryTime
SpellSchoolMask GetSchoolMask() const
bool HasAttribute(SpellAttr0 attribute) const
uint32 StartRecoveryCategory
bool IsIgnoringCooldowns() const
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
UF::UpdateField< UF::UnitData, 0, TYPEID_UNIT > m_unitData
CharmInfo * GetCharmInfo()
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
bool HasAuraType(AuraType auraType) const
int32 GetTotalAuraModifier(AuraType auraType) const
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Player * GetSpellModOwner() const
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
std::vector< PetSpellCooldown > Cooldowns
std::vector< PetSpellHistory > SpellHistory
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< int32 > SpellID
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
bool WithoutCategoryCooldown
WorldPacket const * Write() override
std::vector< SpellChargeEntry > Entries
std::vector< SpellHistoryEntry > Entries
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< SpellCooldownStruct > SpellCooldowns
uint32 GetPetNumber() const
int32 CategoryCoolDownMSec
static void WriteCooldown(PreparedStatementBase *stmt, uint8 &index, CooldownStorageType::value_type const &cooldown)
static void SetIdentifier(PreparedStatementBase *stmt, uint8 index, Unit *owner)
static void WriteCharge(PreparedStatementBase *stmt, uint8 &index, uint32 chargeCategory, ChargeEntry const &charge)
static bool ReadCooldown(Field *fields, uint32 *spellId, CooldownEntry *cooldownEntry)
static bool ReadCharge(Field *fields, uint32 *categoryId, ChargeEntry *chargeEntry)
static bool ReadCooldown(Field *fields, uint32 *spellId, CooldownEntry *cooldownEntry)
static void WriteCharge(PreparedStatementBase *stmt, uint8 &index, uint32 chargeCategory, ChargeEntry const &charge)
static bool ReadCharge(Field *fields, uint32 *categoryId, ChargeEntry *chargeEntry)
static void WriteCooldown(PreparedStatementBase *stmt, uint8 &index, CooldownStorageType::value_type const &cooldown)
static void SetIdentifier(PreparedStatementBase *stmt, uint8 index, Unit *owner)
int32 CategoryRecoveryTime