aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordarkstalker <darkstalker@getmangos.com>2011-02-22 17:02:47 +0600
committerAzazel <azazel.kon@gmail.com>2011-02-22 17:02:47 +0600
commit1646f9d91c70263c9af3a154b59d3e43c9d3a5a8 (patch)
treec41632f6733fa584b95e624cb257691fa24ee6b4
parent401ec2180f06e3b7ad33345f256e19b80d1f5571 (diff)
Core/Spell Mechanics: introduce global cooldown manager for server-side checks for GCD (ported from mangos)
-rwxr-xr-xsrc/server/game/AI/CoreAI/PetAI.cpp5
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.cpp12
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.h3
-rwxr-xr-xsrc/server/game/Entities/Player/Player.h4
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp20
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h28
-rwxr-xr-xsrc/server/game/Server/Protocol/Handlers/PetHandler.cpp4
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp69
-rwxr-xr-xsrc/server/game/Spells/Spell.h3
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);