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.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using GoldXpMultiplier;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Common;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
using UnityEngine.Localization.Settings;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(GoldXpMod), "Gold & XP Multiplier", "2.5.0", "Relsev", null)]
[assembly: MelonGame("BoltBlasterGames", "TheSpellBrigade")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GoldXpMultiplier")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.5.0.0")]
[assembly: AssemblyInformationalVersion("2.5.0")]
[assembly: AssemblyProduct("GoldXpMultiplier")]
[assembly: AssemblyTitle("GoldXpMultiplier")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.5.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 GoldXpMultiplier
{
internal static class GoldPatch
{
public static void Postfix(EarnedGold __result)
{
if (!GoldXpMod.Enabled || __result == null)
{
return;
}
float mult = GoldXpMod.GoldMultiplier;
if (mult != 1f)
{
int totalGold = __result.TotalGold;
int[] array = Read(__result);
Write(__result, Array.ConvertAll(array, (int v) => Scale(v, mult)));
RunSummaryUi.RememberGold(__result, array, mult, totalGold);
}
}
public static int[] Read(EarnedGold g)
{
return new int[6] { g._BaseGold_k__BackingField, g._BonusGoldFromFinalUpgrade_k__BackingField, g._BonusGoldFromGoldGainStat_k__BackingField, g._BonusGoldFromCurses_k__BackingField, g._BonusGoldFromDifficulty_k__BackingField, g._BonusGoldFromUnusedCharacter_k__BackingField };
}
private static void Write(EarnedGold g, int[] v)
{
g._BaseGold_k__BackingField = v[0];
g._BonusGoldFromFinalUpgrade_k__BackingField = v[1];
g._BonusGoldFromGoldGainStat_k__BackingField = v[2];
g._BonusGoldFromCurses_k__BackingField = v[3];
g._BonusGoldFromDifficulty_k__BackingField = v[4];
g._BonusGoldFromUnusedCharacter_k__BackingField = v[5];
}
public static EarnedGold Create(int[] values, EarnedGold percentagesFrom)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: 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_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
EarnedGold val = new EarnedGold();
Write(val, values);
val._BonusGoldPercentageFromCurses_k__BackingField = percentagesFrom._BonusGoldPercentageFromCurses_k__BackingField;
val._BonusGoldPercentageFromDifficulty_k__BackingField = percentagesFrom._BonusGoldPercentageFromDifficulty_k__BackingField;
val._BonusGoldPercentageFromUnusedCharacter_k__BackingField = percentagesFrom._BonusGoldPercentageFromUnusedCharacter_k__BackingField;
return val;
}
private static int Scale(int value, float mult)
{
if (value <= 0)
{
return value;
}
double num = Math.Round((double)value * (double)mult);
if (!(num >= 2147483647.0))
{
return (int)num;
}
return int.MaxValue;
}
}
internal static class XpPatch
{
public static void Prefix(PartyLevelManager __instance, ref float experience)
{
if (!(experience <= 0f))
{
float num = (GoldXpMod.Enabled ? GoldXpMod.XpMultiplier : 1f);
float vanilla = experience;
if (num != 1f)
{
experience *= num;
}
RunSummaryUi.TrackXp(__instance, vanilla, experience);
}
}
}
internal static class ImpactFx
{
private sealed class Spark
{
public RectTransform Rect;
public Image Image;
public Vector2 Velocity;
public float Spin;
}
private const float FallDuration = 0.42f;
private const float ImpactDuration = 0.55f;
private static readonly Color SparkColor = new Color(1f, 0.84f, 0.3f, 1f);
private static Sprite _round;
public static IEnumerator Slam(TMP_Text target, TMP_Text style, string label, string newText, Transform shakeRoot, Action onImpact)
{
if ((Object)(object)target == (Object)null)
{
yield break;
}
object obj;
if (!((Object)(object)((Graphic)target).canvas != (Object)null))
{
obj = null;
}
else
{
Canvas rootCanvas = ((Graphic)target).canvas.rootCanvas;
obj = ((rootCanvas != null) ? ((Component)rootCanvas).GetComponent<RectTransform>() : null);
}
RectTransform root = (RectTransform)obj;
if ((Object)(object)root == (Object)null)
{
target.text = newText;
onImpact?.Invoke();
yield break;
}
target.ForceMeshUpdate(false, false);
Transform transform = target.transform;
Bounds textBounds = target.textBounds;
Vector3 end = ((Transform)root).InverseTransformPoint(transform.TransformPoint(((Bounds)(ref textBounds)).center));
Rect rect = root.rect;
Vector3 start = end + new Vector3(0f, ((Rect)(ref rect)).height * 0.6f, 0f);
TMP_Text slam = CreateLabel(root, style ?? target, label);
RectTransform slamRect = slam.rectTransform;
float t0 = Time.unscaledTime;
while (true)
{
if ((Object)(object)target == (Object)null || (Object)(object)slam == (Object)null)
{
Cleanup(slam, null);
yield break;
}
float num = Mathf.Clamp01((Time.unscaledTime - t0) / 0.42f);
float num2 = num * num * num;
((Transform)slamRect).localPosition = Vector3.LerpUnclamped(start, end, num2);
float num3 = Mathf.Lerp(2.4f, 1f, num2);
((Transform)slamRect).localScale = new Vector3(num3 * 0.85f, num3 * 1.15f, 1f);
((Transform)slamRect).localRotation = Quaternion.Euler(0f, 0f, Mathf.Lerp(-16f, 0f, num2));
slam.alpha = Mathf.Clamp01(num * 5f);
if (num >= 1f)
{
break;
}
yield return null;
}
target.text = newText;
try
{
onImpact?.Invoke();
}
catch (Exception ex)
{
GoldXpMod.Log.Warning("[fx] " + ex.Message);
}
List<Spark> sparks = SpawnSparks(root, end, 26);
Image flash = SpawnFlash(root, end);
Vector3 targetScale = target.transform.localScale;
Vector3 shakeBase = (((Object)(object)shakeRoot != (Object)null) ? shakeRoot.localPosition : Vector3.zero);
t0 = Time.unscaledTime;
float last = t0;
while (true)
{
float unscaledTime = Time.unscaledTime;
float num4 = unscaledTime - last;
last = unscaledTime;
float num5 = Mathf.Clamp01((unscaledTime - t0) / 0.55f);
if ((Object)(object)target != (Object)null)
{
target.transform.localScale = targetScale * (1f + 0.55f * Punch(num5));
}
if ((Object)(object)shakeRoot != (Object)null)
{
float num6 = 22f * (1f - num5) * (1f - num5);
shakeRoot.localPosition = shakeBase + new Vector3(Random.Range(0f - num6, num6), Random.Range(0f - num6, num6), 0f);
}
if ((Object)(object)slam != (Object)null)
{
float num7 = Mathf.Exp(-9f * num5);
((Transform)slamRect).localScale = new Vector3(1f + 0.6f * num7 + 0.25f * num5, 1f - 0.45f * num7 + 0.25f * num5, 1f);
((Transform)slamRect).localPosition = end + new Vector3(0f, 70f * Mathf.Sin(num5 * (float)Math.PI * 0.5f), 0f);
slam.alpha = 1f - num5 * num5;
}
if ((Object)(object)flash != (Object)null)
{
float num8 = 1f - Mathf.Pow(1f - num5, 3f);
((Transform)((Graphic)flash).rectTransform).localScale = Vector3.one * Mathf.Lerp(0.2f, 3.2f, num8);
Color color = ((Graphic)flash).color;
color.a = 0.8f * (1f - num8);
((Graphic)flash).color = color;
}
foreach (Spark item in sparks)
{
if (!((Object)(object)item.Rect == (Object)null))
{
item.Velocity += new Vector2(0f, -1800f) * num4;
RectTransform rect2 = item.Rect;
((Transform)rect2).localPosition = ((Transform)rect2).localPosition + Vector2.op_Implicit(item.Velocity * num4);
((Transform)item.Rect).localRotation = Quaternion.Euler(0f, 0f, ((Transform)item.Rect).localEulerAngles.z + item.Spin * num4);
Color color2 = ((Graphic)item.Image).color;
color2.a = 1f - num5;
((Graphic)item.Image).color = color2;
((Transform)item.Rect).localScale = Vector3.one * (1f - 0.6f * num5);
}
}
if (num5 >= 1f)
{
break;
}
yield return null;
}
if ((Object)(object)target != (Object)null)
{
target.transform.localScale = targetScale;
}
if ((Object)(object)shakeRoot != (Object)null)
{
shakeRoot.localPosition = shakeBase;
}
Cleanup(slam, sparks);
if ((Object)(object)flash != (Object)null)
{
Object.Destroy((Object)(object)((Component)flash).gameObject);
}
}
private static float Punch(float k)
{
return Mathf.Exp(-6f * k) * Mathf.Sin(k * (float)Math.PI * 3.5f + 0.35f) * ((k < 0.02f) ? (k / 0.02f) : 1f);
}
private static TMP_Text CreateLabel(RectTransform root, TMP_Text style, string label)
{
//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_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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_0054: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("SBMod_Slam");
val.AddComponent<RectTransform>();
val.transform.SetParent((Transform)(object)root, false);
val.transform.SetAsLastSibling();
TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj).font = style.font;
((TMP_Text)obj).fontSharedMaterial = style.fontSharedMaterial;
((TMP_Text)obj).fontStyle = style.fontStyle;
((Graphic)obj).color = ((Graphic)style).color;
((TMP_Text)obj).enableVertexGradient = style.enableVertexGradient;
((TMP_Text)obj).colorGradient = style.colorGradient;
((TMP_Text)obj).fontSize = style.fontSize * 1.5f;
((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
((Graphic)obj).raycastTarget = false;
((TMP_Text)obj).text = label;
((TMP_Text)obj).rectTransform.sizeDelta = new Vector2(800f, 400f);
return (TMP_Text)(object)obj;
}
private static List<Spark> SpawnSparks(RectTransform root, Vector3 at, int count)
{
//IL_0012: 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)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: 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_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: 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)
List<Spark> list = new List<Spark>();
for (int i = 0; i < count; i++)
{
GameObject val = new GameObject("SBMod_Spark");
RectTransform val2 = val.AddComponent<RectTransform>();
val.transform.SetParent((Transform)(object)root, false);
val.transform.SetAsLastSibling();
Image val3 = val.AddComponent<Image>();
val3.sprite = RoundSprite();
((Graphic)val3).color = ((i % 3 == 0) ? Color.white : SparkColor);
((Graphic)val3).raycastTarget = false;
float num = Random.Range(22f, 48f);
val2.sizeDelta = new Vector2(num, num);
((Transform)val2).localPosition = at;
((Transform)val2).localRotation = Quaternion.Euler(0f, 0f, 45f);
float num2 = Random.Range(10f, 170f) * ((float)Math.PI / 180f);
float num3 = Random.Range(500f, 1100f);
list.Add(new Spark
{
Rect = val2,
Image = val3,
Velocity = new Vector2(Mathf.Cos(num2), Mathf.Sin(num2)) * num3,
Spin = Random.Range(-720f, 720f)
});
}
return list;
}
private static Image SpawnFlash(RectTransform root, Vector3 at)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//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_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
Sprite val = RoundSprite();
if ((Object)(object)val == (Object)null)
{
return null;
}
GameObject val2 = new GameObject("SBMod_Flash");
RectTransform val3 = val2.AddComponent<RectTransform>();
val2.transform.SetParent((Transform)(object)root, false);
val2.transform.SetAsLastSibling();
Image obj = val2.AddComponent<Image>();
obj.sprite = val;
((Graphic)obj).color = new Color(1f, 0.9f, 0.55f, 0.8f);
((Graphic)obj).raycastTarget = false;
val3.sizeDelta = new Vector2(320f, 320f);
((Transform)val3).localPosition = at;
return obj;
}
private static Sprite RoundSprite()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: 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)
if ((Object)(object)_round != (Object)null)
{
return _round;
}
try
{
Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
Il2CppStructArray<Color32> val2 = new Il2CppStructArray<Color32>(4096L);
float num = 31.5f;
for (int i = 0; i < 64; i++)
{
for (int j = 0; j < 64; j++)
{
float num2 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num)) / num;
float num3 = Mathf.Clamp01(1f - num2);
num3 = num3 * num3 * (3f - 2f * num3);
((Il2CppArrayBase<Color32>)(object)val2)[i * 64 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num3 * 255f));
}
}
val.SetPixels32(val2);
val.Apply(false, true);
((Object)val).hideFlags = (HideFlags)61;
_round = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
((Object)_round).hideFlags = (HideFlags)61;
}
catch (Exception ex)
{
GoldXpMod.Log.Warning("[fx] no round sprite: " + ex.Message);
}
return _round;
}
private static void Cleanup(TMP_Text slam, List<Spark> sparks)
{
if ((Object)(object)slam != (Object)null)
{
Object.Destroy((Object)(object)((Component)slam).gameObject);
}
if (sparks == null)
{
return;
}
foreach (Spark spark in sparks)
{
if ((Object)(object)spark.Rect != (Object)null)
{
Object.Destroy((Object)(object)((Component)spark.Rect).gameObject);
}
}
}
}
public class GoldXpMod : MelonMod
{
public static Instance Log;
private static MelonPreferences_Category _category;
internal static MelonPreferences_Entry<bool> _enabledEntry;
internal static MelonPreferences_Entry<float> _goldEntry;
internal static MelonPreferences_Entry<float> _xpEntry;
internal static MelonPreferences_Entry<float> _rankXpEntry;
private int _hooksInstalled;
private int _hooksTotal;
public static bool Enabled => _enabledEntry?.Value ?? true;
public static float GoldMultiplier => Sanitize(_goldEntry?.Value);
public static float XpMultiplier => Sanitize(_xpEntry?.Value);
public static float RankXpMultiplier => Sanitize(_rankXpEntry?.Value);
public override void OnInitializeMelon()
{
Log = ((MelonBase)this).LoggerInstance;
ValueRange<float> val = new ValueRange<float>(0f, 1000f);
_category = MelonPreferences.CreateCategory("GoldMultiplier", "Gold & XP Multiplier");
_enabledEntry = _category.CreateEntry<bool>("Enabled", true, "Enabled", "Включён ли мод", false, false, (ValueValidator)null, (string)null);
_goldEntry = _category.CreateEntry<float>("Multiplier", 2f, "Gold Multiplier", "Множитель золота за забег (1.0 = ваниль). Умножается и база, и все бонусы", false, false, (ValueValidator)(object)val, (string)null);
_xpEntry = _category.CreateEntry<float>("XpMultiplier", 2f, "Run XP Multiplier", "Множитель опыта в забеге (1.0 = ваниль). В коопе работает, если мод стоит у хоста", false, false, (ValueValidator)(object)val, (string)null);
_rankXpEntry = _category.CreateEntry<float>("RankXpMultiplier", 1f, "Wizard Rank XP Multiplier", "Множитель опыта ранга мага за забег (1.0 = ваниль)", false, false, (ValueValidator)(object)val, (string)null);
_category.SaveToFile(false);
WarnAboutOldVersion();
ApplyPatches();
Log.Msg($"{_hooksInstalled}/{_hooksTotal} hooks — gold x{GoldMultiplier}, run xp x{XpMultiplier}, rank xp x{RankXpMultiplier}{(Enabled ? "" : " (disabled)")}. Settings: Options → Multipliers");
}
public override void OnSceneWasInitialized(int buildIndex, string sceneName)
{
if (sceneName == "StartMenu")
{
MelonCoroutines.Start(RepairSaveLater());
}
}
private static IEnumerator RepairSaveLater()
{
yield return (object)new WaitForSeconds(2f);
try
{
SaveDoctor.RepairCorruptedRanks();
}
catch (Exception value)
{
Log.Error($"rank repair failed: {value}");
}
}
internal static void SaveSettings()
{
_category.SaveToFile(false);
}
private static float Sanitize(float? value)
{
float num = value ?? 1f;
if (!float.IsNaN(num) && !float.IsInfinity(num) && !(num < 0f))
{
return num;
}
return 1f;
}
private static void WarnAboutOldVersion()
{
if (MelonBase.RegisteredMelons.Any((MelonBase m) => m.Info.Name == "SpellBrigadeGoldMultiplier"))
{
Log.Warning("Old version found: delete Mods\\SpellBrigadeGoldMultiplier.dll, otherwise rewards are multiplied twice");
}
}
private void ApplyPatches()
{
Patch(typeof(RunGoldCalculator), "Calculate", typeof(GoldPatch), null, "Postfix");
Patch(typeof(PartyLevelManager), "TryAddExperience", typeof(XpPatch), "Prefix");
Patch(typeof(CharacterRankProgression), "SetRankProgression", typeof(RankXp), "SetRankProgressionPrefix");
Patch(typeof(RunRecordFactory), "CalculateRankProgression", typeof(RankXp), null, "CalculateRankProgressionPostfix");
Patch(typeof(GameOverMissionStatsPanel), "SetValues", typeof(RunSummaryUi), null, "SetValuesPostfix");
Patch(typeof(GameOverMissionStatsPanel), "SetXPEarned", typeof(RunSummaryUi), "SetXpEarnedPrefix");
Patch(typeof(SettingsPanel), "SetupSubPanels", typeof(SettingsTab), "InjectPrefix", "LinkTabButtonsPostfix");
}
private void Patch(Type target, string method, Type patchClass, string prefix = null, string postfix = null)
{
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
_hooksTotal++;
string value = target.Name + "." + method;
try
{
MethodInfo methodInfo = AccessTools.Method(target, method, (Type[])null, (Type[])null) ?? throw new MissingMethodException(target.FullName, method);
if (ReturnsStruct(methodInfo))
{
Log.Warning($"skipped {value}: it returns a struct ({methodInfo.ReturnType.Name}), hooking it corrupts the result");
return;
}
List<string> list = SharedCodeGuard.FindMethodsSharingCode(methodInfo);
if (list.Count > 0)
{
Log.Warning($"skipped {value}: its native code is shared with {list.Count} other method(s), patching would break them (e.g. {string.Join(", ", list.GetRange(0, Math.Min(5, list.Count)))})");
}
else
{
((MelonBase)this).HarmonyInstance.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchClass, prefix, (Type[])null, (Type[])null)), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchClass, postfix, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
_hooksInstalled++;
}
}
catch (Exception ex)
{
Log.Error($"failed to hook {value} — this feature is disabled. {ex.GetType().Name}: {ex.Message}");
}
}
private static bool ReturnsStruct(MethodInfo method)
{
Type returnType = method.ReturnType;
if (returnType == typeof(void) || returnType.IsPrimitive || returnType.IsEnum)
{
return false;
}
if (!returnType.IsValueType)
{
return typeof(ValueType).IsAssignableFrom(returnType);
}
return true;
}
}
internal static class RankXp
{
[ThreadStatic]
public static bool Suspended;
private static (int r0, float p0, int r, float p) _lastScaled = (r0: -1, p0: 0f, r: -1, p: 0f);
public static void SetRankProgressionPrefix(CharacterRankProgression __instance, CharacterId characterId, ref int rank, ref float rankProgress)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
try
{
if (Suspended || !GoldXpMod.Enabled)
{
return;
}
float rankXpMultiplier = GoldXpMod.RankXpMultiplier;
if (rankXpMultiplier == 1f)
{
return;
}
CharacterRankProgress orCreateProgressForCharacter = __instance.GetOrCreateProgressForCharacter(characterId);
if (orCreateProgressForCharacter != null)
{
int currentRank = orCreateProgressForCharacter.CurrentRank;
float progressTowardsNextRank = orCreateProgressForCharacter.ProgressTowardsNextRank;
if ((_lastScaled.r0 != currentRank || _lastScaled.p0 != progressTowardsNextRank || _lastScaled.r != rank || _lastScaled.p != rankProgress) && TryScale(__instance.rankCalculator, orCreateProgressForCharacter.Prestige, currentRank, progressTowardsNextRank, rank, rankProgress, rankXpMultiplier, out var rank2, out var progress))
{
rank = rank2;
rankProgress = progress;
}
}
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[rank xp] {value}");
}
}
public static void CalculateRankProgressionPostfix(RankProgression __result, int prestige)
{
try
{
if (__result == (RankProgression)null || !GoldXpMod.Enabled)
{
return;
}
float rankXpMultiplier = GoldXpMod.RankXpMultiplier;
if (rankXpMultiplier != 1f)
{
LocalPlayer instance = SingletonPersistent<LocalPlayer>.Instance;
object calc;
if (instance == null)
{
calc = null;
}
else
{
CharacterRankProgression characterRankManager = instance.GetCharacterRankManager();
calc = ((characterRankManager != null) ? characterRankManager.rankCalculator : null);
}
int startRank = __result.StartRank;
int endRank = __result.EndRank;
float startRankProgress = __result.StartRankProgress;
float endRankProgress = __result.EndRankProgress;
if (TryScale((CharacterRankCalculator)calc, prestige, startRank, startRankProgress, endRank, endRankProgress, rankXpMultiplier, out var rank, out var progress))
{
__result._EndRank_k__BackingField = rank;
__result._EndRankProgress_k__BackingField = progress;
_lastScaled = (r0: startRank, p0: startRankProgress, r: rank, p: progress);
}
}
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[rank xp] {value}");
}
}
private static bool TryScale(CharacterRankCalculator calc, int prestige, int r0, float p0, int r1, float p1, float mult, out int rank, out float progress)
{
rank = r1;
progress = p1;
if (calc == null || mult == 1f)
{
return false;
}
if (!Sane(r0, p0) || !Sane(r1, p1))
{
return false;
}
if (r1 < r0 || (r1 == r0 && p1 <= p0))
{
return false;
}
if (r1 - r0 > 1000 || calc.IsMaxRank(r0) || calc.IsMaxRank(r1))
{
return false;
}
double num;
if (r1 == r0)
{
num = (double)(p1 - p0) * Minutes(calc, r0, prestige);
}
else
{
num = (double)(1f - p0) * Minutes(calc, r0, prestige);
for (int i = r0 + 1; i < r1; i++)
{
num += Minutes(calc, i, prestige);
}
num += (double)p1 * Minutes(calc, r1, prestige);
}
if (!(num > 0.0) || double.IsInfinity(num))
{
return false;
}
double num2 = num * (double)mult;
int num3 = r0;
double num4 = p0;
while (true)
{
if (calc.IsMaxRank(num3))
{
num4 = 0.0;
break;
}
double num5 = Minutes(calc, num3, prestige);
if (!(num5 > 0.0) || double.IsInfinity(num5))
{
return false;
}
double num6 = (1.0 - num4) * num5;
if (num2 < num6)
{
num4 += num2 / num5;
break;
}
num2 -= num6;
num3++;
num4 = 0.0;
if (num3 - r0 > 10000)
{
return false;
}
}
rank = num3;
progress = (float)Math.Min(num4, 0.9999);
return Sane(rank, progress);
}
private static double Minutes(CharacterRankCalculator calc, int rank, int prestige)
{
return calc.CalculateMinutesRequiredForNextRank(rank, prestige);
}
private static bool Sane(int rank, float progress)
{
if (rank >= 0 && rank <= 1000 && !float.IsNaN(progress) && progress >= 0f)
{
return progress <= 1f;
}
return false;
}
}
internal static class RunSummaryUi
{
private sealed class GoldSnapshot
{
public int[] Vanilla;
public int[] Modded;
public float Mult;
public int VanillaTotal;
public int ModdedTotal;
}
private sealed class Pending
{
public EarnedGoldUI GoldUi;
public EarnedGold ModdedGold;
public GoldSnapshot Gold;
public TMP_Text XpText;
public float XpVanilla;
public float XpModded;
public float XpMult;
public Transform ShakeRoot;
}
private const string BonusPanelName = "SBMod_GoldBonus";
private static readonly Dictionary<IntPtr, GoldSnapshot> Snapshots = new Dictionary<IntPtr, GoldSnapshot>();
private static readonly List<GoldSnapshot> RecentSnapshots = new List<GoldSnapshot>();
private static IntPtr _xpRunId;
private static double _xpVanilla;
private static double _xpModded;
private static Pending _pending;
private static bool _sequenceQueued;
public static void RememberGold(EarnedGold modded, int[] vanilla, float mult, int vanillaTotal)
{
GoldSnapshot goldSnapshot = new GoldSnapshot
{
Vanilla = vanilla,
Modded = GoldPatch.Read(modded),
Mult = mult,
VanillaTotal = vanillaTotal,
ModdedTotal = modded.TotalGold
};
if (Snapshots.Count > 64)
{
Snapshots.Clear();
}
Snapshots[((Il2CppObjectBase)modded).Pointer] = goldSnapshot;
RecentSnapshots.Add(goldSnapshot);
if (RecentSnapshots.Count > 16)
{
RecentSnapshots.RemoveAt(0);
}
}
private static GoldSnapshot FindSnapshot(EarnedGold gold)
{
if (Snapshots.TryGetValue(((Il2CppObjectBase)gold).Pointer, out var value))
{
return value;
}
int[] b = GoldPatch.Read(gold);
for (int num = RecentSnapshots.Count - 1; num >= 0; num--)
{
if (Same(RecentSnapshots[num].Modded, b))
{
return RecentSnapshots[num];
}
}
return null;
}
private static bool Same(int[] a, int[] b)
{
for (int i = 0; i < a.Length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
public static void TrackXp(PartyLevelManager manager, float vanilla, float modded)
{
if (!((Object)(object)manager == (Object)null))
{
if (((Il2CppObjectBase)manager).Pointer != _xpRunId)
{
_xpRunId = ((Il2CppObjectBase)manager).Pointer;
_xpVanilla = 0.0;
_xpModded = 0.0;
}
_xpVanilla += vanilla;
_xpModded += modded;
}
}
public static void SetValuesPostfix(GameOverMissionStatsPanel __instance)
{
try
{
EarnedGoldUI earnedGoldUI = __instance.earnedGoldUI;
EarnedGold val = ((earnedGoldUI != null) ? earnedGoldUI.earnedGold : null);
if (val != null)
{
GoldSnapshot goldSnapshot = FindSnapshot(val);
if (goldSnapshot != null && goldSnapshot.Mult != 1f && goldSnapshot.VanillaTotal != goldSnapshot.ModdedTotal)
{
Queue().GoldUi = earnedGoldUI;
_pending.ShakeRoot = ((Component)__instance).transform;
_pending.ModdedGold = val;
_pending.Gold = goldSnapshot;
earnedGoldUI.earnedGold = GoldPatch.Create(goldSnapshot.Vanilla, val);
}
}
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[summary] gold: {value}");
}
}
public static void SetXpEarnedPrefix(GameOverMissionStatsPanel __instance, ref float xpEarned)
{
try
{
if (_xpModded > 0.0 && _xpVanilla > 0.0 && !(Math.Abs(_xpModded - _xpVanilla) < 0.5))
{
float num = (float)((double)xpEarned * (_xpVanilla / _xpModded));
if (Math.Round(num) != Math.Round(xpEarned))
{
Queue().XpText = __instance.xpEarnedValue;
_pending.ShakeRoot = ((Component)__instance).transform;
_pending.XpMult = GoldXpMod.XpMultiplier;
_pending.XpVanilla = num;
_pending.XpModded = xpEarned;
xpEarned = num;
}
}
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[summary] xp: {value}");
}
}
private static Pending Queue()
{
if (_pending == null)
{
_pending = new Pending();
}
if (!_sequenceQueued)
{
_sequenceQueued = true;
MelonCoroutines.Start(Sequence());
}
return _pending;
}
private static IEnumerator Sequence()
{
yield return null;
Pending job = _pending;
_pending = null;
_sequenceQueued = false;
if (job == null)
{
yield break;
}
TMP_Text goldText = (((Object)(object)job.GoldUi != (Object)null) ? job.GoldUi.totalGoldEarnedText : null);
if ((Object)(object)goldText != (Object)null && job.Gold != null)
{
yield return WaitForValue(goldText, job.Gold.VanillaTotal);
EarnedGoldUI ui = job.GoldUi;
yield return ImpactFx.Slam(goldText, goldText, FormatMult(job.Gold.Mult), FormatLike(goldText.text, job.Gold.ModdedTotal), job.ShakeRoot, delegate
{
ShowBonusPanel(ui, job.Gold.Mult);
PlayBonusSound(ui);
});
if ((Object)(object)ui != (Object)null && job.ModdedGold != null)
{
ui.earnedGold = job.ModdedGold;
}
}
if ((Object)(object)job.XpText != (Object)null)
{
yield return WaitVisible(job.XpText);
string label = FormatMult(job.XpMult);
yield return ImpactFx.Slam(job.XpText, goldText ?? job.XpText, label, FormatLike(job.XpText.text, Mathf.RoundToInt(job.XpModded)) + Suffix(job.XpMult), job.ShakeRoot, delegate
{
PlayBonusSound(job.GoldUi);
});
}
}
private static void ShowBonusPanel(EarnedGoldUI ui, float mult)
{
if ((Object)(object)ui == (Object)null)
{
return;
}
TMP_Text valueText;
GameObject orCreateBonusPanel = GetOrCreateBonusPanel(ui, out valueText);
if (!((Object)(object)orCreateBonusPanel == (Object)null))
{
orCreateBonusPanel.SetActive(true);
if ((Object)(object)valueText != (Object)null)
{
valueText.text = FormatMult(mult);
}
}
}
private static void PlayBonusSound(EarnedGoldUI ui)
{
try
{
if ((Object)(object)ui != (Object)null)
{
OneShotSoundPlayer bonusGoldSoundPlayer = ui.bonusGoldSoundPlayer;
if (bonusGoldSoundPlayer != null)
{
bonusGoldSoundPlayer.Play();
}
}
}
catch
{
}
}
private static IEnumerator WaitForValue(TMP_Text text, int value)
{
float timeout = Time.unscaledTime + 120f;
float stableSince = -1f;
while ((Object)(object)text != (Object)null && Time.unscaledTime < timeout)
{
if (((Behaviour)text).isActiveAndEnabled && ParseInt(text.text) == value)
{
if (stableSince < 0f)
{
stableSince = Time.unscaledTime;
}
else if (Time.unscaledTime - stableSince > 0.35f)
{
break;
}
}
else
{
stableSince = -1f;
}
yield return null;
}
}
private static IEnumerator WaitVisible(TMP_Text text)
{
float timeout = Time.unscaledTime + 120f;
while ((Object)(object)text != (Object)null && !((Behaviour)text).isActiveAndEnabled && Time.unscaledTime < timeout)
{
yield return null;
}
float until = Time.unscaledTime + 0.3f;
while (Time.unscaledTime < until)
{
yield return null;
}
}
private static GameObject GetOrCreateBonusPanel(EarnedGoldUI ui, out TMP_Text valueText)
{
valueText = null;
try
{
BonusGoldUI difficultyGoldBonus = ui.difficultyGoldBonus;
GameObject val = ((difficultyGoldBonus != null) ? difficultyGoldBonus.Panel : null);
if ((Object)(object)val == (Object)null)
{
return null;
}
Transform parent = val.transform.parent;
Transform val2 = parent.Find("SBMod_GoldBonus");
GameObject val3;
if ((Object)(object)val2 != (Object)null)
{
val3 = ((Component)val2).gameObject;
}
else
{
val3 = Object.Instantiate<GameObject>(val, parent);
((Object)val3).name = "SBMod_GoldBonus";
Transform transform = val.transform;
GameObject[] array = new GameObject[2];
BonusGoldUI cursesGoldBonus = ui.cursesGoldBonus;
array[0] = ((cursesGoldBonus != null) ? cursesGoldBonus.Panel : null);
BonusGoldUI unusedCharacterGoldBonus = ui.unusedCharacterGoldBonus;
array[1] = ((unusedCharacterGoldBonus != null) ? unusedCharacterGoldBonus.Panel : null);
GameObject[] array2 = (GameObject[])(object)array;
foreach (GameObject val4 in array2)
{
if ((Object)(object)val4 != (Object)null && (Object)(object)val4.transform.parent == (Object)(object)parent && val4.transform.GetSiblingIndex() > transform.GetSiblingIndex())
{
transform = val4.transform;
}
}
val3.transform.SetSiblingIndex(transform.GetSiblingIndex() + 1);
}
string text = (((Object)(object)difficultyGoldBonus.Text != (Object)null) ? RelativePath(val.transform, difficultyGoldBonus.Text.transform) : null);
foreach (TMP_Text componentsInChild in val3.GetComponentsInChildren<TMP_Text>(true))
{
if (text != null && RelativePath(val3.transform, componentsInChild.transform) == text)
{
foreach (LocalizeStringEvent component in ((Component)componentsInChild).GetComponents<LocalizeStringEvent>())
{
Object.DestroyImmediate((Object)(object)component);
}
valueText = componentsInChild;
}
else if ((Object)(object)val2 == (Object)null)
{
SettingsTab.BindText(componentsInChild, "bonus");
}
}
val3.SetActive(false);
return val3;
}
catch (Exception ex)
{
GoldXpMod.Log.Warning("[summary] bonus panel: " + ex.Message);
return null;
}
}
private static string RelativePath(Transform root, Transform t)
{
if ((Object)(object)t == (Object)(object)root)
{
return "";
}
StringBuilder stringBuilder = new StringBuilder(((Object)t).name);
while ((Object)(object)t.parent != (Object)null && (Object)(object)t.parent != (Object)(object)root)
{
t = t.parent;
stringBuilder.Insert(0, ((Object)t).name + "/");
}
return stringBuilder.ToString();
}
private static string FormatMult(float mult)
{
return "x" + mult.ToString("0.##", CultureInfo.InvariantCulture);
}
private static string Suffix(float mult)
{
return " <color=#FFD54A><size=75%>" + FormatMult(mult) + "</size></color>";
}
private static int ParseInt(string s)
{
if (string.IsNullOrEmpty(s))
{
return -1;
}
long num = 0L;
bool flag = false;
foreach (char c in s)
{
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
num = num * 10 + (c - 48);
flag = true;
if (num <= int.MaxValue)
{
continue;
}
return -1;
default:
continue;
case '<':
break;
}
break;
}
if (!flag)
{
return -1;
}
return (int)num;
}
private static string FormatLike(string sample, int value)
{
char? c = null;
if (!string.IsNullOrEmpty(sample))
{
for (int i = 1; i < sample.Length - 1; i++)
{
if (!char.IsDigit(sample[i]) && char.IsDigit(sample[i - 1]) && char.IsDigit(sample[i + 1]))
{
c = sample[i];
break;
}
}
}
string text = Math.Abs(value).ToString();
if (!c.HasValue || text.Length <= 3)
{
return ((value < 0) ? "-" : "") + text;
}
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < text.Length; j++)
{
if (j > 0 && (text.Length - j) % 3 == 0)
{
stringBuilder.Append(c.Value);
}
stringBuilder.Append(text[j]);
}
return ((value < 0) ? "-" : "") + stringBuilder;
}
}
internal static class SaveDoctor
{
private const int MaxSaneRank = 1000;
public static void RepairCorruptedRanks()
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: 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_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
Instance log = GoldXpMod.Log;
SaveManager instance = SingletonPersistent<SaveManager>.Instance;
LocalPlayer instance2 = SingletonPersistent<LocalPlayer>.Instance;
CharacterRankProgression val = ((instance2 != null) ? instance2.GetCharacterRankManager() : null);
Dictionary<CharacterId, CharacterRankProgress> val2 = ((val != null) ? val.RankProgressPerCharacter : null);
if ((Object)(object)instance == (Object)null || val2 == null)
{
return;
}
List<CharacterId> list = new List<CharacterId>();
Enumerator<CharacterId, CharacterRankProgress> enumerator = val2.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<CharacterId, CharacterRankProgress> current = enumerator.Current;
if (!IsSane(current.Value))
{
list.Add(current.Key);
}
}
if (list.Count == 0)
{
return;
}
List<(int, PlayerSaveData)> list2 = LoadAllSlots(instance);
foreach (CharacterId item3 in list)
{
string value = $"rank {val2[item3].CurrentRank} / progress {val2[item3].ProgressTowardsNextRank}";
int num = 1;
float num2 = 0f;
string value2 = "reset to rank 1 (no healthy save slot)";
foreach (var item4 in list2)
{
int item = item4.Item1;
PlayerSaveData item2 = item4.Item2;
Dictionary<CharacterId, CharacterRankProgress> rankProgressPerCharacter = item2.RankProgressPerCharacter;
if (rankProgressPerCharacter != null && rankProgressPerCharacter.ContainsKey(item3) && IsSane(rankProgressPerCharacter[item3]))
{
num = rankProgressPerCharacter[item3].CurrentRank;
num2 = rankProgressPerCharacter[item3].ProgressTowardsNextRank;
value2 = $"restored from save slot {item} ({item2.SaveTimestamp})";
break;
}
}
RankXp.Suspended = true;
try
{
val.SetRankProgression(item3, num, num2);
}
finally
{
RankXp.Suspended = false;
}
log.Warning($"[save] repaired {item3}: {value} → rank {num} / progress {num2} — {value2}");
}
instance.SavePlayerData();
log.Msg($"[save] repaired {list.Count} character rank(s) and saved");
}
private static bool IsSane(CharacterRankProgress p)
{
if (p != null && p.CurrentRank >= 0 && p.CurrentRank <= 1000 && p.Prestige >= 0 && p.Prestige <= 1000 && !float.IsNaN(p.ProgressTowardsNextRank) && !float.IsInfinity(p.ProgressTowardsNextRank) && p.ProgressTowardsNextRank >= 0f && p.ProgressTowardsNextRank <= 1f)
{
if (p.ProgressTowardsNextRank != 0f)
{
return p.ProgressTowardsNextRank >= 1E-06f;
}
return true;
}
return false;
}
private static List<(int slot, PlayerSaveData data)> LoadAllSlots(SaveManager saveManager)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
List<(int, PlayerSaveData)> list = new List<(int, PlayerSaveData)>();
for (int i = 0; i < SaveManager.SlotCount; i++)
{
try
{
IExternalSaveManager val = saveManager.CreateManagerForSlot(new RollingSaveSlot(i));
if (val != null && val.SaveExists())
{
PlayerSaveData val2 = val.Load<PlayerSaveData>(SaveManager.SaveKey);
if (val2 != null)
{
list.Add((i, val2));
}
}
}
catch (Exception ex)
{
GoldXpMod.Log.Warning($"[save] can't read slot {i}: {ex.GetType().Name}: {ex.Message}");
}
}
list.Sort(delegate((int, PlayerSaveData) a, (int, PlayerSaveData) b)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
DateTime saveTimestamp = b.Item2.SaveTimestamp;
long ticks = ((DateTime)(ref saveTimestamp)).Ticks;
saveTimestamp = a.Item2.SaveTimestamp;
return ticks.CompareTo(((DateTime)(ref saveTimestamp)).Ticks);
});
return list;
}
}
internal static class SettingsTab
{
private sealed class Row
{
public Selector Selector;
public Func<List<string>> Options;
public Func<string> Current;
public Action<string> Apply;
}
private const string ButtonName = "SBMod_Button";
private const string PanelName = "SBMod_Panel";
private static readonly float[] Presets = new float[16]
{
0.5f, 1f, 1.25f, 1.5f, 2f, 2.5f, 3f, 4f, 5f, 7.5f,
10f, 15f, 20f, 25f, 50f, 100f
};
private static readonly List<Row> Rows = new List<Row>();
private static bool _followsLanguage;
public static void InjectPrefix(SettingsPanel __instance)
{
try
{
Inject(__instance);
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[settings tab] inject failed: {value}");
}
}
private static void Inject(SettingsPanel settings)
{
//IL_03f1: 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_03fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0408: Expected O, but got Unknown
List<SubPanel> subPanels = settings.subPanels;
if (subPanels == null || subPanels.Count == 0)
{
return;
}
for (int i = 0; i < subPanels.Count; i++)
{
if ((Object)(object)subPanels[i].Panel != (Object)null && ((Object)subPanels[i].Panel).name == "SBMod_Panel")
{
return;
}
}
SubPanel val = null;
SubPanel val2 = null;
int num = subPanels.Count;
for (int j = 0; j < subPanels.Count; j++)
{
SubPanel val3 = subPanels[j];
if (!((Object)(object)val3.Button == (Object)null) && !((Object)(object)val3.Panel == (Object)null))
{
if (((Object)val3.Panel).name.StartsWith("General"))
{
val = val3;
}
if (((Object)val3.Button).name.StartsWith("Controls"))
{
val2 = val3;
}
if (((Object)val3.Button).name.StartsWith("Credits"))
{
num = j;
}
}
}
if (val == null)
{
val = subPanels[0];
}
if (val2 == null)
{
val2 = subPanels[0];
}
if (!_followsLanguage)
{
_followsLanguage = true;
Strings.OnLanguageChanged(delegate
{
MelonCoroutines.Start(RefreshNextFrame(onlyVisible: false));
});
}
GameObject val4 = Object.Instantiate<GameObject>(((Component)val2.Button).gameObject, ((Component)val2.Button).transform.parent);
((Object)val4).name = "SBMod_Button";
if (num < subPanels.Count)
{
val4.transform.SetSiblingIndex(((Component)subPanels[num].Button).transform.GetSiblingIndex());
}
BindText(val4.GetComponentInChildren<TMP_Text>(true), "tab");
MuteSerializedClicks(val4.GetComponent<Button>());
SelectableButton component = val4.GetComponent<SelectableButton>();
GameObject obj = Object.Instantiate<GameObject>(((Component)val.Panel).gameObject, ((Component)val.Panel).transform.parent);
((Object)obj).name = "SBMod_Panel";
obj.SetActive(false);
NavigateablePanel component2 = obj.GetComponent<NavigateablePanel>();
VerticalLayoutGroup componentInChildren = obj.GetComponentInChildren<VerticalLayoutGroup>(true);
Transform val5 = ((componentInChildren != null) ? ((Component)componentInChildren).transform : null) ?? throw new InvalidOperationException("row container not found");
Transform val6 = null;
for (int num2 = 0; num2 < val5.childCount; num2++)
{
if (!((Object)(object)val6 == (Object)null))
{
break;
}
Transform child = val5.GetChild(num2);
if (((Object)child).name.StartsWith("DamageNumbers"))
{
val6 = child;
}
}
for (int num3 = 0; num3 < val5.childCount; num3++)
{
if (!((Object)(object)val6 == (Object)null))
{
break;
}
Transform child2 = val5.GetChild(num3);
if ((Object)(object)((Component)child2).GetComponentInChildren<Selector>(true) != (Object)null)
{
val6 = child2;
}
}
if ((Object)(object)val6 == (Object)null)
{
throw new InvalidOperationException("selector row template not found");
}
val6.SetParent((Transform)null, false);
for (int num4 = val5.childCount - 1; num4 >= 0; num4--)
{
Object.DestroyImmediate((Object)(object)((Component)val5.GetChild(num4)).gameObject);
}
StripGameLogic(((Component)val6).gameObject);
List<Selectable> list = new List<Selectable>
{
AddToggleRow(val5, val6, "enabled", GoldXpMod._enabledEntry),
AddMultiplierRow(val5, val6, "gold", GoldXpMod._goldEntry),
AddMultiplierRow(val5, val6, "xp", GoldXpMod._xpEntry),
AddMultiplierRow(val5, val6, "rank", GoldXpMod._rankXpEntry)
};
for (int num5 = 0; num5 < list.Count; num5++)
{
SetExplicit(list[num5], (num5 > 0) ? list[num5 - 1] : null, (num5 < list.Count - 1) ? list[num5 + 1] : null, null, null);
}
AddHint(val5, val6);
Object.DestroyImmediate((Object)(object)((Component)val6).gameObject);
component2.firstSelected = ((Component)list[0]).gameObject;
RegisterInputReceivers(settings, ((Component)val.Panel).GetComponentInChildren<Selector>(true), list);
SubPanel val7 = new SubPanel
{
Button = component,
Panel = (Panel)(object)component2
};
subPanels.Insert(num, val7);
((ButtonInteractionHook)component).OnClicked += Action.op_Implicit((Action)delegate
{
MelonCoroutines.Start(RefreshNextFrame());
});
}
public static void LinkTabButtonsPostfix(SettingsPanel __instance)
{
try
{
List<SubPanel> subPanels = __instance.subPanels;
if (subPanels == null)
{
return;
}
List<Button> list = new List<Button>();
Selectable val = null;
for (int i = 0; i < subPanels.Count; i++)
{
Button val2 = (((Object)(object)subPanels[i].Button != (Object)null) ? ((Component)subPanels[i].Button).GetComponent<Button>() : null);
if ((Object)(object)val2 != (Object)null)
{
list.Add(val2);
}
if ((Object)(object)subPanels[i].Panel != (Object)null && ((Object)subPanels[i].Panel).name == "SBMod_Panel")
{
val = (Selectable)(object)((Component)subPanels[i].Panel).GetComponentInChildren<Selector>(true);
}
}
if (list.Count < 2)
{
return;
}
list.Sort((Button a, Button b) => ((Component)a).transform.GetSiblingIndex().CompareTo(((Component)b).transform.GetSiblingIndex()));
Selectable selectOnUp = ((Selectable)list[0]).navigation.selectOnUp;
Selectable selectOnDown = ((Selectable)list[list.Count - 1]).navigation.selectOnDown;
Selectable val3 = null;
foreach (Button item in list)
{
if (((Object)item).name != "SBMod_Button" && (Object)(object)((Selectable)item).navigation.selectOnRight != (Object)null)
{
val3 = ((Selectable)item).navigation.selectOnRight;
break;
}
}
for (int num = 0; num < list.Count; num++)
{
Navigation navigation = ((Selectable)list[num]).navigation;
bool flag = ((Object)list[num]).name == "SBMod_Button";
SetExplicit((Selectable)(object)list[num], (Selectable)((num > 0) ? ((object)list[num - 1]) : ((object)selectOnUp)), (Selectable)((num < list.Count - 1) ? ((object)list[num + 1]) : ((object)selectOnDown)), flag ? null : navigation.selectOnLeft, flag ? (((Object)(object)val3 != (Object)null) ? val : null) : navigation.selectOnRight);
}
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[settings tab] navigation: {value}");
}
}
private static void SetExplicit(Selectable s, Selectable up, Selectable down, Selectable left, Selectable right)
{
if (!((Object)(object)s == (Object)null))
{
Navigation navigation = s.navigation;
navigation.mode = (Mode)4;
navigation.selectOnUp = up;
navigation.selectOnDown = down;
navigation.selectOnLeft = left;
navigation.selectOnRight = right;
s.navigation = navigation;
}
}
private static void RegisterInputReceivers(SettingsPanel settings, Selector nativeSelector, List<Selectable> selectors)
{
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
List<UIPanel> list = new List<UIPanel>();
foreach (UIPanel item in ((Component)settings).GetComponentsInParent<UIPanel>(true))
{
list.Add(item);
}
foreach (UIPanel componentsInChild in ((Component)settings).GetComponentsInChildren<UIPanel>(true))
{
list.Add(componentsInChild);
}
UIPanel val = null;
if ((Object)(object)nativeSelector != (Object)null)
{
foreach (UIPanel item2 in list)
{
List<IUIInputReceiver> inputReceivers = item2.inputReceivers;
if (inputReceivers == null)
{
continue;
}
for (int i = 0; i < inputReceivers.Count; i++)
{
if (!((Object)(object)val == (Object)null))
{
break;
}
if (inputReceivers[i] != null && ((Il2CppObjectBase)inputReceivers[i]).Pointer == ((Il2CppObjectBase)nativeSelector).Pointer)
{
val = item2;
}
}
if ((Object)(object)val != (Object)null)
{
break;
}
}
}
if (val == null)
{
val = ((list.Count > 0) ? list[0] : null);
}
if ((Object)(object)val == (Object)null)
{
GoldXpMod.Log.Warning("[settings tab] no UIPanel — arrow keys won't change values");
return;
}
UIPanel val2 = val;
if (val2.inputReceivers == null)
{
List<IUIInputReceiver> val3 = (val2.inputReceivers = new List<IUIInputReceiver>());
}
UIInputRouter instance = SingletonPersistent<UIInputRouter>.Instance;
bool flag = false;
if (((instance != null) ? instance.currentReceivers : null) != null && (Object)(object)nativeSelector != (Object)null)
{
for (int j = 0; j < instance.currentReceivers.Count; j++)
{
if (instance.currentReceivers[j] != null && ((Il2CppObjectBase)instance.currentReceivers[j]).Pointer == ((Il2CppObjectBase)nativeSelector).Pointer)
{
flag = true;
}
}
}
foreach (Selectable selector in selectors)
{
IUIInputReceiver val5 = (IUIInputReceiver)(((object)((Il2CppObjectBase)selector).TryCast<IUIInputReceiver>()) ?? ((object)new IUIInputReceiver(((Il2CppObjectBase)selector).Pointer)));
val.inputReceivers.Add(val5);
if (flag)
{
instance.Register(val5);
}
}
}
private static Selectable AddToggleRow(Transform container, Transform template, string labelKey, MelonPreferences_Entry<bool> entry)
{
return AddRow(container, template, labelKey, new Row
{
Options = () => new List<string>
{
Strings.Get("on"),
Strings.Get("off")
},
Current = () => Strings.Get(entry.Value ? "on" : "off"),
Apply = delegate(string option)
{
Store(entry, option == Strings.Get("on"));
}
});
}
private static Selectable AddMultiplierRow(Transform container, Transform template, string labelKey, MelonPreferences_Entry<float> entry)
{
return AddRow(container, template, labelKey, new Row
{
Options = delegate
{
List<float> list = new List<float>(Presets);
if (!list.Contains(entry.Value))
{
list.Add(entry.Value);
list.Sort();
}
return list.ConvertAll<string>(Format);
},
Current = () => Format(entry.Value),
Apply = delegate(string option)
{
if (float.TryParse(option.TrimStart('x'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
Store(entry, result);
}
}
});
}
private static Selectable AddRow(Transform container, Transform template, string labelKey, Row row)
{
GameObject obj = Object.Instantiate<GameObject>(((Component)template).gameObject, container);
((Object)obj).name = "SBMod_" + labelKey;
obj.SetActive(true);
Selector componentInChildren = obj.GetComponentInChildren<Selector>(true);
foreach (TMP_Text componentsInChild in obj.GetComponentsInChildren<TMP_Text>(true))
{
if (!componentsInChild.transform.IsChildOf(((Component)componentInChildren).transform))
{
BindText(componentsInChild, labelKey);
}
}
componentInChildren.localizationMode = (LocalizationMode)2;
if ((Object)(object)componentInChildren.valueLocalizeString != (Object)null)
{
((Behaviour)componentInChildren.valueLocalizeString).enabled = false;
}
row.Selector = componentInChildren;
componentInChildren.OnOptionSelected += Action<string>.op_Implicit((Action<string>)delegate(string option)
{
try
{
row.Apply(option);
}
catch (Exception value)
{
GoldXpMod.Log.Error($"[settings tab] {value}");
}
});
Rows.Add(row);
Show(row);
return (Selectable)(object)componentInChildren;
}
private static void AddHint(Transform container, Transform template)
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(((Component)template).gameObject, container);
((Object)obj).name = "SBMod_Hint";
obj.SetActive(true);
Object.DestroyImmediate((Object)(object)((Component)obj.GetComponentInChildren<Selector>(true)).gameObject);
TMP_Text componentInChildren = obj.GetComponentInChildren<TMP_Text>(true);
BindText(componentInChildren, "hint");
componentInChildren.fontSize *= 0.7f;
componentInChildren.alignment = (TextAlignmentOptions)257;
RectTransform rectTransform = componentInChildren.rectTransform;
rectTransform.sizeDelta = new Vector2(0f, 140f);
rectTransform.anchoredPosition = new Vector2(0f, -40f);
}
private static IEnumerator RefreshNextFrame(bool onlyVisible = true)
{
yield return null;
Rows.RemoveAll((Row r) => (Object)(object)r.Selector == (Object)null);
foreach (Row row in Rows)
{
if (!onlyVisible || ((Behaviour)row.Selector).isActiveAndEnabled)
{
Show(row);
}
}
}
private static void Show(Row row)
{
List<string> val = new List<string>();
foreach (string item in row.Options())
{
val.Add(item);
}
string text = row.Current();
row.Selector.SetOptions(val);
row.Selector.SetSelectedOption(text);
row.Selector.SetNonLocalizedValueText(text);
}
private static void Store<T>(MelonPreferences_Entry<T> entry, T value)
{
if (!object.Equals(entry.Value, value))
{
entry.Value = value;
GoldXpMod.SaveSettings();
}
}
private static string Format(float v)
{
return "x" + v.ToString("0.##", CultureInfo.InvariantCulture);
}
internal static void BindText(TMP_Text text, string key)
{
if ((Object)(object)text == (Object)null)
{
return;
}
foreach (LocalizeStringEvent component in ((Component)text).GetComponents<LocalizeStringEvent>())
{
Object.DestroyImmediate((Object)(object)component);
}
Strings.Bind(text, key);
}
private static void StripGameLogic(GameObject row)
{
foreach (MonoBehaviour component in row.GetComponents<MonoBehaviour>())
{
if (((MemberInfo)((Object)component).GetIl2CppType()).Name != "Image")
{
Object.DestroyImmediate((Object)(object)component);
}
}
foreach (TextReplacer componentsInChild in row.GetComponentsInChildren<TextReplacer>(true))
{
Object.DestroyImmediate((Object)(object)componentsInChild);
}
}
private static void MuteSerializedClicks(Button button)
{
if (!((Object)(object)button == (Object)null))
{
for (int i = 0; i < ((UnityEventBase)button.onClick).GetPersistentEventCount(); i++)
{
((UnityEventBase)button.onClick).SetPersistentListenerState(i, (UnityEventCallState)0);
}
}
}
}
internal static class SharedCodeGuard
{
private static Dictionary<IntPtr, List<IntPtr>> _methodsByCode;
public static List<string> FindMethodsSharingCode(MethodBase generatedMethod)
{
List<string> list = new List<string>();
if (!(Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(generatedMethod)?.GetValue(null) is IntPtr intPtr) || intPtr == IntPtr.Zero)
{
return list;
}
IntPtr intPtr2 = Marshal.ReadIntPtr(intPtr);
if (intPtr2 == IntPtr.Zero)
{
return list;
}
if (_methodsByCode == null)
{
_methodsByCode = BuildIndex();
}
if (!_methodsByCode.TryGetValue(intPtr2, out var value))
{
return list;
}
foreach (IntPtr item in value)
{
if (item != intPtr)
{
list.Add(Describe(item));
}
}
return list;
}
private static string Describe(IntPtr method)
{
IntPtr intPtr = IL2CPP.il2cpp_method_get_class(method);
string text = IL2CPP.il2cpp_class_get_namespace_(intPtr);
return (string.IsNullOrEmpty(text) ? IL2CPP.il2cpp_class_get_name_(intPtr) : (text + "." + IL2CPP.il2cpp_class_get_name_(intPtr))) + "::" + IL2CPP.il2cpp_method_get_name_(method);
}
private unsafe static Dictionary<IntPtr, List<IntPtr>> BuildIndex()
{
Dictionary<IntPtr, List<IntPtr>> dictionary = new Dictionary<IntPtr, List<IntPtr>>();
uint num = 0u;
IntPtr* ptr = IL2CPP.il2cpp_domain_get_assemblies(IL2CPP.il2cpp_domain_get(), ref num);
for (uint num2 = 0u; num2 < num; num2++)
{
IntPtr intPtr = IL2CPP.il2cpp_assembly_get_image(ptr[num2]);
uint num3 = IL2CPP.il2cpp_image_get_class_count(intPtr);
for (uint num4 = 0u; num4 < num3; num4++)
{
IntPtr intPtr2 = IL2CPP.il2cpp_image_get_class(intPtr, num4);
if (intPtr2 == IntPtr.Zero)
{
continue;
}
IntPtr zero = IntPtr.Zero;
IntPtr intPtr3;
while ((intPtr3 = IL2CPP.il2cpp_class_get_methods(intPtr2, ref zero)) != IntPtr.Zero)
{
IntPtr intPtr4 = Marshal.ReadIntPtr(intPtr3);
if (!(intPtr4 == IntPtr.Zero))
{
if (!dictionary.TryGetValue(intPtr4, out var value))
{
value = (dictionary[intPtr4] = new List<IntPtr>(1));
}
value.Add(intPtr3);
}
}
}
}
return dictionary;
}
}
internal static class Strings
{
public const string Tab = "tab";
public const string Enabled = "enabled";
public const string On = "on";
public const string Off = "off";
public const string Gold = "gold";
public const string Xp = "xp";
public const string RankXp = "rank";
public const string Hint = "hint";
public const string Bonus = "bonus";
private static readonly string[] Keys = new string[9] { "tab", "enabled", "on", "off", "gold", "xp", "rank", "hint", "bonus" };
private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
{
["en"] = new string[9] { "Multipliers", "Mod Enabled", "On", "Off", "Gold per Run", "Run XP", "Wizard Rank XP", "Changes apply immediately. x1 = vanilla.\nIn co-op, run XP works when the host has the mod.", "Mod multiplier" },
["ru"] = new string[9] { "Множители", "Мод включён", "Вкл", "Выкл", "Золото за забег", "Опыт в забеге", "Опыт мага (ранг)", "Изменения применяются сразу. x1 — как в оригинале.\nОпыт в забеге в коопе работает, если мод стоит у хоста.", "Множитель мода" },
["uk"] = new string[9] { "Множники", "Мод увімкнено", "Увімк", "Вимк", "Золото за забіг", "Досвід у забігу", "Досвід мага (ранг)", "Зміни застосовуються одразу. x1 — як в оригіналі.\nДосвід у забігу в кооперативі працює, якщо мод встановлено в хоста.", "Множник мода" },
["de"] = new string[9] { "Multiplikatoren", "Mod aktiviert", "An", "Aus", "Gold pro Durchlauf", "EP im Durchlauf", "Magier-Rang-EP", "Änderungen gelten sofort. x1 = Original.\nIm Koop wirken die EP im Durchlauf, wenn der Host die Mod hat.", "Mod-Multiplikator" },
["fr"] = new string[9] { "Multiplicateurs", "Mod activé", "Activé", "Désactivé", "Or par partie", "XP de partie", "XP de rang du mage", "Les changements s'appliquent immédiatement. x1 = jeu d'origine.\nEn coop, l'XP de partie fonctionne si l'hôte a le mod.", "Multiplicateur du mod" },
["it"] = new string[9] { "Moltiplicatori", "Mod attiva", "Attivo", "Disattivo", "Oro per partita", "PE della partita", "PE rango mago", "Le modifiche si applicano subito. x1 = originale.\nIn co-op, i PE della partita funzionano se l'host ha la mod.", "Moltiplicatore mod" },
["nl"] = new string[9] { "Vermenigvuldigers", "Mod ingeschakeld", "Aan", "Uit", "Goud per run", "Run-XP", "Tovenaarsrang-XP", "Wijzigingen gelden direct. x1 = origineel.\nIn co-op werkt run-XP als de host de mod heeft.", "Mod-vermenigvuldiger" },
["pl"] = new string[9] { "Mnożniki", "Mod włączony", "Wł.", "Wył.", "Złoto za wyprawę", "PD w wyprawie", "PD rangi maga", "Zmiany działają od razu. x1 = oryginał.\nW trybie co-op PD w wyprawie działa, jeśli host ma moda.", "Mnożnik moda" },
["pt-br"] = new string[9] { "Multiplicadores", "Mod ativado", "Ligado", "Desligado", "Ouro por partida", "XP da partida", "XP de nível do mago", "As mudanças valem na hora. x1 = original.\nNo co-op, o XP da partida funciona se o anfitrião tiver o mod.", "Multiplicador do mod" },
["pt"] = new string[9] { "Multiplicadores", "Mod ativado", "Ligado", "Desligado", "Ouro por partida", "XP da partida", "XP de nível do mago", "As alterações aplicam-se de imediato. x1 = original.\nNo co-op, o XP da partida funciona se o anfitrião tiver o mod.", "Multiplicador do mod" },
["es"] = new string[9] { "Multiplicadores", "Mod activado", "Activado", "Desactivado", "Oro por partida", "XP de la partida", "XP de rango del mago", "Los cambios se aplican al instante. x1 = original.\nEn cooperativo, la XP de la partida funciona si el anfitrión tiene el mod.", "Multiplicador del mod" },
["ja"] = new string[9] { "倍率", "MOD有効", "オン", "オフ", "ラン毎のゴールド", "ラン中の経験値", "魔法使いランク経験値", "変更はすぐに反映されます。x1 = オリジナル。\n協力プレイでは、ホストがMODを導入している場合にラン中の経験値が有効です。", "MOD倍率" },
["ko"] = new string[9] { "배율", "모드 활성화", "켜기", "끄기", "런당 골드", "런 경험치", "마법사 랭크 경험치", "변경 사항은 즉시 적용됩니다. x1 = 원본.\n협동 플레이에서는 호스트에게 모드가 있어야 런 경험치가 적용됩니다.", "모드 배율" },
["zh-hans"] = new string[9] { "倍率", "启用模组", "开", "关", "每局金币", "局内经验", "法师等级经验", "更改立即生效。x1 = 原版。\n联机时,房主安装了模组,局内经验倍率才会生效。", "模组倍率" },
["zh-hant"] = new string[9] { "倍率", "啟用模組", "開", "關", "每局金幣", "局內經驗", "法師等級經驗", "變更立即生效。x1 = 原版。\n連線時,房主安裝了模組,局內經驗倍率才會生效。", "模組倍率" },
["th"] = new string[9] { "ต\u0e31วค\u0e39ณ", "เป\u0e34ดใช\u0e49ม\u0e47อด", "เป\u0e34ด", "ป\u0e34ด", "ทองต\u0e48อรอบ", "EXP ในรอบ", "EXP แรงค\u0e4cน\u0e31กเวทย\u0e4c", "การเปล\u0e35\u0e48ยนแปลงม\u0e35ผลท\u0e31นท\u0e35 x1 = ค\u0e48าเด\u0e34ม\nในโหมดเล\u0e48นร\u0e48วมก\u0e31น EXP ในรอบจะทำงานเม\u0e37\u0e48อโฮสต\u0e4cต\u0e34ดต\u0e31\u0e49งม\u0e47อด", "ต\u0e31วค\u0e39ณของม\u0e47อด" }
};
private static string[] _current;
private static readonly Dictionary<string, bool> FontSupport = new Dictionary<string, bool>();
private static readonly List<(TMP_Text text, string key)> Bound = new List<(TMP_Text, string)>();
private static readonly List<Action> Listeners = new List<Action>();
private static bool _subscribed;
public static string Get(string key)
{
if (_current == null)
{
_current = Resolve(null);
}
int num = Array.IndexOf(Keys, key);
if (num < 0)
{
return key;
}
return _current[num];
}
public static void Bind(TMP_Text text, string key, TMP_Text fontSample = null)
{
if (!((Object)(object)text == (Object)null))
{
EnsureSubscribed();
if (_current == null)
{
_current = Resolve(fontSample ?? text);
}
text.text = Get(key);
Bound.Add((text, key));
}
}
public static void OnLanguageChanged(Action listener)
{
EnsureSubscribed();
Listeners.Add(listener);
}
private static void EnsureSubscribed()
{
if (_subscribed)
{
return;
}
_subscribed = true;
try
{
LocalizationSettings.SelectedLocaleChanged += Action<Locale>.op_Implicit((Action<Locale>)delegate
{
Refresh();
});
}
catch (Exception ex)
{
GoldXpMod.Log.Warning("[lang] can't follow language changes: " + ex.Message);
}
}
private static void Refresh()
{
TMP_Text fontSample = null;
Bound.RemoveAll(((TMP_Text text, string key) b) => (Object)(object)b.text == (Object)null);
using (List<(TMP_Text, string)>.Enumerator enumerator = Bound.GetEnumerator())
{
if (enumerator.MoveNext())
{
fontSample = enumerator.Current.Item1;
}
}
_current = Resolve(fontSample);
foreach (var (val, key) in Bound)
{
val.text = Get(key);
}
foreach (Action listener in Listeners)
{
try
{
listener();
}
catch (Exception ex)
{
GoldXpMod.Log.Warning("[lang] " + ex.Message);
}
}
}
private static string[] Resolve(TMP_Text fontSample)
{
string text = "en";
try
{
Locale selectedLocale = LocalizationSettings.SelectedLocale;
text = ((selectedLocale != null) ? selectedLocale.Identifier.Code : null) ?? "en";
}
catch
{
}
string text2 = TableKey(text);
string[] array = Table[text2];
if (text2 != "en" && (Object)(object)fontSample != (Object)null && !FontHasAll(fontSample, text2, array))
{
GoldXpMod.Log.Warning("[lang] font lacks glyphs for '" + text + "', using English");
text2 = "en";
array = Table[text2];
}
return array;
}
private static string TableKey(string code)
{
code = code.ToLowerInvariant().Replace('_', '-');
if (code.StartsWith("zh"))
{
if (!code.Contains("hant") && !code.Contains("tw") && !code.Contains("hk"))
{
return "zh-hans";
}
return "zh-hant";
}
if (code.StartsWith("pt"))
{
if (!code.Contains("br"))
{
return "pt";
}
return "pt-br";
}
string text = code.Split('-')[0];
if (!Table.ContainsKey(text))
{
return "en";
}
return text;
}
private static bool FontHasAll(TMP_Text sample, string key, string[] table)
{
if (FontSupport.TryGetValue(key, out var value))
{
return value;
}
value = true;
try
{
TMP_FontAsset font = sample.font;
if ((Object)(object)font != (Object)null)
{
foreach (string text in table)
{
foreach (char c in text)
{
if (c > '\u007f' && !char.IsWhiteSpace(c) && !font.HasCharacter(c, true, true))
{
value = false;
break;
}
}
}
}
}
catch
{
value = true;
}
FontSupport[key] = value;
return value;
}
}
}