diff options
| author | darkstalker <darkstalker@getmangos.com> | 2011-02-22 17:02:47 +0600 |
|---|---|---|
| committer | Azazel <azazel.kon@gmail.com> | 2011-02-22 17:02:47 +0600 |
| commit | 1646f9d91c70263c9af3a154b59d3e43c9d3a5a8 (patch) | |
| tree | c41632f6733fa584b95e624cb257691fa24ee6b4 | |
| parent | 401ec2180f06e3b7ad33345f256e19b80d1f5571 (diff) | |
Core/Spell Mechanics: introduce global cooldown manager for server-side checks for GCD (ported from mangos)
| -rwxr-xr-x | src/server/game/AI/CoreAI/PetAI.cpp | 5 | ||||
| -rwxr-xr-x | src/server/game/Entities/Creature/Creature.cpp | 12 | ||||
| -rwxr-xr-x | src/server/game/Entities/Creature/Creature.h | 3 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.h | 4 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.cpp | 20 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 28 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Handlers/PetHandler.cpp | 4 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.cpp | 69 | ||||
| -rwxr-xr-x | src/server/game/Spells/Spell.h | 3 |
9 files changed, 130 insertions, 18 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index ac142db923d..115f65311b9 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -122,7 +122,7 @@ void PetAI::UpdateAI(const uint32 diff) return; // Autocast (casted only in combat or persistent spells in any state) - if (me->GetGlobalCooldown() == 0 && !me->HasUnitState(UNIT_STAT_CASTING)) + if (!me->HasUnitState(UNIT_STAT_CASTING)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; @@ -137,6 +137,9 @@ void PetAI::UpdateAI(const uint32 diff) if (!spellInfo) continue; + if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + continue; + // ignore some combinations of combat state and combat/noncombat spells if (!me->getVictim()) { diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0fd48f47ae6..53370170c9e 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -154,7 +154,6 @@ m_formation(NULL) m_CreatureSpellCooldowns.clear(); m_CreatureCategoryCooldowns.clear(); - m_GlobalCooldown = 0; DisableReputationGain = false; //m_unit_movement_flags = MONSTER_MOVE_WALK; @@ -430,11 +429,6 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data) void Creature::Update(uint32 diff) { - if (m_GlobalCooldown <= diff) - m_GlobalCooldown = 0; - else - m_GlobalCooldown -= diff; - if (IsAIEnabled && TriggerJustRespawned) { TriggerJustRespawned = false; @@ -2185,8 +2179,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 @@ -2195,10 +2187,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/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 43ff73df08c..4933428bf4e 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -577,7 +577,6 @@ class Creature : public Unit, public GridObject<Creature> uint32 m_spells[CREATURE_MAX_SPELLS]; CreatureSpellCooldowns m_CreatureSpellCooldowns; CreatureSpellCooldowns m_CreatureCategoryCooldowns; - uint32 m_GlobalCooldown; bool canStartAttack(Unit const* u, bool force) const; float GetAttackDistance(Unit const* pl) const; @@ -646,8 +645,6 @@ class Creature : public Unit, public GridObject<Creature> void GetHomePosition(float &x, float &y, float &z, float &ori) { m_homePosition.GetPosition(x, y, z, ori); } Position GetHomePosition() { return m_homePosition; } - uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - uint32 GetWaypointPath(){return m_path_id;} void LoadPath(uint32 pathid) { m_path_id = pathid; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d14082cc864..8ee626d18bb 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1640,6 +1640,8 @@ class Player : public Unit, public GridObject<Player> void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); void SendClearCooldown(uint32 spell_id, Unit* target); + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } + void RemoveCategoryCooldown(uint32 cat); void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false); void RemoveAllSpellCooldown(); @@ -2545,6 +2547,8 @@ class Player : public Unit, public GridObject<Player> PlayerTalentMap *m_talents[MAX_TALENT_SPECS]; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use + GlobalCooldownMgr m_GlobalCooldownMgr; + uint8 m_activeSpec; uint8 m_specsCount; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6f1be60e84e..81f048771c9 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -192,6 +192,26 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this) m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } +//////////////////////////////////////////////////////////// +// 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() { // set current spells as deletable diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e546af981a3..73d5cae78f0 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -937,6 +937,30 @@ 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<uint32 /*category*/, GlobalCooldown> 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 { ACT_PASSIVE = 0x01, // 0x01 - passive @@ -1057,6 +1081,8 @@ struct CharmInfo CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } + void SetIsCommandAttack(bool val); bool IsCommandAttack(); void SetIsAtStay(bool val); @@ -1088,6 +1114,8 @@ struct CharmInfo float m_stayX; float m_stayY; float m_stayZ; + + GlobalCooldownMgr m_GlobalCooldownMgr; }; // for clearing special attacks diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp index 9dd53dd14dc..e84817edb05 100755 --- a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp @@ -295,7 +295,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid } if (spellInfo->StartRecoveryCategory > 0) - if (pet->ToCreature()->GetGlobalCooldown() > 0) + if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) return; for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -753,7 +753,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) } if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD - if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0) + if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) { caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); return; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 95769040dde..248a1a89554 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3001,6 +3001,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere m_caster->SetCurrentCastedSpell(this); SendSpellStart(); + TriggerGlobalCooldown(); + if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->AddGlobalCooldown(m_spellInfo,this); @@ -3027,6 +3029,7 @@ void Spell::cancel() switch (oldState) { case SPELL_STATE_PREPARING: + CancelGlobalCooldown(); case SPELL_STATE_DELAYED: SendInterrupted(0); SendCastResult(SPELL_FAILED_INTERRUPTED); @@ -4680,6 +4683,10 @@ SpellCastResult Spell::CheckCast(bool strict) } } + // 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 = m_caster->ToPlayer()->GetBattleground()) @@ -7285,3 +7292,65 @@ void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTarget (*scritr)->_FinishScriptCall(); } } + +enum eGCD { + MIN_GCD = 1000, + MAX_GCD = 1500 +}; + +bool Spell::HasGlobalCooldown() +{ + // Only player or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + return m_caster->ToPlayer()->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 + // There are some spells (mostly not casted directly by player) that have < 1 sec and > 1.5 sec global cooldowns + // but as tests show are not affected by any spell mods. + if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD) + { + // gcd modifier auras are applied only to own spells and only players have such mods + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this); + + // Apply haste rating + gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + if (gcd < MIN_GCD) + gcd = MIN_GCD; + else if (gcd > MAX_GCD) + gcd = MAX_GCD; + } + + // Only players or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->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; + + // Only players or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); +} diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 34ddf5c1028..d83107f1db3 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -543,6 +543,9 @@ class Spell void SetSpellValue(SpellValueMod mod, int32 value); protected: + bool HasGlobalCooldown(); + void TriggerGlobalCooldown(); + void CancelGlobalCooldown(); void SendLoot(uint64 guid, LootType loottype); |
