diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index 2f3ff0aa..c175274b 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -74,6 +74,7 @@ private: ImVec2 nameplateCtxPos_{}; // Screen position of nameplate right-click uint32_t lastPlayerHp_ = 0; // Previous frame HP for damage flash detection float damageFlashAlpha_ = 0.0f; // Screen edge flash intensity (fades to 0) + bool damageFlashEnabled_ = true; float levelUpFlashAlpha_ = 0.0f; // Golden level-up burst effect (fades to 0) uint32_t levelUpDisplayLevel_ = 0; // Level shown in level-up text diff --git a/src/rendering/world_map.cpp b/src/rendering/world_map.cpp index cf4c70fd..9c30a3b5 100644 --- a/src/rendering/world_map.cpp +++ b/src/rendering/world_map.cpp @@ -752,7 +752,6 @@ void WorldMap::updateExploration(const glm::vec3& playerRenderPos) { return (serverExplorationMask[word] & (1u << (bitIndex % 32))) != 0; }; - bool markedAny = false; if (hasServerExplorationMask) { exploredZones.clear(); for (int i = 0; i < static_cast(zones.size()); i++) { @@ -761,15 +760,19 @@ void WorldMap::updateExploration(const glm::vec3& playerRenderPos) { for (uint32_t bit : z.exploreBits) { if (isBitSet(bit)) { exploredZones.insert(i); - markedAny = true; break; } } } + // Always trust the server mask when available — even if empty (unexplored character). + // Also reveal the zone the player is currently standing in so the map isn't pitch-black + // the moment they first enter a new zone (the server bit arrives on the next update). + int curZone = findZoneForPlayer(playerRenderPos); + if (curZone >= 0) exploredZones.insert(curZone); + return; } - if (markedAny) return; - // Server mask unavailable or empty — fall back to locally-accumulated position tracking. + // Server mask unavailable — fall back to locally-accumulated position tracking. // Add the zone the player is currently in to the local set and display that. float wowX = playerRenderPos.y; float wowY = playerRenderPos.x; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 94a9d05a..810a2f52 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -709,7 +709,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { } // Detect HP drop (ignore transitions from 0 — entity just spawned or uninitialized) - if (lastPlayerHp_ > 0 && currentHp < lastPlayerHp_ && currentHp > 0) + if (damageFlashEnabled_ && lastPlayerHp_ > 0 && currentHp < lastPlayerHp_ && currentHp > 0) damageFlashAlpha_ = 1.0f; lastPlayerHp_ = currentHp; @@ -10626,6 +10626,16 @@ void GameScreen::renderSettingsWindow() { ImGui::SameLine(); ImGui::TextDisabled("(ms indicator near minimap)"); + ImGui::Spacing(); + ImGui::SeparatorText("Screen Effects"); + ImGui::Spacing(); + if (ImGui::Checkbox("Damage Flash", &damageFlashEnabled_)) { + if (!damageFlashEnabled_) damageFlashAlpha_ = 0.0f; + saveSettings(); + } + ImGui::SameLine(); + ImGui::TextDisabled("(red vignette on taking damage)"); + ImGui::EndChild(); ImGui::EndTabItem(); } @@ -12290,6 +12300,7 @@ void GameScreen::saveSettings() { out << "show_left_bar=" << (pendingShowLeftBar ? 1 : 0) << "\n"; out << "right_bar_offset_y=" << pendingRightBarOffsetY << "\n"; out << "left_bar_offset_y=" << pendingLeftBarOffsetY << "\n"; + out << "damage_flash=" << (damageFlashEnabled_ ? 1 : 0) << "\n"; // Audio out << "sound_muted=" << (soundMuted_ ? 1 : 0) << "\n"; @@ -12407,6 +12418,8 @@ void GameScreen::loadSettings() { pendingRightBarOffsetY = std::clamp(std::stof(val), -400.0f, 400.0f); } else if (key == "left_bar_offset_y") { pendingLeftBarOffsetY = std::clamp(std::stof(val), -400.0f, 400.0f); + } else if (key == "damage_flash") { + damageFlashEnabled_ = (std::stoi(val) != 0); } // Audio else if (key == "sound_muted") {