diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index ed0f7cb3..ff5adc36 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -796,7 +796,7 @@ public: // 400ms spell-queue window: next spell to cast when current finishes uint32_t getQueuedSpellId() const; - void cancelQueuedSpell() { queuedSpellId_ = 0; queuedSpellTarget_ = 0; } + void cancelQueuedSpell() { if (spellHandler_) spellHandler_->cancelQueuedSpell(); } // Unit cast state (aliased from handler_types.hpp) using UnitCastState = game::UnitCastState; @@ -2543,24 +2543,9 @@ private: uint64_t playerTransportStickyGuid_ = 0; // Last transport player was on (temporary retention) float playerTransportStickyTimer_ = 0.0f; // Seconds to keep sticky transport alive after transient clears std::unique_ptr transportManager_; // Transport movement manager - std::unordered_set knownSpells; - std::unordered_map spellCooldowns; // spellId -> remaining seconds uint32_t weaponProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=2 uint32_t armorProficiency_ = 0; // bitmask from SMSG_SET_PROFICIENCY itemClass=4 std::vector minimapPings_; - uint8_t castCount = 0; - bool casting = false; - bool castIsChannel = false; - uint32_t currentCastSpellId = 0; - float castTimeRemaining = 0.0f; - // Repeat-craft queue: re-cast the same profession spell N more times after current cast finishes - uint32_t craftQueueSpellId_ = 0; - int craftQueueRemaining_ = 0; - // Spell queue: next spell to cast within the 400ms window before current cast ends - uint32_t queuedSpellId_ = 0; - uint64_t queuedSpellTarget_ = 0; - // Per-unit cast state (keyed by GUID, populated from SMSG_SPELL_START) - std::unordered_map unitCastStates_; uint64_t pendingGameObjectInteractGuid_ = 0; // Talents (dual-spec support) @@ -2588,7 +2573,6 @@ private: float areaTriggerCheckTimer_ = 0.0f; bool areaTriggerSuppressFirst_ = false; // suppress first check after map transfer - float castTimeTotal = 0.0f; std::array actionBar{}; std::unordered_map macros_; // client-side macro text (persisted in char config) std::vector playerAuras; diff --git a/include/game/spell_handler.hpp b/include/game/spell_handler.hpp index 9314f76e..6b30a319 100644 --- a/include/game/spell_handler.hpp +++ b/include/game/spell_handler.hpp @@ -79,6 +79,7 @@ public: auto it = unitCastStates_.find(guid); return (it != unitCastStates_.end() && it->second.casting) ? &it->second : nullptr; } + void clearUnitCastStates() { unitCastStates_.clear(); } // Target cast helpers bool isTargetCasting() const; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 981be6f8..766dec0a 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -688,10 +688,6 @@ GameHandler::GameHandler() { wardenHandler_ = std::make_unique(*this); wardenHandler_->initModuleManager(); - // Default spells always available - knownSpells.insert(6603); // Attack - knownSpells.insert(8690); // Hearthstone - // Default action bar layout actionBar[0].type = ActionBarSlot::SPELL; actionBar[0].id = 6603; // Attack in slot 1 @@ -1118,6 +1114,8 @@ for (auto& [guid, entity] : entityController_->getEntityManager().getEntities()) } void GameHandler::updateTimers(float deltaTime) { + if (spellHandler_) spellHandler_->updateTimers(deltaTime); + if (auctionSearchDelayTimer_ > 0.0f) { auctionSearchDelayTimer_ -= deltaTime; if (auctionSearchDelayTimer_ < 0.0f) auctionSearchDelayTimer_ = 0.0f; @@ -4637,14 +4635,9 @@ void GameHandler::selectCharacter(uint64_t characterGuid) { pendingQuestAcceptNpcGuids_.clear(); npcQuestStatus_.clear(); if (combatHandler_) combatHandler_->resetAllCombatState(); - if (spellHandler_) { spellHandler_->casting_ = false; spellHandler_->castIsChannel_ = false; spellHandler_->currentCastSpellId_ = 0; } + if (spellHandler_) spellHandler_->resetCastState(); pendingGameObjectInteractGuid_ = 0; lastInteractedGoGuid_ = 0; - if (spellHandler_) { spellHandler_->castTimeRemaining_ = 0.0f; spellHandler_->castTimeTotal_ = 0.0f; } - craftQueueSpellId_ = 0; - craftQueueRemaining_ = 0; - queuedSpellId_ = 0; - queuedSpellTarget_ = 0; playerDead_ = false; releasedSpirit_ = false; corpseGuid_ = 0; diff --git a/src/game/movement_handler.cpp b/src/game/movement_handler.cpp index d53fda76..f5417b11 100644 --- a/src/game/movement_handler.cpp +++ b/src/game/movement_handler.cpp @@ -1880,10 +1880,6 @@ void MovementHandler::handleNewWorld(network::Packet& packet) { owner_.stopAutoAttack(); owner_.tabCycleStale = true; owner_.resetCastState(); - owner_.craftQueueSpellId_ = 0; - owner_.craftQueueRemaining_ = 0; - owner_.queuedSpellId_ = 0; - owner_.queuedSpellTarget_ = 0; if (owner_.socket) { network::Packet ack(wireOpcode(Opcode::MSG_MOVE_WORLDPORT_ACK)); @@ -1935,7 +1931,7 @@ void MovementHandler::handleNewWorld(network::Packet& packet) { owner_.otherPlayerVisibleItemEntries_.clear(); owner_.otherPlayerVisibleDirty_.clear(); otherPlayerMoveTimeMs_.clear(); - owner_.unitCastStates_.clear(); + if (owner_.spellHandler_) owner_.spellHandler_->clearUnitCastStates(); owner_.unitAurasCache_.clear(); owner_.clearCombatText(); owner_.getEntityManager().clear(); @@ -1949,10 +1945,6 @@ void MovementHandler::handleNewWorld(network::Packet& packet) { owner_.areaTriggerSuppressFirst_ = true; owner_.stopAutoAttack(); owner_.resetCastState(); - owner_.craftQueueSpellId_ = 0; - owner_.craftQueueRemaining_ = 0; - owner_.queuedSpellId_ = 0; - owner_.queuedSpellTarget_ = 0; if (owner_.socket) { network::Packet ack(wireOpcode(Opcode::MSG_MOVE_WORLDPORT_ACK)); diff --git a/src/game/spell_handler.cpp b/src/game/spell_handler.cpp index d64cfc4f..092bb6ef 100644 --- a/src/game/spell_handler.cpp +++ b/src/game/spell_handler.cpp @@ -204,7 +204,7 @@ bool SpellHandler::isTargetCastInterruptible() const { } void SpellHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { - LOG_WARNING("castSpell: spellId=", spellId, " target=0x", std::hex, targetGuid, std::dec); + LOG_DEBUG("castSpell: spellId=", spellId, " target=0x", std::hex, targetGuid, std::dec); // Attack (6603) routes to auto-attack instead of cast if (spellId == 6603) { uint64_t target = targetGuid != 0 ? targetGuid : owner_.targetGuid; @@ -323,8 +323,8 @@ void SpellHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { auto packet = owner_.packetParsers_ ? owner_.packetParsers_->buildCastSpell(spellId, target, ++castCount_) : CastSpellPacket::build(spellId, target, ++castCount_); - LOG_WARNING("CMSG_CAST_SPELL: spellId=", spellId, " target=0x", std::hex, target, std::dec, - " castCount=", static_cast(castCount_), " packetSize=", packet.getSize()); + LOG_DEBUG("CMSG_CAST_SPELL: spellId=", spellId, " target=0x", std::hex, target, std::dec, + " castCount=", static_cast(castCount_), " packetSize=", packet.getSize()); owner_.socket->send(packet); LOG_INFO("Casting spell: ", spellId, " on 0x", std::hex, target, std::dec); @@ -851,9 +851,9 @@ void SpellHandler::handleSpellStart(network::Packet& packet) { LOG_WARNING("Failed to parse SMSG_SPELL_START, size=", packet.getSize()); return; } - LOG_WARNING("SMSG_SPELL_START: caster=0x", std::hex, data.casterUnit, std::dec, - " spell=", data.spellId, " castTime=", data.castTime, - " isPlayer=", (data.casterUnit == owner_.playerGuid)); + LOG_DEBUG("SMSG_SPELL_START: caster=0x", std::hex, data.casterUnit, std::dec, + " spell=", data.spellId, " castTime=", data.castTime, + " isPlayer=", (data.casterUnit == owner_.playerGuid)); // Track cast bar for any non-player caster if (data.casterUnit != owner_.playerGuid && data.castTime > 0) { @@ -2066,12 +2066,12 @@ void SpellHandler::handleCastResult(network::Packet& packet) { uint32_t castResultSpellId = 0; uint8_t castResult = 0; if (owner_.packetParsers_->parseCastResult(packet, castResultSpellId, castResult)) { - LOG_WARNING("SMSG_CAST_RESULT: spellId=", castResultSpellId, " result=", static_cast(castResult)); + LOG_DEBUG("SMSG_CAST_RESULT: spellId=", castResultSpellId, " result=", static_cast(castResult)); if (castResult != 0) { casting_ = false; castIsChannel_ = false; currentCastSpellId_ = 0; castTimeRemaining_ = 0.0f; owner_.lastInteractedGoGuid_ = 0; - owner_.craftQueueSpellId_ = 0; owner_.craftQueueRemaining_ = 0; - owner_.queuedSpellId_ = 0; owner_.queuedSpellTarget_ = 0; + craftQueueSpellId_ = 0; craftQueueRemaining_ = 0; + queuedSpellId_ = 0; queuedSpellTarget_ = 0; int playerPowerType = -1; if (auto pe = owner_.getEntityManager().getEntity(owner_.playerGuid)) { if (auto pu = std::dynamic_pointer_cast(pe))