Skip to content

Commit

Permalink
some improvements to creature cooldown handling
Browse files Browse the repository at this point in the history
 * unified player and creature cooldown handling
 * apply spellmodifier to creature cooldowns
 * improved global coooldown handling and connected petai
 * support cooldown-on-aura-cancel for pets/charmed units
  • Loading branch information
pasdVn committed Mar 12, 2010
1 parent 78f200a commit b9e2f87
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 45 deletions.
26 changes: 13 additions & 13 deletions src/game/Creature.cpp
Expand Up @@ -1809,25 +1809,25 @@ void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time)
m_CreatureSpellCooldowns[spell_id] = end_time;
}

void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t apply_time)
void Creature::_AddCreatureCategoryCooldown(uint32 category, time_t end_time)
{
m_CreatureCategoryCooldowns[category] = apply_time;
m_CreatureCategoryCooldowns[category] = end_time;
}

void Creature::AddCreatureSpellCooldown(uint32 spellid)
void Creature::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if(!spellInfo)
return;

uint32 cooldown = GetSpellRecoveryTime(spellInfo);
if(cooldown)
_AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILISECONDS);

if(spellInfo->Category)
_AddCreatureCategoryCooldown(spellInfo->Category, time(NULL));
// apply spellmod (in case creature is pet)
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown);

if (!cooldown)
return;

m_GlobalCooldown = spellInfo->StartRecoveryTime;
_AddCreatureSpellCooldown(spellInfo->Id, time(NULL) + cooldown/IN_MILISECONDS);
if (spellInfo->Category)
_AddCreatureCategoryCooldown(spellInfo->Category, time(NULL) + cooldown/IN_MILISECONDS);
}

bool Creature::HasCategoryCooldown(uint32 spell_id) const
Expand All @@ -1841,7 +1841,7 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const
return true;

CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category);
return (itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILISECONDS)) > time(NULL));
return (itr != m_CreatureCategoryCooldowns.end() && itr->second > time(NULL));
}

bool Creature::HasSpellCooldown(uint32 spell_id) const
Expand Down
3 changes: 2 additions & 1 deletion src/game/Creature.h
Expand Up @@ -478,7 +478,7 @@ class MANGOS_DLL_SPEC Creature : public Unit

void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time);
void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
void AddCreatureSpellCooldown(uint32 spellid);
void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false);
bool HasSpellCooldown(uint32 spell_id) const;
bool HasCategoryCooldown(uint32 spell_id) const;

Expand Down Expand Up @@ -610,6 +610,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
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 SetGlobalCooldown(uint32 gcd){ m_GlobalCooldown = gcd; }

void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; }

Expand Down
8 changes: 5 additions & 3 deletions src/game/PetAI.cpp
Expand Up @@ -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<std::pair<Unit*, Spell*> > TargetSpellList;
TargetSpellList targetSpellStore;
Expand All @@ -215,6 +215,10 @@ void PetAI::UpdateAI(const uint32 diff)
if (!spellInfo)
continue;

// do not cast if spell is on global cooldown
if (spellInfo->StartRecoveryTime > 0 && m_creature->GetGlobalCooldown())
continue;

// ignore some combinations of combat state and combat/noncombat spells
if (!inCombat)
{
Expand Down Expand Up @@ -298,8 +302,6 @@ void PetAI::UpdateAI(const uint32 diff)
m_creature->SendCreateUpdateToPlayer( (Player*)owner );
}

m_creature->AddCreatureSpellCooldown(spell->m_spellInfo->Id);

spell->prepare(&targets);
}

Expand Down
14 changes: 6 additions & 8 deletions src/game/PetHandler.cpp
Expand Up @@ -170,8 +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 = ObjectAccessor::GetUnit(*_player,guid2);
Expand All @@ -184,6 +182,9 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
return;
}

if (spellInfo->StartRecoveryTime && ((Creature*)pet)->GetGlobalCooldown() > 0)
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)
Expand Down Expand Up @@ -223,8 +224,6 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )

if(result == SPELL_CAST_OK)
{
((Creature*)pet)->AddCreatureSpellCooldown(spellid);

unit_target = spell->m_targets.getUnitTarget();

//10% chance to play special pet attack talk, else growl
Expand Down Expand Up @@ -615,16 +614,16 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
return;
}

if (pet->GetGlobalCooldown() > 0)
return;

SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
if (!spellInfo)
{
sLog.outError("WORLD: unknown PET spell id %i", spellid);
return;
}

if (spellInfo->StartRecoveryTime && pet->GetGlobalCooldown() > 0)
return;

// do not cast not learned spells
if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
return;
Expand All @@ -642,7 +641,6 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )
SpellCastResult result = spell->CheckPetCast(NULL);
if (result == SPELL_CAST_OK)
{
pet->AddCreatureSpellCooldown(spellid);
if (pet->isPet())
{
//10% chance to play special pet attack talk, else growl
Expand Down
9 changes: 6 additions & 3 deletions src/game/Player.cpp
Expand Up @@ -18446,15 +18446,18 @@ void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
m_spellCooldowns[spellid] = sc;
}

void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell* spell)
void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell* spell, Unit* cooldownTarget)
{
if (!cooldownTarget)
cooldownTarget = this;

// start cooldowns at server side, if any
AddSpellAndCategoryCooldowns(spellInfo, itemId, spell);
cooldownTarget->AddSpellAndCategoryCooldowns(spellInfo,itemId,spell);

// Send activate cooldown timer (possible 0) at client side
WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8));
data << uint32(spellInfo->Id);
data << uint64(GetGUID());
data << uint64(cooldownTarget->GetGUID());
SendDirectMessage(&data);
}

Expand Down
4 changes: 2 additions & 2 deletions src/game/Player.h
Expand Up @@ -1617,9 +1617,9 @@ class MANGOS_DLL_SPEC Player : public Unit
time_t t = time(NULL);
return itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0;
}
void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false );
void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false);
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL, Unit* cooldownTarget = NULL);
void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id, bool update = false);
void RemoveSpellCategoryCooldown(uint32 cat, bool update = false);
Expand Down
69 changes: 58 additions & 11 deletions src/game/Spell.cpp
Expand Up @@ -2440,6 +2440,9 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
// set timer base at cast time
ReSetTimer();

// send global cooldown
SendGlobalCooldown();

// stealth must be removed at cast starting (at show channel bar)
// skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
if ( !m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) )
Expand Down Expand Up @@ -2474,6 +2477,7 @@ void Spell::cancel()
switch (m_spellState)
{
case SPELL_STATE_PREPARING:
ResetGlobalCooldown();
case SPELL_STATE_DELAYED:
{
SendInterrupted(0);
Expand Down Expand Up @@ -2858,24 +2862,67 @@ void Spell::_handle_finish_phase()

void Spell::SendSpellCooldown()
{
if(m_caster->GetTypeId() != TYPEID_PLAYER)
return;

Player* _player = (Player*)m_caster;

// mana/health/etc potions, disabled by client (until combat out as declarate)
if (m_CastItem && m_CastItem->IsPotion())
switch (m_caster->GetTypeId())
{
// need in some way provided data for Spell::finish SendCooldownEvent
_player->SetLastPotionId(m_CastItem->GetEntry());
return;
case TYPEID_UNIT:
{
// store cooldown only for controlled creatures
if (!m_caster->isControlledByPlayer())
return;
}break;
case TYPEID_PLAYER:
{
Player* _player = (Player*)m_caster;

// mana/health/etc potions, disabled by client (until combat out as declarate)
if (m_CastItem && m_CastItem->IsPotion())
{
// need in some way provided data for Spell::finish SendCooldownEvent
_player->SetLastPotionId(m_CastItem->GetEntry());
return;
}
}break;
default:
return;;
}

// (1) have infinity cooldown but set at aura apply, (2) passive cooldown at triggering
if(m_spellInfo->Attributes & (SPELL_ATTR_DISABLED_WHILE_ACTIVE | SPELL_ATTR_PASSIVE))
return;
m_caster->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this);
}

void Spell::SendGlobalCooldown()
{
if (!m_spellInfo->StartRecoveryTime)
return;

// server side handling only for charmed creatures and pets
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;

if (!m_caster->isControlledByPlayer())
return;

((Creature*)m_caster)->SetGlobalCooldown(m_spellInfo->StartRecoveryTime);
}

void Spell::ResetGlobalCooldown()
{
// spells without gcd can't reset it
if (!m_spellInfo->StartRecoveryTime)
return;

// server side handling only for charmed creatures and pets
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;

if (!m_caster->isControlledByPlayer())
return;

_player->AddSpellAndCategoryCooldowns(m_spellInfo, m_CastItem ? m_CastItem->GetEntry() : 0, this);
((Creature*)m_caster)->SetGlobalCooldown(0);
// need to send packet for controlled creatures (to the controller), this will clear gcd
((Player*)m_caster->GetCharmerOrOwner())->SendClearCooldown(m_spellInfo->Id, m_caster);
}

void Spell::update(uint32 difftime)
Expand Down
2 changes: 2 additions & 0 deletions src/game/Spell.h
Expand Up @@ -423,6 +423,8 @@ class Spell
void SendSpellStart();
void SendSpellGo();
void SendSpellCooldown();
void SendGlobalCooldown();
void ResetGlobalCooldown();
void SendLogExecute();
void SendInterrupted(uint8 result);
void SendChannelUpdate(uint32 time);
Expand Down
13 changes: 11 additions & 2 deletions src/game/SpellAuras.cpp
Expand Up @@ -1218,11 +1218,20 @@ bool Aura::_RemoveAura()
}

// reset cooldown state for spells
if(caster && caster->GetTypeId() == TYPEID_PLAYER)
if (GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE && caster)
{
if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
// always send for players
if (caster->GetTypeId() == TYPEID_PLAYER)
{
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
((Player*)caster)->SendCooldownEvent(GetSpellProto());
}
// send to controller, if unit is player-controlled
if (caster->isControlledByPlayer())
{
Player* controller = (Player*)(caster->GetCharmerOrOwner());
controller->SendCooldownEvent(GetSpellProto(), 0, NULL, caster);
}
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/game/SpellHandler.cpp
Expand Up @@ -481,8 +481,7 @@ void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
}

pet->RemoveAurasDueToSpell(spellId);

pet->AddCreatureSpellCooldown(spellId);
pet->AddSpellAndCategoryCooldowns(spellInfo, 0);
}

void WorldSession::HandleCancelGrowthAuraOpcode( WorldPacket& /*recvPacket*/)
Expand Down
20 changes: 20 additions & 0 deletions src/game/Unit.cpp
Expand Up @@ -8332,6 +8332,26 @@ bool Unit::IsNeutralToAll() const
return my_faction->IsNeutralToAll();
}

bool Unit::isControlledByPlayer() const
{
// this method will return true, if this unit is directly controlled by a player,
// that means player has a pet cast bar
Unit* owner = GetCharmerOrOwner();

if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
return false;

// player-charmed units always have pet action bar (hope this is correct)
if (isCharmed())
return true;

if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet() &&
((Pet*)this)->isControlled())
return true;

return false;
}

bool Unit::Attack(Unit *victim, bool meleeAttack)
{
if(!victim || victim == this)
Expand Down
2 changes: 2 additions & 0 deletions src/game/Unit.h
Expand Up @@ -1356,6 +1356,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void CastCustomSpell(Unit* Victim,SpellEntry const *spellInfo, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
void CastSpell(float x, float y, float z, SpellEntry const *spellInfo, bool triggered, Item *castItem = NULL, Aura* triggeredByAura = NULL, uint64 originalCaster = 0);
virtual void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false) = 0;

bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const;

Expand Down Expand Up @@ -1415,6 +1416,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
return GetGUID();
}
bool isCharmedOwnedByPlayerOrPlayer() const { return IS_PLAYER_GUID(GetCharmerOrOwnerOrOwnGUID()); }
bool isControlledByPlayer() const;

Player* GetSpellModOwner();

Expand Down

0 comments on commit b9e2f87

Please sign in to comment.