mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-27 05:23:51 +00:00
fix(gameplay): stabilize run animation and clean ghost/death visuals
This commit is contained in:
parent
1a4b21955c
commit
cebca9a882
6 changed files with 51 additions and 27 deletions
|
|
@ -3201,6 +3201,7 @@ private:
|
||||||
bool releasedSpirit_ = false;
|
bool releasedSpirit_ = false;
|
||||||
uint32_t corpseMapId_ = 0;
|
uint32_t corpseMapId_ = 0;
|
||||||
float corpseX_ = 0.0f, corpseY_ = 0.0f, corpseZ_ = 0.0f;
|
float corpseX_ = 0.0f, corpseY_ = 0.0f, corpseZ_ = 0.0f;
|
||||||
|
uint64_t corpseGuid_ = 0;
|
||||||
// Death Knight runes (class 6): slots 0-1=Blood, 2-3=Unholy, 4-5=Frost initially
|
// Death Knight runes (class 6): slots 0-1=Blood, 2-3=Unholy, 4-5=Frost initially
|
||||||
std::array<RuneSlot, 6> playerRunes_ = [] {
|
std::array<RuneSlot, 6> playerRunes_ = [] {
|
||||||
std::array<RuneSlot, 6> r{};
|
std::array<RuneSlot, 6> r{};
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,10 @@ private:
|
||||||
// Character animation state
|
// Character animation state
|
||||||
enum class CharAnimState { IDLE, WALK, RUN, JUMP_START, JUMP_MID, JUMP_END, SIT_DOWN, SITTING, EMOTE, SWIM_IDLE, SWIM, MELEE_SWING, MOUNT, CHARGE, COMBAT_IDLE };
|
enum class CharAnimState { IDLE, WALK, RUN, JUMP_START, JUMP_MID, JUMP_END, SIT_DOWN, SITTING, EMOTE, SWIM_IDLE, SWIM, MELEE_SWING, MOUNT, CHARGE, COMBAT_IDLE };
|
||||||
CharAnimState charAnimState = CharAnimState::IDLE;
|
CharAnimState charAnimState = CharAnimState::IDLE;
|
||||||
|
float locomotionStopGraceTimer_ = 0.0f;
|
||||||
|
bool locomotionWasSprinting_ = false;
|
||||||
|
uint32_t lastPlayerAnimRequest_ = UINT32_MAX;
|
||||||
|
bool lastPlayerAnimLoopRequest_ = true;
|
||||||
void updateCharacterAnimation();
|
void updateCharacterAnimation();
|
||||||
bool isFootstepAnimationState() const;
|
bool isFootstepAnimationState() const;
|
||||||
bool shouldTriggerFootstepEvent(uint32_t animationId, float animationTimeMs, float animationDurationMs);
|
bool shouldTriggerFootstepEvent(uint32_t animationId, float animationTimeMs, float animationDurationMs);
|
||||||
|
|
|
||||||
|
|
@ -3081,9 +3081,11 @@ void Application::setupUICallbacks() {
|
||||||
if (charInstId == 0) return;
|
if (charInstId == 0) return;
|
||||||
// WoW stand state → M2 animation ID mapping
|
// WoW stand state → M2 animation ID mapping
|
||||||
// 0=Stand→0, 1-6=Sit variants→27 (SitGround), 7=Dead→1, 8=Kneel→72
|
// 0=Stand→0, 1-6=Sit variants→27 (SitGround), 7=Dead→1, 8=Kneel→72
|
||||||
|
// Do not force Stand(0) here: locomotion state machine already owns standing/running.
|
||||||
|
// Forcing Stand on packet timing causes visible run-cycle hitching while steering.
|
||||||
uint32_t animId = 0;
|
uint32_t animId = 0;
|
||||||
if (standState == 0) {
|
if (standState == 0) {
|
||||||
animId = 0; // Stand
|
return;
|
||||||
} else if (standState >= 1 && standState <= 6) {
|
} else if (standState >= 1 && standState <= 6) {
|
||||||
animId = 27; // SitGround (covers sit-chair too; correct visual differs by chair height)
|
animId = 27; // SitGround (covers sit-chair too; correct visual differs by chair height)
|
||||||
} else if (standState == 7) {
|
} else if (standState == 7) {
|
||||||
|
|
|
||||||
|
|
@ -8506,6 +8506,7 @@ void GameHandler::selectCharacter(uint64_t characterGuid) {
|
||||||
castTimeTotal = 0.0f;
|
castTimeTotal = 0.0f;
|
||||||
playerDead_ = false;
|
playerDead_ = false;
|
||||||
releasedSpirit_ = false;
|
releasedSpirit_ = false;
|
||||||
|
corpseGuid_ = 0;
|
||||||
targetGuid = 0;
|
targetGuid = 0;
|
||||||
focusGuid = 0;
|
focusGuid = 0;
|
||||||
lastTargetGuid = 0;
|
lastTargetGuid = 0;
|
||||||
|
|
@ -9963,6 +9964,7 @@ void GameHandler::forceClearTaxiAndMovementState() {
|
||||||
resurrectRequestPending_ = false;
|
resurrectRequestPending_ = false;
|
||||||
playerDead_ = false;
|
playerDead_ = false;
|
||||||
releasedSpirit_ = false;
|
releasedSpirit_ = false;
|
||||||
|
corpseGuid_ = 0;
|
||||||
repopPending_ = false;
|
repopPending_ = false;
|
||||||
pendingSpiritHealerGuid_ = 0;
|
pendingSpiritHealerGuid_ = 0;
|
||||||
resurrectCasterGuid_ = 0;
|
resurrectCasterGuid_ = 0;
|
||||||
|
|
@ -10580,11 +10582,13 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
uint64_t ownerGuid = (static_cast<uint64_t>(ownerHigh) << 32) | ownerLow;
|
uint64_t ownerGuid = (static_cast<uint64_t>(ownerHigh) << 32) | ownerLow;
|
||||||
if (ownerGuid == playerGuid || ownerLow == static_cast<uint32_t>(playerGuid)) {
|
if (ownerGuid == playerGuid || ownerLow == static_cast<uint32_t>(playerGuid)) {
|
||||||
// Server coords from movement block
|
// Server coords from movement block
|
||||||
|
corpseGuid_ = block.guid;
|
||||||
corpseX_ = block.x;
|
corpseX_ = block.x;
|
||||||
corpseY_ = block.y;
|
corpseY_ = block.y;
|
||||||
corpseZ_ = block.z;
|
corpseZ_ = block.z;
|
||||||
corpseMapId_ = currentMapId_;
|
corpseMapId_ = currentMapId_;
|
||||||
LOG_INFO("Corpse object detected: server=(", block.x, ", ", block.y, ", ", block.z,
|
LOG_INFO("Corpse object detected: guid=0x", std::hex, corpseGuid_, std::dec,
|
||||||
|
" server=(", block.x, ", ", block.y, ", ", block.z,
|
||||||
") map=", corpseMapId_);
|
") map=", corpseMapId_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11136,6 +11140,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
repopPending_ = false;
|
repopPending_ = false;
|
||||||
resurrectPending_ = false;
|
resurrectPending_ = false;
|
||||||
corpseMapId_ = 0; // corpse reclaimed
|
corpseMapId_ = 0; // corpse reclaimed
|
||||||
|
corpseGuid_ = 0;
|
||||||
LOG_INFO("Player resurrected (PLAYER_FLAGS ghost cleared)");
|
LOG_INFO("Player resurrected (PLAYER_FLAGS ghost cleared)");
|
||||||
if (ghostStateCallback_) ghostStateCallback_(false);
|
if (ghostStateCallback_) ghostStateCallback_(false);
|
||||||
}
|
}
|
||||||
|
|
@ -12908,9 +12913,12 @@ bool GameHandler::canReclaimCorpse() const {
|
||||||
|
|
||||||
void GameHandler::reclaimCorpse() {
|
void GameHandler::reclaimCorpse() {
|
||||||
if (!canReclaimCorpse() || !socket) return;
|
if (!canReclaimCorpse() || !socket) return;
|
||||||
auto packet = ReclaimCorpsePacket::build(playerGuid);
|
// Reclaim expects the corpse object guid when known; fallback to player guid.
|
||||||
|
uint64_t reclaimGuid = (corpseGuid_ != 0) ? corpseGuid_ : playerGuid;
|
||||||
|
auto packet = ReclaimCorpsePacket::build(reclaimGuid);
|
||||||
socket->send(packet);
|
socket->send(packet);
|
||||||
LOG_INFO("Sent CMSG_RECLAIM_CORPSE for guid=0x", std::hex, playerGuid, std::dec);
|
LOG_INFO("Sent CMSG_RECLAIM_CORPSE for guid=0x", std::hex, reclaimGuid, std::dec,
|
||||||
|
(corpseGuid_ == 0 ? " (fallback player guid)" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameHandler::activateSpiritHealer(uint64_t npcGuid) {
|
void GameHandler::activateSpiritHealer(uint64_t npcGuid) {
|
||||||
|
|
@ -20420,6 +20428,7 @@ void GameHandler::handleNewWorld(network::Packet& packet) {
|
||||||
pendingSpiritHealerGuid_ = 0;
|
pendingSpiritHealerGuid_ = 0;
|
||||||
resurrectCasterGuid_ = 0;
|
resurrectCasterGuid_ = 0;
|
||||||
corpseMapId_ = 0;
|
corpseMapId_ = 0;
|
||||||
|
corpseGuid_ = 0;
|
||||||
hostileAttackers_.clear();
|
hostileAttackers_.clear();
|
||||||
stopAutoAttack();
|
stopAutoAttack();
|
||||||
tabCycleStale = true;
|
tabCycleStale = true;
|
||||||
|
|
|
||||||
|
|
@ -1031,9 +1031,8 @@ void Renderer::beginFrame() {
|
||||||
|
|
||||||
// FXAA resource management — FXAA can coexist with FSR1 and FSR3.
|
// FXAA resource management — FXAA can coexist with FSR1 and FSR3.
|
||||||
// When both FXAA and FSR3 are enabled, FXAA runs as a post-FSR3 pass.
|
// When both FXAA and FSR3 are enabled, FXAA runs as a post-FSR3 pass.
|
||||||
// Ghost mode also reuses this post pass for true grayscale when FXAA is
|
// Do not force this pass for ghost mode; keep AA quality strictly user-controlled.
|
||||||
// disabled in settings.
|
const bool useFXAAPostPass = fxaa_.enabled;
|
||||||
const bool useFXAAPostPass = (fxaa_.enabled || ghostMode_);
|
|
||||||
if ((fxaa_.needsRecreate || !useFXAAPostPass) && fxaa_.sceneFramebuffer) {
|
if ((fxaa_.needsRecreate || !useFXAAPostPass) && fxaa_.sceneFramebuffer) {
|
||||||
destroyFXAAResources();
|
destroyFXAAResources();
|
||||||
fxaa_.needsRecreate = false;
|
fxaa_.needsRecreate = false;
|
||||||
|
|
@ -1250,7 +1249,7 @@ void Renderer::endFrame() {
|
||||||
// FSR3+FXAA combined: re-point FXAA's descriptor to the FSR3 temporal output
|
// FSR3+FXAA combined: re-point FXAA's descriptor to the FSR3 temporal output
|
||||||
// so renderFXAAPass() applies spatial AA on the temporally-stabilized frame.
|
// so renderFXAAPass() applies spatial AA on the temporally-stabilized frame.
|
||||||
// This must happen outside the render pass (descriptor updates are CPU-side).
|
// This must happen outside the render pass (descriptor updates are CPU-side).
|
||||||
if ((fxaa_.enabled || ghostMode_) && fxaa_.descSet && fxaa_.sceneSampler) {
|
if (fxaa_.enabled && fxaa_.descSet && fxaa_.sceneSampler) {
|
||||||
VkImageView fsr3OutputView = VK_NULL_HANDLE;
|
VkImageView fsr3OutputView = VK_NULL_HANDLE;
|
||||||
if (fsr2_.useAmdBackend) {
|
if (fsr2_.useAmdBackend) {
|
||||||
if (fsr2_.amdFsr3FramegenRuntimeActive && fsr2_.framegenOutput.image)
|
if (fsr2_.amdFsr3FramegenRuntimeActive && fsr2_.framegenOutput.image)
|
||||||
|
|
@ -1309,7 +1308,7 @@ void Renderer::endFrame() {
|
||||||
// of RCAS sharpening. FXAA descriptor is temporarily pointed to the FSR3
|
// of RCAS sharpening. FXAA descriptor is temporarily pointed to the FSR3
|
||||||
// history buffer (which is already in SHADER_READ_ONLY_OPTIMAL). This gives
|
// history buffer (which is already in SHADER_READ_ONLY_OPTIMAL). This gives
|
||||||
// FSR3 temporal stability + FXAA spatial edge smoothing ("ultra quality native").
|
// FSR3 temporal stability + FXAA spatial edge smoothing ("ultra quality native").
|
||||||
if ((fxaa_.enabled || ghostMode_) && fxaa_.pipeline && fxaa_.descSet) {
|
if (fxaa_.enabled && fxaa_.pipeline && fxaa_.descSet) {
|
||||||
renderFXAAPass();
|
renderFXAAPass();
|
||||||
} else {
|
} else {
|
||||||
// Draw RCAS sharpening from accumulated history buffer
|
// Draw RCAS sharpening from accumulated history buffer
|
||||||
|
|
@ -1318,7 +1317,7 @@ void Renderer::endFrame() {
|
||||||
|
|
||||||
// Restore FXAA descriptor to its normal scene color source so standalone
|
// Restore FXAA descriptor to its normal scene color source so standalone
|
||||||
// FXAA frames are not affected by the FSR3 history pointer set above.
|
// FXAA frames are not affected by the FSR3 history pointer set above.
|
||||||
if ((fxaa_.enabled || ghostMode_) && fxaa_.descSet && fxaa_.sceneSampler && fxaa_.sceneColor.imageView) {
|
if (fxaa_.enabled && fxaa_.descSet && fxaa_.sceneSampler && fxaa_.sceneColor.imageView) {
|
||||||
VkDescriptorImageInfo restoreInfo{};
|
VkDescriptorImageInfo restoreInfo{};
|
||||||
restoreInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
restoreInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
restoreInfo.imageView = fxaa_.sceneColor.imageView;
|
restoreInfo.imageView = fxaa_.sceneColor.imageView;
|
||||||
|
|
@ -1342,7 +1341,7 @@ void Renderer::endFrame() {
|
||||||
}
|
}
|
||||||
fsr2_.frameIndex = (fsr2_.frameIndex + 1) % 256; // Wrap to keep Halton values well-distributed
|
fsr2_.frameIndex = (fsr2_.frameIndex + 1) % 256; // Wrap to keep Halton values well-distributed
|
||||||
|
|
||||||
} else if ((fxaa_.enabled || ghostMode_) && fxaa_.sceneFramebuffer) {
|
} else if (fxaa_.enabled && fxaa_.sceneFramebuffer) {
|
||||||
// End the off-screen scene render pass
|
// End the off-screen scene render pass
|
||||||
vkCmdEndRenderPass(currentCmd);
|
vkCmdEndRenderPass(currentCmd);
|
||||||
|
|
||||||
|
|
@ -1857,7 +1856,18 @@ void Renderer::updateCharacterAnimation() {
|
||||||
|
|
||||||
CharAnimState newState = charAnimState;
|
CharAnimState newState = charAnimState;
|
||||||
|
|
||||||
bool moving = cameraController->isMoving();
|
const bool rawMoving = cameraController->isMoving();
|
||||||
|
const bool rawSprinting = cameraController->isSprinting();
|
||||||
|
constexpr float kLocomotionStopGraceSec = 0.12f;
|
||||||
|
if (rawMoving) {
|
||||||
|
locomotionStopGraceTimer_ = kLocomotionStopGraceSec;
|
||||||
|
locomotionWasSprinting_ = rawSprinting;
|
||||||
|
} else {
|
||||||
|
locomotionStopGraceTimer_ = std::max(0.0f, locomotionStopGraceTimer_ - lastDeltaTime_);
|
||||||
|
}
|
||||||
|
// Debounce brief input/state dropouts (notably during both-mouse steering) so
|
||||||
|
// locomotion clips do not restart every few frames.
|
||||||
|
bool moving = rawMoving || locomotionStopGraceTimer_ > 0.0f;
|
||||||
bool movingForward = cameraController->isMovingForward();
|
bool movingForward = cameraController->isMovingForward();
|
||||||
bool movingBackward = cameraController->isMovingBackward();
|
bool movingBackward = cameraController->isMovingBackward();
|
||||||
bool autoRunning = cameraController->isAutoRunning();
|
bool autoRunning = cameraController->isAutoRunning();
|
||||||
|
|
@ -1870,7 +1880,7 @@ void Renderer::updateCharacterAnimation() {
|
||||||
bool anyStrafeRight = strafeRight && !strafeLeft && pureStrafe;
|
bool anyStrafeRight = strafeRight && !strafeLeft && pureStrafe;
|
||||||
bool grounded = cameraController->isGrounded();
|
bool grounded = cameraController->isGrounded();
|
||||||
bool jumping = cameraController->isJumping();
|
bool jumping = cameraController->isJumping();
|
||||||
bool sprinting = cameraController->isSprinting();
|
bool sprinting = rawSprinting || (!rawMoving && moving && locomotionWasSprinting_);
|
||||||
bool sitting = cameraController->isSitting();
|
bool sitting = cameraController->isSitting();
|
||||||
bool swim = cameraController->isSwimming();
|
bool swim = cameraController->isSwimming();
|
||||||
bool forceMelee = meleeSwingTimer > 0.0f && grounded && !swim;
|
bool forceMelee = meleeSwingTimer > 0.0f && grounded && !swim;
|
||||||
|
|
@ -2530,8 +2540,14 @@ void Renderer::updateCharacterAnimation() {
|
||||||
float currentAnimTimeMs = 0.0f;
|
float currentAnimTimeMs = 0.0f;
|
||||||
float currentAnimDurationMs = 0.0f;
|
float currentAnimDurationMs = 0.0f;
|
||||||
bool haveState = characterRenderer->getAnimationState(characterInstanceId, currentAnimId, currentAnimTimeMs, currentAnimDurationMs);
|
bool haveState = characterRenderer->getAnimationState(characterInstanceId, currentAnimId, currentAnimTimeMs, currentAnimDurationMs);
|
||||||
if (!haveState || currentAnimId != animId) {
|
// Some frames may transiently fail getAnimationState() while resources/instance state churn.
|
||||||
|
// Avoid reissuing the same clip on those frames, which restarts locomotion and causes hitches.
|
||||||
|
const bool requestChanged = (lastPlayerAnimRequest_ != animId) || (lastPlayerAnimLoopRequest_ != loop);
|
||||||
|
const bool shouldPlay = (haveState && currentAnimId != animId) || (!haveState && requestChanged);
|
||||||
|
if (shouldPlay) {
|
||||||
characterRenderer->playAnimation(characterInstanceId, animId, loop);
|
characterRenderer->playAnimation(characterInstanceId, animId, loop);
|
||||||
|
lastPlayerAnimRequest_ = animId;
|
||||||
|
lastPlayerAnimLoopRequest_ = loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5075,7 +5091,7 @@ void Renderer::renderFXAAPass() {
|
||||||
vkCmdBindDescriptorSets(currentCmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
vkCmdBindDescriptorSets(currentCmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
fxaa_.pipelineLayout, 0, 1, &fxaa_.descSet, 0, nullptr);
|
fxaa_.pipelineLayout, 0, 1, &fxaa_.descSet, 0, nullptr);
|
||||||
|
|
||||||
// Pass rcpFrame + sharpness + desaturate (vec4, 16 bytes).
|
// Pass rcpFrame + sharpness + effect flag (vec4, 16 bytes).
|
||||||
// When FSR2/FSR3 is active alongside FXAA, forward FSR2's sharpness so the
|
// When FSR2/FSR3 is active alongside FXAA, forward FSR2's sharpness so the
|
||||||
// post-FXAA unsharp-mask step restores the crispness that FXAA's blur removes.
|
// post-FXAA unsharp-mask step restores the crispness that FXAA's blur removes.
|
||||||
float sharpness = fsr2_.enabled ? fsr2_.sharpness : 0.0f;
|
float sharpness = fsr2_.enabled ? fsr2_.sharpness : 0.0f;
|
||||||
|
|
@ -5083,7 +5099,7 @@ void Renderer::renderFXAAPass() {
|
||||||
1.0f / static_cast<float>(ext.width),
|
1.0f / static_cast<float>(ext.width),
|
||||||
1.0f / static_cast<float>(ext.height),
|
1.0f / static_cast<float>(ext.height),
|
||||||
sharpness,
|
sharpness,
|
||||||
ghostMode_ ? 1.0f : 0.0f // desaturate: 1=ghost grayscale, 0=normal
|
0.0f
|
||||||
};
|
};
|
||||||
vkCmdPushConstants(currentCmd, fxaa_.pipelineLayout,
|
vkCmdPushConstants(currentCmd, fxaa_.pipelineLayout,
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, pc);
|
VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, pc);
|
||||||
|
|
@ -5273,12 +5289,6 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) {
|
||||||
renderOverlay(tint, cmd);
|
renderOverlay(tint, cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ghost mode desaturation overlay (non-FXAA path approximation).
|
|
||||||
// When FXAA is active the FXAA shader applies true per-pixel desaturation;
|
|
||||||
// otherwise a high-opacity gray overlay gives a similar washed-out effect.
|
|
||||||
if (ghostMode_ && overlayPipeline && !(fxaa_.enabled || fxaa_.sceneFramebuffer)) {
|
|
||||||
renderOverlay(glm::vec4(0.5f, 0.5f, 0.55f, 0.82f), cmd);
|
|
||||||
}
|
|
||||||
if (minimap && minimap->isEnabled() && camera && window) {
|
if (minimap && minimap->isEnabled() && camera && window) {
|
||||||
glm::vec3 minimapCenter = camera->getPosition();
|
glm::vec3 minimapCenter = camera->getPosition();
|
||||||
if (cameraController && cameraController->isThirdPerson())
|
if (cameraController && cameraController->isThirdPerson())
|
||||||
|
|
@ -5413,10 +5423,6 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) {
|
||||||
renderOverlay(tint);
|
renderOverlay(tint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ghost mode desaturation overlay (non-FXAA path approximation).
|
|
||||||
if (ghostMode_ && overlayPipeline && !(fxaa_.enabled || fxaa_.sceneFramebuffer)) {
|
|
||||||
renderOverlay(glm::vec4(0.5f, 0.5f, 0.55f, 0.82f));
|
|
||||||
}
|
|
||||||
if (minimap && minimap->isEnabled() && camera && window) {
|
if (minimap && minimap->isEnabled() && camera && window) {
|
||||||
glm::vec3 minimapCenter = camera->getPosition();
|
glm::vec3 minimapCenter = camera->getPosition();
|
||||||
if (cameraController && cameraController->isThirdPerson())
|
if (cameraController && cameraController->isThirdPerson())
|
||||||
|
|
|
||||||
|
|
@ -845,7 +845,9 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
// Update renderer face-target position and selection circle
|
// Update renderer face-target position and selection circle
|
||||||
auto* renderer = core::Application::getInstance().getRenderer();
|
auto* renderer = core::Application::getInstance().getRenderer();
|
||||||
if (renderer) {
|
if (renderer) {
|
||||||
renderer->setInCombat(gameHandler.isInCombat());
|
renderer->setInCombat(gameHandler.isInCombat() &&
|
||||||
|
!gameHandler.isPlayerDead() &&
|
||||||
|
!gameHandler.isPlayerGhost());
|
||||||
static glm::vec3 targetGLPos;
|
static glm::vec3 targetGLPos;
|
||||||
if (gameHandler.hasTarget()) {
|
if (gameHandler.hasTarget()) {
|
||||||
auto target = gameHandler.getTarget();
|
auto target = gameHandler.getTarget();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue