worldbox-observer-mod/IdleSpectator/FocusTooltipPatches.cs
2026-07-14 19:18:57 -05:00

77 lines
2.1 KiB
C#

using HarmonyLib;
namespace IdleSpectator;
/// <summary>
/// Idle pins <see cref="UnitSelectionEffect.last_actor"/> so relationship arrows draw.
/// That same pin would always show the focus unit tip via
/// <see cref="CursorTooltipHelper.updateGameplayTooltip"/>.
/// Allow tips for a real cursor unit or the dossier live sprite; suppress the pin tip on empty world / dossier chrome.
/// </summary>
[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;
}
}
}