From 7e1a463061a642c754e6d73b9a0d354ac9eaa16d Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 20 Feb 2026 20:37:55 -0800 Subject: [PATCH] Fix hostile target selection when faction flags are wrong - make tab-target accept units that are either faction-hostile or actively aggressive toward the player\n- fix cases where enemies remain un-tab-targetable after combat starts due to stale/friendly faction state\n- prefer hostile UNIT picks over nearby GAMEOBJECT picks for both left-click target and right-click interact flows\n- keep existing dead-unit filtering and interaction behavior intact while improving combat target acquisition --- src/game/game_handler.cpp | 5 ++++- src/ui/game_screen.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 445542f8..9c3ab76a 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -6992,10 +6992,13 @@ void GameHandler::tabTarget(float playerX, float playerY, float playerZ) { // Helper: returns true if the entity is a living hostile that can be tab-targeted. auto isValidTabTarget = [&](const std::shared_ptr& e) -> bool { if (!e) return false; + const uint64_t guid = e->getGuid(); auto* unit = dynamic_cast(e.get()); if (!unit) return false; // Not a unit (shouldn't happen after type filter) if (unit->getHealth() == 0) return false; // Dead / corpse - if (!unit->isHostile()) return false; // Friendly + const bool hostileByFaction = unit->isHostile(); + const bool hostileByCombat = isAggressiveTowardPlayer(guid); + if (!hostileByFaction && !hostileByCombat) return false; return true; }; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index d6929edb..c77e0eb7 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -1368,6 +1368,8 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { float closestT = 1e30f; uint64_t closestGuid = 0; + float closestHostileUnitT = 1e30f; + uint64_t closestHostileUnitGuid = 0; const uint64_t myGuid = gameHandler.getPlayerGuid(); for (const auto& [guid, entity] : gameHandler.getEntityManager().getEntities()) { @@ -1403,6 +1405,14 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { float hitT; if (raySphereIntersect(ray, hitCenter, hitRadius, hitT)) { + if (t == game::ObjectType::UNIT) { + auto unit = std::static_pointer_cast(entity); + bool hostileUnit = unit->isHostile() || gameHandler.isAggressiveTowardPlayer(guid); + if (hostileUnit && hitT < closestHostileUnitT) { + closestHostileUnitT = hitT; + closestHostileUnitGuid = guid; + } + } if (hitT < closestT) { closestT = hitT; closestGuid = guid; @@ -1410,6 +1420,11 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { } } + // Prefer hostile monsters over nearby gameobjects/others when both are hittable. + if (closestHostileUnitGuid != 0) { + closestGuid = closestHostileUnitGuid; + } + if (closestGuid != 0) { gameHandler.setTarget(closestGuid); } else { @@ -1447,6 +1462,8 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { float closestT = 1e30f; uint64_t closestGuid = 0; game::ObjectType closestType = game::ObjectType::OBJECT; + float closestHostileUnitT = 1e30f; + uint64_t closestHostileUnitGuid = 0; const uint64_t myGuid = gameHandler.getPlayerGuid(); for (const auto& [guid, entity] : gameHandler.getEntityManager().getEntities()) { auto t = entity->getType(); @@ -1481,6 +1498,14 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { } float hitT; if (raySphereIntersect(ray, hitCenter, hitRadius, hitT)) { + if (t == game::ObjectType::UNIT) { + auto unit = std::static_pointer_cast(entity); + bool hostileUnit = unit->isHostile() || gameHandler.isAggressiveTowardPlayer(guid); + if (hostileUnit && hitT < closestHostileUnitT) { + closestHostileUnitT = hitT; + closestHostileUnitGuid = guid; + } + } if (hitT < closestT) { closestT = hitT; closestGuid = guid; @@ -1488,6 +1513,11 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { } } } + // Prefer hostile monsters over nearby gameobjects/others when right-click picking. + if (closestHostileUnitGuid != 0) { + closestGuid = closestHostileUnitGuid; + closestType = game::ObjectType::UNIT; + } if (closestGuid != 0) { if (closestType == game::ObjectType::GAMEOBJECT) { gameHandler.setTarget(closestGuid);