using HarmonyLib; namespace IdleSpectator; /// /// Idle pins so relationship arrows draw. /// That same pin would always show the focus unit tip via /// . /// Allow tips for a real cursor unit or the dossier live sprite; suppress the pin tip on empty world / dossier chrome. /// [HarmonyPatch(typeof(CursorTooltipHelper), nameof(CursorTooltipHelper.updateGameplayTooltip))] internal static class FocusTooltipPatches { [HarmonyPrefix] private static bool Prefix(ref bool __result, ref Actor __state) { __state = null; if (!SpectatorMode.Active) { return true; } // Live sprite: tip for the focused unit (last_actor is already pinned). if (WatchCaption.IsPointerOverAvatar()) { return true; } // Dossier chrome (not the sprite): no tip. if (WatchCaption.IsPointerOverPanel()) { Tooltip.hideTooltip(); __result = false; return false; } Actor near = GetActorNearCursorSafe(); if (near != null && near.isAlive()) { // Real world hover: briefly use that unit for the tip, then restore the pin. __state = UnitSelectionEffect.last_actor; UnitSelectionEffect.setLastActor(near); return true; } // Empty world (grass, water, etc.): do not leak the idle focus tip. Tooltip.hideTooltip(); __result = false; return false; } [HarmonyPostfix] private static void Postfix(Actor __state) { if (__state != null) { UnitSelectionEffect.setLastActor(__state); } } private static Actor GetActorNearCursorSafe() { try { if (World.world == null || ControllableUnit.isControllingUnit()) { return null; } return World.world.getActorNearCursor(); } catch { return null; } } }