public static void HUDMechArmorReadout_SetHoveredArmor_Postfix(HUDMechArmorReadout __instance, ArmorLocation location, Mech ___displayedMech) { if (__instance.UseForCalledShots && location == ArmorLocation.Head) { Mod.Log.Trace("HUDMAR:SHA entered"); bool canAlwaysCalledShot = false; List <Statistic> customStats = ActorHelper.FindCustomStatistic(ModStats.CalledShowAlwaysAllow, __instance.HUD.SelectedActor); foreach (Statistic stat in customStats) { if (stat.ValueType() == typeof(bool) && stat.Value <bool>()) { canAlwaysCalledShot = true; } } bool canBeTargeted = __instance.HUD.SelectedTarget.IsShutDown || __instance.HUD.SelectedTarget.IsProne || canAlwaysCalledShot; Mod.Log.Debug($" Hover - target:({___displayedMech.DisplayName}_{___displayedMech.GetPilot()?.Name}) canBeTargeted:{canBeTargeted} by attacker:({__instance.HUD.SelectedActor.DisplayName})"); Mod.Log.Debug($" isShutdown:{___displayedMech.IsShutDown} isProne:{___displayedMech.IsProne} canAlwaysCalledShot:{canAlwaysCalledShot}"); if (!canBeTargeted) { Mod.Log.Debug(" preventing targeting of head."); __instance.ClearHoveredArmor(ArmorLocation.Head); } else { Mod.Log.Debug(" target head can be targeted."); } } }
static void Postfix(HUDMechArmorReadout __instance, ArmorLocation location, Mech ___displayedMech) { if (__instance == null || __instance.HUD == null || __instance.HUD.SelectedActor == null || __instance.HUD.SelectedTarget == null) { return; // nothing to do } if (__instance.UseForCalledShots && location == ArmorLocation.Head) { Mod.Log.Trace?.Write("HUDMAR:SHA entered"); bool attackerCanAlwaysMakeCalledShot = __instance.HUD.SelectedActor.CanAlwaysUseCalledShot(); bool targetCanBeCalledShot = __instance.HUD.SelectedTarget.IsShutDown || __instance.HUD.SelectedTarget.IsProne || attackerCanAlwaysMakeCalledShot; Mod.Log.Debug?.Write($" Hover - target:({___displayedMech.DistinctId()}) canBeTargeted:{targetCanBeCalledShot} by attacker:({__instance.HUD.SelectedActor.DistinctId()})"); Mod.Log.Debug?.Write($" isShutdown:{___displayedMech.IsShutDown} isProne:{___displayedMech.IsProne} canAlwaysCalledShot:{attackerCanAlwaysMakeCalledShot}"); if (!targetCanBeCalledShot) { Mod.Log.Debug?.Write(" preventing targeting of head."); __instance.ClearHoveredArmor(ArmorLocation.Head); } else { Mod.Log.Debug?.Write(" target head can be targeted."); } } }
public static void Postfix(HUDBuildingStructureReadout __instance) { if (__instance.DisplayedBuilding != null && __instance.HoverInfoTextStructure != null) { // TODO: Handle sensor lock int maxStructure = HUDMechArmorReadout.FormatForSummary(__instance.DisplayedBuilding.SummaryStructureMax); __instance.HoverInfoTextStructure.SetText($"? / {maxStructure}"); } }
// Private method can't be patched by annotations, so use MethodInfo //public static MethodInfo TargetMethod() { // return AccessTools.Method(typeof(HUDMechArmorReadout), "RefreshHoverInfo", new Type[] { }); //} public static void Postfix(HUDMechArmorReadout __instance) { if (__instance != null && __instance.DisplayedMech != null && __instance.HoverInfoTextArmor != null && __instance.HoverInfoTextStructure != null) { if (!__instance.DisplayedMech.Combat.HostilityMatrix.IsLocalPlayerFriendly(__instance.DisplayedMech.TeamId)) { Mod.Log.Trace?.Write($"Hiding armor and structure on target: {CombatantUtils.Label(__instance.DisplayedMech)}"); ArmorAndStructHelper.ObfuscateArmorAndStructText(__instance.DisplayedMech, __instance.HoverInfoTextArmor, __instance.HoverInfoTextStructure); } } }
public static void Postfix(CombatHUDMechTrayArmorHover __instance) { HUDMechArmorReadout ___Readout = (HUDMechArmorReadout)Traverse.Create(__instance).Property("Readout").GetValue(); CombatHUDTooltipHoverElement ___ToolTip = (CombatHUDTooltipHoverElement)Traverse.Create(__instance).Property("ToolTip").GetValue(); if (___Readout != null && ___Readout.DisplayedMech != null && ___Readout.DisplayedMech.Combat != null && ___ToolTip != null) { Mech target = ___Readout.DisplayedMech; if (!target.Combat.HostilityMatrix.IsLocalPlayerFriendly(target.TeamId)) { SensorScanType scanType = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated); if (scanType < SensorScanType.AllInformation) { ___ToolTip.BuffStrings.Clear(); ___ToolTip.DebuffStrings.Clear(); } } } }
public static void FixRearStructureDisplay(HUDMechArmorReadout __instance, AttackDirection shownAttackDirection) { try { HUDMechArmorReadout me = __instance; float[] timeSinceStructureDamaged = (float[])timeSinceStructureDamagedProp.GetValue(me, null); Color[] structureRear = (Color[])structureRearProp.GetValue(me, null); float flashPeriod = 0f; Color flashColour = Color.black; if (LookAndColor == null) { TryRun(() => LookAndColor = HBS.LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants); } if (LookAndColor != null) { flashPeriod = LookAndColor.FlashArmorTime; flashColour = LookAndColor.ArmorFlash.color; } Dictionary <ArmorLocation, int> dictionary = null; bool mayDisableParts = shownAttackDirection != AttackDirection.None && me.UseForCalledShots; if (mayDisableParts) { dictionary = HUD.Combat.HitLocation.GetMechHitTable(shownAttackDirection, false); } for (int i = 0; i < 8; i++) { float structureFlash = Mathf.Clamp01(1f - timeSinceStructureDamaged[i] / flashPeriod); Color structureColor = structureRear[i]; // The first line that has typo in original code if (mayDisableParts) { ArmorLocation rearLocation = HUDMechArmorReadout.GetArmorLocationFromIndex(i, true, me.flipRearDisplay); bool isIntact = dictionary.ContainsKey(rearLocation) && dictionary[rearLocation] != 0; if (!isIntact) // And the second typo line { structureColor = Color.Lerp(structureColor, Color.black, me.hiddenColorLerp); } } UIHelpers.SetImageColor(me.StructureRear[i], Color.Lerp(structureColor, flashColour, structureFlash)); } } catch (Exception ex) { Error(ex); } }
public static string GetLocationHealthString(ICombatant combatant, ArmorLocation location) { string result = ""; if (combatant.UnitType != UnitType.Mech) { return("NO MECH"); } Mech m = combatant as Mech; Color g = LazySingletonBehavior <UIManager> .Instance.UIColorRefs.gold; Color w = LazySingletonBehavior <UIManager> .Instance.UIColorRefs.whiteHalf; string colorTagG = $"<color=#{ColorUtility.ToHtmlStringRGBA(g)}>"; string colorTagW = $"<color=#{ColorUtility.ToHtmlStringRGBA(w)}>"; string closeColorTag = "</color>"; int currentArmor = (int)m.GetCurrentArmor(location); int maxArmor = (int)HUDMechArmorReadout.GetInitialArmorForLocation(m.MechDef, location); int currentStructure = Math.Max(1, ((int)m.GetCurrentStructure(MechStructureRules.GetChassisLocationFromArmorLocation(location)))); int maxStructure = (int)m.GetMaxStructure(MechStructureRules.GetChassisLocationFromArmorLocation(location)); int totalCurrent = currentArmor + currentStructure; int totalMax = maxArmor + maxStructure; // Simple if (currentStructure < maxStructure || currentArmor <= 0) { result = $"{colorTagG}LOCATION HEALTH: {totalCurrent} / {totalMax}{closeColorTag}"; } else { result = $"{colorTagW}LOCATION HEALTH: {totalCurrent} / {totalMax}{closeColorTag}"; } // Differentiated //result = $"{colorTagG}STRUCTURE: {currentStructure} / {maxStructure}{closeColorTag} {colorTagW}ARMOR: {currentArmor} / {maxArmor}{closeColorTag}"; return(result); }
public static void Postfix(HUDMechArmorReadout __instance, ArmorLocation location, Mech ___displayedMech) { try { if (__instance.UseForCalledShots && location == ArmorLocation.Head) { Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] Clear head selection if too many weapons are enabled..."); int enabledWeaponCount = Utilities.GetReadiedWeaponCount(__instance.HUD.SelectedActor.Weapons, __instance.HUD.SelectedTarget); Pilot selectedPilot = __instance.HUD.SelectedActor.GetPilot(); int maxAllowedWeapons = Utilities.GetMaxAllowedWeaponCountForHeadshots(selectedPilot); bool validWeaponCountForPrecisionStrike = enabledWeaponCount <= maxAllowedWeapons ? true : false; bool headCanBeTargeted = __instance.HUD.SelectedTarget.IsShutDown || __instance.HUD.SelectedTarget.IsProne || validWeaponCountForPrecisionStrike; Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] __instance.HUD.SelectedActor: " + __instance.HUD.SelectedActor.DisplayName); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] enabledWeaponCount: " + enabledWeaponCount); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] validWeaponCountForPrecisionStrike: " + validWeaponCountForPrecisionStrike); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] ___displayedMech: " + ___displayedMech.DisplayName); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] ___displayedMech.IsShutDown: " + ___displayedMech.IsShutDown); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] ___displayedMech.IsProne: " + ___displayedMech.IsProne); Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] headCanBeTargeted: " + headCanBeTargeted); if (!headCanBeTargeted) { Logger.Debug("[HUDMechArmorReadout_SetHoveredArmor_POSTFIX] Prevent targeting of head..."); __instance.ClearHoveredArmor(ArmorLocation.Head); } } } catch (Exception e) { Logger.Error(e); } }
public static void ShowStructureDamageThroughArmour(HUDMechArmorReadout __instance) { try { HUDMechArmorReadout me = __instance; Mech mech = me.DisplayedMech; MechDef mechDef = mech?.MechDef ?? me.DisplayedMechDef; if (mech == null && mechDef == null) { return; } ChassisLocations[] location = me.flipFrontDisplay ? Flipped : Normal; int[] back = me.flipFrontDisplay != me.flipRearDisplay ? new int[] { 0, 0, 4, 3, 2 } : new int[] { 0, 0, 2, 3, 4 }; Color clear = Color.clear; Color[] armor = (Color[])armorProp.GetValue(me, null); Color[] armorRear = (Color[])armorRearProp.GetValue(me, null); Color[] outline = null, outlineRear = null, structure = null, structureRear = null; for (int i = 0; i < 8; i++) { float percent = float.NaN; // Front if (armor[i] != clear) // Skip check on armour-less locations { if (IsStructureDamaged(ref percent, mech, mechDef, location[i])) { if (structure == null) // Lazy reflection access { structure = (Color[])structureProp.GetValue(me, null); outline = (Color[])outlineProp.GetValue(me, null); } outline[i] = structure[i] = armor[i]; if (me.UseForCalledShots) { armor[i] = clear; } else { armor[i].a *= 0.5f; // Front has structure over armor, but structure has more blank to fill. } } } // Back if (i < 2 || i > 4) { continue; } int j = back[i]; if (armorRear[j] != clear) { if (IsStructureDamaged(ref percent, mech, mechDef, location[i])) // i is not typo. We want to check same chassis location as front. { if (structureRear == null) { structureRear = (Color[])structureRearProp.GetValue(me, null); outlineRear = (Color[])outlineRearProp.GetValue(me, null); } outlineRear[j] = structureRear[j] = armorRear[j]; armorRear[j] = clear; } } } } catch (Exception ex) { Error(ex); } }
public static void Postfix(HUDMechArmorReadout __instance) { __instance.flipFrontDisplay = false; __instance.flipRearDisplay = false; }