using Godot; using MegaCrit.Sts2.Core.Combat; using MegaCrit.Sts2.Core.Nodes.Combat; using STS2RitsuLib.Patching.Models; using System; using System.Reflection; namespace VulnerabilityIndicator.Scripts.Patches; /// /// Harmony patch that hooks into the combat UI to: /// 1. Initialize the VulnerabilityChecker when combat starts /// 2. Find and interact with player panel nodes in multiplayer /// public sealed class CombatUiPlayerPanelPatch : IPatchMethod { public static string PatchId => "vuln_indicator_combat_ui"; public static string Description => "Initializes vulnerability checker on combat start and patches player panel rendering"; public static bool IsCritical => false; private static VulnerabilityChecker EnsureCheckerInitialized(CombatState combat) { var checker = VulnerabilityChecker.GetOrCreate(); checker.Initialize(combat); return checker; } public static ModPatchTarget[] GetTargets() => [new(typeof(NCombatUi), nameof(NCombatUi._Ready))]; public static void Postfix(NCombatUi __instance) { try { var combatState = GetCombatState(__instance); if (combatState == null) return; var checker = EnsureCheckerInitialized(combatState); // Refresh indicators for all players checker.OnCardChanged(); } catch (Exception ex) { Entry.Logger.Warn($"CombatUiPlayerPanelPatch error: {ex.Message}"); } } private static CombatState? GetCombatState(NCombatUi combatUi) { try { var type = combatUi.GetType(); // Try common property names for combat state foreach (var propName in new[] { "CombatState", "Combat", "State", "GameState", "CombatGameState" }) { var prop = type.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (prop != null) { var value = prop.GetValue(combatUi); if (value is CombatState cs) return cs; } } // Try traversing up to parent nodes if (combatUi.GetParent() is Node parent) { var parentType = parent.GetType(); foreach (var propName in new[] { "CombatState", "Combat", "State" }) { var prop = parentType.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (prop != null) { var value = prop.GetValue(parent); if (value is CombatState cs) return cs; } } } } catch { // Ignore reflection errors } return null; } }