using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using FishNet; using FishNet.Connection; using FishNet.Managing.Server; using FishNet.Object; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Utilities; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [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 HtfExpanded { public static class Ascension { private static int _level; public static int Level { get { return _level; } set { _level = Mathf.Max(0, value); } } public static int MaxLevel { get { Cfg.EnsureLoaded(); if (Cfg.AscensionMaxLevel > 0) { return Cfg.AscensionMaxLevel; } int i = 0; double num = Cfg.AscensionBaseCost; for (; i < 200; i++) { if (!(num * (double)Cfg.AscensionCostGrowth <= 2147483647.0)) { break; } num *= (double)Cfg.AscensionCostGrowth; } return i; } } public static bool AtMaxLevel => _level >= MaxLevel; public static bool Unlocked { get { try { if ((Object)(object)EndGameManager.Instance != (Object)null && EndGameManager.Instance.HasFinishedGame) { return true; } return SaveManager.CurServerSave?.HasFinishedGame ?? false; } catch { return false; } } } public static float HpMultiplier() { Cfg.EnsureLoaded(); if (_level <= 0) { return 1f; } double num = Math.Pow(Cfg.AscensionHpGrowth, _level); return (num > 1000000000.0) ? 1E+09f : ((float)num); } public static float ValueMultiplier() { Cfg.EnsureLoaded(); if (_level <= 0) { return 1f; } double num = Math.Pow(Cfg.AscensionValueGrowth, _level); return (num > 1000000000.0) ? 1E+09f : ((float)num); } public static int LuckBonus() { Cfg.EnsureLoaded(); return _level * Cfg.AscensionLuckBonus; } public static int ScaleHp(int baseHp) { try { if (_level <= 0 || baseHp <= 0) { return baseHp; } double num = (double)baseHp * (double)HpMultiplier(); if (num >= 2147483647.0) { return int.MaxValue; } return (int)num; } catch (Exception e) { Log.Ex("Ascension.ScaleHp", e); return baseHp; } } public static int CostForNextLevel() { Cfg.EnsureLoaded(); if (AtMaxLevel) { return -1; } double num = (double)Cfg.AscensionBaseCost * Math.Pow(Cfg.AscensionCostGrowth, _level); if (num >= 2147483647.0) { return -1; } return (int)num; } public static bool TryBuy(Player buyer) { try { Cfg.EnsureLoaded(); if (!Cfg.EnableAscension) { Log.Info("ascension purchase refused: disabled in the config"); return false; } if (!Unlocked) { Log.Info("ascension purchase refused: the game has not been finished on this save yet"); return false; } int num = CostForNextLevel(); if (num < 0) { Log.Info("ascension purchase refused: already at the top tier (" + MaxLevel + ")"); return false; } if (!MoneyManager.CanAfford(num)) { Log.Info("ascension purchase refused: cannot afford $" + num); return false; } MoneyManager.RemoveMoney(num, buyer); Level = _level + 1; Luck.SaveForCurrentSave(); Net.BroadcastState(); Log.Info("ascension purchased, now tier " + _level + " (creature health x" + HpMultiplier().ToString("0.#") + ", fish value x" + ValueMultiplier().ToString("0.#") + ", +" + LuckBonus() + " luck)"); return true; } catch (Exception e) { Log.Ex("Ascension.TryBuy", e); return false; } } } public static class Assets { private const string ResourcePrefix = "HtfExpanded.Assets."; private static string[] _searchDirs; private static string _lastSource = ""; public static string ModelDir => Cfg.Dir + "/HowToFishExpanded/models"; public static string[] SearchDirs { get { if (_searchDirs != null) { return _searchDirs; } List list = new List(); try { list.Add(ModelDir); } catch { } try { DirectoryInfo parent = Directory.GetParent(Application.dataPath); if (parent != null) { list.Add(parent.FullName + "/models"); } } catch { } try { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { string directoryName = Path.GetDirectoryName(location); if (!string.IsNullOrEmpty(directoryName)) { list.Add(directoryName + "/models"); } } } catch { } _searchDirs = list.ToArray(); return _searchDirs; } } public static string LastSource => _lastSource; public static void EnsureDir() { try { if (!Directory.Exists(ModelDir)) { Directory.CreateDirectory(ModelDir); } } catch (Exception e) { Log.Ex("Assets.EnsureDir", e); } } public static byte[] Read(string relative) { byte[] array = FromDisk(relative) ?? Inflate(FromDisk(relative + ".gz")); if (array != null) { return array; } byte[] array2 = FromResource(relative) ?? Inflate(FromResource(relative + ".gz")); if (array2 != null) { _lastSource = "the copy built into the mod"; } return array2; } public static string ReadText(string relative) { byte[] array = Read(relative); if (array == null) { return null; } try { return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetString(array); } catch (Exception e) { Log.Ex("Assets.ReadText(" + relative + ")", e); return null; } } public static bool Exists(string relative) { return Read(relative) != null; } public static bool IsEmbedded(string relative) { return FromResource(relative) != null || FromResource(relative + ".gz") != null; } private static byte[] FromDisk(string relative) { string[] searchDirs = SearchDirs; for (int i = 0; i < searchDirs.Length; i++) { try { string path = searchDirs[i] + "/" + relative; if (!File.Exists(path)) { continue; } _lastSource = searchDirs[i]; return File.ReadAllBytes(path); } catch (Exception e) { Log.Ex("Assets.FromDisk(" + relative + ")", e); } } return null; } private static byte[] FromResource(string relative) { try { string name = "HtfExpanded.Assets." + relative.Replace('/', '.'); using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } return array; } catch (Exception e) { Log.Ex("Assets.FromResource(" + relative + ")", e); return null; } } private static byte[] Inflate(byte[] compressed) { if (compressed == null) { return null; } try { using MemoryStream stream = new MemoryStream(compressed); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[16384]; int count; while ((count = gZipStream.Read(array, 0, array.Length)) > 0) { memoryStream.Write(array, 0, count); } return memoryStream.ToArray(); } catch (Exception ex) { Log.Warn("could not decompress an asset: " + ex.Message); return null; } } public static Texture2D LoadTexture(string relative) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown byte[] array = Read(relative); if (array == null) { return null; } try { Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true); if (!ImageConversion.LoadImage(val, array)) { Object.Destroy((Object)(object)val); Log.Warn("'" + relative + "' is not an image the game can read"); return null; } ((Object)val).name = relative; ((Texture)val).filterMode = (FilterMode)(!Cfg.ModelPointFilter); ((Texture)val).wrapMode = (TextureWrapMode)0; val.Apply(true, false); return val; } catch (Exception e) { Log.Ex("Assets.LoadTexture(" + relative + ")", e); return null; } } } public sealed class StoredItem { public byte ItemID; public float Weight = 1f; public float Cookness; public float BettingMultiplier; public float KillScoreMultiplier; public bool IsDripCreature; public byte SkinIndex; public byte Sharpness; public byte Sight; public byte BarrelAttachment; public byte AmmoType; public bool ExtendedMag; public bool LaserSight; public string Label = "?"; public int Worth; public int Tier { get { try { return Variants.TierForWeight(Weight); } catch { return 0; } } } } public static class Backpack { public static readonly List Items = new List(); private static string _saveName = ""; private static MethodInfo _toSavedItem; private static MethodInfo _getTotalSlots; private static FieldInfo _playerField; private static bool _reflectionWarned; public static readonly List RemoteItems = new List(); private const char EntrySep = '~'; private const char FieldSep = '|'; public static bool IsFull => Items.Count >= Capacity(); private static string ModFolder => Luck.ModFolder; public static int RemotePage { get; private set; } public static int RemoteCount { get; private set; } public static int RemoteCapacity { get; private set; } public static int Capacity() { Cfg.EnsureLoaded(); if (!Cfg.EnableBackpack) { return 0; } int num = Mathf.Max(0, Ascension.Level) * Mathf.Max(0, Cfg.BackpackSlotsPerAscension); return Mathf.Clamp(Cfg.BackpackSlots + num, 0, Cfg.BackpackMaxSlots); } public static int HotbarSlots(PlayerInventory inv) { try { if ((Object)(object)inv == (Object)null) { return 0; } if (_getTotalSlots == null) { _getTotalSlots = typeof(PlayerInventory).GetMethod("GetTotalSlots", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_getTotalSlots == null) { return 0; } return (int)_getTotalSlots.Invoke(inv, null); } catch (Exception e) { Log.Ex("Backpack.HotbarSlots", e); return 0; } } public static Player PlayerOf(PlayerInventory inv) { try { if ((Object)(object)inv == (Object)null) { return null; } if (_playerField == null) { _playerField = typeof(PlayerInventory).GetField("_player", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (_playerField != null) { object? value = _playerField.GetValue(inv); Player val = (Player)((value is Player) ? value : null); if ((Object)(object)val != (Object)null) { return val; } } return ((Component)inv).GetComponentInParent(); } catch (Exception e) { Log.Ex("Backpack.PlayerOf", e); return null; } } public static Item HotbarItem(PlayerInventory inv, int slot) { try { if ((Object)(object)inv == (Object)null || slot < 0 || slot > 255) { return null; } Item val = default(Item); return inv._items.TryGetValue((byte)slot, ref val) ? val : null; } catch { return null; } } public static int FirstFreeHotbarSlot(PlayerInventory inv) { int num = HotbarSlots(inv); for (int i = 0; i < num; i++) { if ((Object)(object)HotbarItem(inv, i) == (Object)null) { return i; } } return -1; } private static SavedItem Describe(Item item, byte slot) { try { if (_toSavedItem == null) { _toSavedItem = typeof(SaveManager).GetMethod("ItemToSavedItem", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(byte), typeof(Item) }, null); } if (_toSavedItem == null) { if (!_reflectionWarned) { _reflectionWarned = true; Log.Warn("storage is read-only on this build of the game: SaveManager.ItemToSavedItem is not there, so an item cannot be described without risking losing part of it. Taking things out still works."); } return null; } object? obj = _toSavedItem.Invoke(null, new object[2] { slot, item }); return (SavedItem)((obj is SavedItem) ? obj : null); } catch (Exception e) { Log.Ex("Backpack.Describe", e); return null; } } private static StoredItem FromSaved(SavedItem s, Item live) { StoredItem storedItem = new StoredItem(); storedItem.ItemID = s.ItemID; storedItem.Weight = s.Weight; storedItem.Cookness = s.Cookness; storedItem.BettingMultiplier = s.BettingMultiplier; storedItem.KillScoreMultiplier = s.KillScoreMultiplier; storedItem.IsDripCreature = s.IsDripCreature; storedItem.SkinIndex = s.SkinIndex; storedItem.Sharpness = s.Sharpness; storedItem.Sight = s.Sight; storedItem.BarrelAttachment = s.BarrelAttachment; storedItem.AmmoType = s.AmmoType; storedItem.ExtendedMag = s.ExtendedMag; storedItem.LaserSight = s.LaserSight; try { storedItem.Label = (((Object)(object)live != (Object)null) ? live.GetName() : "?"); } catch { storedItem.Label = "?"; } try { storedItem.Worth = (((Object)(object)live != (Object)null) ? live.TotalWorth : 0); } catch { storedItem.Worth = 0; } if (string.IsNullOrEmpty(storedItem.Label)) { storedItem.Label = "?"; } return storedItem; } private static SavedItem ToSaved(StoredItem r, byte slot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown SavedItem val = new SavedItem(); val.Exists = true; val.InventorySlot = slot; val.ItemID = r.ItemID; val.Weight = r.Weight; val.Cookness = r.Cookness; val.BettingMultiplier = r.BettingMultiplier; val.KillScoreMultiplier = r.KillScoreMultiplier; val.IsDripCreature = r.IsDripCreature; val.SkinIndex = r.SkinIndex; val.Sharpness = r.Sharpness; val.Sight = r.Sight; val.BarrelAttachment = r.BarrelAttachment; val.AmmoType = r.AmmoType; val.ExtendedMag = r.ExtendedMag; val.LaserSight = r.LaserSight; return val; } public static bool Deposit(PlayerInventory inv, int slot, out string why) { why = ""; try { Cfg.EnsureLoaded(); if (!Cfg.EnableBackpack) { why = "Storage is switched off in the config."; return false; } if (!Net.IsServer) { why = "Only the host can move things in and out of storage."; return false; } if ((Object)(object)inv == (Object)null) { why = "No inventory."; return false; } if (IsFull) { why = "Storage is full (" + Items.Count + "/" + Capacity() + ")."; return false; } Item val = HotbarItem(inv, slot); if ((Object)(object)val == (Object)null) { why = "That slot is empty."; return false; } Item val2 = null; try { val2 = inv.SyncedCurItem; } catch { } if ((Object)(object)val2 != (Object)null && (Object)(object)val2 == (Object)(object)val) { why = "You are holding that - press its number again to put it away first."; return false; } SavedItem val3 = Describe(val, (byte)slot); if (val3 == null) { why = "This build of the game will not let the mod describe that item safely, so it was left alone."; return false; } StoredItem storedItem = FromSaved(val3, val); Items.Add(storedItem); SaveNow(); inv.RemoveItem(val); DespawnItem(val); Log.Info("stored " + storedItem.Label + " at " + storedItem.Weight.ToString("0.000") + "x (" + Items.Count + "/" + Capacity() + ")"); return true; } catch (Exception e) { Log.Ex("Backpack.Deposit", e); why = "Something went wrong storing that - see the log."; return false; } } public static int DepositAll(PlayerInventory inv, out string why) { why = ""; int num = 0; try { int num2 = HotbarSlots(inv); Item val = null; try { val = inv.SyncedCurItem; } catch { } for (int i = 0; i < num2; i++) { if (IsFull) { break; } Item val2 = HotbarItem(inv, i); if (!((Object)(object)val2 == (Object)null) && (!((Object)(object)val != (Object)null) || !((Object)(object)val2 == (Object)(object)val))) { if (!Deposit(inv, i, out var why2)) { why = why2; break; } num++; } } if (num == 0 && why.Length == 0) { why = "Nothing to stow."; } } catch (Exception e) { Log.Ex("Backpack.DepositAll", e); why = "Something went wrong - see the log."; } return num; } private static void DespawnItem(Item item) { try { if (!((Object)(object)item == (Object)null)) { GameObject gameObject = ((Component)item).gameObject; ServerManager serverManager = InstanceFinder.ServerManager; if ((Object)(object)serverManager != (Object)null) { serverManager.Despawn(gameObject, (DespawnType?)null); } else { Object.Destroy((Object)(object)gameObject); } } } catch (Exception e) { Log.Ex("Backpack.DespawnItem", e); } } public static bool Withdraw(PlayerInventory inv, int index, out string why) { //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) why = ""; try { Cfg.EnsureLoaded(); if (!Net.IsServer) { why = "Only the host can move things in and out of storage."; return false; } if ((Object)(object)inv == (Object)null) { why = "No inventory."; return false; } if (index < 0 || index >= Items.Count) { why = "Nothing there."; return false; } int num = FirstFreeHotbarSlot(inv); if (num < 0) { why = "No free inventory slot - drop or sell something first."; return false; } StoredItem storedItem = Items[index]; Item spawnable = GameInfo.GetSpawnable(storedItem.ItemID); if ((Object)(object)spawnable == (Object)null) { why = "The game does not have that item any more (id " + storedItem.ItemID + ")."; return false; } Player val = PlayerOf(inv); Vector3 val2 = (((Object)(object)val != (Object)null && (Object)(object)val.Transform != (Object)null) ? val.Transform.position : Vector3.zero); Item val3 = Object.Instantiate(spawnable, val2, Quaternion.identity); if ((Object)(object)val3 == (Object)null) { why = "Could not create that item."; return false; } if ((Object)(object)val != (Object)null) { val3.SetSyncedHolder(val, true); } val3.LoadFromSave(ToSaved(storedItem, (byte)num)); Creature val4 = null; try { val4 = val3.Creature; } catch { } if ((Object)(object)val4 != (Object)null) { Log.Info("withdraw " + storedItem.Label + ": stored " + storedItem.Weight.ToString("0.000") + "x, after LoadFromSave " + ((Item)val4).RandomizedWeight.ToString("0.000") + "x"); val4.ServerKillOnSpawn(); if (storedItem.IsDripCreature) { val4.SetDrip(); } } ServerManager serverManager = InstanceFinder.ServerManager; if ((Object)(object)serverManager == (Object)null) { Object.Destroy((Object)(object)((Component)val3).gameObject); why = "The server is not running."; return false; } serverManager.Spawn(((Component)val3).gameObject, (NetworkConnection)null, default(Scene)); if ((Object)(object)val4 != (Object)null) { Log.Info("withdraw " + storedItem.Label + ": after spawn " + ((Item)val4).RandomizedWeight.ToString("0.000") + "x"); } inv.AddItem((byte)num, val3); Items.RemoveAt(index); SaveNow(); Log.Info("took " + storedItem.Label + " out of storage into slot " + (num + 1) + " (" + Items.Count + "/" + Capacity() + ")"); return true; } catch (Exception e) { Log.Ex("Backpack.Withdraw", e); why = "Something went wrong taking that out - see the log."; return false; } } private static string PathFor(string saveName) { return ModFolder + "/" + saveName + ".backpack.dat"; } private static string CurrentSaveName() { try { ServerSaveObject curServerSave = SaveManager.CurServerSave; return (curServerSave != null && !string.IsNullOrEmpty(curServerSave.Name)) ? curServerSave.Name : ""; } catch { return ""; } } public static void LoadForCurrentSave() { try { Cfg.EnsureLoaded(); _saveName = CurrentSaveName(); Items.Clear(); if (!string.IsNullOrEmpty(_saveName)) { string path = PathFor(_saveName); if (File.Exists(path)) { ReadFile(path); } Log.Info("storage: " + Items.Count + " item(s) held for save '" + _saveName + "' (capacity " + Capacity() + ")"); } } catch (Exception e) { Log.Ex("Backpack.LoadForCurrentSave", e); } } public static void SaveNow() { try { string text = CurrentSaveName(); if (string.IsNullOrEmpty(text)) { text = _saveName; } if (!string.IsNullOrEmpty(text)) { Directory.CreateDirectory(ModFolder); WriteFile(PathFor(text)); } } catch (Exception e) { Log.Ex("Backpack.SaveNow", e); } } private static void WriteFile(string path) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# How To Fish - Extended storage. Safe to delete: you lose what is in it, nothing else."); stringBuilder.AppendLine("v=1"); foreach (StoredItem item in Items) { stringBuilder.Append(item.ItemID).Append('|').Append(item.Weight.ToString("0.#####", CultureInfo.InvariantCulture)) .Append('|') .Append(item.Cookness.ToString("0.#####", CultureInfo.InvariantCulture)) .Append('|') .Append(item.BettingMultiplier.ToString("0.#####", CultureInfo.InvariantCulture)) .Append('|') .Append(item.KillScoreMultiplier.ToString("0.#####", CultureInfo.InvariantCulture)) .Append('|') .Append(item.IsDripCreature ? 1 : 0) .Append('|') .Append(item.SkinIndex) .Append('|') .Append(item.Sharpness) .Append('|') .Append(item.Sight) .Append('|') .Append(item.BarrelAttachment) .Append('|') .Append(item.AmmoType) .Append('|') .Append(item.ExtendedMag ? 1 : 0) .Append('|') .Append(item.LaserSight ? 1 : 0) .Append('|') .Append(item.Worth.ToString(CultureInfo.InvariantCulture)) .Append('|') .Append(Sanitise(item.Label)) .AppendLine(); } File.WriteAllText(path, stringBuilder.ToString()); } private static string Sanitise(string s) { if (string.IsNullOrEmpty(s)) { return "?"; } return s.Replace('|', '/').Replace('\r', ' ').Replace('\n', ' ') .Trim(); } private static void ReadFile(string path) { string[] array = File.ReadAllLines(path); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length == 0 || text2[0] == '#' || text2.StartsWith("v=", StringComparison.Ordinal)) { continue; } string[] array2 = text2.Split(new char[1] { '|' }, 15); if (array2.Length >= 14) { try { StoredItem storedItem = new StoredItem(); storedItem.ItemID = (byte)Mathf.Clamp(ParseInt(array2[0]), 0, 255); storedItem.Weight = ParseFloat(array2[1], 1f); storedItem.Cookness = ParseFloat(array2[2], 0f); storedItem.BettingMultiplier = ParseFloat(array2[3], 0f); storedItem.KillScoreMultiplier = ParseFloat(array2[4], 0f); storedItem.IsDripCreature = ParseInt(array2[5]) != 0; storedItem.SkinIndex = (byte)Mathf.Clamp(ParseInt(array2[6]), 0, 255); storedItem.Sharpness = (byte)Mathf.Clamp(ParseInt(array2[7]), 0, 255); storedItem.Sight = (byte)Mathf.Clamp(ParseInt(array2[8]), 0, 255); storedItem.BarrelAttachment = (byte)Mathf.Clamp(ParseInt(array2[9]), 0, 255); storedItem.AmmoType = (byte)Mathf.Clamp(ParseInt(array2[10]), 0, 255); storedItem.ExtendedMag = ParseInt(array2[11]) != 0; storedItem.LaserSight = ParseInt(array2[12]) != 0; storedItem.Worth = ParseInt(array2[13]); storedItem.Label = ((array2.Length > 14 && array2[14].Trim().Length > 0) ? array2[14].Trim() : "?"); Items.Add(storedItem); } catch (Exception e) { Log.Ex("Backpack.ReadFile line", e); } } } } private static int ParseInt(string s) { int result; return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? result : 0; } private static float ParseFloat(string s, float d) { float result; return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out result) ? result : d; } private static string Wire(string s) { if (string.IsNullOrEmpty(s)) { return "?"; } return s.Replace('~', '-').Replace('|', '/').Replace(';', ',') .Replace('=', '-') .Trim(); } public static string EncodePage(int page, int perPage) { StringBuilder stringBuilder = new StringBuilder(); int value = Capacity(); stringBuilder.Append(page).Append('~').Append(Items.Count) .Append('~') .Append(value); int num = Mathf.Max(0, page * perPage); for (int i = num; i < Items.Count && i < num + perPage; i++) { StoredItem storedItem = Items[i]; stringBuilder.Append('~').Append(i).Append('|') .Append(storedItem.Weight.ToString("0.###", CultureInfo.InvariantCulture)) .Append('|') .Append(storedItem.Worth.ToString(CultureInfo.InvariantCulture)) .Append('|') .Append(Wire(storedItem.Label)); } return stringBuilder.ToString(); } public static void ApplyRemotePage(string payload) { try { if (string.IsNullOrEmpty(payload)) { return; } string[] array = payload.Split('~'); if (array.Length < 3) { return; } int num = ParseInt(array[0]); int num2 = ParseInt(array[1]); int num3 = ParseInt(array[2]); List list = new List(); for (int i = 3; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '|' }, 4); if (array2.Length >= 4) { StoredItem storedItem = new StoredItem(); storedItem.Weight = ParseFloat(array2[1], 1f); storedItem.Worth = ParseInt(array2[2]); storedItem.Label = ((array2[3].Trim().Length > 0) ? array2[3].Trim() : "?"); list.Add(storedItem); } } RemotePage = Mathf.Max(0, num); RemoteCount = Mathf.Max(0, num2); RemoteCapacity = Mathf.Max(0, num3); RemoteItems.Clear(); RemoteItems.AddRange(list); } catch (Exception e) { Log.Ex("Backpack.ApplyRemotePage", e); } } public static string Summary() { try { Cfg.EnsureLoaded(); long num = 0L; foreach (StoredItem item in Items) { num += item.Worth; } return "storage: " + Items.Count + "/" + Capacity() + " item(s), worth about $" + num.ToString("N0") + " when stored"; } catch (Exception ex) { return "storage unavailable: " + ex.Message; } } } public class BackpackPanel : MonoBehaviour { private enum Tab { Storage, Trophies, Credits } private static BackpackPanel _instance; private static readonly Color Shade = UiKit.Shade; private static readonly Color PanelBg = UiKit.PanelBg; private static readonly Color HeaderBg = UiKit.HeaderBg; private static readonly Color CellBg = UiKit.CellBg; private static readonly Color CellEmpty = UiKit.CellEmpty; private static readonly Color TabOn = UiKit.TabOn; private static readonly Color TabOff = UiKit.TabOff; private static readonly Color Gold = UiKit.Gold; private static readonly Color TextLight = UiKit.TextLight; private static readonly Color TextDim = UiKit.TextDim; private static readonly Color Warn = UiKit.Warn; private const float PanelW = 1160f; private const float PanelH = 700f; private const float HeaderH = 58f; private const float FooterH = 44f; private const int StorageCols = 6; private const int StorageRows = 5; private const int TrophyRows = 11; private const int CreditCols = 3; private const int CreditRows = 8; private Canvas _canvas; private RectTransform _root; private RectTransform _body; private TextMeshProUGUI _titleText; private TextMeshProUGUI _footerText; private TextMeshProUGUI _countText; private Image _tabStorageBg; private Image _tabTrophiesBg; private Image _tabCreditsBg; private Tab _tab = Tab.Storage; private int _page; private float _messageUntil; private Key _toggleKey = (Key)36; private bool _built; private readonly UiKit.Hotspots _hotspots = new UiKit.Hotspots(); private int _lastRemoteStamp = -1; public static bool IsOpen { get; private set; } public static void Bootstrap() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown try { Cfg.EnsureLoaded(); if (Cfg.EnableBackpack && !((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("HTFX_BackpackPanel"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); Log.Info("storage panel ready - press " + Cfg.BackpackKey + " to open"); WarnIfKeyTaken(); } } catch (Exception e) { Log.Ex("BackpackPanel.Bootstrap", e); } } private unsafe static void WarnIfKeyTaken() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) try { if (!Enum.TryParse(Cfg.BackpackKey, ignoreCase: true, out Key result)) { return; } PlayerInput input = GameInfo.Input; if ((Object)(object)input == (Object)null) { return; } InputActionAsset actions = input.actions; if ((Object)(object)actions == (Object)null) { return; } string value = "/" + ((object)(*(Key*)(&result))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(); List list = new List(); Enumerator enumerator = actions.actionMaps.GetEnumerator(); try { while (enumerator.MoveNext()) { InputActionMap current = enumerator.Current; if (current == null) { continue; } Enumerator enumerator2 = current.actions.GetEnumerator(); try { while (enumerator2.MoveNext()) { InputAction current2 = enumerator2.Current; if (current2 == null) { continue; } try { Enumerator enumerator3 = current2.bindings.GetEnumerator(); try { while (enumerator3.MoveNext()) { InputBinding current3 = enumerator3.Current; string text = (string.IsNullOrEmpty(((InputBinding)(ref current3)).overridePath) ? ((InputBinding)(ref current3)).path : ((InputBinding)(ref current3)).overridePath); if (!string.IsNullOrEmpty(text) && text.IndexOf("Keyboard", StringComparison.OrdinalIgnoreCase) >= 0 && text.ToLowerInvariant().EndsWith(value, StringComparison.Ordinal)) { string name = current2.name; if (!string.IsNullOrEmpty(name) && !list.Contains(name)) { list.Add(name); } } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } } catch { } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (list.Count == 0) { Log.Info("the storage key (" + ((object)(*(Key*)(&result))/*cast due to .constrained prefix*/).ToString() + ") is not bound to anything in the game."); return; } Log.Warn("the storage key (" + ((object)(*(Key*)(&result))/*cast due to .constrained prefix*/).ToString() + ") is also the game's key for: " + string.Join(", ", list.ToArray()) + ". Opening storage will do both. Change BackpackKey in " + Cfg.Path + " to a free key."); } catch (Exception e) { Log.Ex("BackpackPanel.WarnIfKeyTaken", e); } } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!Enum.TryParse(Cfg.BackpackKey, ignoreCase: true, out _toggleKey)) { _toggleKey = (Key)36; } } private void Update() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) try { Keyboard current = Keyboard.current; if (current != null && ((ButtonControl)current[_toggleKey]).wasPressedThisFrame) { Toggle(); } if (!IsOpen) { return; } if (Paused()) { Close(); return; } PollRemote(); HandleHover(); if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame) { HandleClick(); } } catch (Exception e) { Log.Ex("BackpackPanel.Update", e); } } private static bool Paused() { try { if (PauseManager.IsPaused) { return true; } } catch { } try { if (MainMenuManager.IsInMenu) { return true; } } catch { } return false; } public void Toggle() { if (IsOpen) { Close(); } else { Open(); } } private void Open() { try { Cfg.EnsureLoaded(); if (Cfg.EnableBackpack && !Paused()) { if (!_built) { Build(); _built = true; } if (!((Object)(object)_canvas == (Object)null)) { IsOpen = true; ((Component)_canvas).gameObject.SetActive(true); _page = 0; _messageUntil = 0f; SetCursor(show: true); RequestPageIfClient(); Refresh(); } } } catch (Exception e) { Log.Ex("BackpackPanel.Open", e); } } private void Close() { try { IsOpen = false; if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).gameObject.SetActive(false); } SetCursor(show: false); Backpack.SaveNow(); } catch (Exception e) { Log.Ex("BackpackPanel.Close", e); } } private static void SetCursor(bool show) { try { PlayerCamera.ToggleMouse(show); } catch (Exception e) { Log.Ex("BackpackPanel.SetCursor", e); } } private void HandleHover() { _hotspots.Hover(); } private void HandleClick() { _hotspots.Click(); } private void Say(string text, bool warn) { //IL_0040: 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) _messageUntil = Time.unscaledTime + 4f; if ((Object)(object)_footerText != (Object)null) { ((TMP_Text)_footerText).text = text; ((Graphic)_footerText).color = (warn ? Warn : TextDim); } } private static TMP_FontAsset Font() { return UiKit.Font(); } private static RectTransform NewRect(string name, Transform parent) { return UiKit.NewRect(name, parent); } private static Image NewImage(string name, Transform parent, Color color) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return UiKit.NewImage(name, parent, color); } private static TextMeshProUGUI NewText(string name, Transform parent, string text, int size, Color color, TextAlignmentOptions align) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return UiKit.NewText(name, parent, text, size, color, align); } private static void Place(RectTransform rt, float x, float y, float w, float h) { UiKit.Place(rt, x, y, w, h); } private static void Stretch(RectTransform rt) { UiKit.Stretch(rt); } private void Build() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_0163: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HTFX_BackpackCanvas", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler) }); Object.DontDestroyOnLoad((Object)(object)val); val.transform.SetParent(((Component)this).transform, false); _canvas = val.GetComponent(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 5000; CanvasScaler component = val.GetComponent(); component.uiScaleMode = (ScaleMode)1; component.referenceResolution = new Vector2(1920f, 1080f); component.screenMatchMode = (ScreenMatchMode)0; component.matchWidthOrHeight = 0.5f; Image val2 = NewImage("Shade", val.transform, Shade); Stretch(((Graphic)val2).rectTransform); Image val3 = NewImage("Panel", val.transform, PanelBg); _root = ((Graphic)val3).rectTransform; RectTransform root = _root; RectTransform root2 = _root; Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 0.5f); root2.anchorMax = val4; root.anchorMin = val4; _root.pivot = new Vector2(0.5f, 0.5f); _root.anchoredPosition = Vector2.zero; _root.sizeDelta = new Vector2(1160f, 700f); Image val5 = NewImage("Header", (Transform)(object)_root, HeaderBg); Place(((Graphic)val5).rectTransform, 0f, 0f, 1160f, 58f); _titleText = NewText("Title", (Transform)(object)((Graphic)val5).rectTransform, "Storage", 24, Gold, (TextAlignmentOptions)513); Place(((TMP_Text)_titleText).rectTransform, 20f, 12f, 300f, 34f); _countText = NewText("Count", (Transform)(object)((Graphic)val5).rectTransform, "", 16, TextDim, (TextAlignmentOptions)516); Place(((TMP_Text)_countText).rectTransform, 900f, 18f, 240f, 26f); _tabStorageBg = NewImage("TabStorage", (Transform)(object)((Graphic)val5).rectTransform, TabOn); Place(((Graphic)_tabStorageBg).rectTransform, 300f, 12f, 150f, 34f); TextMeshProUGUI val6 = NewText("TabStorageText", (Transform)(object)((Graphic)_tabStorageBg).rectTransform, "Storage", 16, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val6).rectTransform); _tabTrophiesBg = NewImage("TabTrophies", (Transform)(object)((Graphic)val5).rectTransform, TabOff); Place(((Graphic)_tabTrophiesBg).rectTransform, 458f, 12f, 150f, 34f); TextMeshProUGUI val7 = NewText("TabTrophiesText", (Transform)(object)((Graphic)_tabTrophiesBg).rectTransform, "Trophies", 16, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val7).rectTransform); _tabCreditsBg = NewImage("TabCredits", (Transform)(object)((Graphic)val5).rectTransform, TabOff); Place(((Graphic)_tabCreditsBg).rectTransform, 616f, 12f, 150f, 34f); TextMeshProUGUI val8 = NewText("TabCreditsText", (Transform)(object)((Graphic)_tabCreditsBg).rectTransform, "Credits", 16, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val8).rectTransform); _body = NewRect("Body", (Transform)(object)_root); Place(_body, 0f, 58f, 1160f, 598f); _footerText = NewText("Footer", (Transform)(object)_root, "", 14, TextDim, (TextAlignmentOptions)513); Place(((TMP_Text)_footerText).rectTransform, 20f, 666f, 1120f, 26f); val.SetActive(false); } private void ClearBody() { _hotspots.Clear(); if (!((Object)(object)_body == (Object)null)) { for (int num = ((Transform)_body).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)_body).GetChild(num)).gameObject); } } } private UiKit.Hotspot Clickable(Image bg, Action onClick) { return _hotspots.Add(bg, onClick); } private void Refresh() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0165: Unknown result type (might be due to invalid IL or missing references) try { if (_built && !((Object)(object)_canvas == (Object)null)) { ClearBody(); ((Graphic)_tabStorageBg).color = ((_tab == Tab.Storage) ? TabOn : TabOff); ((Graphic)_tabTrophiesBg).color = ((_tab == Tab.Trophies) ? TabOn : TabOff); ((Graphic)_tabCreditsBg).color = ((_tab == Tab.Credits) ? TabOn : TabOff); Clickable(_tabStorageBg, delegate { _tab = Tab.Storage; _page = 0; Refresh(); }).Base = ((Graphic)_tabStorageBg).color; Clickable(_tabTrophiesBg, delegate { _tab = Tab.Trophies; _page = 0; Refresh(); }).Base = ((Graphic)_tabTrophiesBg).color; Clickable(_tabCreditsBg, delegate { _tab = Tab.Credits; _page = 0; Refresh(); }).Base = ((Graphic)_tabCreditsBg).color; if (_tab == Tab.Storage) { DrawStorage(); } else if (_tab == Tab.Trophies) { DrawTrophies(); } else { DrawCredits(); } if ((Object)(object)_footerText != (Object)null && Time.unscaledTime >= _messageUntil) { ((Graphic)_footerText).color = TextDim; ((TMP_Text)_footerText).text = ((_tab != Tab.Storage) ? ((_tab == Tab.Trophies) ? ("Records for this save. Press " + ((object)Unsafe.As(ref _toggleKey)/*cast due to .constrained prefix*/).ToString() + " to close.") : ("Thanks for playing. Press " + ((object)Unsafe.As(ref _toggleKey)/*cast due to .constrained prefix*/).ToString() + " to close.")) : (Net.IsServer ? ("Click a pocket to store it. Click a stored item to take it back. Mouse only - press " + ((object)Unsafe.As(ref _toggleKey)/*cast due to .constrained prefix*/).ToString() + " to close.") : ("Shared with the host. Click to ask - the host's game does the moving. Press " + ((object)Unsafe.As(ref _toggleKey)/*cast due to .constrained prefix*/).ToString() + " to close."))); } } } catch (Exception e) { Log.Ex("BackpackPanel.Refresh", e); } } private void RequestPageIfClient() { try { if (!Net.IsServer) { Player localPlayer = Player.LocalPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Net.SendStorageSync(localPlayer, _page); } } } catch (Exception e) { Log.Ex("BackpackPanel.RequestPageIfClient", e); } } private void PollRemote() { if (!Net.IsServer) { int num = Backpack.RemoteCount * 1000 + Backpack.RemoteItems.Count * 7 + Backpack.RemotePage; if (num != _lastRemoteStamp) { _lastRemoteStamp = num; Refresh(); } } } private PlayerInventory Inventory() { try { Player localPlayer = Player.LocalPlayer; return ((Object)(object)localPlayer != (Object)null) ? localPlayer.Inventory : null; } catch { return null; } } private void DrawStorage() { //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_054b: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_05b4: Unknown result type (might be due to invalid IL or missing references) //IL_062c: Unknown result type (might be due to invalid IL or missing references) PlayerInventory inv = Inventory(); bool isServer = Net.IsServer; List list = (isServer ? Backpack.Items : Backpack.RemoteItems); int num = (isServer ? Backpack.Capacity() : Backpack.RemoteCapacity); int num2 = (isServer ? Backpack.Items.Count : Backpack.RemoteCount); int num3 = ((!isServer) ? (Backpack.RemotePage * 6 * 5) : 0); ((TMP_Text)_titleText).text = "Storage"; ((TMP_Text)_countText).text = num2 + " / " + num; Place(((TMP_Text)NewText("PocketsLabel", (Transform)(object)_body, "Pockets", 17, Gold, (TextAlignmentOptions)513)).rectTransform, 24f, 14f, 240f, 24f); int num4 = Backpack.HotbarSlots(inv); for (int i = 0; i < 9; i++) { int num5 = i % 3; int num6 = i / 3; float x = 24f + (float)num5 * 100f; float y = 48f + (float)num6 * 92f; bool flag = i < num4; Item val = (flag ? Backpack.HotbarItem(inv, i) : null); Image val2 = NewImage("Pocket" + i, (Transform)(object)_body, (Color)((!flag) ? new Color(0.07f, 0.08f, 0.1f, 1f) : (((Object)(object)val != (Object)null) ? CellBg : CellEmpty))); Place(((Graphic)val2).rectTransform, x, y, 92f, 84f); if (!flag) { TextMeshProUGUI val3 = NewText("PocketLocked" + i, (Transform)(object)((Graphic)val2).rectTransform, "locked", 11, new Color(0.35f, 0.38f, 0.43f, 1f), (TextAlignmentOptions)514); Stretch(((TMP_Text)val3).rectTransform); continue; } TextMeshProUGUI val4 = NewText("PocketNum" + i, (Transform)(object)((Graphic)val2).rectTransform, (i + 1).ToString(), 11, TextDim, (TextAlignmentOptions)257); Place(((TMP_Text)val4).rectTransform, 6f, 4f, 20f, 16f); if ((Object)(object)val == (Object)null) { TextMeshProUGUI val5 = NewText("PocketEmpty" + i, (Transform)(object)((Graphic)val2).rectTransform, "-", 14, new Color(0.3f, 0.34f, 0.39f, 1f), (TextAlignmentOptions)514); Stretch(((TMP_Text)val5).rectTransform); continue; } int tier = 0; try { tier = Variants.TierOf(val); } catch { } string text = "?"; try { text = val.GetName(); } catch { } TextMeshProUGUI val6 = NewText("PocketName" + i, (Transform)(object)((Graphic)val2).rectTransform, text, 12, TierColor(tier), (TextAlignmentOptions)514); Place(((TMP_Text)val6).rectTransform, 4f, 20f, 84f, 44f); int index = i; Clickable(val2, delegate { DoDeposit(index); }); } Image val7 = NewImage("StowAll", (Transform)(object)_body, new Color(0.16f, 0.22f, 0.18f, 1f)); Place(((Graphic)val7).rectTransform, 24f, 330f, 292f, 34f); TextMeshProUGUI val8 = NewText("StowAllText", (Transform)(object)((Graphic)val7).rectTransform, "Stow everything", 14, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val8).rectTransform); Clickable(val7, DoDepositAll); float num7 = 344f; Place(((TMP_Text)NewText("StorageLabel", (Transform)(object)_body, "In storage", 17, Gold, (TextAlignmentOptions)513)).rectTransform, num7, 14f, 300f, 24f); int num8 = Mathf.Max(num, num2); int num9 = 30; int num10 = Mathf.Max(1, Mathf.CeilToInt((float)num8 / (float)num9)); _page = Mathf.Clamp(_page, 0, num10 - 1); for (int num11 = 0; num11 < num9; num11++) { int num12 = _page * num9 + num11; if (num12 >= num8) { break; } int num13 = num11 % 6; int num14 = num11 / 6; float x2 = num7 + (float)num13 * 126f; float y2 = 48f + (float)num14 * 96f; int num15 = num12 - num3; bool flag2 = num15 >= 0 && num15 < list.Count; bool flag3 = num12 >= num; Image val9 = NewImage("Slot" + num12, (Transform)(object)_body, (Color)((!flag2) ? CellEmpty : (flag3 ? new Color(0.22f, 0.14f, 0.12f, 1f) : CellBg))); Place(((Graphic)val9).rectTransform, x2, y2, 118f, 88f); if (flag2) { StoredItem storedItem = list[num15]; TextMeshProUGUI val10 = NewText("SlotName" + num12, (Transform)(object)((Graphic)val9).rectTransform, storedItem.Label, 12, TierColor(storedItem.Tier), (TextAlignmentOptions)258); Place(((TMP_Text)val10).rectTransform, 5f, 6f, 108f, 40f); TextMeshProUGUI val11 = NewText("SlotSub" + num12, (Transform)(object)((Graphic)val9).rectTransform, storedItem.Weight.ToString("0.00") + "x $" + storedItem.Worth.ToString("N0"), 11, TextDim, (TextAlignmentOptions)1026); Place(((TMP_Text)val11).rectTransform, 5f, 62f, 108f, 20f); int index2 = num12; Clickable(val9, delegate { DoWithdraw(index2); }); } } if (num10 > 1) { DrawPager(num7, 534f, 748f, num10); } } private void DrawPager(float x, float y, float w, int pages) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) Image val = NewImage("PagePrev", (Transform)(object)_body, new Color(0.14f, 0.17f, 0.22f, 1f)); Place(((Graphic)val).rectTransform, x, y, 90f, 30f); TextMeshProUGUI val2 = NewText("PagePrevText", (Transform)(object)((Graphic)val).rectTransform, "< Prev", 13, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val2).rectTransform); Clickable(val, delegate { _page = Mathf.Max(0, _page - 1); RequestPageIfClient(); Refresh(); }); TextMeshProUGUI val3 = NewText("PageLabel", (Transform)(object)_body, "Page " + (_page + 1) + " of " + pages, 13, TextDim, (TextAlignmentOptions)514); Place(((TMP_Text)val3).rectTransform, x + 96f, y + 6f, w - 192f, 20f); Image val4 = NewImage("PageNext", (Transform)(object)_body, new Color(0.14f, 0.17f, 0.22f, 1f)); Place(((Graphic)val4).rectTransform, x + w - 90f, y, 90f, 30f); TextMeshProUGUI val5 = NewText("PageNextText", (Transform)(object)((Graphic)val4).rectTransform, "Next >", 13, TextLight, (TextAlignmentOptions)514); Stretch(((TMP_Text)val5).rectTransform); Clickable(val4, delegate { _page = Mathf.Min(pages - 1, _page + 1); RequestPageIfClient(); Refresh(); }); } private void DrawTrophies() { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: 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_0204: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)_titleText).text = "Trophies"; ((TMP_Text)_countText).text = CatchStats.TotalCaught(CatchStats.PerSave).ToString("N0") + " this save"; List list = new List(CatchStats.PerSave.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); if (list.Count == 0) { TextMeshProUGUI val = NewText("TrophyEmpty", (Transform)(object)_body, "Nothing caught yet - go fishing.", 16, TextDim, (TextAlignmentOptions)514); Place(((TMP_Text)val).rectTransform, 0f, 120f, 1160f, 30f); return; } int num = Mathf.Max(1, Mathf.CeilToInt((float)list.Count / 11f)); _page = Mathf.Clamp(_page, 0, num - 1); TextMeshProUGUI val2 = NewText("TrophyHead", (Transform)(object)_body, "Lifetime: " + CatchStats.TotalCaught(CatchStats.Lifetime).ToString("N0") + " caught", 14, TextDim, (TextAlignmentOptions)513); Place(((TMP_Text)val2).rectTransform, 24f, 12f, 600f, 22f); for (int i = 0; i < 11; i++) { int num2 = _page * 11 + i; if (num2 >= list.Count) { break; } SpeciesRecord speciesRecord = CatchStats.PerSave[list[num2]]; Image val3 = NewImage("TrophyRow" + i, (Transform)(object)_body, (i % 2 == 0) ? CellBg : CellEmpty); Place(((Graphic)val3).rectTransform, 24f, 42f + (float)i * 48f, 1112f, 44f); TextMeshProUGUI val4 = NewText("TrophyName" + i, (Transform)(object)((Graphic)val3).rectTransform, speciesRecord.Species, 15, TextLight, (TextAlignmentOptions)513); Place(((TMP_Text)val4).rectTransform, 12f, 4f, 260f, 36f); TextMeshProUGUI val5 = NewText("TrophyCount" + i, (Transform)(object)((Graphic)val3).rectTransform, speciesRecord.TotalCaught.ToString("N0") + " caught", 13, TextDim, (TextAlignmentOptions)513); Place(((TMP_Text)val5).rectTransform, 280f, 4f, 130f, 36f); string text = "ordinary only"; Color color = TextDim; for (int num3 = Variants.Tiers.Length; num3 >= 1; num3--) { if (speciesRecord.TierCounts.Length > num3 && speciesRecord.TierCounts[num3] > 0) { text = Variants.Tiers[num3 - 1].Name + " x" + speciesRecord.TierCounts[num3] + " best " + speciesRecord.TierBestWeight[num3].ToString("0.000") + "x"; color = TierColor(num3); break; } } TextMeshProUGUI val6 = NewText("TrophyBest" + i, (Transform)(object)((Graphic)val3).rectTransform, text, 13, color, (TextAlignmentOptions)513); Place(((TMP_Text)val6).rectTransform, 420f, 4f, 420f, 36f); float num4 = ((speciesRecord.TierBestWeight.Length != 0) ? speciesRecord.TierBestWeight[0] : 0f); TextMeshProUGUI val7 = NewText("TrophyOrd" + i, (Transform)(object)((Graphic)val3).rectTransform, (num4 > 0f) ? ("best ordinary " + num4.ToString("0.000") + "x") : "", 12, TextDim, (TextAlignmentOptions)516); Place(((TMP_Text)val7).rectTransform, 852f, 4f, 248f, 36f); } if (num > 1) { DrawPager(24f, 574f, 1112f, num); } } private void DrawCredits() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)_titleText).text = "Credits"; ((TMP_Text)_countText).text = "v" + ModInfo.Display; TextMeshProUGUI val = NewText("CreditTitle", (Transform)(object)_body, "How To Fish - Extended", 26, Gold, (TextAlignmentOptions)514); Place(((TMP_Text)val).rectTransform, 0f, 18f, 1160f, 34f); float y = 66f; y = Section("Made by", y); for (int i = 0; i < Credits.Authors.Length; i++) { CreditEntry creditEntry = Credits.Authors[i]; TextMeshProUGUI val2 = NewText("Author" + i, (Transform)(object)_body, creditEntry.Name + ((creditEntry.Note != null) ? (" - " + creditEntry.Note) : ""), 17, TextLight, (TextAlignmentOptions)514); Place(((TMP_Text)val2).rectTransform, 0f, y, 1160f, 24f); y += 26f; } y += 14f; y = Section("Contributors", y); if (!Credits.HasTesters) { TextMeshProUGUI val3 = NewText("NoTesters", (Transform)(object)_body, "The people who broke this before you had to.", 14, TextDim, (TextAlignmentOptions)514); Place(((TMP_Text)val3).rectTransform, 0f, y, 1160f, 22f); y += 30f; } else { int num = 24; int num2 = Mathf.Max(1, Mathf.CeilToInt((float)Credits.Testers.Length / (float)num)); _page = Mathf.Clamp(_page, 0, num2 - 1); float num3 = 354.66666f; float num4 = y; for (int j = 0; j < num; j++) { int num5 = _page * num + j; if (num5 >= Credits.Testers.Length) { break; } CreditEntry creditEntry2 = Credits.Testers[num5]; int num6 = j % 3; int num7 = j / 3; float x = 48f + (float)num6 * num3; float num8 = num4 + (float)num7 * 34f; TextMeshProUGUI val4 = NewText("Tester" + num5, (Transform)(object)_body, creditEntry2.Name, 16, TextLight, (TextAlignmentOptions)258); Place(((TMP_Text)val4).rectTransform, x, num8, num3 - 12f, 20f); if (creditEntry2.Note != null) { TextMeshProUGUI val5 = NewText("TesterNote" + num5, (Transform)(object)_body, creditEntry2.Note, 12, TextDim, (TextAlignmentOptions)258); Place(((TMP_Text)val5).rectTransform, x, num8 + 17f, num3 - 12f, 16f); } } int num9 = Mathf.CeilToInt((float)Mathf.Min(num, Credits.Testers.Length - _page * num) / 3f); y = num4 + (float)num9 * 34f + 8f; if (num2 > 1) { DrawPager(48f, y, 1064f, num2); y += 38f; } } y += 10f; y = Section("Thanks", y); for (int k = 0; k < Credits.Thanks.Length; k++) { TextMeshProUGUI val6 = NewText("Thanks" + k, (Transform)(object)_body, Credits.Thanks[k], 14, TextDim, (TextAlignmentOptions)514); Place(((TMP_Text)val6).rectTransform, 0f, y, 1160f, 20f); y += 22f; } } private float Section(string label, float y) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI val = NewText("Head_" + label, (Transform)(object)_body, label, 15, Gold, (TextAlignmentOptions)514); Place(((TMP_Text)val).rectTransform, 0f, y, 1160f, 22f); Image val2 = NewImage("Rule_" + label, (Transform)(object)_body, new Color(0.22f, 0.26f, 0.32f, 1f)); Place(((Graphic)val2).rectTransform, 440f, y + 24f, 280f, 1f); return y + 34f; } private static Color TierColor(int tier) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { if (tier <= 0 || tier > Variants.Tiers.Length) { return TextLight; } string color = Variants.Tiers[tier - 1].Color; if (string.IsNullOrEmpty(color) || color.Length < 7 || color[0] != '#') { return TextLight; } int num = Convert.ToInt32(color.Substring(1, 2), 16); int num2 = Convert.ToInt32(color.Substring(3, 2), 16); int num3 = Convert.ToInt32(color.Substring(5, 2), 16); return new Color((float)num / 255f, (float)num2 / 255f, (float)num3 / 255f, 1f); } catch { return TextLight; } } private void DoDeposit(int slot) { if (!Net.IsServer) { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { Say("No player.", warn: true); return; } Net.SendStorageDeposit(localPlayer, slot); Say("Asking the host...", warn: false); } else { if (Backpack.Deposit(Inventory(), slot, out var why)) { Say("Stored.", warn: false); } else { Say(why, warn: true); } Refresh(); } } private void DoDepositAll() { if (!Net.IsServer) { PlayerInventory val = Inventory(); Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { Say("No player.", warn: true); return; } int num = 0; int num2 = Backpack.HotbarSlots(val); Item val2 = null; try { val2 = (((Object)(object)val != (Object)null) ? val.SyncedCurItem : null); } catch { } for (int i = 0; i < num2; i++) { Item val3 = Backpack.HotbarItem(val, i); if (!((Object)(object)val3 == (Object)null) && (!((Object)(object)val2 != (Object)null) || !((Object)(object)val3 == (Object)(object)val2))) { Net.SendStorageDeposit(localPlayer, i); num++; } } Say((num > 0) ? ("Asking the host to stow " + num + "...") : "Nothing to stow.", num == 0); } else { string why; int num3 = Backpack.DepositAll(Inventory(), out why); if (num3 > 0) { Say("Stored " + num3 + " item" + ((num3 == 1) ? "" : "s") + ((why.Length > 0) ? (" - then stopped: " + why) : "."), why.Length > 0); } else { Say(why, warn: true); } Refresh(); } } private void DoWithdraw(int index) { if (!Net.IsServer) { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { Say("No player.", warn: true); return; } Net.SendStorageWithdraw(localPlayer, index); Say("Asking the host...", warn: false); } else { if (Backpack.Withdraw(Inventory(), index, out var why)) { Say("Taken out.", warn: false); } else { Say(why, warn: true); } Refresh(); } } } public sealed class SpeciesRecord { public string Species; public int[] TierCounts; public float[] TierBestWeight; public long TotalWorth; public int TotalCaught { get { int num = 0; for (int i = 0; i < TierCounts.Length; i++) { num += TierCounts[i]; } return num; } } public SpeciesRecord(string species, int tiers) { Species = species; TierCounts = new int[tiers + 1]; TierBestWeight = new float[tiers + 1]; } } public static class CatchStats { public static Dictionary PerSave = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Dictionary Lifetime = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _saveName = ""; private static string _toastText; private static float _toastUntil; private static GUIStyle _toastStyle; private static string ModFolder => Luck.ModFolder; private static int TierCount() { Cfg.EnsureLoaded(); return Variants.Tiers.Length; } private static SpeciesRecord GetOrCreate(Dictionary dict, string species) { if (!dict.TryGetValue(species, out var value)) { value = (dict[species] = new SpeciesRecord(species, TierCount())); } else if (value.TierCounts.Length != TierCount() + 1) { SpeciesRecord speciesRecord2 = new SpeciesRecord(species, TierCount()); for (int i = 0; i < value.TierCounts.Length && i < speciesRecord2.TierCounts.Length; i++) { speciesRecord2.TierCounts[i] = value.TierCounts[i]; speciesRecord2.TierBestWeight[i] = value.TierBestWeight[i]; } speciesRecord2.TotalWorth = value.TotalWorth; value = (dict[species] = speciesRecord2); } return value; } public static string SpeciesOf(Item item) { if ((Object)(object)item == (Object)null) { return "?"; } string text = ((Object)item).name; int num = text.IndexOf("(Clone)"); if (num > 0) { text = text.Substring(0, num).Trim(); } return string.IsNullOrEmpty(text) ? ((object)item).GetType().Name : text; } public static void RecordCatch(Item item) { try { Cfg.EnsureLoaded(); if (Cfg.EnableCatchStats && !((Object)(object)item == (Object)null) && item is Creature) { string text = SpeciesOf(item); int num = Mathf.Clamp(Variants.TierOf(item), 0, TierCount()); float num2; try { num2 = item._syncedRandomWeight.Value; } catch { num2 = 0f; } int b; try { b = item.TotalWorth; } catch { b = 0; } bool flag = false; SpeciesRecord orCreate = GetOrCreate(PerSave, text); orCreate.TierCounts[num]++; if (num2 > orCreate.TierBestWeight[num]) { orCreate.TierBestWeight[num] = num2; flag = true; } SpeciesRecord orCreate2 = GetOrCreate(Lifetime, text); orCreate2.TierCounts[num]++; if (num2 > orCreate2.TierBestWeight[num]) { orCreate2.TierBestWeight[num] = num2; } orCreate2.TotalWorth = SaturateAdd(orCreate2.TotalWorth, b); Log.Info("caught " + text + ((num > 0) ? (" (" + Variants.Tiers[num - 1].Name + ")") : " (ordinary)") + " weight " + num2.ToString("0.000") + "x worth $" + b.ToString("N0") + (flag ? " [new best]" : "")); if (flag) { string text2 = ((num > 0) ? (Variants.Tiers[num - 1].Name + " " + text) : text); Toast("New best: " + text2 + " " + num2.ToString("0.000") + "x"); } SaveForCurrentSave(); SaveLifetime(); } } catch (Exception e) { Log.Ex("CatchStats.RecordCatch", e); } } private static long SaturateAdd(long a, int b) { if (b <= 0) { return a; } if (a > long.MaxValue - b) { return long.MaxValue; } return a + b; } public static void Toast(string text) { _toastText = text; _toastUntil = Time.unscaledTime + Cfg.CatchToastDuration; } public static void DrawToast() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(_toastText) && !(Time.unscaledTime >= _toastUntil)) { if (_toastStyle == null) { _toastStyle = new GUIStyle(GUI.skin.label); _toastStyle.fontSize = 20; _toastStyle.normal.textColor = new Color(1f, 0.85f, 0.2f, 1f); } GUIContent val = new GUIContent(_toastText); float num = 640f; float num2 = 44f; float num3 = ((float)Screen.width - num) / 2f; GUI.Box(new Rect(num3, 76f, num, num2), GUIContent.none); Vector2 val2 = _toastStyle.CalcSize(val); GUI.Label(new Rect(num3 + Mathf.Max(0f, (num - val2.x) / 2f), 80f, num, num2 - 8f), val, _toastStyle); } } private static string PerSavePath(string saveName) { return ModFolder + "/" + saveName + ".catches.dat"; } private static string LifetimePath() { return ModFolder + "/lifetime.catches.dat"; } private static string CurrentSaveName() { try { ServerSaveObject curServerSave = SaveManager.CurServerSave; return (curServerSave != null && !string.IsNullOrEmpty(curServerSave.Name)) ? curServerSave.Name : ""; } catch { return ""; } } public static void LoadForCurrentSave() { try { _saveName = CurrentSaveName(); PerSave = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(_saveName)) { string path = PerSavePath(_saveName); if (File.Exists(path)) { PerSave = LoadFile(path); } } Log.Info("catch stats: " + TotalCaught(PerSave) + " caught this save ('" + _saveName + "')"); } catch (Exception e) { Log.Ex("CatchStats.LoadForCurrentSave", e); } } public static void SaveForCurrentSave() { try { string text = CurrentSaveName(); if (string.IsNullOrEmpty(text)) { text = _saveName; } if (!string.IsNullOrEmpty(text)) { Directory.CreateDirectory(ModFolder); WriteFile(PerSavePath(text), PerSave); } } catch (Exception e) { Log.Ex("CatchStats.SaveForCurrentSave", e); } } public static void LoadLifetime() { try { Lifetime = new Dictionary(StringComparer.OrdinalIgnoreCase); string path = LifetimePath(); if (File.Exists(path)) { Lifetime = LoadFile(path); } } catch (Exception e) { Log.Ex("CatchStats.LoadLifetime", e); } } public static void SaveLifetime() { try { Directory.CreateDirectory(ModFolder); WriteFile(LifetimePath(), Lifetime); } catch (Exception e) { Log.Ex("CatchStats.SaveLifetime", e); } } public static void ResetForCurrentSave() { PerSave = new Dictionary(StringComparer.OrdinalIgnoreCase); SaveForCurrentSave(); } public static int TotalCaught(Dictionary dict) { int num = 0; foreach (SpeciesRecord value in dict.Values) { num += value.TotalCaught; } return num; } private static void WriteFile(string path, Dictionary dict) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# How To Fish - Extended catch stats. Safe to delete."); stringBuilder.AppendLine("v=1"); foreach (KeyValuePair item in dict) { SpeciesRecord value = item.Value; stringBuilder.Append(item.Key).Append('=').Append(value.TotalWorth.ToString(CultureInfo.InvariantCulture)); for (int i = 0; i < value.TierCounts.Length; i++) { stringBuilder.Append('|').Append(value.TierCounts[i]); } for (int j = 0; j < value.TierBestWeight.Length; j++) { stringBuilder.Append('|').Append(value.TierBestWeight[j].ToString("0.####", CultureInfo.InvariantCulture)); } stringBuilder.AppendLine(); } File.WriteAllText(path, stringBuilder.ToString()); } private static Dictionary LoadFile(string path) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string[] array = File.ReadAllLines(path); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length == 0 || text2[0] == '#') { continue; } int num = text2.IndexOf('='); if (num <= 0) { continue; } string text3 = text2.Substring(0, num).Trim(); if (text3 == "v") { continue; } string[] array2 = text2.Substring(num + 1).Split('|'); if (array2.Length < 1) { continue; } if (!long.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { result = 0L; } int num2 = TierCount() + 1; SpeciesRecord speciesRecord = new SpeciesRecord(text3, TierCount()); speciesRecord.TotalWorth = result; for (int j = 0; j < num2 && j + 1 < array2.Length; j++) { if (int.TryParse(array2[j + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { speciesRecord.TierCounts[j] = Math.Max(0, result2); } } for (int k = 0; k < num2 && k + 1 + num2 < array2.Length; k++) { if (float.TryParse(array2[k + 1 + num2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { speciesRecord.TierBestWeight[k] = Math.Max(0f, result3); } } dictionary[text3] = speciesRecord; } return dictionary; } public static string Summary() { try { Cfg.EnsureLoaded(); int value = TotalCaught(PerSave); int value2 = TotalCaught(Lifetime); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("catch stats: ").Append(value).Append(" this save, ") .Append(value2) .Append(" lifetime"); if (PerSave.Count > 0) { stringBuilder.Append(" | species:"); foreach (SpeciesRecord value3 in PerSave.Values) { stringBuilder.Append(' ').Append(value3.Species).Append(" x") .Append(value3.TotalCaught); } } return stringBuilder.ToString(); } catch (Exception ex) { return "catch stats unavailable: " + ex.Message; } } } public sealed class CatchToast : MonoBehaviour { private static CatchToast _instance; public static void Bootstrap() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown try { Cfg.EnsureLoaded(); if (Cfg.EnableCatchStats && !((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("HTFX_CatchToast"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); } } catch (Exception e) { Log.Ex("CatchToast.Bootstrap", e); } } private void OnGUI() { try { CatchStats.DrawToast(); } catch (Exception e) { Log.Ex("CatchToast.OnGUI", e); } } } public class ConfigPanel : MonoBehaviour { private sealed class Row { public string Name; public string Label; public string Help; public float Min; public float Max; public float Step; public FieldInfo Field; public Row(string name, string label, string help, float min = 0f, float max = 0f, float step = 1f) { Name = name; Label = label; Help = help; Min = min; Max = max; Step = step; } } private sealed class Group { public string Title; public Row[] Rows; public Group(string title, Row[] rows) { Title = title; Rows = rows; } } private static ConfigPanel _instance; private const float PanelW = 1180f; private const float PanelH = 720f; private const float HeaderH = 58f; private const float FooterH = 56f; private const float RowH = 46f; private const int RowsPerPage = 11; private static readonly Group[] Groups = new Group[6] { new Group("Features", new Row[11] { new Row("EnableVariants", "Fish size variants", "Plump through Mythic. Off returns every catch to its vanilla name and value."), new Row("EnableLuckShop", "Lucky Charm stands", "The luck stands on each island, and the luck system behind them."), new Row("EnableAscension", "Ascension (New Game+)", "Unlocks after the game is finished. Off hides the stand entirely."), new Row("EnableBackpack", "Storage panel", "The mod's own inventory window, opened in game with the storage key."), new Row("EnableCatchStats", "Catch trophies", "Records every fish you land and pops a toast on a new record."), new Row("EnableFishScaling", "Fish drawn to size", "Draws a fish at a size matching its weight, instead of one size for all."), new Row("EnableExtraHooks", "Extra hooks", "More than one fish on the line at a time. Still being tuned."), new Row("PreventMoneyOverflow", "Money overflow guard", "Stops a very large catch wrapping the game's 32-bit money counter."), new Row("EnableCustomStandModels", "Custom stand models", "The mod's own kiosk model. Off falls back to a plain marker."), new Row("HighlightModStands", "Outline mod stands", "Keeps the mod's stands permanently outlined so they can be found."), new Row("EnableDebugMenu", "Debug menu", "Developer overlay. Off unless you have been asked to turn it on.") }), new Group("Fish size", new Row[9] { new Row("FishScaleExponent", "Size exponent", "size = weight ^ this. 0.33 is physically honest; higher exaggerates it.", 0f, 1f, 0.01f), new Row("FishScaleMin", "Smallest draw size", "A runt never draws smaller than this.", 0.05f, 1f, 0.05f), new Row("FishScaleMax", "Largest draw size", "A safety rail. Nothing in the variant table reaches it.", 1f, 10f, 0.25f), new Row("ScaleBossFish", "Scale bosses too", "Only does anything with 'Variants from bosses' on as well."), new Row("VariantChanceMulti", "Variant chance", "Multiplies the odds of rolling any variant at all.", 0.1f, 10f, 0.1f), new Row("VariantsFromBirds", "Variants from birds", "Whether a fish taken from a bird can be a variant."), new Row("VariantsFromDynamite", "Variants from dynamite", "Off by default: a blast catches many fish at once."), new Row("VariantsFromBosses", "Variants from bosses", "Rolls a weight for bosses, which the game otherwise pins to 1.0."), new Row("UseColors", "Colour variant names", "Tints the variant prefix in the catch readout.") }), new Group("Health bars", new Row[6] { new Row("EnableFishHealthBars", "Show health bars", "Draws a bar above each fish that drains as it is fought."), new Row("FishHealthBarWidth", "Bar width", "How wide the bar is, in world units.", 0.5f, 4f, 0.1f), new Row("FishHealthBarThickness", "Bar thickness", "How tall the bar is, in world units.", 0.05f, 0.6f, 0.01f), new Row("FishHealthBarLift", "Height above fish", "The gap between the top of a fish and the bar.", 0f, 1.5f, 0.05f), new Row("FishHealthBarOpacity", "Opacity", "Overall transparency, 0.2 to 1.", 0.2f, 1f, 0.05f), new Row("FishHealthBarOnlyWhenDamaged", "Only when damaged", "Hide the bar until the fish takes damage.") }), new Group("Luck", new Row[5] { new Row("LuckBaseCost", "First luck level cost", "What level 1 costs. Every level after grows from this.", 10f, 100000f, 25f), new Row("LuckCostGrowth", "Luck cost growth", "Per-level multiplier on the price.", 1.01f, 2f, 0.01f), new Row("LuckMaxLevel", "Luck level cap", "How far the luck ladder goes.", 5f, 250f, 5f), new Row("OrdinaryChanceAtMaxLuck", "Ordinary at max luck", "Share of catches still plain once luck is maxed.", 0.01f, 1f, 0.01f), new Row("LuckBaseWeightBonus", "Luck weight bonus", "How much luck pushes the weight roll upward.", 0f, 0.2f, 0.01f) }), new Group("Ascension", new Row[7] { new Row("AscensionBaseCost", "First ascension cost", "Price of tier 1.", 100f, 100000000f, 5000f), new Row("AscensionCostGrowth", "Ascension cost growth", "Per-tier multiplier on the price.", 1.05f, 5f, 0.05f), new Row("AscensionHpGrowth", "Creature health growth", "Per-tier multiplier on how hard things hit back.", 1f, 5f, 0.05f), new Row("AscensionValueGrowth", "Fish value growth", "Per-tier multiplier on what a catch is worth.", 1f, 5f, 0.05f), new Row("AscensionMaxLevel", "Ascension tier cap", "How many tiers the loop runs for.", 1f, 100f), new Row("AscensionLuckBonus", "Free luck per tier", "Luck levels granted on each ascension.", 0f, 50f), new Row("EnableAscensionSlots", "Pockets per tier", "Whether ascension grows your hotbar. It stops at nine either way.") }), new Group("Storage and upgrades", new Row[9] { new Row("BackpackSlots", "Storage slots", "How much the storage panel holds before ascension.", 5f, 300f, 5f), new Row("BackpackSlotsPerAscension", "Slots per tier", "Extra storage each ascension tier adds.", 0f, 50f), new Row("ExtraGunTiers", "Extra gun tiers", "-1 means as many as the game can address.", -1f, 250f), new Row("ExtraMeleeTiers", "Extra melee tiers", "-1 means as many as the game can address.", -1f, 250f), new Row("GunDamageGrowth", "Gun damage growth", "Upper bound on the per-tier damage rate.", 1f, 3f, 0.01f), new Row("GunCostGrowth", "Gun cost growth", "Upper bound on the per-tier price rate.", 1.01f, 3f, 0.01f), new Row("UnlockShopCap", "Unlock the shop cap", "Lets the shop sell past its original top tier."), new Row("HookCount", "Hooks on the line", "How many fish can be on the line at once.", 1f, 5f), new Row("HookSpread", "Hook spacing", "How far apart extra fish sit. 0 stacks them.", 0f, 2f, 0.02f) }) }; private Canvas _canvas; private RectTransform _root; private RectTransform _body; private TextMeshProUGUI _titleText; private TextMeshProUGUI _footerText; private readonly List _tabBgs = new List(); private readonly UiKit.Hotspots _hotspots = new UiKit.Hotspots(); private int _tab; private int _page; private bool _built; private bool _dirty; private float _messageUntil; private readonly Dictionary _opening = new Dictionary(); private static bool _resolved; public static bool IsOpen { get; private set; } public static void Bootstrap() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown try { if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("HTFX_ConfigPanel"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); Log.Info("config panel ready; the button is on the main menu"); } } catch (Exception e) { Log.Ex("ConfigPanel.Bootstrap", e); } } public static void OpenPanel() { try { Bootstrap(); if ((Object)(object)_instance != (Object)null) { _instance.Open(); } } catch (Exception e) { Log.Ex("ConfigPanel.OpenPanel", e); } } private void Awake() { try { ResolveFields(); } catch (Exception e) { Log.Ex("ConfigPanel.Awake", e); } } private static void ResolveFields() { if (_resolved) { return; } _resolved = true; int num = 0; Group[] groups = Groups; foreach (Group obj in groups) { Row[] rows = obj.Rows; foreach (Row row in rows) { row.Field = typeof(Cfg).GetField(row.Name, BindingFlags.Static | BindingFlags.Public); if (row.Field == null) { num++; Log.Warn("config panel: setting '" + row.Name + "' is listed in the panel but no longer exists, so its row is hidden"); } } } if (num == 0) { Log.Info("config panel: all " + CountRows() + " settings resolved"); } } private static int CountRows() { int num = 0; Group[] groups = Groups; foreach (Group obj in groups) { num += obj.Rows.Length; } return num; } private void Update() { try { if (IsOpen) { _hotspots.Hover(); if (UiKit.MouseClicked()) { _hotspots.Click(); } if (_messageUntil > 0f && Time.unscaledTime > _messageUntil) { _messageUntil = 0f; Footer(); } } } catch (Exception e) { Log.Ex("ConfigPanel.Update", e); } } private void Open() { try { Cfg.EnsureLoaded(); if (!_built) { Build(); _built = true; } if ((Object)(object)_canvas == (Object)null) { return; } _opening.Clear(); Group[] groups = Groups; foreach (Group obj in groups) { Row[] rows = obj.Rows; foreach (Row row in rows) { if (row.Field != null) { _opening[row.Name] = row.Field.GetValue(null); } } } IsOpen = true; _dirty = false; _tab = 0; _page = 0; _messageUntil = 0f; ((Component)_canvas).gameObject.SetActive(true); Refresh(); } catch (Exception e) { Log.Ex("ConfigPanel.Open", e); } } private void Close() { try { IsOpen = false; if ((Object)(object)_canvas != (Object)null) { ((Component)_canvas).gameObject.SetActive(false); } } catch (Exception e) { Log.Ex("ConfigPanel.Close", e); } } private void Revert() { Group[] groups = Groups; foreach (Group obj in groups) { Row[] rows = obj.Rows; foreach (Row row in rows) { if (row.Field != null && _opening.TryGetValue(row.Name, out var value)) { row.Field.SetValue(null, value); } } } _dirty = false; } private void Save() { try { Cfg.Write(); _opening.Clear(); Group[] groups = Groups; foreach (Group obj in groups) { Row[] rows = obj.Rows; foreach (Row row in rows) { if (row.Field != null) { _opening[row.Name] = row.Field.GetValue(null); } } } _dirty = false; Say("Saved. These apply to the next game you load.", warn: false); Log.Info("config panel: settings saved to " + Cfg.Path); } catch (Exception e) { Log.Ex("ConfigPanel.Save", e); Say("Could not write the config file - see the log.", warn: true); } } private void Say(string text, bool warn) { //IL_0040: 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) _messageUntil = Time.unscaledTime + 5f; if ((Object)(object)_footerText != (Object)null) { ((TMP_Text)_footerText).text = text; ((Graphic)_footerText).color = (warn ? UiKit.Warn : UiKit.Good); } } private void Footer() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_footerText == (Object)null)) { ((TMP_Text)_footerText).text = (_dirty ? "Unsaved changes. Save writes them to the config file; they take effect in the next game you load." : "Changes apply to the next game you load. The config file is in AppData if you would rather edit it there."); ((Graphic)_footerText).color = (_dirty ? UiKit.Gold : UiKit.TextDim); } } private void Build() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_0163: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HTFX_ConfigCanvas", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler) }); Object.DontDestroyOnLoad((Object)(object)val); val.transform.SetParent(((Component)this).transform, false); _canvas = val.GetComponent(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 5200; CanvasScaler component = val.GetComponent(); component.uiScaleMode = (ScaleMode)1; component.referenceResolution = new Vector2(1920f, 1080f); component.screenMatchMode = (ScreenMatchMode)0; component.matchWidthOrHeight = 0.5f; Image val2 = UiKit.NewImage("Shade", val.transform, UiKit.Shade); UiKit.Stretch(((Graphic)val2).rectTransform); Image val3 = UiKit.NewImage("Panel", val.transform, UiKit.PanelBg); _root = ((Graphic)val3).rectTransform; RectTransform root = _root; RectTransform root2 = _root; Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 0.5f); root2.anchorMax = val4; root.anchorMin = val4; _root.pivot = new Vector2(0.5f, 0.5f); _root.anchoredPosition = Vector2.zero; _root.sizeDelta = new Vector2(1180f, 720f); Image val5 = UiKit.NewImage("Header", (Transform)(object)_root, UiKit.HeaderBg); UiKit.Place(((Graphic)val5).rectTransform, 0f, 0f, 1180f, 58f); _titleText = UiKit.NewText("Title", (Transform)(object)((Graphic)val5).rectTransform, "How To Fish - Extended", 22, UiKit.Gold, (TextAlignmentOptions)513); UiKit.Place(((TMP_Text)_titleText).rectTransform, 20f, 14f, 420f, 32f); _body = UiKit.NewRect("Body", (Transform)(object)_root); UiKit.Place(_body, 0f, 58f, 1180f, 606f); _footerText = UiKit.NewText("Footer", (Transform)(object)_root, "", 14, UiKit.TextDim, (TextAlignmentOptions)513); UiKit.Place(((TMP_Text)_footerText).rectTransform, 20f, 672f, 860f, 40f); val.SetActive(false); } private void ClearBody() { _hotspots.Clear(); _tabBgs.Clear(); if (!((Object)(object)_body == (Object)null)) { for (int num = ((Transform)_body).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)_body).GetChild(num)).gameObject); } } } private void Refresh() { try { if (_built && !((Object)(object)_canvas == (Object)null)) { ClearBody(); ((TMP_Text)_titleText).text = "How To Fish - Extended " + ModInfo.Display + " - Settings"; DrawTabs(); DrawRows(); if (Groups[_tab].Title == "Health bars") { DrawHealthBarPreview(); } DrawButtons(); Footer(); } } catch (Exception e) { Log.Ex("ConfigPanel.Refresh", e); } } private void DrawTabs() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) float num = 20f; for (int i = 0; i < Groups.Length; i++) { int index = i; Image val = UiKit.NewImage("Tab" + i, (Transform)(object)_body, (i == _tab) ? UiKit.TabOn : UiKit.TabOff); float num2 = Mathf.Min(190f, 1140f / (float)Groups.Length - 8f); UiKit.Place(((Graphic)val).rectTransform, num, 10f, num2, 36f); TextMeshProUGUI val2 = UiKit.NewText("TabText" + i, (Transform)(object)((Graphic)val).rectTransform, Groups[i].Title, 15, (i == _tab) ? UiKit.Gold : UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val2).rectTransform); _hotspots.Add(val, delegate { _tab = index; _page = 0; Refresh(); }); _tabBgs.Add(val); num += num2 + 8f; } } private void DrawRows() { Row[] rows = Groups[_tab].Rows; int num = Mathf.Max(1, Mathf.CeilToInt((float)rows.Length / 11f)); _page = Mathf.Clamp(_page, 0, num - 1); float num2 = 62f; for (int i = _page * 11; i < rows.Length && i < (_page + 1) * 11; i++) { DrawRow(rows[i], num2); num2 += 46f; } if (num > 1) { DrawPager(num2 + 6f, num); } } private void DrawHealthBarPreview() { //IL_0033: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) float y = 62f + (float)Groups[_tab].Rows.Length * 46f + 8f; Image val = UiKit.NewImage("HpPreview", (Transform)(object)_body, UiKit.CellEmpty); UiKit.Place(((Graphic)val).rectTransform, 20f, y, 1140f, 200f); TextMeshProUGUI val2 = UiKit.NewText("HpPreviewTitle", (Transform)(object)((Graphic)val).rectTransform, "Preview - the bar floats above the fish", 13, UiKit.TextDim, (TextAlignmentOptions)513); UiKit.Place(((TMP_Text)val2).rectTransform, 14f, 8f, 1112f, 20f); float num = 220f; float h = 62f; float num2 = 570f - num / 2f; float num3 = 100f; Image val3 = UiKit.NewImage("HpFish", (Transform)(object)((Graphic)val).rectTransform, new Color(0.24f, 0.31f, 0.4f, 1f)); UiKit.Place(((Graphic)val3).rectTransform, num2, num3, num, h); float num4 = Mathf.Clamp(Cfg.FishHealthBarWidth * 100f, 12f, 1100f); float num5 = Mathf.Clamp(Cfg.FishHealthBarThickness * 100f, 3f, 48f); float num6 = Mathf.Clamp(Cfg.FishHealthBarLift * 100f, 0f, 60f); float fishHealthBarOpacity = Cfg.FishHealthBarOpacity; float x = num2 + (num - num4) / 2f; float y2 = Mathf.Max(34f, num3 - num6 - num5); Image val4 = UiKit.NewImage("HpTrack", (Transform)(object)((Graphic)val).rectTransform, new Color(0.03f, 0.05f, 0.06f, 0.85f * fishHealthBarOpacity)); UiKit.Place(((Graphic)val4).rectTransform, x, y2, num4, num5); Image val5 = UiKit.NewImage("HpFill", (Transform)(object)((Graphic)val).rectTransform, new Color(0.22f, 0.86f, 0.42f, 0.95f * fishHealthBarOpacity)); UiKit.Place(((Graphic)val5).rectTransform, x, y2, num4 * 0.62f, num5); TextMeshProUGUI val6 = UiKit.NewText("HpDims", (Transform)(object)((Graphic)val).rectTransform, "width " + Cfg.FishHealthBarWidth.ToString("0.00") + " x thickness " + Cfg.FishHealthBarThickness.ToString("0.00") + " | " + Mathf.RoundToInt(fishHealthBarOpacity * 100f) + "% opacity" + (Cfg.FishHealthBarOnlyWhenDamaged ? " | hidden until damaged" : ""), 13, UiKit.TextDim, (TextAlignmentOptions)514); UiKit.Place(((TMP_Text)val6).rectTransform, 14f, 176f, 1112f, 20f); } private void DrawRow(Row r, float y) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if (!(r.Field == null)) { Image val = UiKit.NewImage("Row_" + r.Name, (Transform)(object)_body, UiKit.CellEmpty); UiKit.Place(((Graphic)val).rectTransform, 20f, y, 1140f, 40f); TextMeshProUGUI val2 = UiKit.NewText("Label", (Transform)(object)((Graphic)val).rectTransform, r.Label, 16, UiKit.TextLight, (TextAlignmentOptions)513); UiKit.Place(((TMP_Text)val2).rectTransform, 14f, 3f, 280f, 20f); TextMeshProUGUI val3 = UiKit.NewText("Help", (Transform)(object)((Graphic)val).rectTransform, r.Help, 12, UiKit.TextDim, (TextAlignmentOptions)513); UiKit.Place(((TMP_Text)val3).rectTransform, 14f, 21f, 700f, 18f); if (r.Field.FieldType == typeof(bool)) { DrawToggle(r, val); } else { DrawStepper(r, val); } } } private void DrawToggle(Row r, Image rowBg) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) bool flag = (bool)r.Field.GetValue(null); Image val = UiKit.NewImage("Toggle", (Transform)(object)((Graphic)rowBg).rectTransform, flag ? UiKit.TabOn : UiKit.TabOff); UiKit.Place(((Graphic)val).rectTransform, 1010f, 5f, 110f, 30f); TextMeshProUGUI val2 = UiKit.NewText("ToggleText", (Transform)(object)((Graphic)val).rectTransform, flag ? "On" : "Off", 15, flag ? UiKit.Good : UiKit.TextDim, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val2).rectTransform); _hotspots.Add(val, delegate { r.Field.SetValue(null, !(bool)r.Field.GetValue(null)); _dirty = true; Refresh(); }); } private void DrawStepper(Row r, Image rowBg) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) float num = 1140f; Image val = UiKit.NewImage("Minus", (Transform)(object)((Graphic)rowBg).rectTransform, UiKit.CellBg); UiKit.Place(((Graphic)val).rectTransform, num - 250f, 5f, 40f, 30f); TextMeshProUGUI val2 = UiKit.NewText("MinusText", (Transform)(object)((Graphic)val).rectTransform, "-", 20, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val2).rectTransform); TextMeshProUGUI val3 = UiKit.NewText("Value", (Transform)(object)((Graphic)rowBg).rectTransform, Format(r), 16, UiKit.Gold, (TextAlignmentOptions)514); UiKit.Place(((TMP_Text)val3).rectTransform, num - 205f, 8f, 150f, 24f); Image val4 = UiKit.NewImage("Plus", (Transform)(object)((Graphic)rowBg).rectTransform, UiKit.CellBg); UiKit.Place(((Graphic)val4).rectTransform, num - 50f, 5f, 40f, 30f); TextMeshProUGUI val5 = UiKit.NewText("PlusText", (Transform)(object)((Graphic)val4).rectTransform, "+", 20, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val5).rectTransform); _hotspots.Add(val, delegate { Nudge(r, -1); }); _hotspots.Add(val4, delegate { Nudge(r, 1); }); } private void Nudge(Row r, int direction) { try { float num = ((r.Step <= 0f) ? 1f : r.Step); if (r.Field.FieldType == typeof(int)) { int num2 = (int)r.Field.GetValue(null); int num3 = num2 + direction * Mathf.Max(1, Mathf.RoundToInt(num)); num3 = Mathf.Clamp(num3, Mathf.RoundToInt(r.Min), Mathf.RoundToInt(r.Max)); r.Field.SetValue(null, num3); } else { float num4 = (float)r.Field.GetValue(null); float num5 = num4 + (float)direction * num; num5 = Mathf.Round(num5 / num) * num; num5 = Mathf.Clamp(num5, r.Min, r.Max); r.Field.SetValue(null, num5); } _dirty = true; Refresh(); } catch (Exception e) { Log.Ex("ConfigPanel.Nudge", e); } } private static string Format(Row r) { try { object value = r.Field.GetValue(null); if (value is int num) { if (num < 0) { return "auto"; } return num.ToString("N0", CultureInfo.InvariantCulture); } if (value is float num2) { return num2.ToString("0.###", CultureInfo.InvariantCulture); } return (value == null) ? "" : value.ToString(); } catch { return "?"; } } private void DrawPager(float y, int pages) { //IL_0020: 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_00ad: 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_0126: Unknown result type (might be due to invalid IL or missing references) Image val = UiKit.NewImage("PrevPage", (Transform)(object)_body, UiKit.CellBg); UiKit.Place(((Graphic)val).rectTransform, 20f, y, 110f, 30f); TextMeshProUGUI val2 = UiKit.NewText("PrevText", (Transform)(object)((Graphic)val).rectTransform, "Previous", 14, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val2).rectTransform); TextMeshProUGUI val3 = UiKit.NewText("PageLabel", (Transform)(object)_body, "Page " + (_page + 1) + " of " + pages, 14, UiKit.TextDim, (TextAlignmentOptions)514); UiKit.Place(((TMP_Text)val3).rectTransform, 138f, y + 5f, 140f, 22f); Image val4 = UiKit.NewImage("NextPage", (Transform)(object)_body, UiKit.CellBg); UiKit.Place(((Graphic)val4).rectTransform, 286f, y, 110f, 30f); TextMeshProUGUI val5 = UiKit.NewText("NextText", (Transform)(object)((Graphic)val4).rectTransform, "Next", 14, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val5).rectTransform); _hotspots.Add(val, delegate { if (_page > 0) { _page--; Refresh(); } }); _hotspots.Add(val4, delegate { if (_page < pages - 1) { _page++; Refresh(); } }); } private void DrawButtons() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) float y = 562f; float num = 1140f; Image val = UiKit.NewImage("Close", (Transform)(object)_body, UiKit.CellBg); UiKit.Place(((Graphic)val).rectTransform, num - 130f, y, 130f, 34f); TextMeshProUGUI val2 = UiKit.NewText("CloseText", (Transform)(object)((Graphic)val).rectTransform, "Close", 15, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val2).rectTransform); Image val3 = UiKit.NewImage("Revert", (Transform)(object)_body, UiKit.CellBg); UiKit.Place(((Graphic)val3).rectTransform, num - 272f, y, 130f, 34f); TextMeshProUGUI val4 = UiKit.NewText("RevertText", (Transform)(object)((Graphic)val3).rectTransform, "Revert", 15, UiKit.TextLight, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val4).rectTransform); Image val5 = UiKit.NewImage("Save", (Transform)(object)_body, _dirty ? UiKit.TabOn : UiKit.CellBg); UiKit.Place(((Graphic)val5).rectTransform, num - 414f, y, 130f, 34f); TextMeshProUGUI val6 = UiKit.NewText("SaveText", (Transform)(object)((Graphic)val5).rectTransform, "Save", 15, _dirty ? UiKit.Gold : UiKit.TextDim, (TextAlignmentOptions)514); UiKit.Stretch(((TMP_Text)val6).rectTransform); _hotspots.Add(val5, delegate { Save(); }); _hotspots.Add(val3, delegate { Revert(); Refresh(); Say("Reverted to the values this panel opened with.", warn: false); }); _hotspots.Add(val, delegate { if (_dirty) { Revert(); Log.Info("config panel: closed with unsaved changes, so they were discarded"); } Close(); }); } } public static class ModInfo { public const string Guid = "com.ryan.htfexpanded"; public const string Name = "How To Fish - Extended"; public const string Version = "3.0.3"; public const string Author = "Ryan"; public const string Build = ""; public static string Display => ("".Length == 0) ? "3.0.3" : "3.0.3 "; } public static class Log { private static Action _info; private static Action _warn; private static Action _error; public static void Bind(Action info, Action warn, Action error) { _info = info; _warn = warn; _error = error; } public static void Info(string m) { try { if (_info != null) { _info(m); } else { Debug.Log((object)("[HTFX] " + m)); } } catch { } } public static void Warn(string m) { try { if (_warn != null) { _warn(m); } else { Debug.LogWarning((object)("[HTFX] " + m)); } } catch { } } public static void Error(string m) { try { if (_error != null) { _error(m); } else { Debug.LogError((object)("[HTFX] " + m)); } } catch { } } public static void Ex(string where, Exception e) { try { Debug.LogError((object)("[HTFX] exception in " + where + ": " + e)); } catch { } } } public static class Cfg { private static readonly Dictionary _v = new Dictionary(StringComparer.OrdinalIgnoreCase); private static bool _loaded; public const int Version = 31; private static readonly Dictionary _defaultsChangedIn = new Dictionary { { 6, new string[3] { "ExtraGunTiers", "ExtraMeleeTiers", "GunDamageGrowth" } }, { 8, new string[1] { "VariantsFromBirds" } }, { 14, new string[4] { "AscensionCostGrowth", "AscensionHpGrowth", "AscensionValueGrowth", "AscensionLuckBonus" } }, { 18, new string[2] { "LuckMaxLevel", "LuckCostGrowth" } }, { 19, new string[2] { "LuckMaxLevel", "LuckBaseCost" } }, { 20, new string[1] { "LuckCostGrowth" } }, { 22, new string[2] { "LuckMaxLevel", "LuckCurveKnee" } }, { 26, new string[1] { "BackpackKey" } }, { 29, new string[1] { "HookSpread" } }, { 30, new string[3] { "FishScaleExponent=0.3333", "FishScaleMax=2.75", "ScaleBossFish=False" } }, { 31, new string[2] { "EnableExtraHooks=True", "HookCount=2" } } }; public static int ExtraGunTiers = -1; public static int ExtraMeleeTiers = -1; public static float GunDamageGrowth = 1.25f; public static float GunCostGrowth = 1.25f; public static int GunMinTierCost = 750; public static int GunDamageCeiling = 1000000000; public static int GunCostCeiling = 1000000000; public static bool UnlockShopCap = true; public static bool EnableVariants = true; public static bool UseColors = true; public static float VariantChanceMulti = 1f; public static bool VariantsFromDynamite = false; public static bool VariantsFromBirds = true; public static bool VariantsForFixedWeightCreatures = true; public static bool VariantsFromBosses = false; public static int SpawnLogCount = 200; public static int NameLogCount = 60; public static float OrdinaryChanceAtMaxLuck = 0.05f; public static bool EnableLuckShop = true; public static int LuckBaseCost = 250; public static float LuckCostGrowth = 1.05f; public static int LuckMaxLevel = 125; public static int LuckCurveKnee = 50; public static float LuckTopShare = 0.999f; public static int LuckCostStepInterval = 25; public static int LuckCostEarlyLevels = 10; public static float LuckCostLateMultiplier = 5f; public static float LuckBaseWeightBonus = 0.01f; public static float KioskOffsetRight = 0f; public static bool HighlightModStands = true; public static bool EnableAscension = true; public static int AscensionBaseCost = 250000; public static float AscensionCostGrowth = 1.43f; public static float AscensionHpGrowth = 1.45f; public static float AscensionValueGrowth = 1.25f; public static int AscensionLuckBonus = 4; public static int AscensionMaxLevel = 25; public static int AscensionIslandIndex = 0; public static bool EnableAscensionSlots = true; public static int AscensionSlotsPerTier = 1; public static bool EnableExtraHooks = false; public static int HookCount = 1; public static int MaxHookCount = 5; public static float HookSpread = 0.45f; public static bool EnableFishScaling = true; public static float FishScaleExponent = 0.5f; public static float FishScaleMin = 0.55f; public static float FishScaleMax = 5f; public static bool ScaleBossFish = true; public static bool EnableFishHealthBars = true; public static float FishHealthBarWidth = 1.6f; public static float FishHealthBarThickness = 0.16f; public static float FishHealthBarLift = 0.15f; public static float FishHealthBarOpacity = 0.9f; public static bool FishHealthBarOnlyWhenDamaged = false; public static bool EnableBackpack = true; public static string BackpackKey = "V"; public static int BackpackSlots = 30; public static int BackpackSlotsPerAscension = 5; public static int BackpackMaxSlots = 300; public static bool EnableCustomStandModels = true; public static string LuckStandModel = "luckstand"; public static string AscensionStandModel = "ascensionstand"; public static float StandModelScale = 1f; public static float StandModelYaw = 0f; public static float StandModelHeight = 0f; public static bool ModelPointFilter = true; public static bool UseBuiltInStandSpots = true; public static bool StandGroundSnap = true; public static float StandGroundSnapUp = 3f; public static float StandGroundSnapDown = 12f; public static bool StandModelPlainMaterial = true; public static bool PreventMoneyOverflow = true; public static int MaxItemWorth = 0; public static bool CapKillScoreAnimation = true; public static float KillScoreAnimationReference = 500f; public static bool EnableCatchStats = true; public static float CatchToastDuration = 3f; public static string TrophiesMenuKey = "F2"; public static bool EnableDebugMenu = false; public static string DebugMenuKey = "F1"; public static float KioskOffsetForward = 0f; public static string Dir => Application.persistentDataPath; public static string Path => Dir + "/HowToFishExpanded.cfg"; public static void EnsureLoaded() { if (_loaded) { return; } _loaded = true; try { if (File.Exists(Path)) { string[] array = File.ReadAllLines(Path); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length != 0 && text2[0] != '#' && text2[0] != ';') { int num = text2.IndexOf('='); if (num > 0) { _v[text2.Substring(0, num).Trim()] = text2.Substring(num + 1).Trim(); } } } int num2 = I("ConfigVersion", 1); if (num2 != 31) { string text3 = Path + ".v" + num2 + ".bak"; try { if (File.Exists(text3)) { File.Delete(text3); } File.Copy(Path, text3); } catch { } List list = new List(); List list2 = new List(); foreach (KeyValuePair item in _defaultsChangedIn) { if (item.Key <= num2 || item.Key > 31) { continue; } string[] value = item.Value; foreach (string text4 in value) { int num3 = text4.IndexOf('='); string text5 = ((num3 < 0) ? text4 : text4.Substring(0, num3)); string text6 = ((num3 < 0) ? null : text4.Substring(num3 + 1)); if (_v.TryGetValue(text5, out var value2)) { if (text6 == null || SameValue(value2, text6)) { _v.Remove(text5); list.Add(text5); } else { list2.Add(text5); } } } } Apply(); Variants.NormaliseTargets(); Write(); Log.Info("config upgraded from version " + num2 + " to " + 31 + ", your settings kept" + ((list.Count == 0) ? "" : (" except " + string.Join(", ", list.ToArray()) + " which took the new default" + ((list.Count == 1) ? "" : "s"))) + ((list2.Count == 0) ? "" : (". Shipped defaults also moved for " + string.Join(", ", list2.ToArray()) + " but you had changed " + ((list2.Count == 1) ? "it" : "them") + ", so your value" + ((list2.Count == 1) ? " was" : "s were") + " kept")) + ". Old file kept as " + System.IO.Path.GetFileName(text3)); } else { Apply(); Log.Info("config loaded from " + Path); } } else { Variants.NormaliseTargets(); Write(); Log.Info("wrote default config to " + Path); } } catch (Exception e) { Log.Ex("Cfg.EnsureLoaded", e); } } private static int I(string k, int d) { if (_v.TryGetValue(k, out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return d; } private static float F(string k, float d) { if (_v.TryGetValue(k, out var value) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return d; } private static string S(string k, string d) { string value; return (_v.TryGetValue(k, out value) && value.Trim().Length > 0) ? value.Trim() : d; } private static bool B(string k, bool d) { if (_v.TryGetValue(k, out var value)) { value = value.Trim().ToLowerInvariant(); if (value == "true" || value == "1" || value == "yes") { return true; } if (value == "false" || value == "0" || value == "no") { return false; } } return d; } private static bool SameValue(string have, string wasDefault) { if (have == null || wasDefault == null) { return false; } have = have.Trim(); wasDefault = wasDefault.Trim(); if (float.TryParse(have, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(wasDefault, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return Math.Abs(result - result2) <= 1E-06f * Math.Max(1f, Math.Abs(result2)); } return string.Equals(have, wasDefault, StringComparison.OrdinalIgnoreCase); } private static void Apply() { ExtraGunTiers = Mathf.Clamp(I("ExtraGunTiers", ExtraGunTiers), -1, 255); ExtraMeleeTiers = Mathf.Clamp(I("ExtraMeleeTiers", ExtraMeleeTiers), -1, 255); GunDamageGrowth = Mathf.Clamp(F("GunDamageGrowth", GunDamageGrowth), 1f, 3f); GunCostGrowth = Mathf.Clamp(F("GunCostGrowth", GunCostGrowth), 1.01f, 3f); GunMinTierCost = Mathf.Max(1, I("GunMinTierCost", GunMinTierCost)); GunDamageCeiling = Mathf.Clamp(I("GunDamageCeiling", GunDamageCeiling), 1000, 2000000000); GunCostCeiling = Mathf.Clamp(I("GunCostCeiling", GunCostCeiling), 1000, 2000000000); UnlockShopCap = B("UnlockShopCap", UnlockShopCap); EnableVariants = B("EnableVariants", EnableVariants); UseColors = B("UseColors", UseColors); VariantChanceMulti = Mathf.Clamp(F("VariantChanceMulti", VariantChanceMulti), 0f, 25f); VariantsFromDynamite = B("VariantsFromDynamite", VariantsFromDynamite); VariantsFromBirds = B("VariantsFromBirds", VariantsFromBirds); VariantsForFixedWeightCreatures = B("VariantsForFixedWeightCreatures", VariantsForFixedWeightCreatures); VariantsFromBosses = B("VariantsFromBosses", VariantsFromBosses); SpawnLogCount = Mathf.Clamp(I("SpawnLogCount", SpawnLogCount), 0, 5000); NameLogCount = Mathf.Clamp(I("NameLogCount", NameLogCount), 0, 5000); OrdinaryChanceAtMaxLuck = Mathf.Clamp(F("OrdinaryChanceAtMaxLuck", OrdinaryChanceAtMaxLuck), 0.001f, 1f); EnableCustomStandModels = B("EnableCustomStandModels", EnableCustomStandModels); LuckStandModel = S("LuckStandModel", LuckStandModel); AscensionStandModel = S("AscensionStandModel", AscensionStandModel); StandModelScale = Mathf.Clamp(F("StandModelScale", StandModelScale), 0.001f, 1000f); StandModelYaw = F("StandModelYaw", StandModelYaw); StandModelHeight = Mathf.Clamp(F("StandModelHeight", StandModelHeight), -50f, 50f); ModelPointFilter = B("ModelPointFilter", ModelPointFilter); UseBuiltInStandSpots = B("UseBuiltInStandSpots", UseBuiltInStandSpots); StandGroundSnap = B("StandGroundSnap", StandGroundSnap); StandGroundSnapUp = Mathf.Clamp(F("StandGroundSnapUp", StandGroundSnapUp), 0.5f, 50f); StandGroundSnapDown = Mathf.Clamp(F("StandGroundSnapDown", StandGroundSnapDown), 1f, 200f); StandModelPlainMaterial = B("StandModelPlainMaterial", StandModelPlainMaterial); PreventMoneyOverflow = B("PreventMoneyOverflow", PreventMoneyOverflow); MaxItemWorth = Mathf.Max(0, I("MaxItemWorth", MaxItemWorth)); CapKillScoreAnimation = B("CapKillScoreAnimation", CapKillScoreAnimation); KillScoreAnimationReference = Mathf.Clamp(F("KillScoreAnimationReference", KillScoreAnimationReference), 10f, 1000000f); EnableCatchStats = B("EnableCatchStats", EnableCatchStats); CatchToastDuration = Mathf.Clamp(F("CatchToastDuration", CatchToastDuration), 0.5f, 20f); TrophiesMenuKey = S("TrophiesMenuKey", TrophiesMenuKey); EnableLuckShop = B("EnableLuckShop", EnableLuckShop); LuckBaseCost = Mathf.Max(1, I("LuckBaseCost", LuckBaseCost)); LuckCostGrowth = Mathf.Clamp(F("LuckCostGrowth", LuckCostGrowth), 1.01f, 3f); LuckMaxLevel = Mathf.Clamp(I("LuckMaxLevel", LuckMaxLevel), 0, 250); LuckCurveKnee = Mathf.Clamp(I("LuckCurveKnee", LuckCurveKnee), 1, 250); LuckCostStepInterval = Mathf.Clamp(I("LuckCostStepInterval", LuckCostStepInterval), 0, 1000); LuckCostEarlyLevels = Mathf.Clamp(I("LuckCostEarlyLevels", LuckCostEarlyLevels), 0, 1000); LuckCostLateMultiplier = Mathf.Clamp(F("LuckCostLateMultiplier", LuckCostLateMultiplier), 1f, 1000f); LuckTopShare = Mathf.Clamp(F("LuckTopShare", LuckTopShare), 0f, 0.9999f); LuckBaseWeightBonus = Mathf.Clamp(F("LuckBaseWeightBonus", LuckBaseWeightBonus), 0f, 0.2f); KioskOffsetRight = F("KioskOffsetRight", KioskOffsetRight); KioskOffsetForward = F("KioskOffsetForward", KioskOffsetForward); HighlightModStands = B("HighlightModStands", HighlightModStands); EnableAscension = B("EnableAscension", EnableAscension); AscensionBaseCost = Mathf.Max(1, I("AscensionBaseCost", AscensionBaseCost)); AscensionCostGrowth = Mathf.Clamp(F("AscensionCostGrowth", AscensionCostGrowth), 1.01f, 10f); AscensionHpGrowth = Mathf.Clamp(F("AscensionHpGrowth", AscensionHpGrowth), 1f, 100f); AscensionValueGrowth = Mathf.Clamp(F("AscensionValueGrowth", AscensionValueGrowth), 1f, 100f); AscensionLuckBonus = Mathf.Clamp(I("AscensionLuckBonus", AscensionLuckBonus), 0, 500); AscensionMaxLevel = Mathf.Clamp(I("AscensionMaxLevel", AscensionMaxLevel), 0, 200); AscensionIslandIndex = Mathf.Clamp(I("AscensionIslandIndex", AscensionIslandIndex), -1, 32); EnableAscensionSlots = B("EnableAscensionSlots", EnableAscensionSlots); AscensionSlotsPerTier = Mathf.Clamp(I("AscensionSlotsPerTier", AscensionSlotsPerTier), 0, 32); EnableExtraHooks = B("EnableExtraHooks", EnableExtraHooks); MaxHookCount = Mathf.Clamp(I("MaxHookCount", MaxHookCount), 1, 10); HookCount = Mathf.Clamp(I("HookCount", HookCount), 1, MaxHookCount); HookSpread = Mathf.Clamp(F("HookSpread", HookSpread), 0f, 2f); EnableFishScaling = B("EnableFishScaling", EnableFishScaling); FishScaleExponent = Mathf.Clamp(F("FishScaleExponent", FishScaleExponent), 0f, 1f); FishScaleMin = Mathf.Clamp(F("FishScaleMin", FishScaleMin), 0.05f, 1f); FishScaleMax = Mathf.Clamp(F("FishScaleMax", FishScaleMax), 1f, 10f); ScaleBossFish = B("ScaleBossFish", ScaleBossFish); EnableFishHealthBars = B("EnableFishHealthBars", EnableFishHealthBars); FishHealthBarWidth = Mathf.Clamp(F("FishHealthBarWidth", FishHealthBarWidth), 0.5f, 4f); FishHealthBarThickness = Mathf.Clamp(F("FishHealthBarThickness", FishHealthBarThickness), 0.05f, 0.6f); FishHealthBarLift = Mathf.Clamp(F("FishHealthBarLift", FishHealthBarLift), 0f, 1.5f); FishHealthBarOpacity = Mathf.Clamp(F("FishHealthBarOpacity", FishHealthBarOpacity), 0.2f, 1f); FishHealthBarOnlyWhenDamaged = B("FishHealthBarOnlyWhenDamaged", FishHealthBarOnlyWhenDamaged); EnableBackpack = B("EnableBackpack", EnableBackpack); BackpackKey = S("BackpackKey", BackpackKey); BackpackMaxSlots = Mathf.Clamp(I("BackpackMaxSlots", BackpackMaxSlots), 0, 3000); BackpackSlots = Mathf.Clamp(I("BackpackSlots", BackpackSlots), 0, BackpackMaxSlots); BackpackSlotsPerAscension = Mathf.Clamp(I("BackpackSlotsPerAscension", BackpackSlotsPerAscension), 0, 100); EnableDebugMenu = B("EnableDebugMenu", EnableDebugMenu); if (_v.TryGetValue("DebugMenuKey", out var value) && !string.IsNullOrEmpty(value.Trim())) { DebugMenuKey = value.Trim(); } Variants.LoadOverrides(_v); Variants.NormaliseTargets(); } public static void Write() { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# How To Fish - Extended"); stringBuilder.AppendLine("ConfigVersion=" + 31); stringBuilder.AppendLine("# Edit values and restart the game. Delete this file to reset to defaults."); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Weapon / melee upgrades ----------"); stringBuilder.AppendLine("# How many upgrade tiers to add on top of the ones the game ships with."); stringBuilder.AppendLine("# -1 means as many as the game can address (255 tiers total), so the ladder"); stringBuilder.AppendLine("# never runs out however far you push Ascension."); stringBuilder.AppendLine("ExtraGunTiers=" + ExtraGunTiers); stringBuilder.AppendLine("ExtraMeleeTiers=" + ExtraMeleeTiers); stringBuilder.AppendLine("# Damage step growth per added tier. Keep this equal to GunCostGrowth and a"); stringBuilder.AppendLine("# given amount of money always buys about the same amount of power. Setting it"); stringBuilder.AppendLine("# lower than GunCostGrowth means damage falls behind health as you ascend."); stringBuilder.AppendLine("GunDamageGrowth=" + GunDamageGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Each added tier costs this much more than the one before it, starting"); stringBuilder.AppendLine("# from the weapon's own last vanilla price. 1.25 = a 25% step each time."); stringBuilder.AppendLine("# Raise it for a longer grind; lower it to make the late tiers reachable sooner."); stringBuilder.AppendLine("GunCostGrowth=" + GunCostGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("GunMinTierCost=" + GunMinTierCost); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Damage and price are whole numbers and cannot exceed about 2.1 billion."); stringBuilder.AppendLine("# The two growth rates above are therefore treated as an UPPER BOUND: each"); stringBuilder.AppendLine("# weapon's curve is fitted so its very last tier lands on the ceilings below,"); stringBuilder.AppendLine("# instead of running out of range with a couple of hundred tiers still to go."); stringBuilder.AppendLine("# Lower a ceiling for a gentler climb, raise it for a steeper one."); stringBuilder.AppendLine("GunDamageCeiling=" + GunDamageCeiling); stringBuilder.AppendLine("GunCostCeiling=" + GunCostCeiling); stringBuilder.AppendLine("# Let the shop that already sold the last vanilla tier sell all the new ones."); stringBuilder.AppendLine("UnlockShopCap=" + UnlockShopCap); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Fish variants ----------"); stringBuilder.AppendLine("EnableVariants=" + EnableVariants); stringBuilder.AppendLine("# Colour the variant prefix in hover text / kill feed."); stringBuilder.AppendLine("UseColors=" + UseColors); stringBuilder.AppendLine("# Dynamite conjures fish out of nothing and kills them instantly, so letting"); stringBuilder.AppendLine("# it roll variants turns one stick into a pile of jackpots. Off by default."); stringBuilder.AppendLine("VariantsFromDynamite=" + VariantsFromDynamite); stringBuilder.AppendLine("# Seagulls and other birds are creatures too, so they roll variants like"); stringBuilder.AppendLine("# fish do. On by default; set false to keep variants to the water."); stringBuilder.AppendLine("VariantsFromBirds=" + VariantsFromBirds); stringBuilder.AppendLine("# The game skips the weight roll entirely for some species - it pins them"); stringBuilder.AppendLine("# to a flat 1.0 - so they could never be a variant at any luck level. This"); stringBuilder.AppendLine("# rolls for them too. It only ever raises a weight, never lowers one, so a"); stringBuilder.AppendLine("# creature that ships at a deliberate size keeps it unless the roll beats it."); stringBuilder.AppendLine("VariantsForFixedWeightCreatures=" + VariantsForFixedWeightCreatures); stringBuilder.AppendLine("# Bosses stay out of it by default - Ascension is the dial for those."); stringBuilder.AppendLine("VariantsFromBosses=" + VariantsFromBosses); stringBuilder.AppendLine("# How many spawns to log at startup, so you can check what rolled what."); stringBuilder.AppendLine("SpawnLogCount=" + SpawnLogCount); stringBuilder.AppendLine("# How many name lookups to log, so you can see whether the variant prefix"); stringBuilder.AppendLine("# is reaching the UI as well as whether the weight rolled correctly."); stringBuilder.AppendLine("NameLogCount=" + NameLogCount); stringBuilder.AppendLine("# Global multiplier on every variant's roll chance."); stringBuilder.AppendLine("VariantChanceMulti=" + VariantChanceMulti.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Share of catches that are still ordinary fish once luck is maxed."); stringBuilder.AppendLine("# 0.05 means 95% of catches are variants at the top luck level."); stringBuilder.AppendLine("OrdinaryChanceAtMaxLuck=" + OrdinaryChanceAtMaxLuck.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(); Variants.WriteDefaults(stringBuilder); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Custom stand models ----------"); stringBuilder.AppendLine("# Drop a Wavefront .obj, its .mtl and the textures it names into"); stringBuilder.AppendLine("# " + Dir + "/HowToFishExpanded/models"); stringBuilder.AppendLine("# and the matching stand wears it instead of looking like the stall it was"); stringBuilder.AppendLine("# cloned from. OBJ is plain text and not tied to any Unity version, so a"); stringBuilder.AppendLine("# game update cannot invalidate a model. A .obj.gz is read too."); stringBuilder.AppendLine("# Only the appearance changes - if a model fails to load the stand still"); stringBuilder.AppendLine("# works, it just keeps the stall's look."); stringBuilder.AppendLine("EnableCustomStandModels=" + EnableCustomStandModels); stringBuilder.AppendLine("LuckStandModel=" + LuckStandModel); stringBuilder.AppendLine("AscensionStandModel=" + AscensionStandModel); stringBuilder.AppendLine("# Scale, spin and lift the model to sit it on the counter properly."); stringBuilder.AppendLine("StandModelScale=" + StandModelScale.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("StandModelYaw=" + StandModelYaw.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("StandModelHeight=" + StandModelHeight.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Point filtering keeps a small hand-drawn texture crisp. False smooths it."); stringBuilder.AppendLine("ModelPointFilter=" + ModelPointFilter); stringBuilder.AppendLine("# A saved spot is where YOU were standing, and the game's player position"); stringBuilder.AppendLine("# is not at your feet, so a stand put exactly there floats at chest height."); stringBuilder.AppendLine("# This looks down from the saved point and lands it on the ground instead."); stringBuilder.AppendLine("# The mod ships with a stand position for each island, recorded in game."); stringBuilder.AppendLine("# A spot you save yourself always wins over these; set this false to ignore"); stringBuilder.AppendLine("# them entirely and go back to automatic placement."); stringBuilder.AppendLine("UseBuiltInStandSpots=" + UseBuiltInStandSpots); stringBuilder.AppendLine("StandGroundSnap=" + StandGroundSnap); stringBuilder.AppendLine("StandGroundSnapUp=" + StandGroundSnapUp.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("StandGroundSnapDown=" + StandGroundSnapDown.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Materials are copied from the stall the stand replaced. Some stall parts"); stringBuilder.AppendLine("# use the game's shiny or animated shaders, which turn a copied model into"); stringBuilder.AppendLine("# a rainbow. This strips the glow and scrolling back off."); stringBuilder.AppendLine("StandModelPlainMaterial=" + StandModelPlainMaterial); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Money ----------"); stringBuilder.AppendLine("# Money is a 32-bit number, so $2,147,483,647 is as high as it can go, and"); stringBuilder.AppendLine("# the game adds to it without checking. One payout past the limit wraps the"); stringBuilder.AppendLine("# balance round to about minus two billion, which then fails every price"); stringBuilder.AppendLine("# check so nothing can be bought. This holds it at the limit instead, and"); stringBuilder.AppendLine("# repairs a balance that has already wrapped."); stringBuilder.AppendLine("PreventMoneyOverflow=" + PreventMoneyOverflow); stringBuilder.AppendLine("# Ceiling on what any one item can be worth. 0 means no cap. Ascension"); stringBuilder.AppendLine("# doubles fish value per tier, so past about tier 15 a single good catch"); stringBuilder.AppendLine("# can fill your balance to the limit on its own. Set a number here if you"); stringBuilder.AppendLine("# would rather that took a while."); stringBuilder.AppendLine("MaxItemWorth=" + MaxItemWorth); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Kill score popup ----------"); stringBuilder.AppendLine("# The popup counts the score up at a fixed rate, so the bigger the number"); stringBuilder.AppendLine("# the longer it sits on screen, and kills queue up behind it. This speeds"); stringBuilder.AppendLine("# the count-up in proportion to the score so it takes about as long as it"); stringBuilder.AppendLine("# always did. Scores under the reference keep exactly the vanilla timing."); stringBuilder.AppendLine("CapKillScoreAnimation=" + CapKillScoreAnimation); stringBuilder.AppendLine("KillScoreAnimationReference=" + KillScoreAnimationReference.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Luck ----------"); stringBuilder.AppendLine("EnableLuckShop=" + EnableLuckShop); stringBuilder.AppendLine("LuckBaseCost=" + LuckBaseCost); stringBuilder.AppendLine("# Charm price = LuckBaseCost * Growth^level * 2^(level/StepInterval)."); stringBuilder.AppendLine("# The first charm is LuckBaseCost; the price doubles every StepInterval"); stringBuilder.AppendLine("# levels on top of the per-level growth."); stringBuilder.AppendLine("LuckCostGrowth=" + LuckCostGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("LuckMaxLevel=" + LuckMaxLevel); stringBuilder.AppendLine("# Every this many levels the charm price doubles. 0 = no step."); stringBuilder.AppendLine("LuckCostStepInterval=" + LuckCostStepInterval); stringBuilder.AppendLine("# Number of cheap early levels before the late multiplier kicks in."); stringBuilder.AppendLine("LuckCostEarlyLevels=" + LuckCostEarlyLevels); stringBuilder.AppendLine("# Price multiplier from LuckCostEarlyLevels onwards."); stringBuilder.AppendLine("LuckCostLateMultiplier=" + LuckCostLateMultiplier.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Below the knee, luck slides each tier from its chanceAtLuck0 to its"); stringBuilder.AppendLine("# chanceAtMaxLuck exactly as it always did; at the knee the odds are the"); stringBuilder.AppendLine("# shipped max-luck table. Above the knee each tier's weight is multiplied"); stringBuilder.AppendLine("# by g^rank and the whole table renormalised, so the odds slide up the"); stringBuilder.AppendLine("# ladder and the rarest tier converges on certainty."); stringBuilder.AppendLine("LuckCurveKnee=" + LuckCurveKnee); stringBuilder.AppendLine("# The rarest tier's share at LuckMaxLevel. 0.999 = 99.9% Mythic at the top."); stringBuilder.AppendLine("LuckTopShare=" + LuckTopShare.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(); stringBuilder.AppendLine("# Each luck level also nudges ordinary catches this much heavier."); stringBuilder.AppendLine("LuckBaseWeightBonus=" + LuckBaseWeightBonus.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Extra nudge for the Lucky Charm stand, if the automatic spot looks off."); stringBuilder.AppendLine("# It normally places itself at the free end of the bait stall row."); stringBuilder.AppendLine("KioskOffsetRight=" + KioskOffsetRight.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("KioskOffsetForward=" + KioskOffsetForward.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Keep the mod's stands outlined so they stand out from ordinary stalls."); stringBuilder.AppendLine("HighlightModStands=" + HighlightModStands); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Ascension (new game+) ----------"); stringBuilder.AppendLine("# Unlocks after you finish the game. A stand on the first island sells"); stringBuilder.AppendLine("# tiers; each one multiplies every creature's health, and pays for it"); stringBuilder.AppendLine("# with higher fish value and free luck levels."); stringBuilder.AppendLine("EnableAscension=" + EnableAscension); stringBuilder.AppendLine("# Price = BaseCost * Growth^tier. Money is capped at about 2.1 billion by"); stringBuilder.AppendLine("# the game itself, which is what really limits how many tiers are reachable."); stringBuilder.AppendLine("AscensionBaseCost=" + AscensionBaseCost); stringBuilder.AppendLine("AscensionCostGrowth=" + AscensionCostGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Creature health and fish value are each multiplied by their growth^tier."); stringBuilder.AppendLine("AscensionHpGrowth=" + AscensionHpGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("AscensionValueGrowth=" + AscensionValueGrowth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Free luck levels per tier. Capped by LuckMaxLevel like any other luck."); stringBuilder.AppendLine("AscensionLuckBonus=" + AscensionLuckBonus); stringBuilder.AppendLine("# Money is a 32-bit number, so the ladder only has about 8,590x of cost"); stringBuilder.AppendLine("# growth to spend in total. That makes the growth rate decide the tier"); stringBuilder.AppendLine("# count outright: x2.5 gives 10 tiers, x1.43 gives 25, x1.15 gives 64."); stringBuilder.AppendLine("# Raising CostGrowth does not make the ladder longer, only shorter."); stringBuilder.AppendLine("AscensionMaxLevel=" + AscensionMaxLevel); stringBuilder.AppendLine("# Which island the stand appears on. 0 is the first; -1 puts it on all of them."); stringBuilder.AppendLine("AscensionIslandIndex=" + AscensionIslandIndex); stringBuilder.AppendLine("# Extra inventory slots, one per ascension tier by default. The inventory UI"); stringBuilder.AppendLine("# has a fixed number of slot objects and the game indexes straight into that"); stringBuilder.AppendLine("# list, so the bonus is capped at however many exist - going past it is an"); stringBuilder.AppendLine("# index error on the next pickup, not a cosmetic problem. The log says how"); stringBuilder.AppendLine("# many slots your build actually has."); stringBuilder.AppendLine("EnableAscensionSlots=" + EnableAscensionSlots); stringBuilder.AppendLine("AscensionSlotsPerTier=" + AscensionSlotsPerTier); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Extra hooks (test) ----------"); stringBuilder.AppendLine("# More than one fish on the line at once. The game allows exactly one,"); stringBuilder.AppendLine("# but only as a bookkeeping check - the physics already copes, because a"); stringBuilder.AppendLine("# caught fish carries its own joint to the bait. Each extra fish still"); stringBuilder.AppendLine("# takes a full catch timer, so this is patience, not free fish."); stringBuilder.AppendLine("# This is a test of the mechanism; it is not an upgrade you buy yet."); stringBuilder.AppendLine("EnableExtraHooks=" + EnableExtraHooks); stringBuilder.AppendLine("# 1 is vanilla. Try 3 to see how the line behaves with a full load."); stringBuilder.AppendLine("HookCount=" + HookCount); stringBuilder.AppendLine("MaxHookCount=" + MaxHookCount); stringBuilder.AppendLine("# How far apart they hang, in metres: each fish drops this much further"); stringBuilder.AppendLine("# down the trace and kicks out to alternating sides. 0 stacks them."); stringBuilder.AppendLine("HookSpread=" + HookSpread.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Fish size ----------"); stringBuilder.AppendLine("# Draws a fish at a size that matches its weight, so a Mythic looks like"); stringBuilder.AppendLine("# one. The game never does this by itself - weight only drives the name,"); stringBuilder.AppendLine("# the value and the readout."); stringBuilder.AppendLine("EnableFishScaling=" + EnableFishScaling); stringBuilder.AppendLine("# size = weight ^ exponent. Mass goes as volume and volume as the cube of"); stringBuilder.AppendLine("# length, so 0.3333 is the physically honest one - but honest reads as too"); stringBuilder.AppendLine("# small, so the shipped 0.5 exaggerates it: a 15x Mythic draws at 3.9x"); stringBuilder.AppendLine("# rather than 2.5x. 0 turns scaling off, 1 is linear and absurd."); stringBuilder.AppendLine("FishScaleExponent=" + FishScaleExponent.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Hard limits, whatever the exponent works out to."); stringBuilder.AppendLine("FishScaleMin=" + FishScaleMin.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("FishScaleMax=" + FishScaleMax.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Bosses are built at a deliberate size. This only bites when"); stringBuilder.AppendLine("# VariantsFromBosses is on too: without it a boss keeps the flat 1.0"); stringBuilder.AppendLine("# weight the game gives it, and 1.0 scales to exactly 1.0."); stringBuilder.AppendLine("ScaleBossFish=" + ScaleBossFish); stringBuilder.AppendLine("# A small health bar above each fish, drained as it is fought."); stringBuilder.AppendLine("EnableFishHealthBars=" + EnableFishHealthBars); stringBuilder.AppendLine("# Bar size, in world units."); stringBuilder.AppendLine("FishHealthBarWidth=" + FishHealthBarWidth.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("FishHealthBarThickness=" + FishHealthBarThickness.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Gap between the fish and the bar, in world units."); stringBuilder.AppendLine("FishHealthBarLift=" + FishHealthBarLift.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Overall transparency, 0..1."); stringBuilder.AppendLine("FishHealthBarOpacity=" + FishHealthBarOpacity.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("# Hide the bar until the fish has taken damage."); stringBuilder.AppendLine("FishHealthBarOnlyWhenDamaged=" + FishHealthBarOnlyWhenDamaged); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Storage panel ----------"); stringBuilder.AppendLine("# The mod's own inventory window, with a Trophies tab. The game's hotbar"); stringBuilder.AppendLine("# cannot grow past nine slots - it seeds its item store with exactly nine"); stringBuilder.AppendLine("# keys and indexes straight into a fixed list of slot objects - so all the"); stringBuilder.AppendLine("# room above that lives here instead. Stored items are records, not objects:"); stringBuilder.AppendLine("# they cost nothing until you take them back out."); stringBuilder.AppendLine("# Host only for now; a client can open the panel but not move anything."); stringBuilder.AppendLine("EnableBackpack=" + EnableBackpack); stringBuilder.AppendLine("# Any key name from Unity's input system: B, Tab, I, ..."); stringBuilder.AppendLine("BackpackKey=" + BackpackKey); stringBuilder.AppendLine("# Total room = BackpackSlots + BackpackSlotsPerAscension * ascension tier."); stringBuilder.AppendLine("BackpackSlots=" + BackpackSlots); stringBuilder.AppendLine("BackpackSlotsPerAscension=" + BackpackSlotsPerAscension); stringBuilder.AppendLine("BackpackMaxSlots=" + BackpackMaxSlots); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Catch stats & trophies ----------"); stringBuilder.AppendLine("# Records every fish you catch - species, variant tier, weight and"); stringBuilder.AppendLine("# value - into a per-save and a lifetime ledger, with a Trophies view"); stringBuilder.AppendLine("# in the debug menu and a \"new best\" toast."); stringBuilder.AppendLine("EnableCatchStats=" + EnableCatchStats); stringBuilder.AppendLine("CatchToastDuration=" + CatchToastDuration.ToString(CultureInfo.InvariantCulture)); stringBuilder.AppendLine("TrophiesMenuKey=" + TrophiesMenuKey); stringBuilder.AppendLine(); stringBuilder.AppendLine("# ---------- Debug menu ----------"); stringBuilder.AppendLine("# In-game overlay showing live stats, with buttons for money, luck,"); stringBuilder.AppendLine("# fish weights and weapon tiers. Off by default because it can hand"); stringBuilder.AppendLine("# out money and luck. Host-only for anything it changes."); stringBuilder.AppendLine("EnableDebugMenu=" + EnableDebugMenu); stringBuilder.AppendLine("# Any key name from Unity's input system: F1, F2, Insert, Backquote, ..."); stringBuilder.AppendLine("DebugMenuKey=" + DebugMenuKey); Directory.CreateDirectory(Dir); File.WriteAllText(Path, stringBuilder.ToString()); } catch (Exception e) { Log.Ex("Cfg.Write", e); } } } public sealed class CreditEntry { public readonly string Name; public readonly string Note; public CreditEntry(string name) : this(name, null) { } public CreditEntry(string name, string note) { Name = (string.IsNullOrEmpty(name) ? "?" : name.Trim()); Note = (string.IsNullOrEmpty(note) ? null : note.Trim()); } } public static class Credits { public const string ModName = "How To Fish - Extended"; public static readonly CreditEntry[] Authors = new CreditEntry[1] { new CreditEntry("Ryan", "made the mod") }; public static readonly CreditEntry[] Testers = new CreditEntry[4] { new CreditEntry("SeizureSalad", "Mod and helping around the Discord server"), new CreditEntry("ʟ ᴇ ɢ ᴀ ᴄ ʏトム", "HP BUG FINDER"), new CreditEntry("Gnumber82", "Helping in the discord"), new CreditEntry("Nathan", "Mod and supporting since the start") }; public static readonly string[] Thanks = new string[2] { "Everyone in the Discord who tested builds and sent logs back.", "Dazed Games, for a game worth modding." }; public static bool HasTesters => Testers != null && Testers.Length != 0; } public class DebugMenu : MonoBehaviour { private static DebugMenu _instance; private bool _open; private Rect _rect = new Rect(40f, 40f, 470f, 620f); private Vector2 _scroll; private int _tab; private readonly string[] _tabs = new string[5] { "Stats", "Money & Luck", "Fish", "Weapons", "Stands" }; private string _moneyField = "100000"; private string _luckField = "10"; private string _weightField = "1.0"; private string _notice = ""; private string _selfTest = ""; private float _noticeUntil; private float _fps; private Key _toggleKey = (Key)94; private string _spotNote = ""; private static bool IsHost { get { try { return InstanceFinder.IsServerStarted; } catch { return false; } } } private static Player Me => Player.LocalPlayer; private static Item Held { get { try { Player me = Me; return ((Object)(object)me != (Object)null && (Object)(object)me.Holding != (Object)null) ? me.Holding.HeldItem : null; } catch { return null; } } } public static void Bootstrap() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown try { Cfg.EnsureLoaded(); if (Cfg.EnableDebugMenu && !((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("HTFX_DebugMenu"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); Log.Info("debug menu ready - press " + Cfg.DebugMenuKey + " to open"); } } catch (Exception e) { Log.Ex("DebugMenu.Bootstrap", e); } } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!Enum.TryParse(Cfg.DebugMenuKey, ignoreCase: true, out _toggleKey)) { _toggleKey = (Key)94; } } private void Say(string msg) { _notice = msg; _noticeUntil = Time.unscaledTime + 4f; Log.Info("debug menu: " + msg); } private void Update() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) try { _fps = Mathf.Lerp(_fps, 1f / Mathf.Max(Time.unscaledDeltaTime, 0.0001f), 0.1f); Keyboard current = Keyboard.current; if (current != null && ((ButtonControl)current[_toggleKey]).wasPressedThisFrame) { Toggle(); } if (_open) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } } catch (Exception e) { Log.Ex("DebugMenu.Update", e); } } private void Toggle() { _open = !_open; try { PlayerInput input = GameInfo.Input; if ((Object)(object)input != (Object)null) { if (_open) { input.DeactivateInput(); } else { input.ActivateInput(); } } } catch (Exception e) { Log.Ex("DebugMenu.Toggle input", e); } if (!_open) { Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; } } private void OnGUI() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!_open) { return; } try { _rect = GUI.Window(1213482584, _rect, new WindowFunction(DrawWindow), "How To Fish - Extended (debug)"); } catch (Exception e) { Log.Ex("DebugMenu.OnGUI", e); } } private static Transform BodyOf(Player p) { if ((Object)(object)p == (Object)null) { return null; } try { if ((Object)(object)p.Transform != (Object)null) { return p.Transform; } } catch { } return ((Component)p).transform; } private bool RequireHost() { if (IsHost) { return true; } Say("host only - the server owns these values"); return false; } private void DrawWindow(int id) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) //IL_0114: Unknown result type (might be due to invalid IL or missing references) _tab = GUILayout.Toolbar(_tab, _tabs, Array.Empty()); GUILayout.Space(4f); _scroll = GUILayout.BeginScrollView(_scroll, Array.Empty()); switch (_tab) { case 0: DrawStats(); break; case 1: DrawMoneyAndLuck(); break; case 2: DrawFish(); break; case 3: DrawWeapons(); break; case 4: DrawStands(); break; } GUILayout.EndScrollView(); if (!string.IsNullOrEmpty(_notice) && Time.unscaledTime < _noticeUntil) { GUILayout.Space(2f); GUILayout.Label(_notice, Array.Empty()); } GUILayout.Label("Press " + ((object)Unsafe.As(ref _toggleKey)/*cast due to .constrained prefix*/).ToString() + " to close.", Array.Empty()); GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f)); } private static void Row(string label, string value) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) }); GUILayout.Label(value, Array.Empty()); GUILayout.EndHorizontal(); } private static void Header(string text) { GUILayout.Space(6f); GUILayout.Label("--- " + text + " ---", Array.Empty()); } private void DrawStats() { //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) Header("session"); Row("role", IsHost ? "host / server" : "client"); Row("fps", _fps.ToString("0")); try { Row("world seed", GameInfo.Seed.ToString()); } catch { } try { ServerSaveObject curServerSave = SaveManager.CurServerSave; if (curServerSave != null) { Row("world", curServerSave.Name); Row("island", curServerSave.SpawnedIsland + " (max reached " + curServerSave.MaxIsland + ")"); Row("playtime", (curServerSave.Playtime / 3600f).ToString("0.00") + " h"); } } catch { } Header("player"); Player me = Me; if ((Object)(object)me == (Object)null) { GUILayout.Label("no local player yet", Array.Empty()); } else { try { PlayerVitals vitals = me.Vitals; if ((Object)(object)vitals != (Object)null) { Row("health", vitals._syncedHealth.Value.ToString()); Row("fullness", vitals._syncedFullness.Value.ToString()); Row("poison", vitals._syncedPoison.Value.ToString()); Row("fire", vitals._syncedFire.Value.ToString()); } } catch { } try { Transform val = BodyOf(me); if ((Object)(object)val != (Object)null) { Vector3 position = val.position; Row("position", ((Vector3)(ref position)).ToString("0.0")); } } catch { } } Header("economy"); try { Row("money", "$" + MoneyManager.Money.ToString("N0")); } catch { } Row("luck level", Luck.Level + " / " + Cfg.LuckMaxLevel + ((Ascension.LuckBonus() > 0) ? (" (+" + Ascension.LuckBonus() + " from ascension -> " + Luck.EffectiveLevel + ")") : "")); int num = Luck.CostForNextLevel(); Row("next charm", (num < 0) ? "maxed" : ("$" + num.ToString("N0"))); Row("rare fish chance", Luck.ChanceMultiplier().ToString("0.00") + "x"); Header("ascension (new game+)"); Row("unlocked", Ascension.Unlocked ? "yes - game finished" : "no - finish the game first"); Row("tier", Ascension.Level + " / " + Ascension.MaxLevel); Row("creature health", "x" + Ascension.HpMultiplier().ToString("0.##")); Row("fish value", "x" + Ascension.ValueMultiplier().ToString("0.##")); int num2 = Ascension.CostForNextLevel(); Row("next tier", (num2 < 0) ? "top tier reached" : ("$" + num2.ToString("N0"))); Row("wallet", "$" + Money.Current.ToString("N0") + " (ceiling $2,147,483,647)"); Header("held item"); DrawHeldSummary(); Header("variant odds at effective luck " + Luck.EffectiveLevel); Row("bought", Luck.Level + " / " + Cfg.LuckMaxLevel); Row("from ascension", "+" + Ascension.LuckBonus() + ((Luck.Level + Ascension.LuckBonus() > Cfg.LuckMaxLevel) ? " (capped)" : "")); Row("effective", Luck.EffectiveLevel.ToString()); if (Luck.Level >= Cfg.LuckMaxLevel && Ascension.LuckBonus() > 0) { GUILayout.Label("luck is already at the cap, so the ascension bonus has nowhere to go", Array.Empty()); } DrawOddsTable(); Header("mod stands on this island"); DrawStandLocator(); } private void DrawStands() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) Player me = Me; int currentIsland = Spots.CurrentIsland; Header("where you are"); if ((Object)(object)me == (Object)null) { GUILayout.Label("no player yet - load into a world first", Array.Empty()); return; } Transform val = BodyOf(me); if ((Object)(object)val == (Object)null) { GUILayout.Label("cannot read your position yet", Array.Empty()); return; } Vector3 position = val.position; float y = val.eulerAngles.y; Row("island", currentIsland.ToString()); Row("position", ((Vector3)(ref position)).ToString("0.00")); Row("facing", y.ToString("0") + " degrees"); GUILayout.Space(6f); Header("save this place"); GUILayout.Label("Stand where you want it, face the way it should face, then press a button.", GUI.skin.label, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("save as Lucky Charm spot", Array.Empty())) { Save("luck", position, y); } if (GUILayout.Button("save as Ascension spot", Array.Empty())) { Save("ascension", position, y); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("note", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); _spotNote = GUILayout.TextField(_spotNote ?? "", 60, Array.Empty()); if (GUILayout.Button("save as waypoint", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) })) { Save(string.IsNullOrEmpty(_spotNote) ? "note" : Slug(_spotNote), position, y); _spotNote = ""; } GUILayout.EndHorizontal(); GUILayout.Label("A waypoint is just a note to yourself; only 'luck' and 'ascension' place a stand.", Array.Empty()); GUILayout.Space(6f); Header("spots in use"); List all = Spots.All; List list = new List(); foreach (Spot item in DefaultSpots.All) { if (Spots.Saved(item.Kind, item.Island) == null && Cfg.UseBuiltInStandSpots) { list.Add(item); } } if (all.Count == 0 && list.Count == 0) { GUILayout.Label("none - the stands are placed automatically", Array.Empty()); } else { for (int i = 0; i < all.Count; i++) { Spot spot = all[i]; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(Describe(spot, currentIsland, position, "yours"), Array.Empty()); if (GUILayout.Button("forget", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { Spots.Forget(spot.Kind, spot.Island); Shop.Replace(); GUILayout.EndHorizontal(); break; } GUILayout.EndHorizontal(); } for (int j = 0; j < list.Count; j++) { GUILayout.Label(Describe(list[j], currentIsland, position, "ships with the mod"), Array.Empty()); } } GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("reload file", Array.Empty())) { Spots.Reload(); } if (GUILayout.Button("re-place stands now", Array.Empty())) { Shop.Replace(); } GUILayout.EndHorizontal(); GUILayout.Label(Spots.Path, Array.Empty()); GUILayout.Space(6f); Header("stands on this island"); DrawStandLocator(); } private static string Describe(Spot sp, int island, Vector3 pos, string source) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) string text = ((sp.Island == island) ? (Vector3.Distance(pos, sp.Position).ToString("0") + "m away") : ("island " + sp.Island)); return sp.Kind + " - " + text + " " + ((Vector3)(ref sp.Position)).ToString("0.0") + " [" + source + "]"; } private static void Save(string kind, Vector3 pos, float yaw) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (Spots.Record(kind, pos, yaw, "")) { Shop.Replace(); } } private static string Slug(string s) { StringBuilder stringBuilder = new StringBuilder(); string text = s.Trim(); foreach (char c in text) { stringBuilder.Append(char.IsLetterOrDigit(c) ? char.ToLowerInvariant(c) : '-'); } string text2 = stringBuilder.ToString().Trim('-'); return (text2.Length == 0) ? "note" : text2; } private void DrawHeldSummary() { Item held = Held; if ((Object)(object)held == (Object)null) { GUILayout.Label("nothing in hand", Array.Empty()); return; } try { Row("name", held.GetName()); Row("type", (held is Creature) ? "creature" : "item"); Row("weight multiplier", held._syncedRandomWeight.Value.ToString("0.000") + "x"); int num = Variants.TierOf(held); Row("variant", (num == 0) ? "ordinary" : (Variants.Tiers[num - 1].Name + " (tier " + num + ")")); Row("base worth", "$" + held.DefaultWorth.ToString("N0")); Row("total worth", "$" + held.TotalWorth.ToString("N0")); } catch (Exception ex) { GUILayout.Label("could not read item: " + ex.Message, Array.Empty()); } } private void DrawStandLocator() { //IL_006c: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) try { LuckPurchasable[] array = Object.FindObjectsByType((FindObjectsInactive)1); if (array == null || array.Length == 0) { GUILayout.Label("none placed here yet", Array.Empty()); if (!Ascension.Unlocked) { GUILayout.Label("(Ascension needs the game finished first)", Array.Empty()); } return; } Player me = Me; Transform val = BodyOf(me); Vector3 val2 = (((Object)(object)val != (Object)null) ? val.position : Vector3.zero); foreach (LuckPurchasable luckPurchasable in array) { if (!((Object)(object)luckPurchasable == (Object)null)) { Vector3 position = ((Component)luckPurchasable).transform.position; string label = ((luckPurchasable is AscensionPurchasable) ? "Ascension" : "Lucky Charm"); string value = (((Object)(object)val == (Object)null) ? ((Vector3)(ref position)).ToString("0.0") : (Vector3.Distance(val2, position).ToString("0") + "m away, " + Compass(position - val2) + " at " + ((Vector3)(ref position)).ToString("0.0"))); Row(label, value); } } if (!GUILayout.Button("log stand positions", Array.Empty())) { return; } for (int j = 0; j < array.Length; j++) { if ((Object)(object)array[j] != (Object)null) { string obj = ((array[j] is AscensionPurchasable) ? "Ascension" : "Lucky Charm"); Vector3 position2 = ((Component)array[j]).transform.position; Log.Info(obj + " stand at " + ((Vector3)(ref position2)).ToString("0.0")); } } } catch (Exception ex) { GUILayout.Label("locator failed: " + ex.Message, Array.Empty()); } } private static string Compass(Vector3 delta) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) delta.y = 0f; if (((Vector3)(ref delta)).sqrMagnitude < 0.01f) { return "right here"; } float num = Mathf.Atan2(delta.x, delta.z) * 57.29578f; if (num < 0f) { num += 360f; } string[] array = new string[8] { "north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west" }; return array[Mathf.RoundToInt(num / 45f) % 8]; } private void DrawOddsTable() { try { float[] array = Rolls.TierChances(Luck.Level); float[] array2 = Rolls.TierChances(Luck.EffectiveLevel); float num = 1f; float num2 = 1f; for (int i = 0; i < array.Length; i++) { num -= array[i]; num2 -= array2[i]; } GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("tier", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label("bought", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label("effective", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label("ascension", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); DrawOddsRow("ordinary fish", num, num2); for (int j = 0; j < array.Length; j++) { DrawOddsRow(Variants.Tiers[j].Name, array[j], array2[j]); } } catch (Exception ex) { GUILayout.Label("odds unavailable: " + ex.Message, Array.Empty()); } } private static void DrawOddsRow(string name, float bought, float effective) { float num = effective - bought; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label((bought * 100f).ToString("0.000") + " %", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label((effective * 100f).ToString("0.000") + " %", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label(((num >= 0f) ? "+" : "") + (num * 100f).ToString("0.000") + " pts", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); } private void DrawMoneyAndLuck() { Header("money"); try { GUILayout.Label("current: $" + MoneyManager.Money.ToString("N0"), Array.Empty()); } catch { } if (!IsHost) { GUILayout.Label("(host only - you are a client)", Array.Empty()); } GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("+1k", Array.Empty())) { GiveMoney(1000); } if (GUILayout.Button("+10k", Array.Empty())) { GiveMoney(10000); } if (GUILayout.Button("+100k", Array.Empty())) { GiveMoney(100000); } if (GUILayout.Button("+1M", Array.Empty())) { GiveMoney(1000000); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); _moneyField = GUILayout.TextField(_moneyField, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); if (GUILayout.Button("add", Array.Empty())) { GiveMoney(ParseInt(_moneyField, 0)); } if (GUILayout.Button("take", Array.Empty())) { GiveMoney(-ParseInt(_moneyField, 0)); } GUILayout.EndHorizontal(); Header("luck"); GUILayout.Label("level " + Luck.Level + " / " + Cfg.LuckMaxLevel + " (rare fish " + Luck.ChanceMultiplier().ToString("0.00") + "x)", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("-1", Array.Empty())) { SetLuck(Luck.Level - 1); } if (GUILayout.Button("+1", Array.Empty())) { SetLuck(Luck.Level + 1); } if (GUILayout.Button("+5", Array.Empty())) { SetLuck(Luck.Level + 5); } if (GUILayout.Button("max", Array.Empty())) { SetLuck(Cfg.LuckMaxLevel); } if (GUILayout.Button("reset", Array.Empty())) { SetLuck(0); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); _luckField = GUILayout.TextField(_luckField, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); if (GUILayout.Button("set level", Array.Empty())) { SetLuck(ParseInt(_luckField, 0)); } GUILayout.EndHorizontal(); Header("ascension (new game+)"); GUILayout.Label("tier " + Ascension.Level + " health x" + Ascension.HpMultiplier().ToString("0.##") + " value x" + Ascension.ValueMultiplier().ToString("0.##") + " +" + Ascension.LuckBonus() + " luck", Array.Empty()); if (!Ascension.Unlocked) { GUILayout.Label("(locked until the game is finished - the stand will not appear)", Array.Empty()); } GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("-1", Array.Empty())) { SetAscension(Ascension.Level - 1); } if (GUILayout.Button("+1", Array.Empty())) { SetAscension(Ascension.Level + 1); } if (GUILayout.Button("reset", Array.Empty())) { SetAscension(0); } GUILayout.EndHorizontal(); Header("vitals"); if (GUILayout.Button("heal and feed to full", Array.Empty())) { HealUp(); } Header("hooks"); GUILayout.Label(Cfg.EnableExtraHooks ? ("up to " + ExtraHooks.HookCount() + " fish on the line, hung " + Cfg.HookSpread.ToString("0.00") + "m apart") : "extra hooks are switched off in the config", Array.Empty()); GUILayout.Label("leave a fish on the line and wait out another catch timer to see it", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("-1 hook", Array.Empty())) { SetHooks(Cfg.HookCount - 1); } if (GUILayout.Button("+1 hook", Array.Empty())) { SetHooks(Cfg.HookCount + 1); } if (GUILayout.Button("max", Array.Empty())) { SetHooks(Cfg.MaxHookCount); } if (GUILayout.Button("reset to 1", Array.Empty())) { SetHooks(1); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("spread -", Array.Empty())) { SetSpread(Cfg.HookSpread - 0.1f); } if (GUILayout.Button("spread +", Array.Empty())) { SetSpread(Cfg.HookSpread + 0.1f); } if (GUILayout.Button("stack them", Array.Empty())) { SetSpread(0f); } GUILayout.EndHorizontal(); try { Bait val = LocalBait(); GUILayout.Label(((Object)(object)val == (Object)null) ? "no rod in hand" : ("on the line right now: " + ExtraHooks.FishOn(val)), Array.Empty()); } catch { } } private void SetHooks(int to) { Cfg.HookCount = Mathf.Clamp(to, 1, Cfg.MaxHookCount); if (Cfg.HookCount > 1) { Cfg.EnableExtraHooks = true; } Say("hooks: up to " + ExtraHooks.HookCount() + " fish on the line (from the next catch)"); } private void SetSpread(float to) { Cfg.HookSpread = Mathf.Clamp(to, 0f, 2f); Say("hook spread: " + Cfg.HookSpread.ToString("0.00") + "m (from the next catch)"); } private static Bait LocalBait() { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.Holding == (Object)null) { return null; } Item heldItem = localPlayer.Holding.HeldItem; if ((Object)(object)heldItem == (Object)null) { return null; } FishingRod fishingRod = heldItem.FishingRod; return ((Object)(object)fishingRod != (Object)null) ? fishingRod.Bait : null; } private void DrawFish() { GUILayout.Label("Set the weight of the creature in your hands to test", Array.Empty()); GUILayout.Label("variant names, values and thresholds instantly.", Array.Empty()); Header("held creature"); Item held = Held; if (!(held is Creature)) { GUILayout.Label("hold a fish or creature to force a variant.", Array.Empty()); Header("diagnostics"); if (GUILayout.Button("run 10,000 test rolls at this luck", Array.Empty())) { _selfTest = Rolls.SelfTest(10000); } if (!string.IsNullOrEmpty(_selfTest)) { GUILayout.Label(_selfTest, Array.Empty()); } return; } DrawHeldSummary(); if (!IsHost) { GUILayout.Label("(host only - the server owns the weight)", Array.Empty()); return; } Header("force a variant"); for (int i = 0; i < Variants.Tiers.Length; i++) { Variant variant = Variants.Tiers[i]; float heldWeight = (variant.MinWeight + variant.MaxWeight) * 0.5f; if (GUILayout.Button(variant.Name + " (" + variant.MinWeight.ToString("0.00") + " - " + variant.MaxWeight.ToString("0.00") + "x, value x" + variant.WorthMulti.ToString("0.00") + ")", Array.Empty())) { SetHeldWeight(heldWeight); } } if (GUILayout.Button("ordinary (1.00x)", Array.Empty())) { SetHeldWeight(1f); } Header("diagnostics"); if (GUILayout.Button("run 10,000 test rolls at this luck", Array.Empty())) { _selfTest = Rolls.SelfTest(10000); } if (!string.IsNullOrEmpty(_selfTest)) { GUILayout.Label(_selfTest, Array.Empty()); } Header("exact weight multiplier"); GUILayout.BeginHorizontal(Array.Empty()); _weightField = GUILayout.TextField(_weightField, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); if (GUILayout.Button("apply", Array.Empty())) { SetHeldWeight(ParseFloat(_weightField, 1f)); } GUILayout.EndHorizontal(); } private void DrawWeapons() { Item held = Held; Weapon val = (((Object)(object)held != (Object)null) ? held.Weapon : null); Melee val2 = (((Object)(object)held != (Object)null) ? held.Melee : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) { GUILayout.Label("hold a gun or a melee weapon to use this tab", Array.Empty()); return; } if (!IsHost) { GUILayout.Label("(host only - the server owns upgrade tiers)", Array.Empty()); } if ((Object)(object)val != (Object)null) { Header("gun"); try { Attachments attachments = val.Attachments; Row("bullet tier", attachments._syncedBulletIndex.Value.ToString()); Row("damage", attachments.Damage.ToString()); BulletUpgrade nextBulletUpgrade = attachments.GetNextBulletUpgrade(byte.MaxValue); Row("next tier", (nextBulletUpgrade == null) ? "at the top of the ladder" : ("damage " + nextBulletUpgrade.Damage + " for $" + nextBulletUpgrade.Cost.ToString("N0"))); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("+1 tier", Array.Empty())) { UpgradeGun(attachments, 1); } if (GUILayout.Button("+5", Array.Empty())) { UpgradeGun(attachments, 5); } if (GUILayout.Button("max out", Array.Empty())) { UpgradeGun(attachments, 999); } GUILayout.EndHorizontal(); GUILayout.Label("next tiers on this gun:", Array.Empty()); GUILayout.Label(Upgrades.LadderPreview(attachments, "_bulletUpgrades", attachments._syncedBulletIndex.Value, 8), Array.Empty()); } catch (Exception ex) { GUILayout.Label("gun unavailable: " + ex.Message, Array.Empty()); } } if (!((Object)(object)val2 != (Object)null)) { return; } Header("melee"); try { Row("sharpness tier", val2.SharpnessIndex.ToString()); SharpnessUpgrade curSharpness = val2.GetCurSharpness(); if (curSharpness != null) { Row("damage", curSharpness.Damage.ToString()); } SharpnessUpgrade nextSharpnessUpgrade = val2.GetNextSharpnessUpgrade(byte.MaxValue); Row("next tier", (nextSharpnessUpgrade == null) ? "at the top of the ladder" : ("damage " + nextSharpnessUpgrade.Damage + " for $" + nextSharpnessUpgrade.Cost.ToString("N0"))); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("+1 tier", Array.Empty())) { UpgradeMelee(val2, 1); } if (GUILayout.Button("+5", Array.Empty())) { UpgradeMelee(val2, 5); } if (GUILayout.Button("max out", Array.Empty())) { UpgradeMelee(val2, 999); } GUILayout.EndHorizontal(); GUILayout.Label("next tiers on this weapon:", Array.Empty()); GUILayout.Label(Upgrades.LadderPreview(val2, "_sharpnessUpgrades", val2.SharpnessIndex, 8), Array.Empty()); } catch (Exception ex2) { GUILayout.Label("melee unavailable: " + ex2.Message, Array.Empty()); } } private static int ParseInt(string s, int fallback) { int result; return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? result : fallback; } private static float ParseFloat(string s, float fallback) { float result; return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out result) ? result : fallback; } private void GiveMoney(int amount) { if (amount == 0 || !RequireHost()) { return; } try { if (amount > 0) { MoneyManager.AddMoney(amount, Me); } else { MoneyManager.RemoveMoney(-amount, Me); } Say(((amount > 0) ? "added $" : "removed $") + Mathf.Abs(amount).ToString("N0")); } catch (Exception e) { Log.Ex("DebugMenu.GiveMoney", e); } } private void SetLuck(int level) { if (!RequireHost()) { return; } try { Luck.Level = level; Luck.SaveForCurrentSave(); Net.BroadcastState(); Say("luck set to " + Luck.Level); } catch (Exception e) { Log.Ex("DebugMenu.SetLuck", e); } } private void SetAscension(int tier) { if (!RequireHost()) { return; } try { Ascension.Level = tier; Luck.SaveForCurrentSave(); Net.BroadcastState(); Say("ascension set to " + Ascension.Level + " (health x" + Ascension.HpMultiplier().ToString("0.##") + ")"); } catch (Exception e) { Log.Ex("DebugMenu.SetAscension", e); } } private void HealUp() { if (!RequireHost()) { return; } try { PlayerVitals val = (((Object)(object)Me != (Object)null) ? Me.Vitals : null); if (!((Object)(object)val == (Object)null)) { val._syncedHealth.Value = 100; val._syncedFullness.Value = 100; val._syncedPoison.Value = 0; val._syncedFire.Value = 0; Say("healed and fed"); } } catch (Exception e) { Log.Ex("DebugMenu.HealUp", e); } } private void SetHeldWeight(float weight) { if (!RequireHost()) { return; } try { Item held = Held; if (!((Object)(object)held == (Object)null)) { held._syncedRandomWeight.Value = Mathf.Clamp(weight, 0.05f, 100f); Say("weight set to " + weight.ToString("0.000") + "x -> " + held.GetName() + ", $" + held.TotalWorth.ToString("N0")); } } catch (Exception e) { Log.Ex("DebugMenu.SetHeldWeight", e); } } private void UpgradeGun(Attachments a, int steps) { if (!RequireHost()) { return; } try { int num = 0; for (int i = 0; i < steps; i++) { if (a.GetNextBulletUpgrade(byte.MaxValue) == null) { break; } a.UpgradeBullets(); num++; } Say((num == 0) ? "already at the top tier" : ("gun up " + num + " tier(s), damage now " + a.Damage)); } catch (Exception e) { Log.Ex("DebugMenu.UpgradeGun", e); } } private void UpgradeMelee(Melee m, int steps) { if (!RequireHost()) { return; } try { int num = 0; for (int i = 0; i < steps; i++) { if (m.GetNextSharpnessUpgrade(byte.MaxValue) == null) { break; } m.UpgradeSharpness(); num++; } SharpnessUpgrade curSharpness = m.GetCurSharpness(); Say((num == 0) ? "already at the top tier" : ("melee up " + num + " tier(s), damage now " + ((curSharpness != null) ? curSharpness.Damage.ToString() : "?"))); } catch (Exception e) { Log.Ex("DebugMenu.UpgradeMelee", e); } } } public static class DefaultSpots { private static readonly Spot[] _table = new Spot[6] { new Spot { Kind = "luck", Island = 0, Position = new Vector3(-202.945f, 2.077f, 596.954f), Yaw = 0f, Note = "built-in" }, new Spot { Kind = "ascension", Island = 0, Position = new Vector3(-204.289f, 4.327f, 601.248f), Yaw = 0f, Note = "built-in" }, new Spot { Kind = "luck", Island = 1, Position = new Vector3(497.957f, 0.854f, -101.083f), Yaw = 0f, Note = "built-in" }, new Spot { Kind = "luck", Island = 2, Position = new Vector3(303.01f, 0.769f, -569.407f), Yaw = 0f, Note = "built-in" }, new Spot { Kind = "luck", Island = 3, Position = new Vector3(-127.781f, 1.901f, -762.858f), Yaw = 0f, Note = "built-in" }, new Spot { Kind = "luck", Island = 4, Position = new Vector3(-673.582f, 3.93f, -594.31f), Yaw = 0f, Note = "built-in" } }; public static IEnumerable All => _table; public static int Count => _table.Length; public static Spot For(string kind, int island) { Cfg.EnsureLoaded(); if (!Cfg.UseBuiltInStandSpots) { return null; } for (int i = 0; i < _table.Length; i++) { if (_table[i].Island == island && string.Equals(_table[i].Kind, kind, StringComparison.OrdinalIgnoreCase)) { return _table[i]; } } return null; } } public sealed class BaitHooks : MonoBehaviour { public readonly List Extra = new List(); public int LocalAttachCount; public static BaitHooks Of(Bait bait) { if ((Object)(object)bait == (Object)null) { return null; } BaitHooks component = ((Component)bait).GetComponent(); return ((Object)(object)component != (Object)null) ? component : ((Component)bait).gameObject.AddComponent(); } public void Prune() { for (int num = Extra.Count - 1; num >= 0; num--) { if ((Object)(object)Extra[num] == (Object)null) { Extra.RemoveAt(num); } } } } public static class ExtraHooks { private static FieldInfo _serverItemBacking; private static bool _warned; private static int _declinesLogged; private static FieldInfo _jointField; public static int HookCount() { Cfg.EnsureLoaded(); if (!Cfg.EnableExtraHooks) { return 1; } return Mathf.Clamp(Cfg.HookCount, 1, Cfg.MaxHookCount); } private static bool CanReachGate() { if (_serverItemBacking != null) { return true; } _serverItemBacking = typeof(Bait).GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (_serverItemBacking == null && !_warned) { _warned = true; Log.Warn("extra hooks are off on this build of the game: Bait.ServerItemOnBait cannot be reached, so the line keeps its one fish."); } return _serverItemBacking != null; } private static Item GetGate(Bait bait) { object? value = _serverItemBacking.GetValue(bait); return (Item)((value is Item) ? value : null); } private static void SetGate(Bait bait, Item value) { _serverItemBacking.SetValue(bait, value); } public static int FishOn(Bait bait) { if ((Object)(object)bait == (Object)null) { return 0; } BaitHooks baitHooks = BaitHooks.Of(bait); if ((Object)(object)baitHooks == (Object)null) { return 0; } baitHooks.Prune(); int num = baitHooks.Extra.Count; try { if ((Object)(object)bait.ServerItemOnBait != (Object)null) { num++; } } catch { } return num; } private static void Decline(string why) { if (_declinesLogged < 8) { _declinesLogged++; Log.Info("extra hook: not trying for another fish - " + why); } } public static Item BeforeFind(Bait bait) { try { if ((Object)(object)bait == (Object)null) { return null; } int num = HookCount(); if (num <= 1) { return null; } if (!CanReachGate()) { Decline("the game's catch gate cannot be reached"); return null; } Item gate = GetGate(bait); if ((Object)(object)gate == (Object)null) { return null; } BaitHooks baitHooks = BaitHooks.Of(bait); baitHooks.Prune(); if (1 + baitHooks.Extra.Count >= num) { Decline("all " + num + " hook(s) already have a fish"); return null; } SetGate(bait, null); Decline("stepping aside to try for fish " + (2 + baitHooks.Extra.Count) + " (the game still has to want to bite)"); return gate; } catch (Exception e) { Log.Ex("ExtraHooks.BeforeFind", e); return null; } } public static void AfterFind(Bait bait, Item displaced) { try { if ((Object)(object)bait == (Object)null || (Object)(object)displaced == (Object)null || !CanReachGate()) { return; } Item gate = GetGate(bait); if ((Object)(object)gate == (Object)null) { SetGate(bait, displaced); } else if (!((Object)(object)gate == (Object)(object)displaced)) { BaitHooks baitHooks = BaitHooks.Of(bait); baitHooks.Prune(); if (!baitHooks.Extra.Contains(displaced)) { baitHooks.Extra.Add(displaced); } Log.Info("extra hook: " + (1 + baitHooks.Extra.Count) + " fish on the line (up to " + HookCount() + ")"); } } catch (Exception e) { Log.Ex("ExtraHooks.AfterFind", e); } } public static void ReleaseExtras(FishingRod rod) { try { if ((Object)(object)rod == (Object)null) { return; } Bait bait = rod.Bait; if ((Object)(object)bait == (Object)null) { return; } BaitHooks component = ((Component)bait).GetComponent(); if ((Object)(object)component == (Object)null || component.Extra.Count == 0) { return; } int num = 0; for (int i = 0; i < component.Extra.Count; i++) { Item val = component.Extra[i]; if (!((Object)(object)val == (Object)null)) { val.SetAttachedRod((FishingRod)null); num++; } } component.Extra.Clear(); component.LocalAttachCount = 0; if (num > 0) { Log.Info("extra hook: let go of " + num + " extra fish"); } } catch (Exception e) { Log.Ex("ExtraHooks.ReleaseExtras", e); } } public static void SpreadHook(Item item, FishingRod rod) { //IL_0135: 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_013d: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)item == (Object)null || (Object)(object)rod == (Object)null) { return; } Cfg.EnsureLoaded(); if (!Cfg.EnableExtraHooks || HookCount() <= 1 || Cfg.HookSpread <= 0f) { return; } Bait bait = rod.Bait; if ((Object)(object)bait == (Object)null) { return; } BaitHooks baitHooks = BaitHooks.Of(bait); int num = baitHooks.LocalAttachCount++; if (num > 0) { if (_jointField == null) { _jointField = typeof(Item).GetField("_jointToBait", BindingFlags.Instance | BindingFlags.NonPublic); } FixedJoint val = (FixedJoint)((_jointField != null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)((Component)item).GetComponent())); if (!((Object)(object)val == (Object)null)) { float num2 = Cfg.HookSpread * (float)num; float num3 = Cfg.HookSpread * 0.7f * ((num % 2 == 0) ? 1f : (-1f)); Vector3 connectedAnchor = ((Joint)val).connectedAnchor; ((Joint)val).connectedAnchor = connectedAnchor + new Vector3(num3, 0f - num2, 0f); string[] obj = new string[7] { "extra hook: hung fish ", (num + 1).ToString(), " at ", null, null, null, null }; Vector3 connectedAnchor2 = ((Joint)val).connectedAnchor; obj[3] = ((Vector3)(ref connectedAnchor2)).ToString("0.000"); obj[4] = " (was "; obj[5] = ((Vector3)(ref connectedAnchor)).ToString("0.000"); obj[6] = ")"; Log.Info(string.Concat(obj)); } } } catch (Exception e) { Log.Ex("ExtraHooks.SpreadHook", e); } } public static void Forget(Bait bait) { try { if (!((Object)(object)bait == (Object)null)) { BaitHooks component = ((Component)bait).GetComponent(); if ((Object)(object)component != (Object)null) { component.Extra.Clear(); component.LocalAttachCount = 0; } } } catch (Exception e) { Log.Ex("ExtraHooks.Forget", e); } } } public sealed class FishHealthBar : MonoBehaviour { private Creature _creature; private Renderer[] _renderers; private Canvas _canvas; private RectTransform _root; private RectTransform _fill; private Image _fillImage; private float _height = 1.5f; private float _shown = -1f; private float _nextMeasure; private Camera _cam; private float _width = 1.6f; private float _thickness = 0.16f; private float _lift = 0.15f; private float _opacity = 0.9f; private bool _onlyWhenDamaged; public static void Attach(Creature c) { try { Cfg.EnsureLoaded(); if (Cfg.EnableFishHealthBars && !((Object)(object)c == (Object)null) && !(c is Bird) && !(((object)c).GetType().Name == "Albatross") && !((Object)(object)((Component)c).GetComponent() != (Object)null)) { ((Component)c).gameObject.AddComponent()._creature = c; } } catch (Exception e) { Log.Ex("FishHealthBar.Attach", e); } } private void Awake() { try { _renderers = ((Component)this).GetComponentsInChildren(true); _width = Cfg.FishHealthBarWidth; _thickness = Cfg.FishHealthBarThickness; _lift = Cfg.FishHealthBarLift; _opacity = Cfg.FishHealthBarOpacity; _onlyWhenDamaged = Cfg.FishHealthBarOnlyWhenDamaged; Build(); } catch (Exception e) { Log.Ex("FishHealthBar.Awake", e); Shutdown(); } } private void Build() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HTFX Health Bar", new Type[2] { typeof(RectTransform), typeof(Canvas) }); _canvas = val.GetComponent(); _canvas.renderMode = (RenderMode)2; _canvas.sortingOrder = 50; _root = (RectTransform)val.transform; _root.anchorMin = new Vector2(0.5f, 0.5f); _root.anchorMax = new Vector2(0.5f, 0.5f); _root.pivot = new Vector2(0.5f, 0.5f); _root.sizeDelta = new Vector2(_width, _thickness); MakeImage((Transform)(object)_root, "Track", new Color(0.03f, 0.05f, 0.06f, 0.85f * _opacity)); _fillImage = MakeImage((Transform)(object)_root, "Fill", new Color(0.22f, 0.86f, 0.42f, 0.95f)); _fill = ((Graphic)_fillImage).rectTransform; _fill.anchorMin = new Vector2(0f, 0f); _fill.anchorMax = new Vector2(0f, 1f); _fill.pivot = new Vector2(0f, 0.5f); _fill.sizeDelta = Vector2.zero; _fill.anchoredPosition = Vector2.zero; _fill.offsetMin = Vector2.zero; _fill.offsetMax = Vector2.zero; } private Image MakeImage(Transform parent, string name, Color col) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; Image component2 = val.GetComponent(); ((Graphic)component2).color = col; return component2; } private void LateUpdate() { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_creature == (Object)null || (Object)(object)_canvas == (Object)null) { Shutdown(); return; } int value = _creature._hp.Value; int num = _creature.MaxHp; if (num <= 0) { num = 1; } if (value <= 0 || (_onlyWhenDamaged && value >= num)) { ((Behaviour)_canvas).enabled = false; return; } ((Behaviour)_canvas).enabled = true; if (Time.unscaledTime >= _nextMeasure) { _nextMeasure = Time.unscaledTime + 0.5f; RefreshHeight(); } ((Transform)_root).position = ((Component)this).transform.position + Vector3.up * _height; if ((Object)(object)_cam == (Object)null) { _cam = Camera.main; } if ((Object)(object)_cam != (Object)null) { ((Transform)_root).rotation = ((Component)_cam).transform.rotation; } float num2 = Mathf.Clamp01((float)value / (float)num); if (Mathf.Abs(num2 - _shown) > 0.001f) { _shown = num2; _fill.anchorMax = new Vector2(num2, 1f); ((Graphic)_fillImage).color = ((num2 > 0.55f) ? new Color(0.22f, 0.86f, 0.42f, 0.95f * _opacity) : ((num2 > 0.25f) ? new Color(1f, 0.7f, 0.16f, 0.96f * _opacity) : new Color(1f, 0.2f, 0.18f, 0.96f * _opacity))); } } catch (Exception e) { Log.Ex("FishHealthBar.LateUpdate", e); Shutdown(); } } private void RefreshHeight() { //IL_0034: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0095: Unknown result type (might be due to invalid IL or missing references) _height = 1.5f; if (_renderers != null && _renderers.Length != 0) { Bounds bounds = _renderers[0].bounds; Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(((Bounds)(ref bounds)).center, Vector3.zero); for (int i = 0; i < _renderers.Length; i++) { ((Bounds)(ref val)).Encapsulate(_renderers[i].bounds); } if (((Bounds)(ref val)).size.y > 0.01f) { _height = ((Bounds)(ref val)).size.y + _lift; } } } private void Shutdown() { try { Object.Destroy((Object)(object)this); } catch { } } private void OnDestroy() { try { if ((Object)(object)_canvas != (Object)null) { Object.Destroy((Object)(object)((Component)_canvas).gameObject); } } catch { } _canvas = null; } private void OnDisable() { try { if ((Object)(object)_canvas != (Object)null) { ((Behaviour)_canvas).enabled = false; } } catch { } } private void OnEnable() { try { if ((Object)(object)_canvas != (Object)null) { ((Behaviour)_canvas).enabled = true; } } catch { } } } public sealed class FishSize : MonoBehaviour { private Item _item; private Vector3 _baseScale; private bool _haveBase; private float _lastWeight = float.NaN; private static int _logged; public static void Attach(Item item) { try { Cfg.EnsureLoaded(); if (!Cfg.EnableFishScaling || (Object)(object)item == (Object)null || (Object)(object)((Component)item).GetComponent() != (Object)null) { return; } Creature val = null; try { val = item.Creature; } catch { } if ((Object)(object)val == (Object)null) { return; } if (!Cfg.ScaleBossFish) { try { if (Variants.IsBoss(val)) { return; } } catch { } } ((Component)item).gameObject.AddComponent()._item = item; } catch (Exception e) { Log.Ex("FishSize.Attach", e); } } public static void Refresh(Item item) { try { if (!((Object)(object)item == (Object)null)) { FishSize component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = true; component._lastWeight = float.NaN; } else { Attach(item); } } } catch (Exception e) { Log.Ex("FishSize.Refresh", e); } } public static float ScaleFor(float weight) { Cfg.EnsureLoaded(); if (!Cfg.EnableFishScaling) { return 1f; } if (weight <= 0f || float.IsNaN(weight) || float.IsInfinity(weight)) { return 1f; } double num = Math.Pow(weight, Cfg.FishScaleExponent); if (double.IsNaN(num) || double.IsInfinity(num)) { return 1f; } return Mathf.Clamp((float)num, Cfg.FishScaleMin, Cfg.FishScaleMax); } private void LateUpdate() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_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_00a7: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_item == (Object)null) { ((Behaviour)this).enabled = false; return; } float value; try { value = _item._syncedRandomWeight.Value; } catch { return; } if (!_haveBase) { _baseScale = ((Component)this).transform.localScale; _haveBase = true; } float num = ScaleFor(value); Vector3 val = _baseScale * num; Vector3 val2 = ((Component)this).transform.localScale - val; if (((Vector3)(ref val2)).sqrMagnitude > 1E-08f) { ((Component)this).transform.localScale = val; } if (value != _lastWeight && _logged < 20) { _logged++; Log.Info("fish size: " + ((Object)_item).name + " weighs " + value.ToString("0.00") + "x, drawn at " + num.ToString("0.00") + "x size"); } _lastWeight = value; } catch (Exception e) { Log.Ex("FishSize.LateUpdate", e); ((Behaviour)this).enabled = false; } } } public static class Hooks { private static bool _announced; private static bool IsServer() { try { return InstanceFinder.IsServerStarted; } catch { return true; } } public static void OnStartServer() { try { Cfg.EnsureLoaded(); Luck.LoadForCurrentSave(); CatchStats.LoadForCurrentSave(); CatchStats.LoadLifetime(); Backpack.LoadForCurrentSave(); Net.BroadcastState(); } catch (Exception e) { Log.Ex("Hooks.OnStartServer", e); } } public static void Bootstrap() { try { StandModel.LogStatus(); } catch (Exception e) { Log.Ex("Hooks.Bootstrap.models", e); } try { Cfg.EnsureLoaded(); DebugMenu.Bootstrap(); CatchToast.Bootstrap(); TrophiesMenu.Bootstrap(); BackpackPanel.Bootstrap(); ConfigPanel.Bootstrap(); } catch (Exception e2) { Log.Ex("Hooks.Bootstrap", e2); } } public static void OnServerLoaded() { try { Cfg.EnsureLoaded(); if (IsServer()) { Luck.LoadForCurrentSave(); CatchStats.LoadForCurrentSave(); CatchStats.LoadLifetime(); Backpack.LoadForCurrentSave(); Net.BroadcastState(); } if (!_announced) { _announced = true; Log.Info("How To Fish - Extended is active. Config: " + Cfg.Path); } } catch (Exception e) { Log.Ex("Hooks.OnServerLoaded", e); } } public static void BeforeLoadAllServers() { try { string path = Application.persistentDataPath + "/Saves"; if (!Directory.Exists(path)) { return; } string[] files = Directory.GetFiles(path, "*.htfx.txt"); if (files.Length == 0) { return; } Directory.CreateDirectory(Luck.ModFolder); string[] array = files; foreach (string text in array) { try { string text2 = Luck.ModFolder + "/" + Path.GetFileName(text); if (File.Exists(text2)) { File.Delete(text2); } File.Move(text, text2); Log.Warn("moved stray mod file out of the save folder: " + Path.GetFileName(text)); } catch (Exception e) { Log.Ex("BeforeLoadAllServers move", e); } } } catch (Exception e2) { Log.Ex("Hooks.BeforeLoadAllServers", e2); } } public static void OnSaveServer() { try { if (IsServer()) { Luck.SaveForCurrentSave(); CatchStats.SaveForCurrentSave(); CatchStats.SaveLifetime(); Backpack.SaveNow(); } } catch (Exception e) { Log.Ex("Hooks.OnSaveServer", e); } } } public static class Commands { public static bool Handle(string full) { try { if (string.IsNullOrEmpty(full)) { return false; } string text = full.Trim(); if (text.StartsWith("/", StringComparison.Ordinal)) { text = text.Substring(1); } string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return false; } string text2 = array[0].ToLowerInvariant(); if (text2 == "luck") { if (array.Length >= 2 && int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { Luck.Level = result; Luck.SaveForCurrentSave(); Net.BroadcastState(); } Log.Info("luck is level " + Luck.Level + " (" + Luck.ChanceMultiplier().ToString("0.00") + "x variant chance)"); return true; } if (text2 == "ascend" || text2 == "ascension") { if (array.Length >= 2 && int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { Ascension.Level = result2; Luck.SaveForCurrentSave(); Net.BroadcastState(); } Log.Info("ascension tier " + Ascension.Level + " (creature health x" + Ascension.HpMultiplier().ToString("0.##") + ", fish value x" + Ascension.ValueMultiplier().ToString("0.##") + ", +" + Ascension.LuckBonus() + " luck)"); return true; } if (text2 == "storage" || text2 == "backpack") { Cfg.EnsureLoaded(); Log.Info(Backpack.Summary()); return true; } if (text2 == "catches" || text2 == "stats") { Cfg.EnsureLoaded(); Log.Info(CatchStats.Summary()); return true; } if (text2 == "htfx") { Cfg.EnsureLoaded(); Log.Info("How To Fish - Extended | luck " + Luck.Level + " | extra gun tiers " + Cfg.ExtraGunTiers + " | extra melee tiers " + Cfg.ExtraMeleeTiers + " | variants " + (Cfg.EnableVariants ? "on" : "off") + " | ascension tier " + Ascension.Level + " | config " + Cfg.Path); return true; } if (text2 == "htfxreload") { Cfg.Write(); Log.Info("config rewritten with current values"); return true; } } catch (Exception e) { Log.Ex("Commands.Handle", e); } return false; } } public static class KillScoreUI { private static FieldInfo _speed; private static FieldInfo _target; private static float _vanillaSpeed = -1f; private static bool _warned; private static bool Resolve() { if (_speed != null && _target != null) { return true; } try { _speed = typeof(PlayerKillScore).GetField("_animateScoreSpeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _target = typeof(PlayerKillScore).GetField("_targetScore", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { } if ((_speed == null || _target == null) && !_warned) { _warned = true; Log.Warn("PlayerKillScore fields not found - the score popup keeps its vanilla timing."); } return _speed != null && _target != null; } public static void Rescale(PlayerKillScore ui) { try { Cfg.EnsureLoaded(); if ((Object)(object)ui == (Object)null || !Cfg.CapKillScoreAnimation || !Resolve()) { return; } float num = (float)_speed.GetValue(ui); float num2 = (float)_target.GetValue(ui); if (_vanillaSpeed <= 0f) { if (num <= 0f) { return; } _vanillaSpeed = num; } float num3 = Mathf.Max(10f, Cfg.KillScoreAnimationReference); float num4 = 1f; if (num2 > num3) { num4 = Mathf.Log(num2) / Mathf.Log(num3); } _speed.SetValue(ui, _vanillaSpeed * Mathf.Clamp(num4, 1f, 50f)); } catch (Exception e) { Log.Ex("KillScoreUI.Rescale", e); } } } public class LadderMemory : MonoBehaviour { public int VanillaBulletTiers; public int VanillaSharpnessTiers; } public static class Luck { private static int _level; private static string _saveName = ""; public static int Level { get { return _level; } set { Cfg.EnsureLoaded(); _level = Mathf.Clamp(value, 0, Cfg.LuckMaxLevel); } } public static int EffectiveLevel { get { Cfg.EnsureLoaded(); return Mathf.Clamp(_level + Ascension.LuckBonus(), 0, Cfg.LuckMaxLevel); } } public static string ModFolder => Application.persistentDataPath + "/HowToFishExpanded"; public static int CostForNextLevel() { Cfg.EnsureLoaded(); if (_level >= Cfg.LuckMaxLevel) { return -1; } double num = (double)Cfg.LuckBaseCost * Math.Pow(Cfg.LuckCostGrowth, _level); if (Cfg.LuckCostStepInterval > 0) { num *= Math.Pow(2.0, _level / Cfg.LuckCostStepInterval); } if (_level >= Cfg.LuckCostEarlyLevels) { num *= (double)Cfg.LuckCostLateMultiplier; } if (num > 2147483647.0) { return int.MaxValue; } return (int)num; } public static float ChanceMultiplier() { return ChanceMultiplierAt(EffectiveLevel); } public static float ChanceMultiplierAt(int level) { try { float num = Rolls.TotalVariantChance(0); if (num <= 0f) { return 1f; } return Rolls.TotalVariantChance(level) / num; } catch { return 1f; } } private static string SidecarPath(string saveName) { return ModFolder + "/" + saveName + ".luck.dat"; } private static string LegacySidecarPath(string saveName) { return ModFolder + "/" + saveName + ".htfx.txt"; } private static string CurrentSaveName() { try { ServerSaveObject curServerSave = SaveManager.CurServerSave; return (curServerSave != null && !string.IsNullOrEmpty(curServerSave.Name)) ? curServerSave.Name : ""; } catch { return ""; } } public static void LoadForCurrentSave() { try { Cfg.EnsureLoaded(); _saveName = CurrentSaveName(); _level = 0; Ascension.Level = 0; if (string.IsNullOrEmpty(_saveName)) { return; } string path = SidecarPath(_saveName); if (!File.Exists(path)) { string text = LegacySidecarPath(_saveName); if (!File.Exists(text)) { Log.Info("no luck data for save '" + _saveName + "', starting at 0"); return; } path = text; } string[] array = File.ReadAllLines(path); foreach (string text2 in array) { int num = text2.IndexOf('='); if (num <= 0) { continue; } string text3 = text2.Substring(0, num).Trim(); string s = text2.Substring(num + 1).Trim(); if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { if (text3.Equals("luck", StringComparison.OrdinalIgnoreCase)) { Level = result; } else if (text3.Equals("ascension", StringComparison.OrdinalIgnoreCase)) { Ascension.Level = result; } } } Log.Info("loaded luck " + _level + ", ascension " + Ascension.Level + " for save '" + _saveName + "'"); } catch (Exception e) { Log.Ex("Luck.LoadForCurrentSave", e); } } public static void SaveForCurrentSave() { try { string text = CurrentSaveName(); if (string.IsNullOrEmpty(text)) { text = _saveName; } if (!string.IsNullOrEmpty(text)) { Directory.CreateDirectory(ModFolder); File.WriteAllText(SidecarPath(text), "# How To Fish - Extended. Safe to delete; only stores mod progress.\r\nluck=" + _level + "\r\nascension=" + Ascension.Level + "\r\n"); } } catch (Exception e) { Log.Ex("Luck.SaveForCurrentSave", e); } } public static bool TryBuy(Player buyer) { try { Cfg.EnsureLoaded(); int num = CostForNextLevel(); if (num < 0) { Log.Info("luck purchase refused: already at the maximum level (" + Cfg.LuckMaxLevel + ")"); return false; } if (!MoneyManager.CanAfford(num)) { Log.Info("luck purchase refused: cannot afford $" + num); return false; } MoneyManager.RemoveMoney(num, buyer); Level = _level + 1; SaveForCurrentSave(); Net.BroadcastState(); Log.Info("luck purchased, now level " + _level); return true; } catch (Exception e) { Log.Ex("Luck.TryBuy", e); return false; } } } public static class MenuButton { [CompilerGenerated] private static class <>O { public static UnityAction <0>__OpenPanel; } private const string ButtonName = "HTFX_SettingsButton"; private static GameObject _button; private static FieldInfo _pagesField; private static FieldInfo _discordField; private static FieldInfo _instanceField; private static bool _looked; private static bool _warned; private static void Look() { if (_looked) { return; } _looked = true; try { _pagesField = typeof(CanvasManager).GetField("_allMainMenuButtons", BindingFlags.Instance | BindingFlags.NonPublic); _discordField = typeof(CanvasManager).GetField("_discordButton", BindingFlags.Instance | BindingFlags.NonPublic); _instanceField = typeof(CanvasManager).GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic); } catch (Exception e) { Log.Ex("MenuButton.Look", e); } } public static CanvasManager Current() { try { Look(); if (_instanceField != null) { object? value = _instanceField.GetValue(null); CanvasManager val = (CanvasManager)((value is CanvasManager) ? value : null); if ((Object)(object)val != (Object)null) { return val; } } } catch { } try { return Object.FindAnyObjectByType(); } catch { return null; } } public static void Ensure(CanvasManager cm, bool menuEnabled) { try { if ((Object)(object)cm == (Object)null || !menuEnabled) { return; } Cfg.EnsureLoaded(); Look(); if (_pagesField == null) { Warn("the main menu button could not be added: this build of the game has no main menu button list"); } else if (_pagesField.GetValue(cm) is List { Count: not 0 } list) { GameObject val = list[0]; if ((Object)(object)val == (Object)null || (Object)(object)_button != (Object)null || (Object)(object)FindExisting(val) != (Object)null) { return; } GameObject val2 = FindTemplate(cm, val); if ((Object)(object)val2 == (Object)null) { Warn("the main menu button could not be added: no existing menu button was found to copy the styling from"); return; } GameObject val3 = Object.Instantiate(val2, val.transform); ((Object)val3).name = "HTFX_SettingsButton"; val3.SetActive(true); Retext(val3, "How To Fish - Extended"); PlaceBeside(val3, val2); Button component = val3.GetComponent