using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using ReadyViking.Config; using ReadyViking.Input; using ReadyViking.Models; using ReadyViking.Overlay; using ReadyViking.Runtime; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ReadyViking.Config { internal sealed class ReadyVikingConfig { public ConfigEntry ToggleOverlay { get; private set; } public ConfigEntry AutoHideSeconds { get; private set; } public ConfigEntry WeaponDurabilityWarningPercent { get; private set; } public ConfigEntry OverlayPositionX { get; private set; } public ConfigEntry OverlayPositionY { get; private set; } public ReadyVikingConfig(ConfigFile config) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown ToggleOverlay = config.Bind("General", "ToggleOverlay", new KeyboardShortcut((KeyCode)289, Array.Empty()), "Toggle the ReadyViking test overlay."); AutoHideSeconds = config.Bind("General", "AutoHideSeconds", 6f, "Seconds until the overlay hides itself after opening."); WeaponDurabilityWarningPercent = config.Bind("General", "WeaponDurabilityWarningPercent", 25f, new ConfigDescription("Weapon durability percentage at or below which the overlay shows a warning.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); OverlayPositionX = config.Bind("Overlay", "OverlayPositionX", 24f, "Horizontal screen position of the ReadyViking overlay."); OverlayPositionY = config.Bind("Overlay", "OverlayPositionY", 170f, "Vertical screen position of the ReadyViking overlay."); } } } namespace ReadyViking.Input { internal sealed class ReadyVikingInputController { private readonly ConfigEntry _toggleOverlay; public ReadyVikingInputController(ConfigEntry toggleOverlay) { _toggleOverlay = toggleOverlay; } public bool TogglePressed() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = _toggleOverlay.Value; return ((KeyboardShortcut)(ref value)).IsDown(); } } } namespace ReadyViking.Models { internal sealed class ActiveMealSnapshot { public string Name { get; private set; } public float RemainingSeconds { get; private set; } public ActiveMealSnapshot(string name, float remainingSeconds) { Name = name; RemainingSeconds = remainingSeconds; } } internal sealed class ActiveMealsSnapshot { public CheckState State { get; private set; } public int ActiveMealCount { get; private set; } public IReadOnlyList Meals { get; private set; } public ActiveMealsSnapshot(CheckState state, int activeMealCount, IReadOnlyList meals) { State = state; ActiveMealCount = activeMealCount; Meals = meals; } } internal sealed class AmmoSnapshot { public CheckState State { get; private set; } public bool RequiresAmmo { get; private set; } public string AmmoType { get; private set; } public int AvailableAmmo { get; private set; } public AmmoSnapshot(CheckState state, bool requiresAmmo, string ammoType, int availableAmmo) { State = state; RequiresAmmo = requiresAmmo; AmmoType = ammoType; AvailableAmmo = availableAmmo; } } internal sealed class CheckResult { public string Title { get; private set; } public CheckState State { get; private set; } public string Detail { get; private set; } public CheckResult(string title, CheckState state, string detail) { Title = title; State = state; Detail = detail; } } internal enum CheckState { Ready, Warning, Missing, Unknown, NotApplicable } internal sealed class InventorySnapshot { public CheckState SlotsState { get; private set; } public int FreeSlots { get; private set; } public int TotalSlots { get; private set; } public CheckState WeightState { get; private set; } public float CurrentWeight { get; private set; } public float MaxWeight { get; private set; } public InventorySnapshot(CheckState slotsState, int freeSlots, int totalSlots, CheckState weightState, float currentWeight, float maxWeight) { SlotsState = slotsState; FreeSlots = freeSlots; TotalSlots = totalSlots; WeightState = weightState; CurrentWeight = currentWeight; MaxWeight = maxWeight; } } internal sealed class ReadinessReport { public string Headline { get; private set; } public IReadOnlyList Checks { get; private set; } public ReadinessReport(string headline, IReadOnlyList checks) { Headline = headline; Checks = checks; } } internal sealed class ReadyVikingSnapshot { public SnapshotStatus LocalPlayerStatus { get; private set; } public ActiveMealsSnapshot ActiveMeals { get; private set; } public WeaponSnapshot Weapon { get; private set; } public RestedSnapshot Rested { get; private set; } public AmmoSnapshot Ammo { get; private set; } public InventorySnapshot Inventory { get; private set; } public bool LocalPlayerAvailable => LocalPlayerStatus == SnapshotStatus.Available; public ReadyVikingSnapshot(SnapshotStatus localPlayerStatus, ActiveMealsSnapshot activeMeals, WeaponSnapshot weapon, RestedSnapshot rested, AmmoSnapshot ammo, InventorySnapshot inventory) { LocalPlayerStatus = localPlayerStatus; ActiveMeals = activeMeals; Weapon = weapon; Rested = rested; Ammo = ammo; Inventory = inventory; } } internal sealed class RestedSnapshot { public CheckState State { get; private set; } public bool IsRested { get; private set; } public float RemainingSeconds { get; private set; } public RestedSnapshot(CheckState state, bool isRested, float remainingSeconds) { State = state; IsRested = isRested; RemainingSeconds = remainingSeconds; } } internal enum SnapshotStatus { Available, Unknown, Unavailable } internal sealed class WeaponSnapshot { public CheckState State { get; private set; } public string Name { get; private set; } public float CurrentDurability { get; private set; } public float MaxDurability { get; private set; } public float DurabilityPercent { get; private set; } public WeaponSnapshot(CheckState state, string name, float currentDurability, float maxDurability, float durabilityPercent) { State = state; Name = name; CurrentDurability = currentDurability; MaxDurability = maxDurability; DurabilityPercent = durabilityPercent; } } } namespace ReadyViking.Overlay { internal sealed class ReadyVikingOverlayView { private const float PanelWidth = 360f; private const float PanelHeight = 220f; private GUIStyle _titleStyle; private GUIStyle _rowStyle; private GUIStyle _detailStyle; private GUIStyle _panelStyle; public void Draw(ReadinessReport report, float positionX, float positionY) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) EnsureStyles(); Rect val = CreateClampedPanelRect(positionX, positionY); GUILayout.BeginArea(val, _panelStyle); GUILayout.Label(report.Headline, _titleStyle, Array.Empty()); foreach (CheckResult check in report.Checks) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(GetPrefix(check.State), _rowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(48f) }); GUILayout.Label(check.Title, _rowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }); GUILayout.Label(check.Detail, _detailStyle, Array.Empty()); GUILayout.EndHorizontal(); } GUILayout.EndArea(); } private static Rect CreateClampedPanelRect(float positionX, float positionY) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0f, (float)Screen.width - 360f); float num2 = Mathf.Max(0f, (float)Screen.height - 220f); float num3 = Mathf.Clamp(positionX, 0f, num); float num4 = Mathf.Clamp(positionY, 0f, num2); return new Rect(num3, num4, 360f, 220f); } private void EnsureStyles() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown if (_panelStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.box); val.padding = new RectOffset(14, 14, 12, 12); val.margin = new RectOffset(0, 0, 0, 0); _panelStyle = val; val = new GUIStyle(GUI.skin.label); val.fontSize = 18; val.fontStyle = (FontStyle)1; val.richText = true; val.alignment = (TextAnchor)3; _titleStyle = val; val = new GUIStyle(GUI.skin.label); val.fontSize = 13; val.richText = true; val.alignment = (TextAnchor)3; _rowStyle = val; val = new GUIStyle(GUI.skin.label); val.fontSize = 13; val.richText = true; val.alignment = (TextAnchor)3; _detailStyle = val; } } private static string GetPrefix(CheckState state) { return state switch { CheckState.Ready => "OK", CheckState.Warning => "WARN", CheckState.Missing => "MISS", CheckState.Unknown => "UNK", CheckState.NotApplicable => "N/A", _ => "UNK", }; } } } namespace ReadyViking { [BepInPlugin("com.goblinstudio.readyviking", "ReadyViking", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { private ReadyVikingConfig _config; private ReadyVikingInputController _input; private ReadyVikingOverlayView _overlayView; private ReadyVikingSnapshotCollector _snapshotCollector; private ReadinessReport _currentReport; private bool _isVisible; private float _openedAt; private void Awake() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) _config = new ReadyVikingConfig(((BaseUnityPlugin)this).Config); _input = new ReadyVikingInputController(_config.ToggleOverlay); _overlayView = new ReadyVikingOverlayView(); _snapshotCollector = new ReadyVikingSnapshotCollector(); _currentReport = StaticTestReportFactory.Create(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[ReadyViking] loaded v0.1.0"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[ReadyViking] Hotkey: " + _config.ToggleOverlay.Value)); } private void Update() { if (_input != null && _config != null) { if (_input.TogglePressed()) { ToggleOverlay(); } if (_isVisible && Time.realtimeSinceStartup - _openedAt >= Mathf.Max(0.25f, _config.AutoHideSeconds.Value)) { _isVisible = false; } } } private void OnGUI() { if (_isVisible && _overlayView != null && _currentReport != null) { _overlayView.Draw(_currentReport, _config.OverlayPositionX.Value, _config.OverlayPositionY.Value); } } private void ToggleOverlay() { _isVisible = !_isVisible; _openedAt = Time.realtimeSinceStartup; if (_isVisible) { ReadyVikingSnapshot readyVikingSnapshot = _snapshotCollector.Collect(); _currentReport = StaticTestReportFactory.Create(readyVikingSnapshot.ActiveMeals, readyVikingSnapshot.Weapon, _config.WeaponDurabilityWarningPercent.Value, readyVikingSnapshot.Rested, readyVikingSnapshot.Ammo, readyVikingSnapshot.Inventory); string text = ((readyVikingSnapshot.LocalPlayerStatus != SnapshotStatus.Available) ? "Unavailable" : "Available"); string text2 = ((!readyVikingSnapshot.LocalPlayerAvailable) ? "no" : "yes"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[ReadyViking] Snapshot status: " + text + "; local player available: " + text2)); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("[ReadyViking] Weapon snapshot: state=", readyVikingSnapshot.Weapon.State, "; name=", readyVikingSnapshot.Weapon.Name, "; current=", readyVikingSnapshot.Weapon.CurrentDurability, "; max=", readyVikingSnapshot.Weapon.MaxDurability, "; percent=", readyVikingSnapshot.Weapon.DurabilityPercent)); string text3 = ((!readyVikingSnapshot.Rested.IsRested) ? "no" : "yes"); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("[ReadyViking] Rested snapshot: state=", readyVikingSnapshot.Rested.State, "; rested=", text3, "; remaining=", readyVikingSnapshot.Rested.RemainingSeconds)); string text4 = ((!readyVikingSnapshot.Ammo.RequiresAmmo) ? "no" : "yes"); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("[ReadyViking] Ammo snapshot: state=", readyVikingSnapshot.Ammo.State, "; required=", text4, "; type=", readyVikingSnapshot.Ammo.AmmoType, "; available=", readyVikingSnapshot.Ammo.AvailableAmmo)); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("[ReadyViking] Inventory snapshot: slotsState=", readyVikingSnapshot.Inventory.SlotsState, "; free=", readyVikingSnapshot.Inventory.FreeSlots, "; total=", readyVikingSnapshot.Inventory.TotalSlots, "; weightState=", readyVikingSnapshot.Inventory.WeightState, "; current=", readyVikingSnapshot.Inventory.CurrentWeight, "; max=", readyVikingSnapshot.Inventory.MaxWeight)); } } } internal static class PluginInfo { public const string Guid = "com.goblinstudio.readyviking"; public const string Name = "ReadyViking"; public const string Version = "0.1.0"; } } namespace ReadyViking.Runtime { internal sealed class ReadyVikingSnapshotCollector { public ReadyVikingSnapshot Collect() { //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Unknown result type (might be due to invalid IL or missing references) //IL_074c: Unknown result type (might be due to invalid IL or missing references) //IL_0751: Unknown result type (might be due to invalid IL or missing references) //IL_0753: Unknown result type (might be due to invalid IL or missing references) //IL_0757: Invalid comparison between Unknown and I4 //IL_075c: Unknown result type (might be due to invalid IL or missing references) //IL_0760: Invalid comparison between Unknown and I4 //IL_0765: Unknown result type (might be due to invalid IL or missing references) //IL_0768: Invalid comparison between Unknown and I4 Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return new ReadyVikingSnapshot(SnapshotStatus.Unavailable, new ActiveMealsSnapshot(CheckState.NotApplicable, 0, new List()), new WeaponSnapshot(CheckState.NotApplicable, string.Empty, 0f, 0f, 0f), new RestedSnapshot(CheckState.NotApplicable, isRested: false, 0f), new AmmoSnapshot(CheckState.NotApplicable, requiresAmmo: false, string.Empty, 0), new InventorySnapshot(CheckState.NotApplicable, 0, 0, CheckState.NotApplicable, 0f, 0f)); } Inventory val = null; bool flag = false; try { val = ((Humanoid)localPlayer).GetInventory(); flag = true; } catch (Exception) { val = null; } InventorySnapshot inventory; if (!flag || val == null) { inventory = new InventorySnapshot(CheckState.Unknown, 0, 0, CheckState.Unknown, 0f, 0f); } else { int num = 0; int num2 = 0; CheckState slotsState; try { int emptySlots = val.GetEmptySlots(); int width = val.GetWidth(); int height = val.GetHeight(); long num3 = (long)width * (long)height; if (width < 0 || height < 0 || num3 < 0 || num3 > int.MaxValue || emptySlots < 0 || emptySlots > num3) { throw new InvalidOperationException("Invalid inventory slot data"); } slotsState = CheckState.Ready; num = emptySlots; num2 = (int)num3; } catch (Exception) { slotsState = CheckState.Unknown; num = 0; num2 = 0; } float num4 = 0f; float num5 = 0f; CheckState weightState; try { float totalWeight = val.GetTotalWeight(); float maxCarryWeight = localPlayer.GetMaxCarryWeight(); if (float.IsNaN(totalWeight) || float.IsInfinity(totalWeight) || totalWeight < 0f || float.IsNaN(maxCarryWeight) || float.IsInfinity(maxCarryWeight) || maxCarryWeight <= 0f) { throw new InvalidOperationException("Invalid inventory weight data"); } weightState = CheckState.Ready; num4 = totalWeight; num5 = maxCarryWeight; } catch (Exception) { weightState = CheckState.Unknown; num4 = 0f; num5 = 0f; } inventory = new InventorySnapshot(slotsState, num, num2, weightState, num4, num5); } ActiveMealsSnapshot activeMeals; try { List foods = localPlayer.GetFoods(); if (foods == null) { activeMeals = new ActiveMealsSnapshot(CheckState.Unknown, 0, new List()); } else { List list = new List(foods.Count); bool flag2 = true; foreach (Food item in foods) { if (item == null || string.IsNullOrWhiteSpace(item.m_name) || float.IsNaN(item.m_time) || float.IsInfinity(item.m_time) || item.m_time < 0f) { flag2 = false; break; } list.Add(new ActiveMealSnapshot(item.m_name, item.m_time)); } if (!flag2) { activeMeals = new ActiveMealsSnapshot(CheckState.Unknown, 0, new List()); } else { CheckState state = ((list.Count == 0) ? CheckState.Missing : ((list.Count < 3) ? CheckState.Warning : CheckState.Ready)); activeMeals = new ActiveMealsSnapshot(state, list.Count, list); } } } catch (Exception) { activeMeals = new ActiveMealsSnapshot(CheckState.Unknown, 0, new List()); } ItemData val2 = null; SharedData val3 = null; bool flag3 = false; bool flag4 = false; bool flag5 = false; WeaponSnapshot weapon; try { val2 = ((Humanoid)localPlayer).GetCurrentWeapon(); flag3 = true; if (val2 == null) { weapon = new WeaponSnapshot(CheckState.NotApplicable, string.Empty, 0f, 0f, 0f); } else { val3 = val2.m_shared; if (val3 == null) { weapon = new WeaponSnapshot(CheckState.Unknown, string.Empty, 0f, 0f, 0f); } else if (string.IsNullOrWhiteSpace(val3.m_name)) { weapon = new WeaponSnapshot(CheckState.Unknown, string.Empty, 0f, 0f, 0f); } else { flag5 = val2.IsWeapon(); flag4 = true; if (!flag5) { weapon = (((int)val3.m_itemType != 0) ? new WeaponSnapshot(CheckState.Unknown, val3.m_name, 0f, 0f, 0f) : new WeaponSnapshot(CheckState.NotApplicable, val3.m_name, 0f, 0f, 0f)); } else if (!val3.m_useDurability) { weapon = new WeaponSnapshot(CheckState.NotApplicable, val3.m_name, 0f, 0f, 0f); } else { float durability = val2.m_durability; float maxDurability = val2.GetMaxDurability(); if (float.IsNaN(durability) || float.IsInfinity(durability) || durability < 0f || float.IsNaN(maxDurability) || float.IsInfinity(maxDurability) || maxDurability <= 0f || durability > maxDurability) { weapon = new WeaponSnapshot(CheckState.Unknown, val3.m_name, 0f, 0f, 0f); } else { float durabilityPercent = Mathf.Clamp(durability / maxDurability * 100f, 0f, 100f); weapon = new WeaponSnapshot(CheckState.Ready, val3.m_name, durability, maxDurability, durabilityPercent); } } } } } catch (Exception) { weapon = new WeaponSnapshot(CheckState.Unknown, string.Empty, 0f, 0f, 0f); } RestedSnapshot rested; try { SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan == null) { rested = new RestedSnapshot(CheckState.Unknown, isRested: false, 0f); } else { StatusEffect statusEffect = sEMan.GetStatusEffect(SEMan.s_statusEffectRested); if ((Object)(object)statusEffect == (Object)null) { rested = new RestedSnapshot(CheckState.Missing, isRested: false, 0f); } else { float remaningTime = statusEffect.GetRemaningTime(); rested = ((!float.IsNaN(remaningTime) && !float.IsInfinity(remaningTime) && !(remaningTime <= 0f)) ? new RestedSnapshot(CheckState.Ready, isRested: true, remaningTime) : new RestedSnapshot(CheckState.Unknown, isRested: false, 0f)); } } } catch (Exception) { rested = new RestedSnapshot(CheckState.Unknown, isRested: false, 0f); } string text = string.Empty; bool requiresAmmo = false; AmmoSnapshot ammo; try { if (!flag3) { ammo = new AmmoSnapshot(CheckState.Unknown, requiresAmmo: false, string.Empty, 0); } else if (val2 == null) { ammo = new AmmoSnapshot(CheckState.NotApplicable, requiresAmmo: false, string.Empty, 0); } else if (val3 == null || !flag4) { ammo = new AmmoSnapshot(CheckState.Unknown, requiresAmmo: false, string.Empty, 0); } else if (!flag5) { ammo = (((int)val3.m_itemType != 0) ? new AmmoSnapshot(CheckState.Unknown, requiresAmmo: false, string.Empty, 0) : new AmmoSnapshot(CheckState.NotApplicable, requiresAmmo: false, string.Empty, 0)); } else { text = val3.m_ammoType; if (string.IsNullOrWhiteSpace(text)) { ammo = new AmmoSnapshot(CheckState.NotApplicable, requiresAmmo: false, string.Empty, 0); } else { requiresAmmo = true; if (!flag || val == null) { ammo = new AmmoSnapshot(CheckState.Unknown, requiresAmmo: true, text, 0); } else { List allItems = val.GetAllItems(); if (allItems == null) { ammo = new AmmoSnapshot(CheckState.Unknown, requiresAmmo: true, text, 0); } else { long num6 = 0L; bool flag6 = false; foreach (ItemData item2 in allItems) { if (item2 == null || item2.m_shared == null) { flag6 = true; break; } if (!string.Equals(item2.m_shared.m_ammoType, text, StringComparison.Ordinal)) { continue; } ItemType itemType = item2.m_shared.m_itemType; if ((int)itemType != 9 && (int)itemType != 23 && (int)itemType != 2) { if (item2.IsWeapon()) { continue; } flag6 = true; break; } if (item2.m_stack <= 0) { flag6 = true; break; } num6 += item2.m_stack; if (num6 <= int.MaxValue) { continue; } flag6 = true; break; } ammo = (flag6 ? new AmmoSnapshot(CheckState.Unknown, requiresAmmo: true, text, 0) : ((num6 <= 0) ? new AmmoSnapshot(CheckState.Missing, requiresAmmo: true, text, 0) : new AmmoSnapshot(CheckState.Ready, requiresAmmo: true, text, (int)num6))); } } } } } catch (Exception) { ammo = new AmmoSnapshot(CheckState.Unknown, requiresAmmo, text, 0); } return new ReadyVikingSnapshot(SnapshotStatus.Available, activeMeals, weapon, rested, ammo, inventory); } } internal static class StaticTestReportFactory { public static ReadinessReport Create() { return CreateReport(new CheckResult("Meals", CheckState.Ready, "Three active meals")); } public static ReadinessReport Create(ActiveMealsSnapshot activeMeals, WeaponSnapshot weapon, float weaponDurabilityWarningPercent, RestedSnapshot rested, AmmoSnapshot ammo, InventorySnapshot inventory) { return CreateReport(new CheckResult(string.Empty, activeMeals.State, CreateActiveMealsDetail(activeMeals)), CreateWeaponCheck(weapon, weaponDurabilityWarningPercent), CreateRestedCheck(rested), CreateAmmoCheck(ammo), CreateInventoryCheck(inventory)); } private static ReadinessReport CreateReport(CheckResult mealsCheck, CheckResult weaponCheck = null, CheckResult restedCheck = null, CheckResult ammoCheck = null, CheckResult inventoryCheck = null) { if (weaponCheck == null) { weaponCheck = new CheckResult("Weapon", CheckState.Warning, "Sword durability: 28%"); } if (restedCheck == null) { restedCheck = new CheckResult("Rested", CheckState.Ready, "14 min"); } if (ammoCheck == null) { ammoCheck = new CheckResult("Ammo", CheckState.Missing, "No matching ammunition"); } if (inventoryCheck == null) { inventoryCheck = new CheckResult("Inventory", CheckState.Unknown, "Inventory status unknown"); } return new ReadinessReport("READY TO LEAVE?", new List { mealsCheck, restedCheck, weaponCheck, ammoCheck, inventoryCheck }); } private static string CreateActiveMealsDetail(ActiveMealsSnapshot activeMeals) { switch (activeMeals.State) { case CheckState.Ready: case CheckState.Warning: case CheckState.Missing: return "Active meals: " + activeMeals.ActiveMealCount; case CheckState.NotApplicable: return "Active meals unavailable"; default: return "Active meals unknown"; } } private static CheckResult CreateRestedCheck(RestedSnapshot rested) { if (rested == null) { return new CheckResult(string.Empty, CheckState.Unknown, "Rested status unknown"); } switch (rested.State) { case CheckState.Ready: { if (!rested.IsRested || float.IsNaN(rested.RemainingSeconds) || float.IsInfinity(rested.RemainingSeconds) || rested.RemainingSeconds <= 0f) { return new CheckResult(string.Empty, CheckState.Unknown, "Rested status unknown"); } int num = Mathf.Max(1, Mathf.FloorToInt(rested.RemainingSeconds / 60f)); return new CheckResult(string.Empty, CheckState.Ready, "Rested: " + num + " min"); } case CheckState.Missing: return new CheckResult(string.Empty, CheckState.Missing, "Rested not active"); case CheckState.NotApplicable: return new CheckResult(string.Empty, CheckState.NotApplicable, "Rested unavailable"); default: return new CheckResult(string.Empty, CheckState.Unknown, "Rested status unknown"); } } private static CheckResult CreateAmmoCheck(AmmoSnapshot ammo) { if (ammo == null) { return new CheckResult(string.Empty, CheckState.Unknown, "Ammo status unknown"); } switch (ammo.State) { case CheckState.Ready: if (!ammo.RequiresAmmo || string.IsNullOrWhiteSpace(ammo.AmmoType) || ammo.AvailableAmmo <= 0) { return new CheckResult(string.Empty, CheckState.Unknown, "Ammo status unknown"); } return new CheckResult(string.Empty, CheckState.Ready, "Ammo: " + ammo.AvailableAmmo); case CheckState.Missing: if (!ammo.RequiresAmmo || string.IsNullOrWhiteSpace(ammo.AmmoType) || ammo.AvailableAmmo != 0) { return new CheckResult(string.Empty, CheckState.Unknown, "Ammo status unknown"); } return new CheckResult(string.Empty, CheckState.Missing, "Ammo: none"); case CheckState.NotApplicable: if (ammo.RequiresAmmo || !string.IsNullOrWhiteSpace(ammo.AmmoType) || ammo.AvailableAmmo != 0) { return new CheckResult(string.Empty, CheckState.Unknown, "Ammo status unknown"); } return new CheckResult(string.Empty, CheckState.NotApplicable, "Ammo not applicable"); default: return new CheckResult(string.Empty, CheckState.Unknown, "Ammo status unknown"); } } private static CheckResult CreateInventoryCheck(InventorySnapshot inventory) { if (inventory == null) { return new CheckResult(string.Empty, CheckState.Unknown, "Inventory status unknown"); } bool flag = inventory.SlotsState == CheckState.Ready && inventory.FreeSlots >= 0 && inventory.TotalSlots >= 0 && inventory.FreeSlots <= inventory.TotalSlots; bool flag2 = inventory.WeightState == CheckState.Ready && !float.IsNaN(inventory.CurrentWeight) && !float.IsInfinity(inventory.CurrentWeight) && inventory.CurrentWeight >= 0f && !float.IsNaN(inventory.MaxWeight) && !float.IsInfinity(inventory.MaxWeight) && inventory.MaxWeight > 0f; bool flag3 = inventory.SlotsState == CheckState.NotApplicable && inventory.FreeSlots == 0 && inventory.TotalSlots == 0; bool flag4 = inventory.WeightState == CheckState.NotApplicable && inventory.CurrentWeight == 0f && inventory.MaxWeight == 0f; bool flag5 = inventory.SlotsState == CheckState.Unknown && inventory.FreeSlots == 0 && inventory.TotalSlots == 0; bool flag6 = inventory.WeightState == CheckState.Unknown && inventory.CurrentWeight == 0f && inventory.MaxWeight == 0f; if (flag && flag2) { CheckState state = ((inventory.FreeSlots == 0 || inventory.CurrentWeight >= inventory.MaxWeight) ? CheckState.Warning : CheckState.Ready); return new CheckResult(string.Empty, state, "Inventory: " + inventory.FreeSlots + " free | " + FormatWeight(inventory.CurrentWeight) + "/" + FormatWeight(inventory.MaxWeight)); } if (flag3 && flag4) { return new CheckResult(string.Empty, CheckState.NotApplicable, "Inventory unavailable"); } if (flag && flag6) { return new CheckResult(string.Empty, CheckState.Unknown, "Inventory: " + inventory.FreeSlots + " free | weight unknown"); } if (flag2 && flag5) { return new CheckResult(string.Empty, CheckState.Unknown, "Inventory: slots unknown | " + FormatWeight(inventory.CurrentWeight) + "/" + FormatWeight(inventory.MaxWeight)); } return new CheckResult(string.Empty, CheckState.Unknown, "Inventory status unknown"); } private static string FormatWeight(float value) { return value.ToString("0.#", CultureInfo.CurrentCulture); } private static CheckResult CreateWeaponCheck(WeaponSnapshot weapon, float warningPercent) { if (weapon == null) { return new CheckResult(string.Empty, CheckState.Unknown, "Weapon status unknown"); } string displayName = GetDisplayName(weapon.Name); switch (weapon.State) { case CheckState.Ready: { if (string.IsNullOrWhiteSpace(displayName)) { return new CheckResult(string.Empty, CheckState.Unknown, "Weapon status unknown"); } float num = Mathf.Clamp(weapon.DurabilityPercent, 0f, 100f); int num2 = Mathf.RoundToInt(num); CheckState state = ((num <= Mathf.Clamp(warningPercent, 0f, 100f)) ? CheckState.Warning : CheckState.Ready); return new CheckResult(string.Empty, state, displayName + ": " + num2 + "%"); } case CheckState.NotApplicable: if (string.IsNullOrWhiteSpace(displayName) || IsUnarmedName(weapon.Name)) { return new CheckResult(string.Empty, CheckState.NotApplicable, "No weapon equipped"); } return new CheckResult(string.Empty, CheckState.NotApplicable, displayName + ": no durability"); case CheckState.Unknown: if (string.IsNullOrWhiteSpace(displayName)) { return new CheckResult(string.Empty, CheckState.Unknown, "Weapon status unknown"); } return new CheckResult(string.Empty, CheckState.Unknown, displayName + ": durability unknown"); default: return new CheckResult(string.Empty, CheckState.Unknown, "Weapon status unknown"); } } private static string GetDisplayName(string copiedName) { if (string.IsNullOrWhiteSpace(copiedName)) { return string.Empty; } if (!copiedName.StartsWith("$")) { return copiedName; } try { if (Localization.instance != null) { string text = Localization.instance.Localize(copiedName); if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("$")) { return text; } } } catch { } return copiedName; } private static bool IsUnarmedName(string copiedName) { return string.Equals(copiedName, "Unarmed", StringComparison.OrdinalIgnoreCase); } } }