using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.AvatarFramework; using Il2CppScheduleOne.AvatarFramework.Emotions; using Il2CppScheduleOne.Core.Items.Framework; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Dialogue; using Il2CppScheduleOne.Effects; using Il2CppScheduleOne.Equipping; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.PlayerScripts.Health; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.Trash; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Shop; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using S1HungerThirst; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Mod), "Schedule 1 Survival Mode", "0.6.0", "Schedule 1 Survival Mode", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: VerifyLoaderVersion("0.7.0", true)] [assembly: HarmonyDontPatchAll] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Schedule 1 Survival Mode")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.0.0")] [assembly: AssemblyInformationalVersion("0.6.0")] [assembly: AssemblyProduct("Schedule 1 Survival Mode")] [assembly: AssemblyTitle("Schedule 1 Survival Mode")] [assembly: AssemblyVersion("0.6.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 S1HungerThirst { public readonly struct Restore { public readonly float Hunger; public readonly float Thirst; public readonly float Energy; public Restore(float hunger, float thirst, float energy = 0f) { Hunger = hunger; Thirst = thirst; Energy = energy; } } public static class ConsumableMap { private static readonly string[] FoodWords = new string[42] { "banana", "donut", "doughnut", "apple", "orange", "grape", "berry", "fruit", "chip", "crisp", "chocolate", "candy", "cookie", "biscuit", "snack", "sandwich", "burger", "pizza", "taco", "noodle", "soup", "meal", "bread", "cake", "pie", "granola", "cereal", "pretzel", "jerky", "hotdog", "muffin", "pastr", "bean", "chili", "chile", "pepper", "corn", "rice", "egg", "cheese", "tomato", "potato" }; private static readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet _validatedMissing = new HashSet(StringComparer.OrdinalIgnoreCase); private static bool _registryScanned; private static readonly HashSet _runtimeIds = new HashSet(StringComparer.OrdinalIgnoreCase); private static bool _foodMadeDrinkable; private static readonly HashSet _wiredIds = new HashSet(StringComparer.OrdinalIgnoreCase); private static readonly Random _toastRng = new Random(); private static readonly string[] EatLines = new string[14] { "Not bad, actually.", "That {0} didn't last long.", "Demolished the {0}.", "Yeah, that'll do for now.", "Could eat more, honestly.", "Health food, probably.", "Beats skipping lunch.", "Down the hatch.", "Better than nothing.", "Ate the {0}. No regrets yet.", "Something in the tank now.", "Could've used salt, but fine.", "The {0} went down easy.", "Won't win awards. It went down." }; private static readonly string[] DrinkLines = new string[11] { "Knocked back the {0}.", "Better. Still thirsty though.", "Could go another, honestly.", "Hydration, technically.", "Cheers, no one.", "Down in one.", "That's the edge off.", "Wet, at least.", "The {0} barely touched the sides.", "Good enough for now.", "Throat's happier." }; private static readonly string[] EnergyLines = new string[7] { "Bit more awake now.", "{0} kicked in.", "That's the motor turning over.", "Eyes open a bit wider now.", "That'll buy an hour or two.", "Less zombie now.", "Right. Back online, sort of." }; private static readonly string[] TacoLines = new string[9] { "Taco. Don't ask what's in it.", "Not bad for a servo taco.", "Drips everywhere. Ah well.", "Half of it went down my shirt.", "Structural failure halfway through. Worth it.", "The shell gave up before I did.", "Servo tacos. Reliable, in their own way.", "That one had some heat to it.", "Napkin situation: dire." }; private static readonly string[] ManukeLines = new string[7] { "That was four hundred and twenty dollars.", "Tastes expensive. Mostly.", "Pretty convincing wagyu, honestly.", "Four twenty well spent. Probably.", "Tastes like money leaving.", "Can confirm: expensive.", "Genuinely can't fault the fake wagyu." }; private static readonly string[] DanChiliLines = new string[4] { "Dan wasn't kidding about the kick.", "Hardware-store chili. Better than it has any right to be.", "The cumin's doing something in there. Something good.", "Eyes watering a little. Worth it." }; private static readonly string[] DanLasagnaLines = new string[4] { "The comedian's cut. Dan can cook.", "Hardware-store lasagna, and it's genuinely good. Weird day.", "That corner piece was earned.", "Dan builds a solid lasagna. Structurally sound, even." }; private static readonly string[] KyleSpecialLines = new string[7] { "That's a lot of...sauce", "There's so much sauce.", "Couldn't tell you what's under the sauce.", "The sauce outweighed the taco.", "Still finding sauce.", "White sauce all the way down.", "Asked no questions. Kept eating." }; public static void ParseConfigMap() { _map.Clear(); _registryScanned = false; _foodMadeDrinkable = false; string[] array = (NeedsConfig.FoodMapRaw ?? "").Split(';', StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('=', 2); if (array2.Length == 2) { string[] array3 = array2[1].Split('/', 3); float hunger = NeedsConfig.ParseF(array3[0].Trim(), 0f); float thirst = ((array3.Length > 1) ? NeedsConfig.ParseF(array3[1].Trim(), 0f) : 0f); float energy = ((array3.Length > 2) ? NeedsConfig.ParseF(array3[2].Trim(), 0f) : 0f); _map[array2[0].Trim()] = new Restore(hunger, thirst, energy); } } if (!NeedsConfig.GasolineDrinkable) { _map.Remove("gasoline"); } MelonLogger.Msg($"[Food] Config map: {_map.Count} item(s)."); } public static void ScanRegistry() { //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Invalid comparison between Unknown and I4 //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Invalid comparison between Unknown and I4 if (_registryScanned) { return; } _registryScanned = true; try { foreach (string key in _map.Keys) { if (!Registry.ItemExists(key) && _validatedMissing.Add(key)) { MelonLogger.Warning("[Food] Configured item id '" + key + "' does not exist in this game build; entry ignored."); } } if (!NeedsConfig.AutoMapUnknownConsumables) { return; } Il2CppArrayBase val = (((Object)(object)Singleton.Instance != (Object)null) ? Singleton.Instance.GetAllItems() : null)?.ToArray(); if (val == null) { return; } int num = 0; for (int i = 0; i < val.Length; i++) { ItemDefinition val2 = val[i]; if ((Object)(object)val2 == (Object)null || string.IsNullOrEmpty(((BaseItemDefinition)val2).ID) || _map.ContainsKey(((BaseItemDefinition)val2).ID) || ((int)((BaseItemDefinition)val2).Category != 7 && (int)((BaseItemDefinition)val2).Category != 9) || !LooksLikeFood(((BaseItemDefinition)val2).ID, ((BaseItemDefinition)val2).Name)) { continue; } string text = "none"; try { if ((Object)(object)val2.Equippable != (Object)null) { text = ((MemberInfo)((Object)val2.Equippable).GetIl2CppType()).Name; } } catch { text = "?"; } if (text != "none" && text != "Equippable_Viewmodel" && text != "Equippable_Cuke") { VLog($"'{((BaseItemDefinition)val2).ID}' food-named but equip={text} — left alone"); } else { _map[((BaseItemDefinition)val2).ID] = new Restore(20f, 3f); num++; MelonLogger.Msg($"[Food] Auto-mapped food ingredient '{((BaseItemDefinition)val2).ID}' ({((BaseItemDefinition)val2).Name})."); } } if (num > 0) { MelonLogger.Msg($"[Food] Auto-mapped {num} additional edible(s) from the registry."); } if (!NeedsConfig.VerboseConsume) { return; } MelonLogger.Msg($"[Food] ===== FULL ITEM REGISTRY ({val.Length} defs) ====="); for (int j = 0; j < val.Length; j++) { ItemDefinition val3 = val[j]; if ((Object)(object)val3 == (Object)null || string.IsNullOrEmpty(((BaseItemDefinition)val3).ID)) { continue; } string value = "none"; try { if ((Object)(object)val3.Equippable != (Object)null) { value = ((MemberInfo)((Object)val3.Equippable).GetIl2CppType()).Name; } } catch { value = "?"; } bool flag = _map.ContainsKey(((BaseItemDefinition)val3).ID); MelonLogger.Msg($"[Food] {((BaseItemDefinition)val3).ID} | '{((BaseItemDefinition)val3).Name}' | cat={((BaseItemDefinition)val3).Category} | equip={value} | edible={(flag ? "YES" : "no")}"); } MelonLogger.Msg("[Food] ===== END REGISTRY DUMP ====="); } catch (Exception ex) { MelonLogger.Warning("[Food] Registry scan failed (will retry next session): " + ex.Message); _registryScanned = false; } } private static bool LooksLikeFood(string id, string name) { string text = (id + " " + name).ToLowerInvariant(); string[] foodWords = FoodWords; foreach (string value in foodWords) { if (text.Contains(value)) { return true; } } return false; } public static bool TryGet(string itemId, out Restore r) { return _map.TryGetValue(itemId ?? "", out r); } public static void AddRuntimeEntry(string id, Restore r) { if (!string.IsNullOrEmpty(id) && !_map.ContainsKey(id)) { _map[id] = r; _runtimeIds.Add(id); } } public static void OnSessionEnded() { _registryScanned = false; foreach (string runtimeId in _runtimeIds) { _map.Remove(runtimeId); } _runtimeIds.Clear(); } public static bool IsFood(Restore r) { return r.Hunger > r.Thirst; } public static bool WasWired(string id) { return _wiredIds.Contains(id ?? ""); } public static IEnumerable WiredIds() { return _wiredIds; } public static void MakeFoodDrinkable() { //IL_01a4: Unknown result type (might be due to invalid IL or missing references) if (_foodMadeDrinkable) { return; } try { ItemDefinition item = Registry.GetItem("cuke"); if ((Object)(object)item == (Object)null || (Object)(object)item.Equippable == (Object)null) { MelonLogger.Warning("[Eat] cuke definition/equippable not found — cannot wire food consumption yet."); return; } if ((Object)(object)((Il2CppObjectBase)item.Equippable).TryCast() == (Object)null) { MelonLogger.Warning("[Eat] cuke equippable is not Equippable_Cuke — wiring anyway."); } _foodMadeDrinkable = true; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (string key in _map.Keys) { ItemDefinition item2 = Registry.GetItem(key); if ((Object)(object)item2 == (Object)null) { num3++; MelonLogger.Msg("[Eat] '" + key + "' NOT IN REGISTRY — cannot wire."); continue; } if ((Object)(object)item2.Equippable != (Object)null && (Object)(object)((Il2CppObjectBase)item2.Equippable).TryCast() != (Object)null) { num2++; VLog("'" + key + "' already consume-equippable"); continue; } string text = "none"; try { if ((Object)(object)item2.Equippable != (Object)null) { text = ((MemberInfo)((Object)item2.Equippable).GetIl2CppType()).Name; } } catch { text = "?"; } if (text != "none" && text != "Equippable_Viewmodel") { num4++; MelonLogger.Msg($"[Eat] '{key}' has functional equippable ({text}) — NOT wired."); } else { item2.EquipMode = item.EquipMode; item2.Equippable = item.Equippable; ((BaseItemDefinition)item2).EquippableData = ((BaseItemDefinition)item).EquippableData; bool flag = (Object)(object)item2.Equippable != (Object)null && (Object)(object)((Il2CppObjectBase)item2.Equippable).TryCast() != (Object)null; num++; _wiredIds.Add(key); MelonLogger.Msg($"[Eat] '{key}' wired into the native drink flow (verify readback: {(flag ? "OK" : "FAILED")})."); } } MelonLogger.Msg($"[Eat] wiring complete: {num} wired, {num2} already native, {num4} skipped (functional equippable), {num3} missing, {_map.Count} mapped total."); } catch (Exception ex) { MelonLogger.Warning("[Eat] food wiring failed (will retry next session): " + ex.Message); _foodMadeDrinkable = false; } } public static void OnSessionEndedFoodWiring() { _foodMadeDrinkable = false; _wiredIds.Clear(); } internal static void VLog(string msg) { if (NeedsConfig.VerboseConsume) { MelonLogger.Msg("[Eat] " + msg); } } public static string BuildToast(string itemName, Restore r) { string text = itemName ?? ""; string[] pool; if (text.IndexOf("Pan Lasagna", StringComparison.OrdinalIgnoreCase) >= 0) { pool = DanLasagnaLines; } else if (text.IndexOf("Dan's", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Chili", StringComparison.OrdinalIgnoreCase) >= 0) { pool = DanChiliLines; } else if (text.IndexOf("Manuke", StringComparison.OrdinalIgnoreCase) >= 0) { pool = ManukeLines; } else if (text.IndexOf("Special", StringComparison.OrdinalIgnoreCase) >= 0) { pool = KyleSpecialLines; } else if (text.IndexOf("Taco", StringComparison.OrdinalIgnoreCase) >= 0) { pool = TacoLines; } else if (r.Thirst > r.Hunger && r.Thirst > 0f) { pool = DrinkLines; } else if (r.Hunger > 0f) { pool = EatLines; } else { if (!(r.Energy > 0f)) { return itemName; } pool = EnergyLines; } return Lines.Pick(pool, itemName); } } public static class ConsumeAudio { public enum ConsumeSoundKind { Crunch, Soft, Sip, Gulp, Slurp, Beer, Burrito, Native } private static AudioSource _source; private static AudioClip _nativeEat; private static AudioClip _capOpen; private static AudioClip _nativeCap; private static readonly List _pool = new List(); private static bool _nativeSearched; private static bool _poolTried; private static bool _capTried; private static int _lastPick = -1; private static Random _rng = new Random(20260809); private static readonly Dictionary _soundKinds = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["brekkieroll"] = ConsumeSoundKind.Soft, ["tunasando"] = ConsumeSoundKind.Soft, ["delisando"] = ConsumeSoundKind.Soft, ["vendingsando"] = ConsumeSoundKind.Soft, ["porkbun"] = ConsumeSoundKind.Soft, ["pretzelbrat"] = ConsumeSoundKind.Soft, ["bakebrownie"] = ConsumeSoundKind.Soft, ["mingchicken"] = ConsumeSoundKind.Soft, ["rotisserie"] = ConsumeSoundKind.Soft, ["steakfrites"] = ConsumeSoundKind.Soft, ["smokedfish"] = ConsumeSoundKind.Soft, ["danlasagna"] = ConsumeSoundKind.Soft, ["krautslice"] = ConsumeSoundKind.Soft, ["almonddanish"] = ConsumeSoundKind.Soft, ["cremebrulee"] = ConsumeSoundKind.Soft, ["donut"] = ConsumeSoundKind.Soft, ["chili"] = ConsumeSoundKind.Soft, ["megabean"] = ConsumeSoundKind.Soft, ["fishnchips"] = ConsumeSoundKind.Crunch, ["croissant"] = ConsumeSoundKind.Crunch, ["sausageroll"] = ConsumeSoundKind.Crunch, ["theslop"] = ConsumeSoundKind.Slurp, ["instantramen"] = ConsumeSoundKind.Slurp, ["noodlecup"] = ConsumeSoundKind.Slurp, ["onionsoup"] = ConsumeSoundKind.Slurp, ["soupbowl"] = ConsumeSoundKind.Slurp, ["danchili"] = ConsumeSoundKind.Slurp, ["dinercoffee"] = ConsumeSoundKind.Sip, ["urncoffee"] = ConsumeSoundKind.Sip, ["flatwhite"] = ConsumeSoundKind.Sip, ["coatespresso"] = ConsumeSoundKind.Sip, ["lobbycoffee"] = ConsumeSoundKind.Sip, ["thermoscoffee"] = ConsumeSoundKind.Sip, ["churchcoffee"] = ConsumeSoundKind.Sip, ["jasminetea"] = ConsumeSoundKind.Sip, ["slushee"] = ConsumeSoundKind.Gulp, ["bottledwater"] = ConsumeSoundKind.Gulp, ["vodkasoda"] = ConsumeSoundKind.Gulp, ["canarycocktail"] = ConsumeSoundKind.Gulp, ["boxedwine"] = ConsumeSoundKind.Gulp, ["tallboy"] = ConsumeSoundKind.Beer, ["weissbier"] = ConsumeSoundKind.Beer, ["burroito"] = ConsumeSoundKind.Burrito }; private static readonly Dictionary _catPools = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _catLast = new Dictionary(StringComparer.OrdinalIgnoreCase); private static AudioClip _burritoBite; private static bool _burritoTried; private static AudioClip _pillPop; private static bool _pillTried; private static AudioClip _blisterPop; private static bool _blisterTried; private static readonly string[] Tier1 = new string[4] { "chew", "munch", "chomp", "bite" }; private static readonly string[] Tier2 = new string[1] { "crunch" }; private static readonly string[] Tier3 = new string[2] { "meat", "eat" }; private static readonly string[] EatGuards = new string[10] { "death", "weather", "heart", "creat", "beat", "leather", "sweat", "theat", "feat", "repeat" }; public static void PlayCapOpen() { if (!NeedsConfig.ConsumeSound) { return; } try { EnsureBuilt(); AudioClip val = (Alive(_nativeCap) ? _nativeCap : _capOpen); string value = (Alive(_nativeCap) ? "native game clip" : "bundled CC0 recording"); bool flag = (Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source); if (flag && Alive(val)) { _source.pitch = 0.97f + 0.06f * (float)_rng.NextDouble(); _source.PlayOneShot(val, Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume)); MelonLogger.Msg($"[Audio] cap-open: PLAYING '{((Object)val).name}' ({value})"); } else { MelonLogger.Warning($"[Audio] cap-open: NOT PLAYED — source alive={flag}, clip loaded={Alive(val)}"); } } catch (Exception ex) { MelonLogger.Warning("[Audio] Cap-open sound failed: " + ex.Message); } } public static ConsumeSoundKind KindFor(string id) { if (!_soundKinds.TryGetValue(id ?? "", out var value)) { return ConsumeSoundKind.Native; } return value; } public static bool MutesNativeSlurp(string id) { ConsumeSoundKind consumeSoundKind = KindFor(id); if (consumeSoundKind != ConsumeSoundKind.Sip && consumeSoundKind != ConsumeSoundKind.Gulp) { return consumeSoundKind == ConsumeSoundKind.Beer; } return true; } public static bool HasDrinkSound(string id) { return MutesNativeSlurp(id); } public static void PlayConsume(string id) { switch (KindFor(id)) { case ConsumeSoundKind.Burrito: PlayBurritoBite(); break; case ConsumeSoundKind.Soft: PlayCategory("softchew", 3, 0.94f, 0.12f); break; case ConsumeSoundKind.Sip: PlayCategory("sip", 3, 0.96f, 0.08f); break; case ConsumeSoundKind.Gulp: PlayCategory("gulp", 3, 0.94f, 0.12f); break; case ConsumeSoundKind.Slurp: PlayCategory("slurp", 3, 0.95f, 0.1f); break; case ConsumeSoundKind.Beer: PlayCategory("beer", 2, 0.95f, 0.1f); break; default: PlayEat(); break; } } private static void PlayCategory(string baseName, int count, float basePitch, float pitchSpread) { if (!NeedsConfig.ConsumeSound) { return; } try { EnsureBuilt(); if (!_catPools.TryGetValue(baseName, out var value) || value == null) { List list = new List(count); for (int i = 1; i <= count; i++) { AudioClip val = LoadEmbeddedWav($"S1HungerThirst.Assets.{baseName}{i}.wav", $"S1HT_{baseName}{i}"); if ((Object)(object)val != (Object)null) { list.Add(val); } } value = list.ToArray(); _catPools[baseName] = value; MelonLogger.Msg($"[Audio] category '{baseName}': {value.Length}/{count} variant(s) loaded."); } if ((Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source) && value.Length != 0) { int value2; int num = (_catLast.TryGetValue(baseName, out value2) ? value2 : (-1)); int num2; do { num2 = _rng.Next(value.Length); } while (value.Length > 1 && num2 == num); _catLast[baseName] = num2; AudioClip val2 = value[num2]; if (Alive(val2)) { _source.pitch = basePitch + pitchSpread * (float)_rng.NextDouble(); _source.PlayOneShot(val2, Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume)); MelonLogger.Msg($"[Audio] category '{baseName}': PLAYING variant {num2 + 1}"); } } } catch (Exception ex) { MelonLogger.Warning("[Audio] category '" + baseName + "' failed: " + ex.Message); } } private static AudioClip LoadEmbeddedWav(string resource, string clipName) { try { using Stream stream = typeof(ConsumeAudio).Assembly.GetManifestResourceStream(resource); if (stream == null) { MelonLogger.Warning("[Audio] bundled '" + resource + "' not found."); 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 WavToClip(array, clipName); } catch (Exception ex) { MelonLogger.Warning("[Audio] '" + resource + "' load failed: " + ex.Message); return null; } } public static void PlayBurritoBite() { if (!NeedsConfig.ConsumeSound) { MelonLogger.Msg("[Audio] burrito bite: ConsumeSound disabled, no sound."); return; } try { EnsureBuilt(); if (!_burritoTried || !Alive(_burritoBite)) { LoadBurritoBite(); } if ((Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source) && Alive(_burritoBite)) { _source.pitch = 0.95f + 0.1f * (float)_rng.NextDouble(); _source.PlayOneShot(_burritoBite, Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume)); MelonLogger.Msg("[Audio] burrito bite: PLAYING '" + ((Object)_burritoBite).name + "'"); } else { MelonLogger.Msg("[Audio] burrito bite unavailable — falling back to the generic bite."); PlayEat(); } } catch (Exception ex) { MelonLogger.Warning("[Audio] burrito bite failed: " + ex.Message); } } private static void LoadBurritoBite() { _burritoTried = true; try { using Stream stream = typeof(ConsumeAudio).Assembly.GetManifestResourceStream("S1HungerThirst.Assets.burritobite.wav"); if (stream == null) { MelonLogger.Warning("[Audio] bundled burritobite.wav not found in assembly."); return; } 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; } } _burritoBite = WavToClip(array, "S1HT_BurritoBite"); if ((Object)(object)_burritoBite != (Object)null) { MelonLogger.Msg($"[Audio] BURRITO BITE = bundled recording ({_burritoBite.length:0.00}s, freesound_community via Pixabay)."); } } catch (Exception ex) { MelonLogger.Warning("[Audio] burrito bite sample failed to load: " + ex.Message); } } public static void PlayEat() { if (!NeedsConfig.ConsumeSound) { MelonLogger.Msg("[Audio] bite: ConsumeSound disabled, no sound."); return; } try { EnsureBuilt(); AudioClip val = null; string value = null; if ((NeedsConfig.EatClipName ?? "").Trim().Length > 0 && Alive(_nativeEat)) { val = _nativeEat; value = "pinned native clip"; } else if (_pool.Count > 0) { val = PickFromPool(); value = "bundled CC0 recording"; } else if (Alive(_nativeEat)) { val = _nativeEat; value = "native game clip"; } bool flag = (Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source); if (flag && (Object)(object)val != (Object)null) { float num = Mathf.Clamp(NeedsConfig.EatPitchVariance, 0f, 0.5f); _source.pitch = 1f - num * 0.5f + num * (float)_rng.NextDouble(); float num2 = Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume); _source.PlayOneShot(val, num2); MelonLogger.Msg($"[Audio] bite: PLAYING '{((Object)val).name}' ({value}, {val.length:0.00}s, vol={num2:0.00}, pitch={_source.pitch:0.00})"); } else { MelonLogger.Warning($"[Audio] bite: NOT PLAYED — source alive={flag}, pool={_pool.Count}, native={(Alive(_nativeEat) ? ((Object)_nativeEat).name : "none")}"); } } catch (Exception ex) { MelonLogger.Warning("[Audio] Eat sound failed: " + ex.Message); } } private static AudioClip PickFromPool() { if (_pool.Count == 1) { return _pool[0]; } int num; do { num = _rng.Next(_pool.Count); } while (num == _lastPick); _lastPick = num; return _pool[num]; } private static bool Alive(AudioClip c) { if ((Object)(object)c != (Object)null) { return Object.op_Implicit((Object)(object)c); } return false; } public static void Teardown() { try { if ((Object)(object)_source != (Object)null) { Object.Destroy((Object)(object)((Component)_source).gameObject); } } catch { } _source = null; _nativeSearched = false; _nativeEat = null; } private static void EnsureBuilt() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_source == (Object)null || !Object.op_Implicit((Object)(object)_source)) { _source = new GameObject("S1HT_Audio").AddComponent(); _source.playOnAwake = false; _source.spatialBlend = 0f; } if (!_poolTried || PoolDead()) { LoadPool(); } if (!_capTried || !Alive(_capOpen)) { LoadCapOpen(); } if (!_nativeSearched) { FindNativeEatClip(); } } public static void PlayPillPop() { if (!NeedsConfig.ConsumeSound) { return; } try { EnsureBuilt(); if (!_pillTried || !Alive(_pillPop)) { LoadPillPop(); } if ((Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source) && Alive(_pillPop)) { _source.pitch = 0.96f + 0.08f * (float)_rng.NextDouble(); _source.PlayOneShot(_pillPop, Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume)); MelonLogger.Msg("[Audio] pill-pop: PLAYING '" + ((Object)_pillPop).name + "'"); } } catch (Exception ex) { MelonLogger.Warning("[Audio] pill-pop failed: " + ex.Message); } } private static void LoadPillPop() { _pillTried = true; try { using Stream stream = typeof(ConsumeAudio).Assembly.GetManifestResourceStream("S1HungerThirst.Assets.pills.wav"); if (stream == null) { MelonLogger.Warning("[Audio] bundled pills.wav not found in assembly."); return; } 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; } } _pillPop = WavToClip(array, "S1HT_PillPop"); if ((Object)(object)_pillPop != (Object)null) { MelonLogger.Msg($"[Audio] PILL SOUND = bundled recording ({_pillPop.length:0.00}s, Rudmer_Rotteveel via Pixabay)."); } } catch (Exception ex) { MelonLogger.Warning("[Audio] pills sample failed to load: " + ex.Message); } } public static void PlayBlisterPop() { if (!NeedsConfig.ConsumeSound) { return; } try { EnsureBuilt(); if (!_blisterTried || !Alive(_blisterPop)) { LoadBlisterPop(); } if ((Object)(object)_source != (Object)null && Object.op_Implicit((Object)(object)_source) && Alive(_blisterPop)) { _source.pitch = 0.96f + 0.08f * (float)_rng.NextDouble(); _source.PlayOneShot(_blisterPop, Mathf.Clamp01(NeedsConfig.ConsumeSoundVolume)); MelonLogger.Msg("[Audio] blister-pop: PLAYING '" + ((Object)_blisterPop).name + "'"); } } catch (Exception ex) { MelonLogger.Warning("[Audio] blister-pop failed: " + ex.Message); } } private static void LoadBlisterPop() { _blisterTried = true; try { using Stream stream = typeof(ConsumeAudio).Assembly.GetManifestResourceStream("S1HungerThirst.Assets.blister.wav"); if (stream == null) { MelonLogger.Warning("[Audio] bundled blister.wav not found in assembly."); return; } 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; } } _blisterPop = WavToClip(array, "S1HT_BlisterPop"); if ((Object)(object)_blisterPop != (Object)null) { MelonLogger.Msg($"[Audio] BLISTER SOUND = bundled recording ({_blisterPop.length:0.00}s, spinopel via Pixabay)."); } } catch (Exception ex) { MelonLogger.Warning("[Audio] blister sample failed to load: " + ex.Message); } } private static void LoadCapOpen() { _capTried = true; try { using Stream stream = typeof(ConsumeAudio).Assembly.GetManifestResourceStream("S1HungerThirst.Assets.capopen.wav"); if (stream == null) { MelonLogger.Warning("[Audio] bundled capopen.wav not found in assembly."); return; } 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; } } _capOpen = WavToClip(array, "S1HT_CapOpen"); if ((Object)(object)_capOpen != (Object)null) { MelonLogger.Msg($"[Audio] CAP-OPEN SOUND = bundled CC0 recording ({_capOpen.length:0.00}s, OwlishMedia)."); } } catch (Exception ex) { MelonLogger.Warning("[Audio] capopen sample failed to load: " + ex.Message); } } private static bool PoolDead() { for (int i = 0; i < _pool.Count; i++) { if (!Alive(_pool[i])) { return true; } } return _pool.Count == 0; } private static void LoadPool() { _poolTried = true; _pool.Clear(); _lastPick = -1; Assembly assembly = typeof(ConsumeAudio).Assembly; for (int i = 1; i <= 8; i++) { string text = $"S1HungerThirst.Assets.eat{i}.wav"; try { using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { continue; } byte[] array = new byte[stream.Length]; int num; for (int j = 0; j < array.Length; j += num) { num = stream.Read(array, j, array.Length - j); if (num <= 0) { break; } } AudioClip val = WavToClip(array, $"S1HT_Eat{i}"); if ((Object)(object)val != (Object)null) { _pool.Add(val); } } catch (Exception ex) { MelonLogger.Warning("[Audio] bundled '" + text + "' failed to load: " + ex.Message); } } if (_pool.Count > 0) { MelonLogger.Msg($"[Audio] EAT SOUND = pool of {_pool.Count} bundled CC0 bite recordings (cucumber/toast, by cogitollc)."); } else { MelonLogger.Warning("[Audio] NO bundled eat recordings loaded — will try a native game clip."); } } private static AudioClip WavToClip(byte[] b, string name) { if (b.Length < 44 || b[0] != 82 || b[1] != 73 || b[2] != 70 || b[3] != 70 || b[8] != 87 || b[9] != 65 || b[10] != 86 || b[11] != 69) { MelonLogger.Warning("[Audio] '" + name + "' is not a RIFF/WAVE file."); return null; } int num = 0; int num2 = 0; int num3 = 0; int num4 = -1; int num5 = 0; int num6; for (int i = 12; i + 8 <= b.Length; i += 8 + num6 + (num6 & 1)) { string text = Encoding.ASCII.GetString(b, i, 4); num6 = BitConverter.ToInt32(b, i + 4); if (text == "fmt ") { int num7 = BitConverter.ToInt16(b, i + 8); num = BitConverter.ToInt16(b, i + 10); num2 = BitConverter.ToInt32(b, i + 12); num3 = BitConverter.ToInt16(b, i + 22); if (num7 != 1 || num3 != 16) { MelonLogger.Warning($"[Audio] '{name}' format unsupported (fmt={num7}, bits={num3})."); return null; } } else if (text == "data") { num4 = i + 8; num5 = num6; } } if (num4 < 0 || num <= 0 || num2 <= 0) { return null; } if (num4 + num5 > b.Length) { num5 = b.Length - num4; } int num8 = num5 / (2 * num); float[] array = new float[num8]; for (int j = 0; j < num8; j++) { float num9 = 0f; for (int k = 0; k < num; k++) { num9 += (float)BitConverter.ToInt16(b, num4 + (j * num + k) * 2) / 32768f; } array[j] = num9 / (float)num; } AudioClip obj = AudioClip.Create(name, num8, 1, num2, false); obj.SetData(Il2CppStructArray.op_Implicit(array), 0); ((Object)obj).hideFlags = (HideFlags)32; return obj; } private static void FindNativeEatClip() { _nativeSearched = true; try { Il2CppReferenceArray val = Resources.FindObjectsOfTypeAll(Il2CppType.Of()); string text = (NeedsConfig.EatClipName ?? "").Trim(); AudioClip val2 = null; int num = 99; int num2 = 0; for (int i = 0; i < ((Il2CppArrayBase)(object)val).Length; i++) { AudioClip val3 = ((Il2CppObjectBase)((Il2CppArrayBase)(object)val)[i]).TryCast(); if (!((Object)(object)val3 == (Object)null)) { string text2 = ((Object)val3).name.ToLowerInvariant(); if ((Object)(object)_nativeCap == (Object)null && val3.length >= 0.1f && val3.length <= 2f && (text2.Contains("bottlecap") || text2.Contains("bottle_open") || text2.Contains("unscrew") || (text2.Contains("bottle") && text2.Contains("open")))) { _nativeCap = val3; MelonLogger.Msg("[Audio] native bottle-open clip found: '" + ((Object)val3).name + "' — used for mouthwash."); } if (text.Length > 0 && string.Equals(((Object)val3).name, text, StringComparison.OrdinalIgnoreCase)) { val2 = val3; num = 0; break; } int num3 = ScoreName(text2); if (num3 < 99 && NeedsConfig.VerboseConsume && num2 < 25) { MelonLogger.Msg($"[Audio] candidate clip: '{((Object)val3).name}' ({val3.length:0.00}s, tier {num3})"); num2++; } if (num3 < num && val3.length >= 0.15f && val3.length <= 3f) { val2 = val3; num = num3; } } } if ((Object)(object)val2 != (Object)null) { _nativeEat = val2; MelonLogger.Msg($"[Audio] native eat clip available: '{((Object)val2).name}' ({val2.length:0.00}s, tier {num})."); } } catch (Exception ex) { MelonLogger.Warning("[Audio] Native clip search failed: " + ex.Message); } } private static int ScoreName(string n) { string[] tier = Tier1; foreach (string value in tier) { if (n.Contains(value)) { return 1; } } tier = Tier2; foreach (string value2 in tier) { if (n.Contains(value2)) { return 2; } } tier = Tier3; foreach (string text in tier) { if (!n.Contains(text)) { continue; } if (text == "eat") { bool flag = false; string[] eatGuards = EatGuards; foreach (string value3 in eatGuards) { if (n.Contains(value3)) { flag = true; break; } } if (flag) { continue; } } return 3; } return 99; } } public static class ConsumeWatcher { private const string MouthwashId = "mouthwash"; private static IntPtr _vmPtr = IntPtr.Zero; private static Equippable_Cuke _vm; private static bool _vmIsFood; private static bool _vmIsMouthwash; private static bool _vmIsWired; private static bool _vmIsCuke; private static bool _vmIsGasoline; private static bool _vmIsFx; private static bool _vmFxArmed; private static bool _vmIsPill; private static bool _vmHasOwnTrash; private static Restore _vmRestore; private static string _vmName; private static string _vmId; private static bool _wasDrinking; private static ProductDefinition _stashedPseudo; private static bool _pseudoStashed; private static ItemSlot _watchedSlot; private static int _watchedQty = -1; private static readonly HashSet _trashBefore = new HashSet(); private static float _trashWindowUntil; private static int _probeIndex; private static float _nextProbeAt; private static bool _patchProven; private static readonly float[] ProbeDelays = new float[4] { 0.5f, 1.25f, 2.5f, 4f }; private static readonly string[] FxTakenLines = new string[3] { "Straight, no mixer.", "Neat. As intended by nobody.", "Down raw. Here it comes." }; private static readonly string[] FxHeldLines = new string[3] { "Already on something. It can wait.", "One thing at a time.", "The current high called dibs." }; private static readonly string[] PurgeUpLines = new string[3] { "That came straight back up.", "Nope. Straight back out.", "The body voted no on the mouthwash." }; private static readonly string[] PurgeClearedLines = new string[3] { "High's gone with it.", "Sober now. The hard way.", "Whatever that was, it's in the gutter now." }; private static readonly string[] PurgePointlessLines = new string[3] { "Drank mouthwash for no reason. Great.", "Minty. Pointless. Regrettable.", "That achieved nothing except the puking." }; public static bool EatWindowActive { get { if (_trashWindowUntil > 0f) { return Time.unscaledTime <= _trashWindowUntil; } return false; } } private static void ClearVmTracking() { _vmPtr = IntPtr.Zero; _vm = null; _vmIsFood = false; _vmIsWired = false; _vmIsCuke = false; _vmIsGasoline = false; _vmIsFx = false; _vmFxArmed = false; _vmIsPill = false; _vmHasOwnTrash = false; _wasDrinking = false; _stashedPseudo = null; _pseudoStashed = false; _watchedSlot = null; _watchedQty = -1; } public static void Reset() { ClearVmTracking(); _trashBefore.Clear(); _trashWindowUntil = 0f; _probeIndex = 0; } public static void Tick() { //IL_015b: 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_00dc: Unknown result type (might be due to invalid IL or missing references) SweepTrash(); PlayerInventory instance = PlayerSingleton.Instance; if ((Object)(object)instance == (Object)null) { ClearVmTracking(); return; } try { if (_watchedSlot != null && _watchedQty >= 0) { int num = -1; try { num = _watchedSlot.Quantity; } catch { _watchedSlot = null; } if (num >= 0 && num < _watchedQty) { int num2 = _watchedQty - num; Restore vmRestore = _vmRestore; NeedsState.Replenish(vmRestore.Hunger * (float)num2, vmRestore.Thirst * (float)num2, vmRestore.Energy * (float)num2); if (_vmIsMouthwash) { OnMouthwashConsumed(); } else if (_vmIsGasoline) { OnGasolineConsumed(); } else if (_vmIsFx) { NeedsHud.Toast(_vmFxArmed ? Lines.Pick(FxTakenLines) : Lines.Pick(FxHeldLines), _vmFxArmed ? NeedsHud.ToastGood : NeedsHud.ToastNeutral); Diag.Log($"[FX] '{_vmId}' consumed — {(_vmFxArmed ? "effect applied via native flow (registered real-product clone)" : "withheld (real high active)")}."); } else { NeedsHud.Toast(ConsumableMap.BuildToast(_vmName, vmRestore), NeedsHud.ToastGood); if (TacoItem.IsTacoId(_vmId)) { TacoItem.OnTacoEaten(_vmId); } } MelonLogger.Msg($"[Eat] consumed '{_vmId}' x{num2} — restore applied (h={vmRestore.Hunger} t={vmRestore.Thirst} e={vmRestore.Energy})"); } if (num >= 0) { _watchedQty = num; } } } catch (Exception ex) { MelonLogger.Warning("[Eat] quantity watch error: " + ex.Message); } Equippable_Cuke val = null; try { Equippable equippable = instance.Equippable; val = (((Object)(object)equippable != (Object)null) ? ((Il2CppObjectBase)equippable).TryCast() : null); } catch { } if ((Object)(object)val == (Object)null) { if (_vmPtr != IntPtr.Zero) { RestorePseudo(); ClearVmTracking(); } return; } if (((Il2CppObjectBase)val).Pointer != _vmPtr) { RestorePseudo(); _vmPtr = ((Il2CppObjectBase)val).Pointer; _vm = val; _wasDrinking = false; ItemDefinition val2 = ((instance.EquippedItem != null) ? instance.EquippedItem.Definition : null); _vmId = (((Object)(object)val2 != (Object)null) ? ((BaseItemDefinition)val2).ID : "?"); _vmName = (((Object)(object)val2 != (Object)null) ? ((BaseItemDefinition)val2).Name : "?"); bool flag = ConsumableMap.TryGet(_vmId, out _vmRestore); if (!flag) { _vmRestore = new Restore(0f, 20f); } _vmIsMouthwash = string.Equals(_vmId, "mouthwash", StringComparison.OrdinalIgnoreCase); _vmIsGasoline = string.Equals(_vmId, "gasoline", StringComparison.OrdinalIgnoreCase); _vmIsFx = IngredientEffects.IsFxIngredient(_vmId); _vmIsPill = _vmIsFx && IngredientEffects.IsPill(_vmId); _vmIsFood = !_vmIsMouthwash && !_vmIsGasoline && !_vmIsFx && flag && ConsumableMap.IsFood(_vmRestore); _vmIsWired = ConsumableMap.WasWired(_vmId); _vmIsCuke = string.Equals(_vmId, "cuke", StringComparison.OrdinalIgnoreCase); _vmFxArmed = false; _vmHasOwnTrash = false; _watchedSlot = null; _watchedQty = -1; try { _watchedSlot = (ItemSlot)(object)instance.equippedSlot; if (_watchedSlot != null) { _watchedQty = _watchedSlot.Quantity; } } catch { } ConsumableMap.VLog($"equipped '{_vmId}' via cuke flow (food={_vmIsFood}, qty={_watchedQty})"); try { if (NeedsConfig.PreserveDrugEffects) { val.ClearDrugEffects = false; } if (_vmIsWired || _vmIsCuke) { float baseEnergyGain = val.BaseEnergyGain; float minEnergyGain = val.MinEnergyGain; val.BaseEnergyGain = 0f; val.MinEnergyGain = 0f; if (_vmIsWired) { val.HealthGain = 0f; } if (baseEnergyGain != 0f || minEnergyGain != 0f) { ConsumableMap.VLog($"native stim payload zeroed on '{_vmId}' (BaseEnergyGain {baseEnergyGain:0.#}->0, MinEnergyGain {minEnergyGain:0.#}->0) — heart racing is energy-drink-only"); } } if (ConsumableMap.WasWired(_vmId)) { ApplyFoodPresentation(val, val2, muteOpen: true, _vmIsFood || _vmIsPill || ConsumeAudio.MutesNativeSlurp(_vmId)); if (_vmIsMouthwash || _vmIsFx) { _vmHasOwnTrash = SwapTrashPrefab(val, _vmId); } } } catch (Exception ex2) { MelonLogger.Warning("[Eat] presentation error: " + ex2.Message); } } try { bool flag2 = (Object)(object)Player.Local != (Object)null && Player.Local.ConsumedProduct != null; bool flag3 = false; try { ProductItemInstance val3 = (flag2 ? Player.Local.ConsumedProduct : null); flag3 = val3 != null && (Object)(object)((ItemInstance)val3).Definition != (Object)null && (((BaseItemDefinition)((ItemInstance)val3).Definition).ID ?? "").StartsWith("s1ht_fx_", StringComparison.OrdinalIgnoreCase); } catch { } if (_vmIsFx && (!flag2 || flag3 || !NeedsConfig.PreserveDrugEffects)) { ProductDefinition fxProduct = IngredientEffects.GetFxProduct(_vmId); if ((Object)(object)fxProduct != (Object)null && ((Object)(object)_vm.PseudoProduct == (Object)null || ((Il2CppObjectBase)_vm.PseudoProduct).Pointer != ((Il2CppObjectBase)fxProduct).Pointer)) { _vm.PseudoProduct = fxProduct; _vmFxArmed = true; ConsumableMap.VLog($"ingredient effect armed: '{_vmId}' → product '{((BaseItemDefinition)fxProduct).ID}' (native flow)"); } } else if (_vmIsWired || _vmIsCuke) { if ((Object)(object)_vm.PseudoProduct != (Object)null) { _vm.PseudoProduct = null; _vmFxArmed = false; ConsumableMap.VLog(_vmIsCuke ? "cuke pseudo-product removed (plain thirst drink — no stim)" : (_vmIsFx ? "real high active — ingredient effect held back (preservation)" : "wired item — pseudo-product disarmed (no hidden energy kick)")); } } else if (NeedsConfig.PreserveDrugEffects && flag2 && !_pseudoStashed && (Object)(object)_vm.PseudoProduct != (Object)null) { _stashedPseudo = _vm.PseudoProduct; _vm.PseudoProduct = null; _pseudoStashed = true; ConsumableMap.VLog("high — pseudo-product disarmed for this equip"); } else if (_pseudoStashed && !flag2 && !_vmIsWired && !_vmIsCuke) { RestorePseudo(); } bool isDrinking = _vm.IsDrinking; if (isDrinking && !_wasDrinking) { ConsumableMap.VLog("bite/sip started on '" + _vmId + "' — " + (_vmIsMouthwash ? "cap-open, native slurp, purge on completion" : (_vmIsFood ? "CHOMP" : "native slurp"))); if (_vmIsMouthwash) { ConsumeAudio.PlayCapOpen(); } else if (_vmIsFood) { ConsumeAudio.PlayConsume(_vmId); SnapshotTrash(); } else if (_vmIsFx) { if (_vmIsPill) { if (IngredientEffects.IsBottlePill(_vmId)) { ConsumeAudio.PlayPillPop(); } else { ConsumeAudio.PlayBlisterPop(); } } if (!_vmHasOwnTrash) { SnapshotTrash(); } } else if (_vmIsGasoline && !_vmHasOwnTrash) { SnapshotTrash(); } else if (ConsumeAudio.HasDrinkSound(_vmId)) { ConsumeAudio.PlayConsume(_vmId); if (!IsCannedDrink(_vmId)) { SnapshotTrash(); } } } _wasDrinking = isDrinking; } catch (Exception ex3) { MelonLogger.Warning("[Eat] watcher error: " + ex3.Message); } SweepTrash(); } public static void NotifyTrashSpawned(TrashItem t) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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) if (!EatWindowActive || (Object)(object)t == (Object)null) { return; } try { string a = ""; try { a = t.ID ?? ""; } catch { } if (string.Equals(a, "plantscrap", StringComparison.OrdinalIgnoreCase)) { return; } Player local = Player.Local; if ((Object)(object)local != (Object)null) { Vector3 val = ((Component)t).transform.position - ((Component)local).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 64f) { return; } } Object.Destroy((Object)(object)((Component)t).gameObject); if (!_patchProven) { _patchProven = true; MelonLogger.Msg("[Eat] trash patch is live — probe scans disabled from here on."); } _trashWindowUntil = 0f; _probeIndex = ProbeDelays.Length; ConsumableMap.VLog("thrown can culled at spawn (patched path, no scan)"); } catch (Exception ex) { MelonLogger.Warning("[Eat] spawn-cull failed: " + ex.Message); } } private static bool IsCannedDrink(string id) { return string.Equals(id, "tallboy", StringComparison.OrdinalIgnoreCase); } private static void SnapshotTrash() { float unscaledTime = Time.unscaledTime; _trashWindowUntil = unscaledTime + 6f; _probeIndex = 0; _nextProbeAt = unscaledTime + ProbeDelays[0]; if (_patchProven) { _probeIndex = ProbeDelays.Length; return; } _trashBefore.Clear(); try { Il2CppArrayBase val = Object.FindObjectsOfType(); for (int i = 0; i < val.Length; i++) { if ((Object)(object)val[i] != (Object)null) { _trashBefore.Add(((Il2CppObjectBase)val[i]).Pointer); } } } catch (Exception ex) { MelonLogger.Warning("[Eat] trash snapshot failed: " + ex.Message); } } private static void SweepTrash() { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (_trashWindowUntil <= 0f) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime > _trashWindowUntil) { _trashWindowUntil = 0f; } else { if (_patchProven || _probeIndex >= ProbeDelays.Length || unscaledTime < _nextProbeAt) { return; } _probeIndex++; if (_probeIndex < ProbeDelays.Length) { _nextProbeAt = _trashWindowUntil - 6f + ProbeDelays[_probeIndex]; } try { Player local = Player.Local; if ((Object)(object)local == (Object)null) { return; } Vector3 position = ((Component)local).transform.position; Il2CppArrayBase val = Object.FindObjectsOfType(); for (int i = 0; i < val.Length; i++) { TrashItem val2 = val[i]; if ((Object)(object)val2 == (Object)null || _trashBefore.Contains(((Il2CppObjectBase)val2).Pointer)) { continue; } string a = ""; try { a = val2.ID ?? ""; } catch { } if (!string.Equals(a, "plantscrap", StringComparison.OrdinalIgnoreCase)) { Vector3 val3 = ((Component)val2).transform.position - position; if (!(((Vector3)(ref val3)).sqrMagnitude > 64f)) { Object.Destroy((Object)(object)((Component)val2).gameObject); ConsumableMap.VLog($"thrown can culled by probe scan #{_probeIndex}"); _trashWindowUntil = 0f; break; } } } } catch (Exception ex) { MelonLogger.Warning("[Eat] trash probe failed: " + ex.Message); _trashWindowUntil = 0f; } } } private static void OnMouthwashConsumed() { //IL_002c: 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_0054: Unknown result type (might be due to invalid IL or missing references) try { Player local = Player.Local; bool flag = (Object)(object)local != (Object)null && local.ConsumedProduct != null; TriggerNativePuke(local); NeedsHud.Toast(Lines.Pick(PurgeUpLines), NeedsHud.ToastWarn); if (NeedsConfig.MouthwashClearsEffects && flag) { DrugEffects.Reset(); local.ClearProduct(); NeedsHud.Toast(Lines.Pick(PurgeClearedLines), NeedsHud.ToastNeutral); MelonLogger.Msg("[Purge] mouthwash drink completed while high — native TriggerSick + ClearProduct()."); } else { NeedsHud.Toast(Lines.Pick(PurgePointlessLines), NeedsHud.ToastNeutral); MelonLogger.Msg("[Purge] mouthwash drink completed while sober — puked, nothing to clear."); } } catch (Exception ex) { MelonLogger.Warning("[Purge] mouthwash clear failed: " + ex.Message); } } private static void OnGasolineConsumed() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) try { Player local = Player.Local; if ((Object)(object)local == (Object)null) { return; } TriggerNativePuke(local); NeedsHud.Toast("That was petrol.", NeedsHud.ToastBad); PlayerHealth health = local.Health; if (NeedsConfig.GasolineLethal) { MelonLogger.Msg("[Gasoline] consumed — lethal path (SetHealth 0 + SendDie)."); if ((Object)(object)health != (Object)null && health.IsAlive) { health.SetHealth(0f); try { health.SendDie(); return; } catch (Exception ex) { MelonLogger.Warning("[Gasoline] SendDie failed: " + ex.Message); return; } } } else { MelonLogger.Msg("[Gasoline] consumed — knockout path (health floored to 10, energy 0, blackout)."); if ((Object)(object)health != (Object)null && health.IsAlive && health.CurrentHealth > 10f) { health.SetHealth(10f); } NeedsState.SetEnergy(0f); Penalties.Blackout(6f); NeedsHud.Toast("Lights out.", NeedsHud.ToastBad); } } catch (Exception ex2) { MelonLogger.Warning("[Gasoline] consume handling failed: " + ex2.Message); } } private static void TriggerNativePuke(Player player) { try { AvatarEffects val = (((Object)(object)player != (Object)null && (Object)(object)player.Avatar != (Object)null) ? player.Avatar.Effects : null); if ((Object)(object)val != (Object)null) { val.TriggerSick(true); ConsumableMap.VLog("native TriggerSick fired (VomitParticles + VomitSound)"); } else { MelonLogger.Warning("[Purge] AvatarEffects not found — puke visual/sound skipped."); } } catch (Exception ex) { MelonLogger.Warning("[Purge] TriggerSick failed: " + ex.Message); } } private static bool SwapTrashPrefab(Equippable_Cuke vm, string itemId) { try { TrashManager instance = NetworkSingleton.Instance; Il2CppReferenceArray val = (((Object)(object)instance != (Object)null) ? instance.TrashPrefabs : null); if (val == null) { return false; } string text = (itemId ?? "").ToLowerInvariant(); if (text.Length == 0) { return false; } for (int i = 0; i < ((Il2CppArrayBase)(object)val).Length; i++) { TrashItem val2 = ((Il2CppArrayBase)(object)val)[i]; if (!((Object)(object)val2 == (Object)null) && (val2.ID + " " + ((Object)((Component)val2).gameObject).name).ToLowerInvariant().Contains(text)) { vm.TrashPrefab = val2; ConsumableMap.VLog($"trash prefab swapped to '{val2.ID}' (matches '{itemId}')"); return true; } } ConsumableMap.VLog("no '" + itemId + "' trash prefab in TrashManager — borrowed can handling applies"); return false; } catch (Exception ex) { MelonLogger.Warning("[Eat] trash prefab swap failed: " + ex.Message); return false; } } private static void RestorePseudo() { try { if (_pseudoStashed && (Object)(object)_vm != (Object)null && (Object)(object)_stashedPseudo != (Object)null) { _vm.PseudoProduct = _stashedPseudo; } } catch { } _stashedPseudo = null; _pseudoStashed = false; } private static void ApplyFoodPresentation(Equippable_Cuke vm, ItemDefinition def, bool muteOpen = true, bool muteSlurp = true) { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: 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_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Expected O, but got Unknown //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) int num = 0; int layer = ((Component)vm).gameObject.layer; Il2CppArrayBase componentsInChildren = ((Component)vm).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { layer = ((Component)componentsInChildren[i]).gameObject.layer; ((Renderer)componentsInChildren[i]).enabled = false; num++; } } try { if (muteOpen && (Object)(object)vm.OpenSound != (Object)null) { vm.OpenSound.VolumeMultiplier = 0f; } if (muteSlurp && (Object)(object)vm.SlurpSound != (Object)null) { vm.SlurpSound.VolumeMultiplier = 0f; } } catch { } bool flag = false; string text = "none"; try { for (int num2 = ((Component)vm).transform.childCount - 1; num2 >= 0; num2--) { Transform child = ((Component)vm).transform.GetChild(num2); if ((Object)(object)child != (Object)null && (((Object)((Component)child).gameObject).name ?? "").StartsWith("S1HT_")) { Object.Destroy((Object)(object)((Component)child).gameObject); } } Renderer materialDonor = null; Il2CppArrayBase componentsInChildren2 = ((Component)vm).GetComponentsInChildren(true); if (componentsInChildren2.Length > 0) { materialDonor = (Renderer)(object)componentsInChildren2[0]; } if ((Object)(object)def != (Object)null && ItemModels.TryResolve(((BaseItemDefinition)def).ID, out var mesh, out var matKey, out var look, out var handEuler)) { GameObject val = ItemModels.BuildArchetypeHandObject(mesh, matKey, look, materialDonor, layer, handEuler); if ((Object)(object)val != (Object)null) { val.transform.SetParent(((Component)vm).transform, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.Euler(handEuler); flag = true; text = $"archetype mesh '{((Object)mesh).name}' (mat '{matKey}', rot {handEuler})"; } } if (!flag && (Object)(object)def != (Object)null) { string desc; GameObject val2 = ItemModels.BuildFromStoredItem(def, layer, out desc); if ((Object)(object)val2 != (Object)null) { val2.transform.SetParent(((Component)vm).transform, false); val2.transform.localPosition = Vector3.zero; flag = true; text = desc; } } if (!flag && (Object)(object)def != (Object)null && (Object)(object)((BaseItemDefinition)def).Icon != (Object)null) { GameObject val3 = new GameObject("S1HT_FoodVisual"); val3.transform.SetParent(((Component)vm).transform, false); val3.layer = layer; SpriteRenderer obj2 = val3.AddComponent(); obj2.sprite = ((BaseItemDefinition)def).Icon; Bounds bounds = obj2.sprite.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num3 = Mathf.Max(new float[3] { size.x, size.y, 0.01f }); val3.transform.localScale = Vector3.one * (0.16f / num3); val3.transform.localPosition = Vector3.zero; flag = true; text = "flat icon (no prop meshes on this item)"; } } catch (Exception ex) { MelonLogger.Warning("[Eat] food visual failed: " + ex.Message); } try { ItemModels.NoteHandModel(((Object)(object)def != (Object)null) ? ((BaseItemDefinition)def).ID : null, flag ? text : "NOTHING (all sources failed)"); } catch { } ConsumableMap.VLog($"food presentation: {num} can renderer(s) hidden, sounds muted, visual {(flag ? text : "unavailable")}"); } } public static class DanDish { public const string ChiliId = "danchili"; public const string LasagnaId = "danlasagna"; private const string DanNpcId = "dan_samwell"; private const string ReaskChoiceText = "About what I'm growing..."; private const string ReaskAdmitGuid = "S1HT_DAN_ADMIT"; private const string ReaskDenyGuid = "S1HT_DAN_DENY"; private const string ReaskExitGuid = "S1HT_DAN_NVM"; private const string MenuChoiceText = "Ask about lunch"; private const string MenuBuyGuid = "S1HT_DAN_BUY"; private const string MenuExitGuid = "S1HT_DAN_BYE"; private static bool _armed; private static bool _gaveUp; private static bool _hooked; private static bool _menuArmed; private static bool _dumped; private static float _nextAttempt; private static float _nextHoursRefresh; private static int _attempts; private static bool _shopStocked; private static float _nextShopAttempt; private static int _shopAttempts; private static NPC _dan; private static DialogueController _controller; private static readonly Dictionary _introChoices = new Dictionary(StringComparer.Ordinal); private static DialogueChoice _reaskChoice; private static DialogueContainer _reaskConvo; private static DialogueNodeData _reaskReplyNode; private static DialogueContainer _menuConvo; private static DialogueNodeData _menuEntryNode; private static DialogueNodeData _menuSoldNode; private static string _menuDishId; private static string[] _menuEntryLines; private static readonly string[] ClosedLines = new string[3] { "Store's closed. The lunch keeps till tomorrow.", "We're locked up. The crockpot's off.", "Closed for the night. Lunch resumes at eight." }; private static readonly string[] ChiliEntryLines = new string[3] { "Pot of my chili's going in the back. Eleven bucks a bowl.", "Chili's been on since morning. Eleven and it's yours.", "Hungry? The back-room chili's ready. Eleven a bowl." }; private static readonly string[] LasagnaEntryLines = new string[3] { "For my favorite comedian? I brought in the pan lasagna. Sixteen and it's yours.", "Made the pan lasagna last night. Comedians eat for sixteen.", "Got the lasagna in the back. Sixteen. Don't go telling everyone." }; private static readonly string[] ChiliSoldLines = new string[3] { "There you go. Careful, it's got a kick.", "One bowl. The secret's cumin. Don't tell my wife I told you.", "Fresh ladle. Spoon's in the bag." }; private static readonly string[] LasagnaSoldLines = new string[3] { "Corner piece. That's respect.", "There you go. The pan does the heavy lifting.", "Middle cut today. You earned it." }; private static readonly string[] ChiliBrokeLines = new string[3] { "Eleven bucks, chief. The pot doesn't run on goodwill.", "You're short. The chili keeps, come back.", "Eleven, chief. Even my wife pays for hers." }; private static readonly string[] LasagnaBrokeLines = new string[3] { "Sixteen, chief. Comedy doesn't cover it.", "You're short. The pan's not going anywhere.", "Sixteen bucks. I know you're good for it... just not today, huh." }; private static readonly string[] ChiliBoughtToasts = new string[3] { "One bowl of Dan's chili. Housemade.", "Dan's chili, secured.", "Chili from the hardware store. Sure. Why not." }; private static readonly string[] LasagnaBoughtToasts = new string[3] { "Dan's pan lasagna. He likes you.", "The comedian's cut. Still warm.", "Hardware-store lasagna. Genuinely touched." }; public static void OnSessionEnded() { _armed = false; _gaveUp = false; _hooked = false; _menuArmed = false; _dumped = false; _attempts = 0; _nextAttempt = 0f; _nextHoursRefresh = 0f; _shopStocked = false; _shopAttempts = 0; _nextShopAttempt = 0f; _dan = null; _controller = null; _introChoices.Clear(); _reaskChoice = null; _reaskConvo = null; _reaskReplyNode = null; _menuConvo = null; _menuEntryNode = null; _menuSoldNode = null; _menuDishId = null; _menuEntryLines = null; } private static int EffectiveAnswer() { string text = (NeedsConfig.DanDishMode ?? "auto").Trim().ToLowerInvariant(); if (text == "chili") { return 1; } if (text == "lasagna") { return 2; } return SaveData.DanAnswer; } public static void Tick() { if (!NeedsConfig.VendorDanDish) { return; } TickShop(); if (_gaveUp) { return; } if (_armed) { TickArmed(); return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextAttempt) { return; } _nextAttempt = unscaledTime + 2f; try { TryArm(); } catch (Exception ex) { _gaveUp = true; Diag.Log("[DanDish] wiring failed (" + ex.Message + ") — Dan's lunch unavailable this session."); } } private static void TickArmed() { if (!_menuArmed && EffectiveAnswer() != 0) { try { ArmMenu(); } catch (Exception ex) { Diag.Log("[DanDish] menu arm failed: " + ex.Message); _gaveUp = true; } } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextHoursRefresh) { return; } _nextHoursRefresh = unscaledTime + 5f; if (_menuEntryNode == null) { return; } try { _menuEntryNode.DialogueText = (EateryVendors.IsOpenNow(NeedsConfig.HoursHardware) ? Lines.Pick(_menuEntryLines) : Lines.Pick(ClosedLines)); } catch { } } private static void TickShop() { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown if (_shopStocked) { return; } int num = EffectiveAnswer(); if (num == 0) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextShopAttempt) { return; } _nextShopAttempt = unscaledTime + 5f; string text = ((num == 2) ? "danlasagna" : "danchili"); try { if (!EateryVendors.TryGetDef(text, out var def) || (Object)(object)def == (Object)null) { return; } try { def.BasePurchasePrice = Mathf.Max(1f, (num == 2) ? NeedsConfig.DanLasagnaPrice : NeedsConfig.DanChiliPrice); } catch { } List allShops = ShopInterface.AllShops; if (allShops == null) { return; } int num2 = 0; int num3 = 0; for (int i = 0; i < allShops.Count; i++) { ShopInterface val = allShops[i]; if ((Object)(object)val == (Object)null || val.Listings == null) { continue; } bool flag = false; bool flag2 = false; ShopListing val2 = null; for (int j = 0; j < val.Listings.Count; j++) { ShopListing val3 = val.Listings[j]; if (val3 != null && !((Object)(object)val3.Item == (Object)null)) { string obj2 = ((BaseItemDefinition)val3.Item).ID ?? ""; if (obj2 == "soil") { flag = true; val2 = val3; } if (string.Equals(obj2, text, StringComparison.OrdinalIgnoreCase)) { flag2 = true; } } } if (!flag) { continue; } if (flag2) { num3++; continue; } ShopListing val4 = new ShopListing(); val4.name = ((BaseItemDefinition)def).Name; val4.Item = def; val4.LimitedStock = false; val4.RestockRate = (ERestockRate)0; val4.DefaultStock = 99; val4.CanBeDelivered = val2 != null && val2.CanBeDelivered; val.Listings.Add(val4); val4.Initialize(val); try { val.CreateListingUI(val4); } catch { } num2++; } if (num2 + num3 > 0) { _shopStocked = true; Diag.Log($"[DanDish] '{text}' stocked in the hardware store's NATIVE shop UI ({num2} added, {num3} already there) — the earned dish is on the shelf as well as in Dan's dialogue."); } else if (++_shopAttempts >= 24) { _shopStocked = true; Diag.Log("[DanDish] no soil-selling shop found — dish not stocked in the native shop UI this session (dialogue path unaffected)."); } } catch (Exception ex) { MelonLogger.Warning("[DanDish] shop stocking failed: " + ex.Message); } } private static void TryArm() { NPC val = null; try { val = NPCManager.GetNPC("dan_samwell"); if ((Object)(object)val == (Object)null) { Il2CppArrayBase val2 = Object.FindObjectsOfType(); for (int i = 0; i < val2.Length; i++) { NPC val3 = val2[i]; if (!((Object)(object)val3 == (Object)null)) { string text = ""; try { text = (val3.ID ?? "").ToLowerInvariant(); } catch { } if (text == "dan_samwell") { val = val3; break; } } } } } catch { } if ((Object)(object)val == (Object)null) { if (++_attempts >= 15) { _gaveUp = true; Diag.Log("[DanDish] NPC 'dan_samwell' not present in this world — feature skipped (not faked)."); } return; } DialogueController val4 = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInChildren(true); if ((Object)(object)val4 == (Object)null && (Object)(object)val.DialogueHandler != (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponent() ?? ((Component)val.DialogueHandler).GetComponentInChildren(true); } if ((Object)(object)val4 == (Object)null || val4.Choices == null) { _gaveUp = true; Diag.Log("[DanDish] Dan has no DialogueController — feature skipped."); return; } _dan = val; _controller = val4; DumpDanDialogue(); ScanIntroChoices(); DialogueHandler dialogueHandler = val.DialogueHandler; if ((Object)(object)dialogueHandler != (Object)null && !_hooked) { dialogueHandler.onDialogueChoiceChosen.AddListener(UnityAction.op_Implicit((Action)OnChoiceChosen)); _hooked = true; } if ((NeedsConfig.DanDishMode ?? "auto").Trim().ToLowerInvariant() == "auto" && SaveData.DanAnswer == 0) { ArmReask(); } if (EffectiveAnswer() != 0) { ArmMenu(); } _armed = true; Diag.Log($"[DanDish] armed on 'dan_samwell': answer={SaveData.DanAnswer} (0=unknown/1=denied/2=admitted), mode={NeedsConfig.DanDishMode}, introChoicesMapped={_introChoices.Count}, reask={_reaskChoice != null}, menu={_menuArmed}."); } private static void DumpDanDialogue() { if (_dumped || !NeedsConfig.VerboseConsume) { _dumped = true; return; } _dumped = true; try { Diag.Log("[DanDish] ===== DAN'S DIALOGUE ====="); foreach (DialogueContainer item in EnumerateDanContainers()) { DumpContainer(item); } Diag.Log("[DanDish] ===== END DAN'S DIALOGUE ====="); } catch (Exception ex) { Diag.Log("[DanDish] dialogue dump failed: " + ex.Message); } } private static IEnumerable EnumerateDanContainers() { HashSet seen = new HashSet(); List list = new List(); try { Add(_controller.GenericDialogue); } catch { } try { if (_controller.Choices != null) { for (int i = 0; i < _controller.Choices.Count; i++) { if (_controller.Choices[i] != null) { Add(_controller.Choices[i].Conversation); } } } } catch { } try { DialogueHandler val = (((Object)(object)_dan != (Object)null) ? _dan.DialogueHandler : null); List val2 = (((Object)(object)val != (Object)null) ? val.dialogueContainers : null); if (val2 != null) { for (int j = 0; j < val2.Count; j++) { Add(val2[j]); } } } catch { } return list; void Add(DialogueContainer c) { if ((Object)(object)c == (Object)null) { return; } try { if (seen.Add(((Il2CppObjectBase)c).Pointer)) { list.Add(c); } } catch { } } } private static void DumpContainer(DialogueContainer c) { try { if ((Object)(object)c == (Object)null || c.DialogueNodeData == null) { return; } Diag.Log($"[DanDish] container '{((Object)c).name}': {c.DialogueNodeData.Count} node(s), {((c.NodeLinks != null) ? c.NodeLinks.Count : 0)} link(s)"); Il2CppArrayBase val = c.DialogueNodeData.ToArray(); for (int i = 0; i < val.Length; i++) { DialogueNodeData val2 = val[i]; if (val2 == null) { continue; } int num = ((val2.choices != null) ? ((Il2CppArrayBase)(object)val2.choices).Length : 0); Diag.Log($"[DanDish] node[{i}] label='{val2.DialogueNodeLabel}' text='{Trunc(val2.DialogueText)}' choices={num}"); for (int j = 0; j < num; j++) { DialogueChoiceData val3 = ((Il2CppArrayBase)(object)val2.choices)[j]; if (val3 != null) { Diag.Log($"[DanDish] choice '{Trunc(val3.ChoiceText)}' label='{val3.ChoiceLabel}' guid='{val3.Guid}'"); } } } } catch (Exception ex) { Diag.Log("[DanDish] container dump failed: " + ex.Message); } } private static void ScanIntroChoices() { try { foreach (DialogueContainer item in EnumerateDanContainers()) { if ((Object)(object)item == (Object)null || item.DialogueNodeData == null) { continue; } Il2CppArrayBase val = item.DialogueNodeData.ToArray(); for (int i = 0; i < val.Length; i++) { DialogueNodeData val2 = val[i]; if (val2 == null || val2.choices == null || ((Il2CppArrayBase)(object)val2.choices).Length < 2) { continue; } bool flag = false; for (int j = 0; j < ((Il2CppArrayBase)(object)val2.choices).Length; j++) { DialogueChoiceData val3 = ((Il2CppArrayBase)(object)val2.choices)[j]; if (((val3 != null) ? (val3.ChoiceText ?? "").ToLowerInvariant() : "").Contains("drug")) { flag = true; break; } } if (!flag) { continue; } for (int k = 0; k < ((Il2CppArrayBase)(object)val2.choices).Length; k++) { DialogueChoiceData val4 = ((Il2CppArrayBase)(object)val2.choices)[k]; if (val4 != null) { bool value = (val4.ChoiceText ?? "").ToLowerInvariant().Contains("drug"); if (!string.IsNullOrEmpty(val4.ChoiceLabel)) { _introChoices[val4.ChoiceLabel] = value; } if (!string.IsNullOrEmpty(val4.Guid)) { _introChoices[val4.Guid] = value; } } } Diag.Log($"[DanDish] intro question found in '{((Object)item).name}' node[{i}] ('{Trunc(val2.DialogueText)}') — {((Il2CppArrayBase)(object)val2.choices).Length} answer(s) mapped."); } } if (_introChoices.Count == 0) { Diag.Log("[DanDish] no intro question node present on Dan (already played out, or labels stripped) — the re-ask covers it."); } } catch (Exception ex) { Diag.Log("[DanDish] intro scan failed: " + ex.Message); } } private static void ArmReask() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown if (_reaskChoice == null) { DialogueContainer val = ScriptableObject.CreateInstance(); ((Object)val).name = "S1HT_DanReask"; ((Object)val).hideFlags = (HideFlags)32; val.DialogueNodeData = new List(); val.NodeLinks = new List(); val.BranchNodeData = new List(); DialogueNodeData val2 = new DialogueNodeData(); val2.Guid = "S1HT_DAN_REASK_ENTRY"; val2.DialogueNodeLabel = TacoDiag.DiscoveredEntryLabel; val2.DialogueText = "Yeah? What about it?"; val2.choices = new Il2CppReferenceArray(3L); DialogueChoiceData val3 = new DialogueChoiceData(); val3.Guid = "S1HT_DAN_ADMIT"; val3.ChoiceLabel = "S1HT_DAN_ADMIT"; val3.ChoiceText = "Actually... I deal drugs."; DialogueChoiceData val4 = new DialogueChoiceData(); val4.Guid = "S1HT_DAN_DENY"; val4.ChoiceLabel = "S1HT_DAN_DENY"; val4.ChoiceText = "Tomatoes. Strictly tomatoes."; DialogueChoiceData val5 = new DialogueChoiceData(); val5.Guid = "S1HT_DAN_NVM"; val5.ChoiceLabel = "S1HT_DAN_NVM"; val5.ChoiceText = "Never mind."; ((Il2CppArrayBase)(object)val2.choices)[0] = val3; ((Il2CppArrayBase)(object)val2.choices)[1] = val4; ((Il2CppArrayBase)(object)val2.choices)[2] = val5; DialogueNodeData val6 = new DialogueNodeData(); val6.Guid = "S1HT_DAN_REASK_REPLY"; val6.DialogueNodeLabel = val6.Guid; val6.DialogueText = "Alright then."; val6.choices = new Il2CppReferenceArray(0L); val.DialogueNodeData.Add(val2); val.DialogueNodeData.Add(val6); string[] array = new string[3] { "S1HT_DAN_ADMIT", "S1HT_DAN_DENY", "S1HT_DAN_NVM" }; foreach (string baseChoiceOrOptionGUID in array) { NodeLinkData val7 = new NodeLinkData(); val7.BaseDialogueOrBranchNodeGuid = val2.Guid; val7.BaseChoiceOrOptionGUID = baseChoiceOrOptionGUID; val7.TargetNodeGuid = val6.Guid; val.NodeLinks.Add(val7); } _reaskConvo = val; _reaskReplyNode = val6; DialogueChoice val8 = new DialogueChoice(); val8.Enabled = true; val8.ChoiceText = "About what I'm growing..."; val8.ShowWorldspaceDialogue = false; val8.Conversation = val; val8.Priority = 0; val8.onChoosen = new UnityEvent(); try { _controller.AddDialogueChoice(val8, 0); } catch { _controller.Choices.Add(val8); } _reaskChoice = val8; RegisterContainer(val); Diag.Log("[DanDish] re-ask choice armed (this save predates the flag — the player tells Dan again)."); } } private static void CloseReask() { try { if (_reaskChoice != null) { _reaskChoice.Enabled = false; } } catch { } } private static void ArmMenu() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Expected O, but got Unknown //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Expected O, but got Unknown //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Expected O, but got Unknown bool flag = EffectiveAnswer() == 2; _menuDishId = (flag ? "danlasagna" : "danchili"); if (!EateryVendors.TryGetDef(_menuDishId, out var _)) { Diag.Log("[DanDish] '" + _menuDishId + "' not registered yet — menu waits."); return; } _menuEntryLines = (flag ? LasagnaEntryLines : ChiliEntryLines); DialogueContainer val = ScriptableObject.CreateInstance(); ((Object)val).name = "S1HT_DanLunch"; ((Object)val).hideFlags = (HideFlags)32; val.DialogueNodeData = new List(); val.NodeLinks = new List(); val.BranchNodeData = new List(); DialogueNodeData val2 = new DialogueNodeData(); val2.Guid = "S1HT_DAN_LUNCH_ENTRY"; val2.DialogueNodeLabel = TacoDiag.DiscoveredEntryLabel; val2.DialogueText = (EateryVendors.IsOpenNow(NeedsConfig.HoursHardware) ? Lines.Pick(_menuEntryLines) : Lines.Pick(ClosedLines)); val2.choices = new Il2CppReferenceArray(2L); float value = (flag ? NeedsConfig.DanLasagnaPrice : NeedsConfig.DanChiliPrice); DialogueChoiceData val3 = new DialogueChoiceData(); val3.Guid = "S1HT_DAN_BUY"; val3.ChoiceLabel = "S1HT_DAN_BUY"; val3.ChoiceText = (flag ? $"Dan's Homemade Pan Lasagna (${value:0})" : $"Dan's Homemade Chili (${value:0})"); DialogueChoiceData val4 = new DialogueChoiceData(); val4.Guid = "S1HT_DAN_BYE"; val4.ChoiceLabel = "S1HT_DAN_BYE"; val4.ChoiceText = "Nah, all good."; ((Il2CppArrayBase)(object)val2.choices)[0] = val3; ((Il2CppArrayBase)(object)val2.choices)[1] = val4; DialogueNodeData val5 = new DialogueNodeData(); val5.Guid = "S1HT_DAN_LUNCH_SOLD"; val5.DialogueNodeLabel = val5.Guid; val5.DialogueText = "There you go."; val5.choices = new Il2CppReferenceArray(0L); DialogueNodeData val6 = new DialogueNodeData(); val6.Guid = "S1HT_DAN_LUNCH_BYE"; val6.DialogueNodeLabel = val6.Guid; val6.DialogueText = "Suit yourself."; val6.choices = new Il2CppReferenceArray(0L); val.DialogueNodeData.Add(val2); val.DialogueNodeData.Add(val5); val.DialogueNodeData.Add(val6); NodeLinkData val7 = new NodeLinkData(); val7.BaseDialogueOrBranchNodeGuid = val2.Guid; val7.BaseChoiceOrOptionGUID = "S1HT_DAN_BUY"; val7.TargetNodeGuid = val5.Guid; val.NodeLinks.Add(val7); NodeLinkData val8 = new NodeLinkData(); val8.BaseDialogueOrBranchNodeGuid = val2.Guid; val8.BaseChoiceOrOptionGUID = "S1HT_DAN_BYE"; val8.TargetNodeGuid = val6.Guid; val.NodeLinks.Add(val8); DialogueChoice val9 = new DialogueChoice(); val9.Enabled = true; val9.ChoiceText = "Ask about lunch"; val9.ShowWorldspaceDialogue = false; val9.Conversation = val; val9.Priority = 0; val9.onChoosen = new UnityEvent(); try { _controller.AddDialogueChoice(val9, 0); } catch { _controller.Choices.Add(val9); } _menuConvo = val; _menuEntryNode = val2; _menuSoldNode = val5; RegisterContainer(val); _menuArmed = true; Diag.Log($"[DanDish] lunch menu armed: '{_menuDishId}' at ${value:0} ({(flag ? "admitted → lasagna" : "denied → chili")})."); } private static void RegisterContainer(DialogueContainer c) { try { DialogueHandler val = (((Object)(object)_dan != (Object)null) ? _dan.DialogueHandler : null); List val2 = (((Object)(object)val != (Object)null) ? val.dialogueContainers : null); if (val2 != null && !val2.Contains(c)) { val2.Add(c); } } catch { } } private static void OnChoiceChosen(string chosen) { try { if (string.IsNullOrEmpty(chosen)) { return; } if (NeedsConfig.VerboseConsume && !chosen.StartsWith("S1HT_")) { Diag.Log("[DanDish] Dan dialogue choice fired: '" + chosen + "'."); } switch (chosen) { case "S1HT_DAN_ADMIT": SetAnswer(2, "re-ask"); return; case "S1HT_DAN_DENY": SetAnswer(1, "re-ask"); return; case "S1HT_DAN_BUY": Buy(); return; } if (_introChoices.TryGetValue(chosen, out var value) && SaveData.DanAnswer == 0) { SetAnswer((!value) ? 1 : 2, "intro dialogue"); } } catch (Exception ex) { Diag.Log("[DanDish] choice handling failed: " + ex.Message); } } private static void SetAnswer(int value, string source) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) SaveData.DanAnswer = value; CloseReask(); if (_reaskReplyNode != null && source == "re-ask") { _reaskReplyNode.DialogueText = ((value == 2) ? Lines.Pick(new string[2] { "HA. Still committed to the bit. Alright, comedian. Ask me about lunch sometime.", "Ha. Same joke, still funny. Ask me about lunch sometime, comedian." }) : Lines.Pick(new string[2] { "Tomatoes, right. Well, everybody's gotta eat. Ask me about lunch sometime.", "Tomatoes. Good crop this year, I hear. Ask me about lunch sometime." })); } NeedsHud.Toast((value == 2) ? "Dan thinks you're hilarious. Noted." : "Tomatoes it is.", NeedsHud.ToastNeutral); Diag.Log($"[DanDish] answer recorded via {source}: {((value == 2) ? "ADMITTED → lasagna" : "DENIED → chili")} (persists on next game save)."); } private static void Buy() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) try { bool flag = EffectiveAnswer() == 2; string text = _menuDishId ?? (flag ? "danlasagna" : "danchili"); if (!EateryVendors.TryGetDef(text, out var def) || (Object)(object)def == (Object)null) { Diag.Log("[DanDish] '" + text + "' has no definition — sale aborted."); return; } if (!EateryVendors.IsOpenNow(NeedsConfig.HoursHardware)) { if (_menuSoldNode != null) { _menuSoldNode.DialogueText = Lines.Pick(ClosedLines); } NeedsHud.Toast("Shut. Come back when they're open.", NeedsHud.ToastNeutral); Diag.Log("[DanDish] sale blocked — closed (hours " + NeedsConfig.HoursHardware + ")."); return; } float num = (flag ? NeedsConfig.DanLasagnaPrice : NeedsConfig.DanChiliPrice); MoneyManager instance = NetworkSingleton.Instance; PlayerInventory instance2 = PlayerSingleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return; } if (instance.cashBalance < num) { if (_menuSoldNode != null) { _menuSoldNode.DialogueText = (flag ? Lines.Pick(LasagnaBrokeLines) : Lines.Pick(ChiliBrokeLines)); } NeedsHud.Toast($"That's ${num:0} cash. You haven't got it.", NeedsHud.ToastNeutral); return; } instance.ChangeCashBalance(0f - num, true, true); if (_menuSoldNode != null) { _menuSoldNode.DialogueText = (flag ? Lines.Pick(LasagnaSoldLines) : Lines.Pick(ChiliSoldLines)); } instance2.AddItemToInventory(((ItemDefinition)def).GetDefaultInstance(1)); NeedsHud.Toast(flag ? Lines.Pick(LasagnaBoughtToasts) : Lines.Pick(ChiliBoughtToasts), NeedsHud.ToastGood); Diag.Log($"[DanDish] '{text}' sold for ${num:0}."); } catch (Exception ex) { Diag.Log("[DanDish] purchase failed: " + ex.Message); } } private static string Trunc(string s) { if (!string.IsNullOrEmpty(s)) { if (s.Length <= 48) { return s; } return s.Substring(0, 48) + "…"; } return ""; } } public static class Diag { private static readonly object _lock = new object(); private static bool _headerWritten; private static string PathFile => Path.Combine(MelonEnvironment.UserDataDirectory, "S1HungerThirst", "diag.txt"); public static void Log(string message) { try { MelonLogger.Msg(message); } catch { } try { lock (_lock) { string pathFile = PathFile; Directory.CreateDirectory(Path.GetDirectoryName(pathFile)); if (!_headerWritten) { _headerWritten = true; try { FileInfo fileInfo = new FileInfo(pathFile); if (fileInfo.Exists && fileInfo.Length > 262144) { File.Delete(pathFile); } } catch { } File.AppendAllText(pathFile, $"{Environment.NewLine}===== session {DateTime.Now:yyyy-MM-dd HH:mm:ss} ====={Environment.NewLine}"); } File.AppendAllText(pathFile, $"[{DateTime.Now:HH:mm:ss.fff}] {message}{Environment.NewLine}"); } } catch { } } } public static class DrugEffects { private static readonly string[] CrashLines = new string[3] { "There's the come-down. Wonderful.", "And there it goes. The crash tax.", "The loan came due. Paid in energy." }; private static readonly string[] ComedownLines = new string[3] { "Coming down. Appetite's back to normal.", "Levelling out. Back to plain old hungry.", "That's the high gone. Business as usual." }; private static readonly Dictionary _effectRates = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _drugTypeRates = new Dictionary(StringComparer.OrdinalIgnoreCase); private static IntPtr _lastProductPtr = IntPtr.Zero; private static bool _munchiesActive; public static float HungerMult { get; private set; } = 1f; public static float ThirstMult { get; private set; } = 1f; public static float EnergyMult { get; private set; } = 1f; public static bool HungerFaster => HungerMult > 1.15f; public static bool HungerSlower => HungerMult < 0.85f; public static bool ThirstFaster => ThirstMult > 1.15f; public static bool ThirstSlower => ThirstMult < 0.85f; public static bool EnergyFaster => EnergyMult > 1.15f; public static bool EnergySlower => EnergyMult < 0.85f; public static bool StrongStimActive => EnergyMult <= NeedsConfig.StimStrongThreshold; public static void ParseConfigMaps() { ParseInto(_effectRates, NeedsConfig.EffectRatesRaw); ParseInto(_drugTypeRates, NeedsConfig.DrugTypeRatesRaw); _lastProductPtr = IntPtr.Zero; } private static void ParseInto(Dictionary map, string raw) { map.Clear(); string[] array = (raw ?? "").Split(';', StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split('=', 2); if (array2.Length == 2) { string[] array3 = array2[1].Split('/', 3); float hunger = NeedsConfig.ParseF(array3[0].Trim(), 1f); float thirst = ((array3.Length > 1) ? NeedsConfig.ParseF(array3[1].Trim(), 1f) : 1f); float energy = ((array3.Length > 2) ? NeedsConfig.ParseF(array3[2].Trim(), 1f) : 1f); map[Normalize(array2[0])] = new Restore(hunger, thirst, energy); } } } private static string Normalize(string s) { return Regex.Replace(s ?? "", "[^A-Za-z0-9]", "").ToLowerInvariant(); } public static void Reset() { HungerMult = (ThirstMult = (EnergyMult = 1f)); _lastProductPtr = IntPtr.Zero; _munchiesActive = false; } public static void Tick() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) if (!NeedsConfig.DrugEffectsEnabled) { if (HungerMult != 1f || ThirstMult != 1f) { Reset(); } return; } Player local = Player.Local; ProductItemInstance val = (((Object)(object)local != (Object)null) ? local.ConsumedProduct : null); if (val == null) { if (_lastProductPtr != IntPtr.Zero) { bool num = NeedsConfig.EnergyEnabled && NeedsConfig.StimCrashEnabled && StrongStimActive; Reset(); if (num) { NeedsState.DrainEnergy(NeedsConfig.StimCrashCost); NeedsHud.Toast(Lines.Pick(CrashLines), NeedsHud.ToastBad); } else { NeedsHud.Toast(Lines.Pick(ComedownLines), NeedsHud.ToastNeutral); } } } else { if (((Il2CppObjectBase)val).Pointer == _lastProductPtr) { return; } _lastProductPtr = ((Il2CppObjectBase)val).Pointer; float num2 = 0f; float num3 = 0f; float num4 = 0f; bool munchiesActive = false; List list = new List(6); try { ProductDefinition val2 = (((Object)(object)((ItemInstance)val).Definition != (Object)null) ? ((Il2CppObjectBase)((ItemInstance)val).Definition).TryCast() : null); if ((Object)(object)val2 != (Object)null) { if (!(((BaseItemDefinition)val2).ID ?? "").StartsWith("s1ht_fx_", StringComparison.OrdinalIgnoreCase) && _drugTypeRates.TryGetValue(Normalize(((object)val2.DrugType/*cast due to .constrained prefix*/).ToString()), out var value)) { num2 += value.Hunger - 1f; num3 += value.Thirst - 1f; num4 += value.Energy - 1f; string text = Phrase(value); if (text != null) { list.Add($"{val2.DrugType}... {text}"); } } Il2CppArrayBase val3 = ((((PropertyItemDefinition)val2).Properties != null) ? ((PropertyItemDefinition)val2).Properties.ToArray() : null); if (val3 != null) { for (int i = 0; i < val3.Length; i++) { Effect val4 = val3[i]; if ((Object)(object)val4 == (Object)null || !TryMatch(val4, out var rate)) { continue; } num2 += rate.Hunger - 1f; num3 += rate.Thirst - 1f; num4 += rate.Energy - 1f; int num5; if (!(Normalize(((MemberInfo)((Object)val4).GetIl2CppType()).Name) == "munchies")) { num5 = ((Normalize(val4.ID) == "munchies") ? 1 : 0); if (num5 == 0) { goto IL_0289; } } else { num5 = 1; } munchiesActive = true; goto IL_0289; IL_0289: string text2 = ((num5 != 0) ? "munchies just kicked in. Hard." : Phrase(rate)); if (text2 != null) { string text3 = ((!string.IsNullOrEmpty(val4.Name)) ? val4.Name : ((MemberInfo)((Object)val4).GetIl2CppType()).Name); list.Add(text3 + "... " + text2); } } } } } catch (Exception ex) { MelonLogger.Warning("[Drugs] Could not read product effects: " + ex.Message); } HungerMult = Mathf.Clamp(1f + num2, NeedsConfig.DrugMinMult, NeedsConfig.DrugMaxMult); ThirstMult = Mathf.Clamp(1f + num3, NeedsConfig.DrugMinMult, NeedsConfig.DrugMaxMult); EnergyMult = (NeedsConfig.EnergyEnabled ? Mathf.Clamp(1f + num4, 0.1f, NeedsConfig.DrugMaxMult) : 1f); _munchiesActive = munchiesActive; if (NeedsConfig.EnergyEnabled && NeedsConfig.StimKickEnergy > 0f) { if (EnergyMult <= NeedsConfig.StimStrongThreshold) { NeedsState.Replenish(0f, 0f, NeedsConfig.StimKickEnergy); list.Add("Good gear. Wide awake now."); } else if (EnergyMult < NeedsConfig.StimMildThreshold) { NeedsState.Replenish(0f, 0f, NeedsConfig.StimKickEnergy * NeedsConfig.StimKickMildFactor); list.Add("Bit of a buzz."); } } int num6 = 0; foreach (string item in list) { if (num6++ >= 5) { NeedsHud.Toast("...plus a few more", NeedsHud.ToastWarn); break; } NeedsHud.Toast(item, NeedsHud.ToastWarn); } } } private static string Phrase(Restore r) { float num = r.Hunger - 1f; float num2 = r.Thirst - 1f; float num3 = (NeedsConfig.EnergyEnabled ? (r.Energy - 1f) : 0f); float num4 = Mathf.Abs(num); float num5 = Mathf.Abs(num2); float num6 = Mathf.Abs(num3); if (num4 < 0.1f && num5 < 0.1f && num6 < 0.1f) { return null; } if (num4 >= num5 && num4 >= num6) { if (!(num > 0f)) { return "not hungry at all now"; } return "making you hungry, fast"; } if (num5 >= num6) { if (!(num2 > 0f)) { return "keeping the thirst away"; } return "drying you right out"; } if (!(num3 > 0f)) { return "keeping you wide awake"; } return "making you sleepy"; } private static bool TryMatch(Effect fx, out Restore rate) { if (_effectRates.TryGetValue(Normalize(((MemberInfo)((Object)fx).GetIl2CppType()).Name), out rate)) { return true; } if (_effectRates.TryGetValue(Normalize(fx.ID), out rate)) { return true; } if (_effectRates.TryGetValue(Normalize(fx.Name), out rate)) { return true; } return false; } } public static class EateryVendors { internal enum MeshKind { Roll, Cup, Folded, Slab, Native, Bowl, BruleeBowl, Mug, GlassTall, GlassShort, Bottle, Can, NoodleCup, StrawCup, Croissant, PastryDisc, Sandwich, Slice, Bun, FilledBun, Hotdog, TakeoutBox, Carton, Brownie, PlateSteak, Chicken, Fish, Tray } private sealed class Item { public string Id; public string Name; public string Desc; public string[] SoldLines; public float Price; public MeshKind Kind; public Taco3D.FillingLook Look; } private sealed class Vendor { public string Key; public string Establishment; public string NpcId; public string FirstName; public string MenuChoice; public string[] EntryLines; public string[] ByeLines; public string[] BrokeLines; public string[] ClosedLines; public Item[] Items; public Func Enabled; public Func Hours; public bool Armed; public bool GaveUp; public bool Hooked; public float NextAttempt; public int Attempts; public DialogueContainer Convo; public DialogueNodeData SoldNode; public DialogueNodeData EntryNode; public DialogueNodeData ByeNode; } private static readonly Vendor[] Vendors; private static readonly string[] GasMartItems; private static readonly Item[] ShopOnlyItems; private static readonly Item[] DanDishItems; private const string BuyPrefix = "S1HT_EAT_BUY_"; private static readonly Dictionary _defs; private static readonly Dictionary _items; private static bool _gasMartStocked; private static float _nextGasMartAttempt; private static int _gasMartAttempts; private static float _nextHoursRefresh; private static readonly string[] PaidToasts; private static readonly string[] FreeToasts; private static readonly string[] ClosedToasts; private static readonly Dictionary _icons; private static string[] S(params string[] lines) { return lines; } private static Item I(string id, string name, string desc, string[] sold, float price, MeshKind kind, Taco3D.FillingLook look) { return new Item { Id = id, Name = name, Desc = desc, SoldLines = sold, Price = price, Kind = kind, Look = look }; } static EateryVendors() { Vendors = new Vendor[12] { new Vendor { Key = "Diner", Establishment = "the Slop Shop", NpcId = "peggy_myers", FirstName = "peggy", MenuChoice = "Ask what's cooking", EntryLines = S("Kitchen's open, hon. Coffee's $5, breakfast roll's $14, and there's always the Slop.", "Grab a stool, hon. Coffee's $5, roll's $14, Slop's $12.", "Rush is over, so you've got my full attention. What'll it be, hon?"), ByeLines = S("Suit yourself, hon.", "You know where the stools are.", "Alright, hon. Door's always open."), BrokeLines = S("Come back with money, sweetheart.", "This ain't a tab kind of place, hon.", "Wash some dishes or find some dollars, sweetheart."), ClosedLines = S("Kitchen's closed, hon. Grill's back on before eleven.", "We're dark, hon. Come back when the grill's hot.", "Closed up. Even the Slop needs its rest."), Hours = () => NeedsConfig.HoursDiner, Enabled = () => NeedsConfig.VendorDiner, Items = new Item[3] { I("dinercoffee", "Bottomless Coffee", "The bottom is a lie, it's one cup.", S("Fresh pot. Mind the mug.", "There's your coffee, hon. It's strong today.", "Bottomless, within reason."), 5f, MeshKind.Mug, Taco3D.MugCoffeeLook), I("brekkieroll", "Big Breakfast Roll", "Egg, bacon, the works. Rolled.", S("There you go, hon. Eat it while it's hot.", "Roll's heavy today. Good luck.", "Egg, bacon, the works. Go on."), 14f, MeshKind.FilledBun, Taco3D.EggRollLook), I("theslop", "The Slop", "House special. Served in a bowl. Don't ask.", S("One Slop. You're braver than most, hon.", "The Slop. Don't stir it too hard.", "There's the Slop, hon. It grows on you."), 12f, MeshKind.Bowl, Taco3D.SlopBowlLook) } }, new Vendor { Key = "Community", Establishment = "the Community Center", NpcId = "doris_lubbin", FirstName = "doris", MenuChoice = "Ask about the bake sale", EntryLines = S("Urn's hot and the bake sale's out, dear. It's all cheap.", "Come in, dear. Urn's just boiled and Carol dropped off a new batch.", "Hello, dear. Everything on the table's a dollar or three."), ByeLines = S("Take care now.", "Mind how you go, dear.", "See you at the next sale, dear."), BrokeLines = S("It's only a couple of dollars, dear.", "Oh, don't be embarrassed, dear. Come back later.", "The honour box can wait a day, dear."), ClosedLines = S("Hall's locked up till morning, dear.", "We're all packed up for the night, dear.", "Come back after breakfast, dear. The urn takes a while."), Hours = () => NeedsConfig.HoursCommunity, Enabled = () => NeedsConfig.VendorCommunity, Items = new Item[3] { I("urncoffee", "Urn Coffee", "Sixty-cup percolator. Honour box.", S("There you go, dear.", "Milk and sugar's on the end, dear.", "Careful, the urn runs hot."), 2f, MeshKind.Cup, Taco3D.CoffeeLook), I("bakebrownie", "Bake Sale Brownie", "Someone's mum made these.", S("That's Carol's batch. The good batch.", "Last tray of those went in minutes, dear.", "Carol will be thrilled, dear."), 3f, MeshKind.Brownie, Taco3D.BrownieLook), I("tunasando", "Tuna Sandwich", "Cling-filmed, on a paper plate.", S("Made fresh this morning, dear.", "The cling film keeps it honest, dear.", "There's your sandwich, dear. Napkin's underneath."), 5f, MeshKind.Sandwich, Taco3D.TunaSandwichLook) } }, new Vendor { Key = "Supermarket", Establishment = "the Supermarket", NpcId = "george_greene", FirstName = "george", MenuChoice = "Ask about the hot counter", EntryLines = S("Hot counter's fresh. Chicken's $13, sandwiches made to order.", "Hot counter just rotated, pal. Chicken's looking great.", "Hey, good timing. Counter's full and the chicken's fresh out."), ByeLines = S("Right on.", "No worries, pal.", "Catch you round the aisles."), BrokeLines = S("Ah, you're a little short there, pal.", "Few bucks shy, pal. It happens.", "Register says no, pal. Sorry."), ClosedLines = S("Counter's shut for the night, pal. We open bright and early.", "Hot counter's cold, pal. Tomorrow's chicken awaits.", "We're closed up. The chicken sleeps, I sleep."), Hours = () => NeedsConfig.HoursSupermarket, Enabled = () => NeedsConfig.VendorSupermarket, Items = new Item[3] { I("rotisserie", "Rotisserie Chicken", "Hot counter. Best value in town.", S("Good choice. I'd get the chicken too.", "That's the freshest bird on the counter.", "Chicken's still warm, pal. Enjoy."), 13f, MeshKind.Chicken, Taco3D.RoastChickenLook), I("delisando", "Deli Sandwich", "Made to order, wrapped tight.", S("There you are. Napkins are on the end.", "Made that one myself, actually.", "Wrapped tight, pal. Travels well."), 9f, MeshKind.Sandwich, Taco3D.SandwichLook), I("instantramen", "Instant Ramen Cup", "The staple. Just add anything.", S("Kettle's aisle four if you're desperate.", "The staple. No shame in it, pal.", "One ramen. Dinner of champions."), 7f, MeshKind.NoodleCup, Taco3D.RamenLook) } }, new Vendor { Key = "Liquor", Establishment = "the Liquor Store", NpcId = "kim_delaney", FirstName = "kim", MenuChoice = "Ask what's cold", EntryLines = S("Cold case is stocked. The fancy stuff's behind me.", "Cold case's full. Fancy shelf's dusted. What d'you need?", "Evening. Cold stuff's cold, the good stuff's behind me."), ByeLines = S("See ya.", "Later.", "Yep."), BrokeLines = S("Can't float you. Sorry.", "No cash, no bottle.", "Cash first. Store policy, my policy, same thing."), ClosedLines = S("We're closed. Nine to nine, that's the deal.", "Shutters are down. Come back at nine.", "Closed. The bottles aren't going anywhere."), Hours = () => NeedsConfig.HoursLiquor, Enabled = () => NeedsConfig.VendorLiquor, Items = new Item[4] { I("tallboy", "Tallboy", "Cold case, paper bag included.", S("There you go. Bag's included.", "One tallboy. Stay classy.", "Cold as advertised."), 5f, MeshKind.Can, Taco3D.TallboyLook), I("boxedwine", "Boxed Wine", "Silver bag. Four servings, allegedly.", S("It's better than it looks. Slightly.", "Four servings, allegedly. Enjoy.", "The silver bag never lies. Except about servings."), 18f, MeshKind.Carton, Taco3D.WineCartonLook), I("chateaulapeepee", "Château La Peepee", null, S("Ah, a person of taste. That's the good shelf.", "The La Peepee. Someone raised you right.", "Careful with that one. It's actually decent."), 40f, MeshKind.Native, default(Taco3D.FillingLook)), I("brutdugloop", "Brut du Gloop", null, S("The Gloop. Big night, huh.", "Brut du Gloop. Bold.", "That one drinks fancier than it sounds."), 55f, MeshKind.Native, default(Taco3D.FillingLook)) } }, new Vendor { Key = "Cafe", Establishment = "The Butter Box", NpcId = "lily_turner", FirstName = "lily", MenuChoice = "Ask about the pastries", EntryLines = S("Croissants are fresh. The flat white is correct and I won't be changing it.", "Beans came in this morning. The flat white is correct, as always.", "Morning. Pastries are Jackie's, coffee's mine, standards are high."), ByeLines = S("Okay then.", "Mm.", "Enjoy your day, I suppose."), BrokeLines = S("It's $6. The beans cost more than that.", "No. The machine doesn't run on promises.", "Come back funded."), ClosedLines = S("We closed at four-thirty. The machine is off and it stays off.", "Closed. Espresso has hours, and so do I.", "The sign says closed. The sign is correct."), Hours = () => NeedsConfig.HoursCafe, Enabled = () => NeedsConfig.VendorCafe, Items = new Item[3] { I("croissant", "Butter Croissant", "Flaky. Sheds everywhere.", S("Good pick. Jackie boxed that one.", "Flaky. You'll be wearing some of it.", "That one's from the morning bake. You got lucky."), 8f, MeshKind.Croissant, Taco3D.PastryLook), I("flatwhite", "Flat White", "Properly made. She checks.", S("Enjoy. It's made properly.", "Correct temperature, correct ratio. Enjoy.", "There. That's what coffee's supposed to taste like."), 6f, MeshKind.Mug, Taco3D.MugCoffeeLook), I("almonddanish", "Almond Danish", "Behind glass. Tonged.", S("The danish outsells everything. Deserved.", "Jackie's almond danish. She counts them, so savor it.", "Behind glass for a reason. Enjoy."), 7f, MeshKind.PastryDisc, Taco3D.PastryLook) } }, new Vendor { Key = "Pizzeria", Establishment = "Sauerkraut Supreme", NpcId = "ludwig_meyer", FirstName = "ludwig", MenuChoice = "Ask about the pizza", EntryLines = S("Fresh out of the oven. Kraut slice is $8, the weissbier is proper.", "Ah, hunger. Good. The oven is hot and the kraut is ready.", "Welcome, friend. Fresh pies, proper mustard, cold weissbier."), ByeLines = S("Come back hungry.", "Auf wiedersehen, friend.", "The oven will wait for you."), BrokeLines = S("No money, no pie, friend.", "The kraut is not free, friend.", "Come back when the wallet is heavier."), ClosedLines = S("Oven's cold, friend. Come back tomorrow.", "Closed, friend. Even the oven rests.", "The dough is sleeping. Tomorrow."), Hours = () => NeedsConfig.HoursPizzeria, Enabled = () => NeedsConfig.VendorPizzeria, Items = new Item[3] { I("krautslice", "Sauerkraut Supreme Slice", "Kraut. Bratwurst. Mustard swirl.", S("Good, good. The kraut is the secret.", "One slice. The mustard swirl is intentional.", "Eat it hot, friend. Cold kraut is a tragedy."), 8f, MeshKind.Slice, Taco3D.PizzaSliceLook), I("pretzelbrat", "Bratwurst Pretzel Roll", "Sausage in a pretzel bun, brown mustard.", S("Careful, the mustard has opinions.", "Bratwurst, pretzel, mustard. All friends here.", "There, friend. Two hands for that one."), 13f, MeshKind.Hotdog, Taco3D.BratLook), I("weissbier", "Weissbier", "Half litre. Correct glass.", S("Slow. It is not a race.", "Proper glass, proper pour. Prost.", "The weissbier. Correct choice, friend."), 9f, MeshKind.GlassTall, Taco3D.BeerGlassLook) } }, new Vendor { Key = "Chinese", Establishment = "the Chinese restaurant", NpcId = "ming", FirstName = "ming", MenuChoice = "Order some food", EntryLines = S("Counter's open. Pork bun's $5, the chicken plate's $19, tea's $3.", "Counter's open. Say your order.", "You again. Good. What do you want?"), ByeLines = S("Okay.", "Next time.", "Mm."), BrokeLines = S("Cash first. Come back.", "No money? No food. Simple.", "Counter takes cash. Door takes you out."), ClosedLines = S("Closed. Come back.", "Not open. Later.", "Kitchen resting. Come back soon."), Hours = () => NeedsConfig.HoursChinese, Enabled = () => NeedsConfig.VendorChinese, Items = new Item[3] { I("porkbun", "Pork Bun", "Steamed, from the counter basket.", S("There you go. It's hot.", "One bun. Steamed today.", "Good bun. Eat now, not later."), 5f, MeshKind.Bun, Taco3D.SteamedBunLook), I("mingchicken", "General Ming's Chicken", "Sweet, sticky, boxed.", S("Good order. Everyone gets that one.", "General Ming's. The General approves.", "Box is hot. Hold the bottom."), 19f, MeshKind.TakeoutBox, Taco3D.TakeoutLook), I("jasminetea", "Jasmine Tea", "Pot for one.", S("Careful, the pot's hotter than the tea.", "Tea. Sit if you want.", "Jasmine. Good for you. Probably."), 3f, MeshKind.Mug, Taco3D.MugTeaLook) } }, new Vendor { Key = "French", Establishment = "Les Ordures Puantes", NpcId = "louis_fourier", FirstName = "louis", MenuChoice = "Ask for a table", EntryLines = S("Ah. You are... hungry, yes? The soup is $26. The steak, $72. Try to deserve it.", "Ah. You have returned. The kitchen will cope.", "Bonsoir. The soup is exceptional tonight. The rest is merely excellent."), ByeLines = S("As expected.", "Naturally.", "The door is where you left it."), BrokeLines = S("Non. Come back with money.", "This establishment does not do credit. Non.", "Your ambition exceeds your wallet. Come back."), ClosedLines = S("Service begins at five-forty. You may wait outside.", "The kitchen is closed. Anticipation improves the palate.", "We are closed. Hunger will teach you punctuality."), Hours = () => NeedsConfig.HoursFrench, Enabled = () => NeedsConfig.VendorFrench, Items = new Item[3] { I("onionsoup", "Soupe à l'Oignon", "Gruyère raft. Scalding.", S("Bon. Do not rush it.", "The gruyère is still molten. Patience.", "The soup. Treat it with respect."), 26f, MeshKind.Bowl, Taco3D.OnionSoupLook), I("steakfrites", "Steak Frites", "Correct. Unimprovable.", S("Medium rare. I did not ask because there is no other answer.", "The steak requires no sauce, and you will not ask for any.", "Voilà. Do not insult it with ketchup."), 72f, MeshKind.PlateSteak, Taco3D.SteakPlateLook), I("cremebrulee", "Crème Brûlée", "Cracked tableside.", S("The crack was adequate. Enjoy.", "Tableside, as promised. The spoon goes through the middle.", "The brûlée. A civilized ending."), 24f, MeshKind.BruleeBowl, Taco3D.BruleeLook) } }, new Vendor { Key = "Canary", Establishment = "The Crimson Canary", NpcId = "carl_bundy", FirstName = "carl", MenuChoice = "Order at the bar", EntryLines = S("Bar's open. Vodka soda's sixteen, the Canary's twenty-six.", "What are you drinking?", "Bar's stocked. Music's loud. Go."), ByeLines = S("Later.", "Sure.", "Door's that way."), BrokeLines = S("This isn't a charity bar, man.", "Card-declined energy. Come back with cash.", "No cash, no pour."), ClosedLines = S("Bar opens at five. It's not five.", "We're dark till five, man.", "Come back when the neon's on."), Hours = () => NeedsConfig.HoursCanary, Enabled = () => NeedsConfig.VendorCanary, Items = new Item[3] { I("vodkasoda", "Vodka Soda", "The default.", S("Easy one. Smart.", "Vodka soda. Can't mess it up, didn't.", "There. Hydrating, technically."), 16f, MeshKind.GlassShort, Taco3D.VodkaGlassLook), I("canarycocktail", "Canary Cocktail", "Red. Smoking. House signature.", S("Careful with that one.", "House special. Pace yourself.", "The Canary. It bites back."), 26f, MeshKind.GlassShort, Taco3D.CanaryGlassLook), I("coatespresso", "Coat-Check Espresso", "From the staff pot. 3 AM fuel.", S("Don't tell the day shift.", "Staff pot. You didn't get it from me.", "Espresso at this hour. Respect."), 6f, MeshKind.Mug, Taco3D.MugCoffeeLook) } }, new Vendor { Key = "Motel", Establishment = "the Motel Office", NpcId = "donna_martin", FirstName = "donna", MenuChoice = "Ask about the lobby coffee", EntryLines = S("Coffee's two bucks, hon. Sandwich machine works most days.", "Evenin', hon. Coffee's fresh-ish. Machine's in a mood but workin'.", "Hey hon. Pot's on. Machine took my dollar again, but it works."), ByeLines = S("Night.", "Sleep well, hon.", "Holler if you need the kettle."), BrokeLines = S("It's two dollars, sweetie.", "Two bucks, hon. Check the couch cushions.", "Sweetie, it's the cheapest thing in town."), ClosedLines = S("Office is closed, hon.", "Office light's off, hon. Try morning.", "Closed up, sweetie. The bell won't help."), Hours = () => NeedsConfig.HoursMotel, Enabled = () => NeedsConfig.VendorMotel, Items = new Item[3] { I("lobbycoffee", "Lobby Coffee", "Burnt carafe, styrofoam cup.", S("There's creamer somewhere. Probably.", "Carafe's been on a while. Character, I call it.", "Fresh enough, hon. Careful, it's hot."), 2f, MeshKind.Cup, Taco3D.CoffeeLook), I("vendingsando", "Vending Sandwich", "Triangle. Plastic. Refrigerated since Tuesday.", S("The machine only ate one dollar this week.", "B4. The good slot, hon.", "Triangle sandwich. It's honest work."), 7f, MeshKind.Sandwich, Taco3D.SandwichLook), I("noodlecup", "Instant Noodle Cup", "Donna will lend you the kettle.", S("Kettle's by the window, hon.", "Noodles. Add the sachet last, trust me.", "There you go, hon. Kettle takes a minute."), 5f, MeshKind.NoodleCup, Taco3D.RamenLook) } }, new Vendor { Key = "Bait", Establishment = "Randy's Bait & Tackle", NpcId = "randy_caulfield", FirstName = "randy", MenuChoice = "Ask what's fresh", EntryLines = S("Coffee's hot, fish is smoked. What d'you need?", "Yeah? Coffee's on. Fish is fresh smoked.", "Early or late, same shop. What d'you need?"), ByeLines = S("Right.", "Yep.", "Tide won't wait, and neither do I."), BrokeLines = S("Short again? Figures.", "No coin, no fish.", "Come back when you've sold somethin'."), ClosedLines = S("Closed till four. Even I gotta sleep sometime.", "Shop's shut. Fish are safe for now.", "Come back at four. The good stuff lands then."), Hours = () => NeedsConfig.HoursBait, Enabled = () => NeedsConfig.VendorBait, Items = new Item[3] { I("thermoscoffee", "Thermos Coffee", "Four AM. Black.", S("There y'are.", "Black. Like coffee's meant to be.", "Thermos pour. Best kind."), 2f, MeshKind.Cup, Taco3D.CoffeeLook), I("smokedfish", "Smoked Fish", "Vacuum pack, off the counter.", S("Watch the bones.", "Smoked it Tuesday. Perfect by now.", "Good pick. That one fought hard."), 9f, MeshKind.Fish, Taco3D.SmokedFishLook), I("fishnchips", "Fish & Chips", "Fried at the back, wrapped in paper.", S("Salt's on the counter. Go easy.", "Wrapped in yesterday's news. Tradition.", "Fresh out the fryer. Mind your fingers."), 14f, MeshKind.Tray, Taco3D.FishChipsLook) } }, new Vendor { Key = "Church", Establishment = "the church hall", NpcId = "pearl_moore", FirstName = "pearl", MenuChoice = "Ask about the food bank", EntryLines = S("Everyone eats here, dear. There's coffee, and soup at five. No charge.", "Come in, dear. There's always a bowl and a chair for you.", "Hello, dear. The urn's hot and the soup's nearly on."), ByeLines = S("Take care, dear.", "Go gently, dear.", "The door's never locked long, dear."), BrokeLines = S("It's free, dear.", "Put your money away, dear.", "Your money's no good here, dear."), ClosedLines = S("Hall's locked for the night, dear. Morning's not far.", "The hall's resting, dear. Come back with the sun.", "We open with the morning bells, dear."), Hours = () => NeedsConfig.HoursChurch, Enabled = () => NeedsConfig.VendorChurch, Items = new Item[2] { I("churchcoffee", "Coffee & a Biscuit", "After the service, in the hall.", S("Bless you. Eat up.", "There's your coffee, dear. Biscuit's under the napkin.", "Warm yourself up, dear."), 0f, MeshKind.Cup, Taco3D.CoffeeLook), I("soupbowl", "Soup Kitchen Bowl", "Served with bread. No questions.", S("There's seconds if you need them, dear.", "Fresh bread on the side, dear. Go on.", "Sit and eat, dear. No hurry at all."), 0f, MeshKind.Bowl, Taco3D.SoupBowlLook) } } }; GasMartItems = new string[3] { "sausageroll", "slushee", "bottledwater" }; ShopOnlyItems = new Item[3] { I("sausageroll", "Servo Sausage Roll", "Been under the heat lamp a while.", null, 9f, MeshKind.Roll, Taco3D.SausageRollLook), I("slushee", "Blue Slushee", "Blue flavor. Just blue.", null, 6f, MeshKind.StrawCup, Taco3D.SlusheeCupLook), I("bottledwater", "Bottled Water", "The boring correct answer.", null, 2f, MeshKind.Bottle, Taco3D.WaterBottleLook) }; DanDishItems = new Item[2] { I("danchili", "Dan's Homemade Chili", "From the crockpot in the back room.", null, 11f, MeshKind.Bowl, Taco3D.DanChiliBowlLook), I("danlasagna", "Dan's Homemade Pan Lasagna", "Corner piece. He doesn't do this for everyone.", null, 16f, MeshKind.Slab, Taco3D.LasagnaLook) }; _defs = new Dictionary(StringComparer.OrdinalIgnoreCase); _items = new Dictionary(StringComparer.OrdinalIgnoreCase); PaidToasts = new string[3] { "One {0}, sorted.", "{0} acquired.", "Got the {0}. Money well spent, probably." }; FreeToasts = new string[3] { "{0}. On the house.", "Free {0}. Take the win.", "{0}, no charge. Good people." }; ClosedToasts = new string[3] { "Shut. Come back when they're open.", "Closed. The hunger can wait, apparently.", "No luck. They keep hours, unlike me." }; _icons = new Dictionary(StringComparer.OrdinalIgnoreCase); Vendor[] vendors = Vendors; Item[] items; for (int num = 0; num < vendors.Length; num++) { items = vendors[num].Items; foreach (Item item in items) { _items[item.Id] = item; } } items = ShopOnlyItems; foreach (Item item2 in items) { _items[item2.Id] = item2; } items = DanDishItems; foreach (Item item3 in items) { _items[item3.Id] = item3; } } internal static bool TryGetDef(string id, out StorableItemDefinition def) { def = null; if (_defs.TryGetValue(id ?? "", out def)) { return (Object)(object)def != (Object)null; } return false; } public static void OnSessionEnded() { Vendor[] vendors = Vendors; foreach (Vendor obj in vendors) { obj.Armed = false; obj.GaveUp = false; obj.Hooked = false; obj.Attempts = 0; obj.NextAttempt = 0f; obj.Convo = null; obj.SoldNode = null; obj.EntryNode = null; obj.ByeNode = null; } _gasMartStocked = false; _gasMartAttempts = 0; _nextGasMartAttempt = 0f; _nextHoursRefresh = 0f; } public static bool IsOpenNow(string range) { try { if (string.IsNullOrEmpty(range)) { return true; } string text = range.Trim().ToLowerInvariant(); switch (text) { case "always": case "24h": case "open": return true; default: { int num = text.IndexOf('-'); if (num <= 0 || num >= text.Length - 1) { return true; } if (!int.TryParse(text.Substring(0, num).Trim(), out var result)) { return true; } if (!int.TryParse(text.Substring(num + 1).Trim(), out var result2)) { return true; } if (result == result2) { return true; } TimeManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return true; } int currentTime = instance.CurrentTime; return (result >= result2) ? (currentTime >= result || currentTime < result2) : (currentTime >= result && currentTime < result2); } } } catch { return true; } } public static bool TryGetLook(string id, out Mesh mesh, out string matKey, out Taco3D.FillingLook look) { bool upright; return TryGetLook(id, out mesh, out matKey, out look, out upright); } public static bool TryGetLook(string id, out Mesh mesh, out string matKey, out Taco3D.FillingLook look, out bool upright) { mesh = null; matKey = null; look = default(Taco3D.FillingLook); upright = false; if (string.IsNullOrEmpty(id) || !_items.TryGetValue(id, out var value)) { return false; } if (value.Kind == MeshKind.Native) { return false; } mesh = MeshFor(value.Kind); matKey = value.Id; look = value.Look; upright = IsUpright(value.Kind); return true; } internal static IEnumerable AllItemIds() { return _items.Keys; } private static Mesh MeshFor(MeshKind kind) { return (Mesh)(kind switch { MeshKind.Cup => Taco3D.GetCupMesh(), MeshKind.Folded => Taco3D.GetMesh(), MeshKind.Roll => Taco3D.GetRollMesh("roll"), MeshKind.Slab => Taco3D.GetSlabMesh(), MeshKind.Bowl => Taco3D.GetBowlMesh("bowl"), MeshKind.BruleeBowl => Taco3D.GetBowlMesh("brulee", 0.038f, 0.024f, 0.9375f), MeshKind.Mug => Taco3D.GetMugMesh("mug"), MeshKind.GlassTall => Taco3D.GetGlassMesh("glasstall", 0.024f, 0.032f, 0.11f, 0.18f), MeshKind.GlassShort => Taco3D.GetGlassMesh("glassshort", 0.03f, 0.034f, 0.062f, 0.15f), MeshKind.Bottle => Taco3D.GetBottleMesh("bottle"), MeshKind.Can => Taco3D.GetCanMesh("can"), MeshKind.NoodleCup => Taco3D.GetNoodleCupMesh("noodlecup"), MeshKind.StrawCup => Taco3D.GetStrawCupMesh("strawcup"), MeshKind.Croissant => Taco3D.GetCroissantMesh("croissant"), MeshKind.PastryDisc => Taco3D.GetPastryDiscMesh("pastrydisc"), MeshKind.Sandwich => Taco3D.GetSandwichMesh("sandwich"), MeshKind.Slice => Taco3D.GetSliceMesh("slice"), MeshKind.Bun => Taco3D.GetBunMesh("bun"), MeshKind.FilledBun => Taco3D.GetFilledBunMesh("filledbun"), MeshKind.Hotdog => Taco3D.GetHotdogMesh("hotdog"), MeshKind.TakeoutBox => Taco3D.GetTakeoutBoxMesh("takeout"), MeshKind.Carton => Taco3D.GetCartonMesh("carton"), MeshKind.Brownie => Taco3D.GetBrownieMesh("brownie"), MeshKind.PlateSteak => Taco3D.GetPlateSteakMesh("platesteak"), MeshKind.Chicken => Taco3D.GetChickenMesh("chicken"), MeshKind.Fish => Taco3D.GetFishMesh("fish"), MeshKind.Tray => Taco3D.GetTrayMesh("tray"), _ => Taco3D.GetBurritoMesh(), }); } private static bool IsUpright(MeshKind kind) { switch (kind) { case MeshKind.Cup: case MeshKind.Bowl: case MeshKind.BruleeBowl: case MeshKind.Mug: case MeshKind.GlassTall: case MeshKind.GlassShort: case MeshKind.Bottle: case MeshKind.Can: case MeshKind.NoodleCup: case MeshKind.StrawCup: case MeshKind.TakeoutBox: case MeshKind.Carton: case MeshKind.PlateSteak: case MeshKind.Tray: return true; default: return false; } } public static void EnsureRegistered(StorableItemDefinition donor) { foreach (Item value in _items.Values) { if (value.Kind == MeshKind.Native) { continue; } try { if (!Registry.ItemExists(value.Id)) { StorableItemDefinition val = Object.Instantiate(donor); ((Object)val).hideFlags = (HideFlags)32; ((BaseItemDefinition)val).ID = value.Id; ((BaseItemDefinition)val).Name = value.Name; ((BaseItemDefinition)val).Description = value.Desc ?? value.Name; val.BasePurchasePrice = Mathf.Max(1f, value.Price); Sprite val2 = LoadIcon(value); if ((Object)(object)val2 != (Object)null) { ((BaseItemDefinition)val).Icon = val2; } TacoItem.SwapInWorldModel(val, MeshFor(value.Kind), value.Id, value.Look); Singleton.Instance.AddToRegistry((ItemDefinition)(object)val); _defs[value.Id] = val; } } catch (Exception ex) { MelonLogger.Warning("[Eatery] registration failed for '" + value.Id + "': " + ex.Message); } } } public static void Tick() { TickGasMart(); float unscaledTime = Time.unscaledTime; Vendor[] vendors = Vendors; foreach (Vendor vendor in vendors) { if (vendor.Enabled() && !vendor.Armed && !vendor.GaveUp && !(unscaledTime < vendor.NextAttempt)) { vendor.NextAttempt = unscaledTime + 2f; try { TryArm(vendor); } catch (Exception ex) { vendor.GaveUp = true; Diag.Log($"[Eatery] {vendor.Key} wiring failed ({ex.Message}) — vendor unavailable this session."); } } } TickHours(unscaledTime); } private static void TickHours(float now) { if (now < _nextHoursRefresh) { return; } _nextHoursRefresh = now + 5f; Vendor[] vendors = Vendors; foreach (Vendor vendor in vendors) { if (!vendor.Armed || vendor.EntryNode == null) { continue; } try { vendor.EntryNode.DialogueText = (IsOpenNow(vendor.Hours()) ? Lines.Pick(vendor.EntryLines) : Lines.Pick(vendor.ClosedLines)); if (vendor.ByeNode != null) { vendor.ByeNode.DialogueText = Lines.Pick(vendor.ByeLines); } } catch { } } } private static void TickGasMart() { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown if (!NeedsConfig.VendorGasMart || _gasMartStocked) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextGasMartAttempt) { return; } _nextGasMartAttempt = unscaledTime + 5f; try { int num = 0; int num2 = 0; List allShops = ShopInterface.AllShops; if (allShops != null) { for (int i = 0; i < allShops.Count; i++) { ShopInterface val = allShops[i]; if ((Object)(object)val == (Object)null || val.Listings == null) { continue; } ShopListing val2 = null; HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); for (int j = 0; j < val.Listings.Count; j++) { ShopListing val3 = val.Listings[j]; if (val3 != null && !((Object)(object)val3.Item == (Object)null)) { hashSet.Add(((BaseItemDefinition)val3.Item).ID); if (((BaseItemDefinition)val3.Item).ID == "banana") { val2 = val3; } } } if (val2 == null) { continue; } string[] gasMartItems = GasMartItems; foreach (string text in gasMartItems) { StorableItemDefinition value; if (hashSet.Contains(text)) { num2++; } else if (_defs.TryGetValue(text, out value) && !((Object)(object)value == (Object)null)) { ShopListing val4 = new ShopListing(); val4.name = ((BaseItemDefinition)value).Name; val4.Item = value; val4.LimitedStock = false; val4.RestockRate = (ERestockRate)0; val4.DefaultStock = 99; val4.CanBeDelivered = val2.CanBeDelivered; val.Listings.Add(val4); val4.Initialize(val); try { val.CreateListingUI(val4); } catch { } num++; } } } } if (num + num2 > 0) { _gasMartStocked = true; Diag.Log($"[Eatery] Gas-Mart NATIVE shop stocked: {num} listing(s) added, {num2} already there (no fake clerk — the real shop UI)."); } else if (++_gasMartAttempts >= 24) { _gasMartStocked = true; Diag.Log("[Eatery] no banana-selling shop found — Gas-Mart items not stocked this session."); } } catch (Exception ex) { MelonLogger.Warning("[Eatery] Gas-Mart stocking failed: " + ex.Message); } } private static void TryArm(Vendor v) { //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Expected O, but got Unknown NPC val = null; try { val = NPCManager.GetNPC(v.NpcId); if ((Object)(object)val == (Object)null) { Il2CppArrayBase val2 = Object.FindObjectsOfType(); for (int i = 0; i < val2.Length; i++) { NPC val3 = val2[i]; if (!((Object)(object)val3 == (Object)null)) { string text = ""; string text2 = ""; try { text = (val3.ID ?? "").ToLowerInvariant(); } catch { } try { text2 = (val3.FirstName ?? "").ToLowerInvariant(); } catch { } if (text == v.NpcId || text2 == v.FirstName) { val = val3; break; } } } } } catch { } if ((Object)(object)val == (Object)null) { if (++v.Attempts >= 15) { v.GaveUp = true; Diag.Log($"[Eatery] {v.Key}: NPC '{v.NpcId}' not present in this world — vendor skipped (not faked)."); } return; } string value = "?"; try { value = val.ID ?? "?"; } catch { } DialogueController val4 = ((Component)val).GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val).GetComponentInChildren(true); } if ((Object)(object)val4 == (Object)null && (Object)(object)val.DialogueHandler != (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponentInChildren(true); } } if ((Object)(object)val4 == (Object)null || val4.Choices == null) { v.GaveUp = true; Diag.Log($"[Eatery] {v.Key}: NPC '{value}' has no DialogueController — vendor skipped."); return; } for (int j = 0; j < val4.Choices.Count; j++) { DialogueChoice val5 = val4.Choices[j]; if (val5 != null && (val5.ChoiceText ?? "") == v.MenuChoice) { v.Armed = true; return; } } DialogueContainer val6 = BuildConversation(v); DialogueChoice val7 = new DialogueChoice(); val7.Enabled = true; val7.ChoiceText = v.MenuChoice; val7.ShowWorldspaceDialogue = false; val7.Conversation = val6; val7.Priority = 0; val7.onChoosen = new UnityEvent(); try { val4.AddDialogueChoice(val7, 0); } catch { val4.Choices.Add(val7); } DialogueHandler dialogueHandler = val.DialogueHandler; if ((Object)(object)dialogueHandler != (Object)null) { try { List dialogueContainers = dialogueHandler.dialogueContainers; if (dialogueContainers != null && !dialogueContainers.Contains(val6)) { dialogueContainers.Add(val6); } } catch { } if (!v.Hooked) { dialogueHandler.onDialogueChoiceChosen.AddListener(UnityAction.op_Implicit((Action)OnChoice)); v.Hooked = true; } } v.Armed = true; Diag.Log($"[Eatery] {v.Key} armed: '{value}' runs {v.Establishment} ({v.Items.Length} item(s)); existing choices untouched."); } private static DialogueContainer BuildConversation(Vendor v) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Expected O, but got Unknown if ((Object)(object)v.Convo != (Object)null && Object.op_Implicit((Object)(object)v.Convo)) { return v.Convo; } DialogueContainer val = ScriptableObject.CreateInstance(); ((Object)val).name = "S1HT_Eatery_" + v.Key; ((Object)val).hideFlags = (HideFlags)32; val.DialogueNodeData = new List(); val.NodeLinks = new List(); val.BranchNodeData = new List(); DialogueNodeData val2 = new DialogueNodeData(); val2.Guid = "S1HT_EAT_ENTRY_" + v.Key; val2.DialogueNodeLabel = TacoDiag.DiscoveredEntryLabel; val2.DialogueText = (IsOpenNow(v.Hours()) ? Lines.Pick(v.EntryLines) : Lines.Pick(v.ClosedLines)); val2.choices = new Il2CppReferenceArray((long)(v.Items.Length + 1)); DialogueChoiceData[] array = (DialogueChoiceData[])(object)new DialogueChoiceData[v.Items.Length]; for (int i = 0; i < v.Items.Length; i++) { Item item = v.Items[i]; DialogueChoiceData val3 = new DialogueChoiceData(); val3.Guid = "S1HT_EAT_BUY_" + item.Id; val3.ChoiceLabel = val3.Guid; val3.ChoiceText = ((item.Price > 0f) ? $"{item.Name} (${item.Price:0})" : (item.Name + " (free)")); ((Il2CppArrayBase)(object)val2.choices)[i] = val3; array[i] = val3; } DialogueChoiceData val4 = new DialogueChoiceData(); val4.Guid = "S1HT_EAT_EXIT_" + v.Key; val4.ChoiceLabel = val4.Guid; val4.ChoiceText = "Nah, all good."; ((Il2CppArrayBase)(object)val2.choices)[v.Items.Length] = val4; DialogueNodeData val5 = new DialogueNodeData(); val5.Guid = "S1HT_EAT_SOLD_" + v.Key; val5.DialogueNodeLabel = val5.Guid; val5.DialogueText = "There you go."; val5.choices = new Il2CppReferenceArray(0L); DialogueNodeData val6 = new DialogueNodeData(); val6.Guid = "S1HT_EAT_BYE_" + v.Key; val6.DialogueNodeLabel = val6.Guid; val6.DialogueText = Lines.Pick(v.ByeLines); val6.choices = new Il2CppReferenceArray(0L); val.DialogueNodeData.Add(val2); val.DialogueNodeData.Add(val5); val.DialogueNodeData.Add(val6); for (int j = 0; j < array.Length; j++) { NodeLinkData val7 = new NodeLinkData(); val7.BaseDialogueOrBranchNodeGuid = val2.Guid; val7.BaseChoiceOrOptionGUID = array[j].Guid; val7.TargetNodeGuid = val5.Guid; val.NodeLinks.Add(val7); } NodeLinkData val8 = new NodeLinkData(); val8.BaseDialogueOrBranchNodeGuid = val2.Guid; val8.BaseChoiceOrOptionGUID = val4.Guid; val8.TargetNodeGuid = val6.Guid; val.NodeLinks.Add(val8); v.Convo = val; v.SoldNode = val5; v.EntryNode = val2; v.ByeNode = val6; return val; } private static void OnChoice(string chosen) { if (string.IsNullOrEmpty(chosen) || !chosen.StartsWith("S1HT_EAT_BUY_")) { return; } string b = chosen.Substring("S1HT_EAT_BUY_".Length); Vendor[] vendors = Vendors; foreach (Vendor vendor in vendors) { Item[] items = vendor.Items; foreach (Item item in items) { if (string.Equals(item.Id, b, StringComparison.OrdinalIgnoreCase)) { Buy(vendor, item); return; } } } } private static void Buy(Vendor v, Item it) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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) try { StorableItemDefinition value = null; if (it.Kind == MeshKind.Native) { ItemDefinition item = Registry.GetItem(it.Id); value = (((Object)(object)item != (Object)null) ? ((Il2CppObjectBase)item).TryCast() : null); } else { _defs.TryGetValue(it.Id, out value); } if ((Object)(object)value == (Object)null) { Diag.Log("[Eatery] '" + it.Id + "' has no definition — sale aborted."); return; } if (!IsOpenNow(v.Hours())) { if (v.SoldNode != null) { v.SoldNode.DialogueText = Lines.Pick(v.ClosedLines); } NeedsHud.Toast(Lines.Pick(ClosedToasts), NeedsHud.ToastNeutral); Diag.Log($"[Eatery] {v.Key}: sale blocked — closed right now (hours {v.Hours()})."); return; } PlayerInventory instance = PlayerSingleton.Instance; if ((Object)(object)instance == (Object)null) { return; } if (it.Price > 0f) { MoneyManager instance2 = NetworkSingleton.Instance; if ((Object)(object)instance2 == (Object)null) { return; } if (instance2.cashBalance < it.Price) { if (v.SoldNode != null) { v.SoldNode.DialogueText = Lines.Pick(v.BrokeLines); } NeedsHud.Toast($"That's ${it.Price:0} cash. You haven't got it.", NeedsHud.ToastNeutral); return; } instance2.ChangeCashBalance(0f - it.Price, true, true); } if (v.SoldNode != null) { v.SoldNode.DialogueText = Lines.Pick(it.SoldLines); } instance.AddItemToInventory(((ItemDefinition)value).GetDefaultInstance(1)); NeedsHud.Toast((it.Price > 0f) ? Lines.Pick(PaidToasts, it.Name.ToLowerInvariant()) : Lines.Pick(FreeToasts, it.Name), NeedsHud.ToastGood); Diag.Log($"[Eatery] '{it.Id}' {((it.Price > 0f) ? $"sold by {v.Key} for ${it.Price:0}" : ("given free by " + v.Key))}."); } catch (Exception ex) { Diag.Log("[Eatery] purchase failed for '" + it.Id + "': " + ex.Message); } } private static Sprite LoadIcon(Item it) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00f1: 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) if (_icons.TryGetValue(it.Id, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } try { Assembly assembly = typeof(EateryVendors).Assembly; string text = "S1HungerThirst.Assets.eatery_" + it.Id + ".png"; using Stream stream = assembly.GetManifestResourceStream(text); if (stream == null) { MelonLogger.Warning("[Eatery] icon '" + text + "' missing."); 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; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Object)val).hideFlags = (HideFlags)32; if (!ImageConversion.LoadImage(val, Il2CppStructArray.op_Implicit(array))) { return null; } Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)val2).hideFlags = (HideFlags)32; _icons[it.Id] = val2; return val2; } catch (Exception ex) { MelonLogger.Warning("[Eatery] icon load failed for '" + it.Id + "': " + ex.Message); return null; } } } public static class IngredientEffects { private static readonly Dictionary _fx = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _fxProducts = new Dictionary(StringComparer.OrdinalIgnoreCase); private static ProductDefinition _donor; public const string FxIdPrefix = "s1ht_fx_"; private static readonly string[] PillWords = new string[7] { "paracetamol", "addy", "viag", "pill", "aspirin", "tablet", "capsule" }; public static bool IsFxIngredient(string id) { if (NeedsConfig.ConsumeIngredientsForEffects) { return _fx.ContainsKey(id ?? ""); } return false; } public static bool IsPill(string id) { if (string.IsNullOrEmpty(id) || !_fx.TryGetValue(id, out var value)) { return false; } string text = (id + " " + (((Object)(object)value != (Object)null) ? ((BaseItemDefinition)value).Name : "")).ToLowerInvariant(); for (int i = 0; i < PillWords.Length; i++) { if (text.Contains(PillWords[i])) { return true; } } return false; } public static bool IsBottlePill(string id) { return string.Equals(id, "addy", StringComparison.OrdinalIgnoreCase); } public static void OnSessionEnded() { _fx.Clear(); _fxProducts.Clear(); _donor = null; } public static void Discover() { _fx.Clear(); if (!NeedsConfig.ConsumeIngredientsForEffects) { return; } try { _donor = FindDonorProduct(); if ((Object)(object)_donor == (Object)null) { Diag.Log("[FX] no authored donor product found — ingredient effects disabled this session (no fabricated products, ever)."); return; } Il2CppArrayBase val = (((Object)(object)Singleton.Instance != (Object)null) ? Singleton.Instance.GetAllItems() : null)?.ToArray(); if (val == null) { return; } int num = 0; for (int i = 0; i < val.Length; i++) { ItemDefinition val2 = val[i]; if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((BaseItemDefinition)val2).ID) && !((BaseItemDefinition)val2).ID.StartsWith("s1ht_fx_", StringComparison.OrdinalIgnoreCase) && !ConsumableMap.TryGet(((BaseItemDefinition)val2).ID, out var _)) { PropertyItemDefinition val3 = ((Il2CppObjectBase)val2).TryCast(); if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Il2CppObjectBase)val3).TryCast() != (Object)null) && val3.Properties != null && val3.Properties.Count != 0) { _fx[((BaseItemDefinition)val2).ID] = val3; ConsumableMap.AddRuntimeEntry(((BaseItemDefinition)val2).ID, new Restore(0f, 0f)); Diag.Log($"[FX] ingredient '{((BaseItemDefinition)val2).ID}' ({((BaseItemDefinition)val2).Name}) → {DescribeEffects(val3)} — consumable via the native product flow."); num++; } } } Diag.Log($"[FX] {num} drug ingredient(s) wired (donor product: '{((BaseItemDefinition)_donor).ID}')."); } catch (Exception ex) { MelonLogger.Warning("[FX] ingredient discovery failed: " + ex.Message); } } private static ProductDefinition FindDonorProduct() { try { ItemDefinition item = Registry.GetItem("cuke"); Equippable val = (((Object)(object)item != (Object)null) ? item.Equippable : null); Equippable_Cuke val2 = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).TryCast() : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.PseudoProduct != (Object)null) { Diag.Log("[FX] donor = cuke's PseudoProduct '" + ((BaseItemDefinition)val2.PseudoProduct).ID + "' (the proven drink-flow product)."); return val2.PseudoProduct; } } catch { } try { Il2CppArrayBase val3 = (((Object)(object)Singleton.Instance != (Object)null) ? Singleton.Instance.GetAllItems() : null)?.ToArray(); if (val3 == null) { return null; } for (int i = 0; i < val3.Length; i++) { ProductDefinition val4 = (((Object)(object)val3[i] != (Object)null) ? ((Il2CppObjectBase)val3[i]).TryCast() : null); if (!((Object)(object)val4 == (Object)null) && val4.DrugTypes != null && val4.DrugTypes.Count != 0 && !(((BaseItemDefinition)val4).ID ?? "").StartsWith("s1ht_fx_", StringComparison.OrdinalIgnoreCase)) { Diag.Log("[FX] donor = registry product '" + ((BaseItemDefinition)val4).ID + "' (fallback)."); return val4; } } } catch { } return null; } private static string DescribeEffects(PropertyItemDefinition p) { try { Il2CppArrayBase val = p.Properties.ToArray(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < val.Length; i++) { if (!((Object)(object)val[i] == (Object)null)) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } string value = null; try { value = val[i].Name; } catch { } if (string.IsNullOrEmpty(value)) { value = ((MemberInfo)((Object)val[i]).GetIl2CppType()).Name; } stringBuilder.Append(value); } } return (stringBuilder.Length > 0) ? stringBuilder.ToString() : "(unnamed effect)"; } catch { return "(unreadable)"; } } public static ProductDefinition GetFxProduct(string id) { if (_fxProducts.TryGetValue(id ?? "", out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } if ((Object)(object)_donor == (Object)null) { return null; } if (!_fx.TryGetValue(id ?? "", out var value2) || (Object)(object)value2 == (Object)null) { return null; } try { ProductDefinition val = Object.Instantiate(_donor); ((Object)val).hideFlags = (HideFlags)32; ((Object)val).name = "S1HT_FX_" + id; ((BaseItemDefinition)val).ID = "s1ht_fx_" + id; ((BaseItemDefinition)val).Name = ((BaseItemDefinition)value2).Name; List val2 = new List(); Il2CppArrayBase val3 = value2.Properties.ToArray(); for (int i = 0; i < val3.Length; i++) { if ((Object)(object)val3[i] != (Object)null) { val2.Add(val3[i]); } } ((PropertyItemDefinition)val).Properties = val2; val.PlayerEffectDuration = Mathf.RoundToInt(Mathf.Clamp(NeedsConfig.IngredientEffectSeconds, 10f, 600f)); try { Singleton.Instance.AddToRegistry((ItemDefinition)(object)val); } catch (Exception ex) { Diag.Log("[FX] registry add failed for '" + ((BaseItemDefinition)val).ID + "': " + ex.Message); } _fxProducts[id] = val; Diag.Log($"[FX] product built for '{id}': clone of '{((BaseItemDefinition)_donor).ID}', effects swapped to [{DescribeEffects(value2)}], duration {val.PlayerEffectDuration}s, registered."); return val; } catch (Exception ex2) { Diag.Log("[FX] product build failed for '" + id + "': " + ex2.Message); return null; } } } public static class ItemModels { private const float HandTargetSize = 0.15f; private const float HandYaw = 20f; private static readonly HashSet _handLogged = new HashSet(StringComparer.OrdinalIgnoreCase); private static bool _audited; public static bool TryResolve(string id, out Mesh mesh, out string matKey, out Taco3D.FillingLook look, out Vector3 handEuler) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00ee: 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_00f3: Unknown result type (might be due to invalid IL or missing references) mesh = null; matKey = null; look = default(Taco3D.FillingLook); handEuler = Vector3.zero; if (string.IsNullOrEmpty(id)) { return false; } if (TacoItem.TryGetVariant(id, out var v)) { mesh = Taco3D.GetMesh(); matKey = v.Id; look = v.Look; handEuler = new Vector3(-15f, 25f, 0f); return (Object)(object)mesh != (Object)null; } if (string.Equals(id, "burroito", StringComparison.OrdinalIgnoreCase)) { mesh = Taco3D.GetBurritoMesh(); matKey = "burroito"; look = Taco3D.BurroitoLook; handEuler = new Vector3(-10f, 30f, 0f); return (Object)(object)mesh != (Object)null; } if (EateryVendors.TryGetLook(id, out mesh, out matKey, out look, out var upright)) { handEuler = (upright ? new Vector3(0f, 20f, 0f) : new Vector3(-10f, 30f, 0f)); return (Object)(object)mesh != (Object)null; } mesh = null; matKey = null; look = default(Taco3D.FillingLook); return false; } public static GameObject BuildArchetypeHandObject(Mesh mesh, string matKey, Taco3D.FillingLook look, Renderer materialDonor, int layer, Vector3 euler) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mesh == (Object)null) { return null; } GameObject val = new GameObject("S1HT_Hand3D_" + matKey); val.AddComponent().sharedMesh = mesh; MeshRenderer val2 = val.AddComponent(); Material material = Taco3D.GetMaterial(materialDonor, matKey, look); if ((Object)(object)material != (Object)null) { ((Renderer)val2).sharedMaterial = material; } if (layer >= 0) { val.layer = layer; } val.transform.localRotation = Quaternion.Euler(euler); return val; } public static GameObject BuildFromStoredItem(ItemDefinition def, int layer, out string desc) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00e5: 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_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: 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) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: 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_0180: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) desc = "none"; try { StorableItemDefinition val = (((Object)(object)def != (Object)null) ? ((Il2CppObjectBase)def).TryCast() : null); if ((Object)(object)val == (Object)null || (Object)(object)val.StoredItem == (Object)null) { return null; } Transform transform = ((Component)val.StoredItem).transform; Il2CppArrayBase componentsInChildren = ((Component)val.StoredItem).GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } GameObject val2 = new GameObject("S1HT_HandProp_" + ((BaseItemDefinition)def).ID); GameObject val3 = new GameObject("yaw"); val3.transform.SetParent(val2.transform, false); val3.transform.localRotation = Quaternion.Euler(0f, 20f, 0f); GameObject val4 = new GameObject("pivot"); val4.transform.SetParent(val3.transform, false); int num = 0; string text = null; bool have = false; Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(Vector3.zero, Vector3.zero); for (int i = 0; i < componentsInChildren.Length; i++) { MeshFilter val5 = componentsInChildren[i]; if ((Object)(object)val5 == (Object)null || (Object)(object)val5.sharedMesh == (Object)null) { continue; } GameObject gameObject = ((Component)val5).gameObject; if (!gameObject.activeSelf) { continue; } string text2 = ((Object)gameObject).name ?? "part"; if (IsLowerLod(text2)) { continue; } MeshRenderer component = gameObject.GetComponent(); if (!((Object)(object)component != (Object)null) || ((Renderer)component).enabled) { GameObject val6 = new GameObject(text2); val6.transform.SetParent(val4.transform, false); CopyRelativeTransform(transform, ((Component)val5).transform, val6.transform); if (layer >= 0) { val6.layer = layer; } val6.AddComponent().sharedMesh = val5.sharedMesh; MeshRenderer val7 = val6.AddComponent(); if ((Object)(object)component != (Object)null && ((Renderer)component).sharedMaterials != null) { ((Renderer)val7).sharedMaterials = ((Renderer)component).sharedMaterials; } if (text == null) { text = ((Object)val5.sharedMesh).name; } Encapsulate(ref bounds, ref have, val6.transform, val5.sharedMesh.bounds); num++; } } if (num == 0 || !have) { Object.Destroy((Object)(object)val2); return null; } float num2 = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)); float num3 = ((num2 > 0.0001f) ? Mathf.Clamp(0.15f / num2, 0.02f, 40f) : 1f); val4.transform.localScale = Vector3.one * num3; val4.transform.localPosition = (0f - num3) * ((Bounds)(ref bounds)).center; if (layer >= 0) { val2.layer = layer; val3.layer = layer; val4.layer = layer; } desc = $"stored-item prop copy ({num} mesh(es), first '{text}', x{num3:0.###})"; return val2; } catch (Exception ex) { Diag.Log("[Model] hand prop copy failed for '" + SafeId(def) + "': " + ex.Message); return null; } } private static bool IsLowerLod(string name) { int num = name.IndexOf("_LOD", StringComparison.OrdinalIgnoreCase); if (num < 0) { return false; } int num2 = num + 4; if (num2 < name.Length && name[num2] >= '1') { return name[num2] <= '9'; } return false; } private static void CopyRelativeTransform(Transform root, Transform src, Transform dst) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)src.parent != (Object)null && (Object)(object)root != (Object)null && ((Il2CppObjectBase)src.parent).Pointer == ((Il2CppObjectBase)root).Pointer) { dst.localPosition = src.localPosition; dst.localRotation = src.localRotation; dst.localScale = src.localScale; return; } Matrix4x4 val = root.worldToLocalMatrix * src.localToWorldMatrix; Vector4 column = ((Matrix4x4)(ref val)).GetColumn(0); Vector4 column2 = ((Matrix4x4)(ref val)).GetColumn(1); Vector4 column3 = ((Matrix4x4)(ref val)).GetColumn(2); Vector4 column4 = ((Matrix4x4)(ref val)).GetColumn(3); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(column.x, column.y, column.z); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(column2.x, column2.y, column2.z); Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(column3.x, column3.y, column3.z); dst.localPosition = new Vector3(column4.x, column4.y, column4.z); dst.localScale = new Vector3(((Vector3)(ref val2)).magnitude, ((Vector3)(ref val3)).magnitude, ((Vector3)(ref val4)).magnitude); if (((Vector3)(ref val4)).sqrMagnitude > 1E-12f && ((Vector3)(ref val3)).sqrMagnitude > 1E-12f) { dst.localRotation = Quaternion.LookRotation(val4, val3); } } catch { dst.localPosition = src.localPosition; dst.localRotation = src.localRotation; dst.localScale = src.localScale; } } private static void Encapsulate(ref Bounds bounds, ref bool have, Transform t, Bounds local) { //IL_0002: 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) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) Vector3 center = ((Bounds)(ref local)).center; Vector3 extents = ((Bounds)(ref local)).extents; Vector3 val = default(Vector3); for (int i = 0; i < 8; i++) { ((Vector3)(ref val))..ctor(center.x + (((i & 1) == 0) ? (0f - extents.x) : extents.x), center.y + (((i & 2) == 0) ? (0f - extents.y) : extents.y), center.z + (((i & 4) == 0) ? (0f - extents.z) : extents.z)); Vector3 val2 = t.localRotation * Vector3.Scale(val, t.localScale) + t.localPosition; if (!have) { bounds = new Bounds(val2, Vector3.zero); have = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2); } } } public static void OnSessionEnded() { _handLogged.Clear(); _audited = false; } public static void NoteHandModel(string id, string what) { if (!string.IsNullOrEmpty(id) && _handLogged.Add(id)) { Diag.Log("[Model] hand '" + id + "' → " + what); } } public static void RunAudit() { if (_audited) { return; } _audited = true; try { List ids = new List(); HashSet seen = new HashSet(StringComparer.OrdinalIgnoreCase); TacoItem.Variant[] variants = TacoItem.Variants; for (int i = 0; i < variants.Length; i++) { Add(variants[i].Id); } Add("burroito"); foreach (string item in EateryVendors.AllItemIds()) { Add(item); } foreach (string item2 in ConsumableMap.WiredIds()) { Add(item2); } int num = 0; int num2 = 0; int num3 = 0; Diag.Log($"[Model] ===== MODEL AUDIT ({ids.Count} id(s)) ====="); foreach (string item3 in ids) { int kind; string text = AuditOne(item3, out kind); switch (kind) { case 0: num3++; break; case 1: num++; break; default: num2++; break; } Diag.Log("[Model] " + text); } Diag.Log($"[Model] ===== END AUDIT: {num} matching, {num2} MISMATCHED, {num3} not registered ====="); void Add(string s) { if (!string.IsNullOrEmpty(s) && seen.Add(s)) { ids.Add(s); } } } catch (Exception ex) { Diag.Log("[Model] audit failed: " + ex.Message); } } private static string AuditOne(string id, out int kind) { kind = 0; ItemDefinition val = null; try { if (Registry.ItemExists(id)) { val = Registry.GetItem(id); } } catch { } if ((Object)(object)val == (Object)null) { return "'" + id + "': not in the registry this session."; } int count; string text = ShelfMeshName(val, out count); Mesh mesh; string matKey; Taco3D.FillingLook look; Vector3 handEuler; bool num = TryResolve(id, out mesh, out matKey, out look, out handEuler); string text2 = (num ? ((Object)mesh).name : ((count <= 0) ? "(flat icon)" : text)); bool flag = count > 0 && string.Equals(text2, text, StringComparison.Ordinal); kind = (flag ? 1 : 2); string value = (num ? ("archetype, mat '" + matKey + "'") : "own stored-item prop"); return $"'{id}': shelf='{text}' hand='{text2}' [{value}] — {(flag ? "MATCH" : "MISMATCH")}"; } private static string ShelfMeshName(ItemDefinition def, out int count) { count = 0; try { StorableItemDefinition val = ((Il2CppObjectBase)def).TryCast(); if ((Object)(object)val == (Object)null || (Object)(object)val.StoredItem == (Object)null) { return "(no StoredItem)"; } Il2CppArrayBase componentsInChildren = ((Component)val.StoredItem).GetComponentsInChildren(true); string text = null; for (int i = 0; i < componentsInChildren.Length; i++) { MeshFilter val2 = componentsInChildren[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sharedMesh == (Object)null) && ((Component)val2).gameObject.activeSelf && !IsLowerLod(((Object)((Component)val2).gameObject).name ?? "")) { if (text == null) { text = ((Object)val2.sharedMesh).name; } count++; } } return text ?? "(no mesh)"; } catch { return "(unreadable)"; } } private static string SafeId(ItemDefinition def) { try { return ((Object)(object)def != (Object)null) ? (((BaseItemDefinition)def).ID ?? "?") : "null"; } catch { return "?"; } } } public static class Lines { private static readonly Random _rng = new Random(); private static readonly Dictionary _last = new Dictionary(); public static string Pick(string[] pool) { if (pool == null || pool.Length == 0) { return ""; } if (pool.Length == 1) { return pool[0]; } int value; int num = (_last.TryGetValue(pool, out value) ? value : (-1)); int num2; do { num2 = _rng.Next(pool.Length); } while (num2 == num); _last[pool] = num2; return pool[num2]; } public static string Pick(string[] pool, string arg0) { return string.Format(Pick(pool), arg0); } } public static class Session { public static bool InGame { get; private set; } public static void Tick() { bool flag = false; try { LoadManager instance = Singleton.Instance; flag = (Object)(object)instance != (Object)null && instance.IsGameLoaded && (Object)(object)Player.Local != (Object)null; } catch { flag = false; } if (flag != InGame) { InGame = flag; if (flag) { SaveData.LoadForActiveSave(); ConsumableMap.ScanRegistry(); TacoDiag.DumpRegistryAudit(); IngredientEffects.Discover(); ConsumableMap.MakeFoodDrinkable(); NeedsHud.EnsureBuilt(); Diag.Log("[Session] Save loaded — needs active."); ItemModels.RunAudit(); } else { InGame = true; ForceClose(); Diag.Log("[Session] Save closed — needs parked."); } } } public static void ForceClose() { if (InGame) { InGame = false; Safe("SaveData", SaveData.OnSessionEnded); Safe("Needs", NeedsState.OnSessionEnded); Safe("FoodMap", ConsumableMap.OnSessionEnded); Safe("FoodWiring", ConsumableMap.OnSessionEndedFoodWiring); Safe("Ingredients", IngredientEffects.OnSessionEnded); Safe("Consume", ConsumeWatcher.Reset); Safe("Models", ItemModels.OnSessionEnded); Safe("Taco", TacoItem.OnSessionEnded); Safe("Eateries", EateryVendors.OnSessionEnded); Safe("DanDish", DanDish.OnSessionEnded); Safe("FrankPresets", SettingsNpc.OnSessionEnded); Safe("Drugs", DrugEffects.Reset); Safe("Penalties", Penalties.Reset); Safe("Hud", NeedsHud.Teardown); Safe("Audio", ConsumeAudio.Teardown); Diag.Log("[Session] closed — all subsystems reset."); } } private static void Safe(string name, Action step) { try { step(); } catch (Exception ex) { Diag.Log("[Session] " + name + " reset failed: " + ex.Message); } } } public class Mod : MelonMod { private static readonly Dictionary _tickErrors = new Dictionary(); private static readonly string[] HungerS1 = new string[3] { "Getting peckish. Should eat soon.", "Stomach's starting to ask questions.", "Could eat. Not urgent. Yet." }; private static readonly string[] HungerS2 = new string[3] { "Proper hungry now. Need to eat something.", "Stomach's gone from asking to demanding.", "Running on fumes, food-wise." }; private static readonly string[] HungerS3 = new string[3] { "Starving. Eat something, now.", "Body's eating itself. Fix that.", "Past hungry. This is a problem." }; private static readonly string[] ThirstS1 = new string[3] { "Mouth's a bit dry. Grab a drink.", "Could use a drink. The boring kind.", "Throat's getting scratchy." }; private static readonly string[] ThirstS2 = new string[3] { "Parched. Find a drink.", "Properly dry now. Water, soon.", "Swallowing's becoming a chore." }; private static readonly string[] ThirstS3 = new string[3] { "Seriously parched. Drink something, now.", "Dry as the gutter. Drink. Now.", "This thirst is doing damage." }; private static readonly string[] EnergyS1 = new string[3] { "Yawning already. Early night wouldn't hurt.", "Eyelids getting opinions of their own.", "Bit of a yawn on. Noted." }; private static readonly string[] EnergyS2 = new string[3] { "Knackered. Bed soon.", "Running on stubbornness now.", "Properly tired. Bed's calling." }; private static readonly string[] EnergyS3 = new string[3] { "Dead on your feet. Go to bed.", "Awake in name only. Bed. Now.", "The floor's starting to look comfortable." }; public override void OnInitializeMelon() { NeedsConfig.Init(); ((MelonBase)this).HarmonyInstance.PatchAll(typeof(MoveSpeedPatch)); ((MelonBase)this).HarmonyInstance.PatchAll(typeof(SaveHookPatch)); try { ((MelonBase)this).HarmonyInstance.PatchAll(typeof(TrashPatch)); } catch (Exception ex) { MelonLogger.Warning("Trash patch failed to apply (" + ex.Message + ") — probe-scan fallback will handle thrown cans."); } try { ((MelonBase)this).HarmonyInstance.PatchAll(typeof(ShelfPatch)); } catch (Exception ex2) { MelonLogger.Warning("Shelf patch failed to apply (" + ex2.Message + ") — active-template fix still covers placement."); } NeedsState.OnStageWorsened += OnStageWorsened; MelonLogger.Msg("Survival Mode loaded — eat, drink, and sleep. Meters drain on real play time. Food consumes exactly like a drink: select it in the hotbar and use it the same way you drink a cuke. Sleep before you're delirious."); } private static void Run(string name, Action step) { try { step(); } catch (Exception value) { _tickErrors.TryGetValue(name, out var value2); value2 = (_tickErrors[name] = value2 + 1); if (value2 <= 3 || value2 % 300 == 0) { Diag.Log($"[Tick] {name} failed (#{value2}): {value}"); } } } public override void OnUpdate() { if (!NeedsConfig.Enabled) { if (Session.InGame) { Session.ForceClose(); } return; } Run("EnsureRegistered", TacoItem.EnsureRegistered); Run("Session", Session.Tick); if (Session.InGame) { Run("DrugEffects", DrugEffects.Tick); Run("Needs", NeedsState.TickRealTime); Run("Penalties", Penalties.Tick); Run("Consume", ConsumeWatcher.Tick); Run("KyleVendor", TacoItem.TickKyleVendor); Run("Eateries", EateryVendors.Tick); Run("DanDish", DanDish.Tick); Run("MysteryShop", TacoItem.TickMysteryShop); Run("ShelfWatcher", TacoItem.TickShelfWatcher); Run("FrankPresets", SettingsNpc.Tick); Run("Hud", NeedsHud.UpdateVisuals); } } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { Session.ForceClose(); } public override void OnPreferencesSaved() { NeedsConfig.Reload(); if (Session.InGame) { ConsumableMap.ScanRegistry(); IngredientEffects.Discover(); ConsumableMap.MakeFoodDrinkable(); NeedsHud.Teardown(); NeedsHud.EnsureBuilt(); } } private static void OnStageWorsened(int need, NeedStage stage) { //IL_00c5: 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_00be: 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) string[] array; switch (need) { case 0: switch (stage) { case NeedStage.Stage1: break; case NeedStage.Stage2: goto IL_0061; case NeedStage.Stage3: goto IL_0069; default: goto IL_00a1; } array = HungerS1; break; case 1: switch (stage) { case NeedStage.Stage1: break; case NeedStage.Stage2: goto IL_0079; case NeedStage.Stage3: goto IL_0081; default: goto IL_00a1; } array = ThirstS1; break; case 2: switch (stage) { case NeedStage.Stage1: break; case NeedStage.Stage2: goto IL_0091; case NeedStage.Stage3: goto IL_0099; default: goto IL_00a1; } array = EnergyS1; break; default: goto IL_00a1; IL_0099: array = EnergyS3; break; IL_0091: array = EnergyS2; break; IL_0069: array = HungerS3; break; IL_0081: array = ThirstS3; break; IL_0079: array = ThirstS2; break; IL_0061: array = HungerS2; break; IL_00a1: array = null; break; } string[] array2 = array; if (array2 != null) { NeedsHud.Toast(Lines.Pick(array2), (Color)(stage switch { NeedStage.Stage2 => NeedsHud.ToastWarn, NeedStage.Stage1 => NeedsHud.ToastNeutral, _ => NeedsHud.ToastBad, })); } } } public static class NeedsConfig { public sealed class Setting { public string Section; public string Key; public string Desc; public MelonPreferences_Entry Entry; } public static bool Enabled = true; public static bool HungerEnabled = true; public static bool ThirstEnabled = true; public static bool EnergyEnabled = true; public static bool PenaltiesEnabled = true; public static bool DrugEffectsEnabled = true; public static bool TacoEnabled = true; public static bool MouthwashClearsEffects = true; public static bool ConsumeSound = true; public static bool HudEnabled = true; public static bool ToastsEnabled = true; public static bool VignetteEnabled = true; public static bool VerboseConsume = false; public static bool VendorGasMart = true; public static bool VendorDiner = true; public static bool VendorCafe = true; public static bool VendorSupermarket = true; public static bool VendorLiquor = true; public static bool VendorCommunity = true; public static bool VendorPizzeria = true; public static bool VendorChinese = true; public static bool VendorFrench = true; public static bool VendorCanary = true; public static bool VendorMotel = true; public static bool VendorBait = true; public static bool VendorChurch = true; public static bool VendorDanDish = true; public static string DanDishMode = "auto"; public static float DanChiliPrice = 11f; public static float DanLasagnaPrice = 16f; public static string HoursTacos = "0700-2200"; public static string HoursDiner = "1050-2400"; public static string HoursCommunity = "0730-1830"; public static string HoursSupermarket = "0745-2130"; public static string HoursLiquor = "0900-2100"; public static string HoursCafe = "0600-1630"; public static string HoursPizzeria = "0845-2100"; public static string HoursChinese = "always"; public static string HoursFrench = "1740-0130"; public static string HoursCanary = "1700-0700"; public static string HoursMotel = "always"; public static string HoursBait = "1600-1020"; public static string HoursChurch = "0700-2000"; public static string HoursHardware = "0800-1800"; public static float HungerPerRealMinute = 2.4f; public static float ThirstPerRealMinute = 2.8f; public static float EnergyPerRealMinute = 2f; public static float SprintEnergyFactor = 1.5f; public static float ThresholdStage1 = 50f; public static float ThresholdStage2 = 22f; public static float ThresholdStage3 = 8f; public static float SprintBlockBelow = 4f; public static bool LethalStarvation = false; public static float HungerSpeedStage2 = 0.96f; public static float HungerSpeedStage3 = 0.9f; public static float ThirstCritSpeedFactor = 0.97f; public static float ThirstStaminaStage2 = 0.7f; public static float ThirstStaminaStage3 = 0.5f; public static float EnergySpeedStage2 = 0.97f; public static float EnergySpeedStage3 = 0.92f; public static float HealthDrainHungerPerMin = 0.6f; public static float HealthDrainThirstPerMin = 0.9f; public static float HealthFloor = 20f; public static bool EyelidsEnabled = true; public static float EyelidDroopExhausted = 0.9f; public static float EyelidDroopDelirious = 0.72f; public static float MicrosleepBlinkSeconds = 0.7f; public static float MicrosleepMinGap = 25f; public static float MicrosleepMaxGap = 55f; public static float SleepRestorePerHour = 12.5f; public static float LateSleepQuality = 0.75f; public static float LateSleepAfterHour = 2f; public static float SleepHungerCost = 8f; public static float SleepThirstCost = 12f; public static bool CollapseEnabled = true; public static float CollapseDelaySeconds = 180f; public static float CollapseRestoreTo = 35f; public static bool CollapseCashPenalty = true; public static float CollapseCashFraction = 0.1f; public static float CollapseCashCap = 250f; public static float WiredMinEnergyRestore = 15f; public static float WiredDurationSeconds = 300f; public static float WiredDrainFactor = 0.5f; public static bool ConsumeIngredientsForEffects = true; public static float IngredientEffectSeconds = 120f; public static float DrugMinMult = 0.3f; public static float DrugMaxMult = 3.5f; public static float StimKickEnergy = 20f; public static float StimKickMildFactor = 0.5f; public static float StimStrongThreshold = 0.5f; public static float StimMildThreshold = 0.85f; public static bool StimCrashEnabled = true; public static float StimCrashCost = 15f; public static string EffectRatesRaw = "Munchies=2.75/1.15/1;CalorieDense=0.5/1.0/1;Refreshing=0.9/0.6/0.9;Energizing=0.8/1.4/0.5;Focused=0.75/1.2/0.75;ThoughtProvoking=0.85/1.1/0.9;Athletic=1.3/1.5/0.9;Electrifying=1.2/1.5/0.7;Euphoric=1.0/1.3/1;Explosive=1.0/1.2/1;Spicy=1.1/1.7/1;TropicThunder=1.1/1.6/1;BrightEyed=1.0/1.1/0.6;Glowie=1.0/1.1/1;Sedating=0.7/0.85/1.8;Calming=0.9/0.9/1.3;Shrinking=0.8/0.8/1;Laxative=1.6/1.5/1;Toxic=1.3/1.4/1.1;Lethal=1.5/1.5/1.2;Zombifying=1.5/1.3/1.4;Seizure=1.3/1.5/1.1;Paranoia=1.1/1.15/1.1;Schizophrenic=1.1/1.1/1.1;Disorienting=1.0/1.1/1;AntiGravity=1.1/1.2/1;Slippery=1.0/1.1/1;Smelly=1.0/1.05/1;Foggy=1.0/1.0/1.2;Sneaky=1.0/1.0/1;Balding=1.0/1.0/1;Cyclopean=1.0/1.0/1;Gingeritis=1.0/1.0/1;Jennerising=1.0/1.0/1;LongFaced=1.0/1.0/1"; public const string DefaultEffectRates = "Munchies=2.75/1.15/1;CalorieDense=0.5/1.0/1;Refreshing=0.9/0.6/0.9;Energizing=0.8/1.4/0.5;Focused=0.75/1.2/0.75;ThoughtProvoking=0.85/1.1/0.9;Athletic=1.3/1.5/0.9;Electrifying=1.2/1.5/0.7;Euphoric=1.0/1.3/1;Explosive=1.0/1.2/1;Spicy=1.1/1.7/1;TropicThunder=1.1/1.6/1;BrightEyed=1.0/1.1/0.6;Glowie=1.0/1.1/1;Sedating=0.7/0.85/1.8;Calming=0.9/0.9/1.3;Shrinking=0.8/0.8/1;Laxative=1.6/1.5/1;Toxic=1.3/1.4/1.1;Lethal=1.5/1.5/1.2;Zombifying=1.5/1.3/1.4;Seizure=1.3/1.5/1.1;Paranoia=1.1/1.15/1.1;Schizophrenic=1.1/1.1/1.1;Disorienting=1.0/1.1/1;AntiGravity=1.1/1.2/1;Slippery=1.0/1.1/1;Smelly=1.0/1.05/1;Foggy=1.0/1.0/1.2;Sneaky=1.0/1.0/1;Balding=1.0/1.0/1;Cyclopean=1.0/1.0/1;Gingeritis=1.0/1.0/1;Jennerising=1.0/1.0/1;LongFaced=1.0/1.0/1"; public static string DrugTypeRatesRaw = "Marijuana=1.6/1.05/1.25;Methamphetamine=0.5/1.5/0.2;Cocaine=0.6/1.35/0.35;MDMA=0.8/1.5/0.5;Shrooms=1.1/1.2/1;Heroin=0.7/1.1/1.7"; public const string DefaultDrugTypeRates = "Marijuana=1.6/1.05/1.25;Methamphetamine=0.5/1.5/0.2;Cocaine=0.6/1.35/0.35;MDMA=0.8/1.5/0.5;Shrooms=1.1/1.2/1;Heroin=0.7/1.1/1.7"; public static bool AutoMapUnknownConsumables = true; public static float DefaultUnknownHunger = 15f; public static float DefaultUnknownThirst = 10f; public static float DefaultUnknownEnergy = 5f; public static bool PreserveDrugEffects = true; public static bool GasolineDrinkable = true; public static bool GasolineLethal = true; public static string FoodMapRaw = "cuke=2/30/10;energydrink=0/20/30;banana=25/3/5;donut=40/0/10;chili=18/0/0;megabean=30/5/0;mouthwash=0/-5/0;taco=45/5/0;tacochicken=38/5/0;tacoveggie=28/8/0;tacomystery=50/0/0;tacomanuke=60/10/0;tacokylespecial=52/8/0;gasoline=0/0/0;burroito=70/10/0;sausageroll=32/0/0;slushee=0/35/8;brekkieroll=42/5/0;dinercoffee=0/25/12;croissant=26/2/0;bottledwater=0/40/0;theslop=55/0/-5;urncoffee=0/24/14;bakebrownie=24/-4/4;tunasando=30/0/0;rotisserie=60/-5/0;delisando=36/0/0;instantramen=28/10/0;tallboy=3/26/-10;boxedwine=4/45/-25;chateaulapeepee=2/35/-20;brutdugloop=2/35/-20;flatwhite=0/26/16;almonddanish=28/-2/5;onionsoup=32/20/0;steakfrites=68/-6/0;cremebrulee=30/4/8;krautslice=30/-8/0;pretzelbrat=40/-6/0;weissbier=6/28/-10;porkbun=22/3/0;mingchicken=50/-8/5;jasminetea=0/30/8;vodkasoda=0/26/-14;canarycocktail=2/30/-18;coatespresso=0/18/22;lobbycoffee=0/20/14;vendingsando=30/0/0;noodlecup=28/10/0;thermoscoffee=0/22/16;smokedfish=34/-8/0;fishnchips=48/-8/0;churchcoffee=8/20/10;soupbowl=40/15/0;danchili=52/6/0;danlasagna=64/4/0"; public const string DefaultFoodMap = "cuke=2/30/10;energydrink=0/20/30;banana=25/3/5;donut=40/0/10;chili=18/0/0;megabean=30/5/0;mouthwash=0/-5/0;taco=45/5/0;tacochicken=38/5/0;tacoveggie=28/8/0;tacomystery=50/0/0;tacomanuke=60/10/0;tacokylespecial=52/8/0;gasoline=0/0/0;burroito=70/10/0;sausageroll=32/0/0;slushee=0/35/8;brekkieroll=42/5/0;dinercoffee=0/25/12;croissant=26/2/0;bottledwater=0/40/0;theslop=55/0/-5;urncoffee=0/24/14;bakebrownie=24/-4/4;tunasando=30/0/0;rotisserie=60/-5/0;delisando=36/0/0;instantramen=28/10/0;tallboy=3/26/-10;boxedwine=4/45/-25;chateaulapeepee=2/35/-20;brutdugloop=2/35/-20;flatwhite=0/26/16;almonddanish=28/-2/5;onionsoup=32/20/0;steakfrites=68/-6/0;cremebrulee=30/4/8;krautslice=30/-8/0;pretzelbrat=40/-6/0;weissbier=6/28/-10;porkbun=22/3/0;mingchicken=50/-8/5;jasminetea=0/30/8;vodkasoda=0/26/-14;canarycocktail=2/30/-18;coatespresso=0/18/22;lobbycoffee=0/20/14;vendingsando=30/0/0;noodlecup=28/10/0;thermoscoffee=0/22/16;smokedfish=34/-8/0;fishnchips=48/-8/0;churchcoffee=8/20/10;soupbowl=40/15/0;danchili=52/6/0;danlasagna=64/4/0"; public static float TacoPrice = 21f; public static float TacoPriceChicken = 18f; public static float TacoPriceVeggie = 18f; public static float TacoPriceMystery = 6f; public static float TacoPriceKyleSpecial = 69f; public static float TacoPriceManuke = 420f; public static bool BurroitoEnabled = true; public static float BurroitoPrice = 42069f; public static float BurroitoSpeedBonus = 0.1f; public static float ManukeSatietySeconds = 180f; public static float ManukeSatietyDrainFactor = 0.25f; public static float MysteryTacoBadChance = 0.25f; public static float KyleTacoBadChance = 0.05f; public static float ManukeTacoBadChance = 0f; public static bool VeganTacoEnabled = true; public static float VeganTacoPrice = 5f; public static float MysteryHungerLossFraction = 0.6f; public static float MysteryCrookGutsSeconds = 45f; public static float CrookGutsSpeedFactor = 0.93f; public static float TacoSatietySeconds = 60f; public static float TacoSatietyDrainFactor = 0.5f; public static float ConsumeSoundVolume = 0.7f; public static float EatPitchVariance = 0.12f; public static string EatClipName = ""; public static string HudCorner = "BottomLeft"; public static float HudOffsetX = 24f; public static float HudOffsetY = 24f; public static float HudScale = 1f; public static bool HudFadeWhenFine = true; public static float HudFadeAlpha = 0.3f; public static bool ShowNumbers = false; public static float ToastSeconds = 6f; public static string HudColorFood = "F0A93C"; public static string HudColorFoodLow = "E9762E"; public static string HudColorFoodCrit = "E03A2A"; public static string HudColorWater = "4FC1E8"; public static string HudColorWaterLow = "2E86D9"; public static string HudColorWaterCrit = "D9503C"; public static string HudColorEnergy = "8F7BE8"; public static string HudColorEnergyLow = "B56AC9"; public static string HudColorEnergyCrit = "E03A2A"; public static Color HudColorFoodParsed; public static Color HudColorFoodLowParsed; public static Color HudColorFoodCritParsed; public static Color HudColorWaterParsed; public static Color HudColorWaterLowParsed; public static Color HudColorWaterCritParsed; public static Color HudColorEnergyParsed; public static Color HudColorEnergyLowParsed; public static Color HudColorEnergyCritParsed; private const int CurrentConfigVersion = 2; private static readonly List _pullers = new List(); private static readonly List> _migrators = new List>(); private static MelonPreferences_Entry _configVersion; public static readonly List Settings = new List(); private static bool _legacyMigrated; private static void Register(MelonPreferences_Category cat, string key, string desc, MelonPreferences_Entry e) { string section = (cat.Identifier.StartsWith("S1HT_") ? cat.Identifier.Substring(5) : cat.Identifier); Settings.Add(new Setting { Section = section, Key = key, Desc = desc, Entry = e }); } public static void Init() { MelonPreferences_Category obj = MelonPreferences.CreateCategory("S1HT_Features", "Survival - Feature Toggles"); MelonPreferences_Category cat = MelonPreferences.CreateCategory("S1HT_Drain", "Survival - Drain Rates"); MelonPreferences_Category cat2 = MelonPreferences.CreateCategory("S1HT_Thresholds", "Survival - Stage Thresholds"); MelonPreferences_Category cat3 = MelonPreferences.CreateCategory("S1HT_Penalties", "Survival - Penalties"); MelonPreferences_Category cat4 = MelonPreferences.CreateCategory("S1HT_Sleep", "Survival - Sleep & Energy"); MelonPreferences_Category cat5 = MelonPreferences.CreateCategory("S1HT_Drugs", "Survival - Drug Interactions"); MelonPreferences_Category cat6 = MelonPreferences.CreateCategory("S1HT_Food", "Survival - Food & Restores"); MelonPreferences_Category val = MelonPreferences.CreateCategory("S1HT_Tacos", "Survival - Tacos"); MelonPreferences_Category cat7 = MelonPreferences.CreateCategory("S1HT_Audio", "Survival - Audio"); MelonPreferences_Category cat8 = MelonPreferences.CreateCategory("S1HT_HUD", "Survival - HUD"); Bind(obj, "Enabled", () => Enabled, delegate(bool v) { Enabled = v; }, "Master switch for the whole mod. false = everything off, meters parked."); Bind(obj, "HungerEnabled", () => HungerEnabled, delegate(bool v) { HungerEnabled = v; }, "The hunger pillar. false = hunger frozen at 100, row hidden, no hunger penalties.", isNew: true); Bind(obj, "ThirstEnabled", () => ThirstEnabled, delegate(bool v) { ThirstEnabled = v; }, "The thirst pillar. false = thirst frozen at 100, row hidden, no thirst penalties.", isNew: true); Bind(obj, "EnergyEnabled", () => EnergyEnabled, delegate(bool v) { EnergyEnabled = v; }, "The energy/sleep pillar. false = classic hunger+thirst only."); Bind(obj, "PenaltiesEnabled", () => PenaltiesEnabled, delegate(bool v) { PenaltiesEnabled = v; }, "false = meters only; no movement/stamina/health/eyelid consequences."); Bind(obj, "DrugEffectsEnabled", () => DrugEffectsEnabled, delegate(bool v) { DrugEffectsEnabled = v; }, "Drugs modify depletion rates while you're high (plus stim kicks/crashes)."); Bind(obj, "TacoEnabled", () => TacoEnabled, delegate(bool v) { TacoEnabled = v; }, "The taco menu: four items, Kyle's vendor conversation, shop fallback. Turning OFF mid-session leaves already-registered items until restart."); Bind(obj, "MouthwashClearsEffects", () => MouthwashClearsEffects, delegate(bool v) { MouthwashClearsEffects = v; }, "Drinking mouthwash makes you puke, clearing the active high (the purge)."); Bind(obj, "ConsumeSound", () => ConsumeSound, delegate(bool v) { ConsumeSound = v; }, "Play the recorded bite/cap-open sounds when eating and drinking."); Bind(obj, "HudEnabled", () => HudEnabled, delegate(bool v) { HudEnabled = v; }, "Show the meter rows. false with ToastsEnabled=true keeps text feedback only.", isNew: true); Bind(obj, "ToastsEnabled", () => ToastsEnabled, delegate(bool v) { ToastsEnabled = v; }, "Show the stacked text feedback lines (eat lines, warnings, Kyle, buffs).", isNew: true); Bind(obj, "VignetteEnabled", () => VignetteEnabled, delegate(bool v) { VignetteEnabled = v; }, "Screen-edge vignette at critical hunger/thirst stages."); Bind(obj, "VerboseConsume", () => VerboseConsume, delegate(bool v) { VerboseConsume = v; }, "Log every consume/vendor stage plus the TacoDiag dumps to the MelonLoader log."); Bind(obj, "VendorGasMart", () => VendorGasMart, delegate(bool v) { VendorGasMart = v; }, "Stock convenience food in the NATIVE Gas-Mart shop UI (sausage roll, slushee, water). Off applies next session.", isNew: true); Bind(obj, "VendorDiner", () => VendorDiner, delegate(bool v) { VendorDiner = v; }, "Peggy Myers vends at the Slop Shop diner. Off applies next session.", isNew: true); Bind(obj, "VendorCafe", () => VendorCafe, delegate(bool v) { VendorCafe = v; }, "Lily Turner vends at The Butter Box cafe. Off applies next session.", isNew: true); Bind(obj, "VendorSupermarket", () => VendorSupermarket, delegate(bool v) { VendorSupermarket = v; }, "George Greene vends the Supermarket hot counter.", isNew: true); Bind(obj, "VendorLiquor", () => VendorLiquor, delegate(bool v) { VendorLiquor = v; }, "Kim Delaney vends the Liquor Store (incl. the native Chateau La Peepee / Brut du Gloop bottles).", isNew: true); Bind(obj, "VendorCommunity", () => VendorCommunity, delegate(bool v) { VendorCommunity = v; }, "Doris Lubbin vends the Community Center bake sale.", isNew: true); Bind(obj, "VendorPizzeria", () => VendorPizzeria, delegate(bool v) { VendorPizzeria = v; }, "Ludwig Meyer vends Sauerkraut Supreme.", isNew: true); Bind(obj, "VendorChinese", () => VendorChinese, delegate(bool v) { VendorChinese = v; }, "Mrs. Ming vends the Chinese restaurant counter.", isNew: true); Bind(obj, "VendorFrench", () => VendorFrench, delegate(bool v) { VendorFrench = v; }, "Louis Fourier vends Les Ordures Puantes.", isNew: true); Bind(obj, "VendorCanary", () => VendorCanary, delegate(bool v) { VendorCanary = v; }, "Carl Bundy vends The Crimson Canary bar.", isNew: true); Bind(obj, "VendorMotel", () => VendorMotel, delegate(bool v) { VendorMotel = v; }, "Donna Martin vends the Motel Office lobby (the early-game safety net).", isNew: true); Bind(obj, "VendorBait", () => VendorBait, delegate(bool v) { VendorBait = v; }, "Randy Caulfield vends Randy's Bait & Tackle.", isNew: true); Bind(obj, "VendorChurch", () => VendorChurch, delegate(bool v) { VendorChurch = v; }, "Pearl Moore's FREE church food bank (the anti-soft-lock floor).", isNew: true); Bind(obj, "HoursTacos", () => HoursTacos, delegate(string v) { HoursTacos = v; }, "Kyle's selling hours, game-clock HHMM-HHMM (canon shift 07:27-22:01). 'always' = never closed. Bad values fail open.", isNew: true); Bind(obj, "HoursDiner", () => HoursDiner, delegate(string v) { HoursDiner = v; }, "Slop Shop hours, HHMM-HHMM game time. May wrap midnight. 'always' = never closed.", isNew: true); Bind(obj, "HoursCommunity", () => HoursCommunity, delegate(string v) { HoursCommunity = v; }, "Community Center hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "HoursSupermarket", () => HoursSupermarket, delegate(string v) { HoursSupermarket = v; }, "Supermarket hot-counter hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "HoursLiquor", () => HoursLiquor, delegate(string v) { HoursLiquor = v; }, "Liquor Store hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "HoursCafe", () => HoursCafe, delegate(string v) { HoursCafe = v; }, "The Butter Box cafe hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "HoursPizzeria", () => HoursPizzeria, delegate(string v) { HoursPizzeria = v; }, "Sauerkraut Supreme hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "HoursChinese", () => HoursChinese, delegate(string v) { HoursChinese = v; }, "Chinese restaurant hours. Canon default 'always' (the counter never closes).", isNew: true); Bind(obj, "HoursFrench", () => HoursFrench, delegate(string v) { HoursFrench = v; }, "Les Ordures Puantes dinner service, HHMM-HHMM game time (wraps midnight).", isNew: true); Bind(obj, "HoursCanary", () => HoursCanary, delegate(string v) { HoursCanary = v; }, "The Crimson Canary bar hours, HHMM-HHMM game time (wraps midnight).", isNew: true); Bind(obj, "HoursMotel", () => HoursMotel, delegate(string v) { HoursMotel = v; }, "Motel Office hours. Default 'always' (the early-game safety net stays open).", isNew: true); Bind(obj, "HoursBait", () => HoursBait, delegate(string v) { HoursBait = v; }, "Randy's Bait & Tackle hours, HHMM-HHMM game time (overnight, wraps midnight).", isNew: true); Bind(obj, "HoursChurch", () => HoursChurch, delegate(string v) { HoursChurch = v; }, "Church hall food-bank hours, HHMM-HHMM game time.", isNew: true); Bind(obj, "VendorDanDish", () => VendorDanDish, delegate(bool v) { VendorDanDish = v; }, "Dan Samwell's homemade lunch at the hardware store: chili if you never admitted to dealing, pan lasagna if you did.", isNew: true); Bind(obj, "DanDishMode", () => DanDishMode, delegate(string v) { DanDishMode = v; }, "auto = use the recorded intro answer (or Dan's one-time re-ask on older saves); 'chili' or 'lasagna' forces that branch.", isNew: true); Bind(obj, "DanChiliPrice", () => DanChiliPrice, delegate(float v) { DanChiliPrice = v; }, "Price of Dan's Homemade Chili.", isNew: true); Bind(obj, "DanLasagnaPrice", () => DanLasagnaPrice, delegate(float v) { DanLasagnaPrice = v; }, "Price of Dan's Homemade Pan Lasagna (the admitted-dealer reward).", isNew: true); Bind(obj, "HoursHardware", () => HoursHardware, delegate(string v) { HoursHardware = v; }, "Dan's Hardware hours, HHMM-HHMM game time (gates the lunch).", isNew: true); Bind(cat, "HungerPerRealMinute", () => HungerPerRealMinute, delegate(float v) { HungerPerRealMinute = v; }, "Hunger lost per real minute of active play (0..25; pauses/menus don't count). Default 2.4 = empty in ~42 min."); Bind(cat, "ThirstPerRealMinute", () => ThirstPerRealMinute, delegate(float v) { ThirstPerRealMinute = v; }, "Thirst lost per real minute of active play (0..25). Default 2.8 = empty in ~36 min."); Bind(cat, "EnergyPerRealMinute", () => EnergyPerRealMinute, delegate(float v) { EnergyPerRealMinute = v; }, "Energy lost per real minute of active play (0..25). Default 2.0 = empty in ~50 min."); Bind(cat, "SprintEnergyFactor", () => SprintEnergyFactor, delegate(float v) { SprintEnergyFactor = v; }, "Energy drain multiplier while sprinting (1..5)."); Bind(cat2, "ThresholdStage1", () => ThresholdStage1, delegate(float v) { ThresholdStage1 = v; }, "Below this fullness (0..100): Peckish / Thirsty / Weary."); Bind(cat2, "ThresholdStage2", () => ThresholdStage2, delegate(float v) { ThresholdStage2 = v; }, "Below this (0..Stage1): Hungry / Parched / Exhausted — light penalties begin."); Bind(cat2, "ThresholdStage3", () => ThresholdStage3, delegate(float v) { ThresholdStage3 = v; }, "Below this (0..Stage2): Starving / Dehydrated / Delirious — heavy penalties."); Bind(cat2, "SprintBlockBelow", () => SprintBlockBelow, delegate(float v) { SprintBlockBelow = v; }, "Sprint is disabled when the worst of hunger/thirst drops below this (0..100)."); Bind(cat3, "LethalStarvation", () => LethalStarvation, delegate(bool v) { LethalStarvation = v; }, "true = starvation/dehydration can kill. false = health never drained below HealthFloor."); Bind(cat3, "HungerSpeedStage2", () => HungerSpeedStage2, delegate(float v) { HungerSpeedStage2 = v; }, "Move-speed multiplier while Hungry (0.3..1)."); Bind(cat3, "HungerSpeedStage3", () => HungerSpeedStage3, delegate(float v) { HungerSpeedStage3 = v; }, "Move-speed multiplier while Starving (0.3..1)."); Bind(cat3, "ThirstCritSpeedFactor", () => ThirstCritSpeedFactor, delegate(float v) { ThirstCritSpeedFactor = v; }, "Extra move-speed multiplier while Dehydrated (0.3..1).", isNew: true); Bind(cat3, "ThirstStaminaStage2", () => ThirstStaminaStage2, delegate(float v) { ThirstStaminaStage2 = v; }, "Stamina reserve cap factor while Parched (0.1..1)."); Bind(cat3, "ThirstStaminaStage3", () => ThirstStaminaStage3, delegate(float v) { ThirstStaminaStage3 = v; }, "Stamina reserve cap factor while Dehydrated (0.1..1)."); Bind(cat3, "EnergySpeedStage2", () => EnergySpeedStage2, delegate(float v) { EnergySpeedStage2 = v; }, "Move-speed multiplier while Exhausted (0.3..1)."); Bind(cat3, "EnergySpeedStage3", () => EnergySpeedStage3, delegate(float v) { EnergySpeedStage3 = v; }, "Move-speed multiplier while Delirious (0.3..1)."); Bind(cat3, "HealthDrainHungerPerMin", () => HealthDrainHungerPerMin, delegate(float v) { HealthDrainHungerPerMin = v; }, "HP lost per real minute at 0 hunger (0..20)."); Bind(cat3, "HealthDrainThirstPerMin", () => HealthDrainThirstPerMin, delegate(float v) { HealthDrainThirstPerMin = v; }, "HP lost per real minute at 0 thirst (0..20)."); Bind(cat3, "HealthFloor", () => HealthFloor, delegate(float v) { HealthFloor = v; }, "Health is never drained below this (0..100) unless LethalStarvation."); Bind(cat3, "EyelidsEnabled", () => EyelidsEnabled, delegate(bool v) { EyelidsEnabled = v; }, "Drive the game's drowsy-eyelids overlay (droop + microsleep blinks) when tired."); Bind(cat3, "EyelidDroopExhausted", () => EyelidDroopExhausted, delegate(float v) { EyelidDroopExhausted = v; }, "Eyelid open multiplier while Exhausted (0.05..1; lower = droopier).", isNew: true); Bind(cat3, "EyelidDroopDelirious", () => EyelidDroopDelirious, delegate(float v) { EyelidDroopDelirious = v; }, "Eyelid open multiplier while Delirious (0.05..1).", isNew: true); Bind(cat3, "MicrosleepBlinkSeconds", () => MicrosleepBlinkSeconds, delegate(float v) { MicrosleepBlinkSeconds = v; }, "Length of an involuntary microsleep blink while Delirious (0.1..3 s).", isNew: true); Bind(cat3, "MicrosleepMinGap", () => MicrosleepMinGap, delegate(float v) { MicrosleepMinGap = v; }, "Seconds between microsleep blinks at rock-bottom energy (3+).", isNew: true); Bind(cat3, "MicrosleepMaxGap", () => MicrosleepMaxGap, delegate(float v) { MicrosleepMaxGap = v; }, "Seconds between microsleep blinks when barely Delirious (>= MinGap).", isNew: true); Bind(cat4, "SleepRestorePerHour", () => SleepRestorePerHour, delegate(float v) { SleepRestorePerHour = v; }, "Energy restored per hour slept (0..50; 12.5 = a full 8h night refills completely)."); Bind(cat4, "LateSleepQuality", () => LateSleepQuality, delegate(float v) { LateSleepQuality = v; }, "Sleep-restore factor (0..1) when you go to bed after LateSleepAfterHour."); Bind(cat4, "LateSleepAfterHour", () => LateSleepAfterHour, delegate(float v) { LateSleepAfterHour = v; }, "Bed time at/after this AM hour (0..6) counts as a late night.", isNew: true); Bind(cat4, "SleepHungerCost", () => SleepHungerCost, delegate(float v) { SleepHungerCost = v; }, "One-time hunger cost (0..100) applied when you wake up after sleeping."); Bind(cat4, "SleepThirstCost", () => SleepThirstCost, delegate(float v) { SleepThirstCost = v; }, "One-time thirst cost (0..100) applied when you wake up after sleeping."); Bind(cat4, "CollapseEnabled", () => CollapseEnabled, delegate(bool v) { CollapseEnabled = v; }, "Pass out after sustained zero energy (warned twice; never lethal)."); Bind(cat4, "CollapseDelaySeconds", () => CollapseDelaySeconds, delegate(float v) { CollapseDelaySeconds = v; }, "Seconds at zero energy before you collapse (min 30)."); Bind(cat4, "CollapseRestoreTo", () => CollapseRestoreTo, delegate(float v) { CollapseRestoreTo = v; }, "Energy (0..100) after a collapse."); Bind(cat4, "CollapseCashPenalty", () => CollapseCashPenalty, delegate(bool v) { CollapseCashPenalty = v; }, "Collapsing away from your own property loses some cash on hand."); Bind(cat4, "CollapseCashFraction", () => CollapseCashFraction, delegate(float v) { CollapseCashFraction = v; }, "Fraction of cash (0..1) lost on an away-collapse."); Bind(cat4, "CollapseCashCap", () => CollapseCashCap, delegate(float v) { CollapseCashCap = v; }, "Maximum cash lost on an away-collapse (0+)."); Bind(cat4, "WiredMinEnergyRestore", () => WiredMinEnergyRestore, delegate(float v) { WiredMinEnergyRestore = v; }, "Consumables restoring at least this much energy (0..100) also grant the Wired buff."); Bind(cat4, "WiredDurationSeconds", () => WiredDurationSeconds, delegate(float v) { WiredDurationSeconds = v; }, "Wired buff duration in real seconds of play (0+)."); Bind(cat4, "WiredDrainFactor", () => WiredDrainFactor, delegate(float v) { WiredDrainFactor = v; }, "Energy drain multiplier while Wired (0.1..1)."); Bind(cat5, "ConsumeIngredientsForEffects", () => ConsumeIngredientsForEffects, delegate(bool v) { ConsumeIngredientsForEffects = v; }, "Drug-making ingredients can be consumed directly, applying the effect they'd give a mix. Off applies at next save load.", isNew: true); Bind(cat5, "IngredientEffectSeconds", () => IngredientEffectSeconds, delegate(float v) { IngredientEffectSeconds = v; }, "Duration (10..600 s) of an effect gained by eating the ingredient raw.", isNew: true); Bind(cat5, "DrugMinMult", () => DrugMinMult, delegate(float v) { DrugMinMult = v; }, "Floor for the combined drug depletion multiplier (0.1..1)."); Bind(cat5, "DrugMaxMult", () => DrugMaxMult, delegate(float v) { DrugMaxMult = v; }, "Ceiling for the combined drug depletion multiplier (1..10)."); Bind(cat5, "StimKickEnergy", () => StimKickEnergy, delegate(float v) { StimKickEnergy = v; }, "Instant energy (0..100) when a strong stimulant high lands."); Bind(cat5, "StimKickMildFactor", () => StimKickMildFactor, delegate(float v) { StimKickMildFactor = v; }, "Mild stimulants give this fraction (0..1) of StimKickEnergy.", isNew: true); Bind(cat5, "StimStrongThreshold", () => StimStrongThreshold, delegate(float v) { StimStrongThreshold = v; }, "Energy-rate multiplier at/below which a stim counts as STRONG (0.1..1; strong = full kick, crash, collapse reset).", isNew: true); Bind(cat5, "StimMildThreshold", () => StimMildThreshold, delegate(float v) { StimMildThreshold = v; }, "Energy-rate multiplier below which a stim counts as MILD (StimStrongThreshold..1).", isNew: true); Bind(cat5, "StimCrashEnabled", () => StimCrashEnabled, delegate(bool v) { StimCrashEnabled = v; }, "Strong stimulants cost energy when the high wears off (the crash)."); Bind(cat5, "StimCrashCost", () => StimCrashCost, delegate(float v) { StimCrashCost = v; }, "Energy lost in a stimulant crash (0..100)."); Bind(cat5, "EffectRates", () => EffectRatesRaw, delegate(string v) { EffectRatesRaw = v; }, "Effect=hunger/thirst/energy rate multipliers per drug effect; 1.0 = neutral. Unknown names are ignored."); Bind(cat5, "DrugTypeRates", () => DrugTypeRatesRaw, delegate(string v) { DrugTypeRatesRaw = v; }, "DrugType=hunger/thirst/energy base multipliers (Marijuana, Methamphetamine, Cocaine, MDMA, Shrooms, Heroin)."); Bind(cat6, "FoodMap", () => FoodMapRaw, delegate(string v) { FoodMapRaw = v; }, "itemId=hunger/thirst/energy restore triples separated by ';'. Values live-reload; brand-new ids wire on the next preferences save or session."); Bind(cat6, "AutoMapUnknownConsumables", () => AutoMapUnknownConsumables, delegate(bool v) { AutoMapUnknownConsumables = v; }, "Give unmapped food-named Ingredient/Consumable items a default restore value."); Bind(cat6, "DefaultUnknownHunger", () => DefaultUnknownHunger, delegate(float v) { DefaultUnknownHunger = v; }, "Hunger restored by auto-mapped consumables (0..100)."); Bind(cat6, "DefaultUnknownThirst", () => DefaultUnknownThirst, delegate(float v) { DefaultUnknownThirst = v; }, "Thirst restored by auto-mapped consumables (0..100)."); Bind(cat6, "DefaultUnknownEnergy", () => DefaultUnknownEnergy, delegate(float v) { DefaultUnknownEnergy = v; }, "Energy restored by auto-mapped consumables (0..100)."); Bind(cat6, "PreserveDrugEffects", () => PreserveDrugEffects, delegate(bool v) { PreserveDrugEffects = v; }, "Food and drink satisfy needs only — they never clear or replace your active high."); Bind(cat6, "GasolineDrinkable", () => GasolineDrinkable, delegate(bool v) { GasolineDrinkable = v; }, "Gasoline can be drunk. It drops you. Turning OFF mid-session applies at the next save load.", isNew: true); Bind(cat6, "GasolineLethal", () => GasolineLethal, delegate(bool v) { GasolineLethal = v; }, "true = drinking gasoline kills you. false = near-lethal knockout (health floored, blackout).", isNew: true); Bind(val, "TacoPrice", () => TacoPrice, delegate(float v) { TacoPrice = v; }, "Beef Taco price (1+). Registry prices update live; Kyle's spiel re-bakes next session."); Bind(val, "TacoPriceChicken", () => TacoPriceChicken, delegate(float v) { TacoPriceChicken = v; }, "Chicken Taco price (1+)."); Bind(val, "TacoPriceVeggie", () => TacoPriceVeggie, delegate(float v) { TacoPriceVeggie = v; }, "Veggie Taco price (1+)."); Bind(val, "TacoPriceMystery", () => TacoPriceMystery, delegate(float v) { TacoPriceMystery = v; }, "Mystery Meat Taco price (1+). Convenience-store shelf; cheap and sketchy by design."); Bind(val, "TacoPriceKyleSpecial", () => TacoPriceKyleSpecial, delegate(float v) { TacoPriceKyleSpecial = v; }, "Kyle's Special price (1+). The one with all the white sauce.", isNew: true); Bind(val, "TacoPriceManuke", () => TacoPriceManuke, delegate(float v) { TacoPriceManuke = v; }, "The Manuke Taco price (1+). Kyle's premium option; deliberately exempt from the 18/21 policy.", isNew: true); Bind(val, "ManukeSatietySeconds", () => ManukeSatietySeconds, delegate(float v) { ManukeSatietySeconds = v; }, "Duration (0..3600 s) of the sits-well buff after a Manuke Taco. 0 disables.", isNew: true); Bind(val, "ManukeSatietyDrainFactor", () => ManukeSatietyDrainFactor, delegate(float v) { ManukeSatietyDrainFactor = v; }, "Hunger drain multiplier (0.1..1) while the Manuke buff runs (lower = stronger).", isNew: true); Bind(val, "BurroitoEnabled", () => BurroitoEnabled, delegate(bool v) { BurroitoEnabled = v; }, "Kyle (reluctantly) sells The Big Burroito (tm): a one-time purchase granting a permanent move-speed bonus.", isNew: true); Bind(val, "BurroitoPrice", () => BurroitoPrice, delegate(float v) { BurroitoPrice = v; }, "The Big Burroito (tm)'s one-time price (1+).", isNew: true); Bind(val, "BurroitoSpeedBonus", () => BurroitoSpeedBonus, delegate(float v) { BurroitoSpeedBonus = v; }, "Permanent move-speed bonus once The Big Burroito (tm) is owned (0..0.5; 0.1 = +10%).", isNew: true); Bind(val, "MysteryTacoBadChance", () => MysteryTacoBadChance, delegate(float v) { MysteryTacoBadChance = v; }, "Chance (0..1) a Mystery Taco turns on you. 0 = always safe, 1 = always bad."); Bind(val, "KyleTacoBadChance", () => KyleTacoBadChance, delegate(float v) { KyleTacoBadChance = v; }, "Chance (0..1) KYLE'S SPECIAL turns on you (beef/chicken/veggie are always safe). Default 0.05.", isNew: true); Bind(val, "ManukeTacoBadChance", () => ManukeTacoBadChance, delegate(float v) { ManukeTacoBadChance = v; }, "Chance (0..1) the $420 Manuke turns on you. Default 0 — premium food is excluded from the gamble.", isNew: true); Bind(val, "VeganTacoEnabled", () => VeganTacoEnabled, delegate(bool v) { VeganTacoEnabled = v; }, "Kyle's vegan taco option (what he sells you is... plant-based). Off applies next session.", isNew: true); Bind(val, "VeganTacoPrice", () => VeganTacoPrice, delegate(float v) { VeganTacoPrice = v; }, "Price of the vegan taco (1+). Default 5.", isNew: true); Bind(val, "MysteryHungerLossFraction", () => MysteryHungerLossFraction, delegate(float v) { MysteryHungerLossFraction = v; }, "Share (0..1) of the Mystery Taco's restore clawed back on a bad roll.", isNew: true); Bind(val, "MysteryCrookGutsSeconds", () => MysteryCrookGutsSeconds, delegate(float v) { MysteryCrookGutsSeconds = v; }, "Length (0..600 s) of the queasy spell after a bad taco. 0 disables it.", isNew: true); Bind(val, "CrookGutsSpeedFactor", () => CrookGutsSpeedFactor, delegate(float v) { CrookGutsSpeedFactor = v; }, "Move-speed multiplier (0.3..1) during the queasy spell.", isNew: true); Bind(val, "TacoSatietySeconds", () => TacoSatietySeconds, delegate(float v) { TacoSatietySeconds = v; }, "Duration (0..3600 s) of the sits-well buff after a good taco. 0 disables."); Bind(val, "TacoSatietyDrainFactor", () => TacoSatietyDrainFactor, delegate(float v) { TacoSatietyDrainFactor = v; }, "Hunger drain multiplier (0.1..1) while the sits-well buff is active."); Bind(cat7, "ConsumeSoundVolume", () => ConsumeSoundVolume, delegate(float v) { ConsumeSoundVolume = v; }, "Consume sound volume (0..1)."); Bind(cat7, "EatPitchVariance", () => EatPitchVariance, delegate(float v) { EatPitchVariance = v; }, "Random pitch spread on bite sounds (0..0.5), centred on normal pitch. 0 = every bite identical.", isNew: true); Bind(cat7, "EatClipName", () => EatClipName, delegate(string v) { EatClipName = v; }, "Exact name of a native AudioClip to use as the eat sound (see '[Audio] candidate clip' log lines); empty = the bundled pool."); Bind(cat8, "HudCorner", () => HudCorner, delegate(string v) { HudCorner = v; }, "BottomLeft, BottomRight, TopLeft or TopRight."); Bind(cat8, "HudOffsetX", () => HudOffsetX, delegate(float v) { HudOffsetX = v; }, "Horizontal inset from the chosen corner, px (0..2000)."); Bind(cat8, "HudOffsetY", () => HudOffsetY, delegate(float v) { HudOffsetY = v; }, "Vertical inset from the chosen corner, px (0..2000)."); Bind(cat8, "HudScale", () => HudScale, delegate(float v) { HudScale = v; }, "Overall HUD scale (0.5..2.5)."); Bind(cat8, "HudFadeWhenFine", () => HudFadeWhenFine, delegate(bool v) { HudFadeWhenFine = v; }, "Dim the meters while you are fine and fed."); Bind(cat8, "HudFadeAlpha", () => HudFadeAlpha, delegate(float v) { HudFadeAlpha = v; }, "Meter opacity (0..1) while dimmed by HudFadeWhenFine.", isNew: true); Bind(cat8, "ShowNumbers", () => ShowNumbers, delegate(bool v) { ShowNumbers = v; }, "Show a percentage on each meter's label while it is Fine (stage words still take over when low).", isNew: true); Bind(cat8, "ToastSeconds", () => ToastSeconds, delegate(float v) { ToastSeconds = v; }, "How long each toast line stays up (1..15 s).", isNew: true); Bind(cat8, "HudColorFood", () => HudColorFood, delegate(string v) { HudColorFood = v; }, "Food bar hex color while healthy (RRGGBB).", isNew: true); Bind(cat8, "HudColorFoodLow", () => HudColorFoodLow, delegate(string v) { HudColorFoodLow = v; }, "Food bar hex color at the warning stage.", isNew: true); Bind(cat8, "HudColorFoodCrit", () => HudColorFoodCrit, delegate(string v) { HudColorFoodCrit = v; }, "Food bar hex color at the critical stage.", isNew: true); Bind(cat8, "HudColorWater", () => HudColorWater, delegate(string v) { HudColorWater = v; }, "Water bar hex color while healthy.", isNew: true); Bind(cat8, "HudColorWaterLow", () => HudColorWaterLow, delegate(string v) { HudColorWaterLow = v; }, "Water bar hex color at the warning stage.", isNew: true); Bind(cat8, "HudColorWaterCrit", () => HudColorWaterCrit, delegate(string v) { HudColorWaterCrit = v; }, "Water bar hex color at the critical stage.", isNew: true); Bind(cat8, "HudColorEnergy", () => HudColorEnergy, delegate(string v) { HudColorEnergy = v; }, "Energy bar hex color while healthy.", isNew: true); Bind(cat8, "HudColorEnergyLow", () => HudColorEnergyLow, delegate(string v) { HudColorEnergyLow = v; }, "Energy bar hex color at the warning stage.", isNew: true); Bind(cat8, "HudColorEnergyCrit", () => HudColorEnergyCrit, delegate(string v) { HudColorEnergyCrit = v; }, "Energy bar hex color at the critical stage.", isNew: true); _configVersion = obj.CreateEntry("ConfigVersion", 0, (string)null, "Internal: config layout version. Do not edit.", false, false, (ValueValidator)null, (string)null); int value = _configVersion.Value; if (value < 1) { MigrateLegacyConfig(); } if (value < 2) { MigrateBurroitoKeys(val); } if (value < 2) { _configVersion.Value = 2; } Reload(); MelonPreferences.Save(); ScrubLegacySection(); } private static void EnsureFoodMapCoverage() { try { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string[] array = (FoodMapRaw ?? "").Split(';', StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { hashSet.Add(text.Substring(0, num).Trim()); } } List list = null; array = "cuke=2/30/10;energydrink=0/20/30;banana=25/3/5;donut=40/0/10;chili=18/0/0;megabean=30/5/0;mouthwash=0/-5/0;taco=45/5/0;tacochicken=38/5/0;tacoveggie=28/8/0;tacomystery=50/0/0;tacomanuke=60/10/0;tacokylespecial=52/8/0;gasoline=0/0/0;burroito=70/10/0;sausageroll=32/0/0;slushee=0/35/8;brekkieroll=42/5/0;dinercoffee=0/25/12;croissant=26/2/0;bottledwater=0/40/0;theslop=55/0/-5;urncoffee=0/24/14;bakebrownie=24/-4/4;tunasando=30/0/0;rotisserie=60/-5/0;delisando=36/0/0;instantramen=28/10/0;tallboy=3/26/-10;boxedwine=4/45/-25;chateaulapeepee=2/35/-20;brutdugloop=2/35/-20;flatwhite=0/26/16;almonddanish=28/-2/5;onionsoup=32/20/0;steakfrites=68/-6/0;cremebrulee=30/4/8;krautslice=30/-8/0;pretzelbrat=40/-6/0;weissbier=6/28/-10;porkbun=22/3/0;mingchicken=50/-8/5;jasminetea=0/30/8;vodkasoda=0/26/-14;canarycocktail=2/30/-18;coatespresso=0/18/22;lobbycoffee=0/20/14;vendingsando=30/0/0;noodlecup=28/10/0;thermoscoffee=0/22/16;smokedfish=34/-8/0;fishnchips=48/-8/0;churchcoffee=8/20/10;soupbowl=40/15/0;danchili=52/6/0;danlasagna=64/4/0".Split(';', StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { int num2 = text2.IndexOf('='); if (num2 > 0 && !hashSet.Contains(text2.Substring(0, num2).Trim())) { List obj = list ?? new List(); list = obj; obj.Add(text2.Trim()); } } if (list != null) { FoodMapRaw = (FoodMapRaw ?? "").TrimEnd(';') + ";" + string.Join(";", list); TrySetEntry("FoodMap", FoodMapRaw); MelonLogger.Msg($"[Config] FoodMap healed — {list.Count} missing default entr(ies) appended: {string.Join(", ", list)}"); } } catch (Exception ex) { MelonLogger.Warning("[Config] FoodMap heal failed: " + ex.Message); } } private static void MigrateLegacyConfig() { try { string path = Path.Combine(MelonEnvironment.UserDataDirectory, "MelonPreferences.cfg"); bool flag = false; try { flag = File.Exists(path) && File.ReadAllText(path).Contains("[S1HungerThirst]"); } catch { } if (!flag) { MelonLogger.Msg("[Config] no legacy [S1HungerThirst] section — migration skipped (fresh install)."); return; } MelonPreferences_Category obj2 = MelonPreferences.CreateCategory("S1HungerThirst", "Hunger & Thirst (legacy)"); foreach (Action migrator in _migrators) { migrator(obj2); } _legacyMigrated = true; MelonLogger.Msg($"[Config] migrated {_migrators.Count} value(s) from the legacy [S1HungerThirst] section into the new grouped sections."); } catch (Exception ex) { MelonLogger.Warning("[Config] legacy migration failed (defaults in effect): " + ex.Message); } } private static void ScrubLegacySection() { if (!_legacyMigrated) { return; } try { MelonPreferences.RemoveCategoryFromFile(Path.Combine(MelonEnvironment.UserDataDirectory, "MelonPreferences.cfg"), "S1HungerThirst"); MelonLogger.Msg("[Config] legacy [S1HungerThirst] section scrubbed from the cfg."); } catch { MelonLogger.Msg("[Config] legacy section left in place (inert; safe to delete by hand)."); } } private static void MigrateBurroitoKeys(MelonPreferences_Category tacos) { try { (string, string)[] obj = new(string, string)[3] { ("BorritoEnabled", "BurroitoEnabled"), ("BorritoPrice", "BurroitoPrice"), ("BorritoSpeedBonus", "BurroitoSpeedBonus") }; int num = 0; (string, string)[] array = obj; for (int i = 0; i < array.Length; i++) { var (text, b) = array[i]; foreach (Setting setting in Settings) { if (string.Equals(setting.Key, b, StringComparison.OrdinalIgnoreCase)) { if (setting.Entry is MelonPreferences_Entry val) { MelonPreferences_Entry val2 = tacos.CreateEntry(text, val.Value, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); val.Value = val2.Value; } if (setting.Entry is MelonPreferences_Entry val3) { MelonPreferences_Entry val4 = tacos.CreateEntry(text, val3.Value, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); val3.Value = val4.Value; } try { tacos.DeleteEntry(text); } catch { } num++; break; } } } if (num > 0) { MelonLogger.Msg($"[Config] Borrito->Burroito key migration: {num} value(s) carried over."); } } catch (Exception ex) { MelonLogger.Warning("[Config] Burroito key migration failed (defaults in effect): " + ex.Message); } } private static void Bind(MelonPreferences_Category cat, string key, Func get, Action set, string desc, bool isNew = false) { MelonPreferences_Entry e = cat.CreateEntry(key, get(), (string)null, desc, false, false, (ValueValidator)null, (string)null); _pullers.Add(delegate { set(e.Value); }); Register(cat, key, desc, (MelonPreferences_Entry)(object)e); if (!isNew) { _migrators.Add(delegate(MelonPreferences_Category legacy) { MelonPreferences_Entry val = legacy.CreateEntry(key, e.Value, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); e.Value = val.Value; }); } } private static void Bind(MelonPreferences_Category cat, string key, Func get, Action set, string desc, bool isNew = false) { MelonPreferences_Entry e = cat.CreateEntry(key, get(), (string)null, desc, false, false, (ValueValidator)null, (string)null); _pullers.Add(delegate { set(e.Value); }); Register(cat, key, desc, (MelonPreferences_Entry)(object)e); if (!isNew) { _migrators.Add(delegate(MelonPreferences_Category legacy) { MelonPreferences_Entry val = legacy.CreateEntry(key, e.Value, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); e.Value = val.Value; }); } } private static void Bind(MelonPreferences_Category cat, string key, Func get, Action set, string desc, bool isNew = false) { MelonPreferences_Entry e = cat.CreateEntry(key, get(), (string)null, desc, false, false, (ValueValidator)null, (string)null); _pullers.Add(delegate { set(e.Value); }); Register(cat, key, desc, (MelonPreferences_Entry)(object)e); if (!isNew) { _migrators.Add(delegate(MelonPreferences_Category legacy) { MelonPreferences_Entry val = legacy.CreateEntry(key, e.Value, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); e.Value = val.Value; }); } } public static void Reload() { //IL_06b3: Unknown result type (might be due to invalid IL or missing references) //IL_06b8: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Unknown result type (might be due to invalid IL or missing references) //IL_06db: Unknown result type (might be due to invalid IL or missing references) //IL_06e0: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_06f4: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_0717: Unknown result type (might be due to invalid IL or missing references) //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) //IL_0730: Unknown result type (might be due to invalid IL or missing references) //IL_073f: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_0753: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) foreach (Action puller in _pullers) { puller(); } EnsureFoodMapCoverage(); HungerPerRealMinute = Mathf.Clamp(HungerPerRealMinute, 0f, 25f); ThirstPerRealMinute = Mathf.Clamp(ThirstPerRealMinute, 0f, 25f); EnergyPerRealMinute = Mathf.Clamp(EnergyPerRealMinute, 0f, 25f); SprintEnergyFactor = Mathf.Clamp(SprintEnergyFactor, 1f, 5f); ThresholdStage1 = Mathf.Clamp(ThresholdStage1, 1f, 100f); ThresholdStage2 = Mathf.Clamp(ThresholdStage2, 0f, ThresholdStage1); ThresholdStage3 = Mathf.Clamp(ThresholdStage3, 0f, ThresholdStage2); SprintBlockBelow = Mathf.Clamp(SprintBlockBelow, 0f, 100f); HungerSpeedStage2 = Mathf.Clamp(HungerSpeedStage2, 0.3f, 1f); HungerSpeedStage3 = Mathf.Clamp(HungerSpeedStage3, 0.3f, 1f); ThirstCritSpeedFactor = Mathf.Clamp(ThirstCritSpeedFactor, 0.3f, 1f); ThirstStaminaStage2 = Mathf.Clamp(ThirstStaminaStage2, 0.1f, 1f); ThirstStaminaStage3 = Mathf.Clamp(ThirstStaminaStage3, 0.1f, 1f); EnergySpeedStage2 = Mathf.Clamp(EnergySpeedStage2, 0.3f, 1f); EnergySpeedStage3 = Mathf.Clamp(EnergySpeedStage3, 0.3f, 1f); HealthDrainHungerPerMin = Mathf.Clamp(HealthDrainHungerPerMin, 0f, 20f); HealthDrainThirstPerMin = Mathf.Clamp(HealthDrainThirstPerMin, 0f, 20f); HealthFloor = Mathf.Clamp(HealthFloor, 0f, 100f); EyelidDroopExhausted = Mathf.Clamp(EyelidDroopExhausted, 0.05f, 1f); EyelidDroopDelirious = Mathf.Clamp(EyelidDroopDelirious, 0.05f, 1f); MicrosleepBlinkSeconds = Mathf.Clamp(MicrosleepBlinkSeconds, 0.1f, 3f); MicrosleepMinGap = Mathf.Max(3f, MicrosleepMinGap); MicrosleepMaxGap = Mathf.Max(MicrosleepMinGap, MicrosleepMaxGap); SleepRestorePerHour = Mathf.Clamp(SleepRestorePerHour, 0f, 50f); LateSleepQuality = Mathf.Clamp01(LateSleepQuality); LateSleepAfterHour = Mathf.Clamp(LateSleepAfterHour, 0f, 6f); SleepHungerCost = Mathf.Clamp(SleepHungerCost, 0f, 100f); SleepThirstCost = Mathf.Clamp(SleepThirstCost, 0f, 100f); CollapseDelaySeconds = Mathf.Max(30f, CollapseDelaySeconds); CollapseRestoreTo = Mathf.Clamp(CollapseRestoreTo, 0f, 100f); CollapseCashFraction = Mathf.Clamp01(CollapseCashFraction); CollapseCashCap = Mathf.Max(0f, CollapseCashCap); WiredMinEnergyRestore = Mathf.Clamp(WiredMinEnergyRestore, 0f, 100f); WiredDurationSeconds = Mathf.Max(0f, WiredDurationSeconds); WiredDrainFactor = Mathf.Clamp(WiredDrainFactor, 0.1f, 1f); IngredientEffectSeconds = Mathf.Clamp(IngredientEffectSeconds, 10f, 600f); DrugMinMult = Mathf.Clamp(DrugMinMult, 0.1f, 1f); DrugMaxMult = Mathf.Clamp(DrugMaxMult, 1f, 10f); StimKickEnergy = Mathf.Clamp(StimKickEnergy, 0f, 100f); StimKickMildFactor = Mathf.Clamp01(StimKickMildFactor); StimStrongThreshold = Mathf.Clamp(StimStrongThreshold, 0.1f, 1f); StimMildThreshold = Mathf.Clamp(StimMildThreshold, StimStrongThreshold, 1f); StimCrashCost = Mathf.Clamp(StimCrashCost, 0f, 100f); DefaultUnknownHunger = Mathf.Clamp(DefaultUnknownHunger, 0f, 100f); DefaultUnknownThirst = Mathf.Clamp(DefaultUnknownThirst, 0f, 100f); DefaultUnknownEnergy = Mathf.Clamp(DefaultUnknownEnergy, 0f, 100f); TacoPrice = Mathf.Max(1f, TacoPrice); TacoPriceChicken = Mathf.Max(1f, TacoPriceChicken); TacoPriceVeggie = Mathf.Max(1f, TacoPriceVeggie); TacoPriceMystery = Mathf.Max(1f, TacoPriceMystery); TacoPriceKyleSpecial = Mathf.Max(1f, TacoPriceKyleSpecial); TacoPriceManuke = Mathf.Max(1f, TacoPriceManuke); BurroitoPrice = Mathf.Max(1f, BurroitoPrice); BurroitoSpeedBonus = Mathf.Clamp(BurroitoSpeedBonus, 0f, 0.5f); ManukeSatietySeconds = Mathf.Clamp(ManukeSatietySeconds, 0f, 3600f); ManukeSatietyDrainFactor = Mathf.Clamp(ManukeSatietyDrainFactor, 0.1f, 1f); MysteryTacoBadChance = Mathf.Clamp01(MysteryTacoBadChance); KyleTacoBadChance = Mathf.Clamp01(KyleTacoBadChance); ManukeTacoBadChance = Mathf.Clamp01(ManukeTacoBadChance); VeganTacoPrice = Mathf.Clamp(VeganTacoPrice, 1f, 100000f); MysteryHungerLossFraction = Mathf.Clamp01(MysteryHungerLossFraction); MysteryCrookGutsSeconds = Mathf.Clamp(MysteryCrookGutsSeconds, 0f, 600f); CrookGutsSpeedFactor = Mathf.Clamp(CrookGutsSpeedFactor, 0.3f, 1f); TacoSatietySeconds = Mathf.Clamp(TacoSatietySeconds, 0f, 3600f); TacoSatietyDrainFactor = Mathf.Clamp(TacoSatietyDrainFactor, 0.1f, 1f); ConsumeSoundVolume = Mathf.Clamp01(ConsumeSoundVolume); EatPitchVariance = Mathf.Clamp(EatPitchVariance, 0f, 0.5f); HudOffsetX = Mathf.Clamp(HudOffsetX, 0f, 2000f); HudOffsetY = Mathf.Clamp(HudOffsetY, 0f, 2000f); HudScale = Mathf.Clamp(HudScale, 0.5f, 2.5f); HudFadeAlpha = Mathf.Clamp01(HudFadeAlpha); ToastSeconds = Mathf.Clamp(ToastSeconds, 1f, 15f); HudColorFoodParsed = ParseHexColor(HudColorFood, 15771964); HudColorFoodLowParsed = ParseHexColor(HudColorFoodLow, 15300142); HudColorFoodCritParsed = ParseHexColor(HudColorFoodCrit, 14694954); HudColorWaterParsed = ParseHexColor(HudColorWater, 5226984); HudColorWaterLowParsed = ParseHexColor(HudColorWaterLow, 3049177); HudColorWaterCritParsed = ParseHexColor(HudColorWaterCrit, 14241852); HudColorEnergyParsed = ParseHexColor(HudColorEnergy, 9403368); HudColorEnergyLowParsed = ParseHexColor(HudColorEnergyLow, 11889353); HudColorEnergyCritParsed = ParseHexColor(HudColorEnergyCrit, 14694954); ConsumableMap.ParseConfigMap(); DrugEffects.ParseConfigMaps(); TacoItem.OnConfigReload(); } public static bool TrySetEntry(string key, object value) { for (int i = 0; i < Settings.Count; i++) { Setting setting = Settings[i]; if (!string.Equals(setting.Key, key, StringComparison.OrdinalIgnoreCase)) { continue; } if (setting.Entry is MelonPreferences_Entry val && value is bool value2) { val.Value = value2; return true; } if (setting.Entry is MelonPreferences_Entry val2) { if (value is float value3) { val2.Value = value3; return true; } if (value is int num) { val2.Value = num; return true; } if (value is double num2) { val2.Value = (float)num2; return true; } } if (setting.Entry is MelonPreferences_Entry val3 && value is string value4) { val3.Value = value4; return true; } return false; } return false; } public static Color ParseHexColor(string s, int fallbackRgb) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) string text = (s ?? "").Trim().TrimStart('#'); if (text.Length == 6 && int.TryParse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { return new Color((float)((result >> 16) & 0xFF) / 255f, (float)((result >> 8) & 0xFF) / 255f, (float)(result & 0xFF) / 255f, 1f); } return new Color((float)((fallbackRgb >> 16) & 0xFF) / 255f, (float)((fallbackRgb >> 8) & 0xFF) / 255f, (float)(fallbackRgb & 0xFF) / 255f, 1f); } public static float ParseF(string s, float fallback) { if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } } public static class NeedsHud { private sealed class ToastLine { public string Text; public Color Color; public float ExpiresAt; } private static readonly Color PanelBg = new Color(0.055f, 0.06f, 0.085f, 0.72f); private static readonly Color TrackBg = new Color(0.1f, 0.11f, 0.14f, 0.85f); private static readonly Color TextSoft = FromHex(13223357); private static readonly Color TextMain = FromHex(16118508); private static readonly Color BadgeFast = FromHex(16736074); private static readonly Color BadgeSlow = FromHex(8378474); public static readonly Color ToastGood = FromHex(12576928); public static readonly Color ToastWarn = FromHex(15905402); public static readonly Color ToastBad = FromHex(15761520); public static readonly Color ToastNeutral = FromHex(13618116); private const float ChipSize = 20f; private const float BarWidth = 148f; private const float BarHeight = 12f; private const float LabelWidth = 52f; private const float RowHeight = 20f; private const float RowGap = 6f; private const float RootWidth = 228f; private const int ToastLines = 5; private const float ToastLineHeight = 17f; private static GameObject _meterRoot; private static GameObject _vignetteGo; private static CanvasGroup _meterGroup; private static Image _vignette; private static Image _foodFill; private static Image _waterFill; private static Image _energyFill; private static Image _foodChipIcon; private static Image _waterChipIcon; private static Image _energyChipIcon; private static Image _foodBadge; private static Image _waterBadge; private static Image _energyBadge; private static TextMeshProUGUI _foodLabel; private static TextMeshProUGUI _waterLabel; private static TextMeshProUGUI _energyLabel; private static Sprite _rounded; private static Sprite _solidBar; private static Sprite _circle; private static Sprite _foodIcon; private static Sprite _waterIcon; private static Sprite _moonIcon; private static Sprite _radial; private static float _foodShown = 100f; private static float _waterShown = 100f; private static float _energyShown = 100f; private static readonly List _toasts = new List(); private static readonly TextMeshProUGUI[] _toastLabels = (TextMeshProUGUI[])(object)new TextMeshProUGUI[5]; private static Color FoodOk => NeedsConfig.HudColorFoodParsed; private static Color FoodLow => NeedsConfig.HudColorFoodLowParsed; private static Color FoodCrit => NeedsConfig.HudColorFoodCritParsed; private static Color WaterOk => NeedsConfig.HudColorWaterParsed; private static Color WaterLow => NeedsConfig.HudColorWaterLowParsed; private static Color WaterCrit => NeedsConfig.HudColorWaterCritParsed; private static Color EnergyOk => NeedsConfig.HudColorEnergyParsed; private static Color EnergyLow => NeedsConfig.HudColorEnergyLowParsed; private static Color EnergyCrit => NeedsConfig.HudColorEnergyCritParsed; private static float ToastLifetime => NeedsConfig.ToastSeconds; public static bool IsBuilt { get { if ((Object)(object)_meterRoot != (Object)null) { return Object.op_Implicit((Object)(object)_meterRoot); } return false; } } private static bool AnyToastVisible => _toasts.Count > 0; public static void EnsureBuilt() { if (IsBuilt || (!NeedsConfig.HudEnabled && !NeedsConfig.ToastsEnabled)) { return; } HUD instance = Singleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.canvas == (Object)null) { return; } try { Build(instance); } catch (Exception value) { MelonLogger.Error($"[HUD] Build failed: {value}"); Teardown(); } } public static void Teardown() { try { if ((Object)(object)_meterRoot != (Object)null) { Object.Destroy((Object)(object)_meterRoot); } if ((Object)(object)_vignetteGo != (Object)null) { Object.Destroy((Object)(object)_vignetteGo); } } catch { } _meterRoot = null; _vignetteGo = null; _foodShown = (_waterShown = 100f); } private static void Build(HUD hud) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00e1: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)hud.canvas).transform; if (!Alive(_rounded)) { _rounded = MakeRoundedRect(); } if (!Alive(_solidBar)) { _solidBar = MakeSolidBar(); } if (!Alive(_circle)) { _circle = MakeCircle(); } if (!Alive(_foodIcon)) { _foodIcon = MakeFoodIcon(); } if (!Alive(_waterIcon)) { _waterIcon = MakeWaterIcon(); } if (!Alive(_moonIcon)) { _moonIcon = MakeMoonIcon(); } if (!Alive(_radial)) { _radial = MakeRadialVignette(); } _vignetteGo = new GameObject("S1HT_Vignette"); _vignetteGo.transform.SetParent(transform, false); _vignetteGo.transform.SetSiblingIndex(0); RectTransform obj = _vignetteGo.AddComponent(); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; _vignette = _vignetteGo.AddComponent(); _vignette.sprite = _radial; ((Graphic)_vignette).color = new Color(0f, 0f, 0f, 0f); ((Graphic)_vignette).raycastTarget = false; _meterRoot = new GameObject("S1HT_Meters"); _meterRoot.transform.SetParent(transform, false); _meterRoot.transform.SetAsLastSibling(); bool hudEnabled = NeedsConfig.HudEnabled; int num = (hudEnabled ? ((NeedsConfig.ThirstEnabled ? 1 : 0) + (NeedsConfig.HungerEnabled ? 1 : 0) + (NeedsConfig.EnergyEnabled ? 1 : 0)) : 0); RectTransform obj2 = _meterRoot.AddComponent(); ApplyCorner(obj2); obj2.sizeDelta = new Vector2(228f, 20f * (float)num + 6f * (float)Mathf.Max(0, num - 1) + 22f); ((Transform)obj2).localScale = Vector3.one * NeedsConfig.HudScale; _meterGroup = _meterRoot.AddComponent(); _meterGroup.interactable = false; _meterGroup.blocksRaycasts = false; TMP_FontAsset val = (((Object)(object)hud.selectedItemLabel != (Object)null) ? ((TMP_Text)hud.selectedItemLabel).font : null); _waterChipIcon = null; _waterFill = null; _waterLabel = null; _waterBadge = null; _foodChipIcon = null; _foodFill = null; _foodLabel = null; _foodBadge = null; _energyChipIcon = null; _energyFill = null; _energyLabel = null; _energyBadge = null; int num2 = 0; if (hudEnabled && NeedsConfig.ThirstEnabled) { BuildRow("Water", 26f * (float)num2++, _waterIcon, WaterOk, val, out _waterChipIcon, out _waterFill, out _waterLabel, out _waterBadge); } if (hudEnabled && NeedsConfig.HungerEnabled) { BuildRow("Food", 26f * (float)num2++, _foodIcon, FoodOk, val, out _foodChipIcon, out _foodFill, out _foodLabel, out _foodBadge); } if (hudEnabled && NeedsConfig.EnergyEnabled) { BuildRow("Energy", 26f * (float)num2++, _moonIcon, EnergyOk, val, out _energyChipIcon, out _energyFill, out _energyLabel, out _energyBadge); } float num3 = 20f * (float)num + 6f * (float)Mathf.Max(0, num - 1) + 6f; Vector2 val3 = default(Vector2); for (int i = 0; i < 5; i++) { GameObject val2 = new GameObject($"S1HT_Toast{i}"); val2.transform.SetParent(_meterRoot.transform, false); RectTransform obj3 = val2.AddComponent(); ((Vector2)(ref val3))..ctor(0f, 0f); obj3.pivot = val3; Vector2 anchorMin = (obj3.anchorMax = val3); obj3.anchorMin = anchorMin; obj3.anchoredPosition = new Vector2(1f, num3 + (float)i * 17f); obj3.sizeDelta = new Vector2(388f, 17f); TextMeshProUGUI val5 = val2.AddComponent(); if ((Object)(object)val != (Object)null) { ((TMP_Text)val5).font = val; } ((TMP_Text)val5).fontSize = 12.5f; ((TMP_Text)val5).alignment = (TextAlignmentOptions)1025; ((Graphic)val5).raycastTarget = false; ((TMP_Text)val5).text = ""; _toastLabels[i] = val5; } _toasts.Clear(); _foodShown = NeedsState.Hunger; _waterShown = NeedsState.Thirst; _energyShown = NeedsState.Energy; MelonLogger.Msg($"[HUD] Meters built ({num} rows)."); } private static void SetPanel(Image img, Sprite sprite, float targetHeight) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) img.sprite = sprite; img.type = (Type)1; float num = Mathf.Max(sprite.border.y, sprite.border.x); if (num > 0f) { img.pixelsPerUnitMultiplier = Mathf.Max(1f, num / (targetHeight * 0.45f)); } } private static void BuildRow(string name, float y, Sprite icon, Color tint, TMP_FontAsset font, out Image chipIcon, out Image fill, out TextMeshProUGUI label, out Image badge) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0065: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0183: 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_01aa: 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_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Expected O, but got Unknown //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Expected O, but got Unknown //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("S1HT_" + name + "Chip"); val.transform.SetParent(_meterRoot.transform, false); RectTransform obj = val.AddComponent(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 0f); obj.pivot = val2; Vector2 val3 = (obj.anchorMin = (obj.anchorMax = val2)); obj.anchoredPosition = new Vector2(0f, y); obj.sizeDelta = new Vector2(20f, 20f); Image obj2 = val.AddComponent(); SetPanel(obj2, _rounded, 20f); ((Graphic)obj2).color = PanelBg; ((Graphic)obj2).raycastTarget = false; GameObject val6 = new GameObject("S1HT_" + name + "Icon"); val6.transform.SetParent(val.transform, false); RectTransform obj3 = val6.AddComponent(); obj3.anchorMin = Vector2.zero; obj3.anchorMax = Vector2.one; obj3.offsetMin = new Vector2(2.5f, 2.5f); obj3.offsetMax = new Vector2(-2.5f, -2.5f); chipIcon = val6.AddComponent(); chipIcon.sprite = icon; ((Graphic)chipIcon).color = tint; ((Graphic)chipIcon).raycastTarget = false; GameObject val7 = new GameObject("S1HT_" + name + "Badge"); val7.transform.SetParent(val.transform, false); RectTransform obj4 = val7.AddComponent(); ((Vector2)(ref val3))..ctor(1f, 1f); obj4.anchorMax = val3; obj4.anchorMin = val3; obj4.pivot = new Vector2(0.5f, 0.5f); obj4.anchoredPosition = new Vector2(-1.5f, -1.5f); obj4.sizeDelta = new Vector2(7f, 7f); badge = val7.AddComponent(); badge.sprite = _circle; ((Graphic)badge).raycastTarget = false; ((Behaviour)badge).enabled = false; GameObject val8 = new GameObject("S1HT_" + name + "Track"); val8.transform.SetParent(_meterRoot.transform, false); RectTransform obj5 = val8.AddComponent(); ((Vector2)(ref val2))..ctor(0f, 0f); obj5.pivot = val2; val3 = (obj5.anchorMin = (obj5.anchorMax = val2)); obj5.anchoredPosition = new Vector2(24f, y + 4f); obj5.sizeDelta = new Vector2(148f, 12f); Image obj6 = val8.AddComponent(); SetPanel(obj6, _rounded, 12f); ((Graphic)obj6).color = TrackBg; ((Graphic)obj6).raycastTarget = false; GameObject val11 = new GameObject("S1HT_" + name + "Fill"); val11.transform.SetParent(val8.transform, false); RectTransform obj7 = val11.AddComponent(); ((Vector2)(ref val2))..ctor(0f, 0.5f); obj7.pivot = val2; val3 = (obj7.anchorMin = (obj7.anchorMax = val2)); obj7.anchoredPosition = new Vector2(1.5f, 0f); obj7.sizeDelta = new Vector2(145f, 9f); fill = val11.AddComponent(); SetPanel(fill, _solidBar, 9f); ((Graphic)fill).color = tint; ((Graphic)fill).raycastTarget = false; GameObject val14 = new GameObject("S1HT_" + name + "Label"); val14.transform.SetParent(_meterRoot.transform, false); RectTransform obj8 = val14.AddComponent(); ((Vector2)(ref val2))..ctor(0f, 0f); obj8.pivot = val2; val3 = (obj8.anchorMin = (obj8.anchorMax = val2)); obj8.anchoredPosition = new Vector2(176f, y); obj8.sizeDelta = new Vector2(52f, 20f); label = val14.AddComponent(); if ((Object)(object)font != (Object)null) { ((TMP_Text)label).font = font; } ((TMP_Text)label).fontSize = 11f; ((TMP_Text)label).alignment = (TextAlignmentOptions)4097; ((Graphic)label).color = TextSoft; ((Graphic)label).raycastTarget = false; ((TMP_Text)label).text = ""; } private static void ApplyCorner(RectTransform root) { //IL_0065: 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_006e: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) float hudOffsetX = NeedsConfig.HudOffsetX; float hudOffsetY = NeedsConfig.HudOffsetY; Vector2 val = default(Vector2); switch ((NeedsConfig.HudCorner ?? "BottomLeft").Trim().ToLowerInvariant()) { case "bottomright": { ((Vector2)(ref val))..ctor(1f, 0f); root.pivot = val; Vector2 anchorMin = (root.anchorMax = val); root.anchorMin = anchorMin; root.anchoredPosition = new Vector2(0f - hudOffsetX, hudOffsetY); break; } case "topleft": { ((Vector2)(ref val))..ctor(0f, 1f); root.pivot = val; Vector2 anchorMin = (root.anchorMax = val); root.anchorMin = anchorMin; root.anchoredPosition = new Vector2(hudOffsetX, 0f - hudOffsetY); break; } case "topright": { ((Vector2)(ref val))..ctor(1f, 1f); root.pivot = val; Vector2 anchorMin = (root.anchorMax = val); root.anchorMin = anchorMin; root.anchoredPosition = new Vector2(0f - hudOffsetX, 0f - hudOffsetY); break; } default: { ((Vector2)(ref val))..ctor(0f, 0f); root.pivot = val; Vector2 anchorMin = (root.anchorMax = val); root.anchorMin = anchorMin; root.anchoredPosition = new Vector2(hudOffsetX, hudOffsetY); break; } } } public static void Toast(string message, Color color) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(message) || !NeedsConfig.ToastsEnabled) { return; } foreach (ToastLine toast in _toasts) { if (toast.Text == message) { toast.ExpiresAt = Time.unscaledTime + ToastLifetime; toast.Color = color; return; } } _toasts.Add(new ToastLine { Text = message, Color = color, ExpiresAt = Time.unscaledTime + ToastLifetime }); while (_toasts.Count > 5) { _toasts.RemoveAt(0); } } private static void UpdateToasts() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) float now = Time.unscaledTime; _toasts.RemoveAll((ToastLine t) => now >= t.ExpiresAt); for (int num = 0; num < 5; num++) { TextMeshProUGUI val = _toastLabels[num]; if (!((Object)(object)val == (Object)null) && Object.op_Implicit((Object)(object)val)) { int num2 = _toasts.Count - 1 - num; if (num2 < 0) { ((TMP_Text)val).text = ""; continue; } ToastLine toastLine = _toasts[num2]; float num3 = Mathf.Clamp01((toastLine.ExpiresAt - now) / 0.6f); ((TMP_Text)val).text = toastLine.Text; ((Graphic)val).color = new Color(toastLine.Color.r, toastLine.Color.g, toastLine.Color.b, num3); } } } public static void UpdateVisuals() { //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_00c7: 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_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) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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) if (!NeedsConfig.HudEnabled && !NeedsConfig.ToastsEnabled) { if (IsBuilt) { Teardown(); } return; } if (!IsBuilt) { EnsureBuilt(); if (!IsBuilt) { return; } } float unscaledDeltaTime = Time.unscaledDeltaTime; _foodShown = Mathf.MoveTowards(_foodShown, NeedsState.Hunger, unscaledDeltaTime * 30f); _waterShown = Mathf.MoveTowards(_waterShown, NeedsState.Thirst, unscaledDeltaTime * 30f); _energyShown = Mathf.MoveTowards(_energyShown, NeedsState.Energy, unscaledDeltaTime * 30f); float pulse = 0.5f + 0.5f * Mathf.Sin(Time.unscaledTime * 5f); UpdateRow(_foodFill, _foodChipIcon, _foodLabel, _foodShown, NeedsState.HungerStage, 0, FoodOk, FoodLow, FoodCrit, pulse); UpdateRow(_waterFill, _waterChipIcon, _waterLabel, _waterShown, NeedsState.ThirstStage, 1, WaterOk, WaterLow, WaterCrit, pulse); UpdateRow(_energyFill, _energyChipIcon, _energyLabel, _energyShown, NeedsState.EnergyStage, 2, EnergyOk, EnergyLow, EnergyCrit, pulse); UpdateBadge(_foodBadge, DrugEffects.HungerFaster, DrugEffects.HungerSlower || NeedsState.SatietyActive, pulse); UpdateBadge(_waterBadge, DrugEffects.ThirstFaster, DrugEffects.ThirstSlower, pulse); UpdateBadge(_energyBadge, DrugEffects.EnergyFaster, DrugEffects.EnergySlower || NeedsState.IsWired, pulse); UpdateToasts(); bool flag = NeedsState.HungerStage == NeedStage.Fine && NeedsState.ThirstStage == NeedStage.Fine && NeedsState.EnergyStage == NeedStage.Fine && (!NeedsConfig.HungerEnabled || NeedsState.Hunger > 80f) && (!NeedsConfig.ThirstEnabled || NeedsState.Thirst > 80f) && (!NeedsConfig.EnergyEnabled || NeedsState.Energy > 80f) && !DrugEffects.HungerFaster && !DrugEffects.ThirstFaster && !DrugEffects.EnergyFaster && !AnyToastVisible; float num = ((NeedsConfig.HudFadeWhenFine && flag) ? NeedsConfig.HudFadeAlpha : 1f); if ((Object)(object)_meterGroup != (Object)null) { _meterGroup.alpha = Mathf.MoveTowards(_meterGroup.alpha, num, unscaledDeltaTime * 2.5f); } UpdateVignette(pulse); } private static void UpdateRow(Image fill, Image chipIcon, TextMeshProUGUI label, float shown, NeedStage stage, int need, Color ok, Color low, Color crit, float pulse) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_0061: 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_006a: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fill == (Object)null) { return; } float num = Mathf.Clamp01(shown / 100f); RectTransform rectTransform = ((Graphic)fill).rectTransform; float num2 = Mathf.Max(num * 145f, (num <= 0.001f) ? 0f : 8f); rectTransform.sizeDelta = new Vector2(num2, 9f); ((Behaviour)fill).enabled = num > 0.001f; Color val = (((Graphic)fill).color = GradientColor(shown, ok, low, crit, pulse)); if ((Object)(object)chipIcon != (Object)null) { ((Graphic)chipIcon).color = val; } if ((Object)(object)label != (Object)null) { if (stage == NeedStage.Fine) { ((TMP_Text)label).text = (NeedsConfig.ShowNumbers ? $"{Mathf.RoundToInt(shown)}%" : ""); ((Graphic)label).color = TextSoft; } else { ((TMP_Text)label).text = NeedsState.StageName(need, stage).ToUpperInvariant(); ((Graphic)label).color = ((stage >= NeedStage.Stage2) ? Color.Lerp(TextMain, val, 0.6f) : TextSoft); } } } private static Color GradientColor(float value, Color healthy, Color warn, Color crit, float pulse) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) float thresholdStage = NeedsConfig.ThresholdStage1; float thresholdStage2 = NeedsConfig.ThresholdStage2; float thresholdStage3 = NeedsConfig.ThresholdStage3; if (value >= thresholdStage) { return healthy; } if (value >= thresholdStage2) { return Color.Lerp(warn, healthy, Mathf.InverseLerp(thresholdStage2, thresholdStage, value)); } if (value >= thresholdStage3) { return Color.Lerp(crit, warn, Mathf.InverseLerp(thresholdStage3, thresholdStage2, value)); } return Color.Lerp(crit, Color.Lerp(crit, Color.white, 0.3f), pulse); } private static void UpdateBadge(Image badge, bool faster, bool slower, float pulse) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) if (!((Object)(object)badge == (Object)null) && (((Behaviour)badge).enabled = NeedsConfig.DrugEffectsEnabled && (faster || slower))) { Color val = (faster ? BadgeFast : BadgeSlow); ((Graphic)badge).color = new Color(val.r, val.g, val.b, 0.65f + 0.35f * pulse); } } private static void UpdateVignette(float pulse) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_vignette == (Object)null) { return; } if (!NeedsConfig.VignetteEnabled || !NeedsConfig.PenaltiesEnabled) { ((Graphic)_vignette).color = new Color(0f, 0f, 0f, 0f); return; } float num = Mathf.Min(NeedsConfig.HungerEnabled ? NeedsState.Hunger : 100f, NeedsConfig.ThirstEnabled ? NeedsState.Thirst : 100f); float num2 = Mathf.InverseLerp(NeedsConfig.ThresholdStage2, 0f, num); if (num2 <= 0f) { ((Graphic)_vignette).color = new Color(0f, 0f, 0f, 0f); return; } float num3 = 0.3f * num2; if (num < NeedsConfig.ThresholdStage3) { num3 += 0.07f * pulse; } Color val = ((NeedsState.Hunger < NeedsState.Thirst) ? new Color(0.22f, 0.05f, 0.02f) : new Color(0.05f, 0.09f, 0.16f)); ((Graphic)_vignette).color = new Color(val.r, val.g, val.b, Mathf.Clamp(num3, 0f, 0.34f)); } private static bool Alive(Sprite s) { if ((Object)(object)s != (Object)null) { return Object.op_Implicit((Object)(object)s); } return false; } private static Color FromHex(int rgb) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) return new Color((float)((rgb >> 16) & 0xFF) / 255f, (float)((rgb >> 8) & 0xFF) / 255f, (float)(rgb & 0xFF) / 255f, 1f); } private static Texture2D NewTex(int w, int h) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new Texture2D(w, h, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, hideFlags = (HideFlags)32 }; } private static Sprite Finish(Texture2D tex, int size, Vector4 border = default(Vector4)) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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) tex.Apply(); Sprite obj = ((border == default(Vector4)) ? Sprite.Create(tex, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f) : Sprite.Create(tex, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, border)); ((Object)obj).hideFlags = (HideFlags)32; return obj; } private static Sprite MakeRoundedRect() { //IL_00ce: 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) Texture2D val = NewTex(32, 32); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = Mathf.Max(Mathf.Abs((float)j + 0.5f - 16f) - 5f, 0f); float num2 = Mathf.Max(Mathf.Abs((float)i + 0.5f - 16f) - 5f, 0f); float num3 = Mathf.Sqrt(num * num + num2 * num2); float num4 = Mathf.Clamp01(11f - num3 + 0.5f); val.SetPixel(j, i, new Color(1f, 1f, 1f, num4)); } } return Finish(val, 32, new Vector4(13f, 13f, 13f, 13f)); } private static Sprite MakeSolidBar() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NewTex(24, 24); for (int i = 0; i < 24; i++) { for (int j = 0; j < 24; j++) { float num = Mathf.Max(Mathf.Abs((float)j + 0.5f - 12f) - 6f, 0f); float num2 = Mathf.Max(Mathf.Abs((float)i + 0.5f - 12f) - 6f, 0f); float num3 = Mathf.Sqrt(num * num + num2 * num2); val.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(6f - num3 + 0.5f))); } } return Finish(val, 24, new Vector4(8f, 8f, 8f, 8f)); } private static Sprite MakeCircle() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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) Texture2D val = NewTex(16, 16); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { float num = Mathf.Sqrt(((float)j + 0.5f - 8f) * ((float)j + 0.5f - 8f) + ((float)i + 0.5f - 8f) * ((float)i + 0.5f - 8f)); val.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(7f - num + 0.5f))); } } return Finish(val, 16); } private static Sprite MakeFoodIcon() { //IL_0121: 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_00fa: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NewTex(32, 32); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = 0f; float num2 = Mathf.Abs((float)j + 0.5f - 16f); if (i >= 18 && i <= 26) { float num3 = ((float)i - 18f) / 8f; float num4 = 12f * Mathf.Sqrt(Mathf.Max(0f, 1f - num3 * num3 * 0.85f)); num = Mathf.Max(num, Mathf.Clamp01(num4 - num2 + 0.5f)); } if (i >= 13 && i <= 16) { num = Mathf.Max(num, Mathf.Clamp01(13f - num2 + 0.5f)); } if (i >= 6 && i <= 11) { float num5 = ((i <= 7 || i >= 10) ? 11f : 12f); num = Mathf.Max(num, Mathf.Clamp01(num5 - num2 + 0.5f)); } val.SetPixel(j, i, new Color(1f, 1f, 1f, num)); } } return Finish(val, 32); } private static Sprite MakeMoonIcon() { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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) Texture2D val = NewTex(32, 32); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = (float)j + 0.5f; float num2 = (float)i + 0.5f; float num3 = Mathf.Sqrt((num - 16f) * (num - 16f) + (num2 - 16f) * (num2 - 16f)); float num4 = Mathf.Clamp01(12f - num3 + 0.5f); float num5 = Mathf.Sqrt((num - 22f) * (num - 22f) + (num2 - 20f) * (num2 - 20f)); float num6 = Mathf.Clamp01(10.5f - num5 + 0.5f); val.SetPixel(j, i, new Color(1f, 1f, 1f, num4 * (1f - num6))); } } return Finish(val, 32); } private static Sprite MakeWaterIcon() { //IL_00f8: 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_00d1: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NewTex(32, 32); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = (float)j + 0.5f; float num2 = (float)i + 0.5f; float num3 = Mathf.Sqrt((num - 16f) * (num - 16f) + (num2 - 12f) * (num2 - 12f)); float num4 = Mathf.Clamp01(9.5f - num3 + 0.5f); if (num2 > 12f && num2 <= 28f) { float num5 = (num2 - 12f) / 16f; float num6 = 9.5f * (1f - num5); num4 = Mathf.Max(num4, Mathf.Clamp01(num6 - Mathf.Abs(num - 16f) + 0.5f)); } val.SetPixel(j, i, new Color(1f, 1f, 1f, num4)); } } return Finish(val, 32); } private static Sprite MakeRadialVignette() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NewTex(128, 128); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num = ((float)j + 0.5f) / 128f * 2f - 1f; float num2 = ((float)i + 0.5f) / 128f * 2f - 1f; float num3 = Mathf.Sqrt(num * num + num2 * num2); float num4 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01((num3 - 0.55f) / 0.75f)); val.SetPixel(j, i, new Color(1f, 1f, 1f, num4)); } } return Finish(val, 128); } } public enum NeedStage { Fine, Stage1, Stage2, Stage3 } public static class Need { public const int Hunger = 0; public const int Thirst = 1; public const int Energy = 2; } public static class NeedsState { private static bool _wasSleeping; private static int _bedTimeHHMM = -1; private static readonly string[] WiredLines = new string[3] { "Wide awake. Sleep can wait.", "Heart's up, eyes are open. Let's go.", "Sleep's cancelled for a bit." }; private static readonly string[] WakeFullLines = new string[3] { "Slept like a log.", "Out cold, the good kind.", "Full recharge. Rare." }; private static readonly string[] WakeLateLines = new string[3] { "Slept rough. Still yawning.", "Late night, thin sleep.", "Bed at that hour barely counts." }; private static readonly string[] WakeOkLines = new string[3] { "Decent kip.", "Slept alright. Could've gone longer.", "Not bad. The pillow did its job." }; public static float Hunger { get; private set; } = 100f; public static float Thirst { get; private set; } = 100f; public static float Energy { get; private set; } = 100f; public static NeedStage HungerStage { get; private set; } = NeedStage.Fine; public static NeedStage ThirstStage { get; private set; } = NeedStage.Fine; public static NeedStage EnergyStage { get; private set; } = NeedStage.Fine; public static float WiredRemaining { get; private set; } public static bool IsWired => WiredRemaining > 0f; public static float SatietyRemaining { get; private set; } public static float SatietyFactor { get; private set; } = 1f; public static bool SatietyActive => SatietyRemaining > 0f; public static event Action OnStageWorsened; public static void StartSatiety(float seconds, float drainFactor) { if (!(seconds <= 0f)) { SatietyRemaining = seconds; SatietyFactor = Mathf.Clamp(drainFactor, 0.1f, 1f); } } public static void ResetToDefaults() { Restore(100f, 100f, 100f); } public static void Restore(float hunger, float thirst, float energy) { Hunger = Mathf.Clamp(hunger, 0f, 100f); Thirst = Mathf.Clamp(thirst, 0f, 100f); Energy = Mathf.Clamp(energy, 0f, 100f); _wasSleeping = false; _bedTimeHHMM = -1; WiredRemaining = 0f; SatietyRemaining = 0f; SatietyFactor = 1f; RecomputeStages(silent: true); } public static void OnSessionEnded() { _wasSleeping = false; _bedTimeHHMM = -1; } public static void Replenish(float hunger, float thirst, float energy = 0f) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) Hunger = Mathf.Clamp(Hunger + hunger, 0f, 100f); Thirst = Mathf.Clamp(Thirst + thirst, 0f, 100f); if (NeedsConfig.EnergyEnabled && energy != 0f) { Energy = Mathf.Clamp(Energy + energy, 0f, 100f); if (energy >= NeedsConfig.WiredMinEnergyRestore) { WiredRemaining = NeedsConfig.WiredDurationSeconds; NeedsHud.Toast(Lines.Pick(WiredLines), NeedsHud.ToastGood); } } RecomputeStages(silent: false); } public static void DrainEnergy(float amount) { if (NeedsConfig.EnergyEnabled) { Energy = Mathf.Clamp(Energy - amount, 0f, 100f); RecomputeStages(silent: false); } } public static void SetEnergy(float value) { Energy = Mathf.Clamp(value, 0f, 100f); RecomputeStages(silent: true); } public static void TickRealTime() { bool flag = false; int bedTimeHHMM = -1; try { TimeManager instance = NetworkSingleton.Instance; if ((Object)(object)instance != (Object)null) { flag = instance.IsSleepInProgress; bedTimeHHMM = instance.CurrentTime; } if (!flag && (Object)(object)Player.Local != (Object)null) { flag = Player.Local.IsSleeping; } } catch { } if (flag) { if (!_wasSleeping) { _wasSleeping = true; _bedTimeHHMM = bedTimeHHMM; } return; } if (_wasSleeping) { _wasSleeping = false; SettleSleep(); return; } float deltaTime = Time.deltaTime; if (deltaTime <= 0f || deltaTime > 1f) { return; } try { PlayerCamera instance2 = PlayerSingleton.Instance; if ((Object)(object)instance2 != (Object)null && instance2.ActiveUIElementCount > 0) { return; } } catch { } if (WiredRemaining > 0f) { WiredRemaining = Mathf.Max(0f, WiredRemaining - deltaTime); } if (SatietyRemaining > 0f) { SatietyRemaining = Mathf.Max(0f, SatietyRemaining - deltaTime); } float num = deltaTime / 60f; if (NeedsConfig.HungerEnabled) { float num2 = NeedsConfig.HungerPerRealMinute * DrugEffects.HungerMult; if (SatietyRemaining > 0f) { num2 *= SatietyFactor; } Hunger = Mathf.Clamp(Hunger - num2 * num, 0f, 100f); } if (NeedsConfig.ThirstEnabled) { Thirst = Mathf.Clamp(Thirst - NeedsConfig.ThirstPerRealMinute * DrugEffects.ThirstMult * num, 0f, 100f); } if (NeedsConfig.EnergyEnabled) { float num3 = NeedsConfig.EnergyPerRealMinute * DrugEffects.EnergyMult; try { PlayerMovement instance3 = PlayerSingleton.Instance; if ((Object)(object)instance3 != (Object)null && instance3.IsSprinting) { num3 *= NeedsConfig.SprintEnergyFactor; } } catch { } if (WiredRemaining > 0f) { num3 *= NeedsConfig.WiredDrainFactor; } Energy = Mathf.Clamp(Energy - num3 * num, 0f, 100f); } RecomputeStages(silent: false); } private static void SettleSleep() { //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (NeedsConfig.HungerEnabled) { Hunger = Mathf.Clamp(Hunger - NeedsConfig.SleepHungerCost, 0f, 100f); } if (NeedsConfig.ThirstEnabled) { Thirst = Mathf.Clamp(Thirst - NeedsConfig.SleepThirstCost, 0f, 100f); } if (NeedsConfig.EnergyEnabled && _bedTimeHHMM >= 0) { int num = _bedTimeHHMM / 100 * 60 + _bedTimeHHMM % 100; float num2 = Mathf.Clamp((float)((420 - num + 1440) % 1440) / 60f, 1f, 13f); bool flag = (float)num >= NeedsConfig.LateSleepAfterHour * 60f && num < 420; float num3 = (flag ? Mathf.Clamp01(NeedsConfig.LateSleepQuality) : 1f); float num4 = num2 * NeedsConfig.SleepRestorePerHour * num3; Energy = Mathf.Clamp(Energy + num4, 0f, 100f); string text = ((Energy >= 99.5f) ? Lines.Pick(WakeFullLines) : (flag ? Lines.Pick(WakeLateLines) : Lines.Pick(WakeOkLines))); NeedsHud.Toast(text, NeedsHud.ToastGood); try { SleepCanvas instance = Singleton.Instance; if (instance != null) { instance.QueueSleepMessage(text, 3f); } } catch { } } _bedTimeHHMM = -1; RecomputeStages(silent: false); } public static NeedStage StageOf(float value) { if (value < NeedsConfig.ThresholdStage3) { return NeedStage.Stage3; } if (value < NeedsConfig.ThresholdStage2) { return NeedStage.Stage2; } if (value < NeedsConfig.ThresholdStage1) { return NeedStage.Stage1; } return NeedStage.Fine; } private static void RecomputeStages(bool silent) { NeedStage needStage = (NeedsConfig.HungerEnabled ? StageOf(Hunger) : NeedStage.Fine); NeedStage needStage2 = (NeedsConfig.ThirstEnabled ? StageOf(Thirst) : NeedStage.Fine); NeedStage needStage3 = (NeedsConfig.EnergyEnabled ? StageOf(Energy) : NeedStage.Fine); if (needStage > HungerStage && !silent) { NeedsState.OnStageWorsened?.Invoke(0, needStage); } if (needStage2 > ThirstStage && !silent) { NeedsState.OnStageWorsened?.Invoke(1, needStage2); } if (needStage3 > EnergyStage && !silent) { NeedsState.OnStageWorsened?.Invoke(2, needStage3); } HungerStage = needStage; ThirstStage = needStage2; EnergyStage = needStage3; } public static string StageName(int need, NeedStage s) { if (s == NeedStage.Fine) { return "Fine"; } return need switch { 0 => s switch { NeedStage.Stage2 => "Hungry", NeedStage.Stage1 => "Peckish", _ => "Starving", }, 1 => s switch { NeedStage.Stage2 => "Parched", NeedStage.Stage1 => "Thirsty", _ => "Dehydrated", }, _ => s switch { NeedStage.Stage2 => "Exhausted", NeedStage.Stage1 => "Weary", _ => "Delirious", }, }; } } public static class Penalties { private const string SprintBlockTag = "S1HT_Critical"; private const string DrowsyTag = "S1HT_Drowsy"; private const string BlinkTag = "S1HT_Blink"; private static float _crookGutsUntil; private static bool _sprintBlocked; private static float _healthDrainCarry; private static float _appliedDroop = -1f; private static bool _blinkActive; private static float _blinkEndsAt; private static float _nextBlinkAt; private static float _collapseAt = -1f; private static bool _warned30; private static bool _stimResetUsed; private static readonly string[] CollapseWarnLines = new string[3] { "Eyes are closing on their own. Bed, right now.", "Body's clocking out with or without you.", "This is the last warning the legs are giving." }; private static readonly string[] StimHoldLines = new string[3] { "Only the gear's keeping you awake right now.", "The stims are doing all the standing.", "Chemically upright. That's all this is." }; private static readonly string[] Collapse30Lines = new string[3] { "About to hit the deck.", "Thirty seconds of vertical left, tops.", "Floor incoming." }; private static readonly string[] CollapseDropLines = new string[3] { "Lights out. You dropped where you stood.", "Gone. The pavement caught you.", "The body called it. Blackout." }; public static float SpeedFactor { get; private set; } = 1f; public static float BurroitoFactor { get { if (!NeedsConfig.BurroitoEnabled || !SaveData.BurroitoOwned) { return 1f; } return 1f + NeedsConfig.BurroitoSpeedBonus; } } public static bool CrookGutsActive => Time.unscaledTime < _crookGutsUntil; public static void StartCrookGuts(float seconds) { if (seconds > 0f) { _crookGutsUntil = Time.unscaledTime + seconds; } } public static void Blackout(float seconds) { try { EyelidOverlay instance = Singleton.Instance; if (!((Object)(object)instance == (Object)null)) { instance.OpenMultiplier.AddOverride(0f, 70, "S1HT_Blink"); _blinkActive = true; _blinkEndsAt = Time.unscaledTime + Mathf.Max(1f, seconds); } } catch (Exception ex) { MelonLogger.Warning("[Penalties] blackout failed: " + ex.Message); } } public static void Tick() { Player local = Player.Local; if ((Object)(object)local == (Object)null) { return; } if (!NeedsConfig.PenaltiesEnabled) { if (SpeedFactor != 1f || _sprintBlocked) { Reset(); } return; } float num = 1f; if (NeedsState.HungerStage == NeedStage.Stage2) { num = NeedsConfig.HungerSpeedStage2; } else if (NeedsState.HungerStage == NeedStage.Stage3) { num = NeedsConfig.HungerSpeedStage3; } if (NeedsState.ThirstStage == NeedStage.Stage3) { num *= NeedsConfig.ThirstCritSpeedFactor; } if (NeedsConfig.EnergyEnabled) { if (NeedsState.EnergyStage == NeedStage.Stage2) { num *= NeedsConfig.EnergySpeedStage2; } else if (NeedsState.EnergyStage == NeedStage.Stage3) { num *= NeedsConfig.EnergySpeedStage3; } } if (CrookGutsActive) { num *= NeedsConfig.CrookGutsSpeedFactor; } SpeedFactor = Mathf.Clamp(num, 0.5f, 1f); PlayerMovement instance = PlayerSingleton.Instance; if ((Object)(object)instance != (Object)null) { float num2 = 1f; if (NeedsState.ThirstStage == NeedStage.Stage2) { num2 = NeedsConfig.ThirstStaminaStage2; } else if (NeedsState.ThirstStage == NeedStage.Stage3) { num2 = NeedsConfig.ThirstStaminaStage3; } if (num2 < 1f) { float num3 = PlayerMovement.StaminaReserveMax * num2; if (instance.CurrentStaminaReserve > num3) { instance.CurrentStaminaReserve = num3; } } bool flag = Mathf.Min(NeedsState.Hunger, NeedsState.Thirst) < NeedsConfig.SprintBlockBelow; if (flag != _sprintBlocked) { if (flag) { instance.AddSprintBlocker("S1HT_Critical"); } else { instance.RemoveSprintBlocker("S1HT_Critical"); } _sprintBlocked = flag; } } TickHealthDrain(local); if (NeedsConfig.EnergyEnabled) { TickEnergyPenalties(local); } else { ClearEnergyPenalties(); } } private static void TickEnergyPenalties(Player player) { //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) EyelidOverlay val = (NeedsConfig.EyelidsEnabled ? Singleton.Instance : null); float unscaledTime = Time.unscaledTime; float num = ((NeedsState.EnergyStage == NeedStage.Stage3) ? NeedsConfig.EyelidDroopDelirious : ((NeedsState.EnergyStage == NeedStage.Stage2) ? NeedsConfig.EyelidDroopExhausted : (-1f))); if ((Object)(object)val != (Object)null && num != _appliedDroop) { try { val.OpenMultiplier.RemoveOverride("S1HT_Drowsy"); if (num > 0f) { val.OpenMultiplier.AddOverride(num, 50, "S1HT_Drowsy"); } _appliedDroop = num; } catch (Exception ex) { MelonLogger.Warning("[Penalties] Eyelid droop failed: " + ex.Message); } } if (NeedsState.EnergyStage == NeedStage.Stage3 && (Object)(object)val != (Object)null && !player.IsSleeping) { if (_blinkActive && unscaledTime >= _blinkEndsAt) { EndBlink(val); } else if (!_blinkActive && unscaledTime >= _nextBlinkAt) { if (_nextBlinkAt <= 0f) { _nextBlinkAt = unscaledTime + 8f; } else { try { val.OpenMultiplier.AddOverride(0.05f, 60, "S1HT_Blink"); _blinkActive = true; _blinkEndsAt = unscaledTime + NeedsConfig.MicrosleepBlinkSeconds; } catch { } } } } else if (_blinkActive && (Object)(object)val != (Object)null) { EndBlink(val); } else if (NeedsState.EnergyStage != NeedStage.Stage3) { _nextBlinkAt = 0f; } if (!NeedsConfig.CollapseEnabled) { _collapseAt = -1f; } else if (NeedsState.Energy > 5f) { _collapseAt = -1f; _stimResetUsed = false; } else { if (NeedsState.Energy > 0f) { return; } if (_collapseAt < 0f) { _collapseAt = unscaledTime + Mathf.Max(30f, NeedsConfig.CollapseDelaySeconds); _warned30 = false; NeedsHud.Toast(Lines.Pick(CollapseWarnLines), NeedsHud.ToastBad); return; } if (DrugEffects.StrongStimActive && !_stimResetUsed) { _stimResetUsed = true; _collapseAt = unscaledTime + Mathf.Max(30f, NeedsConfig.CollapseDelaySeconds); NeedsHud.Toast(Lines.Pick(StimHoldLines), NeedsHud.ToastWarn); return; } if (!_warned30 && _collapseAt - unscaledTime <= 30f) { _warned30 = true; NeedsHud.Toast(Lines.Pick(Collapse30Lines), NeedsHud.ToastBad); } if (unscaledTime >= _collapseAt && !player.IsSleeping) { _collapseAt = -1f; Collapse(player, val); } } } private static void EndBlink(EyelidOverlay eyes) { try { eyes.OpenMultiplier.RemoveOverride("S1HT_Blink"); } catch { } _blinkActive = false; float num = 1f - Mathf.Clamp01(NeedsState.Energy / Mathf.Max(1f, NeedsConfig.ThresholdStage3)); _nextBlinkAt = Time.unscaledTime + Mathf.Lerp(NeedsConfig.MicrosleepMaxGap, NeedsConfig.MicrosleepMinGap, num); } private static void Collapse(Player player, EyelidOverlay eyes) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) NeedsState.SetEnergy(NeedsConfig.CollapseRestoreTo); if ((Object)(object)eyes != (Object)null) { try { eyes.OpenMultiplier.AddOverride(0f, 70, "S1HT_Blink"); _blinkActive = true; _blinkEndsAt = Time.unscaledTime + 5f; } catch { } } string text = Lines.Pick(CollapseDropLines); if (NeedsConfig.CollapseCashPenalty && (Object)(object)player.CurrentProperty == (Object)null) { try { MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance != (Object)null) { float num = Mathf.Min(instance.cashBalance * Mathf.Clamp01(NeedsConfig.CollapseCashFraction), Mathf.Max(0f, NeedsConfig.CollapseCashCap)); num = Mathf.Floor(num); if (num >= 1f) { instance.ChangeCashBalance(0f - num, true, false); text = $"Hit the deck in the street. Woke up ${num:0} lighter."; } } } catch (Exception ex) { MelonLogger.Warning("[Penalties] Collapse cash sting failed: " + ex.Message); } } NeedsHud.Toast(text, NeedsHud.ToastBad); MelonLogger.Msg("[Energy] Collapse. " + text); } private static void ClearEnergyPenalties() { if (_appliedDroop < 0f && !_blinkActive && _collapseAt < 0f) { return; } try { EyelidOverlay instance = Singleton.Instance; if ((Object)(object)instance != (Object)null) { instance.OpenMultiplier.RemoveOverride("S1HT_Drowsy"); instance.OpenMultiplier.RemoveOverride("S1HT_Blink"); } } catch { } _appliedDroop = -1f; _blinkActive = false; _nextBlinkAt = 0f; _collapseAt = -1f; } private static void TickHealthDrain(Player player) { float num = 0f; if (NeedsState.Hunger <= 0f) { num += NeedsConfig.HealthDrainHungerPerMin; } if (NeedsState.Thirst <= 0f) { num += NeedsConfig.HealthDrainThirstPerMin; } if (num <= 0f) { _healthDrainCarry = 0f; return; } float deltaTime = Time.deltaTime; if (deltaTime <= 0f || deltaTime > 1f) { return; } PlayerHealth health = player.Health; if ((Object)(object)health == (Object)null || !health.IsAlive) { return; } _healthDrainCarry += num * (deltaTime / 60f); if (_healthDrainCarry < 0.5f) { return; } float healthDrainCarry = _healthDrainCarry; _healthDrainCarry = 0f; float num2 = (NeedsConfig.LethalStarvation ? 0f : Mathf.Max(0f, NeedsConfig.HealthFloor)); float num3 = Mathf.Max(health.CurrentHealth - healthDrainCarry, num2); if (num3 >= health.CurrentHealth) { return; } health.SetHealth(num3); if (!NeedsConfig.LethalStarvation || !(num3 <= 0f)) { return; } try { health.SendDie(); } catch (Exception ex) { MelonLogger.Warning("[Penalties] SendDie failed: " + ex.Message); } } public static void Reset() { SpeedFactor = 1f; _healthDrainCarry = 0f; _stimResetUsed = false; _crookGutsUntil = 0f; ClearEnergyPenalties(); if (!_sprintBlocked) { return; } try { PlayerMovement instance = PlayerSingleton.Instance; if (instance != null) { instance.RemoveSprintBlocker("S1HT_Critical"); } } catch { } _sprintBlocked = false; } } [HarmonyPatch] public static class MoveSpeedPatch { [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void AfterGetMoveSpeed(ref float __result) { if (NeedsConfig.Enabled && Session.InGame) { float num = Penalties.SpeedFactor * Penalties.BurroitoFactor; if (num != 1f) { __result *= num; } } } } public static class SaveData { private static string _activeKey; public static bool BurroitoOwned { get; set; } public static int DanAnswer { get; set; } private static string Dir => Path.Combine(MelonEnvironment.UserDataDirectory, "S1HungerThirst"); public static string ComputeActiveKey() { try { LoadManager instance = Singleton.Instance; if ((Object)(object)instance != (Object)null) { try { SaveInfo activeSaveInfo = instance.ActiveSaveInfo; if (activeSaveInfo != null) { string value = Sanitize(activeSaveInfo.OrganisationName); return $"slot{activeSaveInfo.SaveSlotNumber}_{value}"; } } catch { } string loadedGameFolderPath = instance.LoadedGameFolderPath; if (!string.IsNullOrEmpty(loadedGameFolderPath)) { return Sanitize(Path.GetFileName(loadedGameFolderPath.TrimEnd('/', '\\'))); } } } catch (Exception ex) { MelonLogger.Warning("[Save] Could not resolve save identity: " + ex.Message); } return "default"; } private static string Sanitize(string s) { if (string.IsNullOrEmpty(s)) { return "unnamed"; } s = Regex.Replace(s, "[^A-Za-z0-9_-]+", "_"); if (s.Length <= 48) { return s; } return s.Substring(0, 48); } public static void LoadForActiveSave() { _activeKey = ComputeActiveKey(); string path = Path.Combine(Dir, _activeKey + ".json"); try { if (File.Exists(path)) { string text = File.ReadAllText(path); float num = ReadField(text, "hunger", 100f); float num2 = ReadField(text, "thirst", 100f); float num3 = ReadField(text, "energy", 100f); BurroitoOwned = Regex.IsMatch(text, "\"burroito\"\\s*:\\s*true") || Regex.IsMatch(text, "\"borrito\"\\s*:\\s*true"); if (BurroitoOwned && !Regex.IsMatch(text, "\"burroito\"")) { Diag.Log("[Save] legacy 'borrito' owned-flag found — migrated to 'burroito' (buff preserved)."); } DanAnswer = Math.Max(0, Math.Min(2, (int)ReadField(text, "dan", 0f))); NeedsState.Restore(num, num2, num3); MelonLogger.Msg($"[Save] Loaded '{_activeKey}': food {num:0.#}, water {num2:0.#}, energy {num3:0.#}, burroito={BurroitoOwned}, dan={DanAnswer}."); return; } } catch (Exception ex) { MelonLogger.Warning("[Save] Read failed for '" + _activeKey + "', starting fresh: " + ex.Message); } BurroitoOwned = false; DanAnswer = 0; NeedsState.ResetToDefaults(); MelonLogger.Msg("[Save] Fresh save '" + _activeKey + "': starting sated."); } public static void WriteForActiveSave() { if (string.IsNullOrEmpty(_activeKey)) { return; } try { Directory.CreateDirectory(Dir); string contents = string.Format(CultureInfo.InvariantCulture, "{{\"v\":5,\"hunger\":{0:0.##},\"thirst\":{1:0.##},\"energy\":{2:0.##},\"burroito\":{3},\"dan\":{4},\"savedUtc\":\"{5:O}\"}}", NeedsState.Hunger, NeedsState.Thirst, NeedsState.Energy, BurroitoOwned ? "true" : "false", DanAnswer, DateTime.UtcNow); File.WriteAllText(Path.Combine(Dir, _activeKey + ".json"), contents); } catch (Exception ex) { MelonLogger.Warning("[Save] Write failed for '" + _activeKey + "': " + ex.Message); } } public static void OnSessionEnded() { _activeKey = null; BurroitoOwned = false; DanAnswer = 0; } private static float ReadField(string json, string name, float fallback) { Match match = Regex.Match(json, "\"" + name + "\"\\s*:\\s*(-?[0-9.]+)"); if (!match.Success || !float.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } } [HarmonyPatch] public static class SaveHookPatch { [HarmonyPostfix] [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { })] private static void AfterSaveNoArgs() { if (Session.InGame) { SaveData.WriteForActiveSave(); } } [HarmonyPostfix] [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { typeof(string) })] private static void AfterSaveWithPath(string saveFolderPath) { if (Session.InGame) { SaveData.WriteForActiveSave(); } } } public static class SettingsNpc { private sealed class Pillar { public string Key; public string Word; public string ChoiceText; public string[] NodeTexts; public object[][] Rows; } private const string LevelPrefix = "S1HT_P_"; private const string CatPrefix = "S1HT_PCAT_"; private const string ExitGuid = "S1HT_P_EXIT"; private static readonly string[] LevelNames = new string[7] { "Off", "Very Easy", "Casual", "Standard", "Hardcore", "Max", "Super Harsh" }; private static readonly string[] LevelChoiceTexts = new string[7] { "Turn it off", "Go real easy on me", "Keep it pretty light", "Just keep it normal", "Make me work for it", "Really put me through it", "Try to kill me" }; private static readonly string[][] ConfirmPools = new string[7][] { new string[3] { "{0}'s off. One less thing for you to whine about.", "{0}'s off. There. Baby mode.", "Fine. {0} doesn't exist anymore. Happy?" }, new string[3] { "{0}'s on very easy. Want me to chew it for you too?", "Fine. {0} barely exists now. Practically a spa.", "{0} set to very easy. My grandma called. She's embarrassed." }, new string[3] { "Eased up on {0}. Whatever, man.", "{0}'s on easy now. Adorable.", "Casual {0}. Sure. Training wheels stay on." }, new string[3] { "{0}'s back to standard. Congrats on being normal.", "Standard {0}. The default exists for a reason.", "{0}'s standard again. Boring. Correct, but boring." }, new string[3] { "Ha. {0}'s gonna bite now. Don't come crying.", "Hardcore {0}. Now we're talking.", "{0}'s got teeth now. Your funeral." }, new string[3] { "{0}'s maxed. You're gonna regret this one.", "Maxed {0}. I'd say good luck, but it won't help.", "{0} at max. Write your will first." }, new string[3] { "{0}'s past max now. I'll tell them you asked for this.", "Super harsh {0}. Start writing goodbye notes.", "There. {0} will actively hunt you now. Enjoy." } }; private static readonly string[] FrankEntryLines = new string[4] { "So which part of surviving is too hard for you?", "What now. Food, water, or sleep?", "You again. Which one's beating you today?", "Talk. Which part of staying alive needs adjusting?" }; private static readonly string[] FrankByeLines = new string[3] { "Then quit wasting my time.", "Great talk. Go away.", "Come back when you've picked one." }; private static readonly string[] FrankToasts = new string[3] { "Frank set {0}.", "Frank dialed in {0}. Grudgingly.", "{0}, per Frank. He had opinions." }; private static readonly Pillar[] Pillars = new Pillar[3] { new Pillar { Key = "H", Word = "Food", ChoiceText = "About food", NodeTexts = new string[3] { "Food, huh. How soft are we talking?", "Hunger settings. Pick a lane.", "Food. Everybody's favorite complaint. How hard do you want it?" }, Rows = new object[7][] { new object[8] { "HungerEnabled", false, true, true, true, true, true, true }, new object[8] { "HungerPerRealMinute", 2.4f, 0.6f, 1.2f, 2.4f, 3.6f, 8f, 12f }, new object[8] { "HungerSpeedStage2", 0.96f, 0.995f, 0.98f, 0.96f, 0.92f, 0.85f, 0.78f }, new object[8] { "HungerSpeedStage3", 0.9f, 0.98f, 0.95f, 0.9f, 0.8f, 0.7f, 0.55f }, new object[8] { "HealthDrainHungerPerMin", 0.6f, 0.1f, 0.3f, 0.6f, 1.5f, 3f, 6f }, new object[8] { "SleepHungerCost", 8f, 2f, 4f, 8f, 12f, 20f, 30f }, new object[8] { "LethalStarvation", false, false, false, false, false, true, true } } }, new Pillar { Key = "T", Word = "Water", ChoiceText = "About water", NodeTexts = new string[3] { "Thirst. Pick your poison.", "Water settings. Choose. I'm parched just listening to you.", "Thirst, huh. How dry do you want life to get?" }, Rows = new object[7][] { new object[8] { "ThirstEnabled", false, true, true, true, true, true, true }, new object[8] { "ThirstPerRealMinute", 2.8f, 0.7f, 1.4f, 2.8f, 4.2f, 9f, 13f }, new object[8] { "ThirstStaminaStage2", 0.7f, 0.95f, 0.85f, 0.7f, 0.55f, 0.4f, 0.25f }, new object[8] { "ThirstStaminaStage3", 0.5f, 0.85f, 0.7f, 0.5f, 0.35f, 0.2f, 0.1f }, new object[8] { "ThirstCritSpeedFactor", 0.97f, 0.995f, 0.99f, 0.97f, 0.94f, 0.9f, 0.82f }, new object[8] { "HealthDrainThirstPerMin", 0.9f, 0.15f, 0.45f, 0.9f, 2f, 4f, 8f }, new object[8] { "SleepThirstCost", 12f, 3f, 6f, 12f, 18f, 25f, 35f } } }, new Pillar { Key = "S", Word = "Sleep", ChoiceText = "About sleep", NodeTexts = new string[3] { "Sleep. Some people just skip it. What do you want?", "Sleep settings. Insomnia's free, everything else has levels.", "Sleep. Overrated or essential, pick a difficulty." }, Rows = new object[13][] { new object[8] { "EnergyEnabled", false, true, true, true, true, true, true }, new object[8] { "EnergyPerRealMinute", 2f, 0.5f, 1f, 2f, 3f, 6f, 9f }, new object[8] { "SprintEnergyFactor", 1.5f, 1.1f, 1.2f, 1.5f, 1.8f, 2.5f, 3.5f }, new object[8] { "EnergySpeedStage2", 0.97f, 0.995f, 0.99f, 0.97f, 0.94f, 0.9f, 0.82f }, new object[8] { "EnergySpeedStage3", 0.92f, 0.98f, 0.96f, 0.92f, 0.85f, 0.75f, 0.6f }, new object[8] { "SleepRestorePerHour", 12.5f, 18f, 15f, 12.5f, 10f, 8f, 6.5f }, new object[8] { "LateSleepQuality", 0.75f, 1f, 0.9f, 0.75f, 0.6f, 0.4f, 0.25f }, new object[8] { "CollapseEnabled", true, false, false, true, true, true, true }, new object[8] { "CollapseDelaySeconds", 180f, 420f, 300f, 180f, 90f, 45f, 20f }, new object[8] { "CollapseCashPenalty", true, false, false, true, true, true, true }, new object[8] { "CollapseCashFraction", 0.1f, 0.02f, 0.05f, 0.1f, 0.2f, 0.3f, 0.5f }, new object[8] { "CollapseCashCap", 250f, 50f, 100f, 250f, 500f, 2000f, 10000f }, new object[8] { "EyelidsEnabled", true, true, true, true, true, true, true } } } }; private static bool _armed; private static bool _gaveUp; private static bool _handlerHooked; private static float _nextAttempt; private static int _attempts; private static DialogueContainer _convo; private static DialogueNodeData _doneNode; public static void OnSessionEnded() { _armed = false; _gaveUp = false; _handlerHooked = false; _attempts = 0; _nextAttempt = 0f; _convo = null; _doneNode = null; } public static void Tick() { //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Expected O, but got Unknown //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown if (_armed || _gaveUp) { return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextAttempt) { return; } _nextAttempt = unscaledTime + 2f; NPC val = null; try { val = NPCManager.GetNPC("frank"); if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("frank_hoover"); } if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("frankhoover"); } if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("crankyfrank"); } if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("cranky_frank"); } if ((Object)(object)val == (Object)null) { Il2CppArrayBase val2 = Object.FindObjectsOfType(); for (int i = 0; i < val2.Length; i++) { NPC val3 = val2[i]; if (!((Object)(object)val3 == (Object)null)) { string text = ""; string text2 = ""; try { text = val3.ID ?? ""; } catch { } try { text2 = val3.FirstName ?? ""; } catch { } if (text.ToLowerInvariant().Contains("frank") || text2.ToLowerInvariant() == "frank") { val = val3; break; } } } } } catch (Exception ex) { MelonLogger.Warning("[Preset] Frank lookup error: " + ex.Message); } if ((Object)(object)val == (Object)null) { if (++_attempts >= 20) { _gaveUp = true; Diag.Log("[Preset] Cranky Frank not found in this world — pillar levels unavailable this session (cfg still works)."); } return; } try { string text3 = "?"; try { text3 = val.ID ?? "?"; } catch { } DialogueController val4 = ((Component)val).GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val).GetComponentInChildren(true); } if ((Object)(object)val4 == (Object)null && (Object)(object)val.DialogueHandler != (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponentInChildren(true); } } if ((Object)(object)val4 == (Object)null || val4.Choices == null) { _gaveUp = true; Diag.Log("[Preset] Frank (id '" + text3 + "') has no DialogueController — pillar levels unavailable this session."); return; } for (int j = 0; j < val4.Choices.Count; j++) { DialogueChoice val5 = val4.Choices[j]; if (val5 != null && (val5.ChoiceText ?? "").StartsWith("Adjust the survival")) { _armed = true; return; } } DialogueContainer val6 = BuildConversation(); DialogueChoice val7 = new DialogueChoice(); val7.Enabled = true; val7.ChoiceText = "Adjust the survival routine"; val7.ShowWorldspaceDialogue = false; val7.Conversation = val6; val7.Priority = 0; val7.onChoosen = new UnityEvent(); try { val4.AddDialogueChoice(val7, 0); } catch { val4.Choices.Add(val7); } DialogueHandler dialogueHandler = val.DialogueHandler; if ((Object)(object)dialogueHandler != (Object)null) { try { List dialogueContainers = dialogueHandler.dialogueContainers; if (dialogueContainers != null && !dialogueContainers.Contains(val6)) { dialogueContainers.Add(val6); } } catch { } if (!_handlerHooked) { dialogueHandler.onDialogueChoiceChosen.AddListener(UnityAction.op_Implicit((Action)OnChoice)); _handlerHooked = true; } } _armed = true; Diag.Log($"[Preset] Cranky Frank armed (id '{text3}') — 3 pillar submenus x 5 levels; his {val4.Choices.Count - 1} existing choice(s) untouched."); } catch (Exception value) { _gaveUp = true; Diag.Log($"[Preset] Frank wiring failed ({value}) — pillar levels unavailable this session."); } } private static DialogueContainer BuildConversation() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Expected O, but got Unknown //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown if ((Object)(object)_convo != (Object)null && Object.op_Implicit((Object)(object)_convo)) { return _convo; } DialogueContainer c = ScriptableObject.CreateInstance(); ((Object)c).name = "S1HT_PillarConversation"; ((Object)c).hideFlags = (HideFlags)32; c.DialogueNodeData = new List(); c.NodeLinks = new List(); c.BranchNodeData = new List(); DialogueNodeData val = new DialogueNodeData(); val.Guid = "S1HT_P_ENTRY"; val.DialogueNodeLabel = TacoDiag.DiscoveredEntryLabel; val.DialogueText = Lines.Pick(FrankEntryLines); val.choices = new Il2CppReferenceArray((long)(Pillars.Length + 1)); for (int i = 0; i < Pillars.Length; i++) { DialogueChoiceData val2 = new DialogueChoiceData(); val2.Guid = "S1HT_PCAT_" + Pillars[i].Key; val2.ChoiceLabel = val2.Guid; val2.ChoiceText = Pillars[i].ChoiceText; ((Il2CppArrayBase)(object)val.choices)[i] = val2; } DialogueChoiceData val3 = new DialogueChoiceData(); val3.Guid = "S1HT_P_EXIT"; val3.ChoiceLabel = "S1HT_P_EXIT"; val3.ChoiceText = "Never mind."; ((Il2CppArrayBase)(object)val.choices)[Pillars.Length] = val3; c.DialogueNodeData.Add(val); DialogueNodeData val4 = new DialogueNodeData(); val4.Guid = "S1HT_P_DONE"; val4.DialogueNodeLabel = "S1HT_P_DONE"; val4.DialogueText = "Done."; val4.choices = new Il2CppReferenceArray(0L); c.DialogueNodeData.Add(val4); DialogueNodeData val5 = new DialogueNodeData(); val5.Guid = "S1HT_P_BYE"; val5.DialogueNodeLabel = "S1HT_P_BYE"; val5.DialogueText = Lines.Pick(FrankByeLines); val5.choices = new Il2CppReferenceArray(0L); c.DialogueNodeData.Add(val5); Link(val.Guid, val3.Guid, val5.Guid); for (int j = 0; j < Pillars.Length; j++) { Pillar pillar = Pillars[j]; DialogueNodeData val6 = new DialogueNodeData(); val6.Guid = "S1HT_P_NODE_" + pillar.Key; val6.DialogueNodeLabel = val6.Guid; val6.DialogueText = Lines.Pick(pillar.NodeTexts); val6.choices = new Il2CppReferenceArray((long)(LevelNames.Length + 1)); for (int k = 0; k < LevelNames.Length; k++) { DialogueChoiceData val7 = new DialogueChoiceData(); val7.Guid = $"{"S1HT_P_"}{pillar.Key}_{k}"; val7.ChoiceLabel = val7.Guid; val7.ChoiceText = LevelChoiceTexts[k]; ((Il2CppArrayBase)(object)val6.choices)[k] = val7; Link(val6.Guid, val7.Guid, val4.Guid); } DialogueChoiceData val8 = new DialogueChoiceData(); val8.Guid = "S1HT_P_BACK_" + pillar.Key; val8.ChoiceLabel = val8.Guid; val8.ChoiceText = "Something else."; ((Il2CppArrayBase)(object)val6.choices)[LevelNames.Length] = val8; c.DialogueNodeData.Add(val6); Link(val.Guid, "S1HT_PCAT_" + pillar.Key, val6.Guid); Link(val6.Guid, val8.Guid, val.Guid); } _convo = c; _doneNode = val4; return c; void Link(string fromNode, string viaChoice, string toNode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown NodeLinkData val9 = new NodeLinkData(); val9.BaseDialogueOrBranchNodeGuid = fromNode; val9.BaseChoiceOrOptionGUID = viaChoice; val9.TargetNodeGuid = toNode; c.NodeLinks.Add(val9); } } private static void OnChoice(string chosen) { if (string.IsNullOrEmpty(chosen) || !chosen.StartsWith("S1HT_P_")) { return; } string[] array = chosen.Substring("S1HT_P_".Length).Split('_'); if (array.Length != 2 || !int.TryParse(array[1], out var result)) { return; } for (int i = 0; i < Pillars.Length; i++) { if (string.Equals(Pillars[i].Key, array[0], StringComparison.OrdinalIgnoreCase)) { ApplyLevel(Pillars[i], result); break; } } } private static void ApplyLevel(Pillar pillar, int level) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) try { if (level < 0 || level >= LevelNames.Length) { return; } int num = 0; int num2 = 0; for (int i = 0; i < pillar.Rows.Length; i++) { if (NeedsConfig.TrySetEntry((string)pillar.Rows[i][0], pillar.Rows[i][level + 1])) { num++; } else { num2++; } } if (_doneNode != null) { _doneNode.DialogueText = Lines.Pick(ConfirmPools[level], pillar.Word); } try { MelonPreferences.Save(); } catch (Exception ex) { MelonLogger.Warning("[Preset] save failed: " + ex.Message); } NeedsHud.Toast(Lines.Pick(FrankToasts, pillar.Word.ToLowerInvariant() + " to " + LevelNames[level]), NeedsHud.ToastGood); Diag.Log($"[Preset] pillar {pillar.Word} → {LevelNames[level]}: {num} value(s) written{((num2 > 0) ? $", {num2} MISSED" : "")}, saved + live-reloaded."); } catch (Exception ex2) { Diag.Log("[Preset] pillar apply failed: " + ex2.Message); } } } public static class Taco3D { public readonly struct FillingLook { public readonly Color Primary; public readonly Color Secondary; public readonly Color Accent; public readonly Color LettuceA; public readonly Color LettuceB; public FillingLook(Color primary, Color secondary, Color accent, Color lettuceA, Color lettuceB) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) Primary = primary; Secondary = secondary; Accent = accent; LettuceA = lettuceA; LettuceB = lettuceB; } } private struct P { public float R; public float Y; public float V; public P(float r, float y, float v) { R = r; Y = y; V = v; } } private static Mesh _mesh; private static readonly Dictionary _materials = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _palettes = new Dictionary(StringComparer.OrdinalIgnoreCase); public static readonly FillingLook BeefLook = new FillingLook(new Color(0.45f, 0.28f, 0.16f), new Color(0.55f, 0.34f, 0.18f), new Color(0.78f, 0.24f, 0.17f), new Color(0.42f, 0.66f, 0.25f), new Color(0.33f, 0.55f, 0.2f)); public static readonly FillingLook ChickenLook = new FillingLook(new Color(0.85f, 0.72f, 0.48f), new Color(0.92f, 0.82f, 0.58f), new Color(0.78f, 0.24f, 0.17f), new Color(0.42f, 0.66f, 0.25f), new Color(0.33f, 0.55f, 0.2f)); public static readonly FillingLook VeggieLook = new FillingLook(new Color(0.42f, 0.66f, 0.25f), new Color(0.78f, 0.24f, 0.17f), new Color(0.95f, 0.75f, 0.2f), new Color(0.48f, 0.72f, 0.28f), new Color(0.36f, 0.58f, 0.22f)); public static readonly FillingLook MysteryLook = new FillingLook(new Color(0.45f, 0.48f, 0.36f), new Color(0.38f, 0.33f, 0.42f), new Color(0.55f, 0.58f, 0.3f), new Color(0.5f, 0.55f, 0.3f), new Color(0.4f, 0.44f, 0.26f)); public static readonly FillingLook ManukeLook = new FillingLook(new Color(0.55f, 0.22f, 0.18f), new Color(0.88f, 0.78f, 0.72f), new Color(0.95f, 0.78f, 0.25f), new Color(0.42f, 0.66f, 0.25f), new Color(0.58f, 0.62f, 0.24f)); public static readonly FillingLook KyleSpecialLook = new FillingLook(new Color(0.5f, 0.3f, 0.18f), new Color(0.62f, 0.38f, 0.2f), new Color(0.9f, 0.88f, 0.8f), new Color(0.96f, 0.95f, 0.9f), new Color(0.88f, 0.86f, 0.8f)); public static readonly FillingLook BurroitoLook = new FillingLook(new Color(0.72f, 0.52f, 0.28f), new Color(0.8f, 0.6f, 0.32f), new Color(0.66f, 0.46f, 0.24f), new Color(0.8f, 0.6f, 0.32f), new Color(0.72f, 0.52f, 0.28f)); public static readonly FillingLook PastryLook = new FillingLook(new Color(0.85f, 0.66f, 0.36f), new Color(0.78f, 0.58f, 0.3f), new Color(0.7f, 0.5f, 0.26f), new Color(0.8f, 0.62f, 0.34f), new Color(0.72f, 0.54f, 0.28f)); public static readonly FillingLook EggRollLook = new FillingLook(new Color(0.93f, 0.8f, 0.42f), new Color(0.86f, 0.7f, 0.34f), new Color(0.78f, 0.3f, 0.2f), new Color(0.88f, 0.74f, 0.38f), new Color(0.8f, 0.64f, 0.32f)); public static readonly FillingLook SlusheeLook = new FillingLook(new Color(0.22f, 0.52f, 0.88f), new Color(0.28f, 0.6f, 0.94f), new Color(0.18f, 0.44f, 0.78f), new Color(0.85f, 0.9f, 0.96f), new Color(0.76f, 0.82f, 0.9f)); public static readonly FillingLook CoffeeLook = new FillingLook(new Color(0.9f, 0.86f, 0.78f), new Color(0.84f, 0.8f, 0.72f), new Color(0.94f, 0.9f, 0.82f), new Color(0.38f, 0.26f, 0.18f), new Color(0.32f, 0.22f, 0.15f)); public static readonly FillingLook WaterLook = new FillingLook(new Color(0.72f, 0.84f, 0.94f), new Color(0.66f, 0.8f, 0.92f), new Color(0.8f, 0.9f, 0.97f), new Color(0.55f, 0.72f, 0.88f), new Color(0.48f, 0.66f, 0.84f)); public static readonly FillingLook SoupLook = new FillingLook(new Color(0.86f, 0.66f, 0.3f), new Color(0.8f, 0.58f, 0.26f), new Color(0.92f, 0.76f, 0.4f), new Color(0.78f, 0.56f, 0.26f), new Color(0.7f, 0.5f, 0.22f)); public static readonly FillingLook ChocoLook = new FillingLook(new Color(0.34f, 0.22f, 0.14f), new Color(0.4f, 0.26f, 0.16f), new Color(0.28f, 0.18f, 0.12f), new Color(0.38f, 0.24f, 0.15f), new Color(0.3f, 0.2f, 0.13f)); public static readonly FillingLook BeerLook = new FillingLook(new Color(0.85f, 0.58f, 0.2f), new Color(0.78f, 0.5f, 0.16f), new Color(0.9f, 0.66f, 0.26f), new Color(0.96f, 0.94f, 0.86f), new Color(0.9f, 0.88f, 0.8f)); public static readonly FillingLook WineLook = new FillingLook(new Color(0.76f, 0.76f, 0.8f), new Color(0.7f, 0.7f, 0.74f), new Color(0.82f, 0.82f, 0.86f), new Color(0.52f, 0.14f, 0.2f), new Color(0.44f, 0.12f, 0.17f)); public static readonly FillingLook PizzaLook = new FillingLook(new Color(0.92f, 0.76f, 0.34f), new Color(0.84f, 0.8f, 0.58f), new Color(0.62f, 0.32f, 0.22f), new Color(0.85f, 0.8f, 0.55f), new Color(0.76f, 0.7f, 0.46f)); public static readonly FillingLook TeaLook = new FillingLook(new Color(0.72f, 0.8f, 0.58f), new Color(0.66f, 0.75f, 0.52f), new Color(0.8f, 0.86f, 0.66f), new Color(0.46f, 0.58f, 0.34f), new Color(0.4f, 0.52f, 0.3f)); public static readonly FillingLook RedLook = new FillingLook(new Color(0.78f, 0.16f, 0.22f), new Color(0.7f, 0.12f, 0.18f), new Color(0.88f, 0.26f, 0.3f), new Color(0.9f, 0.86f, 0.82f), new Color(0.84f, 0.8f, 0.76f)); public static readonly FillingLook FishLook = new FillingLook(new Color(0.82f, 0.64f, 0.56f), new Color(0.74f, 0.58f, 0.52f), new Color(0.88f, 0.72f, 0.62f), new Color(0.72f, 0.6f, 0.52f), new Color(0.64f, 0.54f, 0.48f)); public static readonly FillingLook ChiliLook = new FillingLook(new Color(0.58f, 0.2f, 0.1f), new Color(0.72f, 0.52f, 0.3f), new Color(0.9f, 0.85f, 0.74f), new Color(0.86f, 0.8f, 0.7f), new Color(0.78f, 0.72f, 0.62f)); public static readonly FillingLook MugCoffeeLook = new FillingLook(new Color(0.3f, 0.2f, 0.13f), new Color(0.36f, 0.25f, 0.16f), new Color(0.92f, 0.9f, 0.86f), new Color(0.34f, 0.23f, 0.15f), new Color(0.28f, 0.19f, 0.12f)); public static readonly FillingLook MugTeaLook = new FillingLook(new Color(0.62f, 0.72f, 0.42f), new Color(0.56f, 0.66f, 0.38f), new Color(0.93f, 0.92f, 0.88f), new Color(0.58f, 0.68f, 0.4f), new Color(0.52f, 0.62f, 0.36f)); public static readonly FillingLook SoupBowlLook = new FillingLook(new Color(0.86f, 0.66f, 0.3f), new Color(0.8f, 0.58f, 0.26f), new Color(0.92f, 0.88f, 0.8f), new Color(0.78f, 0.56f, 0.26f), new Color(0.7f, 0.5f, 0.22f)); public static readonly FillingLook SlopBowlLook = new FillingLook(new Color(0.52f, 0.44f, 0.34f), new Color(0.46f, 0.4f, 0.32f), new Color(0.72f, 0.72f, 0.74f), new Color(0.48f, 0.42f, 0.33f), new Color(0.42f, 0.36f, 0.28f)); public static readonly FillingLook OnionSoupLook = new FillingLook(new Color(0.74f, 0.52f, 0.24f), new Color(0.68f, 0.46f, 0.2f), new Color(0.48f, 0.3f, 0.18f), new Color(0.93f, 0.8f, 0.44f), new Color(0.8f, 0.62f, 0.3f)); public static readonly FillingLook BruleeLook = new FillingLook(new Color(0.95f, 0.86f, 0.6f), new Color(0.92f, 0.82f, 0.55f), new Color(0.94f, 0.92f, 0.88f), new Color(0.55f, 0.34f, 0.12f), new Color(0.46f, 0.27f, 0.09f)); public static readonly FillingLook RamenLook = new FillingLook(new Color(0.92f, 0.82f, 0.52f), new Color(0.86f, 0.74f, 0.44f), new Color(0.9f, 0.88f, 0.84f), new Color(0.88f, 0.78f, 0.48f), new Color(0.82f, 0.7f, 0.42f)); public static readonly FillingLook BeerGlassLook = new FillingLook(new Color(0.85f, 0.58f, 0.2f), new Color(0.8f, 0.52f, 0.17f), new Color(0.8f, 0.82f, 0.84f), new Color(0.96f, 0.94f, 0.86f), new Color(0.9f, 0.88f, 0.8f)); public static readonly FillingLook VodkaGlassLook = new FillingLook(new Color(0.8f, 0.87f, 0.92f), new Color(0.74f, 0.82f, 0.88f), new Color(0.82f, 0.85f, 0.88f), new Color(0.93f, 0.96f, 0.98f), new Color(0.85f, 0.9f, 0.94f)); public static readonly FillingLook CanaryGlassLook = new FillingLook(new Color(0.78f, 0.16f, 0.22f), new Color(0.7f, 0.12f, 0.18f), new Color(0.8f, 0.82f, 0.84f), new Color(0.92f, 0.84f, 0.82f), new Color(0.84f, 0.3f, 0.32f)); public static readonly FillingLook TallboyLook = new FillingLook(new Color(0.16f, 0.52f, 0.52f), new Color(0.14f, 0.46f, 0.48f), new Color(0.76f, 0.78f, 0.8f), new Color(0.7f, 0.72f, 0.74f), new Color(0.62f, 0.64f, 0.66f)); public static readonly FillingLook WaterBottleLook = new FillingLook(new Color(0.72f, 0.84f, 0.94f), new Color(0.66f, 0.8f, 0.92f), new Color(0.8f, 0.9f, 0.97f), new Color(0.94f, 0.96f, 0.98f), new Color(0.86f, 0.9f, 0.94f)); public static readonly FillingLook SlusheeCupLook = new FillingLook(new Color(0.22f, 0.52f, 0.88f), new Color(0.28f, 0.6f, 0.94f), new Color(0.85f, 0.9f, 0.96f), new Color(0.9f, 0.93f, 0.97f), new Color(0.78f, 0.84f, 0.92f)); public static readonly FillingLook WineCartonLook = new FillingLook(new Color(0.46f, 0.14f, 0.2f), new Color(0.4f, 0.12f, 0.17f), new Color(0.82f, 0.8f, 0.78f), new Color(0.78f, 0.78f, 0.82f), new Color(0.7f, 0.7f, 0.74f)); public static readonly FillingLook SandwichLook = new FillingLook(new Color(0.46f, 0.62f, 0.28f), new Color(0.85f, 0.45f, 0.35f), new Color(0.9f, 0.86f, 0.78f), new Color(0.5f, 0.66f, 0.3f), new Color(0.42f, 0.56f, 0.26f)); public static readonly FillingLook TunaSandwichLook = new FillingLook(new Color(0.84f, 0.78f, 0.64f), new Color(0.78f, 0.7f, 0.56f), new Color(0.9f, 0.86f, 0.78f), new Color(0.8f, 0.74f, 0.6f), new Color(0.74f, 0.68f, 0.54f)); public static readonly FillingLook RoastChickenLook = new FillingLook(new Color(0.8f, 0.52f, 0.22f), new Color(0.72f, 0.44f, 0.18f), new Color(0.86f, 0.6f, 0.28f), new Color(0.76f, 0.48f, 0.2f), new Color(0.68f, 0.4f, 0.16f)); public static readonly FillingLook PizzaSliceLook = new FillingLook(new Color(0.72f, 0.3f, 0.18f), new Color(0.66f, 0.26f, 0.16f), new Color(0.85f, 0.66f, 0.32f), new Color(0.92f, 0.76f, 0.34f), new Color(0.82f, 0.76f, 0.52f)); public static readonly FillingLook BratLook = new FillingLook(new Color(0.55f, 0.3f, 0.18f), new Color(0.48f, 0.26f, 0.15f), new Color(0.62f, 0.42f, 0.22f), new Color(0.52f, 0.28f, 0.16f), new Color(0.46f, 0.24f, 0.14f)); public static readonly FillingLook TakeoutLook = new FillingLook(new Color(0.72f, 0.38f, 0.16f), new Color(0.66f, 0.32f, 0.13f), new Color(0.92f, 0.9f, 0.86f), new Color(0.68f, 0.34f, 0.14f), new Color(0.62f, 0.3f, 0.12f)); public static readonly FillingLook SteakPlateLook = new FillingLook(new Color(0.58f, 0.28f, 0.2f), new Color(0.52f, 0.24f, 0.17f), new Color(0.93f, 0.92f, 0.9f), new Color(0.38f, 0.2f, 0.14f), new Color(0.32f, 0.16f, 0.11f)); public static readonly FillingLook SmokedFishLook = new FillingLook(new Color(0.86f, 0.6f, 0.48f), new Color(0.8f, 0.54f, 0.44f), new Color(0.82f, 0.62f, 0.5f), new Color(0.62f, 0.42f, 0.28f), new Color(0.54f, 0.36f, 0.24f)); public static readonly FillingLook FishChipsLook = new FillingLook(new Color(0.9f, 0.72f, 0.36f), new Color(0.84f, 0.64f, 0.3f), new Color(0.92f, 0.9f, 0.86f), new Color(0.86f, 0.66f, 0.32f), new Color(0.78f, 0.58f, 0.26f)); public static readonly FillingLook BrownieLook = new FillingLook(new Color(0.32f, 0.2f, 0.13f), new Color(0.38f, 0.25f, 0.16f), new Color(0.3f, 0.19f, 0.12f), new Color(0.44f, 0.3f, 0.19f), new Color(0.36f, 0.23f, 0.14f)); public static readonly FillingLook DanChiliBowlLook = new FillingLook(new Color(0.58f, 0.2f, 0.1f), new Color(0.72f, 0.52f, 0.3f), new Color(0.9f, 0.85f, 0.74f), new Color(0.62f, 0.24f, 0.12f), new Color(0.52f, 0.18f, 0.09f)); public static readonly FillingLook LasagnaLook = new FillingLook(new Color(0.62f, 0.28f, 0.18f), new Color(0.85f, 0.7f, 0.42f), new Color(0.52f, 0.22f, 0.14f), new Color(0.93f, 0.78f, 0.38f), new Color(0.72f, 0.48f, 0.22f)); public static readonly FillingLook SausageRollLook = new FillingLook(new Color(0.55f, 0.3f, 0.18f), new Color(0.48f, 0.26f, 0.15f), new Color(0.86f, 0.68f, 0.36f), new Color(0.8f, 0.6f, 0.3f), new Color(0.72f, 0.52f, 0.26f)); public static readonly FillingLook SteamedBunLook = new FillingLook(new Color(0.72f, 0.42f, 0.32f), new Color(0.66f, 0.36f, 0.28f), new Color(0.95f, 0.93f, 0.9f), new Color(0.88f, 0.86f, 0.82f), new Color(0.82f, 0.8f, 0.76f)); private static Mesh _burritoMesh; private static Mesh _cupMesh; private static Mesh _slabMesh; private const float OUT = 0.0625f; private const float INN = 0.1875f; private const float FIL = 0.4375f; private const float VES = 0.6875f; private const float TOP = 0.9375f; private static readonly Dictionary _archetypes = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Mesh GetCupMesh() { //IL_0095: 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_01a8: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Expected O, but got Unknown //IL_0207: Expected O, but got Unknown //IL_0166: 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) if ((Object)(object)_cupMesh != (Object)null && Object.op_Implicit((Object)(object)_cupMesh)) { return _cupMesh; } List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; for (int i = 0; i < 9; i++) { float num = (float)i / 8f; float num2 = num * 0.115f; float num3 = Mathf.Lerp(0.032f, 0.042f, num); for (int j = 0; j < 18; j++) { float num4 = (float)Math.PI * 2f * (float)j / 17f; list.Add(new Vector3(num3 * Mathf.Cos(num4), num2, num3 * Mathf.Sin(num4))); list2.Add(new Vector2(num * 2f, 0.4375f)); } } AddGrid(list3, count, 9, 18, flip: false); int count2 = list.Count; for (int k = 0; k < 5; k++) { float num5 = (float)k / 4f; float num6 = 0.042f * (1f - num5 * num5 * 0.92f) + 0.003f; float num7 = 0.115f + 0.012f * Mathf.Sin(num5 * (float)Math.PI * 0.5f); for (int l = 0; l < 18; l++) { float num8 = (float)Math.PI * 2f * (float)l / 17f; list.Add(new Vector3(num6 * Mathf.Cos(num8), num7, num6 * Mathf.Sin(num8))); list2.Add(new Vector2(num5, 0.9375f)); } } AddGrid(list3, count2, 5, 18, flip: false); Mesh val = new Mesh { name = "S1HT_Cup" }; val.SetVertices(Il2CppStructArray.op_Implicit(list.ToArray())); val.SetUVs(0, Il2CppStructArray.op_Implicit(list2.ToArray())); val.triangles = Il2CppStructArray.op_Implicit(list3.ToArray()); val.RecalculateNormals(); val.RecalculateBounds(); ((Object)val).hideFlags = (HideFlags)32; _cupMesh = val; return val; } public static Mesh GetBurritoMesh() { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: 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_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Expected O, but got Unknown //IL_01eb: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_burritoMesh != (Object)null && Object.op_Implicit((Object)(object)_burritoMesh)) { return _burritoMesh; } List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; for (int i = 0; i < 25; i++) { float num = (float)i / 24f; float num2 = (num * 2f - 1f) * 0.085f; float num3 = Mathf.Clamp01(Mathf.Min(num, 1f - num) / 0.18f); float num4 = num3 * num3 * (3f - 2f * num3); float num5 = 0.05f * (0.06f + 0.94f * num4) * (1f + 0.05f * Mathf.Sin((float)Math.PI * num)); bool flag = num < 0.14f || num > 0.86f; for (int j = 0; j < 20; j++) { float num6 = (float)Math.PI * 2f * (float)j / 19f; float num7 = 1f + 0.04f * Mathf.Sin(num * 17f + (float)j * 1.9f); list.Add(new Vector3(num2, num5 * Mathf.Cos(num6) * num7, num5 * Mathf.Sin(num6) * num7)); list2.Add(new Vector2(num * 3f, flag ? 0.1875f : 0.0625f)); } } AddGrid(list3, count, 25, 20, flip: false); Mesh val = new Mesh { name = "S1HT_Burroito" }; val.SetVertices(Il2CppStructArray.op_Implicit(list.ToArray())); val.SetUVs(0, Il2CppStructArray.op_Implicit(list2.ToArray())); val.triangles = Il2CppStructArray.op_Implicit(list3.ToArray()); val.RecalculateNormals(); val.RecalculateBounds(); ((Object)val).hideFlags = (HideFlags)32; _burritoMesh = val; return val; } public static Mesh GetSlabMesh() { //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Expected O, but got Unknown //IL_0225: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_slabMesh != (Object)null && Object.op_Implicit((Object)(object)_slabMesh)) { return _slabMesh; } List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; for (int i = 0; i < 15; i++) { float num = (float)i / 14f; float num2 = (num * 2f - 1f) * 0.055f; float num3 = Mathf.Clamp01(Mathf.Min(num, 1f - num) / 0.08f); float num4 = 0.05f + 0.95f * (num3 * num3 * (3f - 2f * num3)); float num5 = 1f + 0.1f * Mathf.Sin((float)Math.PI * num); for (int j = 0; j < 22; j++) { float num6 = (float)Math.PI * 2f * (float)j / 21f; float num7 = Mathf.Cos(num6); float num8 = Mathf.Sin(num6); float num9 = 0.026f * Mathf.Sign(num7) * Mathf.Pow(Mathf.Abs(num7), 0.55f); float num10 = 0.043f * Mathf.Sign(num8) * Mathf.Pow(Mathf.Abs(num8), 0.55f); if (num9 > 0f) { num9 *= num5; } float num11 = 1f + 0.03f * Mathf.Sin(num * 13f + (float)j * 2.3f); list.Add(new Vector3(num2, num9 * num4 * num11, num10 * num4 * num11)); list2.Add(new Vector2(num * 2f, (num7 > 0.45f) ? 0.9375f : 0.4375f)); } } AddGrid(list3, count, 15, 22, flip: false); Mesh val = new Mesh { name = "S1HT_Slab" }; val.SetVertices(Il2CppStructArray.op_Implicit(list.ToArray())); val.SetUVs(0, Il2CppStructArray.op_Implicit(list2.ToArray())); val.triangles = Il2CppStructArray.op_Implicit(list3.ToArray()); val.RecalculateNormals(); val.RecalculateBounds(); ((Object)val).hideFlags = (HideFlags)32; _slabMesh = val; return val; } public static GameObject CreateBurritoObject(Renderer materialDonor, float scale, int layer) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("S1HT_Burroito3D"); val.AddComponent().sharedMesh = GetBurritoMesh(); MeshRenderer val2 = val.AddComponent(); Material material = GetMaterial(materialDonor, "burroito", BurroitoLook); if ((Object)(object)material != (Object)null) { ((Renderer)val2).sharedMaterial = material; } val.transform.localScale = Vector3.one * scale; if (layer >= 0) { val.layer = layer; } return val; } public static Mesh GetMesh() { //IL_00a6: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Expected O, but got Unknown //IL_04c7: Expected O, but got Unknown //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_mesh != (Object)null && Object.op_Implicit((Object)(object)_mesh)) { return _mesh; } List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; for (int i = 0; i < 17; i++) { float num = (float)i / 16f; float x = (num * 2f - 1f) * 0.075f; float num2 = RadiusAt(num); for (int j = 0; j < 18; j++) { float num3 = (float)Math.PI / 180f * Mathf.Lerp(140f, 400f, (float)j / 17f); list.Add(V(x, num2 * Mathf.Cos(num3), num2 * Mathf.Sin(num3))); list2.Add(new Vector2(num, 0.0625f)); } } AddGrid(list3, count, 17, 18, flip: false); int count2 = list.Count; for (int k = 0; k < 17; k++) { float num4 = (float)k / 16f; float x2 = (num4 * 2f - 1f) * 0.075f; float num5 = RadiusAt(num4) * 0.9f; for (int l = 0; l < 18; l++) { float num6 = (float)Math.PI / 180f * Mathf.Lerp(140f, 400f, (float)l / 17f); list.Add(V(x2, num5 * Mathf.Cos(num6), num5 * Mathf.Sin(num6))); list2.Add(new Vector2(num4, 0.1875f)); } } AddGrid(list3, count2, 17, 18, flip: true); for (int m = 0; m < 2; m++) { int num7 = ((m != 0) ? 17 : 0); for (int n = 0; n < 16; n++) { int a = count + n * 18 + num7; int num8 = count + (n + 1) * 18 + num7; int num9 = count2 + n * 18 + num7; int c = count2 + (n + 1) * 18 + num7; if (m == 0) { AddQuad(list3, a, num8, c, num9); } else { AddQuad(list3, a, num9, c, num8); } } } int count3 = list.Count; for (int num10 = 0; num10 < 17; num10++) { float num11 = (float)num10 / 16f; float x3 = (num11 * 2f - 1f) * 0.075f * 0.94f; float num12 = RadiusAt(num11) * 0.9f; float num13 = num12 * 0.5f; float num14 = num12 * 0.32f; for (int num15 = 0; num15 < 11; num15++) { float num16 = (float)Math.PI / 180f * Mathf.Lerp(-15f, 195f, (float)num15 / 10f); float num17 = 1f + 0.06f * Mathf.Sin(num11 * 19f + (float)num15 * 2.1f); list.Add(V(x3, num13 * Mathf.Cos(num16) * 0.8f * num17, num14 + num13 * Mathf.Sin(num16) * 0.66f * num17)); list2.Add(new Vector2(num11 * 2f, 0.4375f)); } } AddGrid(list3, count3, 17, 11, flip: false); int count4 = list.Count; for (int num18 = 0; num18 < 17; num18++) { float num19 = (float)num18 / 16f; float x4 = (num19 * 2f - 1f) * 0.075f * 0.9f; float num20 = RadiusAt(num19) * 0.9f; float num21 = num20 * 0.36f; float num22 = num20 * 0.58f; for (int num23 = 0; num23 < 9; num23++) { float num24 = (float)num23 / 8f; float num25 = (float)Math.PI / 180f * Mathf.Lerp(-8f, 188f, num24); float num26 = 1f + 0.16f * Mathf.Sin(num19 * 23f + (float)num23 * 3.7f); float num27 = num21 * num26; list.Add(V(x4, num27 * Mathf.Cos(num25) * 0.72f, num22 + num27 * Mathf.Sin(num25) * 0.8f)); list2.Add(new Vector2(num19 * 3f, 0.9375f)); } } AddGrid(list3, count4, 17, 9, flip: false); Mesh val = new Mesh { name = "S1HT_Taco" }; val.SetVertices(Il2CppStructArray.op_Implicit(list.ToArray())); val.SetUVs(0, Il2CppStructArray.op_Implicit(list2.ToArray())); val.triangles = Il2CppStructArray.op_Implicit(list3.ToArray()); val.RecalculateNormals(); val.RecalculateBounds(); ((Object)val).hideFlags = (HideFlags)32; _mesh = val; return val; static float RadiusAt(float t) { float num28 = (t * 2f - 1f) * 0.075f; return Mathf.Sqrt(Mathf.Max(0.0001f, 0.005625f - num28 * num28)); } static Vector3 V(float num28, float y, float z) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) return new Vector3(num28, z, 0f - y); } } private static void AddGrid(List tris, int start, int nx, int na, bool flip) { for (int i = 0; i < nx - 1; i++) { for (int j = 0; j < na - 1; j++) { int num = start + i * na + j; int item = num + 1; int num2 = num + na; int item2 = num2 + 1; if (!flip) { tris.Add(num); tris.Add(item); tris.Add(num2); tris.Add(item); tris.Add(item2); tris.Add(num2); } else { tris.Add(num); tris.Add(num2); tris.Add(item); tris.Add(item); tris.Add(num2); tris.Add(item2); } } } } private static void AddQuad(List tris, int a, int b, int c, int d) { tris.Add(a); tris.Add(b); tris.Add(c); tris.Add(a); tris.Add(c); tris.Add(d); } private static Mesh Finish(string name, List v, List uv, List t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown Mesh val = new Mesh { name = name }; val.SetVertices(Il2CppStructArray.op_Implicit(v.ToArray())); val.SetUVs(0, Il2CppStructArray.op_Implicit(uv.ToArray())); val.triangles = Il2CppStructArray.op_Implicit(t.ToArray()); val.RecalculateNormals(); val.RecalculateBounds(); ((Object)val).hideFlags = (HideFlags)32; return val; } private static void LatheInto(List verts, List uvs, List tris, P[] profile, int na, Vector3 offset, float wobble = 0f, float phase = 0f) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) int count = verts.Count; for (int i = 0; i < profile.Length; i++) { P p = profile[i]; for (int j = 0; j < na; j++) { float num = (float)Math.PI * 2f * (float)j / (float)(na - 1) + phase; float num2 = 1f + wobble * Mathf.Sin((float)i * 4.7f + (float)j * 2.1f); verts.Add(offset + new Vector3(p.R * num2 * Mathf.Cos(num), p.Y, p.R * num2 * Mathf.Sin(num))); uvs.Add(new Vector2((float)i * 0.35f + (float)j * 0.11f, p.V)); } } AddGrid(tris, count, profile.Length, na, flip: false); } private static void SlabInto(List verts, List uvs, List tris, float halfLen, float halfH, float halfD, float topV, float sideV, Vector3 offset, float dome = 0.1f, float wobble = 0.03f) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) int count = verts.Count; for (int i = 0; i < 13; i++) { float num = (float)i / 12f; float num2 = (num * 2f - 1f) * halfLen; float num3 = Mathf.Clamp01(Mathf.Min(num, 1f - num) / 0.09f); float num4 = 0.05f + 0.95f * (num3 * num3 * (3f - 2f * num3)); float num5 = 1f + dome * Mathf.Sin((float)Math.PI * num); for (int j = 0; j < 18; j++) { float num6 = (float)Math.PI * 2f * (float)j / 17f; float num7 = Mathf.Cos(num6); float num8 = Mathf.Sin(num6); float num9 = halfH * Mathf.Sign(num7) * Mathf.Pow(Mathf.Abs(num7), 0.55f); float num10 = halfD * Mathf.Sign(num8) * Mathf.Pow(Mathf.Abs(num8), 0.55f); if (num9 > 0f) { num9 *= num5; } float num11 = 1f + wobble * Mathf.Sin(num * 13f + (float)j * 2.3f); verts.Add(offset + new Vector3(num2, num9 * num4 * num11, num10 * num4 * num11)); uvs.Add(new Vector2(num * 2f, (num7 > 0.45f) ? topV : sideV)); } } AddGrid(tris, count, 13, 18, flip: false); } private static Mesh Cached(string key, Func build) { if (_archetypes.TryGetValue(key, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } value = build(); _archetypes[key] = value; return value; } public static Mesh GetBowlMesh(string key, float r = 0.052f, float h = 0.034f, float contentsV = 0.4375f) { return Cached(key, delegate { //IL_013a: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[8] { new P(0f, 0f, 0.6875f), new P(r * 0.55f, 0f, 0.6875f), new P(r * 0.92f, h * 0.45f, 0.6875f), new P(r, h, 0.6875f), new P(r * 0.93f, h, 0.6875f), new P(r * 0.88f, h * 0.86f, contentsV), new P(r * 0.5f, h * 0.82f, contentsV), new P(0f, h * 0.84f, contentsV) }, 20, Vector3.zero, 0.015f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetMugMesh(string key, float r = 0.031f, float h = 0.072f) { return Cached(key, delegate { //IL_0108: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.6875f), new P(r * 0.85f, 0f, 0.6875f), new P(r, h * 0.08f, 0.6875f), new P(r, h, 0.6875f), new P(r * 0.9f, h, 0.6875f), new P(r * 0.86f, h * 0.9f, 0.4375f), new P(0f, h * 0.88f, 0.4375f) }, 18, Vector3.zero, 0.01f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetGlassMesh(string key, float r0, float r1, float h, float headFrac) { return Cached(key, delegate { //IL_0149: Unknown result type (might be due to invalid IL or missing references) float num = h * (1f - headFrac); List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[8] { new P(0f, 0f, 0.6875f), new P(r0 * 0.9f, 0f, 0.6875f), new P(r0, h * 0.04f, 0.4375f), new P(Mathf.Lerp(r0, r1, 0.6f), num, 0.4375f), new P(Mathf.Lerp(r0, r1, 0.62f), num + 0.001f, 0.9375f), new P(r1, h, 0.9375f), new P(r1 * 0.85f, h, 0.9375f), new P(0f, h * 0.99f, 0.9375f) }, 18, Vector3.zero); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetBottleMesh(string key) { return Cached(key, delegate { //IL_012d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[10] { new P(0f, 0f, 0.4375f), new P(0.0207f, 0f, 0.4375f), new P(0.023f, 0.0069f, 0.4375f), new P(0.023f, 0.063250005f, 0.4375f), new P(0.01265f, 0.08625f, 0.4375f), new P(0.0092f, 0.0943f, 0.4375f), new P(0.0092f, 0.1012f, 0.4375f), new P(0.01035f, 0.1035f, 0.9375f), new P(0.01035f, 0.115f, 0.9375f), new P(0f, 0.115f, 0.9375f) }, 16, Vector3.zero); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetCanMesh(string key) { return Cached(key, delegate { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[6] { new P(0f, 0f, 0.6875f), new P(0.02132f, 0f, 0.6875f), new P(0.026f, 0.0036799998f, 0.4375f), new P(0.026f, 0.084640004f, 0.4375f), new P(0.02236f, 0.092f, 0.6875f), new P(0f, 0.092f, 0.6875f) }, 18, Vector3.zero); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetNoodleCupMesh(string key) { return Cached(key, delegate { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[8] { new P(0f, 0f, 0.6875f), new P(0.026999999f, 0f, 0.6875f), new P(0.03f, 0.0028f, 0.6875f), new P(0.042f, 0.07f, 0.6875f), new P(0.03948f, 0.07f, 0.6875f), new P(0.0378f, 0.063f, 0.4375f), new P(0.021f, 0.0616f, 0.4375f), new P(0f, 0.063f, 0.4375f) }, 18, Vector3.zero, 0.012f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetStrawCupMesh(string key) { return Cached(key, delegate { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.4375f), new P(0.028800001f, 0f, 0.4375f), new P(0.032f, 0.00345f, 0.4375f), new P(0.042f, 0.115f, 0.4375f), new P(0.04158f, 0.119f, 0.9375f), new P(0.0168f, 0.128f, 0.9375f), new P(0f, 0.12900001f, 0.9375f) }, 18, Vector3.zero); LatheInto(list, list2, list3, new P[4] { new P(0.0045f, 0.115f, 0.9375f), new P(0.0045f, 0.16f, 0.9375f), new P(0.002f, 0.163f, 0.9375f), new P(0f, 0.163f, 0.9375f) }, 8, new Vector3(0.013f, 0f, 0.006f)); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetCroissantMesh(string key) { return Cached(key, delegate { //IL_00a4: 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_00b3: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_0147: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; Vector3 val = default(Vector3); for (int i = 0; i < 15; i++) { float num = (float)i / 14f; float num2 = (num - 0.5f) * 3.05f; float num3 = 0.02f * Mathf.Pow(Mathf.Sin((float)Math.PI * num), 0.7f) + 0.002f; ((Vector3)(ref val))..ctor(0.042f * Mathf.Sin(num2), num3 * 0.9f, 0.042f * Mathf.Cos(num2) - 0.0168f); Vector3 val2 = Vector3.Cross(new Vector3(Mathf.Cos(num2), 0f, 0f - Mathf.Sin(num2)), Vector3.up); for (int j = 0; j < 12; j++) { float num4 = (float)Math.PI * 2f * (float)j / 11f; float num5 = 1f + 0.08f * Mathf.Sin(num * 22f); Vector3 item = val + (val2 * Mathf.Cos(num4) + Vector3.up * Mathf.Sin(num4)) * num3 * num5; list.Add(item); list2.Add(new Vector2(num * 3f, (j % 5 == 0) ? 0.1875f : 0.0625f)); } } AddGrid(list3, count, 15, 12, flip: false); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetPastryDiscMesh(string key) { return Cached(key, delegate { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[6] { new P(0f, 0f, 0.0625f), new P(0.034f, 0f, 0.0625f), new P(0.04f, 0.0077f, 0.0625f), new P(0.0368f, 0.0165f, 0.0625f), new P(0.024f, 0.022f, 0.9375f), new P(0f, 0.0198f, 0.9375f) }, 20, Vector3.zero, 0.03f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetSandwichMesh(string key) { return Cached(key, delegate { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0240: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0175: 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_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: 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) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: 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) List list = new List(); List list2 = new List(); List list3 = new List(); Vector2[] array = (Vector2[])(object)new Vector2[3] { new Vector2(-0.042f, -0.036f), new Vector2(0.048f, -0.036f), new Vector2(-0.042f, 0.05f) }; float[] array2 = new float[4] { 0f, 0.012f, 0.02f, 0.032f }; float[] array3 = new float[3] { 0.0625f, 0.4375f, 0.0625f }; for (int i = 0; i < 3; i++) { float num = array2[i]; float num2 = array2[i + 1]; float num3 = array3[i]; for (int j = 0; j < 3; j++) { Vector2 val = array[j]; Vector2 val2 = array[(j + 1) % 3]; float num4 = ((i == 1) ? 1.06f : 1f); int count = list.Count; list.Add(new Vector3(val.x * num4, num, val.y * num4)); list2.Add(new Vector2(0f, num3)); list.Add(new Vector3(val2.x * num4, num, val2.y * num4)); list2.Add(new Vector2(1f, num3)); list.Add(new Vector3(val2.x * num4, num2, val2.y * num4)); list2.Add(new Vector2(1f, num3)); list.Add(new Vector3(val.x * num4, num2, val.y * num4)); list2.Add(new Vector2(0f, num3)); list3.AddRange(new int[6] { count, count + 2, count + 1, count, count + 3, count + 2 }); } } int count2 = list.Count; Vector2[] array4 = array; foreach (Vector2 val3 in array4) { list.Add(new Vector3(val3.x, array2[3], val3.y)); list2.Add(new Vector2(val3.x * 8f, 0.0625f)); } list3.AddRange(new int[3] { count2, count2 + 2, count2 + 1 }); int count3 = list.Count; array4 = array; foreach (Vector2 val4 in array4) { list.Add(new Vector3(val4.x, 0f, val4.y)); list2.Add(new Vector2(val4.x * 8f, 0.1875f)); } list3.AddRange(new int[3] { count3, count3 + 1, count3 + 2 }); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetSliceMesh(string key) { return Cached(key, delegate { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: 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) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: 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_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: 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_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); Vector2[] array = (Vector2[])(object)new Vector2[3] { new Vector2(-0.042f, -0.042749997f), new Vector2(0.042f, -0.042749997f), new Vector2(0f, 0.05225f) }; int count = list.Count; Vector2[] array2 = array; foreach (Vector2 val in array2) { list.Add(new Vector3(val.x, 0.01f, val.y)); list2.Add(new Vector2(val.x * 6f + 0.5f, 0.9375f)); } list3.AddRange(new int[3] { count, count + 2, count + 1 }); int count2 = list.Count; array2 = array; foreach (Vector2 val2 in array2) { list.Add(new Vector3(val2.x, 0f, val2.y)); list2.Add(new Vector2(val2.x * 6f + 0.5f, 0.1875f)); } list3.AddRange(new int[3] { count2, count2 + 1, count2 + 2 }); for (int j = 0; j < 3; j++) { Vector2 val3 = array[j]; Vector2 val4 = array[(j + 1) % 3]; int count3 = list.Count; list.Add(new Vector3(val3.x, 0f, val3.y)); list2.Add(new Vector2(0f, 0.4375f)); list.Add(new Vector3(val4.x, 0f, val4.y)); list2.Add(new Vector2(1f, 0.4375f)); list.Add(new Vector3(val4.x, 0.01f, val4.y)); list2.Add(new Vector2(1f, 0.4375f)); list.Add(new Vector3(val3.x, 0.01f, val3.y)); list2.Add(new Vector2(0f, 0.4375f)); list3.AddRange(new int[6] { count3, count3 + 2, count3 + 1, count3, count3 + 3, count3 + 2 }); } int count4 = list.Count; for (int k = 0; k < 10; k++) { float num = Mathf.Lerp(-0.042f, 0.042f, (float)k / 9f); for (int l = 0; l < 8; l++) { float num2 = (float)Math.PI * (float)l / 7f; list.Add(new Vector3(num, 0.005f + 0.011f * Mathf.Sin(num2), -0.042749997f - 0.006f * Mathf.Cos(num2))); list2.Add(new Vector2((float)k * 0.4f, 0.0625f)); } } AddGrid(list3, count4, 10, 8, flip: true); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetBunMesh(string key) { return Cached(key, delegate { //IL_00da: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.6875f), new P(0.0288f, 0f, 0.6875f), new P(0.036f, 0.013500001f, 0.6875f), new P(0.03312f, 0.030600002f, 0.6875f), new P(0.0198f, 0.0423f, 0.6875f), new P(0.0072f, 0.045f, 0.9375f), new P(0f, 0.045f, 0.9375f) }, 18, Vector3.zero, 0.02f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetRollMesh(string key) { return Cached(key, delegate { //IL_0168: 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) List list = new List(); List list2 = new List(); List list3 = new List(); int count = list.Count; for (int i = 0; i < 15; i++) { float num = (float)i / 14f; float num2 = (num * 2f - 1f) * 0.055f; float num3 = Mathf.Clamp01(Mathf.Min(num, 1f - num) / 0.05f); float num4 = 0.6f + 0.4f * (num3 * num3 * (3f - 2f * num3)); float num5 = 1f + 0.12f * Mathf.Sin((float)Math.PI * num); bool flag = num < 0.04f || num > 0.96f; for (int j = 0; j < 16; j++) { float num6 = (float)Math.PI * 2f * (float)j / 15f; float num7 = Mathf.Cos(num6); float num8 = Mathf.Sin(num6); float num9 = 0.018f * Mathf.Sign(num7) * Mathf.Pow(Mathf.Abs(num7), 0.6f); float num10 = 0.021f * Mathf.Sign(num8) * Mathf.Pow(Mathf.Abs(num8), 0.6f); if (num9 > 0f) { num9 *= num5; } float num11 = 1f + 0.025f * Mathf.Sin(num * 17f + (float)j * 2.7f); list.Add(new Vector3(num2, 0.018f + num9 * num4 * num11, num10 * num4 * num11)); float num12 = (flag ? 0.4375f : ((num7 > 0.72f && (int)(num * 9f) % 2 == 0) ? 0.1875f : 0.0625f)); list2.Add(new Vector2(num * 2f, num12)); } } AddGrid(list3, count, 15, 16, flip: false); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetFilledBunMesh(string key) { return Cached(key, delegate { //IL_012d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[10] { new P(0f, 0f, 0.0625f), new P(0.032f, 0f, 0.0625f), new P(0.038399998f, 0.0099f, 0.0625f), new P(0.038f, 0.0176f, 0.0625f), new P(0.042399995f, 0.022f, 0.4375f), new P(0.041599996f, 0.028599998f, 0.4375f), new P(0.038f, 0.033f, 0.0625f), new P(0.034f, 0.04675f, 0.0625f), new P(0.018f, 0.055f, 0.0625f), new P(0f, 0.055f, 0.0625f) }, 18, Vector3.zero, 0.02f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetHotdogMesh(string key) { return Cached(key, delegate { //IL_002e: 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) List list = new List(); List list2 = new List(); List list3 = new List(); SlabInto(list, list2, list3, 0.055f, 0.02f, 0.024f, 0.6875f, 0.6875f, Vector3.zero, 0.05f); SlabInto(list, list2, list3, 0.065f, 0.011f, 0.011f, 0.4375f, 0.4375f, new Vector3(0f, 0.026f, 0f), 0f, 0.02f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetTakeoutBoxMesh(string key) { return Cached(key, delegate { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.6875f), new P(0.028f, 0f, 0.6875f), new P(0.03f, 0.004f, 0.6875f), new P(0.04f, 0.062f, 0.6875f), new P(0.037f, 0.062f, 0.6875f), new P(0.033f, 0.056f, 0.4375f), new P(0f, 0.055f, 0.4375f) }, 5, Vector3.zero, 0f, (float)Math.PI / 4f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetCartonMesh(string key) { return Cached(key, delegate { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.6875f), new P(0.03f, 0f, 0.6875f), new P(0.032f, 0.004f, 0.4375f), new P(0.032f, 0.075f, 0.4375f), new P(0.032f, 0.092f, 0.9375f), new P(0.028f, 0.096f, 0.9375f), new P(0f, 0.096f, 0.9375f) }, 5, Vector3.zero, 0f, (float)Math.PI / 4f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetBrownieMesh(string key) { return Cached(key, delegate { //IL_003d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); SlabInto(list, list2, list3, 0.028f, 0.011f, 0.024f, 0.9375f, 0.4375f, new Vector3(0f, 0.011f, 0f), 0.06f, 0.02f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetPlateSteakMesh(string key) { return Cached(key, delegate { //IL_00a4: 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_017d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[5] { new P(0f, 0f, 0.6875f), new P(0.045f, 0f, 0.6875f), new P(0.06f, 0.007f, 0.6875f), new P(0.058f, 0.009f, 0.6875f), new P(0f, 0.006f, 0.6875f) }, 22, Vector3.zero); SlabInto(list, list2, list3, 0.026f, 0.008f, 0.018f, 0.9375f, 0.4375f, new Vector3(-0.014f, 0.015f, -0.004f), 0.05f); LatheInto(list, list2, list3, new P[4] { new P(0f, 0.006f, 0.0625f), new P(0.017f, 0.006f, 0.0625f), new P(0.012f, 0.024f, 0.0625f), new P(0f, 0.028f, 0.0625f) }, 10, new Vector3(0.026f, 0f, 0.014f), 0.06f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetChickenMesh(string key) { return Cached(key, delegate { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[7] { new P(0f, 0f, 0.4375f), new P(0.03f, 0f, 0.4375f), new P(0.042f, 0.014f, 0.4375f), new P(0.045f, 0.03f, 0.4375f), new P(0.038f, 0.046f, 0.4375f), new P(0.022f, 0.056f, 0.4375f), new P(0f, 0.06f, 0.4375f) }, 18, Vector3.zero, 0.025f); LatheInto(list, list2, list3, new P[4] { new P(0.011f, 0f, 0.4375f), new P(0.009f, 0.02f, 0.4375f), new P(0.005f, 0.032f, 0.1875f), new P(0f, 0.034f, 0.1875f) }, 10, new Vector3(0.024f, 0.012f, 0.03f), 0.03f); LatheInto(list, list2, list3, new P[4] { new P(0.011f, 0f, 0.4375f), new P(0.009f, 0.02f, 0.4375f), new P(0.005f, 0.032f, 0.1875f), new P(0f, 0.034f, 0.1875f) }, 10, new Vector3(-0.024f, 0.012f, 0.03f), 0.03f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetFishMesh(string key) { return Cached(key, delegate { //IL_003d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); SlabInto(list, list2, list3, 0.058f, 0.008f, 0.022f, 0.9375f, 0.4375f, new Vector3(0f, 0.008f, 0f), 0.04f, 0.05f); return Finish("S1HT_" + key, list, list2, list3); }); } public static Mesh GetTrayMesh(string key) { return Cached(key, delegate { //IL_00be: 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_017c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); LatheInto(list, list2, list3, new P[6] { new P(0f, 0f, 0.6875f), new P(0.036f, 0f, 0.6875f), new P(0.045f, 0.028f, 0.6875f), new P(0.042f, 0.028f, 0.6875f), new P(0.036f, 0.02f, 0.0625f), new P(0f, 0.018f, 0.0625f) }, 5, Vector3.zero, 0f, (float)Math.PI / 4f); LatheInto(list, list2, list3, new P[3] { new P(0.026f, 0.018f, 0.0625f), new P(0.02f, 0.034f, 0.0625f), new P(0f, 0.04f, 0.0625f) }, 12, new Vector3(-0.006f, 0f, -0.006f), 0.08f); SlabInto(list, list2, list3, 0.03f, 0.007f, 0.013f, 0.9375f, 0.9375f, new Vector3(0.012f, 0.042f, 0.01f), 0.05f, 0.06f); return Finish("S1HT_" + key, list, list2, list3); }); } private static Texture2D GetPalette(string variantKey, FillingLook look) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_00ec: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0245: 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_0209: 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_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) if (_palettes.TryGetValue(variantKey, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)1; ((Object)val).hideFlags = (HideFlags)32; Color val2 = default(Color); ((Color)(ref val2))..ctor(0.93f, 0.76f, 0.42f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.8f, 0.6f, 0.3f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.82f, 0.64f, 0.34f); Random random = new Random(42 + variantKey.GetHashCode()); int num = 16; Color[,] array = new Color[num, num]; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { int num2 = i * 8 + 4; Color val5; if (num2 < 16) { val5 = ((random.NextDouble() < 0.06) ? val3 : val2); } else if (num2 < 32) { val5 = val4; } else if (num2 < 64) { double num3 = random.NextDouble(); val5 = ((num3 < 0.72) ? look.Primary : ((num3 < 0.96) ? look.Secondary : look.Accent)); float num4 = 1f + 0.05f * ((float)random.NextDouble() - 0.5f); ((Color)(ref val5))..ctor(Mathf.Clamp01(val5.r * num4), Mathf.Clamp01(val5.g * num4), Mathf.Clamp01(val5.b * num4)); } else if (num2 < 112) { Color accent = look.Accent; val5 = (Color)((random.NextDouble() < 0.07) ? new Color(accent.r * 0.86f, accent.g * 0.86f, accent.b * 0.86f) : accent); } else { val5 = ((random.NextDouble() < 0.7) ? look.LettuceA : look.LettuceB); } array[j, i] = val5; } } for (int k = 0; k < 128; k++) { for (int l = 0; l < 128; l++) { val.SetPixel(l, k, array[l / 8, k / 8]); } } val.Apply(); _palettes[variantKey] = val; return val; } public static Material GetMaterial(Renderer donor, string variantKey, FillingLook look) { //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_009f: 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) if (_materials.TryGetValue(variantKey, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } Texture2D palette = GetPalette(variantKey, look); try { if ((Object)(object)donor != (Object)null && (Object)(object)donor.sharedMaterial != (Object)null) { Material val = Object.Instantiate(donor.sharedMaterial); ((Object)val).name = "S1HT_TacoMat_" + variantKey; ((Object)val).hideFlags = (HideFlags)32; val.mainTexture = (Texture)(object)palette; if (val.HasProperty("_BaseMap")) { val.SetTexture("_BaseMap", (Texture)(object)palette); } if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", Color.white); } if (val.HasProperty("_Color")) { val.SetColor("_Color", Color.white); } _materials[variantKey] = val; MelonLogger.Msg($"[Taco] '{variantKey}' material cloned from game asset (shader '{((Object)val.shader).name}')."); return val; } } catch (Exception ex) { MelonLogger.Warning("[Taco] material clone failed: " + ex.Message); } try { Shader val2 = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val2 == (Object)null) { val2 = Shader.Find("Universal Render Pipeline/Simple Lit"); } if ((Object)(object)val2 == (Object)null) { val2 = Shader.Find("Sprites/Default"); } Material val3 = new Material(val2); ((Object)val3).name = "S1HT_TacoMat_" + variantKey + "_Fallback"; ((Object)val3).hideFlags = (HideFlags)32; val3.mainTexture = (Texture)(object)palette; if (val3.HasProperty("_BaseMap")) { val3.SetTexture("_BaseMap", (Texture)(object)palette); } _materials[variantKey] = val3; MelonLogger.Msg($"[Taco] '{variantKey}' material fallback (shader '{((Object)val2).name}')."); return val3; } catch (Exception ex2) { MelonLogger.Warning("[Taco] fallback material failed: " + ex2.Message); return null; } } public static GameObject CreateTacoObject(Renderer materialDonor, float scale, int layer, string variantKey, FillingLook look) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("S1HT_Taco3D_" + variantKey); val.AddComponent().sharedMesh = GetMesh(); MeshRenderer val2 = val.AddComponent(); Material material = GetMaterial(materialDonor, variantKey, look); if ((Object)(object)material != (Object)null) { ((Renderer)val2).sharedMaterial = material; } val.transform.localScale = Vector3.one * scale; if (layer >= 0) { val.layer = layer; } return val; } } public static class TacoDiag { private static bool _ran; private static bool _registryDumped; public static string DiscoveredEntryLabel { get; private set; } = "ENTRY"; public static void OnSessionEnded() { _ran = false; _registryDumped = false; } public static void DumpRegistryAudit() { if (_registryDumped || !NeedsConfig.VerboseConsume) { return; } _registryDumped = true; try { Il2CppArrayBase val = (((Object)(object)Singleton.Instance != (Object)null) ? Singleton.Instance.GetAllItems() : null)?.ToArray(); if (val == null) { Diag.Log("[RegistryAudit] registry unavailable."); return; } Diag.Log($"[RegistryAudit] ===== {val.Length} REGISTRY ITEMS (id | name | type | price) ====="); for (int i = 0; i < val.Length; i++) { ItemDefinition val2 = val[i]; if ((Object)(object)val2 == (Object)null) { continue; } string value = "?"; string value2 = "?"; string value3 = "?"; string value4 = "-"; try { value = ((BaseItemDefinition)val2).ID ?? "?"; } catch { } try { value2 = ((BaseItemDefinition)val2).Name ?? "?"; } catch { } try { value3 = ((MemberInfo)((Object)val2).GetIl2CppType()).Name; } catch { } try { StorableItemDefinition val3 = ((Il2CppObjectBase)val2).TryCast(); if ((Object)(object)val3 != (Object)null) { value4 = val3.BasePurchasePrice.ToString("0.##"); } } catch { } Diag.Log($"[RegistryAudit] {value} | {value2} | {value3} | ${value4}"); } Diag.Log("[RegistryAudit] ===== END ====="); } catch (Exception ex) { MelonLogger.Warning("[RegistryAudit] failed: " + ex.Message); } } public static void Run(NPC kyle) { if (_ran || !NeedsConfig.VerboseConsume) { return; } _ran = true; try { DumpKyleHierarchy(kyle); DumpWorkingVendorDialogue(); DumpHandlerContainers(kyle); } catch (Exception ex) { MelonLogger.Warning("[TacoDiag] failed: " + ex.Message); } } private static void DumpKyleHierarchy(NPC kyle) { if (!((Object)(object)kyle == (Object)null)) { MelonLogger.Msg("[TacoDiag] ===== KYLE HIERARCHY ====="); DumpTransform(((Component)kyle).transform, 0, 3); MelonLogger.Msg("[TacoDiag] ===== END KYLE ====="); } } private static void DumpTransform(Transform t, int depth, int maxDepth) { if ((Object)(object)t == (Object)null || depth > maxDepth) { return; } Il2CppArrayBase components = ((Component)t).GetComponents(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < components.Length; i++) { if (!((Object)(object)components[i] == (Object)null)) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(((MemberInfo)((Object)components[i]).GetIl2CppType()).Name); } } MelonLogger.Msg($"[TacoDiag] {new string(' ', depth * 2)}{((Object)((Component)t).gameObject).name} [{stringBuilder}]"); for (int j = 0; j < t.childCount; j++) { DumpTransform(t.GetChild(j), depth + 1, maxDepth); } } private static void DumpWorkingVendorDialogue() { try { DialogueController val = (DialogueController)(object)Object.FindObjectOfType(); string value = "SkateboardSeller"; if ((Object)(object)val == (Object)null) { val = (DialogueController)(object)Object.FindObjectOfType(); value = "ArmsDealer"; } if ((Object)(object)val == (Object)null) { MelonLogger.Msg("[TacoDiag] no working vendor found in scene to study."); return; } MelonLogger.Msg($"[TacoDiag] ===== WORKING VENDOR ({value}) on '{((Object)((Component)val).gameObject).name}' ====="); MelonLogger.Msg($"[TacoDiag] controller Choices: {((val.Choices != null) ? val.Choices.Count : (-1))}"); if (val.Choices != null) { Il2CppArrayBase val2 = val.Choices.ToArray(); for (int i = 0; i < val2.Length; i++) { DialogueChoice val3 = val2[i]; if (val3 != null) { MelonLogger.Msg($"[TacoDiag] choice[{i}]: '{val3.ChoiceText}' conv={(((Object)(object)val3.Conversation != (Object)null) ? ((Object)val3.Conversation).name : "null")} priority={val3.Priority}"); DumpContainer(val3.Conversation); } } } DumpContainer(val.GenericDialogue); MelonLogger.Msg("[TacoDiag] ===== END VENDOR ====="); } catch (Exception ex) { MelonLogger.Warning("[TacoDiag] vendor dump failed: " + ex.Message); } } private static void DumpContainer(DialogueContainer c) { if ((Object)(object)c == (Object)null || c.DialogueNodeData == null) { return; } MelonLogger.Msg($"[TacoDiag] container '{((Object)c).name}': {c.DialogueNodeData.Count} node(s), {((c.NodeLinks != null) ? c.NodeLinks.Count : 0)} link(s), allowExit={c.AllowExit}"); Il2CppArrayBase val = c.DialogueNodeData.ToArray(); for (int i = 0; i < val.Length; i++) { DialogueNodeData val2 = val[i]; if (val2 == null) { continue; } int num = ((val2.choices != null) ? ((Il2CppArrayBase)(object)val2.choices).Length : 0); MelonLogger.Msg($"[TacoDiag] node[{i}] label='{val2.DialogueNodeLabel}' text='{Trunc(val2.DialogueText)}' choices={num}"); if (i == 0 && !string.IsNullOrEmpty(val2.DialogueNodeLabel)) { DiscoveredEntryLabel = val2.DialogueNodeLabel; } for (int j = 0; j < num; j++) { DialogueChoiceData val3 = ((Il2CppArrayBase)(object)val2.choices)[j]; if (val3 != null) { MelonLogger.Msg($"[TacoDiag] choice '{Trunc(val3.ChoiceText)}' label='{val3.ChoiceLabel}'"); } } } } private static void DumpHandlerContainers(NPC kyle) { try { DialogueHandler val = (((Object)(object)kyle != (Object)null) ? kyle.DialogueHandler : null); if ((Object)(object)val == (Object)null) { MelonLogger.Msg("[TacoDiag] Kyle has no DialogueHandler."); return; } MelonLogger.Msg("[TacoDiag] Kyle handler on '" + ((Object)((Component)val).gameObject).name + "'"); DialogueController val2 = ((Component)val).GetComponent() ?? ((Component)val).GetComponentInChildren(true); if ((Object)(object)val2 == (Object)null) { return; } MelonLogger.Msg("[TacoDiag] ===== KYLE'S OWN DIALOGUE ====="); DumpContainer(val2.GenericDialogue); if (val2.Choices != null) { Il2CppArrayBase val3 = val2.Choices.ToArray(); for (int i = 0; i < val3.Length; i++) { if (val3[i] != null) { MelonLogger.Msg($"[TacoDiag] Kyle choice[{i}]: '{val3[i].ChoiceText}'"); DumpContainer(val3[i].Conversation); } } } MelonLogger.Msg("[TacoDiag] ===== END KYLE'S DIALOGUE ====="); } catch (Exception ex) { MelonLogger.Warning("[TacoDiag] handler dump failed: " + ex.Message); } } private static string Trunc(string s) { if (!string.IsNullOrEmpty(s)) { if (s.Length <= 48) { return s; } return s.Substring(0, 48) + "…"; } return ""; } } public static class TacoItem { public sealed class Variant { public string Id; public string Name; public string Desc; public string[] SoldLines; public string[] BoughtToasts; public Func Price; public Taco3D.FillingLook Look; public string IconResource; public bool SoldByKyle = true; } public const string TacoId = "taco"; public const string BurroitoId = "burroito"; public static readonly Variant[] Variants = new Variant[6] { new Variant { Id = "taco", Name = "Beef Taco", Desc = "Street taco from the servo. Best not to ask.", Price = () => NeedsConfig.TacoPrice, Look = Taco3D.BeefLook, IconResource = "S1HungerThirst.Assets.taco.png", SoldLines = new string[5] { "Beef. Can't go wrong. Enjoy, man.", "The classic. Good call.", "Beef, my man. Cornerstone of the menu.", "Hot off the grill. Careful, dude.", "One beef. The beef abides." }, BoughtToasts = new string[3] { "Kyle sorted you out. One beef taco.", "Beef taco acquired.", "One beef off Kyle. Smells promising." } }, new Variant { Id = "tacochicken", Name = "Chicken Taco", Desc = "Chook taco. Allegedly chook.", Price = () => NeedsConfig.TacoPriceChicken, Look = Taco3D.ChickenLook, IconResource = "S1HungerThirst.Assets.taco_chicken.png", SoldLines = new string[5] { "Chicken's underrated, honestly.", "One chicken. Solid choice.", "Chicken. The thinking man's taco.", "One chicken, extra crispy bits on top.", "Good pick. The chicken's actually chicken today." }, BoughtToasts = new string[3] { "One chook taco off Kyle.", "Chicken, allegedly.", "One chicken taco. Smells legit." } }, new Variant { Id = "tacoveggie", Name = "Veggie Taco", Desc = "Beans and salad. The sensible one.", Price = () => NeedsConfig.TacoPriceVeggie, Look = Taco3D.VeggieLook, IconResource = "S1HungerThirst.Assets.taco_veggie.png", SoldLines = new string[5] { "Veggie. Respect. More beef for me.", "One veggie. The green stuff's real, pretty sure.", "Green machine. There you go, man.", "One veggie. Clean living, dude.", "Veggie. My guy grows the beans himself, probably." }, BoughtToasts = new string[3] { "Veggie taco. Kyle didn't comment.", "The healthy option, from a taco cart.", "One veggie taco. Beans and hope." } }, new Variant { Id = "tacokylespecial", Name = "Kyle's Special", Desc = "Comes with a lot of white sauce. House recipe.", Price = () => NeedsConfig.TacoPriceKyleSpecial, Look = Taco3D.KyleSpecialLook, IconResource = "S1HungerThirst.Assets.taco_kylespecial.png", SoldLines = new string[5] { "The Special. Made it fresh, man.", "Extra sauce on that one. No charge.", "The Special. Sauce recipe's a family secret. Not my family, but still.", "One Special. Made with love and sauce. Mostly sauce.", "There you go, man. Napkins are... somewhere." }, BoughtToasts = new string[3] { "One Kyle's Special. Don't ask about the sauce.", "The Special. So much sauce, zero answers.", "Kyle's Special. Best eaten unexamined." } }, new Variant { Id = "tacomanuke", Name = "The Manuke Taco", Desc = "Made with genuine faux Japanese wagyu. Worth every dollar.", Price = () => NeedsConfig.TacoPriceManuke, Look = Taco3D.ManukeLook, IconResource = "S1HungerThirst.Assets.taco_manuke.png", SoldLines = new string[5] { "Ah, a Manuke man. You can just tell, dude.", "Four twenty, cheers. That's the wagyu talking.", "The Manuke. Big spender energy, my man.", "One Manuke. That cow was raised on massages and lies.", "That's the premium experience right there, dude." }, BoughtToasts = new string[3] { "One Manuke Taco. Kyle counted the cash twice.", "$420 of taco. It better whisper secrets.", "The Manuke. Wallet's lighter, spirit's about the same." } }, new Variant { Id = "tacomystery", Name = "Mystery Meat Taco", Desc = "Servo-shelf special. No further questions.", Price = () => NeedsConfig.TacoPriceMystery, Look = Taco3D.MysteryLook, IconResource = "S1HungerThirst.Assets.taco_mystery.png", SoldByKyle = false, SoldLines = null, BoughtToasts = null } }; private static readonly Dictionary _defs = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary _icons = new Dictionary(StringComparer.OrdinalIgnoreCase); private static bool _warnedNoBanana; private static bool _nativeSpriteChecked; private static readonly Random _rng = new Random(); private static readonly string[] BadTacoWarnLines = new string[3] { "That taco fought back.", "Something in that taco was still angry.", "That one was a mistake." }; private static readonly string[] BadTacoLossLines = new string[3] { "Most of it came straight back up.", "The gutter got most of it.", "Refund unavailable. Lunch also unavailable." }; private static readonly string[] SatietyLines = new string[3] { "That'll sit with you a while.", "Solid base in the tank now.", "That one's staying put." }; private static readonly string[] ManukeSatietyLines = new string[3] { "That'll sit with you a good long while.", "Four hundred dollar taco, four hundred dollar staying power.", "The wagyu settles in for the long haul." }; private static bool _kyleArmed; private static bool _kyleGaveUp; private static float _nextKyleAttempt; private static int _kyleAttempts; private static readonly string[] KyleClosedLines = new string[4] { "We're closed, man. Come back tomorrow.", "Cart's dark, dude. Tacos sleep too.", "Off the clock, my man. Grill's cold.", "Closed. Even I go home sometimes, man." }; private static readonly string[] KyleClosedToasts = new string[3] { "Kyle's off the clock.", "Cart's shut. Tragic.", "No Kyle till morning." }; private static float _nextKyleHoursCheck; private static bool _kyleShowsClosed; private const string BuyPrefix = "S1HT_TACO_BUY_"; private const string BurroitoGuid = "S1HT_TACO_BURROITO"; private const string VeganAskGuid = "S1HT_TACO_VEGAN_ASK"; private const string VeganBuyGuid = "S1HT_TACO_VEGAN_BUY"; private const string VeganNahGuid = "S1HT_TACO_VEGAN_NAH"; private const string ExitGuid = "S1HT_TACO_EXIT"; private static bool _handlerHooked; private static NPC _kyle; private static DialogueContainer _convo; private static DialogueNodeData _soldNode; private static DialogueNodeData _entryNode; private static DialogueNodeData _byeNode; private static DialogueNodeData _veganOfferNode; private static int _lastOpener = -1; private static readonly string[] ByeLines = new string[6] { "No stress. They're not going anywhere.", "All good. You know where I am.", "Later, man.", "Catch you, dude.", "More for me then.", "It's cool. The tacos forgive you." }; private static readonly string[] BrokeLines = new string[6] { "Ah, you're short, man. Tacos aren't a charity.", "Come back with cash, man. They'll keep.", "Dude. You're broke. It happens.", "Can't spot you, man. Cart rules.", "No cash, no taco. I don't make the rules. I do, actually.", "The register's watching, man. Cash first." }; private static readonly string[] BurroitoSoldLines = new string[7] { "Dude. Are you SERIOUS. ...Fine. One Big Burroito. Never again.", "Nah man, fuck this thing. Last one I'm ever making, I swear.", "Ugh. FINE. Take it. Don't talk to me for like an hour.", "You know what, fine. FINE. Here's your stupid magnificent burrito.", "I hate this thing, man. Take it and go be fast somewhere else.", "One Big Burroito. My arms hurt already. Here.", "You're such a bitch for having me make this thing, dude." }; private static readonly string[] BurroitoOwnedLines = new string[5] { "Dude, no. One each, ever. We talked about this.", "Nah man, fuck that thing. Never again.", "Bro. One per lifetime. It's in the rules I just made up.", "You HAVE one. It lives in you now. No.", "Ask me again and I'm switching carts, dude." }; private static readonly string[] BurroitoBrokeLines = new string[5] { "It's forty-two grand, my man. You don't have it.", "Dude, you can't afford it. Stop.", "Forty-two grand, man. I've seen your wallet.", "That's a car, dude. You're asking me for a car.", "Nah man. Come back rich." }; private static readonly string[] VeganLeafIdsOrdered = new string[6] { "leaf", "weedleaf", "plantleaf", "cannabisleaf", "plantscrap", "cocaleaf" }; private static readonly string[] VeganSoldLines = new string[5] { "There it is. Farm to table, my man.", "Enjoy, dude. That's the garden talking.", "Fresh as it gets. Literally today's harvest.", "One vegan taco. Zero animals involved, guaranteed.", "That's the green stuff, my man. All natural." }; private static readonly string[] VeganBrokeLines = new string[4] { "It's five bucks, dude.", "Five. Bucks. C'mon, man.", "Even the vegan one costs money, man.", "Five dollars, dude. Cheapest thing I sell." }; private static readonly string[] VeganOutLines = new string[2] { "Ah, we're out of the vegan ones, my man.", "Vegan one's, uh... restocking. Come back later, dude." }; private static readonly string[] VeganBoughtToasts = new string[3] { "One 'vegan taco', sorted.", "The 'vegan taco' is in the bag.", "Bought a 'vegan taco'. It's very green." }; private static int _lastVeganOffer = -1; private static bool _mysteryStocked; private static float _nextShopAttempt; private static int _shopAttempts; private static readonly HashSet _seenStored = new HashSet(); private static float _nextShelfSweep; private static bool _energyRefDumped; private static string KyleClosedLine => Lines.Pick(KyleClosedLines); public static bool IsTacoId(string id) { Variant v; return TryGetVariant(id, out v); } public static bool TryGetVariant(string id, out Variant v) { for (int i = 0; i < Variants.Length; i++) { if (string.Equals(Variants[i].Id, id, StringComparison.OrdinalIgnoreCase)) { v = Variants[i]; return true; } } v = null; return false; } public static void EnsureRegistered() { if (!NeedsConfig.TacoEnabled) { return; } try { if ((Object)(object)Singleton.Instance == (Object)null || !Registry.ItemExists("banana")) { return; } ItemDefinition item = Registry.GetItem("banana"); StorableItemDefinition val = (((Object)(object)item != (Object)null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val == (Object)null) { if (!_warnedNoBanana) { _warnedNoBanana = true; MelonLogger.Warning("[Taco] banana def not storable — cannot clone."); } return; } for (int i = 0; i < Variants.Length; i++) { Variant variant = Variants[i]; if (!Registry.ItemExists(variant.Id)) { StorableItemDefinition val2 = Object.Instantiate(val); ((Object)val2).hideFlags = (HideFlags)32; ((BaseItemDefinition)val2).ID = variant.Id; ((BaseItemDefinition)val2).Name = variant.Name; ((BaseItemDefinition)val2).Description = variant.Desc; val2.BasePurchasePrice = Mathf.Max(1f, variant.Price()); Sprite val3 = LoadIcon(variant); if ((Object)(object)val3 != (Object)null) { ((BaseItemDefinition)val2).Icon = val3; } SwapInTacoWorldModel(val2, variant); Singleton.Instance.AddToRegistry((ItemDefinition)(object)val2); _defs[variant.Id] = val2; MelonLogger.Msg($"[Taco] registered '{variant.Id}' ({variant.Name}, cloned from banana): ${val2.BasePurchasePrice:0}, icon {(((Object)(object)val3 != (Object)null) ? "custom" : "inherited")}."); } } if (NeedsConfig.BurroitoEnabled && !Registry.ItemExists("burroito")) { StorableItemDefinition val4 = Object.Instantiate(val); ((Object)val4).hideFlags = (HideFlags)32; ((BaseItemDefinition)val4).ID = "burroito"; ((BaseItemDefinition)val4).Name = "The Big Burroito (tm)"; ((BaseItemDefinition)val4).Description = "One giant burrito. Kyle hates that you know about it."; val4.BasePurchasePrice = Mathf.Max(1f, NeedsConfig.BurroitoPrice); Sprite val5 = LoadIconResource("burroito", "S1HungerThirst.Assets.burrito.png"); if ((Object)(object)val5 != (Object)null) { ((BaseItemDefinition)val4).Icon = val5; } SwapInWorldModel(val4, Taco3D.GetBurritoMesh(), "burroito", Taco3D.BurroitoLook); Singleton.Instance.AddToRegistry((ItemDefinition)(object)val4); _defs["burroito"] = val4; Diag.Log($"[Burroito] registered '{"burroito"}' (The Burroito, burrito mesh): ${val4.BasePurchasePrice:0}."); } EateryVendors.EnsureRegistered(val); } catch (Exception ex) { MelonLogger.Warning("[Taco] registration failed: " + ex.Message); } } private static float BadChanceFor(string id) { if (string.Equals(id, "tacomystery", StringComparison.OrdinalIgnoreCase)) { return NeedsConfig.MysteryTacoBadChance; } if (string.Equals(id, "tacomanuke", StringComparison.OrdinalIgnoreCase)) { return NeedsConfig.ManukeTacoBadChance; } if (string.Equals(id, "tacokylespecial", StringComparison.OrdinalIgnoreCase)) { return NeedsConfig.KyleTacoBadChance; } return 0f; } public static void OnTacoEaten(string id) { //IL_00dc: 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_01e5: Unknown result type (might be due to invalid IL or missing references) if (!TryGetVariant(id, out var _)) { return; } try { float num = BadChanceFor(id); if (num > 0f && _rng.NextDouble() < (double)num) { float num2 = 0f; if (ConsumableMap.TryGet(id, out var r)) { num2 = Mathf.Max(0f, r.Hunger * NeedsConfig.MysteryHungerLossFraction); } NeedsState.Replenish(0f - num2, 0f); Penalties.StartCrookGuts(NeedsConfig.MysteryCrookGutsSeconds); try { AvatarEffects val = (((Object)(object)Player.Local != (Object)null && (Object)(object)Player.Local.Avatar != (Object)null) ? Player.Local.Avatar.Effects : null); if ((Object)(object)val != (Object)null) { val.TriggerSick(true); } } catch (Exception ex) { MelonLogger.Warning("[Taco] bad-taco vomit failed: " + ex.Message); } NeedsHud.Toast(Lines.Pick(BadTacoWarnLines), NeedsHud.ToastWarn); NeedsHud.Toast(Lines.Pick(BadTacoLossLines), NeedsHud.ToastBad); MelonLogger.Msg($"[Taco] BAD taco '{id}' (rolled under {num:P0}): {num2:0} hunger clawed back, crook guts {NeedsConfig.MysteryCrookGutsSeconds:0}s, native TriggerSick. High untouched."); } else { bool flag = string.Equals(id, "tacomanuke", StringComparison.OrdinalIgnoreCase); float num3 = (flag ? NeedsConfig.ManukeSatietySeconds : NeedsConfig.TacoSatietySeconds); float num4 = (flag ? NeedsConfig.ManukeSatietyDrainFactor : NeedsConfig.TacoSatietyDrainFactor); if (num3 > 0f) { NeedsState.StartSatiety(num3, num4); NeedsHud.Toast(flag ? Lines.Pick(ManukeSatietyLines) : Lines.Pick(SatietyLines), NeedsHud.ToastGood); MelonLogger.Msg($"[Taco] '{id}' eaten — sits-well buff {num3:0}s (hunger drain x{num4:0.0#})."); } } } catch (Exception ex2) { MelonLogger.Warning("[Taco] eat outcome failed: " + ex2.Message); } } public static void OnSessionEnded() { _kyleArmed = false; _kyleGaveUp = false; _kyleAttempts = 0; _nextKyleAttempt = 0f; _nextKyleHoursCheck = 0f; _kyleShowsClosed = false; _handlerHooked = false; _kyle = null; _convo = null; _soldNode = null; _entryNode = null; _byeNode = null; _veganOfferNode = null; _energyRefDumped = false; _mysteryStocked = false; _shopAttempts = 0; _nextShopAttempt = 0f; OnShelfSessionEnded(); TacoDiag.OnSessionEnded(); } private static bool KyleOpenNow() { return EateryVendors.IsOpenNow(NeedsConfig.HoursTacos); } private static void RefreshKyleHours() { float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextKyleHoursCheck) { return; } _nextKyleHoursCheck = unscaledTime + 5f; if (_entryNode == null) { return; } try { bool flag = KyleOpenNow(); if (!flag && !_kyleShowsClosed) { _entryNode.DialogueText = KyleClosedLine; _kyleShowsClosed = true; } else if (flag && _kyleShowsClosed) { RollNextLines(); _kyleShowsClosed = false; } } catch { } } public static void TickKyleVendor() { //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Expected O, but got Unknown //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Expected O, but got Unknown if (!NeedsConfig.TacoEnabled || _defs.Count < Variants.Length || _kyleGaveUp) { return; } if (_kyleArmed) { RefreshKyleHours(); return; } float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextKyleAttempt) { return; } _nextKyleAttempt = unscaledTime + 2f; NPC val = null; try { val = NPCManager.GetNPC("kyle"); if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("kyle_cooley"); } if ((Object)(object)val == (Object)null) { val = NPCManager.GetNPC("kylecooley"); } if ((Object)(object)val == (Object)null) { Il2CppArrayBase val2 = Object.FindObjectsOfType(); for (int i = 0; i < val2.Length; i++) { NPC val3 = val2[i]; if (!((Object)(object)val3 == (Object)null)) { string text = ""; string text2 = ""; try { text = val3.ID ?? ""; } catch { } try { text2 = val3.FirstName ?? ""; } catch { } if (text.ToLowerInvariant().Contains("kyle") || text2.ToLowerInvariant() == "kyle") { val = val3; break; } } } } } catch (Exception ex) { MelonLogger.Warning("[Taco] Kyle lookup error: " + ex.Message); } if ((Object)(object)val == (Object)null) { if (++_kyleAttempts >= 15) { _kyleGaveUp = true; Diag.Log("[Taco] Kyle not found in this world — falling back to shop listings."); EnsureShopListings(); } return; } try { MelonLogger.Msg("[Taco] Kyle resolved (id '" + SafeId(val) + "') — running diagnostics, then locating his DialogueController..."); TacoDiag.Run(val); DialogueController val4 = ((Component)val).GetComponent(); string value = "root"; if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val).GetComponentInChildren(true); value = "children"; } if ((Object)(object)val4 == (Object)null && (Object)(object)val.DialogueHandler != (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponent(); if ((Object)(object)val4 == (Object)null) { val4 = ((Component)val.DialogueHandler).GetComponentInChildren(true); } value = "handler object"; } if ((Object)(object)val4 == (Object)null || val4.Choices == null) { _kyleGaveUp = true; Diag.Log("[Taco] no DialogueController found anywhere on Kyle (handler=" + (((Object)(object)val.DialogueHandler != (Object)null) ? "present" : "null") + ") — falling back to shop listings."); EnsureShopListings(); return; } MelonLogger.Msg($"[Taco] controller found on {value}: {((MemberInfo)((Object)val4).GetIl2CppType()).Name} on '{((Object)((Component)val4).gameObject).name}', {val4.Choices.Count} existing choice(s)."); for (int j = 0; j < val4.Choices.Count; j++) { DialogueChoice val5 = val4.Choices[j]; if (val5 != null && (val5.ChoiceText ?? "").StartsWith("Ask about tacos")) { _kyleArmed = true; return; } } DialogueContainer val6 = BuildTacoConversation(); DialogueChoice val7 = new DialogueChoice(); val7.Enabled = true; val7.ChoiceText = "Ask about tacos"; val7.ShowWorldspaceDialogue = false; val7.Conversation = val6; val7.Priority = 0; val7.onChoosen = new UnityEvent(); try { val4.AddDialogueChoice(val7, 0); } catch (Exception ex2) { MelonLogger.Warning("[Taco] AddDialogueChoice failed (" + ex2.Message + ") — appending to Choices directly."); val4.Choices.Add(val7); } DialogueHandler dialogueHandler = val.DialogueHandler; if ((Object)(object)dialogueHandler != (Object)null) { try { List dialogueContainers = dialogueHandler.dialogueContainers; if (dialogueContainers != null && !dialogueContainers.Contains(val6)) { dialogueContainers.Add(val6); ConsumableMap.VLog("taco conversation registered in Kyle's handler container list"); } } catch (Exception ex3) { ConsumableMap.VLog("handler container list not writable (" + ex3.Message + ") — skipped"); } if (!_handlerHooked) { dialogueHandler.onDialogueChoiceChosen.AddListener(UnityAction.op_Implicit((Action)OnKyleDialogueChoice)); dialogueHandler.onDialogueNodeDisplayed.AddListener(UnityAction.op_Implicit((Action)OnKyleNodeDisplayed)); _handlerHooked = true; } } _kyle = val; _kyleArmed = true; bool flag = NeedsConfig.BurroitoEnabled && !SaveData.BurroitoOwned; Diag.Log($"[Taco] Kyle armed (controller {((MemberInfo)((Object)val4).GetIl2CppType()).Name}) — taco menu added ({KyleVariants().Count} real tacos{(flag ? " + Burroito" : "")} + exit, entry label '{TacoDiag.DiscoveredEntryLabel}'); his {val4.Choices.Count - 1} existing choice(s) untouched."); } catch (Exception value2) { _kyleGaveUp = true; Diag.Log($"[Taco] dialogue wiring failed ({value2}) — falling back to shop listings."); EnsureShopListings(); } } private static string SafeId(NPC n) { try { return n.ID ?? "?"; } catch { return "?"; } } private static string RollOpener() { string value = P(NeedsConfig.TacoPrice); string value2 = P(NeedsConfig.TacoPriceChicken); string value3 = P(NeedsConfig.TacoPriceVeggie); string value4 = P(NeedsConfig.TacoPriceManuke); string value5 = P(NeedsConfig.TacoPriceKyleSpecial); string[] array = new string[6] { $"Oh hey, good timing my man... fresh batch out back. Beef's ${value}, chicken's ${value2}, veggie's ${value3}. The Special's ${value5}, extra sauce. And the Manuke's ${value4}. That one's genuine faux wagyu.", $"Taco guy's never off the clock, man. Beef ${value}, chicken ${value2}, veggie ${value3}. Special's ${value5}. Manuke's ${value4}... the good stuff.", $"Knew you'd be back. Beef's ${value}, chicken and veggie are both ${value2}. Special's ${value5}, house recipe. The Manuke's ${value4}. Honestly it sells itself.", $"My man. Batch just came off. Beef ${value}, chicken ${value2}, veggie ${value3}, Special ${value5}. And the Manuke's ${value4}. Life-changing, probably.", $"Yo. Cart's stocked, dude. ${value} for beef, ${value2} chicken, ${value3} veggie. Special's ${value5} if you're feeling brave. Manuke's ${value4}.", $"Hey hey. Got you covered. Beef ${value}, chicken ${value2}, veggie ${value3}. Special's ${value5} today. The Manuke sits at ${value4}, as it should." }; int num; do { num = _rng.Next(array.Length); } while (num == _lastOpener); _lastOpener = num; return array[num]; } private static void RollNextLines() { try { if (_entryNode != null) { _entryNode.DialogueText = RollOpener(); } if (_byeNode != null) { _byeNode.DialogueText = Lines.Pick(ByeLines); } } catch { } } private static List KyleVariants() { List list = new List(Variants.Length); Variant[] variants = Variants; foreach (Variant variant in variants) { if (variant.SoldByKyle) { list.Add(variant); } } return list; } private static DialogueContainer BuildTacoConversation() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Expected O, but got Unknown //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Expected O, but got Unknown //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Expected O, but got Unknown //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Expected O, but got Unknown //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Expected O, but got Unknown //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Expected O, but got Unknown //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Expected O, but got Unknown //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Expected O, but got Unknown //IL_0494: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Expected O, but got Unknown if ((Object)(object)_convo != (Object)null && Object.op_Implicit((Object)(object)_convo)) { return _convo; } DialogueContainer val = ScriptableObject.CreateInstance(); ((Object)val).name = "S1HT_TacoConversation"; ((Object)val).hideFlags = (HideFlags)32; val.DialogueNodeData = new List(); val.NodeLinks = new List(); val.BranchNodeData = new List(); List list = KyleVariants(); bool flag = NeedsConfig.BurroitoEnabled && !SaveData.BurroitoOwned; DialogueNodeData val2 = new DialogueNodeData(); val2.Guid = "S1HT_TACO_ENTRY"; val2.DialogueNodeLabel = TacoDiag.DiscoveredEntryLabel; val2.DialogueText = RollOpener(); bool veganTacoEnabled = NeedsConfig.VeganTacoEnabled; int num = list.Count + (flag ? 1 : 0) + (veganTacoEnabled ? 1 : 0) + 1; val2.choices = new Il2CppReferenceArray((long)num); DialogueChoiceData[] array = (DialogueChoiceData[])(object)new DialogueChoiceData[list.Count]; for (int i = 0; i < list.Count; i++) { Variant variant = list[i]; DialogueChoiceData val3 = new DialogueChoiceData(); val3.Guid = "S1HT_TACO_BUY_" + variant.Id; val3.ChoiceLabel = "S1HT_TACO_BUY_" + variant.Id; val3.ChoiceText = variant.Name + " ($" + P(variant.Price()) + ")"; ((Il2CppArrayBase)(object)val2.choices)[i] = val3; array[i] = val3; } int count = list.Count; if (flag) { DialogueChoiceData val4 = new DialogueChoiceData(); val4.Guid = "S1HT_TACO_BURROITO"; val4.ChoiceLabel = "S1HT_TACO_BURROITO"; val4.ChoiceText = "The Big Burroito (tm) ($" + P(NeedsConfig.BurroitoPrice) + ")"; ((Il2CppArrayBase)(object)val2.choices)[count++] = val4; } if (veganTacoEnabled) { DialogueChoiceData val5 = new DialogueChoiceData(); val5.Guid = "S1HT_TACO_VEGAN_ASK"; val5.ChoiceLabel = "S1HT_TACO_VEGAN_ASK"; val5.ChoiceText = "Got any vegan tacos?"; ((Il2CppArrayBase)(object)val2.choices)[count++] = val5; } DialogueChoiceData val6 = new DialogueChoiceData(); val6.Guid = "S1HT_TACO_EXIT"; val6.ChoiceLabel = "S1HT_TACO_EXIT"; val6.ChoiceText = "Nah, all good."; ((Il2CppArrayBase)(object)val2.choices)[count] = val6; DialogueNodeData val7 = new DialogueNodeData(); val7.Guid = "S1HT_TACO_SOLD"; val7.DialogueNodeLabel = "S1HT_SOLD"; val7.DialogueText = "There you go, man."; val7.choices = new Il2CppReferenceArray(0L); DialogueNodeData val8 = new DialogueNodeData(); val8.Guid = "S1HT_TACO_BYE"; val8.DialogueNodeLabel = "S1HT_BYE"; val8.DialogueText = ByeLines[0]; val8.choices = new Il2CppReferenceArray(0L); DialogueNodeData val9 = null; if (veganTacoEnabled) { val9 = new DialogueNodeData(); val9.Guid = "S1HT_TACO_VEGAN_OFFER"; val9.DialogueNodeLabel = "S1HT_VEGAN_OFFER"; val9.DialogueText = RollVeganOffer(); val9.choices = new Il2CppReferenceArray(2L); DialogueChoiceData val10 = new DialogueChoiceData(); val10.Guid = "S1HT_TACO_VEGAN_BUY"; val10.ChoiceLabel = "S1HT_TACO_VEGAN_BUY"; val10.ChoiceText = "Yeah, I'll take one. ($" + P(NeedsConfig.VeganTacoPrice) + ")"; DialogueChoiceData val11 = new DialogueChoiceData(); val11.Guid = "S1HT_TACO_VEGAN_NAH"; val11.ChoiceLabel = "S1HT_TACO_VEGAN_NAH"; val11.ChoiceText = "Let me think about it."; ((Il2CppArrayBase)(object)val9.choices)[0] = val10; ((Il2CppArrayBase)(object)val9.choices)[1] = val11; } val.DialogueNodeData.Add(val2); val.DialogueNodeData.Add(val7); val.DialogueNodeData.Add(val8); if (val9 != null) { val.DialogueNodeData.Add(val9); } for (int j = 0; j < array.Length; j++) { NodeLinkData val12 = new NodeLinkData(); val12.BaseDialogueOrBranchNodeGuid = val2.Guid; val12.BaseChoiceOrOptionGUID = array[j].Guid; val12.TargetNodeGuid = val7.Guid; val.NodeLinks.Add(val12); } if (flag) { NodeLinkData val13 = new NodeLinkData(); val13.BaseDialogueOrBranchNodeGuid = val2.Guid; val13.BaseChoiceOrOptionGUID = "S1HT_TACO_BURROITO"; val13.TargetNodeGuid = val7.Guid; val.NodeLinks.Add(val13); } if (val9 != null) { NodeLinkData val14 = new NodeLinkData(); val14.BaseDialogueOrBranchNodeGuid = val2.Guid; val14.BaseChoiceOrOptionGUID = "S1HT_TACO_VEGAN_ASK"; val14.TargetNodeGuid = val9.Guid; val.NodeLinks.Add(val14); NodeLinkData val15 = new NodeLinkData(); val15.BaseDialogueOrBranchNodeGuid = val9.Guid; val15.BaseChoiceOrOptionGUID = "S1HT_TACO_VEGAN_BUY"; val15.TargetNodeGuid = val7.Guid; val.NodeLinks.Add(val15); NodeLinkData val16 = new NodeLinkData(); val16.BaseDialogueOrBranchNodeGuid = val9.Guid; val16.BaseChoiceOrOptionGUID = "S1HT_TACO_VEGAN_NAH"; val16.TargetNodeGuid = val8.Guid; val.NodeLinks.Add(val16); } NodeLinkData val17 = new NodeLinkData(); val17.BaseDialogueOrBranchNodeGuid = val2.Guid; val17.BaseChoiceOrOptionGUID = val6.Guid; val17.TargetNodeGuid = val8.Guid; val.NodeLinks.Add(val17); _convo = val; _soldNode = val7; _entryNode = val2; _byeNode = val8; _veganOfferNode = val9; return val; } private static string P(float price) { return $"{Mathf.Max(1f, price):0}"; } private static void OnKyleNodeDisplayed(string label) { if (!string.IsNullOrEmpty(label)) { if (label.StartsWith("S1HT_") || label == TacoDiag.DiscoveredEntryLabel) { ConsumableMap.VLog("taco dialogue node displayed: '" + label + "'"); } if (label == "S1HT_SOLD" || label == "S1HT_BYE") { RollNextLines(); } } } private static void OnKyleDialogueChoice(string chosen) { if (!string.IsNullOrEmpty(chosen)) { Variant v; if (chosen == "S1HT_TACO_BURROITO") { OnBuyBurroito(); } else if (chosen == "S1HT_TACO_VEGAN_BUY") { OnBuyVeganTaco(); } else if (chosen.StartsWith("S1HT_TACO_BUY_") && TryGetVariant(chosen.Substring("S1HT_TACO_BUY_".Length), out v) && v.SoldByKyle) { OnBuyTaco(v); } } } private static void OnBuyBurroito() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) try { if (!KyleOpenNow()) { if (_soldNode != null) { _soldNode.DialogueText = KyleClosedLine; } NeedsHud.Toast(Lines.Pick(KyleClosedToasts), NeedsHud.ToastNeutral); Diag.Log("[Burroito] refused — closed (hours " + NeedsConfig.HoursTacos + ")."); return; } TriggerKyleAngry(8f); if (!NeedsConfig.BurroitoEnabled) { return; } if (SaveData.BurroitoOwned) { if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(BurroitoOwnedLines); } Diag.Log("[Burroito] re-ask refused (already owned)."); return; } float num = Mathf.Max(1f, NeedsConfig.BurroitoPrice); MoneyManager instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return; } if (instance.cashBalance < num) { if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(BurroitoBrokeLines); } NeedsHud.Toast($"The Big Burroito (tm) is ${num:0} cash. You haven't got it.", NeedsHud.ToastNeutral); Diag.Log($"[Burroito] refused — cash {instance.cashBalance:0} < {num:0}."); return; } instance.ChangeCashBalance(0f - num, true, true); SaveData.BurroitoOwned = true; try { PlayerInventory instance2 = PlayerSingleton.Instance; if ((Object)(object)instance2 != (Object)null && _defs.TryGetValue("burroito", out var value) && (Object)(object)value != (Object)null) { instance2.AddItemToInventory(((ItemDefinition)value).GetDefaultInstance(1)); } } catch (Exception ex) { Diag.Log("[Burroito] item delivery failed: " + ex.Message); } if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(BurroitoSoldLines); } NeedsHud.Toast($"Kyle handed it over like it insulted him. Permanently {NeedsConfig.BurroitoSpeedBonus:P0} quicker on your feet.", NeedsHud.ToastGood); Diag.Log($"[Burroito] SOLD for ${num:0} — item delivered, permanent x{1f + NeedsConfig.BurroitoSpeedBonus:0.00} move speed, flag persists on next game save."); } catch (Exception ex2) { Diag.Log("[Burroito] purchase failed: " + ex2.Message); } } internal static string RollVeganOffer() { string text = P(NeedsConfig.VeganTacoPrice); string[] array = new string[4] { "Oh yeah, for sure. We do a vegan one. $" + text + ", super fresh.", "Vegan? Totally, man. $" + text + ". Locally sourced, like... very locally.", "Yeah dude, the vegan option. $" + text + ". It's basically pure plants.", "For sure, for sure. One vegan taco, $" + text + ". Chef's pick." }; int num; do { num = _rng.Next(array.Length); } while (num == _lastVeganOffer); _lastVeganOffer = num; return array[num]; } private static StorableItemDefinition ResolveVeganLeaf(out string usedId) { usedId = null; for (int i = 0; i < VeganLeafIdsOrdered.Length; i++) { try { if (Registry.ItemExists(VeganLeafIdsOrdered[i])) { ItemDefinition item = Registry.GetItem(VeganLeafIdsOrdered[i]); StorableItemDefinition val = (((Object)(object)item != (Object)null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val != (Object)null) { usedId = VeganLeafIdsOrdered[i]; return val; } } } catch { } } return null; } private static void OnBuyVeganTaco() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: 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_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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) try { if (!NeedsConfig.VeganTacoEnabled) { return; } if (!KyleOpenNow()) { if (_soldNode != null) { _soldNode.DialogueText = KyleClosedLine; } NeedsHud.Toast(Lines.Pick(KyleClosedToasts), NeedsHud.ToastNeutral); return; } float num = Mathf.Max(1f, NeedsConfig.VeganTacoPrice); MoneyManager instance = NetworkSingleton.Instance; PlayerInventory instance2 = PlayerSingleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return; } if (instance.cashBalance < num) { if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(VeganBrokeLines); } NeedsHud.Toast($"Kyle wants ${num:0} cash. You haven't got it.", NeedsHud.ToastNeutral); return; } string text = null; try { TrashManager instance3 = NetworkSingleton.Instance; Player local = Player.Local; if ((Object)(object)instance3 != (Object)null && (Object)(object)local != (Object)null) { Transform transform = ((Component)local).transform; Vector3 val = transform.position + transform.forward * 0.7f + Vector3.up * 1.2f; Vector3 val2 = transform.forward * 1.1f + Vector3.up * 0.6f; TrashItem val3 = instance3.CreateTrashItem("plantscrap", val, Random.rotation, val2, "", false); if ((Object)(object)val3 != (Object)null) { int value = -1; try { value = val3.SellValue; } catch { } text = $"recyclable leaf trash 'plantscrap' (recycler SellValue ${value})"; } } } catch (Exception ex) { Diag.Log("[VeganTaco] leaf trash spawn failed (" + ex.Message + ") — trying the inventory fallback."); } if (text == null) { string usedId; StorableItemDefinition val4 = ResolveVeganLeaf(out usedId); if ((Object)(object)val4 == (Object)null) { if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(VeganOutLines); } NeedsHud.Toast("No vegan tacos today.", NeedsHud.ToastNeutral); Diag.Log("[VeganTaco] no delivery possible (trash spawn failed AND no leaf item; probed: " + string.Join(", ", VeganLeafIdsOrdered) + ") — sale skipped, no charge."); return; } instance2.AddItemToInventory(((ItemDefinition)val4).GetDefaultInstance(1)); text = $"inventory item '{usedId}' ({((BaseItemDefinition)val4).Name}) [fallback]"; } instance.ChangeCashBalance(0f - num, true, true); if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(VeganSoldLines); } NeedsHud.Toast(Lines.Pick(VeganBoughtToasts), NeedsHud.ToastGood); Diag.Log($"[VeganTaco] SOLD for ${num:0} — delivered {text}. He never explained."); } catch (Exception ex2) { Diag.Log("[VeganTaco] purchase failed: " + ex2.Message); } } private static void TriggerKyleAngry(float seconds) { try { Avatar val = (((Object)(object)_kyle != (Object)null) ? _kyle.Avatar : null); AvatarEmotionManager val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren(true) : null); if ((Object)(object)val2 == (Object)null) { Diag.Log("[Burroito] no AvatarEmotionManager on Kyle — angry face skipped."); return; } string[] array = new string[5] { "Angry", "Annoyed", "Frustrated", "Grumpy", "Concerned" }; for (int i = 0; i < array.Length; i++) { if (val2.HasEmotion(array[i])) { val2.AddEmotionOverride(array[i], "S1HT_Burroito", seconds, 90); Diag.Log($"[Burroito] Kyle's angry face ON: emotion '{array[i]}' for {seconds:0}s (AvatarEmotionManager.AddEmotionOverride)."); return; } } Diag.Log("[Burroito] no anger-flavored emotion preset on Kyle's roster — face unchanged."); } catch (Exception ex) { Diag.Log("[Burroito] angry emotion failed: " + ex.Message); } } private static void OnBuyTaco(Variant v) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) try { if (!_defs.TryGetValue(v.Id, out var value) || (Object)(object)value == (Object)null) { return; } if (!KyleOpenNow()) { if (_soldNode != null) { _soldNode.DialogueText = KyleClosedLine; } NeedsHud.Toast(Lines.Pick(KyleClosedToasts), NeedsHud.ToastNeutral); MelonLogger.Msg($"[Taco] '{v.Id}' refused — closed (hours {NeedsConfig.HoursTacos})."); return; } float num = Mathf.Max(1f, v.Price()); MoneyManager instance = NetworkSingleton.Instance; PlayerInventory instance2 = PlayerSingleton.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return; } if (instance.cashBalance < num) { if (_soldNode != null) { _soldNode.DialogueText = Lines.Pick(BrokeLines); } NeedsHud.Toast($"Kyle wants ${num:0} cash. You haven't got it.", NeedsHud.ToastNeutral); MelonLogger.Msg($"[Taco] '{v.Id}' purchase refused — cash {instance.cashBalance:0} < {num:0}."); } else { if (_soldNode != null && v.SoldLines != null && v.SoldLines.Length != 0) { _soldNode.DialogueText = Lines.Pick(v.SoldLines); } instance.ChangeCashBalance(0f - num, true, true); instance2.AddItemToInventory(((ItemDefinition)value).GetDefaultInstance(1)); NeedsHud.Toast(Lines.Pick(v.BoughtToasts), NeedsHud.ToastGood); MelonLogger.Msg($"[Taco] '{v.Id}' sold by Kyle for ${num:0}."); } } catch (Exception ex) { MelonLogger.Warning("[Taco] purchase failed: " + ex.Message); } } public static void OnConfigReload() { Variant[] variants = Variants; foreach (Variant variant in variants) { if (_defs.TryGetValue(variant.Id, out var value) && (Object)(object)value != (Object)null) { try { value.BasePurchasePrice = Mathf.Max(1f, variant.Price()); } catch { } } } if (_defs.TryGetValue("burroito", out var value2) && (Object)(object)value2 != (Object)null) { try { value2.BasePurchasePrice = Mathf.Max(1f, NeedsConfig.BurroitoPrice); } catch { } } } public static void TickMysteryShop() { if (!NeedsConfig.TacoEnabled || _mysteryStocked || !_defs.TryGetValue("tacomystery", out var value) || (Object)(object)value == (Object)null) { return; } float unscaledTime = Time.unscaledTime; if (!(unscaledTime < _nextShopAttempt)) { _nextShopAttempt = unscaledTime + 5f; TryGetVariant("tacomystery", out var v); int added = 0; int present = 0; ListVariantInShops(v, ref added, ref present); if (added + present > 0) { _mysteryStocked = true; MelonLogger.Msg($"[Taco] Mystery Meat Taco stocked on the convenience-store shelf ({added} added, {present} already there)."); } else if (++_shopAttempts >= 24) { _mysteryStocked = true; MelonLogger.Warning("[Taco] no banana-selling shop found this session — Mystery Meat Taco not stocked."); } } } public static void EnsureShopListings() { if (!NeedsConfig.TacoEnabled || _defs.Count == 0) { return; } Variant[] variants = Variants; foreach (Variant variant in variants) { if (variant.SoldByKyle) { int added = 0; int present = 0; ListVariantInShops(variant, ref added, ref present); if (added > 0) { MelonLogger.Msg($"[Taco] fallback: '{variant.Id}' listed in {added} shop(s)."); } } } } private static void ListVariantInShops(Variant v, ref int added, ref int present) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown if (v == null || !_defs.TryGetValue(v.Id, out var value) || (Object)(object)value == (Object)null) { return; } try { List allShops = ShopInterface.AllShops; if (allShops == null) { return; } for (int i = 0; i < allShops.Count; i++) { ShopInterface val = allShops[i]; if ((Object)(object)val == (Object)null || val.Listings == null) { continue; } ShopListing val2 = null; bool flag = false; for (int j = 0; j < val.Listings.Count; j++) { ShopListing val3 = val.Listings[j]; if (val3 != null && !((Object)(object)val3.Item == (Object)null)) { if (string.Equals(((BaseItemDefinition)val3.Item).ID, v.Id, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } if (((BaseItemDefinition)val3.Item).ID == "banana") { val2 = val3; } } } if (flag) { present++; } else if (val2 != null) { ShopListing val4 = new ShopListing(); val4.name = v.Name; val4.Item = value; val4.LimitedStock = false; val4.RestockRate = (ERestockRate)0; val4.DefaultStock = 99; val4.CanBeDelivered = val2.CanBeDelivered; val.Listings.Add(val4); val4.Initialize(val); try { val.CreateListingUI(val4); } catch (Exception ex) { MelonLogger.Warning("[Taco] listing UI for '" + val.ShopName + "' failed: " + ex.Message); } added++; MelonLogger.Msg($"[Taco] '{v.Id}' listed in '{val.ShopName}' at ${value.BasePurchasePrice:0}."); } } } catch (Exception ex2) { MelonLogger.Warning("[Taco] shop listing failed: " + ex2.Message); } } private static void SwapInTacoWorldModel(StorableItemDefinition def, Variant v) { SwapInWorldModel(def, Taco3D.GetMesh(), v.Id, v.Look); } public static void SwapInWorldModel(StorableItemDefinition def, Mesh mesh, string matKey, Taco3D.FillingLook look) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0189: 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_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)def.StoredItem == (Object)null) { MelonLogger.Msg("[Taco] donor has no StoredItem — '" + matKey + "' world model unchanged."); return; } StoredItem val = Object.Instantiate(def.StoredItem); ((Component)val).gameObject.SetActive(true); ((Component)val).transform.position = new Vector3(0f, -3000f, 0f); ((Object)((Component)val).gameObject).hideFlags = (HideFlags)32; Object.DontDestroyOnLoad((Object)(object)((Component)val).gameObject); ((Object)((Component)val).gameObject).name = "S1HT_StoredItem_" + matKey; Il2CppArrayBase componentsInChildren = ((Component)val).GetComponentsInChildren(true); Material material = Taco3D.GetMaterial((Renderer)(object)((componentsInChildren.Length > 0) ? componentsInChildren[0] : null), matKey, look); int num = 0; Il2CppArrayBase componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { if (!((Object)(object)componentsInChildren2[i] == (Object)null)) { Transform transform = ((Component)componentsInChildren2[i]).transform; ConsumableMap.VLog($"stored-item child '{((Object)((Component)transform).gameObject).name}' before: pos {transform.localPosition}, rot {transform.localEulerAngles}, scale {transform.localScale}"); componentsInChildren2[i].sharedMesh = mesh; transform.localScale = Vector3.one; transform.localPosition = new Vector3(transform.localPosition.x, Mathf.Max(transform.localPosition.y, 0.06f), transform.localPosition.z); ConsumableMap.VLog($"stored-item child '{((Object)((Component)transform).gameObject).name}' after: pos {transform.localPosition}, rot {transform.localEulerAngles}, scale {transform.localScale}"); num++; } } for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)null && (Object)(object)material != (Object)null) { ((Renderer)componentsInChildren[j]).sharedMaterial = material; } } def.StoredItem = val; Diag.Log($"[Model] shelf '{matKey}' → mesh '{((Object)mesh).name}' mat '{(((Object)(object)material != (Object)null) ? ((Object)material).name : "inherited")}' ({num} mesh(es) on the prop, template ACTIVE at y=-3000)."); } catch (Exception ex) { MelonLogger.Warning($"[Taco] world model swap failed ({ex.Message}) — donor visuals kept for '{matKey}'."); } } private static void DumpEnergyDrinkReference() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) if (_energyRefDumped) { return; } _energyRefDumped = true; try { ItemDefinition item = Registry.GetItem("energydrink"); StorableItemDefinition val = (((Object)(object)item != (Object)null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val == (Object)null || (Object)(object)val.StoredItem == (Object)null) { Diag.Log("[Shelf] REFERENCE: energydrink StoredItem not found."); return; } Transform transform = ((Component)val.StoredItem).transform; Diag.Log($"[Shelf] REFERENCE energydrink prop root: rot {transform.localEulerAngles}, scale {transform.localScale}"); Il2CppArrayBase componentsInChildren = ((Component)val.StoredItem).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { Transform transform2 = ((Component)componentsInChildren[i]).transform; Diag.Log($"[Shelf] REFERENCE energydrink child '{((Object)((Component)transform2).gameObject).name}': pos {transform2.localPosition}, rot {transform2.localEulerAngles}, scale {transform2.localScale}"); } } } catch (Exception ex) { Diag.Log("[Shelf] REFERENCE dump failed: " + ex.Message); } } public static void OnStoredItemPlaced(StoredItem inst) { FixPlacedInstance(inst, "patch"); } public static void TickShelfWatcher() { float unscaledTime = Time.unscaledTime; if (unscaledTime < _nextShelfSweep) { return; } _nextShelfSweep = unscaledTime + 2f; DumpEnergyDrinkReference(); try { Il2CppArrayBase val = Object.FindObjectsOfType(); for (int i = 0; i < val.Length; i++) { StoredItem val2 = val[i]; if (!((Object)(object)val2 == (Object)null) && !_seenStored.Contains(((Il2CppObjectBase)val2).Pointer)) { _seenStored.Add(((Il2CppObjectBase)val2).Pointer); FixPlacedInstance(val2, "watcher"); } } } catch (Exception ex) { MelonLogger.Warning("[Shelf] sweep failed: " + ex.Message); } } public static void OnShelfSessionEnded() { _seenStored.Clear(); _nextShelfSweep = 0f; } private static void FixPlacedInstance(StoredItem inst, string source) { //IL_008d: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_024b: 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) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)inst == (Object)null) { return; } string text = null; try { text = ((inst.item != null && (Object)(object)((ItemInstance)inst.item).Definition != (Object)null) ? ((BaseItemDefinition)((ItemInstance)inst.item).Definition).ID : null); } catch { } if (!ItemModels.TryResolve(text, out var mesh, out var matKey, out var look, out var handEuler)) { return; } GameObject gameObject = ((Component)inst).gameObject; List list = new List(6); if (!gameObject.activeSelf) { gameObject.SetActive(true); list.Add("activated"); } handEuler = gameObject.transform.localScale; if (((Vector3)(ref handEuler)).sqrMagnitude < 0.0001f) { gameObject.transform.localScale = Vector3.one; list.Add("root-scale"); } Il2CppArrayBase componentsInChildren = gameObject.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { GameObject val = new GameObject("S1HT_ShelfModel_" + matKey); val.transform.SetParent(gameObject.transform, false); val.transform.localPosition = new Vector3(0f, 0.06f, 0f); val.layer = gameObject.layer; val.AddComponent().sharedMesh = mesh; MeshRenderer val2 = val.AddComponent(); Material material = Taco3D.GetMaterial(null, matKey, look); if ((Object)(object)material != (Object)null) { ((Renderer)val2).sharedMaterial = material; } list.Add("visual-built"); componentsInChildren = gameObject.GetComponentsInChildren(true); } else { for (int i = 0; i < componentsInChildren.Length; i++) { MeshFilter val3 = componentsInChildren[i]; if (!((Object)(object)val3 == (Object)null)) { if ((Object)(object)val3.sharedMesh == (Object)null || ((Object)val3.sharedMesh).name != ((Object)mesh).name) { val3.sharedMesh = mesh; list.Add("mesh"); } Transform transform = ((Component)val3).transform; Quaternion rotation = transform.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; if (Mathf.Abs(Mathf.DeltaAngle(eulerAngles.x, 0f)) > 2f || Mathf.Abs(Mathf.DeltaAngle(eulerAngles.z, 0f)) > 2f) { transform.rotation = Quaternion.Euler(0f, eulerAngles.y, 0f); list.Add("leveled"); } if (transform.localPosition.y < 0.04f) { transform.localPosition = new Vector3(transform.localPosition.x, 0.06f, transform.localPosition.z); list.Add("seated"); } if (transform.localScale != Vector3.one) { transform.localScale = Vector3.one; list.Add("child-scale"); } if (!((Component)val3).gameObject.activeSelf) { ((Component)val3).gameObject.SetActive(true); list.Add("mesh-go-activated"); } } } } Il2CppArrayBase componentsInChildren2 = gameObject.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { MeshRenderer val4 = componentsInChildren2[j]; if (!((Object)(object)val4 == (Object)null)) { if (!((Renderer)val4).enabled) { ((Renderer)val4).enabled = true; list.Add("renderer-enabled"); } Material material2 = Taco3D.GetMaterial((Renderer)(object)val4, matKey, look); if ((Object)(object)material2 != (Object)null && ((Object)(object)((Renderer)val4).sharedMaterial == (Object)null || ((Il2CppObjectBase)((Renderer)val4).sharedMaterial).Pointer != ((Il2CppObjectBase)material2).Pointer)) { ((Renderer)val4).sharedMaterial = material2; list.Add("material"); } } } string value = ((list.Count > 0) ? string.Join(",", list) : "none-needed"); Diag.Log($"[Shelf] '{text}' via {source}: mesh='{((Object)mesh).name}' mat='{matKey}' actions=[{value}] activeInHierarchy={gameObject.activeInHierarchy} renderers={componentsInChildren2.Length} worldPos={gameObject.transform.position} lossyScale={gameObject.transform.lossyScale}"); } catch (Exception ex) { Diag.Log("[Shelf] repair failed (" + source + "): " + ex.Message); } } private static Sprite LoadIcon(Variant v) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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) if (_icons.TryGetValue(v.Id, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } if (!_nativeSpriteChecked) { _nativeSpriteChecked = true; try { Il2CppReferenceArray val = Resources.FindObjectsOfTypeAll(Il2CppType.Of()); for (int i = 0; i < ((Il2CppArrayBase)(object)val).Length; i++) { Sprite val2 = ((Il2CppObjectBase)((Il2CppArrayBase)(object)val)[i]).TryCast(); if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name.ToLowerInvariant().Contains("taco")) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(84, 3); defaultInterpolatedStringHandler.AppendLiteral("[Taco] FYI: native sprite '"); defaultInterpolatedStringHandler.AppendFormatted(((Object)val2).name); defaultInterpolatedStringHandler.AppendLiteral("' ("); Rect rect = val2.rect; defaultInterpolatedStringHandler.AppendFormatted(((Rect)(ref rect)).width, "0"); defaultInterpolatedStringHandler.AppendLiteral("x"); rect = val2.rect; defaultInterpolatedStringHandler.AppendFormatted(((Rect)(ref rect)).height, "0"); defaultInterpolatedStringHandler.AppendLiteral(") exists — using custom per-variant icons regardless."); MelonLogger.Msg(defaultInterpolatedStringHandler.ToStringAndClear()); } } } catch (Exception ex) { MelonLogger.Warning("[Taco] native sprite scan failed: " + ex.Message); } } return LoadIconResource(v.Id, v.IconResource); } private static Sprite LoadIconResource(string cacheId, string resource) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if (_icons.TryGetValue(cacheId, out var value) && (Object)(object)value != (Object)null && Object.op_Implicit((Object)(object)value)) { return value; } try { using Stream stream = typeof(TacoItem).Assembly.GetManifestResourceStream(resource); if (stream == null) { MelonLogger.Warning("[Taco] icon resource '" + resource + "' missing — keeping donor icon."); 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; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ((Object)val).hideFlags = (HideFlags)32; if (!ImageConversion.LoadImage(val, Il2CppStructArray.op_Implicit(array))) { MelonLogger.Warning("[Taco] '" + cacheId + "' icon failed to decode — keeping donor icon."); return null; } Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)val2).hideFlags = (HideFlags)32; _icons[cacheId] = val2; return val2; } catch (Exception ex) { MelonLogger.Warning($"[Taco] '{cacheId}' icon load failed ({ex.Message}) — keeping donor icon."); return null; } } } [HarmonyPatch] public static class TrashPatch { [HarmonyPostfix] [HarmonyPatch(typeof(TrashManager), "CreateTrashItem", new Type[] { typeof(string), typeof(Vector3), typeof(Quaternion), typeof(Vector3), typeof(string), typeof(bool) })] private static void AfterCreateTrashItem(TrashItem __result) { try { if (NeedsConfig.Enabled && Session.InGame) { ConsumeWatcher.NotifyTrashSpawned(__result); } } catch (Exception ex) { MelonLogger.Warning("[Eat] trash spawn postfix error: " + ex.Message); } } } [HarmonyPatch] public static class ShelfPatch { [HarmonyPostfix] [HarmonyPatch(typeof(StoredItem), "InitializeStoredItem", new Type[] { typeof(StorableItemInstance), typeof(StorageGrid), typeof(Vector2), typeof(float) })] private static void AfterInitializeStoredItem(StoredItem __instance) { try { TacoItem.OnStoredItemPlaced(__instance); } catch (Exception ex) { MelonLogger.Warning("[Shelf] placement postfix error: " + ex.Message); } } } }