mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
game/rendering: play SpellCast animation during SMSG_SPELL_START
Add SpellCastAnimCallback to GameHandler, triggered on SMSG_SPELL_START (start=true) and cleared on SMSG_SPELL_GO / SMSG_SPELL_FAILURE (start=false) for both the player and other units. Connect the callback in Application to play animation 3 (SpellCast) on the player character, NPCs, and other players when they begin a cast. The cast animation is one-shot (loop=false) so it auto-returns to Stand when complete via the existing return-to-idle logic. Also fire stop-cast on spell failure to cancel any stuck cast pose.
This commit is contained in:
parent
c20d7c2638
commit
59c50e3beb
3 changed files with 61 additions and 0 deletions
|
|
@ -623,6 +623,11 @@ public:
|
||||||
using MeleeSwingCallback = std::function<void()>;
|
using MeleeSwingCallback = std::function<void()>;
|
||||||
void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); }
|
void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); }
|
||||||
|
|
||||||
|
// Spell cast animation callbacks — true=start cast/channel, false=finish/cancel
|
||||||
|
// guid: caster (may be player or another unit), isChannel: channel vs regular cast
|
||||||
|
using SpellCastAnimCallback = std::function<void(uint64_t guid, bool start, bool isChannel)>;
|
||||||
|
void setSpellCastAnimCallback(SpellCastAnimCallback cb) { spellCastAnimCallback_ = std::move(cb); }
|
||||||
|
|
||||||
// NPC swing callback (plays attack animation on NPC)
|
// NPC swing callback (plays attack animation on NPC)
|
||||||
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
||||||
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
||||||
|
|
@ -2246,6 +2251,7 @@ private:
|
||||||
NpcAggroCallback npcAggroCallback_;
|
NpcAggroCallback npcAggroCallback_;
|
||||||
NpcRespawnCallback npcRespawnCallback_;
|
NpcRespawnCallback npcRespawnCallback_;
|
||||||
MeleeSwingCallback meleeSwingCallback_;
|
MeleeSwingCallback meleeSwingCallback_;
|
||||||
|
SpellCastAnimCallback spellCastAnimCallback_;
|
||||||
NpcSwingCallback npcSwingCallback_;
|
NpcSwingCallback npcSwingCallback_;
|
||||||
NpcGreetingCallback npcGreetingCallback_;
|
NpcGreetingCallback npcGreetingCallback_;
|
||||||
NpcFarewellCallback npcFarewellCallback_;
|
NpcFarewellCallback npcFarewellCallback_;
|
||||||
|
|
|
||||||
|
|
@ -2762,6 +2762,38 @@ void Application::setupUICallbacks() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Spell cast animation callback — play cast animation on caster (player or NPC/other player)
|
||||||
|
gameHandler->setSpellCastAnimCallback([this](uint64_t guid, bool start, bool /*isChannel*/) {
|
||||||
|
if (!renderer) return;
|
||||||
|
auto* cr = renderer->getCharacterRenderer();
|
||||||
|
if (!cr) return;
|
||||||
|
// Animation 3 = SpellCast (one-shot; return-to-idle handled by character_renderer)
|
||||||
|
const uint32_t castAnim = 3;
|
||||||
|
// Check player character
|
||||||
|
{
|
||||||
|
uint32_t charInstId = renderer->getCharacterInstanceId();
|
||||||
|
if (charInstId != 0 && guid == gameHandler->getPlayerGuid()) {
|
||||||
|
if (start) cr->playAnimation(charInstId, castAnim, false);
|
||||||
|
// On finish: playAnimation(castAnim, loop=false) will auto-return to Stand
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check creatures and other online players
|
||||||
|
{
|
||||||
|
auto it = creatureInstances_.find(guid);
|
||||||
|
if (it != creatureInstances_.end()) {
|
||||||
|
if (start) cr->playAnimation(it->second, castAnim, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto it = playerInstances_.find(guid);
|
||||||
|
if (it != playerInstances_.end()) {
|
||||||
|
if (start) cr->playAnimation(it->second, castAnim, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// NPC greeting callback - play voice line
|
// NPC greeting callback - play voice line
|
||||||
gameHandler->setNpcGreetingCallback([this](uint64_t guid, const glm::vec3& position) {
|
gameHandler->setNpcGreetingCallback([this](uint64_t guid, const glm::vec3& position) {
|
||||||
if (renderer && renderer->getNpcVoiceManager()) {
|
if (renderer && renderer->getNpcVoiceManager()) {
|
||||||
|
|
|
||||||
|
|
@ -2605,9 +2605,15 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
ssm->stopPrecast();
|
ssm->stopPrecast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (spellCastAnimCallback_) {
|
||||||
|
spellCastAnimCallback_(playerGuid, false, false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Another unit's cast failed — clear their tracked cast bar
|
// Another unit's cast failed — clear their tracked cast bar
|
||||||
unitCastStates_.erase(failGuid);
|
unitCastStates_.erase(failGuid);
|
||||||
|
if (spellCastAnimCallback_) {
|
||||||
|
spellCastAnimCallback_(failGuid, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -12949,6 +12955,10 @@ void GameHandler::handleSpellStart(network::Packet& packet) {
|
||||||
s.spellId = data.spellId;
|
s.spellId = data.spellId;
|
||||||
s.timeTotal = data.castTime / 1000.0f;
|
s.timeTotal = data.castTime / 1000.0f;
|
||||||
s.timeRemaining = s.timeTotal;
|
s.timeRemaining = s.timeTotal;
|
||||||
|
// Trigger cast animation on the casting unit
|
||||||
|
if (spellCastAnimCallback_) {
|
||||||
|
spellCastAnimCallback_(data.casterUnit, true, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the player's own cast, start cast bar
|
// If this is the player's own cast, start cast bar
|
||||||
|
|
@ -12970,6 +12980,11 @@ void GameHandler::handleSpellStart(network::Packet& packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger cast animation on player character
|
||||||
|
if (spellCastAnimCallback_) {
|
||||||
|
spellCastAnimCallback_(playerGuid, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Hearthstone cast: begin pre-loading terrain at bind point during cast time
|
// Hearthstone cast: begin pre-loading terrain at bind point during cast time
|
||||||
// so tiles are ready when the teleport fires (avoids falling through un-loaded terrain).
|
// so tiles are ready when the teleport fires (avoids falling through un-loaded terrain).
|
||||||
// Spell IDs: 6948 = Vanilla Hearthstone (rank 1), 8690 = TBC/WotLK Hearthstone
|
// Spell IDs: 6948 = Vanilla Hearthstone (rank 1), 8690 = TBC/WotLK Hearthstone
|
||||||
|
|
@ -13021,6 +13036,14 @@ void GameHandler::handleSpellGo(network::Packet& packet) {
|
||||||
casting = false;
|
casting = false;
|
||||||
currentCastSpellId = 0;
|
currentCastSpellId = 0;
|
||||||
castTimeRemaining = 0.0f;
|
castTimeRemaining = 0.0f;
|
||||||
|
|
||||||
|
// End cast animation on player character
|
||||||
|
if (spellCastAnimCallback_) {
|
||||||
|
spellCastAnimCallback_(playerGuid, false, false);
|
||||||
|
}
|
||||||
|
} else if (spellCastAnimCallback_) {
|
||||||
|
// End cast animation on other unit
|
||||||
|
spellCastAnimCallback_(data.casterUnit, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear unit cast bar when the spell lands (for any tracked unit)
|
// Clear unit cast bar when the spell lands (for any tracked unit)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue