using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using InfoOverhaul.Compat;
using InfoOverhaul.Delta;
using InfoOverhaul.Stats;
using InfoOverhaul.UI;
using Microsoft.CodeAnalysis;
using TMPro;
using UnboundLib.GameModes;
using UnboundLib.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyCompany("InfoOverhaul")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+661a91535814621160b5d94d61679bade4fe1c2d")]
[assembly: AssemblyProduct("Info Overhaul")]
[assembly: AssemblyTitle("InfoOverhaul")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace InfoOverhaul
{
internal static class IOLog
{
private static ManualLogSource _logger;
internal static void Init(ManualLogSource logger)
{
_logger = logger;
}
internal static void Section(string title)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogInfo((object)("── " + title + " ──"));
}
}
internal static void Line(string message)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogInfo((object)message);
}
}
internal static void Warn(string message)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogWarning((object)message);
}
}
internal static void Error(string message)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogError((object)message);
}
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("InfoOverhaul", "Info Overhaul", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
private void Awake()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
IOLog.Init(Logger);
IOLog.Section("Plugin Awake");
new Harmony("InfoOverhaul").PatchAll();
StatTemplateDeltaRegistrar.Init();
MfmTier2Compat.Init();
((Component)this).gameObject.AddComponent<PickStatsController>();
((Component)this).gameObject.AddComponent<CardDeltaPreviewOverlay>();
IOLog.Line("Plugin InfoOverhaul loaded.");
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "InfoOverhaul";
public const string PLUGIN_NAME = "Info Overhaul";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace InfoOverhaul.UI
{
public class CardDeltaPreviewOverlay : MonoBehaviour
{
[CompilerGenerated]
private sealed class <OnPickSequenceEnd>d__19 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public CardDeltaPreviewOverlay <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPickSequenceEnd>d__19(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
int num = <>1__state;
CardDeltaPreviewOverlay cardDeltaPreviewOverlay = <>4__this;
if (num != 0)
{
return false;
}
<>1__state = -1;
cardDeltaPreviewOverlay.OnPickSequenceEnded();
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public static CardDeltaPreviewOverlay instance;
private static readonly FieldInfo SpawnedCardsField = AccessTools.Field(typeof(CardChoice), "spawnedCards");
private static readonly FieldInfo SelectedCardField = AccessTools.Field(typeof(CardChoice), "currentlySelectedCard");
private const int RowsPerCol = 3;
private const int MaxCols = 5;
private Canvas _canvas;
private TextMeshProUGUI _headerText;
private TextMeshProUGUI[] _colTexts;
private bool _pickSequenceActive;
private void Awake()
{
instance = this;
BuildUI();
GameModeManager.AddHook("PickEnd", (Func<IGameModeHandler, IEnumerator>)OnPickSequenceEnd);
IOLog.Section("CardDeltaPreviewOverlay initialized");
}
private void BuildUI()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
_canvas = UIHelper.CreateFullscreenCanvas("IO_CardDeltaPreview", 55);
Transform transform = ((Component)_canvas).transform;
Vector2 anchorMin = new Vector2(0.18f, 0.085f);
Vector2 anchorMax = new Vector2(0.82f, 0.22f);
Color? bg = new Color(0.04f, 0.06f, 0.1f, 0.92f);
RectTransform parent = UIHelper.CreatePanel(transform, "DeltaPanel", anchorMin, anchorMax, default(Vector2), default(Vector2), bg);
RectTransform parent2 = UIHelper.CreatePanel((Transform)(object)parent, "Header", new Vector2(0.01f, 0.72f), new Vector2(0.99f, 0.98f));
_headerText = UIHelper.CreateText((Transform)(object)parent2, "HeaderText", "Card preview", 20, (TextAlignmentOptions)4097, (Color?)new Color(0.75f, 0.85f, 1f));
_colTexts = (TextMeshProUGUI[])(object)new TextMeshProUGUI[5];
float num = 0.2f;
for (int i = 0; i < 5; i++)
{
float num2 = (float)i * num + 0.01f;
float num3 = (float)(i + 1) * num - 0.01f;
RectTransform parent3 = UIHelper.CreatePanel((Transform)(object)parent, $"Col{i}", new Vector2(num2, 0.02f), new Vector2(num3, 0.7f));
_colTexts[i] = UIHelper.CreateText((Transform)(object)parent3, "Text", string.Empty, 17, (TextAlignmentOptions)257, (Color?)new Color(0.92f, 0.94f, 1f));
((TMP_Text)_colTexts[i]).richText = true;
}
((Component)_canvas).gameObject.SetActive(false);
}
public void OnPickSequenceStarted()
{
if ((Object)(object)GetLocalHumanPlayer() == (Object)null)
{
SetVisible(visible: false);
return;
}
_pickSequenceActive = true;
SetVisible(visible: true);
Refresh();
}
public void OnPickSequenceEnded()
{
_pickSequenceActive = false;
SetVisible(visible: false);
}
private void Update()
{
if (_pickSequenceActive && !((Object)(object)_canvas == (Object)null) && ((Component)_canvas).gameObject.activeSelf)
{
Refresh();
}
}
private void Refresh()
{
Player localHumanPlayer = GetLocalHumanPlayer();
if ((Object)(object)localHumanPlayer == (Object)null)
{
SetVisible(visible: false);
return;
}
if (!TryGetHighlightedCard(out var card))
{
((TMP_Text)_headerText).text = "Card preview";
SetColumns(null);
((TMP_Text)_colTexts[0]).text = "—";
return;
}
((TMP_Text)_headerText).text = "If " + card.cardName + ":";
if (!CardDeltaRegistry.TryGetDeltas(localHumanPlayer, card, out var deltas))
{
SetColumns(null);
((TMP_Text)_colTexts[0]).text = "N/A";
}
else if (deltas.Count == 0)
{
SetColumns(null);
((TMP_Text)_colTexts[0]).text = "No stat changes";
}
else
{
SetColumns(deltas);
}
}
private void SetColumns(IReadOnlyList<StatDeltaLine> deltas)
{
if (deltas == null)
{
for (int i = 0; i < 5; i++)
{
((TMP_Text)_colTexts[i]).text = string.Empty;
((Component)_colTexts[i]).gameObject.SetActive(i == 0);
}
return;
}
int num = Mathf.Clamp(Mathf.CeilToInt((float)deltas.Count / 3f), 1, 5);
for (int j = 0; j < 5; j++)
{
bool flag = j < num;
((Component)_colTexts[j]).gameObject.SetActive(flag);
if (!flag)
{
continue;
}
StringBuilder stringBuilder = new StringBuilder();
int num2 = j * 3;
int num3 = Mathf.Min(num2 + 3, deltas.Count);
for (int k = num2; k < num3; k++)
{
if (k > num2)
{
stringBuilder.AppendLine();
}
stringBuilder.Append(deltas[k].FormatRichText());
}
((TMP_Text)_colTexts[j]).text = stringBuilder.ToString();
}
}
private static bool TryGetHighlightedCard(out CardInfo card)
{
card = null;
CardChoice val = CardChoice.instance;
if ((Object)(object)val == (Object)null || !val.IsPicking || SpawnedCardsField == null || SelectedCardField == null)
{
return false;
}
if (!(SpawnedCardsField.GetValue(val) is List<GameObject> list) || list.Count == 0)
{
return false;
}
int num = (int)SelectedCardField.GetValue(val);
num = Mathf.Clamp(num, 0, list.Count - 1);
GameObject val2 = list[num];
if ((Object)(object)val2 == (Object)null)
{
return false;
}
card = val2.GetComponent<CardInfo>();
if ((Object)(object)card == (Object)null)
{
card = val2.GetComponentInChildren<CardInfo>();
}
return (Object)(object)card != (Object)null;
}
private static Player GetLocalHumanPlayer()
{
if ((Object)(object)PlayerManager.instance == (Object)null)
{
return null;
}
foreach (Player player in PlayerManager.instance.players)
{
if ((Object)(object)player == (Object)null)
{
continue;
}
PlayerAPI component = ((Component)player).GetComponent<PlayerAPI>();
if (component == null || !((Behaviour)component).enabled)
{
object value = AccessTools.Field(typeof(CharacterData), "view").GetValue(player.data);
if (value == null)
{
return player;
}
if ((bool)AccessTools.Property(value.GetType(), "IsMine").GetValue(value, null))
{
return player;
}
}
}
return null;
}
private void SetVisible(bool visible)
{
if ((Object)(object)_canvas != (Object)null)
{
((Component)_canvas).gameObject.SetActive(visible);
}
}
[IteratorStateMachine(typeof(<OnPickSequenceEnd>d__19))]
private IEnumerator OnPickSequenceEnd(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPickSequenceEnd>d__19(0)
{
<>4__this = this
};
}
}
public class PickStatsController : MonoBehaviour
{
[CompilerGenerated]
private sealed class <OnPickSequenceEnd>d__14 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public PickStatsController <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPickSequenceEnd>d__14(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
int num = <>1__state;
PickStatsController pickStatsController = <>4__this;
if (num != 0)
{
return false;
}
<>1__state = -1;
IOLog.Line("Pick sequence ended — auto-closing stats window.");
pickStatsController.EndPickPhase("HookPickEnd");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <OnPlayerPickEnd>d__13 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPlayerPickEnd>d__13(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
IOLog.Line($"Single player pick ended (picker={currentPickerID}); keeping stats UI up until pick sequence ends.");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public static PickStatsController instance;
public static bool isPickPhase;
public static int currentPickerID = -1;
private Canvas _canvas;
private StatsPopup _popup;
private GameObject _showStatsBtnGo;
private void Awake()
{
instance = this;
BuildUI();
GameModeManager.AddHook("PlayerPickEnd", (Func<IGameModeHandler, IEnumerator>)OnPlayerPickEnd);
GameModeManager.AddHook("PickEnd", (Func<IGameModeHandler, IEnumerator>)OnPickSequenceEnd);
IOLog.Section("PickStatsController initialized");
}
private void BuildUI()
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
_canvas = UIHelper.CreateFullscreenCanvas("IO_PickStatsCanvas", 160);
RectTransform component = ((Component)_canvas).GetComponent<RectTransform>();
Button val = UIHelper.AnchorButton(component, "ShowStatsBtn", "Show Stats", new Vector2(0.02f, 0.02f), new Vector2(0.16f, 0.08f), new Color(0.18f, 0.35f, 0.55f, 1f), 24);
((UnityEvent)val.onClick).AddListener(new UnityAction(TogglePopup));
_showStatsBtnGo = ((Component)val).gameObject;
_popup = StatsPopup.Create((Transform)(object)component);
((Component)_canvas).gameObject.SetActive(false);
}
public void BeginPickPhase(int pickerID, string source)
{
if (pickerID >= 0)
{
if ((Object)(object)GetLocalHumanPlayer() == (Object)null)
{
HideAll();
IOLog.Line($"Pick phase for player {pickerID} (source={source}) — no local human, UI hidden.");
return;
}
currentPickerID = pickerID;
isPickPhase = true;
((Component)_canvas).gameObject.SetActive(true);
_showStatsBtnGo.SetActive(true);
CardDeltaPreviewOverlay.instance?.OnPickSequenceStarted();
IOLog.Line($"Pick phase active — picker={pickerID}, showing local stats (source={source}).");
}
}
public void EndPickPhase(string source)
{
IOLog.Line($"Pick phase ended (source={source}), was picker={currentPickerID}");
isPickPhase = false;
currentPickerID = -1;
CardDeltaPreviewOverlay.instance?.OnPickSequenceEnded();
HideAll();
}
private void HideAll()
{
_popup?.Hide();
if ((Object)(object)_canvas != (Object)null)
{
((Component)_canvas).gameObject.SetActive(false);
}
}
private void TogglePopup()
{
Player localHumanPlayer = GetLocalHumanPlayer();
if (!((Object)(object)localHumanPlayer == (Object)null))
{
if (_popup.IsVisible)
{
_popup.Hide();
}
else
{
_popup.Show(localHumanPlayer);
}
}
}
private static Player GetLocalHumanPlayer()
{
if ((Object)(object)PlayerManager.instance == (Object)null)
{
return null;
}
foreach (Player player in PlayerManager.instance.players)
{
if ((Object)(object)player == (Object)null)
{
continue;
}
PlayerAPI component = ((Component)player).GetComponent<PlayerAPI>();
if (component == null || !((Behaviour)component).enabled)
{
object value = AccessTools.Field(typeof(CharacterData), "view").GetValue(player.data);
if (value == null)
{
return player;
}
if ((bool)AccessTools.Property(value.GetType(), "IsMine").GetValue(value, null))
{
return player;
}
}
}
return null;
}
[IteratorStateMachine(typeof(<OnPlayerPickEnd>d__13))]
private IEnumerator OnPlayerPickEnd(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPlayerPickEnd>d__13(0);
}
[IteratorStateMachine(typeof(<OnPickSequenceEnd>d__14))]
private IEnumerator OnPickSequenceEnd(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPickSequenceEnd>d__14(0)
{
<>4__this = this
};
}
}
internal class StatsPopup : MonoBehaviour
{
private readonly List<TextMeshProUGUI> _leftLines = new List<TextMeshProUGUI>();
private readonly List<TextMeshProUGUI> _rightLines = new List<TextMeshProUGUI>();
private RectTransform _root;
private Player _player;
public bool IsVisible => ((Component)this).gameObject.activeSelf;
public static StatsPopup Create(Transform parent)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("IO_StatsPopup");
val.transform.SetParent(parent, false);
StatsPopup statsPopup = val.AddComponent<StatsPopup>();
statsPopup.Build();
val.SetActive(false);
return statsPopup;
}
private void Build()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Expected O, but got Unknown
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_0206: Unknown result type (might be due to invalid IL or missing references)
//IL_0225: Unknown result type (might be due to invalid IL or missing references)
//IL_0234: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
//IL_026e: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
//IL_027b: Unknown result type (might be due to invalid IL or missing references)
//IL_027e: Unknown result type (might be due to invalid IL or missing references)
//IL_0284: Unknown result type (might be due to invalid IL or missing references)
_root = ((Component)this).gameObject.AddComponent<RectTransform>();
_root.anchorMin = Vector2.zero;
_root.anchorMax = Vector2.one;
RectTransform root = _root;
Vector2 offsetMin = (_root.offsetMax = Vector2.zero);
root.offsetMin = offsetMin;
GameObject val = new GameObject("Backdrop");
val.transform.SetParent(((Component)this).transform, false);
RectTransform obj = val.AddComponent<RectTransform>();
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
offsetMin = (obj.offsetMax = Vector2.zero);
obj.offsetMin = offsetMin;
((Graphic)val.AddComponent<Image>()).color = new Color(0.02f, 0.02f, 0.05f, 1f);
Transform transform = ((Component)this).transform;
Vector2 anchorMin = new Vector2(0.12f, 0.08f);
Vector2 anchorMax = new Vector2(0.88f, 0.92f);
Color? bg = new Color(0.08f, 0.09f, 0.14f, 1f);
RectTransform parent = UIHelper.CreatePanel(transform, "Panel", anchorMin, anchorMax, default(Vector2), default(Vector2), bg);
UIHelper.CreateText((Transform)(object)UIHelper.CreatePanel((Transform)(object)parent, "Title", new Vector2(0f, 0.9f), Vector2.one), "TitleText", "Player Stats", 36, (TextAlignmentOptions)514);
((UnityEvent)UIHelper.AnchorButton(parent, "CloseBtn", "Close", new Vector2(0.82f, 0.91f), new Vector2(0.98f, 0.99f), new Color(0.45f, 0.12f, 0.12f), 22).onClick).AddListener(new UnityAction(Hide));
RectTransform parent2 = UIHelper.CreatePanel((Transform)(object)parent, "Columns", new Vector2(0.04f, 0.04f), new Vector2(0.96f, 0.88f));
RectTransform parent3 = UIHelper.CreatePanel((Transform)(object)parent2, "LeftColumn", new Vector2(0f, 0f), new Vector2(0.48f, 1f));
RectTransform parent4 = UIHelper.CreatePanel((Transform)(object)parent2, "RightColumn", new Vector2(0.52f, 0f), Vector2.one);
BuildColumn(parent3, _leftLines, 12);
BuildColumn(parent4, _rightLines, 12);
}
private static void BuildColumn(RectTransform parent, List<TextMeshProUGUI> sink, int lineCount)
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
float num = 1f / (float)lineCount;
for (int i = 0; i < lineCount; i++)
{
float num2 = 1f - (float)i * num;
float num3 = num2 - num;
TextMeshProUGUI item = UIHelper.CreateText((Transform)(object)UIHelper.CreatePanel((Transform)(object)parent, $"Line{i}", new Vector2(0f, num3), new Vector2(1f, num2)), "Text", "—", 22, (TextAlignmentOptions)4097, (Color?)new Color(0.92f, 0.94f, 1f));
sink.Add(item);
}
}
public void Show(Player player)
{
_player = player;
((Component)this).gameObject.SetActive(true);
Refresh();
}
public void Hide()
{
((Component)this).gameObject.SetActive(false);
_player = null;
}
private void Update()
{
if (IsVisible && !((Object)(object)_player == (Object)null))
{
Refresh();
}
}
private void Refresh()
{
List<StatsReader.StatLine> stats = StatsReader.Collect(_player);
ApplyColumn(_leftLines, stats, 0);
ApplyColumn(_rightLines, stats, _leftLines.Count);
}
private static void ApplyColumn(List<TextMeshProUGUI> labels, List<StatsReader.StatLine> stats, int offset)
{
for (int i = 0; i < labels.Count; i++)
{
int num = offset + i;
((TMP_Text)labels[i]).text = ((num < stats.Count) ? stats[num].Text : string.Empty);
}
}
}
internal static class UIHelper
{
public static Canvas CreateFullscreenCanvas(string name, int sortOrder = 100)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
Object.DontDestroyOnLoad((Object)val);
val.SetActive(false);
Canvas val2 = val.AddComponent<Canvas>();
val2.renderMode = (RenderMode)0;
val2.sortingOrder = sortOrder;
CanvasScaler obj = val.AddComponent<CanvasScaler>();
obj.uiScaleMode = (ScaleMode)1;
obj.referenceResolution = new Vector2(1920f, 1080f);
val.AddComponent<GraphicRaycaster>();
return val2;
}
public static RectTransform CreatePanel(Transform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin = default(Vector2), Vector2 offsetMax = default(Vector2), Color? bg = null)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
RectTransform obj = val.AddComponent<RectTransform>();
obj.anchorMin = anchorMin;
obj.anchorMax = anchorMax;
obj.offsetMin = offsetMin;
obj.offsetMax = offsetMax;
if (bg.HasValue)
{
((Graphic)val.AddComponent<Image>()).color = bg.Value;
}
return obj;
}
public static TextMeshProUGUI CreateText(Transform parent, string name, string text, int fontSize = 24, TextAlignmentOptions alignment = 514, Color? color = null)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
RectTransform obj = val.AddComponent<RectTransform>();
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
TextMeshProUGUI obj2 = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj2).text = text;
((TMP_Text)obj2).fontSize = fontSize;
((TMP_Text)obj2).alignment = alignment;
((Graphic)obj2).color = (Color)(((??)color) ?? Color.white);
return obj2;
}
public static Button AnchorButton(RectTransform parent, string name, string label, Vector2 anchorMin, Vector2 anchorMax, Color bgColor, int fontSize)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
val.transform.SetParent((Transform)(object)parent, false);
RectTransform obj = val.AddComponent<RectTransform>();
obj.anchorMin = anchorMin;
obj.anchorMax = anchorMax;
Vector2 offsetMin = (obj.offsetMax = Vector2.zero);
obj.offsetMin = offsetMin;
Image val2 = val.AddComponent<Image>();
((Graphic)val2).color = bgColor;
Button obj2 = val.AddComponent<Button>();
((Selectable)obj2).targetGraphic = (Graphic)(object)val2;
ColorBlock val3 = default(ColorBlock);
((ColorBlock)(ref val3)).normalColor = bgColor;
((ColorBlock)(ref val3)).highlightedColor = bgColor * 1.3f;
((ColorBlock)(ref val3)).pressedColor = bgColor * 0.7f;
((ColorBlock)(ref val3)).disabledColor = new Color(0.25f, 0.25f, 0.25f, 0.6f);
((ColorBlock)(ref val3)).colorMultiplier = 1f;
((ColorBlock)(ref val3)).fadeDuration = 0.1f;
ColorBlock colors = val3;
((Selectable)obj2).colors = colors;
GameObject val4 = new GameObject("Label");
val4.transform.SetParent(val.transform, false);
RectTransform obj3 = val4.AddComponent<RectTransform>();
obj3.anchorMin = Vector2.zero;
obj3.anchorMax = Vector2.one;
offsetMin = (obj3.offsetMax = Vector2.zero);
obj3.offsetMin = offsetMin;
TextMeshProUGUI obj4 = val4.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj4).text = label;
((TMP_Text)obj4).fontSize = fontSize;
((TMP_Text)obj4).alignment = (TextAlignmentOptions)514;
((Graphic)obj4).color = Color.white;
return obj2;
}
}
}
namespace InfoOverhaul.Stats
{
internal static class PoisonResistanceStatsBridge
{
private static bool _resolved;
private static PropertyInfo _instanceProp;
private static MethodInfo _getPercent;
public static bool IsAvailable
{
get
{
Resolve();
if (_instanceProp != null)
{
return _getPercent != null;
}
return false;
}
}
private static void Resolve()
{
if (_resolved)
{
return;
}
_resolved = true;
try
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ShieldsMod");
if (!(assembly == null))
{
Type type = assembly.GetType("ShieldsMod.Poison.PoisonResistanceManager");
if (!(type == null))
{
_instanceProp = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
_getPercent = type.GetMethod("GetReductionPercent", BindingFlags.Instance | BindingFlags.Public);
}
}
}
catch (Exception ex)
{
IOLog.Warn("PoisonResistanceStatsBridge resolve failed: " + ex.Message);
}
}
public static bool TryGetPercent(int playerID, out float percent)
{
percent = 0f;
Resolve();
if (_instanceProp == null || _getPercent == null)
{
return false;
}
try
{
object value = _instanceProp.GetValue(null);
if (value == null)
{
return false;
}
percent = (float)_getPercent.Invoke(value, new object[1] { playerID });
return true;
}
catch (Exception ex)
{
IOLog.Warn("TryGetPercent failed: " + ex.Message);
return false;
}
}
}
internal static class ShieldStatsBridge
{
private static bool _resolved;
private static PropertyInfo _instanceProp;
private static MethodInfo _getShield;
private static FieldInfo _currentField;
private static FieldInfo _maxField;
public static bool IsAvailable
{
get
{
Resolve();
if (_instanceProp != null)
{
return _getShield != null;
}
return false;
}
}
private static void Resolve()
{
if (_resolved)
{
return;
}
_resolved = true;
try
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ShieldsMod");
if (assembly == null)
{
IOLog.Line("ShieldsMod not loaded — Shield Health will show as N/A.");
return;
}
Type type = assembly.GetType("ShieldsMod.Shield.ShieldManager");
Type type2 = assembly.GetType("ShieldsMod.Shield.ShieldState");
if (type == null || type2 == null)
{
IOLog.Warn("ShieldsMod shield types not found.");
return;
}
_instanceProp = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public);
_getShield = type.GetMethod("GetShield", BindingFlags.Instance | BindingFlags.Public);
_currentField = type2.GetField("Current", BindingFlags.Instance | BindingFlags.Public);
_maxField = type2.GetField("Max", BindingFlags.Instance | BindingFlags.Public);
if (_instanceProp == null || _getShield == null || _currentField == null || _maxField == null)
{
IOLog.Warn("ShieldsMod shield API incomplete.");
}
}
catch (Exception ex)
{
IOLog.Error("ShieldStatsBridge resolve failed: " + ex.Message);
}
}
public static bool TryGetShieldHealth(int playerID, out float current, out float max)
{
current = 0f;
max = 0f;
Resolve();
if (_instanceProp == null || _getShield == null)
{
return false;
}
try
{
object value = _instanceProp.GetValue(null);
if (value == null)
{
return false;
}
object obj = _getShield.Invoke(value, new object[1] { playerID });
if (obj == null)
{
return false;
}
current = (float)_currentField.GetValue(obj);
max = (float)_maxField.GetValue(obj);
return true;
}
catch (Exception ex)
{
IOLog.Warn("TryGetShieldHealth failed: " + ex.Message);
return false;
}
}
}
internal static class StatsReader
{
internal readonly struct StatLine
{
public readonly string Text;
public StatLine(string text)
{
Text = text;
}
}
public static List<StatLine> Collect(Player player)
{
List<StatLine> list = new List<StatLine>(24);
if ((Object)(object)player == (Object)null)
{
return list;
}
Gun val = player.data?.weaponHandler?.gun;
Block val2 = player.data?.block;
list.Add(new StatLine($"HP: {player.data.health:f0} / {player.data.maxHealth:f0}"));
list.Add(new StatLine($"Lives: {player.data.stats.respawns + 1:f0}"));
list.Add(new StatLine(((Object)(object)val2 != (Object)null) ? $"Block CD: {val2.Cooldown():f2}s" : "Block CD: —"));
list.Add(new StatLine(((Object)(object)val2 != (Object)null) ? $"Block Count: {val2.additionalBlocks + 1:f0}" : "Block Count: —"));
list.Add(new StatLine(FormatShieldHealth(player.playerID)));
list.Add(new StatLine(FormatPoisonResistance(player.playerID)));
if ((Object)(object)val != (Object)null)
{
list.Add(new StatLine($"DMG: {val.damage * 55f * val.bulletDamageMultiplier:f0}"));
list.Add(new StatLine($"Knockback: {val.knockback:f2}"));
list.Add(new StatLine($"Life Steal: {player.data.stats.lifeSteal:f2}"));
list.Add(new StatLine($"Damage Grow: {val.damageAfterDistanceMultiplier:f2}"));
list.Add(new StatLine($"Bullet Slow: {val.slow:f2}"));
list.Add(new StatLine($"Move SPD: {player.data.stats.movementSpeed:f2}"));
list.Add(new StatLine($"Jump Height: {player.data.stats.jump:f2}"));
list.Add(new StatLine($"Player Size: {player.data.stats.sizeMultiplier:f2}"));
list.Add(new StatLine($"Attack SPD: {val.attackSpeed * val.attackSpeedMultiplier:f2}s"));
list.Add(new StatLine($"Bullet SPD: {val.projectileSpeed:f2}"));
list.Add(new StatLine($"Projectile SPD: {val.projectielSimulatonSpeed:f2}"));
GunAmmo componentInChildren = ((Component)val).GetComponentInChildren<GunAmmo>();
if ((Object)(object)componentInChildren != (Object)null)
{
float num = (componentInChildren.reloadTime + componentInChildren.reloadTimeAdd) * componentInChildren.reloadTimeMultiplier;
list.Add(new StatLine($"Reload Time: {num:f2}s"));
list.Add(new StatLine($"Ammo: {componentInChildren.maxAmmo:f0}"));
}
else
{
list.Add(new StatLine("Reload Time: —"));
list.Add(new StatLine("Ammo: —"));
}
list.Add(new StatLine($"Bullet Gravity: {val.gravity:f2}"));
list.Add(new StatLine($"Bullets: {val.numberOfProjectiles:f0}"));
list.Add(new StatLine($"Bullet Range: {val.destroyBulletAfter:f2}"));
list.Add(new StatLine($"Bounces: {val.reflects:f0}"));
list.Add(new StatLine($"Bursts: {val.bursts:f0}"));
}
else
{
list.Add(new StatLine("DMG: —"));
list.Add(new StatLine("Knockback: —"));
list.Add(new StatLine($"Life Steal: {player.data.stats.lifeSteal:f2}"));
list.Add(new StatLine("Damage Grow: —"));
list.Add(new StatLine("Bullet Slow: —"));
list.Add(new StatLine($"Move SPD: {player.data.stats.movementSpeed:f2}"));
list.Add(new StatLine($"Jump Height: {player.data.stats.jump:f2}"));
list.Add(new StatLine($"Player Size: {player.data.stats.sizeMultiplier:f2}"));
list.Add(new StatLine("Attack SPD: —"));
list.Add(new StatLine("Bullet SPD: —"));
list.Add(new StatLine("Projectile SPD: —"));
list.Add(new StatLine("Reload Time: —"));
list.Add(new StatLine("Ammo: —"));
list.Add(new StatLine("Bullet Gravity: —"));
list.Add(new StatLine("Bullets: —"));
list.Add(new StatLine("Bullet Range: —"));
list.Add(new StatLine("Bounces: —"));
list.Add(new StatLine("Bursts: —"));
}
return list;
}
private static string FormatShieldHealth(int playerID)
{
if (ShieldStatsBridge.TryGetShieldHealth(playerID, out var current, out var max))
{
return $"Shield Health: {current:f0} / {max:f0}";
}
if (!ShieldStatsBridge.IsAvailable)
{
return "Shield Health: N/A";
}
return "Shield Health: — / —";
}
private static string FormatPoisonResistance(int playerID)
{
if (PoisonResistanceStatsBridge.TryGetPercent(playerID, out var percent))
{
return $"Poison Resistance: {percent:f0}%";
}
if (!PoisonResistanceStatsBridge.IsAvailable)
{
return "Poison Resistance: N/A";
}
return "Poison Resistance: 0%";
}
}
}
namespace InfoOverhaul.Patches
{
[HarmonyPatch]
internal static class PickPhasePatches
{
[HarmonyPatch(typeof(CardChoiceVisuals), "Show")]
[HarmonyPrefix]
private static void CardChoiceVisuals_Show_Prefix(int pickerID, bool animateIn)
{
PickStatsController.instance?.BeginPickPhase(pickerID, "CardChoiceVisuals.Show");
}
[HarmonyPatch(typeof(CardChoice), "StartPick")]
[HarmonyPostfix]
private static void CardChoice_StartPick_Postfix(int picksToSet, int pickerIDToSet)
{
PickStatsController.instance?.BeginPickPhase(pickerIDToSet, "CardChoice.StartPick");
}
}
}
namespace InfoOverhaul.Delta
{
public static class CardDeltaRegistry
{
public delegate IReadOnlyList<StatDeltaLine> DeltaProvider(Player player, CardInfo card);
public delegate IReadOnlyList<(string label, string before, string after)> SimpleDeltaProvider(Player player, CardInfo card);
private static readonly Dictionary<string, DeltaProvider> Providers = new Dictionary<string, DeltaProvider>(StringComparer.Ordinal);
private static readonly Dictionary<string, List<DeltaProvider>> Addons = new Dictionary<string, List<DeltaProvider>>(StringComparer.Ordinal);
public static void RegisterSimple(string cardName, SimpleDeltaProvider provider)
{
Register(cardName, (Player player, CardInfo card) => ToLines(provider(player, card)));
}
public static void Register(string cardName, DeltaProvider provider)
{
if (!string.IsNullOrEmpty(cardName) && provider != null)
{
Providers[cardName] = provider;
IOLog.Line("CardDeltaRegistry — registered '" + cardName + "'.");
}
}
public static void RegisterAddon(string cardName, DeltaProvider addon)
{
if (!string.IsNullOrEmpty(cardName) && addon != null)
{
if (!Addons.TryGetValue(cardName, out var value))
{
value = new List<DeltaProvider>();
Addons[cardName] = value;
}
value.Add(addon);
IOLog.Line("CardDeltaRegistry — addon registered for '" + cardName + "'.");
}
}
public static void RegisterAddonSimple(string cardName, SimpleDeltaProvider addon)
{
RegisterAddon(cardName, (Player player, CardInfo card) => ToLines(addon(player, card)));
}
public static bool IsRegistered(string cardName)
{
if (!string.IsNullOrEmpty(cardName))
{
if (!Providers.ContainsKey(cardName))
{
if (Addons.TryGetValue(cardName, out var value))
{
return value.Count > 0;
}
return false;
}
return true;
}
return false;
}
public static bool TryGetDeltas(Player player, CardInfo card, out IReadOnlyList<StatDeltaLine> deltas)
{
deltas = null;
if ((Object)(object)player == (Object)null || (Object)(object)card == (Object)null)
{
return false;
}
string text = ResolveCardName(card);
if (string.IsNullOrEmpty(text))
{
return false;
}
DeltaProvider value;
bool flag = Providers.TryGetValue(text, out value);
List<DeltaProvider> value2;
bool flag2 = Addons.TryGetValue(text, out value2) && value2.Count > 0;
if (!flag && !flag2)
{
return false;
}
List<StatDeltaLine> list = new List<StatDeltaLine>();
if (flag)
{
list.AddRange(value(player, card) ?? Array.Empty<StatDeltaLine>());
}
if (flag2)
{
foreach (DeltaProvider item in value2)
{
list.AddRange(item(player, card) ?? Array.Empty<StatDeltaLine>());
}
}
deltas = list;
return true;
}
internal static string ResolveCardName(CardInfo card)
{
if (!string.IsNullOrEmpty(card.cardName))
{
return card.cardName;
}
if (!((Object)(object)card.sourceCard != (Object)null))
{
return null;
}
return card.sourceCard.cardName;
}
private static IReadOnlyList<StatDeltaLine> ToLines(IReadOnlyList<(string label, string before, string after)> tuples)
{
if (tuples == null || tuples.Count == 0)
{
return Array.Empty<StatDeltaLine>();
}
return tuples.Select(((string label, string before, string after) t) => (string.IsNullOrEmpty(t.before) && string.IsNullOrEmpty(t.after)) ? StatDeltaLine.Note(t.label) : new StatDeltaLine(t.label, t.before, t.after)).ToList();
}
}
public static class CardDeltaTier2
{
public static void RegisterEffectNotes(string cardName, params string[] notes)
{
if (notes != null && notes.Length != 0)
{
CardDeltaRegistry.RegisterAddon(cardName, (Player _, CardInfo __) => notes.Select(StatDeltaLine.Note).ToList());
}
}
public static void RegisterEffectNotes(string cardName, Func<Player, CardInfo, IReadOnlyList<string>> notes)
{
if (notes != null)
{
CardDeltaRegistry.RegisterAddon(cardName, (Player player, CardInfo card) => (notes(player, card) ?? Array.Empty<string>()).Select(StatDeltaLine.Note).ToList());
}
}
public static void RegisterOverrideSimple(string cardName, CardDeltaRegistry.SimpleDeltaProvider provider)
{
CardDeltaRegistry.RegisterSimple(cardName, provider);
}
}
public readonly struct StatDeltaLine
{
private const string IncreaseColor = "#66FF88";
private const string DecreaseColor = "#FF6666";
private const string NeutralColor = "#EBF0FF";
public readonly string Label;
public readonly string Before;
public readonly string After;
public readonly bool IsNote;
public StatDeltaLine(string label, string before, string after, bool isNote = false)
{
Label = label;
Before = before;
After = after;
IsNote = isNote;
}
public static StatDeltaLine Note(string text)
{
return new StatDeltaLine(text, null, null, isNote: true);
}
public string Format()
{
if (!IsNote)
{
return Label + ": " + Before + " --> " + After;
}
return Label;
}
public string FormatRichText()
{
if (IsNote)
{
return Label;
}
if (!TryParseStatValue(Before, out var value) || !TryParseStatValue(After, out var value2))
{
return Format();
}
string text = ((value2 > value) ? "#66FF88" : ((value2 < value) ? "#FF6666" : "#EBF0FF"));
return Label + ": " + Before + " --> <color=" + text + ">" + After + "</color>";
}
private static bool TryParseStatValue(string text, out float value)
{
value = 0f;
if (string.IsNullOrEmpty(text))
{
return false;
}
int i;
for (i = 0; i < text.Length && (char.IsDigit(text[i]) || text[i] == '.' || text[i] == '-'); i++)
{
}
if (i == 0)
{
return false;
}
return float.TryParse(text.Substring(0, i), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
}
}
internal static class StatTemplateDeltaProvider
{
private const float Epsilon = 0.0001f;
public static IReadOnlyList<StatDeltaLine> Compute(Player player, CardInfo card)
{
if ((Object)(object)player == (Object)null || (Object)(object)card == (Object)null)
{
return Array.Empty<StatDeltaLine>();
}
GameObject obj = (((Object)(object)card.sourceCard != (Object)null) ? ((Component)card.sourceCard).gameObject : ((Component)card).gameObject);
Gun component = obj.GetComponent<Gun>();
CharacterStatModifiers component2 = obj.GetComponent<CharacterStatModifiers>();
Block componentInChildren = obj.GetComponentInChildren<Block>();
if (!HasStatTemplate(component, component2, componentInChildren))
{
return Array.Empty<StatDeltaLine>();
}
Gun val = player.data?.weaponHandler?.gun;
Block val2 = player.data?.block;
CharacterData data = player.data;
CharacterStatModifiers component3 = ((Component)player).GetComponent<CharacterStatModifiers>();
GunAmmo val3 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<GunAmmo>() : null);
List<StatDeltaLine> list = new List<StatDeltaLine>();
if ((Object)(object)component2 != (Object)null && (Object)(object)data != (Object)null && (Object)(object)component3 != (Object)null)
{
TryAdd(list, "HP", data.maxHealth, data.maxHealth * component2.health, "f0");
TryAdd(list, "Lives", (float)component3.respawns + 1f, (float)(component3.respawns + component2.respawns) + 1f, "f0");
TryAdd(list, "Move SPD", component3.movementSpeed, component3.movementSpeed * component2.movementSpeed, "f2");
TryAdd(list, "Jump Height", component3.jump, component3.jump * component2.jump, "f2");
TryAdd(list, "Player Size", component3.sizeMultiplier, component3.sizeMultiplier * component2.sizeMultiplier, "f2");
TryAdd(list, "Life Steal", component3.lifeSteal, component3.lifeSteal + component2.lifeSteal, "f2");
}
if ((Object)(object)componentInChildren != (Object)null && (Object)(object)val2 != (Object)null)
{
float before = val2.Cooldown();
float after = (val2.cooldown + val2.cdAdd + componentInChildren.cdAdd) * (val2.cdMultiplier * componentInChildren.cdMultiplier);
TryAdd(list, "Block CD", before, after, "f2", "s");
TryAdd(list, "Block Count", (float)val2.additionalBlocks + 1f, (float)(val2.additionalBlocks + componentInChildren.additionalBlocks) + 1f, "f0");
}
if ((Object)(object)component != (Object)null && (Object)(object)val != (Object)null)
{
float before2 = val.damage * 55f * val.bulletDamageMultiplier;
float after2 = ApplyGunDamage(val.damage, val.numberOfProjectiles, component) * 55f * (val.bulletDamageMultiplier * component.bulletDamageMultiplier);
TryAdd(list, "DMG", before2, after2, "f0");
TryAdd(list, "Knockback", val.knockback, ApplyKnockback(val.knockback, val.numberOfProjectiles, component), "f2");
TryAdd(list, "Damage Grow", val.damageAfterDistanceMultiplier, val.damageAfterDistanceMultiplier * component.damageAfterDistanceMultiplier, "f2");
TryAdd(list, "Bullet Slow", val.slow, val.slow + component.slow, "f2");
TryAdd(list, "Attack SPD", val.attackSpeed * val.attackSpeedMultiplier, val.attackSpeed * component.attackSpeed * val.attackSpeedMultiplier, "f2", "s");
TryAdd(list, "Bullet SPD", val.projectileSpeed, val.projectileSpeed * component.projectileSpeed, "f2");
TryAdd(list, "Projectile SPD", val.projectielSimulatonSpeed, val.projectielSimulatonSpeed * component.projectielSimulatonSpeed, "f2");
TryAdd(list, "Bullet Gravity", val.gravity, val.gravity * component.gravity, "f2");
TryAdd(list, "Bullets", val.numberOfProjectiles, val.numberOfProjectiles + component.numberOfProjectiles, "f0");
TryAdd(list, "Bounces", val.reflects, val.reflects + component.reflects, "f0");
TryAdd(list, "Bursts", val.bursts, val.bursts + component.bursts, "f0");
if (component.destroyBulletAfter != 0f)
{
TryAdd(list, "Bullet Range", val.destroyBulletAfter, component.destroyBulletAfter, "f2");
}
else
{
TryAdd(list, "Bullet Range", val.destroyBulletAfter, val.destroyBulletAfter + component.destroyBulletAfter, "f2");
}
}
if ((Object)(object)component != (Object)null && (Object)(object)val3 != (Object)null)
{
float before3 = (val3.reloadTime + val3.reloadTimeAdd) * val3.reloadTimeMultiplier;
float after3 = (val3.reloadTime + val3.reloadTimeAdd + component.reloadTimeAdd) * (val3.reloadTimeMultiplier * component.reloadTime);
TryAdd(list, "Reload Time", before3, after3, "f2", "s");
TryAdd(list, "Ammo", val3.maxAmmo, Mathf.Clamp(val3.maxAmmo + component.ammo, 1, 90), "f0");
}
return list;
}
internal static bool HasStatTemplate(Gun cardGun, CharacterStatModifiers cardPlayer, Block cardBlock)
{
if ((Object)(object)cardGun != (Object)null && GunHasChanges(cardGun))
{
return true;
}
if ((Object)(object)cardPlayer != (Object)null && PlayerHasChanges(cardPlayer))
{
return true;
}
if ((Object)(object)cardBlock != (Object)null && BlockHasChanges(cardBlock))
{
return true;
}
return false;
}
private static bool GunHasChanges(Gun g)
{
if (Mathf.Approximately(g.damage, 1f) && Mathf.Approximately(g.bulletDamageMultiplier, 1f) && Mathf.Approximately(g.knockback, 1f) && Mathf.Approximately(g.attackSpeed, 1f) && Mathf.Approximately(g.projectileSpeed, 1f) && Mathf.Approximately(g.projectielSimulatonSpeed, 1f) && Mathf.Approximately(g.gravity, 1f) && Mathf.Approximately(g.damageAfterDistanceMultiplier, 1f) && Mathf.Approximately(g.reloadTime, 1f) && Mathf.Approximately(g.reloadTimeAdd, 0f) && g.ammo == 0 && g.numberOfProjectiles == 0 && g.reflects == 0 && g.bursts == 0 && g.slow == 0f)
{
return g.destroyBulletAfter != 0f;
}
return true;
}
private static bool PlayerHasChanges(CharacterStatModifiers s)
{
if (Mathf.Approximately(s.health, 1f) && Mathf.Approximately(s.movementSpeed, 1f) && Mathf.Approximately(s.jump, 1f) && Mathf.Approximately(s.sizeMultiplier, 1f) && s.respawns == 0)
{
return s.lifeSteal != 0f;
}
return true;
}
private static bool BlockHasChanges(Block b)
{
if (Mathf.Approximately(b.cdMultiplier, 1f) && b.cdAdd == 0f)
{
return b.additionalBlocks != 0;
}
return true;
}
private static float ProjectileBlendFactor(int cardProjectiles, int currentProjectiles)
{
if (cardProjectiles == 0 || currentProjectiles == 1)
{
return 1f;
}
return (float)cardProjectiles / (float)(cardProjectiles + currentProjectiles);
}
private static float ApplyGunDamage(float currentDamage, int currentProjectiles, Gun cardGun)
{
float num = ProjectileBlendFactor(cardGun.numberOfProjectiles, currentProjectiles);
return Mathf.Max(currentDamage * (1f - num * (1f - cardGun.damage)), 0.25f);
}
private static float ApplyKnockback(float currentKnockback, int currentProjectiles, Gun cardGun)
{
float num = ProjectileBlendFactor(cardGun.numberOfProjectiles, currentProjectiles);
return currentKnockback * (1f - num * (1f - cardGun.knockback));
}
private static void TryAdd(List<StatDeltaLine> lines, string label, float before, float after, string format, string suffix = "")
{
if (!(Mathf.Abs(before - after) < 0.0001f))
{
lines.Add(new StatDeltaLine(label, before.ToString(format) + suffix, after.ToString(format) + suffix));
}
}
}
internal static class StatTemplateDeltaRegistrar
{
internal static void Init()
{
CardManager.AddAllCardsCallback((Action<CardInfo[]>)RegisterAll);
IOLog.Line("StatTemplateDeltaRegistrar — waiting for CardManager.FirstTimeStart.");
}
private static void RegisterAll(CardInfo[] cards)
{
IOLog.Section("StatTemplateDeltaRegistrar — RegisterAll");
int num = 0;
int num2 = 0;
foreach (CardInfo val in cards)
{
if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.cardName))
{
continue;
}
if (CardDeltaRegistry.IsRegistered(val.cardName))
{
num2++;
continue;
}
GameObject obj = (((Object)(object)val.sourceCard != (Object)null) ? ((Component)val.sourceCard).gameObject : ((Component)val).gameObject);
Gun component = obj.GetComponent<Gun>();
CharacterStatModifiers component2 = obj.GetComponent<CharacterStatModifiers>();
Block componentInChildren = obj.GetComponentInChildren<Block>();
if (StatTemplateDeltaProvider.HasStatTemplate(component, component2, componentInChildren))
{
CardDeltaRegistry.Register(val.cardName, StatTemplateDeltaProvider.Compute);
num++;
}
}
IOLog.Line($"Registered {num} stat-template cards (skipped {num2} already registered).");
}
}
}
namespace InfoOverhaul.Compat
{
internal static class MfmTier2Compat
{
internal static void Init()
{
CardManager.AddAllCardsCallback((Action<CardInfo[]>)delegate
{
RegisterEffectNotes();
});
}
private static void RegisterEffectNotes()
{
IOLog.Section("MfmTier2Compat — RegisterEffectNotes");
IOLog.Line("MfmTier2Compat ready (no notes registered yet — add per card as validated).");
}
}
}