Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SurvivalNeeds v1.0.1
plugins/SurvivalNeeds.dll
Decompiled 3 days agousing System; using System.Collections; 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 BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SurvivalNeeds")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+e71ae06cc59fc4048ec21a02357166f94a697f06")] [assembly: AssemblyProduct("SurvivalNeeds")] [assembly: AssemblyTitle("SurvivalNeeds")] [assembly: AssemblyVersion("1.0.1.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 SurvivalNeeds { public static class Cfg { public enum HudPlacement { Auto, RightOfHealth, AboveHealth } public static ConfigEntry<bool> HudEnabled; public static ConfigEntry<float> HudOffsetX; public static ConfigEntry<float> HudOffsetY; public static ConfigEntry<float> HudScale; public static ConfigEntry<bool> ShowPercentages; public static ConfigEntry<float> LowWarningPercent; public static ConfigEntry<HudPlacement> Placement; public static ConfigEntry<float> HungerMinutes; public static ConfigEntry<float> ThirstMinutes; public static ConfigEntry<float> EnergyMinutes; public static ConfigEntry<float> SprintEnergyMultiplier; public static ConfigEntry<bool> ResetOnDeath; public static ConfigEntry<float> Tier2MinHealth; public static ConfigEntry<float> Tier3MinHealth; public static ConfigEntry<float> Tier4MinHealth; public static ConfigEntry<float> Tier5MinHealth; public static ConfigEntry<float> Tier1Fill; public static ConfigEntry<float> Tier2Fill; public static ConfigEntry<float> Tier3Fill; public static ConfigEntry<float> Tier4Fill; public static ConfigEntry<float> Tier5Fill; public static ConfigEntry<float> StaminaToEnergy; public static ConfigEntry<float> MaxEnergyPerFood; public static ConfigEntry<bool> DrinksFillThirst; public static ConfigEntry<float> DrinkThirstFill; public static ConfigEntry<string> DrinkItems; public static ConfigEntry<int> WaterSkinCharges; public static ConfigEntry<float> WaterSkinThirstPerCharge; public static ConfigEntry<string> WaterSkinRecipe; public static ConfigEntry<string> WaterSkinStation; public static ConfigEntry<int> WaterSkinStationLevel; public static ConfigEntry<bool> AutoRefillInWater; public static ConfigEntry<bool> RefillOnUseNearWater; public static ConfigEntry<float> RefillDistance; public static ConfigEntry<bool> DrinkFromWaterEnabled; public static ConfigEntry<KeyboardShortcut> DrinkFromWaterKey; public static ConfigEntry<float> DrinkFromWaterAmount; public static ConfigEntry<float> DrinkFromWaterCooldown; public static ConfigEntry<float> RestEnergyPerTick; public static ConfigEntry<bool> SleepFullRestore; public static ConfigEntry<float> StarvationDamage; public static ConfigEntry<float> WarningInterval; public static ConfigEntry<bool> ExhaustionEnabled; private static ConfigDescription Admin(string text, AcceptableValueBase range = null) { //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_0017: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigDescription(text, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } }); } private static ConfigDescription Local(string text, AcceptableValueBase range = null) { //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_0017: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigDescription(text, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = false } }); } public static void Bind(ConfigFile c) { //IL_0603: Unknown result type (might be due to invalid IL or missing references) HudEnabled = c.Bind<bool>("1 - HUD", "Enabled", true, Local("Show the Hunger, Thirst and Energy bars.")); Placement = c.Bind<HudPlacement>("1 - HUD", "Placement", HudPlacement.Auto, Local("Auto places the bars right of the health bar, or above it if that space is taken. RightOfHealth and AboveHealth force one side.")); HudOffsetX = c.Bind<float>("1 - HUD", "OffsetX", 0f, Local("Horizontal offset in HUD pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f))); HudOffsetY = c.Bind<float>("1 - HUD", "OffsetY", 0f, Local("Vertical offset in HUD pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f))); HudScale = c.Bind<float>("1 - HUD", "Scale", 1f, Local("Size multiplier for the bars.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f))); ShowPercentages = c.Bind<bool>("1 - HUD", "ShowPercentages", true, Local("Show the percentage next to each bar.")); LowWarningPercent = c.Bind<float>("1 - HUD", "LowWarningPercent", 15f, Local("Bars pulse when below this percentage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); HungerMinutes = c.Bind<float>("2 - Decay", "HungerMinutes", 60f, Admin("Real minutes for hunger to drain from 100 to 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10000f))); ThirstMinutes = c.Bind<float>("2 - Decay", "ThirstMinutes", 45f, Admin("Real minutes for thirst to drain from 100 to 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10000f))); EnergyMinutes = c.Bind<float>("2 - Decay", "EnergyMinutes", 90f, Admin("Real minutes awake for energy to drain from 100 to 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10000f))); SprintEnergyMultiplier = c.Bind<float>("2 - Decay", "SprintEnergyMultiplier", 3f, Admin("Energy drain multiplier while sprinting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f))); ResetOnDeath = c.Bind<bool>("2 - Decay", "ResetOnDeath", true, Admin("Refill all needs when you die and respawn.")); Tier2MinHealth = c.Bind<float>("3 - Food", "Tier2MinHealth", 20f, Admin("Minimum food health for tier 2. Anything below is tier 1.")); Tier3MinHealth = c.Bind<float>("3 - Food", "Tier3MinHealth", 40f, Admin("Minimum food health for tier 3.")); Tier4MinHealth = c.Bind<float>("3 - Food", "Tier4MinHealth", 60f, Admin("Minimum food health for tier 4.")); Tier5MinHealth = c.Bind<float>("3 - Food", "Tier5MinHealth", 80f, Admin("Minimum food health for tier 5.")); Tier1Fill = c.Bind<float>("3 - Food", "Tier1Fill", 10f, Admin("Hunger percent filled by a tier 1 food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); Tier2Fill = c.Bind<float>("3 - Food", "Tier2Fill", 20f, Admin("Hunger percent filled by a tier 2 food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); Tier3Fill = c.Bind<float>("3 - Food", "Tier3Fill", 30f, Admin("Hunger percent filled by a tier 3 food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); Tier4Fill = c.Bind<float>("3 - Food", "Tier4Fill", 40f, Admin("Hunger percent filled by a tier 4 food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); Tier5Fill = c.Bind<float>("3 - Food", "Tier5Fill", 50f, Admin("Hunger percent filled by a tier 5 food.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); StaminaToEnergy = c.Bind<float>("3 - Food", "StaminaToEnergy", 0.25f, Admin("Energy percent restored per point of the food's stamina value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f))); MaxEnergyPerFood = c.Bind<float>("3 - Food", "MaxEnergyPerFood", 25f, Admin("Most energy percent a single food item can restore.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); DrinksFillThirst = c.Bind<bool>("3 - Food", "DrinksFillThirst", true, Admin("Meads and other drinks fill thirst.")); DrinkThirstFill = c.Bind<float>("3 - Food", "DrinkThirstFill", 25f, Admin("Thirst percent filled by a mead or drink.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); DrinkItems = c.Bind<string>("3 - Food", "DrinkItems", "Mead,BarleyWine", Admin("Comma separated prefab name prefixes counted as drinks. Items flagged as drinks by the game always count.")); WaterSkinCharges = c.Bind<int>("4 - WaterSkin", "Charges", 3, Admin("Charges in a full waterskin.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20))); WaterSkinThirstPerCharge = c.Bind<float>("4 - WaterSkin", "ThirstPerCharge", 25f, Admin("Thirst percent restored per charge.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); WaterSkinRecipe = c.Bind<string>("4 - WaterSkin", "Recipe", "LeatherScraps:4,DeerHide:2", Admin("Crafting cost as Prefab:Amount pairs separated by commas.")); WaterSkinStation = c.Bind<string>("4 - WaterSkin", "CraftingStation", "piece_workbench", Admin("Crafting station prefab name. Leave empty to craft by hand.")); WaterSkinStationLevel = c.Bind<int>("4 - WaterSkin", "CraftingStationLevel", 1, Admin("Required crafting station level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10))); AutoRefillInWater = c.Bind<bool>("4 - WaterSkin", "AutoRefillInWater", true, Admin("Refill waterskins while standing, wading or swimming in water.")); RefillOnUseNearWater = c.Bind<bool>("4 - WaterSkin", "RefillOnUseNearWater", true, Admin("Using a waterskin that is not full near water refills it.")); RefillDistance = c.Bind<float>("4 - WaterSkin", "RefillDistance", 3f, Admin("How close to water, in meters, counts as near water.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f))); DrinkFromWaterEnabled = c.Bind<bool>("5 - Drink From Water", "Enabled", true, Admin("Allow drinking straight from water you stand in.")); DrinkFromWaterKey = c.Bind<KeyboardShortcut>("5 - Drink From Water", "Key", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), Local("Key to drink from water you are standing in.")); DrinkFromWaterAmount = c.Bind<float>("5 - Drink From Water", "ThirstPerSip", 20f, Admin("Thirst percent restored per sip.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); DrinkFromWaterCooldown = c.Bind<float>("5 - Drink From Water", "CooldownSeconds", 1.5f, Admin("Seconds between sips.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f))); RestEnergyPerTick = c.Bind<float>("6 - Rest", "EnergyPerTick", 1f, Admin("Energy points per tick while resting. One tick per second per comfort level.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f))); SleepFullRestore = c.Bind<bool>("6 - Rest", "SleepFullRestore", true, Admin("Sleeping through the night fully restores energy.")); StarvationDamage = c.Bind<float>("7 - Starvation", "DamagePerTick", 1f, Admin("Damage per second when hunger or thirst is empty. Does not stack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f))); WarningInterval = c.Bind<float>("7 - Starvation", "WarningIntervalSeconds", 30f, Admin("Seconds between repeated warning messages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f))); ExhaustionEnabled = c.Bind<bool>("8 - Exhaustion", "Enabled", true, Admin("At 0 energy, stamina is locked at 0 and sprinting is disabled.")); } public static int TierFor(float health) { if (health >= Tier5MinHealth.Value) { return 5; } if (health >= Tier4MinHealth.Value) { return 4; } if (health >= Tier3MinHealth.Value) { return 3; } if (health >= Tier2MinHealth.Value) { return 2; } return 1; } public static float FillFor(int tier) { return tier switch { 5 => Tier5Fill.Value, 4 => Tier4Fill.Value, 3 => Tier3Fill.Value, 2 => Tier2Fill.Value, _ => Tier1Fill.Value, }; } public static float EnergyFor(float stamina) { return Mathf.Clamp(stamina * StaminaToEnergy.Value, 0f, MaxEnergyPerFood.Value); } } public static class Commands { public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetNeedCommand("sn_hunger", "Hunger")); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetNeedCommand("sn_thirst", "Thirst")); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetNeedCommand("sn_energy", "Energy")); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetNeedCommand("sn_all", "All")); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RefillCommand()); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new StatusCommand()); } public static bool Allowed() { if (Terminal.m_cheat) { return true; } SynchronizationManager instance = SynchronizationManager.Instance; if (instance != null) { return instance.PlayerIsAdmin; } return false; } public static void Print(string text) { if ((Object)(object)Console.instance != (Object)null) { ((Terminal)Console.instance).AddString(text); } } public static bool Guard() { if (!Allowed()) { Print("SurvivalNeeds: admin or devcommands required."); return false; } if ((Object)(object)Player.m_localPlayer == (Object)null) { Print("SurvivalNeeds: no local player."); return false; } return true; } } public class SetNeedCommand : ConsoleCommand { private readonly string _name; private readonly string _need; public override string Name => _name; public override string Help => "[0-100] Set " + _need.ToLowerInvariant() + " (SurvivalNeeds, admin or devcommands)"; public SetNeedCommand(string name, string need) { _name = name; _need = need; } public override void Run(string[] args) { if (!Commands.Guard()) { return; } if (args.Length < 1 || !float.TryParse(args[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { Commands.Print("Usage: " + _name + " <0-100>"); return; } switch (_need) { case "Hunger": Needs.Hunger = result; break; case "Thirst": Needs.Thirst = result; break; case "Energy": Needs.Energy = result; break; default: Needs.SetAll(result); break; } Needs.Clamp(); Needs.Save(Player.m_localPlayer); Commands.Print(StatusCommand.Describe()); } } public class RefillCommand : ConsoleCommand { public override string Name => "sn_refill"; public override string Help => "Refill all waterskins in your inventory (SurvivalNeeds, admin or devcommands)"; public override void Run(string[] args) { if (Commands.Guard()) { WaterSkin.RefillAll(Player.m_localPlayer, message: true); Commands.Print("Waterskins refilled."); } } } public class StatusCommand : ConsoleCommand { public override string Name => "sn_status"; public override string Help => "Show hunger, thirst, energy and resting state (SurvivalNeeds)"; public static string Describe() { return string.Format(CultureInfo.InvariantCulture, "Hunger {0:0.#} Thirst {1:0.#} Energy {2:0.#} Resting {3} (comfort {4}) Exhausted {5}", Needs.Hunger, Needs.Thirst, Needs.Energy, NeedsController.Resting, NeedsController.Comfort, Needs.Exhausted); } public override void Run(string[] args) { Commands.Print(Describe()); } } public static class Icons { public static Sprite WaterSkin; public static Sprite Hunger; public static Sprite Thirst; public static Sprite Energy; private static Sprite _rounded; public static Sprite Rounded { get { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0115: 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_0144: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rounded != (Object)null) { return _rounded; } Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; Color32[] array = (Color32[])(object)new Color32[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = Mathf.Clamp((float)j + 0.5f, 15.5f, 16.5f); float num2 = Mathf.Clamp((float)i + 0.5f, 15.5f, 16.5f); float num3 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), new Vector2(num, num2)); float num4 = Mathf.Clamp01(15.5f - num3 + 0.5f); array[i * 32 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num4 * 255f)); } } val.SetPixels32(array); val.Apply(); _rounded = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(15f, 15f, 15f, 15f)); ((Object)_rounded).name = "SurvivalNeeds_Rounded"; return _rounded; } } public static void Load() { WaterSkin = FromResource("waterskin.png"); Hunger = FromResource("hunger.png"); Thirst = FromResource("thirst.png"); Energy = FromResource("energy.png"); } private static Sprite FromResource(string file) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0096: 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) using Stream stream = typeof(Icons).Assembly.GetManifestResourceStream("SurvivalNeeds.Assets." + file); if (stream == null) { Plugin.Warn("Missing embedded icon " + file); return null; } MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); ImageConversion.LoadImage(val, memoryStream.ToArray()); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; ((Object)val).name = "SurvivalNeeds_" + file; Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = ((Object)val).name; return obj; } } public static class NeedEffects { public const string StarvingName = "SE_SurvivalNeeds_Starving"; public const string DehydratedName = "SE_SurvivalNeeds_Dehydrated"; public const string ExhaustedName = "SE_SurvivalNeeds_Exhausted"; public static int StarvingHash; public static int DehydratedHash; public static int ExhaustedHash; public static void Register() { StarvingHash = Add("SE_SurvivalNeeds_Starving", "Starving", Icons.Hunger, "Your hunger is empty. You lose health every second until you eat.", "You are starving! Eat something."); DehydratedHash = Add("SE_SurvivalNeeds_Dehydrated", "Dehydrated", Icons.Thirst, "Your thirst is empty. You lose health every second until you drink.", "You are dehydrated! Find water."); ExhaustedHash = Add("SE_SurvivalNeeds_Exhausted", "Exhausted", Icons.Energy, "Your energy is empty. No stamina and no sprinting until you rest, sleep or eat.", "You are exhausted! Rest or sleep."); } private static int Add(string id, string display, Sprite icon, string tooltip, string start) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown StatusEffect val = ScriptableObject.CreateInstance<StatusEffect>(); ((Object)val).name = id; val.m_name = display; val.m_tooltip = tooltip; val.m_icon = icon; val.m_ttl = 0f; val.m_startMessageType = (MessageType)2; val.m_startMessage = start; val.m_stopMessage = ""; ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(val, false)); return val.NameHash(); } public static void Sync(Player p, int hash, bool active) { SEMan sEMan = ((Character)p).GetSEMan(); if (sEMan != null) { bool flag = sEMan.HaveStatusEffect(hash); if (active && !flag) { sEMan.AddStatusEffect(hash, false, 0, 0f, (short)0); } else if (!active && flag) { sEMan.RemoveStatusEffect(hash, true); } } } } public static class Needs { public const float Max = 100f; private const string KeyHunger = "SurvivalNeeds.Hunger"; private const string KeyThirst = "SurvivalNeeds.Thirst"; private const string KeyEnergy = "SurvivalNeeds.Energy"; public static float Hunger = 100f; public static float Thirst = 100f; public static float Energy = 100f; public static bool ResetPending; public static bool Exhausted { get { if (Cfg.ExhaustionEnabled.Value && Energy <= 0f) { return (Object)(object)Player.m_localPlayer != (Object)null; } return false; } } public static void Clamp() { Hunger = Mathf.Clamp(Hunger, 0f, 100f); Thirst = Mathf.Clamp(Thirst, 0f, 100f); Energy = Mathf.Clamp(Energy, 0f, 100f); } public static void SetAll(float v) { Hunger = v; Thirst = v; Energy = v; Clamp(); } public static void LoadFrom(Player p) { if (ResetPending) { ResetPending = false; SetAll(100f); Save(p); } else { Hunger = Read(p, "SurvivalNeeds.Hunger"); Thirst = Read(p, "SurvivalNeeds.Thirst"); Energy = Read(p, "SurvivalNeeds.Energy"); Clamp(); } } private static float Read(Player p, string key) { if ((Object)(object)p != (Object)null && p.m_customData != null && p.m_customData.TryGetValue(key, out var value) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return 100f; } public static void Save(Player p) { if (!((Object)(object)p == (Object)null) && p.m_customData != null) { p.m_customData["SurvivalNeeds.Hunger"] = Hunger.ToString("0.###", CultureInfo.InvariantCulture); p.m_customData["SurvivalNeeds.Thirst"] = Thirst.ToString("0.###", CultureInfo.InvariantCulture); p.m_customData["SurvivalNeeds.Energy"] = Energy.ToString("0.###", CultureInfo.InvariantCulture); } } public static bool IsDrink(ItemData item) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return false; } if (WaterSkin.Is(item)) { return false; } if ((int)item.m_shared.m_itemType != 2) { return false; } if (item.m_shared.m_isDrink) { return true; } string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : ""); string text2 = item.m_shared.m_name ?? ""; string[] array = (Cfg.DrinkItems.Value ?? "").Split(','); for (int i = 0; i < array.Length; i++) { string text3 = array[i].Trim(); if (text3.Length != 0) { if (text.StartsWith(text3, StringComparison.OrdinalIgnoreCase)) { return true; } if (text2.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } public static bool IsFood(ItemData item) { if (item == null || item.m_shared == null) { return false; } SharedData shared = item.m_shared; if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f)) { return shared.m_foodEitr > 0f; } return true; } public static void OnAte(Player p, ItemData item) { if (IsFood(item)) { float num = Cfg.FillFor(Cfg.TierFor(item.m_shared.m_food)); float num2 = Cfg.EnergyFor(item.m_shared.m_foodStamina); Hunger += num; Energy += num2; Clamp(); Save(p); } } public static void OnDrank(Player p, ItemData item) { if (Cfg.DrinksFillThirst.Value && IsDrink(item)) { Thirst += Cfg.DrinkThirstFill.Value; Clamp(); Save(p); } } } public class NeedsController : MonoBehaviour { public static NeedsController Instance; private Player _tracked; private float _tick; private bool _resting; private int _comfort; private float _lastWarning = -9999f; private float _lastSip = -9999f; private NeedsHud _hud; private bool _hudFailed; public static bool Resting { get { if ((Object)(object)Instance != (Object)null) { return Instance._resting; } return false; } } public static int Comfort { get { if (!((Object)(object)Instance != (Object)null)) { return 0; } return Instance._comfort; } } private void Awake() { Instance = this; } private void Update() { Player localPlayer = Player.m_localPlayer; EnsureHud(); if ((Object)(object)localPlayer == (Object)null) { _tracked = null; return; } if ((Object)(object)localPlayer != (Object)(object)_tracked) { _tracked = localPlayer; Needs.LoadFrom(localPlayer); _tick = 0f; _resting = false; } if (((Character)localPlayer).IsDead() || ((Character)localPlayer).InIntro()) { return; } float deltaTime = Time.deltaTime; if (deltaTime <= 0f) { return; } Needs.Hunger -= deltaTime * 100f / (Cfg.HungerMinutes.Value * 60f); Needs.Thirst -= deltaTime * 100f / (Cfg.ThirstMinutes.Value * 60f); if (!localPlayer.IsSleeping() && !_resting) { float num = deltaTime * 100f / (Cfg.EnergyMinutes.Value * 60f); if (((Character)localPlayer).IsRunning()) { num *= Cfg.SprintEnergyMultiplier.Value; } Needs.Energy -= num; } Needs.Clamp(); _tick += deltaTime; int num2 = 0; while (_tick >= 1f && num2++ < 5) { _tick -= 1f; Second(localPlayer); } if (_tick > 1f) { _tick = 0f; } HandleDrinkKey(localPlayer); } private void EnsureHud() { if ((Object)(object)_hud != (Object)null || _hudFailed || (Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_rootObject == (Object)null) { return; } try { _hud = NeedsHud.Create(Hud.instance); } catch (Exception ex) { Plugin.Warn("HUD creation failed: " + ex); _hudFailed = true; } } private void Second(Player p) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) _resting = CheckResting(p, out _comfort); if (_resting) { Needs.Energy += (float)Mathf.Max(1, _comfort) * Cfg.RestEnergyPerTick.Value; } bool flag = Needs.Hunger <= 0f; bool flag2 = Needs.Thirst <= 0f; if ((flag || flag2) && Cfg.StarvationDamage.Value > 0f && !((Character)p).InGodMode()) { HitData val = new HitData(); val.m_damage.m_damage = Cfg.StarvationDamage.Value; val.m_point = ((Component)p).transform.position; val.m_dir = Vector3.zero; val.m_hitType = (HitType)0; ((Character)p).ApplyDamage(val, true, false, (DamageModifier)0); } NeedEffects.Sync(p, NeedEffects.StarvingHash, flag); NeedEffects.Sync(p, NeedEffects.DehydratedHash, flag2); NeedEffects.Sync(p, NeedEffects.ExhaustedHash, Needs.Exhausted); if (flag || flag2 || Needs.Exhausted) { if (Time.time - _lastWarning >= Cfg.WarningInterval.Value) { _lastWarning = Time.time; string text = ((flag && flag2) ? "You are starving and dehydrated!" : (flag ? "You are starving! Eat something." : ((!flag2) ? "You are exhausted! Rest or sleep." : "You are dehydrated! Find water."))); ((Character)p).Message((MessageType)1, text, 0, (Sprite)null, false); } } else { _lastWarning = -9999f; } if (Cfg.AutoRefillInWater.Value && WaterSkin.InWater(p)) { WaterSkin.RefillAll(p, message: true); } Needs.Clamp(); Needs.Save(p); } private static bool CheckResting(Player p, out int comfort) { comfort = 0; if (!((Character)p).IsSitting() && !((Character)p).InBed() && (!((Character)p).IsAttached() || ((Character)p).IsAttachedToShip())) { return false; } SEMan sEMan = ((Character)p).GetSEMan(); if (sEMan == null) { return false; } if (!sEMan.HaveStatusEffect(SEMan.s_statusEffectRested) && !sEMan.HaveStatusEffect(SEMan.s_statusEffectResting)) { return false; } comfort = p.GetComfortLevel(); if (comfort <= 0) { comfort = SE_Rested.CalculateComfortLevel(p); } if (comfort <= 0) { comfort = 1; } return true; } private void HandleDrinkKey(Player p) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!Cfg.DrinkFromWaterEnabled.Value) { return; } KeyboardShortcut value = Cfg.DrinkFromWaterKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && CanUseKeys(p) && !(Time.time - _lastSip < Cfg.DrinkFromWaterCooldown.Value)) { if (!WaterSkin.InWater(p)) { ((Character)p).Message((MessageType)2, "Stand in water to drink", 0, (Sprite)null, false); return; } _lastSip = Time.time; Needs.Thirst += Cfg.DrinkFromWaterAmount.Value; Needs.Clamp(); Needs.Save(p); WaterSkin.PlayDrinkEffects(p); ((Character)p).Message((MessageType)1, "You drink from the water", 0, Icons.Thirst, false); } } private static bool CanUseKeys(Player p) { if (((Character)p).IsDead() || ((Character)p).InPlaceMode()) { return false; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return false; } if (Console.IsVisible() || TextInput.IsVisible() || Menu.IsVisible() || InventoryGui.IsVisible() || Minimap.IsOpen() || StoreGui.IsVisible()) { return false; } IInputSystem current = UnityInput.Current; if (current.GetKey((KeyCode)306) || current.GetKey((KeyCode)305) || current.GetKey((KeyCode)308) || current.GetKey((KeyCode)307)) { return false; } return true; } public void OnPlayerDied(Player p) { if (Cfg.ResetOnDeath.Value) { Needs.SetAll(100f); Needs.Save(p); Needs.ResetPending = true; } } } public class NeedsHud : MonoBehaviour { private class Row { public RectTransform Fill; public Image FillImage; public Image Glow; public Image Track; public RectTransform Icon; public TMP_Text Text; public Color Color; public float Shown = -1f; } private const float Pad = 8f; private const float RowH = 18f; private const float Gap = 5f; private const float IconSize = 18f; private const float BarW = 118f; private const float BarH = 8f; private const float TextW = 36f; private const float Margin = 14f; private static readonly Color HungerColor = new Color(1f, 0.58f, 0.16f, 1f); private static readonly Color ThirstColor = new Color(0.25f, 0.64f, 1f, 1f); private static readonly Color EnergyColor = new Color(1f, 0.84f, 0.2f, 1f); private static readonly Color LowColor = new Color(1f, 0.22f, 0.18f, 1f); private static readonly Color BackColor = new Color(0.04f, 0.045f, 0.055f, 0.62f); private static readonly Color TrackColor = new Color(0f, 0f, 0f, 0.55f); private Hud _hud; private RectTransform _root; private RectTransform _panel; private Image _panelImage; private readonly List<Row> _rows = new List<Row>(); private float _layoutTimer; private bool _lastPercent = true; public static NeedsHud Create(Hud hud) { //IL_0018: 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_0034: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SurvivalNeedsHud", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(hud.m_rootObject.transform, false); val.layer = hud.m_rootObject.layer; NeedsHud needsHud = val.AddComponent<NeedsHud>(); needsHud.Build(hud); return needsHud; } private void Build(Hud hud) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0028: 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_0052: 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_0088: 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_00a8: 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_010a: 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_0170: 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) _hud = hud; _root = (RectTransform)((Component)this).transform; _root.anchorMin = new Vector2(0.5f, 0.5f); _root.anchorMax = new Vector2(0.5f, 0.5f); _root.pivot = Vector2.zero; _root.sizeDelta = Vector2.zero; _panel = NewRect("Panel", (Transform)(object)_root); _panel.anchorMin = Vector2.zero; _panel.anchorMax = Vector2.zero; _panel.pivot = Vector2.zero; _panel.anchoredPosition = Vector2.zero; _panelImage = ((Component)_panel).gameObject.AddComponent<Image>(); _panelImage.sprite = Icons.Rounded; _panelImage.type = (Type)1; _panelImage.pixelsPerUnitMultiplier = 1.6f; ((Graphic)_panelImage).color = BackColor; ((Graphic)_panelImage).raycastTarget = false; TMP_FontAsset font = (((Object)(object)hud.m_healthText != (Object)null) ? hud.m_healthText.font : null); _rows.Add(MakeRow("Energy", Icons.Energy, EnergyColor, 0, font)); _rows.Add(MakeRow("Thirst", Icons.Thirst, ThirstColor, 1, font)); _rows.Add(MakeRow("Hunger", Icons.Hunger, HungerColor, 2, font)); ApplySize(); Layout(); } private static RectTransform NewRect(string name, Transform parent) { //IL_0014: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); val.layer = ((Component)parent).gameObject.layer; return (RectTransform)val.transform; } private Row MakeRow(string name, Sprite icon, Color color, int index, TMP_FontAsset font) { //IL_0006: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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) //IL_011f: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: 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_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_0314: 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_035a: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) Row obj = new Row { Color = color }; RectTransform val = NewRect(name, (Transform)(object)_panel); val.anchorMin = Vector2.zero; val.anchorMax = Vector2.zero; val.pivot = Vector2.zero; val.anchoredPosition = new Vector2(8f, 8f + (float)index * 23f); val.sizeDelta = new Vector2(184f, 18f); RectTransform val2 = NewRect("Icon", (Transform)(object)val); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0f, 0.5f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0.5f, 0.5f); val2.anchoredPosition = new Vector2(9f, 0f); val2.sizeDelta = new Vector2(18f, 18f); Image obj2 = ((Component)val2).gameObject.AddComponent<Image>(); obj2.sprite = icon; obj2.preserveAspect = true; ((Graphic)obj2).raycastTarget = false; obj.Icon = val2; RectTransform val4 = NewRect("Track", (Transform)(object)val); ((Vector2)(ref val3))..ctor(0f, 0.5f); val4.anchorMax = val3; val4.anchorMin = val3; val4.pivot = new Vector2(0f, 0.5f); val4.anchoredPosition = new Vector2(24f, 0f); val4.sizeDelta = new Vector2(118f, 8f); obj.Track = ((Component)val4).gameObject.AddComponent<Image>(); obj.Track.sprite = Icons.Rounded; obj.Track.type = (Type)1; obj.Track.pixelsPerUnitMultiplier = 3.75f; ((Graphic)obj.Track).color = TrackColor; ((Graphic)obj.Track).raycastTarget = false; RectTransform val5 = NewRect("Glow", (Transform)(object)val4); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val5.offsetMin = new Vector2(-3f, -3f); val5.offsetMax = new Vector2(3f, 3f); obj.Glow = ((Component)val5).gameObject.AddComponent<Image>(); obj.Glow.sprite = Icons.Rounded; obj.Glow.type = (Type)1; obj.Glow.pixelsPerUnitMultiplier = 2.142857f; ((Graphic)obj.Glow).color = new Color(LowColor.r, LowColor.g, LowColor.b, 0f); ((Graphic)obj.Glow).raycastTarget = false; ((Transform)val5).SetAsFirstSibling(); RectTransform val6 = NewRect("Fill", (Transform)(object)val4); val6.anchorMin = Vector2.zero; val6.anchorMax = Vector2.one; val6.offsetMin = Vector2.zero; val6.offsetMax = Vector2.zero; obj.FillImage = ((Component)val6).gameObject.AddComponent<Image>(); obj.FillImage.sprite = Icons.Rounded; obj.FillImage.type = (Type)1; obj.FillImage.pixelsPerUnitMultiplier = 3.75f; ((Graphic)obj.FillImage).color = color; ((Graphic)obj.FillImage).raycastTarget = false; obj.Fill = val6; RectTransform obj3 = NewRect("Shine", (Transform)(object)val6); obj3.anchorMin = new Vector2(0f, 0.55f); obj3.anchorMax = new Vector2(1f, 1f); obj3.offsetMin = new Vector2(2f, 0f); obj3.offsetMax = new Vector2(-2f, -1f); Image obj4 = ((Component)obj3).gameObject.AddComponent<Image>(); obj4.sprite = Icons.Rounded; obj4.type = (Type)1; obj4.pixelsPerUnitMultiplier = 10f; ((Graphic)obj4).color = new Color(1f, 1f, 1f, 0.22f); ((Graphic)obj4).raycastTarget = false; RectTransform obj5 = NewRect("Text", (Transform)(object)val); ((Vector2)(ref val3))..ctor(0f, 0.5f); obj5.anchorMax = val3; obj5.anchorMin = val3; obj5.pivot = new Vector2(0f, 0.5f); obj5.anchoredPosition = new Vector2(148f, 0f); obj5.sizeDelta = new Vector2(36f, 18f); TextMeshProUGUI val7 = ((Component)obj5).gameObject.AddComponent<TextMeshProUGUI>(); if ((Object)(object)font != (Object)null) { ((TMP_Text)val7).font = font; } ((TMP_Text)val7).fontSize = 13f; ((TMP_Text)val7).alignment = (TextAlignmentOptions)4097; ((TMP_Text)val7).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)val7).overflowMode = (TextOverflowModes)0; ((Graphic)val7).color = new Color(1f, 1f, 1f, 0.9f); ((Graphic)val7).raycastTarget = false; ((TMP_Text)val7).text = "100%"; obj.Text = (TMP_Text)(object)val7; return obj; } private void ApplySize() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) bool flag = (_lastPercent = Cfg.ShowPercentages.Value); float num = 150f + (flag ? 42f : 0f) + 8f; float num2 = 80f; _panel.sizeDelta = new Vector2(num, num2); foreach (Row row in _rows) { ((Component)row.Text).gameObject.SetActive(flag); } } private void Update() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; bool flag = Cfg.HudEnabled.Value && (Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead(); if (((Component)_panel).gameObject.activeSelf != flag) { ((Component)_panel).gameObject.SetActive(flag); } if (flag) { if (_lastPercent != Cfg.ShowPercentages.Value) { ApplySize(); } float value = Cfg.HudScale.Value; ((Transform)_root).localScale = new Vector3(value, value, 1f); _layoutTimer -= Time.unscaledDeltaTime; if (_layoutTimer <= 0f) { _layoutTimer = 0.5f; Layout(); } float unscaledDeltaTime = Time.unscaledDeltaTime; UpdateRow(_rows[0], Needs.Energy, unscaledDeltaTime); UpdateRow(_rows[1], Needs.Thirst, unscaledDeltaTime); UpdateRow(_rows[2], Needs.Hunger, unscaledDeltaTime); } } private void UpdateRow(Row row, float value, float dt) { //IL_0093: 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_01e8: 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_0208: 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_00fa: 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_0149: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: 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_027d: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(value / 100f); if (row.Shown < 0f) { row.Shown = num; } row.Shown = Mathf.Lerp(row.Shown, num, 1f - Mathf.Exp(-6f * dt)); if (Mathf.Abs(row.Shown - num) < 0.0005f) { row.Shown = num; } float num2 = 0.06779661f; float num3 = ((row.Shown <= 0.001f) ? 0f : Mathf.Max(row.Shown, num2)); row.Fill.anchorMax = new Vector2(num3, 1f); ((Behaviour)row.FillImage).enabled = num3 > 0f; bool flag = value / 100f * 100f < Cfg.LowWarningPercent.Value; if (flag) { float num4 = 0.5f + 0.5f * Mathf.Sin(Time.unscaledTime * 6f); ((Graphic)row.FillImage).color = Color.Lerp(row.Color, LowColor, 0.25f + 0.5f * num4); ((Graphic)row.Glow).color = new Color(LowColor.r, LowColor.g, LowColor.b, 0.15f + 0.4f * num4); float num5 = 1f + 0.14f * num4; ((Transform)row.Icon).localScale = new Vector3(num5, num5, 1f); ((Graphic)row.Track).color = Color.Lerp(TrackColor, new Color(0.35f, 0.02f, 0.02f, 0.7f), num4); } else { ((Graphic)row.FillImage).color = row.Color; ((Graphic)row.Glow).color = new Color(LowColor.r, LowColor.g, LowColor.b, 0f); ((Transform)row.Icon).localScale = Vector3.one; ((Graphic)row.Track).color = TrackColor; } if (((Component)row.Text).gameObject.activeSelf) { string text = Mathf.RoundToInt(value) + "%"; if (row.Text.text != text) { row.Text.text = text; } ((Graphic)row.Text).color = (Color)(flag ? Color.Lerp(Color.white, LowColor, 0.6f) : new Color(1f, 1f, 1f, 0.9f)); } } private bool LocalBounds(RectTransform t, out Rect rect) { //IL_0001: 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_006c: 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_0071: 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_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) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) //IL_00a9: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) rect = default(Rect); if ((Object)(object)t == (Object)null || !((Component)t).gameObject.activeInHierarchy) { return false; } Vector3[] array = (Vector3[])(object)new Vector3[4]; t.GetWorldCorners(array); Transform parent = ((Transform)_root).parent; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(float.MaxValue, float.MaxValue); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(float.MinValue, float.MinValue); Vector3[] array2 = array; foreach (Vector3 val3 in array2) { Vector3 val4 = parent.InverseTransformPoint(val3); val = Vector2.Min(val, Vector2.op_Implicit(val4)); val2 = Vector2.Max(val2, Vector2.op_Implicit(val4)); } rect = Rect.MinMaxRect(val.x, val.y, val2.x, val2.y); if (((Rect)(ref rect)).width > 1f) { return ((Rect)(ref rect)).height > 1f; } return false; } private void Layout() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_0103: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: 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_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: 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_022e: Unknown result type (might be due to invalid IL or missing references) //IL_023a: 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_0108: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_hud == (Object)null) { return; } Transform parent = ((Transform)_root).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); float num; if (!((Object)(object)val != (Object)null)) { num = 1920f; } else { Rect rect = val.rect; num = ((Rect)(ref rect)).width; } float num2 = num; bool flag = false; Rect val2 = default(Rect); RectTransform[] array = (RectTransform[])(object)new RectTransform[3] { _hud.m_healthPanel, _hud.m_foodBarRoot, _hud.m_gpRoot }; foreach (RectTransform t in array) { if (LocalBounds(t, out var rect2) && (!((Object)(object)val != (Object)null) || !(((Rect)(ref rect2)).width > num2 * 0.45f))) { val2 = (flag ? Rect.MinMaxRect(Mathf.Min(((Rect)(ref val2)).xMin, ((Rect)(ref rect2)).xMin), Mathf.Min(((Rect)(ref val2)).yMin, ((Rect)(ref rect2)).yMin), Mathf.Max(((Rect)(ref val2)).xMax, ((Rect)(ref rect2)).xMax), Mathf.Max(((Rect)(ref val2)).yMax, ((Rect)(ref rect2)).yMax)) : rect2); flag = true; } } float value = Cfg.HudScale.Value; Vector2 val3 = _panel.sizeDelta * value; Vector2 val5 = default(Vector2); if (!flag) { Rect val4 = (Rect)(((Object)(object)val != (Object)null) ? val.rect : new Rect(-960f, -540f, 1920f, 1080f)); ((Vector2)(ref val5))..ctor(((Rect)(ref val4)).xMin + 320f, ((Rect)(ref val4)).yMin + 30f); } else { Vector2 val6 = default(Vector2); ((Vector2)(ref val6))..ctor(((Rect)(ref val2)).xMax + 14f, ((Rect)(ref val2)).yMin); Vector2 val7 = default(Vector2); ((Vector2)(ref val7))..ctor(((Rect)(ref val2)).xMin, ((Rect)(ref val2)).yMax + 14f); val5 = (Vector2)(Cfg.Placement.Value switch { Cfg.HudPlacement.AboveHealth => val7, Cfg.HudPlacement.RightOfHealth => val6, _ => Blocked(new Rect(val6, val3)) ? val7 : val6, }); } val5 += new Vector2(Cfg.HudOffsetX.Value, Cfg.HudOffsetY.Value); ((Transform)_root).localPosition = new Vector3(val5.x, val5.y, 0f); } private bool Blocked(Rect candidate) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) RectTransform[] array = (RectTransform[])(object)new RectTransform[2] { _hud.m_staminaBar2Root, (RectTransform)(((Object)(object)_hud.m_actionBarRoot != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null) }; foreach (RectTransform t in array) { if (LocalBounds(t, out var rect) && ((Rect)(ref rect)).Overlaps(candidate)) { return true; } } Transform parent = ((Transform)_root).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val != (Object)null) { float xMax = ((Rect)(ref candidate)).xMax; Rect rect2 = val.rect; if (xMax > ((Rect)(ref rect2)).center.x - 160f) { return true; } } return false; } } [HarmonyPatch(typeof(Player), "EatFood")] internal static class EatFoodPatch { private static void Postfix(Player __instance, ItemData item, bool __result) { if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Needs.OnAte(__instance, item); } } } [HarmonyPatch(typeof(Player), "ConsumeItem")] internal static class ConsumeItemPatch { private static void Postfix(Player __instance, ItemData item, bool __result) { if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Needs.OnDrank(__instance, item); } } } [HarmonyPatch(typeof(Humanoid), "UseItem")] internal static class UseItemPatch { private static bool Prefix(Humanoid __instance, ItemData item) { if (item == null || !WaterSkin.Is(item)) { return true; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } WaterSkin.Use(val, item); return false; } } [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] internal static class UpdateStatsPatch { private static readonly FieldRef<Player, float> Stamina = AccessTools.FieldRefAccess<Player, float>("m_stamina"); private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Needs.Exhausted) { Stamina.Invoke(__instance) = 0f; } } } [HarmonyPatch(typeof(Player), "CheckRun")] internal static class CheckRunPatch { private static void Postfix(Player __instance, ref bool __result) { if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && Needs.Exhausted) { __result = false; } } } [HarmonyPatch(typeof(Player), "SetSleeping")] internal static class SetSleepingPatch { private static void Prefix(Player __instance, bool sleep) { if (!sleep && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __instance.IsSleeping() && Cfg.SleepFullRestore.Value) { Needs.Energy = 100f; Needs.Save(__instance); ((Character)__instance).Message((MessageType)1, "You wake up fully rested", 0, Icons.Energy, false); } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class OnDeathPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)NeedsController.Instance == (Object)null)) { NeedsController.Instance.OnPlayerDied(__instance); } } } [HarmonyPatch(typeof(Player), "Save")] internal static class SavePatch { private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Needs.Save(__instance); } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] internal static class TooltipPatch { private static void Postfix(ItemData item, ref string __result) { if (item == null || item.m_shared == null) { return; } try { StringBuilder stringBuilder = new StringBuilder(__result ?? ""); if (WaterSkin.Is(item)) { int charges = WaterSkin.GetCharges(item); stringBuilder.Append("\n\n<color=#6fbaff>Charges: <b>").Append(charges).Append("/") .Append(WaterSkin.MaxCharges) .Append("</b></color>"); stringBuilder.Append("\n<color=#6fbaff>+").Append(Cfg.WaterSkinThirstPerCharge.Value.ToString("0")).Append("% thirst per drink</color>"); stringBuilder.Append("\n<color=#a0a0a0>Refills in water, or use it near water.</color>"); } else { if (Needs.IsFood(item)) { int num = Cfg.TierFor(item.m_shared.m_food); stringBuilder.Append("\n\n<color=#ff9c3a>Hunger tier <b>T").Append(num).Append("</b>: +") .Append(Cfg.FillFor(num).ToString("0")) .Append("% hunger</color>"); float num2 = Cfg.EnergyFor(item.m_shared.m_foodStamina); if (num2 > 0f) { stringBuilder.Append("\n<color=#ffd84a>+").Append(num2.ToString("0.#")).Append("% energy</color>"); } } if (Cfg.DrinksFillThirst.Value && Needs.IsDrink(item)) { stringBuilder.Append(Needs.IsFood(item) ? "\n" : "\n\n").Append("<color=#6fbaff>+").Append(Cfg.DrinkThirstFill.Value.ToString("0")) .Append("% thirst</color>"); } } __result = stringBuilder.ToString(); } catch (Exception ex) { Plugin.Warn("Tooltip patch: " + ex.Message); } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGridPatch { private static readonly FieldInfo InvField = AccessTools.Field(typeof(InventoryGrid), "m_inventory"); private static readonly MethodInfo GetElement = AccessTools.Method(typeof(InventoryGrid), "GetElement", (Type[])null, (Type[])null); private static void Postfix(InventoryGrid __instance) { try { Inventory val = (Inventory)((InvField != null) ? /*isinst with value type is only supported in some contexts*/: null); if (val == null || GetElement == null) { return; } int width = val.GetWidth(); foreach (ItemData allItem in val.GetAllItems()) { if (WaterSkin.Is(allItem)) { object? obj = GetElement.Invoke(__instance, new object[3] { allItem.m_gridPos.x, allItem.m_gridPos.y, width }); InventoryElement val2 = (InventoryElement)((obj is InventoryElement) ? obj : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_amount == (Object)null)) { ChargeText.Apply(val2.m_amount, allItem); } } } } catch (Exception ex) { Plugin.Warn("Inventory overlay: " + ex.Message); } } } [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] internal static class HotkeyBarPatch { private static readonly FieldInfo Elements = AccessTools.Field(typeof(HotkeyBar), "m_elements"); private static readonly FieldInfo Items = AccessTools.Field(typeof(HotkeyBar), "m_items"); private static FieldInfo _amount; private static void Postfix(HotkeyBar __instance) { try { IList list = ((Elements != null) ? (Elements.GetValue(__instance) as IList) : null); IList list2 = ((Items != null) ? (Items.GetValue(__instance) as IList) : null); if (list == null || list2 == null) { return; } foreach (object item in list2) { ItemData val = (ItemData)((item is ItemData) ? item : null); if (val == null || !WaterSkin.Is(val)) { continue; } int x = val.m_gridPos.x; if (x < 0 || x >= list.Count) { continue; } object obj = list[x]; if (obj != null) { if (_amount == null) { _amount = AccessTools.Field(obj.GetType(), "m_amount"); } TMP_Text val2 = (TMP_Text)((_amount != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val2 != (Object)null) { ChargeText.Apply(val2, val); } } } } catch (Exception ex) { Plugin.Warn("Hotbar overlay: " + ex.Message); } } } internal static class ChargeText { public static void Apply(TMP_Text txt, ItemData item) { int charges = WaterSkin.GetCharges(item); if (!((Component)txt).gameObject.activeSelf) { ((Component)txt).gameObject.SetActive(true); } txt.text = ((charges > 0) ? ("<color=#8fd0ff>" + charges + "/" + WaterSkin.MaxCharges + "</color>") : ("<color=#ff7a6a>0/" + WaterSkin.MaxCharges + "</color>")); } } [BepInPlugin("com.survivalneeds.valheim", "SurvivalNeeds", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "com.survivalneeds.valheim"; public const string ModName = "SurvivalNeeds"; public const string Version = "1.0.1"; public static Plugin Instance; private Harmony _harmony; private void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown Instance = this; Cfg.Bind(((BaseUnityPlugin)this).Config); Icons.Load(); NeedEffects.Register(); WaterSkin.Register(); Commands.Register(); _harmony = new Harmony("com.survivalneeds.valheim"); _harmony.PatchAll(typeof(Plugin).Assembly); ((Component)this).gameObject.AddComponent<NeedsController>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SurvivalNeeds 1.0.1 loaded"); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } public static void Log(string msg) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg); } } public static void Warn(string msg) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg); } } } public static class WaterSkin { public const string PrefabName = "SurvivalNeeds_WaterSkin"; public const string DisplayName = "Waterskin"; public const string BasePrefab = "MeadTasty"; private const string ChargesKey = "SurvivalNeeds.Charges"; private static CustomItem _item; private static readonly FieldRef<Character, ZSyncAnimation> ZAnim = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim"); public static int MaxCharges => Mathf.Max(1, Cfg.WaterSkinCharges.Value); public static void Register() { PrefabManager.OnVanillaPrefabsAvailable += AddItem; ItemManager.OnItemsRegistered += ApplyRecipe; SynchronizationManager.OnConfigurationSynchronized += delegate { ApplyRecipe(); }; Cfg.WaterSkinRecipe.SettingChanged += delegate { ApplyRecipe(); }; Cfg.WaterSkinStation.SettingChanged += delegate { ApplyRecipe(); }; Cfg.WaterSkinStationLevel.SettingChanged += delegate { ApplyRecipe(); }; } private static void AddItem() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= AddItem; ItemConfig val = new ItemConfig(); val.Name = "Waterskin"; val.Description = "A stitched leather pouch with a cork stopper. Holds a few good swallows of water. Refill it by wading into water or using it near water."; val.CraftingStation = Cfg.WaterSkinStation.Value ?? ""; val.MinStationLevel = Cfg.WaterSkinStationLevel.Value; val.Requirements = ParseRequirements(Cfg.WaterSkinRecipe.Value); val.Icons = (Sprite[])(object)((!((Object)(object)Icons.WaterSkin != (Object)null)) ? null : new Sprite[1] { Icons.WaterSkin }); ItemConfig val2 = val; _item = new CustomItem("SurvivalNeeds_WaterSkin", "MeadTasty", val2); ItemDrop itemDrop = _item.ItemDrop; if ((Object)(object)itemDrop != (Object)null) { SharedData shared = itemDrop.m_itemData.m_shared; shared.m_name = "Waterskin"; shared.m_description = val2.Description; shared.m_itemType = (ItemType)16; shared.m_maxStackSize = 1; shared.m_weight = 1f; shared.m_value = 0; shared.m_teleportable = true; shared.m_consumeStatusEffect = null; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_foodRegen = 0f; shared.m_foodBurnTime = 0f; shared.m_isDrink = false; if ((Object)(object)Icons.WaterSkin != (Object)null) { shared.m_icons = (Sprite[])(object)new Sprite[1] { Icons.WaterSkin }; } } ItemManager.Instance.AddItem(_item); } private static RequirementConfig[] ParseRequirements(string text) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); string[] array = (text ?? "").Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length == 2 && int.TryParse(array2[1].Trim(), out var result) && result > 0) { list.Add(new RequirementConfig(array2[0].Trim(), result, 0, true)); } } if (list.Count == 0) { list.Add(new RequirementConfig("LeatherScraps", 4, 0, true)); list.Add(new RequirementConfig("DeerHide", 2, 0, true)); } return list.ToArray(); } public static void ApplyRecipe() { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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_0126: Expected O, but got Unknown ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_recipes == null) { return; } Recipe val = null; foreach (Recipe recipe in instance.m_recipes) { if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && ((Object)recipe.m_item).name == "SurvivalNeeds_WaterSkin") { val = recipe; break; } } if ((Object)(object)val == (Object)null) { return; } List<Requirement> list = new List<Requirement>(); RequirementConfig[] array = ParseRequirements(Cfg.WaterSkinRecipe.Value); foreach (RequirementConfig val2 in array) { GameObject itemPrefab = instance.GetItemPrefab(val2.Item); ItemDrop val3 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val3 == (Object)null) { Plugin.Warn("Unknown waterskin recipe item " + val2.Item); continue; } list.Add(new Requirement { m_resItem = val3, m_amount = val2.Amount, m_amountPerLevel = 0, m_recover = true }); } if (list.Count > 0) { val.m_resources = list.ToArray(); } val.m_minStationLevel = Cfg.WaterSkinStationLevel.Value; string value = Cfg.WaterSkinStation.Value; if (string.IsNullOrEmpty(value)) { val.m_craftingStation = null; return; } GameObject val4 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(value) : null); CraftingStation val5 = (((Object)(object)val4 != (Object)null) ? val4.GetComponent<CraftingStation>() : null); if ((Object)(object)val5 != (Object)null) { val.m_craftingStation = val5; } } public static bool Is(ItemData item) { if (item == null || item.m_shared == null) { return false; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name == "SurvivalNeeds_WaterSkin"; } if (item.m_shared.m_name == "Waterskin" && item.m_shared.m_maxStackSize == 1) { return item.m_shared.m_food <= 0f; } return false; } public static int GetCharges(ItemData item) { if (item.m_customData != null && item.m_customData.TryGetValue("SurvivalNeeds.Charges", out var value) && int.TryParse(value, out var result)) { return Mathf.Clamp(result, 0, MaxCharges); } return MaxCharges; } public static void SetCharges(ItemData item, int v) { if (item.m_customData == null) { item.m_customData = new Dictionary<string, string>(); } item.m_customData["SurvivalNeeds.Charges"] = Mathf.Clamp(v, 0, MaxCharges).ToString(); } public static void Use(Player p, ItemData item) { int charges = GetCharges(item); if (charges < MaxCharges && Cfg.RefillOnUseNearWater.Value && NearWater(p, Cfg.RefillDistance.Value)) { SetCharges(item, MaxCharges); ((Character)p).Message((MessageType)2, "Waterskin refilled", 0, Icons.WaterSkin, false); return; } if (charges <= 0) { ((Character)p).Message((MessageType)2, "Empty, refill at water", 0, Icons.WaterSkin, false); return; } if (Needs.Thirst >= 99.5f) { ((Character)p).Message((MessageType)2, "You are not thirsty", 0, (Sprite)null, false); return; } SetCharges(item, charges - 1); Needs.Thirst += Cfg.WaterSkinThirstPerCharge.Value; Needs.Clamp(); Needs.Save(p); PlayDrinkEffects(p); ((Character)p).Message((MessageType)1, "Drank from waterskin (" + (charges - 1) + "/" + MaxCharges + ")", 0, Icons.Thirst, false); } public static void RefillAll(Player p, bool message) { Inventory inventory = ((Humanoid)p).GetInventory(); if (inventory == null) { return; } bool flag = false; foreach (ItemData allItem in inventory.GetAllItems()) { if (Is(allItem) && GetCharges(allItem) < MaxCharges) { SetCharges(allItem, MaxCharges); flag = true; } } if (flag && message) { ((Character)p).Message((MessageType)2, "Waterskin refilled", 0, Icons.WaterSkin, false); } } public static void PlayDrinkEffects(Player p) { //IL_0035: 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_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) try { ZSyncAnimation val = ZAnim.Invoke((Character)(object)p); if ((Object)(object)val != (Object)null) { val.SetTrigger("eat"); } if (((Humanoid)p).m_consumeItemEffects != null) { ((Humanoid)p).m_consumeItemEffects.Create(((Component)p).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } catch { } } public static bool InWater(Player p) { if ((Object)(object)p != (Object)null) { if (!((Character)p).InWater()) { return ((Character)p).IsSwimming(); } return true; } return false; } public static bool NearWater(Player p, float distance) { //IL_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0087: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (InWater(p)) { return true; } if (distance <= 0f || (Object)(object)ZoneSystem.instance == (Object)null) { return false; } Vector3 position = ((Component)p).transform.position; if (WaterAt(position, position.y, distance)) { return true; } float[] array = new float[2] { distance * 0.5f, distance }; foreach (float num in array) { for (int j = 0; j < 12; j++) { float num2 = (float)j * MathF.PI * 2f / 12f; if (WaterAt(new Vector3(position.x + Mathf.Cos(num2) * num, position.y, position.z + Mathf.Sin(num2) * num), position.y, distance)) { return true; } } } return false; } private static bool WaterAt(Vector3 pt, float playerY, float distance) { //IL_0000: 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) float liquidLevel = Floating.GetLiquidLevel(pt, 1f, (LiquidType)0); if (liquidLevel < -1000f) { return false; } float groundHeight = ZoneSystem.instance.GetGroundHeight(pt); if (liquidLevel <= groundHeight + 0.15f) { return false; } return Mathf.Abs(liquidLevel - playerY) <= distance + 1.5f; } } }