From 6ba4e2521461530b78d3831b6ce2d467cfd45d2a Mon Sep 17 00:00:00 2001 From: darkstalker Date: Sat, 25 Sep 2010 15:51:13 +0400 Subject: [PATCH] [s0237] Implement server side global cooldown check. Signed-off-by: VladimirMangos Also pet/controlled unit global cooldown code replaced by new placed in charmInfo structure. Thanks to nos4r2zod for testing and gcd range check implement. (based on commit defa062) --- src/game/Creature.cpp | 12 -------- src/game/Creature.h | 3 -- src/game/PetAI.cpp | 5 +++- src/game/PetHandler.cpp | 13 +++++---- src/game/Player.cpp | 2 +- src/game/Player.h | 4 +++ src/game/Spell.cpp | 62 ++++++++++++++++++++++++++++++++++++++++ src/game/Spell.h | 5 ++++ src/game/Unit.cpp | 25 ++++++++++++++++ src/game/Unit.h | 26 +++++++++++++++++ src/shared/revision_nr.h | 2 +- 11 files changed, 135 insertions(+), 24 deletions(-) diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 2a6b63757c9..6ca820c8ab4 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -137,7 +137,6 @@ m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE) m_CreatureSpellCooldowns.clear(); m_CreatureCategoryCooldowns.clear(); - m_GlobalCooldown = 0; m_splineFlags = SPLINEFLAG_WALKMODE; } @@ -394,11 +393,6 @@ uint32 Creature::ChooseDisplayId(const CreatureInfo *cinfo, const CreatureData * void Creature::Update(uint32 diff) { - if(m_GlobalCooldown <= diff) - m_GlobalCooldown = 0; - else - m_GlobalCooldown -= diff; - if (m_needNotify) { m_needNotify = false; @@ -1999,8 +1993,6 @@ void Creature::AddCreatureSpellCooldown(uint32 spellid) if(spellInfo->Category) _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL)); - - m_GlobalCooldown = spellInfo->StartRecoveryTime; } bool Creature::HasCategoryCooldown(uint32 spell_id) const @@ -2009,10 +2001,6 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const if(!spellInfo) return false; - // check global cooldown if spell affected by it - if (spellInfo->StartRecoveryCategory > 0 && m_GlobalCooldown > 0) - return true; - CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category); return (itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL)); } diff --git a/src/game/Creature.h b/src/game/Creature.h index ea43b26de3b..fe45ee87519 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -543,7 +543,6 @@ class MANGOS_DLL_SPEC Creature : public Unit uint32 m_spells[CREATURE_MAX_SPELLS]; CreatureSpellCooldowns m_CreatureSpellCooldowns; CreatureSpellCooldowns m_CreatureCategoryCooldowns; - uint32 m_GlobalCooldown; float GetAttackDistance(Unit const* pl) const; @@ -612,8 +611,6 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetSummonPoint(float fX, float fY, float fZ, float fOrient) { m_summonXpoint = fX; m_summonYpoint = fY; m_summonZpoint = fZ; m_summonOrientation = fOrient; } void GetSummonPoint(float &fX, float &fY, float &fZ, float &fOrient) const { fX = m_summonXpoint; fY = m_summonYpoint; fZ = m_summonZpoint; fOrient = m_summonOrientation; } - uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } void SetActiveObjectState(bool on); diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp index b9a6fe941e0..11e90280b9d 100644 --- a/src/game/PetAI.cpp +++ b/src/game/PetAI.cpp @@ -200,7 +200,7 @@ void PetAI::UpdateAI(const uint32 diff) } // Autocast (casted only in combat or persistent spells in any state) - if (m_creature->GetGlobalCooldown() == 0 && !m_creature->IsNonMeleeSpellCasted(false)) + if (!m_creature->IsNonMeleeSpellCasted(false)) { typedef std::vector > TargetSpellList; TargetSpellList targetSpellStore; @@ -215,6 +215,9 @@ void PetAI::UpdateAI(const uint32 diff) if (!spellInfo) continue; + if (m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + continue; + // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index e0f8d0a9d5a..5c383a31b1a 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -170,9 +170,6 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) case ACT_ENABLED: // 0xC1 spell { Unit* unit_target = NULL; - if (((Creature*)pet)->GetGlobalCooldown() > 0) - return; - if(guid2) unit_target = _player->GetMap()->GetUnit(guid2); @@ -184,6 +181,9 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) return; } + if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + return; + for(int i = 0; i < MAX_EFFECT_INDEX;++i) { if(spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) @@ -642,9 +642,6 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) return; } - if (pet->GetGlobalCooldown() > 0) - return; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); if (!spellInfo) { @@ -652,6 +649,10 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) return; } + if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + return; + + // do not cast not learned spells if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index b28c128dba8..bedd2e5185c 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -17797,7 +17797,7 @@ void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell data << GetObjectGuid(); SendDirectMessage(&data); } - //slot to be excluded while counting + bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) { if(!enchantmentcondition) diff --git a/src/game/Player.h b/src/game/Player.h index 78f49eebeaa..c986fbe579e 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1487,6 +1487,8 @@ class MANGOS_DLL_SPEC Player : public Unit void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); void SendClearCooldown( uint32 spell_id, Unit* target ); + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } + void RemoveArenaSpellCooldowns(); void RemoveAllSpellCooldown(); void _LoadSpellCooldowns(QueryResult *result); @@ -2246,6 +2248,8 @@ class MANGOS_DLL_SPEC Player : public Unit PlayerSpellMap m_spells; SpellCooldowns m_spellCooldowns; + GlobalCooldownMgr m_GlobalCooldownMgr; + ActionButtonList m_actionButtons; float m_auraBaseMod[BASEMOD_END][MOD_END]; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index f200eeb6155..f1c84ad025c 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -2306,6 +2306,8 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura) // will show cast bar SendSpellStart(); + + TriggerGlobalCooldown(); } // execute triggered without cast time explicitly in call point else if(m_timer == 0) @@ -2327,6 +2329,9 @@ void Spell::cancel() switch (m_spellState) { case SPELL_STATE_PREPARING: + CancelGlobalCooldown(); + + //(no break) case SPELL_STATE_DELAYED: { SendInterrupted(0); @@ -3545,6 +3550,10 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_NOT_READY; } + // check global cooldown + if (strict && !m_IsTriggeredSpell && HasGlobalCooldown()) + return SPELL_FAILED_NOT_READY; + // only allow triggered spells if at an ended battleground if (!m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER) if(BattleGround * bg = ((Player*)m_caster)->GetBattleGround()) @@ -5784,3 +5793,56 @@ WorldObject* Spell::GetCastingObject() const return m_caster; } +bool Spell::HasGlobalCooldown() +{ + // global cooldown have only player or controlled units + if (m_caster->GetCharmInfo()) + return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + return ((Player*)m_caster)->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); + else + return false; +} + +void Spell::TriggerGlobalCooldown() +{ + int32 gcd = m_spellInfo->StartRecoveryTime; + if (!gcd) + return; + + // global cooldown can't leave range 1..1.5 secs (if it it) + // exist some spells (mostly not player directly casted) that have < 1 sec and > 1.5 sec global cooldowns + // but its as test show not affected any spell mods. + if (m_spellInfo->StartRecoveryTime >= 1000 && m_spellInfo->StartRecoveryTime <= 1500) + { + // apply haste rating + gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + + if (gcd < 1000) + gcd = 1000; + else if (gcd > 1500) + gcd = 1500; + } + + // global cooldown have only player or controlled units + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); +} + +void Spell::CancelGlobalCooldown() +{ + if (!m_spellInfo->StartRecoveryTime) + return; + + // cancel global cooldown when interrupting current cast + if (m_caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) != this) + return; + + // global cooldown have only player or controlled units + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + ((Player*)m_caster)->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); +} diff --git a/src/game/Spell.h b/src/game/Spell.h index bdb12fdc4fa..50bbe842ab3 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -315,7 +315,9 @@ class Spell ~Spell(); void prepare(SpellCastTargets const* targets, Aura* triggeredByAura = NULL); + void cancel(); + void update(uint32 difftime); void cast(bool skipCheck = false); void finish(bool ok = true); @@ -446,6 +448,9 @@ class Spell void CleanupTargetList(); protected: + bool HasGlobalCooldown(); + void TriggerGlobalCooldown(); + void CancelGlobalCooldown(); void SendLoot(uint64 guid, LootType loottype); bool IgnoreItemRequirements() const; // some item use spells have unexpected reagent data diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 63168cd3658..b5abcb9ea9c 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -74,6 +74,9 @@ static bool isNonTriggerAura[TOTAL_AURAS]; // Prepare lists static bool procPrepared = InitTriggerAuraData(); +//////////////////////////////////////////////////////////// +// Methods of class MovementInfo + void MovementInfo::Read(ByteBuffer &data) { data >> moveFlags; @@ -154,6 +157,28 @@ void MovementInfo::Write(ByteBuffer &data) const } } +//////////////////////////////////////////////////////////// +// Methods of class GlobalCooldownMgr + +bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const +{ + GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory); + return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration; +} + +void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd) +{ + m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime()); +} + +void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo) +{ + m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0; +} + +//////////////////////////////////////////////////////////// +// Methods of class Unit + Unit::Unit() : WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostileRefManager(this) { diff --git a/src/game/Unit.h b/src/game/Unit.h index d1d0b6f01f3..44d238182a9 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -837,6 +837,29 @@ enum CurrentSpellTypes #define CURRENT_FIRST_NON_MELEE_SPELL 1 #define CURRENT_MAX_SPELL 4 +struct GlobalCooldown +{ + explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) {} + + uint32 duration; + uint32 cast_time; +}; + +typedef UNORDERED_MAP GlobalCooldownList; + +class GlobalCooldownMgr // Shared by Player and CharmInfo +{ + public: + GlobalCooldownMgr() {} + + public: + bool HasGlobalCooldown(SpellEntry const* spellInfo) const; + void AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd); + void CancelGlobalCooldown(SpellEntry const* spellInfo); + + private: + GlobalCooldownList m_GlobalCooldowns; +}; enum ActiveStates { @@ -969,6 +992,8 @@ struct CharmInfo void ToggleCreatureAutocast(uint32 spellid, bool apply); CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } + + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } private: Unit* m_unit; @@ -977,6 +1002,7 @@ struct CharmInfo CommandStates m_CommandState; ReactStates m_reactState; uint32 m_petnumber; + GlobalCooldownMgr m_GlobalCooldownMgr; }; // for clearing special attacks diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 1b55568f89b..0e3e227c393 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "0236" + #define REVISION_NR "0237" #endif // __REVISION_NR_H__