diff --git a/include/core/application.hpp b/include/core/application.hpp index 8e50aaba..2e00e89a 100644 --- a/include/core/application.hpp +++ b/include/core/application.hpp @@ -160,6 +160,7 @@ private: uint32_t wyvernDisplayId_ = 0; bool lastTaxiFlight_ = false; float taxiStreamCooldown_ = 0.0f; + bool idleYawned_ = false; // Online gameobject model spawning struct GameObjectInstanceInfo { diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 9a095a5d..6679d102 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -148,6 +148,12 @@ public: */ const MovementInfo& getMovementInfo() const { return movementInfo; } uint32_t getCurrentMapId() const { return currentMapId_; } + bool getHomeBind(uint32_t& mapId, glm::vec3& pos) const { + if (!hasHomeBind_) return false; + mapId = homeBindMapId_; + pos = homeBindPos_; + return true; + } /** * Send a movement packet @@ -781,6 +787,9 @@ private: // Player GUID and map uint64_t playerGuid = 0; uint32_t currentMapId_ = 0; + bool hasHomeBind_ = false; + uint32_t homeBindMapId_ = 0; + glm::vec3 homeBindPos_{0.0f}; // ---- Phase 1: Name caches ---- std::unordered_map playerNameCache; diff --git a/include/rendering/camera_controller.hpp b/include/rendering/camera_controller.hpp index 2a44649d..00cd83aa 100644 --- a/include/rendering/camera_controller.hpp +++ b/include/rendering/camera_controller.hpp @@ -45,6 +45,7 @@ public: void setOnlineMode(bool online) { onlineMode = online; } void startIntroPan(float durationSec = 2.8f, float orbitDegrees = 140.0f); bool isIntroActive() const { return introActive; } + bool isIdleOrbit() const { return idleOrbit_; } float getMovementSpeed() const { return movementSpeed; } const glm::vec3& getDefaultPosition() const { return defaultPosition; } diff --git a/src/core/application.cpp b/src/core/application.cpp index 04504953..fa870cb7 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -407,6 +407,13 @@ void Application::update(float deltaTime) { if (lastTaxiFlight_ && !onTaxi) { renderer->getCameraController()->clearMovementInputs(); } + bool idleOrbit = renderer->getCameraController()->isIdleOrbit(); + if (idleOrbit && !idleYawned_ && renderer) { + renderer->playEmote("yawn"); + idleYawned_ = true; + } else if (!idleOrbit) { + idleYawned_ = false; + } } if (renderer) { renderer->setTaxiFlight(onTaxi); diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 9f47d6a8..806c5428 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -582,9 +582,12 @@ void GameHandler::handlePacket(network::Packet& packet) { if (BindPointUpdateParser::parse(packet, data)) { LOG_INFO("Bindpoint updated: mapId=", data.mapId, " pos=(", data.x, ", ", data.y, ", ", data.z, ")"); + glm::vec3 canonical = core::coords::serverToCanonical( + glm::vec3(data.x, data.y, data.z)); + hasHomeBind_ = true; + homeBindMapId_ = data.mapId; + homeBindPos_ = canonical; if (bindPointCallback_) { - glm::vec3 canonical = core::coords::serverToCanonical( - glm::vec3(data.x, data.y, data.z)); bindPointCallback_(data.mapId, canonical.x, canonical.y, canonical.z); } addSystemChatMessage("Your home has been set."); diff --git a/src/rendering/camera_controller.cpp b/src/rendering/camera_controller.cpp index d0032686..08f7c751 100644 --- a/src/rendering/camera_controller.cpp +++ b/src/rendering/camera_controller.cpp @@ -531,6 +531,10 @@ void CameraController::update(float deltaTime) { if (m2Renderer) { m2H = m2Renderer->getFloorHeight(x, y, targetPos.z); } + bool firstPerson = (!thirdPerson) || (currentDistance < 0.6f); + if (firstPerson) { + wmoH.reset(); + } auto base = selectReachableFloor(terrainH, wmoH, targetPos.z, stepUpBudget); bool fromM2 = false; if (m2H && *m2H <= targetPos.z + stepUpBudget && (!base || *m2H > *base)) { @@ -607,6 +611,7 @@ void CameraController::update(float deltaTime) { // Skip entirely while swimming — the swim floor clamp handles vertical bounds. if (!swimming) { float stepUpBudget = grounded ? 1.6f : 1.2f; + bool firstPerson = (!thirdPerson) || (currentDistance < 0.6f); // 1. Center-only sample for terrain/WMO floor selection. // Using only the center prevents tunnel entrances from snapping @@ -619,7 +624,7 @@ void CameraController::update(float deltaTime) { terrainH = terrainManager->getHeightAt(targetPos.x, targetPos.y); } float wmoProbeZ = std::max(targetPos.z, lastGroundZ) + stepUpBudget + 0.5f; - if (wmoRenderer) { + if (wmoRenderer && !firstPerson) { wmoH = wmoRenderer->getFloorHeight(targetPos.x, targetPos.y, wmoProbeZ); } groundH = selectReachableFloor(terrainH, wmoH, targetPos.z, stepUpBudget); diff --git a/src/ui/inventory_screen.cpp b/src/ui/inventory_screen.cpp index 4b4da531..8fb471b6 100644 --- a/src/ui/inventory_screen.cpp +++ b/src/ui/inventory_screen.cpp @@ -1159,6 +1159,17 @@ void InventoryScreen::renderItemTooltip(const game::ItemDef& item) { ImVec4 qColor = getQualityColor(item.quality); ImGui::TextColored(qColor, "%s", item.name.c_str()); + if (item.itemId == 6948 && gameHandler_) { + uint32_t mapId = 0; + glm::vec3 pos; + if (gameHandler_->getHomeBind(mapId, pos)) { + ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), + "Home: map %u (%.1f, %.1f, %.1f)", mapId, pos.x, pos.y, pos.z); + } else { + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Home: not set"); + } + } + // Slot type if (item.inventoryType > 0) { const char* slotName = "";