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 YoureTired v0.2.6
YoureTired.dll
Decompiled a day agousing System; using System.Collections; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace YoureTired; [BepInPlugin("com.marccunningham.yourtired", "You're Tired", "0.3.0")] [BepInProcess("valheim.exe")] public sealed class YoureTiredPlugin : BaseUnityPlugin { private enum HudResizeHandle { None, TopLeft, TopRight, BottomLeft, BottomRight } public const string PluginGuid = "com.marccunningham.yourtired"; public const string PluginName = "You're Tired"; public const string PluginVersion = "0.3.0"; private const float ReferenceScreenWidth = 2048f; private const float ReferenceScreenHeight = 1152f; private const float DefaultStackRightAtReference = 470f; private const float DefaultStackTopAtReference = 982f; private const float DefaultStackBottomAtReference = 1111f; private const float PreviousGapAtReference = 12f; private const float DefaultGapAtReference = 26f; private const float DefaultMeterWidthAtReference = 30f; private const float DefaultFrameThicknessAtReference = 2f; private const float MinimumTickInterval = 0.1f; private const float MaximumElapsedMultiplier = 3f; private const float MinimumRestingSpeed = 0.25f; private const float ActionActivityWindowSeconds = 0.8f; private const float CombatActivityWindowSeconds = 1.4f; private const float ZdoMissingEnergy = -1f; private const string ZdoEnergy = "YoureTired_Energy"; internal static YoureTiredPlugin Instance; private ConfigEntry<bool> modEnabled; private ConfigEntry<KeyCode> diagnosticKey; private ConfigEntry<KeyCode> sessionToggleKey; private ConfigEntry<float> tickInterval; private ConfigEntry<float> startingEnergy; private ConfigEntry<float> saveInterval; private ConfigEntry<bool> verboseLogging; private ConfigEntry<string> difficultyPreset; private ConfigEntry<string> lastAppliedDifficultyPreset; private ConfigEntry<float> minimumStaminaRegenMultiplier; private ConfigEntry<bool> showHud; private ConfigEntry<bool> hideHudWithCtrlF3; private ConfigEntry<float> stackRightAtReference; private ConfigEntry<float> stackTopAtReference; private ConfigEntry<float> stackBottomAtReference; private ConfigEntry<float> gapAtReference; private ConfigEntry<float> meterWidthAtReference; private ConfigEntry<float> frameThicknessAtReference; private ConfigEntry<KeyCode> hudLayoutEditorKey; private ConfigEntry<bool> enableYawnAudio; private ConfigEntry<float> yawnEnergyThreshold; private ConfigEntry<float> yawnRearmMargin; private ConfigEntry<float> yawnRepeatAtThresholdSeconds; private ConfigEntry<float> yawnRepeatAtZeroSeconds; private ConfigEntry<float> yawnRepeatRandomnessSeconds; private ConfigEntry<float> yawnAudioVolume; private ConfigEntry<string> yawnAudioFile; private ConfigEntry<float> awakeDrainPerSecond; private ConfigEntry<float> sprintDrainPerSecond; private ConfigEntry<float> swimmingDrainPerSecond; private ConfigEntry<float> actionDrainPerSecond; private ConfigEntry<float> coldDrainPerSecond; private ConfigEntry<float> freezingExtraDrainPerSecond; private ConfigEntry<float> lowFoodDrainPerSecond; private ConfigEntry<float> injuryDrainAtMaximumPerSecond; private ConfigEntry<float> shelterRestRecoveryPerSecond; private ConfigEntry<float> warmRecoveryPerSecond; private ConfigEntry<float> foodRecoveryPerSecond; private ConfigEntry<float> sleepingRecoveryPerSecond; private ConfigEntry<bool> enableTestKeys; private ConfigEntry<KeyCode> testDrainKey; private ConfigEntry<KeyCode> testRestoreKey; private Harmony harmony; private bool runtimeEnabled = true; private bool stateLoaded; private float energy; private float tickTimer; private float saveTimer; private float actionActivityRemaining; private float combatActivityRemaining; private FatigueSnapshot lastSnapshot; private float lastEnergyDeltaPerSecond; private bool hasSnapshot; private bool staminaRegenPatchInstalled; private bool runDrainPatchInstalled; private bool attackCostPatchInstalled; private bool jogSpeedPatchInstalled; private bool runSpeedPatchInstalled; private FieldInfo foodListField; private FieldInfo currentAttackField; private MethodInfo healthPercentageMethod; private Type injuryPluginType; private FieldInfo injuryPluginInstanceField; private MethodInfo injuryIsActiveForMethod; private MethodInfo injuryRunSpeedMultiplierMethod; private bool injuryReflectionResolved; private bool injuryReflectionUsable; private Texture2D pixelTexture; private GUIStyle headerStyle; private GUIStyle valueStyle; private GUIStyle stateStyle; private bool guiFailureLogged; private bool hudLayoutEditorActive; private bool hudLayoutDragging; private HudResizeHandle hudResizeHandle; private Vector2 hudEditStartMouse; private Rect hudEditStartRect; private CursorLockMode hudPreviousCursorLockMode; private bool hudPreviousCursorVisible; private bool hudCursorStateCaptured; private bool hudHiddenByCtrlF3; private string pluginDirectory; private Component yawnAudioSource; private object yawnAudioClip; private float lastYawnAudioTime = -99999f; private float nextYawnAudioTime; private void Awake() { Instance = this; pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired 0.3.0 loading."); BindConfig(); MigrateLegacyDefaultsToNormal(); ApplyDifficultyPresetIfChanged(); ((MonoBehaviour)this).StartCoroutine(LoadYawnAudio()); MigrateHudSpacingFromPrototype(); ResolveVanillaReflection(); CreatePixelTexture(); if (!FatigueRules.RunSelfTests(out var failure)) { ((BaseUnityPlugin)this).Logger.LogError((object)("You're Tired rule self-test failed: " + failure)); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired rule self-test passed."); } InstallPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired 0.3.0 loaded. F4 writes diagnostics; F1 safely toggles the system for this session. Yawns now repeat gently at low Energy, becoming more frequent only near exhaustion. HUD spacing moved right to " + 26f.ToString("0") + " px at 2048x1152.")); } private void OnDestroy() { RestoreHudCursor(); TrySaveCurrentPlayer(); if (harmony != null) { harmony.UnpatchSelf(); } DestroyYawnAudio(); if ((Object)(object)pixelTexture != (Object)null) { Object.Destroy((Object)(object)pixelTexture); pixelTexture = null; } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { //IL_0032: 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_0077: 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_01ca: Unknown result type (might be due to invalid IL or missing references) if (TryToggleHudWithCtrlF3()) { return; } if (hudLayoutEditorActive && (!showHud.Value || IsHudHiddenByCtrlF3())) { CloseHudLayoutEditorForHiddenHud(); } if (Input.GetKeyDown(hudLayoutEditorKey.Value) && showHud.Value && !IsHudHiddenByCtrlF3()) { ToggleHudLayoutEditor(); } if (Input.GetKeyDown(diagnosticKey.Value)) { WriteDiagnostic(); } if (Input.GetKeyDown(sessionToggleKey.Value)) { runtimeEnabled = !runtimeEnabled; ShowMessage("You're Tired: " + (runtimeEnabled ? "ON" : "OFF")); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired session toggle: " + (runtimeEnabled ? "ON" : "OFF") + ".")); } if (!runtimeEnabled || !modEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { return; } EnsureStateLoaded(localPlayer); if (stateLoaded) { float deltaTime = Time.deltaTime; actionActivityRemaining = Mathf.Max(0f, actionActivityRemaining - deltaTime); combatActivityRemaining = Mathf.Max(0f, combatActivityRemaining - deltaTime); if (enableTestKeys.Value && Input.GetKeyDown(testDrainKey.Value)) { energy = FatigueRules.ClampEnergy(energy - 10f); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired test drain: Energy=" + energy.ToString("0") + "%.")); } if (enableTestKeys.Value && Input.GetKeyDown(testRestoreKey.Value)) { energy = FatigueRules.ClampEnergy(energy + 10f); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired test recovery: Energy=" + energy.ToString("0") + "%.")); } float num = Mathf.Max(0.1f, tickInterval.Value); tickTimer += deltaTime; saveTimer += deltaTime; if (tickTimer >= num) { float elapsedSeconds = Mathf.Min(tickTimer, num * 3f); tickTimer = 0f; TickEnergy(localPlayer, elapsedSeconds); } if (saveTimer >= Mathf.Max(1f, saveInterval.Value)) { saveTimer = 0f; SaveState(localPlayer); } } } private void TickEnergy(Player player, float elapsedSeconds) { try { FatigueSnapshot snapshot = ReadSnapshot(player); FatigueSettings settings = ReadSettings(); float num = FatigueRules.CalculateEnergyDelta(snapshot, elapsedSeconds, settings); energy = FatigueRules.ClampEnergy(energy + num); lastSnapshot = snapshot; lastEnergyDeltaPerSecond = ((elapsedSeconds > 0f) ? (num / elapsedSeconds) : 0f); hasSnapshot = true; UpdateYawnAudio(); if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Energy=" + energy.ToString("0.0") + ", rate=" + lastEnergyDeltaPerSecond.ToString("0.000") + "/s, " + SnapshotToDiagnosticText(snapshot))); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("You're Tired energy update failed: " + ex)); } } private void UpdateYawnAudio() { if (enableYawnAudio == null || !enableYawnAudio.Value) { return; } float num = Mathf.Clamp(yawnEnergyThreshold.Value, 1f, 99f); float num2 = Mathf.Min(100f, num + Mathf.Clamp(yawnRearmMargin.Value, 1f, 50f)); if (energy >= num2) { lastYawnAudioTime = -99999f; nextYawnAudioTime = 0f; } else if (!(energy > num) && yawnAudioClip != null) { float unscaledTime = Time.unscaledTime; float currentYawnRepeatInterval = GetCurrentYawnRepeatInterval(num); if (lastYawnAudioTime > -1000f) { nextYawnAudioTime = Mathf.Min(nextYawnAudioTime, lastYawnAudioTime + currentYawnRepeatInterval); } if (!(unscaledTime < nextYawnAudioTime) && TryPlayYawnOneShot(yawnAudioClip, Mathf.Clamp01(yawnAudioVolume.Value))) { lastYawnAudioTime = unscaledTime; nextYawnAudioTime = unscaledTime + GetCurrentYawnRepeatInterval(num); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired: yawn played at Energy " + energy.ToString("0") + "%. Next possible yawn in " + (nextYawnAudioTime - unscaledTime).ToString("0") + " seconds.")); } } } private float GetCurrentYawnRepeatInterval(float threshold) { float num = Mathf.Clamp(yawnRepeatAtThresholdSeconds.Value, 45f, 600f); float num2 = Mathf.Clamp(yawnRepeatAtZeroSeconds.Value, 35f, num); float num3 = Mathf.Clamp01((threshold - Mathf.Clamp(energy, 0f, threshold)) / threshold); float num4 = Mathf.Lerp(num, num2, num3); float num5 = Mathf.Min(Mathf.Max(0f, yawnRepeatRandomnessSeconds.Value), num4 * 0.2f); return Mathf.Max(35f, num4 + Random.Range(0f - num5, num5)); } private IEnumerator LoadYawnAudio() { string path = ((yawnAudioFile != null && !string.IsNullOrWhiteSpace(yawnAudioFile.Value)) ? yawnAudioFile.Value.Trim() : "yawn.mp3"); string path2 = Path.Combine(pluginDirectory ?? string.Empty, "assets", "audio", path); yield return ((MonoBehaviour)this).StartCoroutine(LoadExternalMp3(path2, delegate(object clip) { yawnAudioClip = clip; }, "yawn")); } private IEnumerator LoadExternalMp3(string path, Action<object> onLoaded, string label) { object request; object operation; if (string.IsNullOrEmpty(path) || !File.Exists(path)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: " + label + " audio file was not found at " + path)); } else if (TryBeginExternalMp3Request(path, label, out request, out operation)) { yield return operation; CompleteExternalMp3Request(request, onLoaded, label); } } private bool TryBeginExternalMp3Request(string path, string label, out object request, out object operation) { request = null; operation = null; try { Type type = FindAudioRuntimeType("UnityEngine.Networking.UnityWebRequestMultimedia"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: UnityWebRequestMultimedia was unavailable; could not load " + label + " audio.")); return false; } MethodInfo methodInfo = null; MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name == "GetAudioClip" && methodInfo2.GetParameters().Length == 2) { methodInfo = methodInfo2; break; } } if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: no compatible GetAudioClip method was found for " + label + " audio.")); return false; } object obj = Enum.Parse(methodInfo.GetParameters()[1].ParameterType, "MPEG"); request = methodInfo.Invoke(null, new object[2] { new Uri(path).AbsoluteUri, obj }); if (request == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: could not create the request for " + label + " audio.")); return false; } MethodInfo method = request.GetType().GetMethod("SendWebRequest", Type.EmptyTypes); if (method == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: no SendWebRequest method was found for " + label + " audio.")); DisposeAudioRequest(request); request = null; return false; } operation = method.Invoke(request, null); if (operation == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: SendWebRequest returned no operation for " + label + " audio.")); DisposeAudioRequest(request); request = null; return false; } return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: could not start loading " + label + " audio. " + ex.Message)); DisposeAudioRequest(request); request = null; operation = null; return false; } } private void CompleteExternalMp3Request(object request, Action<object> onLoaded, string label) { try { if (request == null) { return; } PropertyInfo property = request.GetType().GetProperty("error", BindingFlags.Instance | BindingFlags.Public); string text = ((property != null) ? (property.GetValue(request, null) as string) : null); if (!string.IsNullOrEmpty(text)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: failed to load " + label + " audio. " + text)); return; } PropertyInfo property2 = request.GetType().GetProperty("downloadHandler", BindingFlags.Instance | BindingFlags.Public); object obj = ((property2 != null) ? property2.GetValue(request, null) : null); PropertyInfo propertyInfo = obj?.GetType().GetProperty("audioClip", BindingFlags.Instance | BindingFlags.Public); object obj2 = ((propertyInfo != null) ? propertyInfo.GetValue(obj, null) : null); if (obj2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: the " + label + " MP3 decoded without an AudioClip.")); return; } onLoaded?.Invoke(obj2); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired: loaded " + label + " audio from " + Path.GetFileName(GetAudioRequestUrl(request)) + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: could not finish loading " + label + " audio. " + ex.Message)); } finally { DisposeAudioRequest(request); } } private bool TryPlayYawnOneShot(object clip, float volume) { if (clip == null) { return false; } Component val = EnsureYawnAudioSource(); if ((Object)(object)val == (Object)null) { return false; } try { MethodInfo[] methods = ((object)val).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "PlayOneShot" && methodInfo.GetParameters().Length == 2) { methodInfo.Invoke(val, new object[2] { clip, volume }); return true; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: failed to play yawn audio. " + ex.Message)); } return false; } private Component EnsureYawnAudioSource() { if ((Object)(object)yawnAudioSource != (Object)null) { return yawnAudioSource; } Type type = FindAudioRuntimeType("UnityEngine.AudioSource"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"You're Tired: Unity AudioSource was unavailable."); return null; } yawnAudioSource = ((Component)this).gameObject.GetComponent(type); if ((Object)(object)yawnAudioSource == (Object)null) { yawnAudioSource = ((Component)this).gameObject.AddComponent(type); } if ((Object)(object)yawnAudioSource != (Object)null) { SetAudioProperty(yawnAudioSource, "playOnAwake", false); SetAudioProperty(yawnAudioSource, "spatialBlend", 0f); SetAudioProperty(yawnAudioSource, "loop", false); } return yawnAudioSource; } private void DestroyYawnAudio() { object obj = yawnAudioClip; Object val = (Object)((obj is Object) ? obj : null); if (val != (Object)null) { Object.Destroy(val); } yawnAudioClip = null; yawnAudioSource = null; } private static void SetAudioProperty(Component source, string name, object value) { if (!((Object)(object)source == (Object)null)) { PropertyInfo property = ((object)source).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(source, value, null); } } } private static Type FindAudioRuntimeType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } private static string GetAudioRequestUrl(object request) { if (request == null) { return string.Empty; } try { PropertyInfo property = request.GetType().GetProperty("url", BindingFlags.Instance | BindingFlags.Public); string text = ((property != null) ? (property.GetValue(request, null) as string) : null); return string.IsNullOrEmpty(text) ? string.Empty : text; } catch { return string.Empty; } } private static void DisposeAudioRequest(object request) { if (request is IDisposable disposable) { disposable.Dispose(); } } private FatigueSnapshot ReadSnapshot(Player player) { //IL_0031: 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_00f0: Unknown result type (might be due to invalid IL or missing references) SEMan sEMan = ((Character)player).GetSEMan(); bool flag = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet); bool flag2 = sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectCampFire); bool flag3 = (Object)(object)EffectArea.IsPointInsideArea(((Component)player).transform.position, (Type)1, 0f) != (Object)null; bool flag4 = player.InShelter(); bool flag5 = ((Character)player).InBed(); bool flag6 = ((Character)player).IsSwimming(); bool isSprinting = ((Character)player).IsRunning() && !flag6; bool flag7 = EnvMan.IsCold(); bool flag8 = EnvMan.IsFreezing(); bool flag9 = IsCurrentAttackActive(player); FatigueSnapshot result = new FatigueSnapshot { IsSleeping = (flag5 && flag4 && !flag), IsSprinting = isSprinting, IsSwimming = flag6, IsActionActive = (actionActivityRemaining > 0f || combatActivityRemaining > 0f || flag9), IsSheltered = flag4 }; Vector3 velocity = ((Character)player).GetVelocity(); result.IsRestingStill = ((Vector3)(ref velocity)).magnitude <= 0.25f; result.IsWarm = flag2 || flag3; result.IsDry = !flag; result.IsCold = flag7 || flag8; result.IsFreezing = flag8; result.FoodCount = GetFoodCount(player); result.InjurySeverity = GetInjurySeverity(player); return result; } private FatigueSettings ReadSettings() { return new FatigueSettings { AwakeDrainPerSecond = Mathf.Max(0f, awakeDrainPerSecond.Value), SprintDrainPerSecond = Mathf.Max(0f, sprintDrainPerSecond.Value), SwimmingDrainPerSecond = Mathf.Max(0f, swimmingDrainPerSecond.Value), ActionDrainPerSecond = Mathf.Max(0f, actionDrainPerSecond.Value), ColdDrainPerSecond = Mathf.Max(0f, coldDrainPerSecond.Value), FreezingExtraDrainPerSecond = Mathf.Max(0f, freezingExtraDrainPerSecond.Value), LowFoodDrainPerSecond = Mathf.Max(0f, lowFoodDrainPerSecond.Value), InjuryDrainAtMaximumPerSecond = Mathf.Max(0f, injuryDrainAtMaximumPerSecond.Value), ShelterRestRecoveryPerSecond = Mathf.Max(0f, shelterRestRecoveryPerSecond.Value), WarmRecoveryPerSecond = Mathf.Max(0f, warmRecoveryPerSecond.Value), FoodRecoveryPerSecond = Mathf.Max(0f, foodRecoveryPerSecond.Value), SleepingRecoveryPerSecond = Mathf.Max(0f, sleepingRecoveryPerSecond.Value) }; } internal bool IsActiveFor(Player player) { if (runtimeEnabled && modEnabled.Value && stateLoaded && (Object)(object)player != (Object)null) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } internal float GetStaminaRegenMultiplier() { return Mathf.Max(FatigueRules.GetEffects(energy).StaminaRegenMultiplier, Mathf.Clamp(minimumStaminaRegenMultiplier.Value, 0.1f, 1f)); } internal float GetRunStaminaMultiplier() { return FatigueRules.GetEffects(energy).SprintStaminaMultiplier; } internal float GetAttackStaminaMultiplier() { return FatigueRules.GetEffects(energy).ToolStaminaMultiplier; } internal float GetMovementMultiplier() { return FatigueRules.GetEffects(energy).MovementMultiplier; } internal void NotifyStaminaUsingAction(Player player) { if (IsActiveFor(player)) { actionActivityRemaining = Mathf.Max(actionActivityRemaining, 0.8f); } } internal void NotifyDamageTaken(Player player) { if (IsActiveFor(player)) { combatActivityRemaining = Mathf.Max(combatActivityRemaining, 1.4f); } } private void EnsureStateLoaded(Player player) { if (!stateLoaded) { ZDO ownedPlayerZdo = GetOwnedPlayerZdo(player); if (ownedPlayerZdo != null) { float num = ownedPlayerZdo.GetFloat("YoureTired_Energy", -1f); energy = ((num < 0f) ? FatigueRules.ClampEnergy(startingEnergy.Value) : FatigueRules.ClampEnergy(num)); stateLoaded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired loaded Energy=" + energy.ToString("0.0") + "%.")); } } } private void SaveState(Player player) { if (stateLoaded && !((Object)(object)player == (Object)null)) { ZDO ownedPlayerZdo = GetOwnedPlayerZdo(player); if (ownedPlayerZdo != null) { ownedPlayerZdo.Set("YoureTired_Energy", FatigueRules.ClampEnergy(energy)); } } } private void TrySaveCurrentPlayer() { try { SaveState(Player.m_localPlayer); } catch { } } private static ZDO GetOwnedPlayerZdo(Player player) { ZNetView component = ((Component)player).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return null; } return component.GetZDO(); } private int GetFoodCount(Player player) { if (foodListField == null || (Object)(object)player == (Object)null) { return 0; } try { return (foodListField.GetValue(player) is ICollection collection) ? collection.Count : 0; } catch { return 0; } } private bool IsCurrentAttackActive(Player player) { if (currentAttackField == null || (Object)(object)player == (Object)null) { return false; } try { return currentAttackField.GetValue(player) != null; } catch { return false; } } private float GetInjurySeverity(Player player) { float num = 0f; if (healthPercentageMethod != null) { try { float num2 = Mathf.Clamp01((float)healthPercentageMethod.Invoke(player, null)); num = (1f - num2) * 35f; } catch { num = 0f; } } ResolveInjuryReflection(); if (!injuryReflectionUsable) { return num; } try { object value = injuryPluginInstanceField.GetValue(null); if (value == null || !(bool)injuryIsActiveForMethod.Invoke(value, new object[1] { player })) { return num; } float num3 = Mathf.Clamp((float)injuryRunSpeedMultiplierMethod.Invoke(value, null), 0.3f, 1f); float num4 = (1f - num3) * 100f; return Mathf.Max(num, num4); } catch { injuryReflectionUsable = false; return num; } } private void ResolveVanillaReflection() { foodListField = FindInstanceField(typeof(Player), "m_foods"); currentAttackField = FindInstanceField(typeof(Player), "m_currentAttack"); healthPercentageMethod = FindInstanceMethod(typeof(Player), "GetHealthPercentage", Type.EmptyTypes); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired reflection: foods=" + (foodListField != null) + ", currentAttack=" + (currentAttackField != null) + ", healthPercent=" + (healthPercentageMethod != null) + ".")); } private void ResolveInjuryReflection() { if (injuryReflectionResolved) { return; } injuryReflectionResolved = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("YoureInjured.YoureInjuredPlugin"); if (type != null) { injuryPluginType = type; break; } } if (!(injuryPluginType == null)) { injuryPluginInstanceField = injuryPluginType.GetField("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); injuryIsActiveForMethod = injuryPluginType.GetMethod("IsActiveFor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Player) }, null); injuryRunSpeedMultiplierMethod = injuryPluginType.GetMethod("GetRunSpeedMultiplier", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); injuryReflectionUsable = injuryPluginInstanceField != null && injuryIsActiveForMethod != null && injuryRunSpeedMultiplierMethod != null; ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired injury compatibility=" + injuryReflectionUsable + ".")); } } private void InstallPatches() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown harmony = new Harmony("com.marccunningham.yourtired"); staminaRegenPatchInstalled = TryPatch(FindInstanceMethod(typeof(SEMan), "ModifyStaminaRegen", null), null, new HarmonyMethod(typeof(YoureTiredPatches), "SEManModifyStaminaRegenPostfix", (Type[])null), "SEMan.ModifyStaminaRegen(...)"); runDrainPatchInstalled = TryPatch(FindInstanceMethod(typeof(SEMan), "ModifyRunStaminaDrain", null), null, new HarmonyMethod(typeof(YoureTiredPatches), "SEManModifyRunStaminaDrainPostfix", (Type[])null), "SEMan.ModifyRunStaminaDrain(...)"); attackCostPatchInstalled = TryPatch(FindInstanceMethod(typeof(SEMan), "ModifyAttackStaminaUsage", null), null, new HarmonyMethod(typeof(YoureTiredPatches), "SEManModifyAttackStaminaUsagePostfix", (Type[])null), "SEMan.ModifyAttackStaminaUsage(...)"); jogSpeedPatchInstalled = TryPatch(FindInstanceMethod(typeof(Character), "GetJogSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(YoureTiredPatches), "CharacterGetJogSpeedFactorPostfix", (Type[])null), "Character.GetJogSpeedFactor()"); runSpeedPatchInstalled = TryPatch(FindInstanceMethod(typeof(Character), "GetRunSpeedFactor", Type.EmptyTypes), null, new HarmonyMethod(typeof(YoureTiredPatches), "CharacterGetRunSpeedFactorPostfix", (Type[])null), "Character.GetRunSpeedFactor()"); TryPatch(FindInstanceMethod(typeof(Character), "ApplyDamage", null), null, new HarmonyMethod(typeof(YoureTiredPatches), "CharacterApplyDamagePostfix", (Type[])null), "Character.ApplyDamage(...)"); } private bool TryPatch(MethodInfo target, HarmonyMethod prefix, HarmonyMethod postfix, string targetName) { if (target == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("You're Tired: could not find " + targetName + ". That one feature is disabled.")); return false; } try { harmony.Patch((MethodBase)target, prefix, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired: patched " + targetName + ".")); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("You're Tired: failed to patch " + targetName + ": " + ex)); return false; } } private static FieldInfo FindInstanceField(Type type, string fieldName) { Type type2 = type; while (type2 != null) { FieldInfo field = type2.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type2 = type2.BaseType; } return null; } private static MethodInfo FindInstanceMethod(Type type, string methodName, Type[] parameterTypes) { if (parameterTypes != null) { return type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == methodName) { return methods[i]; } } return null; } private void BindConfig() { FatigueSettings fatigueSettings = FatigueRules.CreateBeginnerFriendlyDefaults(); modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Set false to disable the entire tiredness system, including Energy changes and fatigue penalties."); diagnosticKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "DiagnosticKey", (KeyCode)285, "Writes current Energy, environment and patch information to BepInEx/LogOutput.log."); sessionToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "SessionToggleKey", (KeyCode)282, "Emergency in-game toggle for You're Tired. This avoids the F2-F10 keys already used by your other mods."); tickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickIntervalSeconds", 0.5f, "How often Energy is recalculated. Lower is smoother but uses slightly more CPU."); startingEnergy = ((BaseUnityPlugin)this).Config.Bind<float>("General", "StartingEnergyForNewCharacters", 100f, "Energy used only when this character has no saved You're Tired state yet."); saveInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SaveIntervalSeconds", 5f, "How often Energy is saved to the owned player data."); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Writes one fatigue line every tick. Leave off during normal play."); difficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "Preset", "Normal", "Choose Easy, Normal, Hard, or Extreme. Change this setting, then restart Valheim to apply that mod's matching survival balance."); lastAppliedDifficultyPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Difficulty", "LastAppliedPreset", "Normal", "Internal preset tracking. Leave this alone; it records the last difficulty preset applied."); minimumStaminaRegenMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Difficulty", "MinimumStaminaRegenMultiplier", 0.85f, "Safety floor for this mod's own Energy penalty. It prevents exhaustion from reducing stamina recovery into a no-escape state when other Scavengers mods are also active."); showHud = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "ShowTiredMeter", true, "Set false to hide only the Tired HUD while the tiredness system continues running."); hideHudWithCtrlF3 = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "HideHudWithCtrlF3", true, "When enabled, Ctrl+F3 hides or restores this mod's HUD along with Valheim's HUD toggle. The tiredness system keeps running."); stackRightAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "ExistingStackRightAt2048x1152", 470f, "Right edge of the existing Cold/Injured survival stack in the supplied 2048x1152 screenshot."); stackTopAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "ExistingStackTopAt2048x1152", 982f, "Top edge of the existing Cold/Injured survival stack in the supplied 2048x1152 screenshot."); stackBottomAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "ExistingStackBottomAt2048x1152", 1111f, "Bottom edge of the existing Cold/Injured survival stack in the supplied 2048x1152 screenshot."); gapAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "GapRightOfExistingStackAt2048x1152", 26f, "Clear horizontal gap before the Tired meter. V0.2 default is 26 pixels at 2048x1152, moved right from V0.1's 12 pixels."); meterWidthAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "MeterWidthAt2048x1152", 30f, "Width of the Tired meter including its frame."); frameThicknessAtReference = ((BaseUnityPlugin)this).Config.Bind<float>("HUD Layout", "FrameThicknessAt2048x1152", 2f, "Frame thickness of the Tired meter."); hudLayoutEditorKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("HUD Layout Editor", "ToggleTiredLayoutEditorKey", (KeyCode)108, "Press L to enter or leave Tired HUD layout mode. In layout mode, drag the meter and drag a gold corner handle to resize it."); enableYawnAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Yawn Audio", "Enabled", true, "Plays the supplied yawn sound when Energy first reaches the tired threshold, then occasionally while Energy remains low."); yawnEnergyThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "EnergyThreshold", 45f, "Energy percentage at or below which the first yawn plays. 45 means the player yawns when Energy first reaches 45 or lower."); yawnRearmMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "RearmMarginAboveThreshold", 5f, "Energy that must be regained above the yawn threshold before the next tired spell can play an immediate yawn."); yawnRepeatAtThresholdSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "RepeatSecondsAtThreshold", 150f, "Approximate seconds between yawns while Energy stays near the tired threshold. Higher values are less frequent."); yawnRepeatAtZeroSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "RepeatSecondsAtZeroEnergy", 60f, "Approximate seconds between yawns at 0 Energy. The interval smoothly shortens as Energy falls from the threshold to zero."); yawnRepeatRandomnessSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "RepeatRandomnessSeconds", 12f, "Small random variation around repeat timing so yawns do not sound mechanical. This is safety-capped to avoid annoyance."); yawnAudioVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Yawn Audio", "Volume", 0.62f, "Volume for the externally loaded yawn sound."); yawnAudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("Yawn Audio", "YawnFile", "yawn.mp3", "MP3 filename expected in assets/audio beside the You're Tired DLL."); awakeDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "AwakeDrainPerSecond", fatigueSettings.AwakeDrainPerSecond, "Gentle Energy drain while awake. It is intentionally low so ordinary exploration is fair."); sprintDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "SprintDrainPerSecond", fatigueSettings.SprintDrainPerSecond, "Extra Energy drain while sprinting."); swimmingDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "SwimmingDrainPerSecond", fatigueSettings.SwimmingDrainPerSecond, "Extra Energy drain while swimming. Swimming replaces sprint drain rather than stacking with it."); actionDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "CombatAndWorkDrainPerSecond", fatigueSettings.ActionDrainPerSecond, "Extra Energy drain during stamina-using attacks, including combat, chopping and mining."); coldDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "ColdDrainPerSecond", fatigueSettings.ColdDrainPerSecond, "Extra Energy drain during cold conditions."); freezingExtraDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "FreezingExtraDrainPerSecond", fatigueSettings.FreezingExtraDrainPerSecond, "Additional Energy drain during freezing conditions on top of ordinary cold."); lowFoodDrainPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "LowFoodDrainPerSecond", fatigueSettings.LowFoodDrainPerSecond, "Extra drain when fewer than two Valheim food slots are active."); injuryDrainAtMaximumPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Drain", "InjuryDrainAtMaximumPerSecond", fatigueSettings.InjuryDrainAtMaximumPerSecond, "Maximum extra drain from severe injury/low health. It scales gradually and never deals damage."); shelterRestRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "DryShelterRestRecoveryPerSecond", fatigueSettings.ShelterRestRecoveryPerSecond, "Energy restored while dry, sheltered and nearly still."); warmRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "WarmthRecoveryPerSecond", fatigueSettings.WarmRecoveryPerSecond, "Extra Energy restored while dry near a campfire or heat area."); foodRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "FoodRecoveryPerSecond", fatigueSettings.FoodRecoveryPerSecond, "Extra Energy restored with two or more active Valheim food slots."); sleepingRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Recovery", "SleepingRecoveryPerSecond", fatigueSettings.SleepingRecoveryPerSecond, "Strong Energy restoration while in a dry sheltered bed."); enableTestKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableTestKeys", false, "Enables F5 to remove 10 Energy and F11 to restore 10 Energy. Keep false for normal play."); testDrainKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "TestDrainKey", (KeyCode)286, "Debug-only key that removes 10 Energy when EnableTestKeys is true."); testRestoreKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "TestRestoreKey", (KeyCode)292, "Debug-only key that restores 10 Energy when EnableTestKeys is true."); } private void MigrateLegacyDefaultsToNormal() { if (Mathf.Abs(awakeDrainPerSecond.Value - 0.018f) < 0.0001f && Mathf.Abs(sprintDrainPerSecond.Value - 0.065f) < 0.0001f && Mathf.Abs(swimmingDrainPerSecond.Value - 0.095f) < 0.0001f && Mathf.Abs(actionDrainPerSecond.Value - 0.038f) < 0.0001f && Mathf.Abs(coldDrainPerSecond.Value - 0.022f) < 0.0001f && Mathf.Abs(freezingExtraDrainPerSecond.Value - 0.042f) < 0.0001f && Mathf.Abs(lowFoodDrainPerSecond.Value - 0.02f) < 0.0001f && Mathf.Abs(injuryDrainAtMaximumPerSecond.Value - 0.06f) < 0.0001f) { ApplyDifficultyPreset("Normal"); ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired: migrated untouched legacy fatigue defaults to the balanced Normal preset."); } } private void ApplyDifficultyPresetIfChanged() { string text = NormalizeDifficultyPreset(difficultyPreset.Value); if (!string.Equals(difficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase)) { difficultyPreset.Value = text; } if (!string.Equals(lastAppliedDifficultyPreset.Value, text, StringComparison.OrdinalIgnoreCase)) { ApplyDifficultyPreset(text); lastAppliedDifficultyPreset.Value = text; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired: applied " + text + " difficulty preset.")); } } private static string NormalizeDifficultyPreset(string value) { if (string.Equals(value, "Easy", StringComparison.OrdinalIgnoreCase)) { return "Easy"; } if (string.Equals(value, "Hard", StringComparison.OrdinalIgnoreCase)) { return "Hard"; } if (string.Equals(value, "Extreme", StringComparison.OrdinalIgnoreCase)) { return "Extreme"; } return "Normal"; } private void ApplyDifficultyPreset(string preset) { switch (preset) { case "Easy": awakeDrainPerSecond.Value = 0.01f; sprintDrainPerSecond.Value = 0.035f; swimmingDrainPerSecond.Value = 0.055f; actionDrainPerSecond.Value = 0.02f; coldDrainPerSecond.Value = 0.01f; freezingExtraDrainPerSecond.Value = 0.018f; lowFoodDrainPerSecond.Value = 0.01f; injuryDrainAtMaximumPerSecond.Value = 0.025f; shelterRestRecoveryPerSecond.Value = 0.1f; warmRecoveryPerSecond.Value = 0.07f; foodRecoveryPerSecond.Value = 0.035f; sleepingRecoveryPerSecond.Value = 0.42f; minimumStaminaRegenMultiplier.Value = 0.92f; break; case "Hard": awakeDrainPerSecond.Value = 0.02f; sprintDrainPerSecond.Value = 0.075f; swimmingDrainPerSecond.Value = 0.11f; actionDrainPerSecond.Value = 0.045f; coldDrainPerSecond.Value = 0.028f; freezingExtraDrainPerSecond.Value = 0.05f; lowFoodDrainPerSecond.Value = 0.025f; injuryDrainAtMaximumPerSecond.Value = 0.075f; shelterRestRecoveryPerSecond.Value = 0.06f; warmRecoveryPerSecond.Value = 0.035f; foodRecoveryPerSecond.Value = 0.014f; sleepingRecoveryPerSecond.Value = 0.29f; minimumStaminaRegenMultiplier.Value = 0.78f; break; case "Extreme": awakeDrainPerSecond.Value = 0.028f; sprintDrainPerSecond.Value = 0.1f; swimmingDrainPerSecond.Value = 0.14f; actionDrainPerSecond.Value = 0.06f; coldDrainPerSecond.Value = 0.04f; freezingExtraDrainPerSecond.Value = 0.07f; lowFoodDrainPerSecond.Value = 0.035f; injuryDrainAtMaximumPerSecond.Value = 0.1f; shelterRestRecoveryPerSecond.Value = 0.045f; warmRecoveryPerSecond.Value = 0.025f; foodRecoveryPerSecond.Value = 0.01f; sleepingRecoveryPerSecond.Value = 0.22f; minimumStaminaRegenMultiplier.Value = 0.72f; break; default: awakeDrainPerSecond.Value = 0.014f; sprintDrainPerSecond.Value = 0.05f; swimmingDrainPerSecond.Value = 0.075f; actionDrainPerSecond.Value = 0.03f; coldDrainPerSecond.Value = 0.015f; freezingExtraDrainPerSecond.Value = 0.028f; lowFoodDrainPerSecond.Value = 0.014f; injuryDrainAtMaximumPerSecond.Value = 0.04f; shelterRestRecoveryPerSecond.Value = 0.08f; warmRecoveryPerSecond.Value = 0.055f; foodRecoveryPerSecond.Value = 0.025f; sleepingRecoveryPerSecond.Value = 0.36f; minimumStaminaRegenMultiplier.Value = 0.85f; break; } } private void MigrateHudSpacingFromPrototype() { if (Mathf.Abs(gapAtReference.Value - 12f) < 0.01f) { gapAtReference.Value = 26f; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired: migrated V0.1 HUD gap from 12 to 26 pixels."); } } private void CreatePixelTexture() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) pixelTexture = new Texture2D(1, 1, (TextureFormat)4, false); ((Object)pixelTexture).name = "YoureTired_HudPixel"; pixelTexture.SetPixel(0, 0, Color.white); pixelTexture.Apply(); ((Object)pixelTexture).hideFlags = (HideFlags)61; } private void OnGUI() { if (!runtimeEnabled || !modEnabled.Value || !showHud.Value || IsHudHiddenByCtrlF3() || (Object)(object)pixelTexture == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } try { EnsureGuiStyles(); int depth = GUI.depth; GUI.depth = -1000; DrawEnergyMeter(); GUI.depth = depth; } catch (Exception ex) { if (!guiFailureLogged) { guiFailureLogged = true; ((BaseUnityPlugin)this).Logger.LogError((object)("You're Tired HUD draw failed: " + ex)); } } } private void EnsureGuiStyles() { //IL_0026: 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_0044: Expected O, but got Unknown //IL_0088: 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_009e: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (headerStyle == null || valueStyle == null || stateStyle == null) { GUIStyle val = (GUIStyle)(((Object)(object)GUI.skin != (Object)null) ? ((object)GUI.skin.label) : ((object)new GUIStyle())); headerStyle = new GUIStyle(val); headerStyle.alignment = (TextAnchor)4; headerStyle.fontStyle = (FontStyle)1; headerStyle.fontSize = 11; headerStyle.normal.textColor = new Color(0.96f, 0.79f, 0.35f, 1f); valueStyle = new GUIStyle(val); valueStyle.alignment = (TextAnchor)4; valueStyle.fontStyle = (FontStyle)1; valueStyle.fontSize = 10; valueStyle.normal.textColor = Color.white; stateStyle = new GUIStyle(val); stateStyle.alignment = (TextAnchor)4; stateStyle.fontStyle = (FontStyle)0; stateStyle.fontSize = 9; stateStyle.normal.textColor = new Color(0.9f, 0.9f, 0.84f, 0.95f); } } private void DrawEnergyMeter() { //IL_008e: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: 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_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) float hudScale = GetHudScale(); float num = (stackRightAtReference.Value + gapAtReference.Value) * hudScale; float num2 = stackTopAtReference.Value * hudScale; float num3 = Mathf.Max(70f * hudScale, (stackBottomAtReference.Value - stackTopAtReference.Value) * hudScale); float num4 = Mathf.Max(22f * hudScale, meterWidthAtReference.Value * hudScale); float num5 = Mathf.Clamp(frameThicknessAtReference.Value * hudScale, 1f, 6f); Rect val = ClampMeterRect(new Rect(num, num2, num4, num3), hudScale); float num6 = 129f * hudScale; float num7 = 30f * hudScale; float num8 = Mathf.Clamp(Mathf.Min(((Rect)(ref val)).width / num7, ((Rect)(ref val)).height / num6), 0.55f, 3f); headerStyle.fontSize = Mathf.Max(8, Mathf.RoundToInt(11f * num8)); valueStyle.fontSize = Mathf.Max(8, Mathf.RoundToInt(10f * num8)); stateStyle.fontSize = Mathf.Max(7, Mathf.RoundToInt(9f * num8)); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref val)).x - 10f * hudScale, ((Rect)(ref val)).y - 17f * hudScale, ((Rect)(ref val)).width + 20f * hudScale, 15f * hudScale); Rect val3 = new Rect(((Rect)(ref val)).x - 13f * hudScale, ((Rect)(ref val)).yMax + 1f * hudScale, ((Rect)(ref val)).width + 26f * hudScale, 14f * hudScale); DrawRect(val, new Color(0.025f, 0.04f, 0.03f, 0.88f)); Color colour = default(Color); ((Color)(ref colour))..ctor(0.45f, 0.35f, 0.16f, 0.92f); DrawRect(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width, num5), colour); DrawRect(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).yMax - num5, ((Rect)(ref val)).width, num5), colour); DrawRect(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, num5, ((Rect)(ref val)).height), colour); DrawRect(new Rect(((Rect)(ref val)).xMax - num5, ((Rect)(ref val)).y, num5, ((Rect)(ref val)).height), colour); float num9 = ((Rect)(ref val)).x + num5 + 2f * hudScale; float num10 = ((Rect)(ref val)).y + num5 + 2f * hudScale; float num11 = Mathf.Max(1f, ((Rect)(ref val)).width - 2f * num5 - 4f * hudScale); float num12 = Mathf.Max(1f, ((Rect)(ref val)).height - 2f * num5 - 4f * hudScale); Rect rect = default(Rect); ((Rect)(ref rect))..ctor(num9, num10, num11, num12); DrawRect(rect, new Color(0f, 0f, 0f, 0.72f)); float num13 = energy / 100f; float num14 = ((Rect)(ref rect)).height * num13; Rect rect2 = default(Rect); ((Rect)(ref rect2))..ctor(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - num14, ((Rect)(ref rect)).width, num14); DrawRect(rect2, GetEnergyColour(energy)); GUI.Label(val2, "TIRED", headerStyle); GUI.Label(val, energy.ToString("0"), valueStyle); GUI.Label(val3, FatigueRules.GetStage(energy).ToString().ToUpperInvariant(), stateStyle); DrawHudLayoutEditor(val, hudScale); } private void DrawRect(Rect rect, Color colour) { //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_000b: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = colour; GUI.DrawTexture(rect, (Texture)(object)pixelTexture); GUI.color = color; } private static float GetHudScale() { float num = Mathf.Min((float)Screen.width / 2048f, (float)Screen.height / 1152f); return Mathf.Max(0.25f, num); } private static Rect ClampMeterRect(Rect rect, float scale) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) float num = 22f * scale; float num2 = 70f * scale; float num3 = Mathf.Clamp(((Rect)(ref rect)).width, num, Mathf.Max(num, (float)Screen.width - 4f)); float num4 = Mathf.Clamp(((Rect)(ref rect)).height, num2, Mathf.Max(num2, (float)Screen.height - 4f)); float num5 = Mathf.Clamp(((Rect)(ref rect)).x, 0f, Mathf.Max(0f, (float)Screen.width - num3)); float num6 = Mathf.Clamp(((Rect)(ref rect)).y, 0f, Mathf.Max(0f, (float)Screen.height - num4)); return new Rect(num5, num6, num3, num4); } private bool IsHudHiddenByCtrlF3() { if (hideHudWithCtrlF3 != null && hideHudWithCtrlF3.Value) { return hudHiddenByCtrlF3; } return false; } private bool TryToggleHudWithCtrlF3() { if (!IsCtrlF3Pressed()) { return false; } if (hideHudWithCtrlF3 == null || !hideHudWithCtrlF3.Value) { return true; } hudHiddenByCtrlF3 = !hudHiddenByCtrlF3; if (hudHiddenByCtrlF3) { CloseHudLayoutEditorForHiddenHud(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired: Ctrl+F3 HUD " + (hudHiddenByCtrlF3 ? "hidden." : "restored."))); return true; } private static bool IsCtrlF3Pressed() { if (Input.GetKeyDown((KeyCode)284)) { if (!Input.GetKey((KeyCode)306)) { return Input.GetKey((KeyCode)305); } return true; } return false; } private void CloseHudLayoutEditorForHiddenHud() { if (hudLayoutEditorActive) { hudLayoutEditorActive = false; hudLayoutDragging = false; hudResizeHandle = HudResizeHandle.None; RestoreHudCursor(); ((BaseUnityPlugin)this).Config.Save(); } } private void ToggleHudLayoutEditor() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) hudLayoutEditorActive = !hudLayoutEditorActive; hudLayoutDragging = false; hudResizeHandle = HudResizeHandle.None; if (hudLayoutEditorActive) { hudPreviousCursorLockMode = Cursor.lockState; hudPreviousCursorVisible = Cursor.visible; hudCursorStateCaptured = true; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; ShowMessage("Tired layout mode: drag meter or a gold corner. Press L again to save."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired: Tired HUD layout editor enabled."); } else { RestoreHudCursor(); ((BaseUnityPlugin)this).Config.Save(); ShowMessage("Tired layout saved."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"You're Tired: Tired HUD layout editor saved and closed."); } } private void RestoreHudCursor() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (hudCursorStateCaptured) { Cursor.lockState = hudPreviousCursorLockMode; Cursor.visible = hudPreviousCursorVisible; hudCursorStateCaptured = false; } } private void DrawHudLayoutEditor(Rect meterRect, float scale) { //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Invalid comparison between Unknown and I4 //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0053: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00d4: 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_008d: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_00de: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) if (!hudLayoutEditorActive) { return; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; Event current = Event.current; if (current != null) { Vector2 mousePosition = current.mousePosition; if ((int)current.type == 0 && current.button == 0) { HudResizeHandle resizeHandle = GetResizeHandle(meterRect, mousePosition); if (resizeHandle != HudResizeHandle.None) { hudResizeHandle = resizeHandle; hudLayoutDragging = false; hudEditStartMouse = mousePosition; hudEditStartRect = meterRect; current.Use(); } else if (((Rect)(ref meterRect)).Contains(mousePosition)) { hudLayoutDragging = true; hudResizeHandle = HudResizeHandle.None; hudEditStartMouse = mousePosition; hudEditStartRect = meterRect; current.Use(); } } else if ((int)current.type == 3 && current.button == 0 && (hudLayoutDragging || hudResizeHandle != HudResizeHandle.None)) { Vector2 val = mousePosition - hudEditStartMouse; Rect rect = (Rect)(hudLayoutDragging ? new Rect(((Rect)(ref hudEditStartRect)).x + val.x, ((Rect)(ref hudEditStartRect)).y + val.y, ((Rect)(ref hudEditStartRect)).width, ((Rect)(ref hudEditStartRect)).height) : ResizeRect(hudEditStartRect, val, hudResizeHandle, 22f * scale, 70f * scale)); StoreMeterRect(rect, scale); current.Use(); } else if ((int)current.type == 1 && current.button == 0 && (hudLayoutDragging || hudResizeHandle != HudResizeHandle.None)) { hudLayoutDragging = false; hudResizeHandle = HudResizeHandle.None; ((BaseUnityPlugin)this).Config.Save(); current.Use(); } } DrawEditorOutline(meterRect); Color color = GUI.color; GUI.color = new Color(1f, 0.78f, 0.22f, 1f); GUI.Label(new Rect(12f, 60f, 820f, 24f), "L — Tired layout mode: drag meter; drag any gold corner to resize; press L again to save."); GUI.color = color; } private void StoreMeterRect(Rect rect, float scale) { //IL_0000: 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_0007: Unknown result type (might be due to invalid IL or missing references) Rect val = ClampMeterRect(rect, scale); float num = Mathf.Max(0.01f, scale); stackRightAtReference.Value = Mathf.Max(0f, ((Rect)(ref val)).x / num - gapAtReference.Value); stackTopAtReference.Value = Mathf.Max(0f, ((Rect)(ref val)).y / num); stackBottomAtReference.Value = stackTopAtReference.Value + Mathf.Max(70f, ((Rect)(ref val)).height / num); meterWidthAtReference.Value = Mathf.Max(22f, ((Rect)(ref val)).width / num); } private static HudResizeHandle GetResizeHandle(Rect rect, Vector2 mouse) { //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_0020: 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_004d: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_00b6: Unknown result type (might be due to invalid IL or missing references) Rect val = new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, 14f, 14f); if (((Rect)(ref val)).Contains(mouse)) { return HudResizeHandle.TopLeft; } val = new Rect(((Rect)(ref rect)).xMax - 14f, ((Rect)(ref rect)).y, 14f, 14f); if (((Rect)(ref val)).Contains(mouse)) { return HudResizeHandle.TopRight; } val = new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - 14f, 14f, 14f); if (((Rect)(ref val)).Contains(mouse)) { return HudResizeHandle.BottomLeft; } val = new Rect(((Rect)(ref rect)).xMax - 14f, ((Rect)(ref rect)).yMax - 14f, 14f, 14f); if (((Rect)(ref val)).Contains(mouse)) { return HudResizeHandle.BottomRight; } return HudResizeHandle.None; } private static Rect ResizeRect(Rect start, Vector2 delta, HudResizeHandle handle, float minimumWidth, float minimumHeight) { //IL_0029: 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_0056: 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_0045: 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_00b1: 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) float num = ((Rect)(ref start)).x; float num2 = ((Rect)(ref start)).y; float num3 = ((Rect)(ref start)).width; float num4 = ((Rect)(ref start)).height; switch (handle) { case HudResizeHandle.TopLeft: case HudResizeHandle.BottomLeft: num += delta.x; num3 -= delta.x; break; case HudResizeHandle.TopRight: case HudResizeHandle.BottomRight: num3 += delta.x; break; } switch (handle) { case HudResizeHandle.TopLeft: case HudResizeHandle.TopRight: num2 += delta.y; num4 -= delta.y; break; case HudResizeHandle.BottomLeft: case HudResizeHandle.BottomRight: num4 += delta.y; break; } if (num3 < minimumWidth) { if (handle == HudResizeHandle.TopLeft || handle == HudResizeHandle.BottomLeft) { num = ((Rect)(ref start)).xMax - minimumWidth; } num3 = minimumWidth; } if (num4 < minimumHeight) { if (handle == HudResizeHandle.TopLeft || handle == HudResizeHandle.TopRight) { num2 = ((Rect)(ref start)).yMax - minimumHeight; } num4 = minimumHeight; } return ClampMeterRect(new Rect(num, num2, num3, num4), GetHudScale()); } private void DrawEditorOutline(Rect rect) { //IL_0000: 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_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_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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = new Color(1f, 0.72f, 0.15f, 0.95f); DrawRect(new Rect(((Rect)(ref rect)).x - 1f, ((Rect)(ref rect)).y - 1f, ((Rect)(ref rect)).width + 2f, 2f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).x - 1f, ((Rect)(ref rect)).yMax - 1f, ((Rect)(ref rect)).width + 2f, 2f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).x - 1f, ((Rect)(ref rect)).y - 1f, 2f, ((Rect)(ref rect)).height + 2f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).xMax - 1f, ((Rect)(ref rect)).y - 1f, 2f, ((Rect)(ref rect)).height + 2f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).x - 2f, ((Rect)(ref rect)).y - 2f, 8f, 8f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).xMax - 6f, ((Rect)(ref rect)).y - 2f, 8f, 8f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).x - 2f, ((Rect)(ref rect)).yMax - 6f, 8f, 8f), GUI.color); DrawRect(new Rect(((Rect)(ref rect)).xMax - 6f, ((Rect)(ref rect)).yMax - 6f, 8f, 8f), GUI.color); GUI.color = color; } private static Color GetEnergyColour(float currentEnergy) { //IL_002f: 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) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) return (Color)(FatigueRules.GetStage(currentEnergy) switch { FatigueStage.Fresh => new Color(0.3f, 0.78f, 0.38f, 0.95f), FatigueStage.Worn => new Color(0.9f, 0.72f, 0.22f, 0.95f), FatigueStage.Tired => new Color(0.92f, 0.48f, 0.16f, 0.95f), _ => new Color(0.76f, 0.18f, 0.15f, 0.95f), }); } private void WriteDiagnostic() { float num = Mathf.Min((float)Screen.width / 2048f, (float)Screen.height / 1152f); num = Mathf.Max(0.25f, num); float num2 = (stackRightAtReference.Value + gapAtReference.Value) * num; float num3 = stackTopAtReference.Value * num; float num4 = Mathf.Max(18f, meterWidthAtReference.Value * num); float num5 = Mathf.Max(24f, (stackBottomAtReference.Value - stackTopAtReference.Value) * num); string text = (hasSnapshot ? SnapshotToDiagnosticText(lastSnapshot) : "no snapshot yet"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("You're Tired diagnostic: enabled=" + runtimeEnabled + ", loaded=" + stateLoaded + ", energy=" + energy.ToString("0.0") + ", stage=" + FatigueRules.GetStage(energy).ToString() + ", rate=" + lastEnergyDeltaPerSecond.ToString("0.000") + "/s, patches=[regen=" + staminaRegenPatchInstalled + ", runDrain=" + runDrainPatchInstalled + ", attack=" + attackCostPatchInstalled + ", jog=" + jogSpeedPatchInstalled + ", run=" + runSpeedPatchInstalled + "], meter=(x=" + num2.ToString("0.0") + ", y=" + num3.ToString("0.0") + ", w=" + num4.ToString("0.0") + ", h=" + num5.ToString("0.0") + "), " + text + ".")); } private static string SnapshotToDiagnosticText(FatigueSnapshot snapshot) { return "snapshot=[sleep=" + snapshot.IsSleeping + ", sprint=" + snapshot.IsSprinting + ", swim=" + snapshot.IsSwimming + ", action=" + snapshot.IsActionActive + ", shelter=" + snapshot.IsSheltered + ", still=" + snapshot.IsRestingStill + ", warm=" + snapshot.IsWarm + ", dry=" + snapshot.IsDry + ", cold=" + snapshot.IsCold + ", freezing=" + snapshot.IsFreezing + ", food=" + snapshot.FoodCount + ", injury=" + snapshot.InjurySeverity.ToString("0.0") + "]"; } private static void ShowMessage(string text) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false); } } } internal enum FatigueStage { Fresh, Worn, Tired, Exhausted } internal struct FatigueSnapshot { public bool IsSleeping; public bool IsSprinting; public bool IsSwimming; public bool IsActionActive; public bool IsSheltered; public bool IsRestingStill; public bool IsWarm; public bool IsDry; public bool IsCold; public bool IsFreezing; public int FoodCount; public float InjurySeverity; } internal struct FatigueSettings { public float AwakeDrainPerSecond; public float SprintDrainPerSecond; public float SwimmingDrainPerSecond; public float ActionDrainPerSecond; public float ColdDrainPerSecond; public float FreezingExtraDrainPerSecond; public float LowFoodDrainPerSecond; public float InjuryDrainAtMaximumPerSecond; public float ShelterRestRecoveryPerSecond; public float WarmRecoveryPerSecond; public float FoodRecoveryPerSecond; public float SleepingRecoveryPerSecond; } internal struct FatigueEffects { public float StaminaRegenMultiplier; public float SprintStaminaMultiplier; public float ToolStaminaMultiplier; public float MovementMultiplier; } internal static class FatigueRules { public const float MinimumEnergy = 0f; public const float MaximumEnergy = 100f; internal static FatigueSettings CreateBeginnerFriendlyDefaults() { return new FatigueSettings { AwakeDrainPerSecond = 0.014f, SprintDrainPerSecond = 0.05f, SwimmingDrainPerSecond = 0.075f, ActionDrainPerSecond = 0.03f, ColdDrainPerSecond = 0.015f, FreezingExtraDrainPerSecond = 0.028f, LowFoodDrainPerSecond = 0.014f, InjuryDrainAtMaximumPerSecond = 0.04f, ShelterRestRecoveryPerSecond = 0.08f, WarmRecoveryPerSecond = 0.055f, FoodRecoveryPerSecond = 0.025f, SleepingRecoveryPerSecond = 0.36f }; } internal static float ClampEnergy(float value) { return Mathf.Clamp(value, 0f, 100f); } internal static FatigueStage GetStage(float currentEnergy) { float num = ClampEnergy(currentEnergy); if (num >= 75f) { return FatigueStage.Fresh; } if (num >= 50f) { return FatigueStage.Worn; } if (num >= 25f) { return FatigueStage.Tired; } return FatigueStage.Exhausted; } internal static FatigueEffects GetEffects(float currentEnergy) { return GetStage(currentEnergy) switch { FatigueStage.Fresh => new FatigueEffects { StaminaRegenMultiplier = 1f, SprintStaminaMultiplier = 1f, ToolStaminaMultiplier = 1f, MovementMultiplier = 1f }, FatigueStage.Worn => new FatigueEffects { StaminaRegenMultiplier = 0.94f, SprintStaminaMultiplier = 1.05f, ToolStaminaMultiplier = 1.03f, MovementMultiplier = 0.98f }, FatigueStage.Tired => new FatigueEffects { StaminaRegenMultiplier = 0.82f, SprintStaminaMultiplier = 1.14f, ToolStaminaMultiplier = 1.1f, MovementMultiplier = 0.92f }, _ => new FatigueEffects { StaminaRegenMultiplier = 0.65f, SprintStaminaMultiplier = 1.28f, ToolStaminaMultiplier = 1.2f, MovementMultiplier = 0.8f }, }; } internal static float CalculateEnergyDelta(FatigueSnapshot snapshot, float elapsedSeconds, FatigueSettings settings) { float num = Mathf.Max(0f, elapsedSeconds); if (num <= 0f) { return 0f; } float num2 = 0f; if (snapshot.IsSleeping) { num2 += Mathf.Max(0f, settings.SleepingRecoveryPerSecond); return num2 * num; } num2 -= Mathf.Max(0f, settings.AwakeDrainPerSecond); if (snapshot.IsSwimming) { num2 -= Mathf.Max(0f, settings.SwimmingDrainPerSecond); } else if (snapshot.IsSprinting) { num2 -= Mathf.Max(0f, settings.SprintDrainPerSecond); } if (snapshot.IsActionActive) { num2 -= Mathf.Max(0f, settings.ActionDrainPerSecond); } if (snapshot.IsCold) { num2 -= Mathf.Max(0f, settings.ColdDrainPerSecond); } if (snapshot.IsFreezing) { num2 -= Mathf.Max(0f, settings.FreezingExtraDrainPerSecond); } if (snapshot.FoodCount < 2) { num2 -= Mathf.Max(0f, settings.LowFoodDrainPerSecond); } num2 -= Mathf.Max(0f, settings.InjuryDrainAtMaximumPerSecond) * Mathf.Clamp01(snapshot.InjurySeverity / 100f); if (snapshot.IsDry && snapshot.IsSheltered && snapshot.IsRestingStill) { num2 += Mathf.Max(0f, settings.ShelterRestRecoveryPerSecond); } if (snapshot.IsDry && snapshot.IsWarm) { num2 += Mathf.Max(0f, settings.WarmRecoveryPerSecond); } if (snapshot.FoodCount >= 2) { num2 += Mathf.Max(0f, settings.FoodRecoveryPerSecond); } return num2 * num; } internal static bool RunSelfTests(out string failure) { failure = null; if (ClampEnergy(-5f) != 0f || ClampEnergy(105f) != 100f) { failure = "ClampEnergy returned an invalid range."; return false; } if (GetStage(100f) != FatigueStage.Fresh || GetStage(50f) != FatigueStage.Worn || GetStage(25f) != FatigueStage.Tired || GetStage(0f) != FatigueStage.Exhausted) { failure = "Fatigue stage thresholds are invalid."; return false; } FatigueSettings settings = CreateBeginnerFriendlyDefaults(); if (CalculateEnergyDelta(new FatigueSnapshot { IsSleeping = true }, 1f, settings) <= 0f) { failure = "Sleeping must restore energy."; return false; } return true; } } internal static class YoureTiredPatches { public static void SEManModifyStaminaRegenPostfix(Character ___m_character, ref float __0) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((___m_character is Player) ? ___m_character : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { __0 *= instance.GetStaminaRegenMultiplier(); } } public static void SEManModifyRunStaminaDrainPostfix(Character ___m_character, ref float __1) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((___m_character is Player) ? ___m_character : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { __1 *= instance.GetRunStaminaMultiplier(); } } public static void SEManModifyAttackStaminaUsagePostfix(Character ___m_character, ref float __1) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((___m_character is Player) ? ___m_character : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { instance.NotifyStaminaUsingAction(player); __1 *= instance.GetAttackStaminaMultiplier(); } } public static void CharacterGetJogSpeedFactorPostfix(Character __instance, ref float __result) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { __result *= instance.GetMovementMultiplier(); } } public static void CharacterGetRunSpeedFactorPostfix(Character __instance, ref float __result) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { __result *= instance.GetMovementMultiplier(); } } public static void CharacterApplyDamagePostfix(Character __instance) { YoureTiredPlugin instance = YoureTiredPlugin.Instance; Player player = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)instance != (Object)null && instance.IsActiveFor(player)) { instance.NotifyDamageTaken(player); } } }