feat(Core/Player): implement Spell Queue (#20797)

This commit is contained in:
Jelle Meeus
2024-12-12 11:59:52 +01:00
committed by GitHub
parent f31bf723a0
commit 993bdcb84e
10 changed files with 227 additions and 1 deletions

View File

@@ -79,6 +79,7 @@ void Player::Update(uint32 p_time)
// used to implement delayed far teleports
SetMustDelayTeleport(true);
ProcessSpellQueue();
Unit::Update(p_time);
SetMustDelayTeleport(false);
@@ -2255,3 +2256,89 @@ void Player::ProcessTerrainStatusUpdate()
else
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWATER_INDARKWATER);
}
uint32 Player::GetSpellQueueWindow() const
{
return sWorld->getIntConfig(CONFIG_SPELL_QUEUE_WINDOW);
}
bool Player::CanExecutePendingSpellCastRequest(SpellInfo const* spellInfo)
{
if (GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
return false;
if (GetSpellCooldownDelay(spellInfo->Id) > GetSpellQueueWindow())
return false;
for (CurrentSpellTypes spellSlot : {CURRENT_MELEE_SPELL, CURRENT_GENERIC_SPELL})
if (Spell* spell = GetCurrentSpell(spellSlot))
{
bool autoshot = spell->m_spellInfo->IsAutoRepeatRangedSpell();
if (IsNonMeleeSpellCast(false, true, true, autoshot))
return false;
}
return true;
}
const PendingSpellCastRequest* Player::GetCastRequest(uint32 category) const
{
for (const PendingSpellCastRequest& request : SpellQueue)
if (request.category == category)
return &request;
return nullptr;
}
bool Player::CanRequestSpellCast(SpellInfo const* spellInfo)
{
if (!sWorld->getBoolConfig(CONFIG_SPELL_QUEUE_ENABLED))
return false;
// Check for existing cast request with the same category
if (GetCastRequest(spellInfo->StartRecoveryCategory))
return false;
if (GetGlobalCooldownMgr().GetGlobalCooldown(spellInfo) > GetSpellQueueWindow())
return false;
if (GetSpellCooldownDelay(spellInfo->Id) > GetSpellQueueWindow())
return false;
// If there is an existing cast that will last longer than the allowable
// spell queue window, then we can't request a new spell cast
for (CurrentSpellTypes spellSlot : { CURRENT_MELEE_SPELL, CURRENT_GENERIC_SPELL })
if (Spell* spell = GetCurrentSpell(spellSlot))
if (spell->GetCastTimeRemaining() > static_cast<int32>(GetSpellQueueWindow()))
return false;
return true;
}
void Player::ExecuteOrCancelSpellCastRequest(PendingSpellCastRequest* request, bool isCancel /* = false*/)
{
if (isCancel)
request->cancelInProgress = true;
if (WorldSession* session = GetSession())
{
if (request->isItem)
session->HandleUseItemOpcode(request->requestPacket);
else
session->HandleCastSpellOpcode(request->requestPacket);
}
}
void Player::ProcessSpellQueue()
{
while (!SpellQueue.empty())
{
PendingSpellCastRequest& request = SpellQueue.front(); // Peek at the first spell
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(request.spellId);
if (CanExecutePendingSpellCastRequest(spellInfo))
{
ExecuteOrCancelSpellCastRequest(&request);
SpellQueue.pop_front(); // Remove from the queue
}
else // If the first spell can't execute, stop processing
break;
}
}