From 81b1f87313514785cc83eb150c609d9bf9d11f64 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 6 Feb 2026 03:39:36 -0800 Subject: [PATCH] Fix lantern glow rendering and add NPC combat animations Disable depth testing for additive/mod blend mode batches so glow quads render as proper light halos instead of visible transparent discs. Add NPC swing callback to play attack animation (anim 16) when NPCs melee in single-player combat. --- include/game/game_handler.hpp | 5 +++++ src/core/application.cpp | 6 ++++++ src/game/game_handler.cpp | 4 ++++ src/rendering/m2_renderer.cpp | 11 ++++++++++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 618786df..931adb8e 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -256,6 +256,10 @@ public: using MeleeSwingCallback = std::function; void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); } + // NPC swing callback (single-player combat: plays attack animation on NPC) + using NpcSwingCallback = std::function; + void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); } + // Local player stats (single-player) uint32_t getLocalPlayerHealth() const { return localPlayerHealth_; } uint32_t getLocalPlayerMaxHealth() const { return localPlayerMaxHealth_; } @@ -625,6 +629,7 @@ private: static constexpr float SWING_SPEED = 2.0f; NpcDeathCallback npcDeathCallback_; MeleeSwingCallback meleeSwingCallback_; + NpcSwingCallback npcSwingCallback_; uint32_t localPlayerHealth_ = 0; uint32_t localPlayerMaxHealth_ = 0; uint32_t localPlayerLevel_ = 1; diff --git a/src/core/application.cpp b/src/core/application.cpp index cd0bdad5..75383494 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -1135,6 +1135,12 @@ void Application::spawnNpcs() { cr->playAnimation(instanceId, 1, false); // animation ID 1 = Death } }); + gameHandler->setNpcSwingCallback([npcMgr, cr](uint64_t guid) { + uint32_t instanceId = npcMgr->findRenderInstanceId(guid); + if (instanceId != 0 && cr) { + cr->playAnimation(instanceId, 16, false); // animation ID 16 = Attack1 + } + }); } npcsSpawned = true; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index b9fda259..f5eaf1b9 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -3747,6 +3747,10 @@ void GameHandler::performNpcSwing(uint64_t guid) { if (!entity || entity->getType() != ObjectType::UNIT) return; auto unit = std::static_pointer_cast(entity); + if (npcSwingCallback_) { + npcSwingCallback_(guid); + } + static std::mt19937 rng(std::random_device{}()); std::uniform_real_distribution roll(0.0f, 1.0f); diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 241d14eb..eef91596 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -1306,6 +1306,12 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm:: glDepthMask(GL_FALSE); } + // Disable depth testing entirely for additive/mod blends (glow, light halos) + bool disableDepth = (batch.blendMode >= 3); + if (disableDepth) { + glDisable(GL_DEPTH_TEST); + } + // Unlit: material flag 0x01 or additive/mod blend modes bool unlit = (batch.materialFlags & 0x01) != 0 || batch.blendMode >= 3; shader->setUniform("uUnlit", unlit); @@ -1323,7 +1329,10 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm:: glDrawElements(GL_TRIANGLES, batch.indexCount, GL_UNSIGNED_SHORT, (void*)(batch.indexStart * sizeof(uint16_t))); - // Restore depth writes and blend func after transparent batch + // Restore depth test, depth writes, and blend func after transparent batch + if (disableDepth) { + glEnable(GL_DEPTH_TEST); + } if (batchTransparent && fadeAlpha >= 1.0f) { glDepthMask(GL_TRUE); }