using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("headclef")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3+36c2f787465646b4db308667143f010a5173cca0")]
[assembly: AssemblyProduct("Improve")]
[assembly: AssemblyTitle("Improve")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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 Improve
{
[BepInPlugin("headclef.Improve", "Improve", "1.0.3")]
public class Improve : BaseUnityPlugin
{
private const string PluginGuid = "headclef.Improve";
private const string PluginName = "Improve";
private const string PluginVersion = "1.0.3";
internal static ConfigEntry<float> DifficultyMultiplier;
internal static ConfigEntry<int> BaseCost;
internal static Improve Instance { get; private set; }
internal static ManualLogSource Logger => Instance._logger;
private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;
internal Harmony? Harmony { get; set; }
private void Awake()
{
//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_005b: Expected O, but got Unknown
//IL_0060: Expected O, but got Unknown
Instance = this;
((Component)this).gameObject.transform.parent = null;
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
BindConfiguration();
SaveData.Initialize();
ImproveMenu.Initialize();
if (Harmony == null)
{
Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
Harmony val2 = val;
Harmony = val;
}
Harmony.PatchAll();
Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
}
private void OnDestroy()
{
Harmony? harmony = Harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
private void BindConfiguration()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
DifficultyMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Leveling", "Difficulty Multiplier", 0.5f, new ConfigDescription("Difficulty multiplier for level-up cost. Easy=0.25, Standard=0.5, Hard=0.75, Hardest=1.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
BaseCost = ((BaseUnityPlugin)this).Config.Bind<int>("Leveling", "Base Cost", 1000000, new ConfigDescription("Base haul cost for the first level-up. Cost doubles each level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100000, 10000000), Array.Empty<object>()));
}
}
public static class ImproveMenu
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static BuilderDelegate <>9__4_0;
public static BuilderDelegate <>9__4_1;
public static BuilderDelegate <>9__4_2;
public static Action <>9__8_3;
public static Action <>9__8_0;
public static Action <>9__8_4;
public static Action <>9__8_1;
public static Action <>9__8_2;
internal void <Initialize>b__4_0(Transform parent)
{
AddImproveButton(parent);
}
internal void <Initialize>b__4_1(Transform parent)
{
AddImproveButton(parent);
}
internal void <Initialize>b__4_2(Transform parent)
{
AddImproveButton(parent);
}
internal void <CreateStatsPage>b__8_0()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
MenuAPI.OpenPopup("Reset Stats", Color.yellow, "Reclaim all spent stat points? Your haul and level will be preserved.", (Action)delegate
{
SaveData.ResetStats();
_statsPage.ClosePage(true);
}, (Action)null);
}
internal void <CreateStatsPage>b__8_3()
{
SaveData.ResetStats();
_statsPage.ClosePage(true);
}
internal void <CreateStatsPage>b__8_1()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
MenuAPI.OpenPopup("Reset All", Color.red, "Wipe ALL progress including haul, level, and stat allocations? This cannot be undone!", (Action)delegate
{
SaveData.ResetAll();
_statsPage.ClosePage(true);
}, (Action)null);
}
internal void <CreateStatsPage>b__8_4()
{
SaveData.ResetAll();
_statsPage.ClosePage(true);
}
internal void <CreateStatsPage>b__8_2()
{
_statsPage.ClosePage(true);
}
}
[CompilerGenerated]
private sealed class <FixRepoButton>d__6 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public REPOButton btn;
public Transform parent;
private TextMeshProUGUI <tmp>5__1;
private RectTransform <parentRt>5__2;
private RectTransform <btnRt>5__3;
private RectTransform <textRt>5__4;
private float <marginRight>5__5;
private float <marginBottom>5__6;
private float <x>5__7;
private float <y>5__8;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <FixRepoButton>d__6(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<tmp>5__1 = null;
<parentRt>5__2 = null;
<btnRt>5__3 = null;
<textRt>5__4 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Expected O, but got Unknown
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: 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_01d9: Unknown result type (might be due to invalid IL or missing references)
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
{
<>1__state = -1;
Canvas.ForceUpdateCanvases();
<tmp>5__1 = ((Component)btn).GetComponentInChildren<TextMeshProUGUI>(true);
if ((Object)(object)<tmp>5__1 != (Object)null)
{
<btnRt>5__3 = ((REPOElement)btn).rectTransform;
<textRt>5__4 = (RectTransform)((TMP_Text)<tmp>5__1).transform;
((Transform)<textRt>5__4).SetParent((Transform)(object)<btnRt>5__3, false);
<textRt>5__4.anchorMin = Vector2.zero;
<textRt>5__4.anchorMax = Vector2.one;
<textRt>5__4.pivot = new Vector2(0.5f, 0.5f);
<textRt>5__4.offsetMin = new Vector2(14f, 6f);
<textRt>5__4.offsetMax = new Vector2(-14f, -6f);
((TMP_Text)<tmp>5__1).alignment = (TextAlignmentOptions)4614;
((TMP_Text)<tmp>5__1).enableWordWrapping = false;
<btnRt>5__3 = null;
<textRt>5__4 = null;
}
ref RectTransform reference = ref <parentRt>5__2;
Transform obj = parent;
reference = (RectTransform)(object)((obj is RectTransform) ? obj : null);
if ((Object)(object)<parentRt>5__2 != (Object)null)
{
<marginRight>5__5 = 40f;
<marginBottom>5__6 = 20f;
Rect rect = <parentRt>5__2.rect;
float width = ((Rect)(ref rect)).width;
rect = ((REPOElement)btn).rectTransform.rect;
<x>5__7 = width - ((Rect)(ref rect)).width - <marginRight>5__5;
<y>5__8 = <marginBottom>5__6;
((Transform)((REPOElement)btn).rectTransform).localPosition = new Vector3(<x>5__7, <y>5__8, 0f);
}
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();
}
}
private static REPOPopupPage _statsPage;
private static REPOPopupPage _skillsPage;
private static REPOLabel _availablePointsLabel;
private static REPOSlider[] _skillSliders;
internal static void Initialize()
{
//IL_0015: 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_0020: Expected O, but got Unknown
//IL_003a: 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)
//IL_0045: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
object obj = <>c.<>9__4_0;
if (obj == null)
{
BuilderDelegate val = delegate(Transform parent)
{
AddImproveButton(parent);
};
<>c.<>9__4_0 = val;
obj = (object)val;
}
MenuAPI.AddElementToMainMenu((BuilderDelegate)obj);
object obj2 = <>c.<>9__4_1;
if (obj2 == null)
{
BuilderDelegate val2 = delegate(Transform parent)
{
AddImproveButton(parent);
};
<>c.<>9__4_1 = val2;
obj2 = (object)val2;
}
MenuAPI.AddElementToEscapeMenu((BuilderDelegate)obj2);
object obj3 = <>c.<>9__4_2;
if (obj3 == null)
{
BuilderDelegate val3 = delegate(Transform parent)
{
AddImproveButton(parent);
};
<>c.<>9__4_2 = val3;
obj3 = (object)val3;
}
MenuAPI.AddElementToLobbyMenu((BuilderDelegate)obj3);
}
private static void AddImproveButton(Transform parent)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
REPOButton btn = MenuAPI.CreateREPOButton("Improve", (Action)OpenImproveMenu, parent, new Vector2(0f, 300f));
((MonoBehaviour)Improve.Instance).StartCoroutine(FixRepoButton(btn, parent));
}
[IteratorStateMachine(typeof(<FixRepoButton>d__6))]
private static IEnumerator FixRepoButton(REPOButton btn, Transform parent)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <FixRepoButton>d__6(0)
{
btn = btn,
parent = parent
};
}
private static void OpenImproveMenu()
{
((BaseUnityPlugin)Improve.Instance).Config.Reload();
CreateStatsPage();
CreateSkillsPage();
}
private static void CreateStatsPage()
{
//IL_008b: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: 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_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_022d: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_0297: Unknown result type (might be due to invalid IL or missing references)
//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0323: Unknown result type (might be due to invalid IL or missing references)
//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
_statsPage = MenuAPI.CreateREPOPopupPage("Improve - Progress", (PresetSide)0, false, true, 0f);
int num = SaveData.CurrentLevel();
int num2 = SaveData.AvailablePoints();
int num3 = SaveData.TotalSpent();
int value = SaveData.HaulNeededForNextLevel();
string difficultyLabel = GetDifficultyLabel();
string text = (SaveData.IsOverspent() ? $"{num2} (OVER!)" : $"{num2}");
float num4 = 0.75f;
REPOElement[] array = (REPOElement[])(object)new REPOElement[15]
{
(REPOElement)MenuAPI.CreateREPOLabel("Lifetime Haul:", ((Component)_statsPage).transform, new Vector2(40f, 280f)),
(REPOElement)MenuAPI.CreateREPOLabel("Current Level:", ((Component)_statsPage).transform, new Vector2(40f, 255f)),
(REPOElement)MenuAPI.CreateREPOLabel("Available Points:", ((Component)_statsPage).transform, new Vector2(40f, 230f)),
(REPOElement)MenuAPI.CreateREPOLabel("Spent Points:", ((Component)_statsPage).transform, new Vector2(40f, 205f)),
(REPOElement)MenuAPI.CreateREPOLabel("Next Level In:", ((Component)_statsPage).transform, new Vector2(40f, 180f)),
(REPOElement)MenuAPI.CreateREPOLabel("Difficulty:", ((Component)_statsPage).transform, new Vector2(40f, 155f)),
(REPOElement)MenuAPI.CreateREPOLabel(FormatHaul(SaveData.LifetimeHaul.Value), ((Component)_statsPage).transform, new Vector2(240f, 280f)),
(REPOElement)MenuAPI.CreateREPOLabel($"{num}", ((Component)_statsPage).transform, new Vector2(240f, 255f)),
(REPOElement)(_availablePointsLabel = MenuAPI.CreateREPOLabel(text, ((Component)_statsPage).transform, new Vector2(240f, 230f))),
(REPOElement)MenuAPI.CreateREPOLabel($"{num3}", ((Component)_statsPage).transform, new Vector2(240f, 205f)),
(REPOElement)MenuAPI.CreateREPOLabel(FormatHaul(value), ((Component)_statsPage).transform, new Vector2(240f, 180f)),
(REPOElement)MenuAPI.CreateREPOLabel(difficultyLabel, ((Component)_statsPage).transform, new Vector2(240f, 155f)),
(REPOElement)MenuAPI.CreateREPOButton("Reset Stats", (Action)delegate
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
MenuAPI.OpenPopup("Reset Stats", Color.yellow, "Reclaim all spent stat points? Your haul and level will be preserved.", (Action)delegate
{
SaveData.ResetStats();
_statsPage.ClosePage(true);
}, (Action)null);
}, ((Component)_statsPage).transform, new Vector2(40f, 80f)),
(REPOElement)MenuAPI.CreateREPOButton("Reset All", (Action)delegate
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
MenuAPI.OpenPopup("Reset All", Color.red, "Wipe ALL progress including haul, level, and stat allocations? This cannot be undone!", (Action)delegate
{
SaveData.ResetAll();
_statsPage.ClosePage(true);
}, (Action)null);
}, ((Component)_statsPage).transform, new Vector2(220f, 80f)),
(REPOElement)MenuAPI.CreateREPOButton("Close", (Action)delegate
{
_statsPage.ClosePage(true);
}, ((Component)_statsPage).transform, new Vector2(130f, 20f))
};
REPOElement[] array2 = array;
foreach (REPOElement val in array2)
{
REPOLabel val2 = (REPOLabel)(object)((val is REPOLabel) ? val : null);
if (val2 != null && (Object)(object)val2.labelTMP != (Object)null)
{
TextMeshProUGUI labelTMP = val2.labelTMP;
((TMP_Text)labelTMP).fontSize = ((TMP_Text)labelTMP).fontSize * num4;
}
else
{
REPOButton val3 = (REPOButton)(object)((val is REPOButton) ? val : null);
if (val3 != null && (Object)(object)val3.labelTMP != (Object)null)
{
TextMeshProUGUI labelTMP2 = val3.labelTMP;
((TMP_Text)labelTMP2).fontSize = ((TMP_Text)labelTMP2).fontSize * num4;
((REPOElement)val3).rectTransform.sizeDelta = new Vector2(160f, ((REPOElement)val3).rectTransform.sizeDelta.y);
}
}
_statsPage.AddElement(val.rectTransform, Vector2.op_Implicit(((Transform)val.rectTransform).localPosition));
}
_statsPage.OpenPage(false);
}
private static void CreateSkillsPage()
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: 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_0258: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
int num = SaveData.AvailablePoints();
int available = Math.Max(num, 0);
_skillsPage = MenuAPI.CreateREPOPopupPage("Improve - Skills", (PresetSide)1, false, false, 0f);
float num2 = 0.75f;
if (SaveData.IsOverspent())
{
REPOLabel val = MenuAPI.CreateREPOLabel($"Over budget by {Math.Abs(num)} pts! Reset stats or earn more haul.", ((Component)_skillsPage).transform, default(Vector2));
if ((Object)(object)val.labelTMP != (Object)null)
{
TextMeshProUGUI labelTMP = val.labelTMP;
((TMP_Text)labelTMP).fontSize = ((TMP_Text)labelTMP).fontSize * num2;
}
_skillsPage.AddElementToScrollView(((REPOElement)val).rectTransform, default(Vector2), 0f, 0f);
}
_skillSliders = (REPOSlider[])(object)new REPOSlider[13]
{
CreateSlider("Health", SaveData.AllocHealth, available, 0),
CreateSlider("Sprint Speed", SaveData.AllocSpeed, available, 1),
CreateSlider("Stamina", SaveData.AllocStamina, available, 2),
CreateSlider("Extra Jump", SaveData.AllocExtraJump, available, 3),
CreateSlider("Grab Range", SaveData.AllocGrabRange, available, 4),
CreateSlider("Grab Strength", SaveData.AllocGrabStrength, available, 5),
CreateSlider("Throw", SaveData.AllocGrabThrow, available, 6),
CreateSlider("Tumble Launch", SaveData.AllocTumbleLaunch, available, 7),
CreateSlider("Tumble Climb", SaveData.AllocTumbleClimb, available, 8),
CreateSlider("Tumble Wings", SaveData.AllocTumbleWings, available, 9),
CreateSlider("Crouch Rest", SaveData.AllocCrouchRest, available, 10),
CreateSlider("Map Count", SaveData.AllocMapPlayerCount, available, 11, 1),
CreateSlider("Death Head", SaveData.AllocDeathHeadBattery, available, 12)
};
REPOSlider[] skillSliders = _skillSliders;
foreach (REPOSlider val2 in skillSliders)
{
if ((Object)(object)val2.labelTMP != (Object)null)
{
TextMeshProUGUI labelTMP2 = val2.labelTMP;
((TMP_Text)labelTMP2).fontSize = ((TMP_Text)labelTMP2).fontSize * num2;
}
_skillsPage.AddElementToScrollView(((REPOElement)val2).rectTransform, default(Vector2), 0f, 0f);
}
((REPOElement)_skillSliders[0]).repoScrollViewElement.topPadding = 5f;
_skillsPage.scrollView.spacing = 5f;
_skillsPage.OpenPage(true);
}
private static REPOSlider CreateSlider(string name, ConfigEntry<int> entry, int available, int index, int maxCap = int.MaxValue)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
ConfigEntry<int> entry2 = entry;
return MenuAPI.CreateREPOSlider(name, string.Empty, (Action<int>)delegate(int value)
{
OnPointChanged(index, entry2, value);
}, ((Component)_skillsPage).transform, default(Vector2), 0, Math.Clamp(entry2.Value + available, 0, maxCap), entry2.Value, "", "", (BarBehavior)0);
}
private static void OnPointChanged(int index, ConfigEntry<int> entry, int value)
{
entry.Value = value;
int num = SaveData.AvailablePoints();
int num2 = Math.Max(num, 0);
string text = (SaveData.IsOverspent() ? $"{num} (OVER!)" : $"{num}");
((TMP_Text)_availablePointsLabel.labelTMP).text = text;
for (int i = 0; i < _skillSliders.Length; i++)
{
REPOSlider val = _skillSliders[i];
int num3 = ((((TMP_Text)val.labelTMP).text == "Map Count") ? 1 : int.MaxValue);
if (i == index)
{
val.max = Mathf.Min(value + num2, num3);
}
else
{
val.max = Mathf.Min(val.value + (float)num2, (float)num3);
}
val.SetValue(val.value, false);
}
}
private static string GetDifficultyLabel()
{
float value = Improve.DifficultyMultiplier.Value;
if (value <= 0.25f)
{
return "Easy";
}
if (value <= 0.5f)
{
return "Standard";
}
if (value <= 0.75f)
{
return "Hard";
}
return "Hardest";
}
private static string FormatHaul(int value)
{
if (value >= 1000000000)
{
return ((double)value / 1000000000.0).ToString("0.##") + "B";
}
if (value >= 1000000)
{
return ((double)value / 1000000.0).ToString("0.##") + "M";
}
if (value >= 1000)
{
return ((double)value / 1000.0).ToString("0.##") + "K";
}
return value.ToString("N0");
}
}
public static class SaveData
{
public static ConfigEntry<int> LifetimeHaul;
public static ConfigEntry<int> AllocHealth;
public static ConfigEntry<int> AllocSpeed;
public static ConfigEntry<int> AllocStamina;
public static ConfigEntry<int> AllocExtraJump;
public static ConfigEntry<int> AllocGrabRange;
public static ConfigEntry<int> AllocGrabStrength;
public static ConfigEntry<int> AllocGrabThrow;
public static ConfigEntry<int> AllocTumbleLaunch;
public static ConfigEntry<int> AllocTumbleClimb;
public static ConfigEntry<int> AllocTumbleWings;
public static ConfigEntry<int> AllocCrouchRest;
public static ConfigEntry<int> AllocMapPlayerCount;
public static ConfigEntry<int> AllocDeathHeadBattery;
internal static readonly string[] AllStatNames = new string[13]
{
"playerUpgradeHealth", "playerUpgradeSpeed", "playerUpgradeStamina", "playerUpgradeExtraJump", "playerUpgradeRange", "playerUpgradeStrength", "playerUpgradeThrow", "playerUpgradeLaunch", "playerUpgradeTumbleClimb", "playerUpgradeTumbleWings",
"playerUpgradeCrouchRest", "playerUpgradeMapPlayerCount", "playerUpgradeDeathHeadBattery"
};
private static readonly Dictionary<string, FieldInfo> _dictFields = new Dictionary<string, FieldInfo>();
internal static readonly Dictionary<string, int> _appliedBase = new Dictionary<string, int>();
internal static void Initialize()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
ConfigFile val = new ConfigFile(Path.Combine(Application.persistentDataPath, "REPOModData/Improve/save.cfg"), false);
LifetimeHaul = val.Bind<int>("Progress", "LifetimeHaul", 0, "Total haul accumulated across all sessions.");
AllocHealth = val.Bind<int>("Skills", "Health", 0, "Points spent on Health.");
AllocSpeed = val.Bind<int>("Skills", "SprintSpeed", 0, "Points spent on Sprint Speed.");
AllocStamina = val.Bind<int>("Skills", "Stamina", 0, "Points spent on Stamina.");
AllocExtraJump = val.Bind<int>("Skills", "ExtraJump", 0, "Points spent on Extra Jump.");
AllocGrabRange = val.Bind<int>("Skills", "GrabRange", 0, "Points spent on Grab Range.");
AllocGrabStrength = val.Bind<int>("Skills", "GrabStrength", 0, "Points spent on Grab Strength.");
AllocGrabThrow = val.Bind<int>("Skills", "GrabThrow", 0, "Points spent on Throw.");
AllocTumbleLaunch = val.Bind<int>("Skills", "TumbleLaunch", 0, "Points spent on Tumble Launch.");
AllocTumbleClimb = val.Bind<int>("Skills", "TumbleClimb", 0, "Points spent on Tumble Climb.");
AllocTumbleWings = val.Bind<int>("Skills", "TumbleWings", 0, "Points spent on Tumble Wings.");
AllocCrouchRest = val.Bind<int>("Skills", "CrouchRest", 0, "Points spent on Crouch Rest.");
AllocMapPlayerCount = val.Bind<int>("Skills", "MapPlayerCount", 0, "Points spent on Map Player Count.");
AllocDeathHeadBattery = val.Bind<int>("Skills", "DeathHeadBattery", 0, "Points spent on Death Head Battery.");
}
public static int CurrentLevel()
{
float num = Improve.BaseCost.Value;
float value = Improve.DifficultyMultiplier.Value;
float num2 = num * value;
if (num2 <= 0f || LifetimeHaul.Value <= 0)
{
return 0;
}
int val = (int)Math.Floor(Math.Log((double)LifetimeHaul.Value / (double)num2 + 1.0, 2.0));
return Math.Max(val, 0);
}
public static int TotalHaulForLevel(int level)
{
if (level <= 0)
{
return 0;
}
float num = Improve.BaseCost.Value;
float value = Improve.DifficultyMultiplier.Value;
return (int)((double)num * (Math.Pow(2.0, level) - 1.0) * (double)value);
}
public static int HaulNeededForNextLevel()
{
int num = TotalHaulForLevel(CurrentLevel() + 1);
return Math.Max(num - LifetimeHaul.Value, 0);
}
public static int TotalSpent()
{
return AllocHealth.Value + AllocSpeed.Value + AllocStamina.Value + AllocExtraJump.Value + AllocGrabRange.Value + AllocGrabStrength.Value + AllocGrabThrow.Value + AllocTumbleLaunch.Value + AllocTumbleClimb.Value + AllocTumbleWings.Value + AllocCrouchRest.Value + AllocMapPlayerCount.Value + AllocDeathHeadBattery.Value;
}
public static int AvailablePoints()
{
return CurrentLevel() - TotalSpent();
}
public static bool IsOverspent()
{
return AvailablePoints() < 0;
}
public static void ResetStats()
{
AllocHealth.Value = 0;
AllocSpeed.Value = 0;
AllocStamina.Value = 0;
AllocExtraJump.Value = 0;
AllocGrabRange.Value = 0;
AllocGrabStrength.Value = 0;
AllocGrabThrow.Value = 0;
AllocTumbleLaunch.Value = 0;
AllocTumbleClimb.Value = 0;
AllocTumbleWings.Value = 0;
AllocCrouchRest.Value = 0;
AllocMapPlayerCount.Value = 0;
AllocDeathHeadBattery.Value = 0;
Improve.Logger.LogInfo((object)"Stat allocations reset. Points reclaimed.");
}
public static void ResetAll()
{
LifetimeHaul.Value = 0;
ResetStats();
Improve.Logger.LogInfo((object)"Full reset — haul and stats wiped.");
}
internal static int GetAllocationForStat(string statName)
{
if (1 == 0)
{
}
int result = statName switch
{
"playerUpgradeHealth" => AllocHealth.Value,
"playerUpgradeSpeed" => AllocSpeed.Value,
"playerUpgradeStamina" => AllocStamina.Value,
"playerUpgradeExtraJump" => AllocExtraJump.Value,
"playerUpgradeRange" => AllocGrabRange.Value,
"playerUpgradeStrength" => AllocGrabStrength.Value,
"playerUpgradeThrow" => AllocGrabThrow.Value,
"playerUpgradeLaunch" => AllocTumbleLaunch.Value,
"playerUpgradeTumbleClimb" => AllocTumbleClimb.Value,
"playerUpgradeTumbleWings" => AllocTumbleWings.Value,
"playerUpgradeCrouchRest" => AllocCrouchRest.Value,
"playerUpgradeMapPlayerCount" => AllocMapPlayerCount.Value,
"playerUpgradeDeathHeadBattery" => AllocDeathHeadBattery.Value,
_ => 0,
};
if (1 == 0)
{
}
return result;
}
private static Dictionary<string, int>? GetStatDict(string statName)
{
if (!_dictFields.TryGetValue(statName, out FieldInfo value))
{
value = typeof(StatsManager).GetField(statName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
_dictFields[statName] = value;
}
return value?.GetValue(StatsManager.instance) as Dictionary<string, int>;
}
private static int ReadStatLocal(string statName, string steamId)
{
Dictionary<string, int> statDict = GetStatDict(statName);
if (statDict != null && statDict.TryGetValue(steamId, out var value))
{
return value;
}
return 0;
}
private static void WriteStatLocal(string statName, string steamId, int value)
{
Dictionary<string, int> statDict = GetStatDict(statName);
if (statDict != null)
{
statDict[steamId] = value;
}
}
public static void ApplyStats()
{
if ((Object)(object)PlayerController.instance == (Object)null || (Object)(object)StatsManager.instance == (Object)null)
{
return;
}
string playerSteamID = PlayerController.instance.playerSteamID;
_appliedBase.Clear();
string[] allStatNames = AllStatNames;
foreach (string text in allStatNames)
{
int allocationForStat = GetAllocationForStat(text);
int num = ReadStatLocal(text, playerSteamID);
_appliedBase[text] = num;
if (allocationForStat > 0)
{
WriteStatLocal(text, playerSteamID, num + allocationForStat);
}
}
Improve.Logger.LogInfo((object)$"Improve stats applied locally (Level {CurrentLevel()}, {TotalSpent()} spent, {AvailablePoints()} available).");
}
public static bool EnforceStats()
{
if ((Object)(object)PlayerController.instance == (Object)null)
{
return false;
}
if ((Object)(object)StatsManager.instance == (Object)null)
{
return false;
}
if (_appliedBase.Count == 0)
{
return false;
}
string playerSteamID = PlayerController.instance.playerSteamID;
bool flag = false;
string[] allStatNames = AllStatNames;
foreach (string text in allStatNames)
{
int allocationForStat = GetAllocationForStat(text);
int num = ReadStatLocal(text, playerSteamID);
int value;
int num2 = (_appliedBase.TryGetValue(text, out value) ? value : 0);
int num3 = num2 + allocationForStat;
if (num != num3)
{
int num4 = ((num >= num3) ? (num - allocationForStat) : num);
_appliedBase[text] = num4;
flag = true;
if (allocationForStat > 0)
{
int value2 = num4 + allocationForStat;
WriteStatLocal(text, playerSteamID, value2);
}
}
}
if (flag)
{
Improve.Logger.LogDebug((object)"Watchdog: detected external stat change — re-applied allocations locally.");
}
return flag;
}
}
}
namespace Improve.Patches
{
[HarmonyPatch]
internal static class HaulTrackerPatch
{
private static int _haulAtLevelStart;
[HarmonyPatch(typeof(StatsManager), "PlayerAdd")]
[HarmonyPostfix]
private static void PlayerAdd_Postfix(string _steamID)
{
if (!(_steamID != PlayerAvatar.instance.steamID))
{
_haulAtLevelStart = StatsManager.instance.GetRunStatTotalHaul();
Improve.Logger.LogDebug((object)$"Level start baseline: {_haulAtLevelStart}");
}
}
[HarmonyPatch(typeof(SemiFunc), "OnSceneSwitch")]
[HarmonyPrefix]
private static void OnSceneSwitch_Prefix()
{
if (SemiFunc.RunIsLevel())
{
int runStatTotalHaul = StatsManager.instance.GetRunStatTotalHaul();
int num = runStatTotalHaul - _haulAtLevelStart;
if (num > 0)
{
ConfigEntry<int> lifetimeHaul = SaveData.LifetimeHaul;
lifetimeHaul.Value += num;
Improve.Logger.LogInfo((object)$"Level haul captured: +{num} (lifetime: {SaveData.LifetimeHaul.Value})");
}
}
}
}
[HarmonyPatch]
internal static class StatApplyPatch
{
[CompilerGenerated]
private sealed class <DeferredApply>d__4 : IEnumerator<object>, IEnumerator, IDisposable
{
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 <DeferredApply>d__4(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>2__current = null;
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
<>2__current = null;
<>1__state = 3;
return true;
case 3:
<>1__state = -1;
if (!SemiFunc.RunIsLevel())
{
return false;
}
SaveData.ApplyStats();
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 <WatchdogLoop>d__7 : IEnumerator<object>, IEnumerator, IDisposable
{
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 <WatchdogLoop>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(1f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
break;
case 2:
<>1__state = -1;
break;
}
if (SemiFunc.RunIsLevel())
{
SaveData.EnforceStats();
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 2;
return true;
}
_watchdog = null;
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();
}
}
private static Coroutine? _watchdog;
[HarmonyPatch(typeof(StatsManager), "PlayerAdd")]
[HarmonyPostfix]
private static void PlayerAdd_Postfix(string _steamID)
{
if (SemiFunc.RunIsLevel() && !(_steamID != PlayerAvatar.instance.steamID))
{
SaveData._appliedBase.Clear();
Improve.Logger.LogDebug((object)"Player data added — deferring Improve stat application...");
((MonoBehaviour)Improve.Instance).StartCoroutine(DeferredApply());
StartWatchdog();
}
}
[HarmonyPatch(typeof(PunManager), "ReceiveSyncData")]
[HarmonyPostfix]
private static void ReceiveSyncData_Postfix(bool finalChunk)
{
if (finalChunk && SemiFunc.RunIsLevel())
{
if (SaveData._appliedBase.Count > 0)
{
Improve.Logger.LogDebug((object)"Sync complete — enforcing Improve allocations...");
SaveData.EnforceStats();
}
else
{
Improve.Logger.LogDebug((object)"Sync complete, not yet applied — deferring...");
((MonoBehaviour)Improve.Instance).StartCoroutine(DeferredApply());
}
}
}
[HarmonyPatch(typeof(SemiFunc), "OnSceneSwitch")]
[HarmonyPrefix]
private static void OnSceneSwitch_Prefix()
{
if (SemiFunc.RunIsLevel())
{
StopWatchdog();
SaveData._appliedBase.Clear();
}
}
[IteratorStateMachine(typeof(<DeferredApply>d__4))]
private static IEnumerator DeferredApply()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DeferredApply>d__4(0);
}
private static void StartWatchdog()
{
StopWatchdog();
_watchdog = ((MonoBehaviour)Improve.Instance).StartCoroutine(WatchdogLoop());
}
private static void StopWatchdog()
{
if (_watchdog != null)
{
((MonoBehaviour)Improve.Instance).StopCoroutine(_watchdog);
_watchdog = null;
}
}
[IteratorStateMachine(typeof(<WatchdogLoop>d__7))]
private static IEnumerator WatchdogLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <WatchdogLoop>d__7(0);
}
}
}