using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UltimateLethal.CrewMorale")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("UltimateLethal.CrewMorale")] [assembly: AssemblyTitle("UltimateLethal.CrewMorale")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UltimateLethal.CrewMorale { [BepInPlugin("ultimatelethal.crewmorale", "Ultimate Lethal Crew Morale", "0.1.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class CrewMoralePlugin : BaseUnityPlugin { public const string Guid = "ultimatelethal.crewmorale"; public const string Name = "Ultimate Lethal Crew Morale"; public const string Version = "0.1.6"; internal static CrewMoralePlugin Instance; internal static ConfigEntry StartingMorale; internal static ConfigEntry MinimumMorale; internal static ConfigEntry MaximumMorale; internal static ConfigEntry DecorationPriceScaleCredits; internal static ConfigEntry DecorationPriceExponent; internal static ConfigEntry DecorationMaxMoraleEach; internal static ConfigEntry DecorationBonusCap; internal static ConfigEntry DeathPenalty; internal static ConfigEntry ReunionReward; internal static ConfigEntry QuotaFulfilledReward; internal static ConfigEntry FullCrewShipRecoveryPerSecond; internal static ConfigEntry OrbitRecoveryPerSecond; internal static ConfigEntry EmptyShipDecayPerSecond; internal static ConfigEntry HighMoraleSanityGainMultiplier; internal static ConfigEntry LowMoraleSanityGainMultiplier; internal static ConfigEntry HighMoraleRecoveryMultiplier; internal static ConfigEntry LowMoraleRecoveryMultiplier; internal static ConfigEntry ShowHud; internal static ConfigEntry HudX; internal static ConfigEntry HudY; internal static ConfigEntry HudWidth; internal static ConfigEntry HudHeight; internal static ConfigEntry SanityHudRaisePixels; private Harmony _harmony; private float _nextStateTick; private bool _wasFullLivingCrewInShip; private bool _wasLanded; private bool _someoneLeftShipThisExpedition; private bool _expeditionHadDeath; private bool _reunionAwardedThisExpedition; private int _expeditionStartingCrewCount; private readonly HashSet _expeditionRoster = new HashSet(); private readonly HashSet _countedDeadPlayers = new HashSet(); private bool _quotaStateInitialized; private bool _quotaWasFulfilled; private float _previousDecorationBonus = -1f; private float _eventUntil; private string _eventTitle = ""; private string _eventDetail = ""; private GUIStyle _labelStyle; private GUIStyle _smallStyle; private GUIStyle _eventTitleStyle; private GUIStyle _eventDetailStyle; private Texture2D _pixel; internal static float Morale { get; private set; } = 55f; internal static float DecorationBaseline { get; private set; } = 0f; internal static int DecorationCount { get; private set; } = 0; private void Awake() { //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Expected O, but got Unknown Instance = this; StartingMorale = ((BaseUnityPlugin)this).Config.Bind("Morale", "StartingMorale", 55f, "Morale at the beginning of a session."); MinimumMorale = ((BaseUnityPlugin)this).Config.Bind("Morale", "MinimumMorale", 0f, "Minimum morale."); MaximumMorale = ((BaseUnityPlugin)this).Config.Bind("Morale", "MaximumMorale", 100f, "Maximum morale."); DecorationPriceScaleCredits = ((BaseUnityPlugin)this).Config.Bind("Decorations", "PriceScaleCredits", 200f, "Price divisor used by the decoration morale curve."); DecorationPriceExponent = ((BaseUnityPlugin)this).Config.Bind("Decorations", "PriceExponent", 1.15f, "Exponent used by the decoration morale curve. Values above 1 make expensive decorations more efficient."); DecorationMaxMoraleEach = ((BaseUnityPlugin)this).Config.Bind("Decorations", "MaxMoralePerDecoration", 10f, "Maximum morale a single decoration can contribute regardless of price."); DecorationBonusCap = ((BaseUnityPlugin)this).Config.Bind("Decorations", "DecorationBonusCap", 20f, "Maximum total baseline morale supplied by all decorations."); DeathPenalty = ((BaseUnityPlugin)this).Config.Bind("Events", "DeathPenalty", 18f, "Immediate morale loss per crew death."); ReunionReward = ((BaseUnityPlugin)this).Config.Bind("Events", "PerfectReunionReward", 10f, "Morale gained when everyone who started the expedition returns to the ship alive after someone has left it."); QuotaFulfilledReward = ((BaseUnityPlugin)this).Config.Bind("Events", "QuotaFulfilledReward", 15f, "Morale gained once when the current quota becomes fulfilled."); FullCrewShipRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind("Events", "FullCrewShipRecoveryPerSecond", 0.00833333f, "Passive morale recovery while the full living crew is together inside the ship (+0.5 morale/minute)."); OrbitRecoveryPerSecond = ((BaseUnityPlugin)this).Config.Bind("Events", "OrbitRecoveryPerSecond", 0.0166667f, "Additional passive morale recovery while the ship is safely in orbit (+1 morale/minute)."); EmptyShipDecayPerSecond = ((BaseUnityPlugin)this).Config.Bind("Events", "EmptyShipDecayPerSecond", 0.03f, "Morale decay while nobody living is in the ship."); MigrateLegacyBalanceValues(); HighMoraleSanityGainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sanity", "HighMoraleSanityGainMultiplier", 0.6f, "At 100 morale, positive insanity gain is multiplied by this."); LowMoraleSanityGainMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sanity", "LowMoraleSanityGainMultiplier", 1.3f, "At 0 morale, positive insanity gain is multiplied by this."); HighMoraleRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sanity", "HighMoraleRecoveryMultiplier", 1.45f, "At 100 morale, negative insanity change (recovery) is multiplied by this."); LowMoraleRecoveryMultiplier = ((BaseUnityPlugin)this).Config.Bind("Sanity", "LowMoraleRecoveryMultiplier", 0.65f, "At 0 morale, negative insanity change (recovery) is multiplied by this."); ShowHud = ((BaseUnityPlugin)this).Config.Bind("HUD", "ShowMoraleBar", true, "Show Crew Morale while the local player is in the ship."); HudX = ((BaseUnityPlugin)this).Config.Bind("HUD", "X", 0.5f, "Horizontal screen anchor (0 to 1)."); HudY = ((BaseUnityPlugin)this).Config.Bind("HUD", "Y", 0.105f, "Vertical screen anchor (0 to 1)."); HudWidth = ((BaseUnityPlugin)this).Config.Bind("HUD", "Width", 260f, "Morale bar width in pixels."); HudHeight = ((BaseUnityPlugin)this).Config.Bind("HUD", "Height", 14f, "Morale bar height in pixels."); SanityHudRaisePixels = ((BaseUnityPlugin)this).Config.Bind("HUD", "SanityHudRaisePixels", 360f, "Moves InsanityMod's bottom-right sanity ring upward by this many pixels."); Morale = Clamp(StartingMorale.Value); _harmony = new Harmony("ultimatelethal.crewmorale"); _harmony.PatchAll(); TryPatchInsanityMod(); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Starting morale: {2:0}", "Ultimate Lethal Crew Morale", "0.1.6", Morale)); } private void MigrateLegacyBalanceValues() { if (Mathf.Approximately(DeathPenalty.Value, 12f)) { DeathPenalty.Value = 18f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy DeathPenalty 12 -> 18."); } if (Mathf.Approximately(FullCrewShipRecoveryPerSecond.Value, 0.2f) || Mathf.Approximately(FullCrewShipRecoveryPerSecond.Value, 0.07f) || Mathf.Approximately(FullCrewShipRecoveryPerSecond.Value, 0.03f)) { FullCrewShipRecoveryPerSecond.Value = 0.00833333f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy full-crew passive recovery -> +0.5 morale/minute."); } if (Mathf.Approximately(OrbitRecoveryPerSecond.Value, 0.35f) || Mathf.Approximately(OrbitRecoveryPerSecond.Value, 0.12f) || Mathf.Approximately(OrbitRecoveryPerSecond.Value, 0.05f)) { OrbitRecoveryPerSecond.Value = 0.0166667f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy orbit passive recovery -> +1 morale/minute."); } } private void Start() { _expeditionRoster.Clear(); _countedDeadPlayers.Clear(); } private void Update() { if (!(Time.unscaledTime < _nextStateTick)) { float num = 0.25f; _nextStateTick = Time.unscaledTime + num; AdjustInsanityHudPosition(); if (!((Object)(object)StartOfRound.Instance == (Object)null)) { RefreshDecorationBaseline(); ApplyWorldState(num); } } } private static void AdjustInsanityHudPosition() { //IL_004d: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("InsanityHud_Root"); if ((Object)(object)val == (Object)null) { return; } RectTransform component = val.GetComponent(); if (!((Object)(object)component == (Object)null)) { float num = 130f + Mathf.Max(0f, SanityHudRaisePixels?.Value ?? 360f); Vector2 anchoredPosition = component.anchoredPosition; if (Mathf.Abs(anchoredPosition.y - num) > 0.1f) { component.anchoredPosition = new Vector2(anchoredPosition.x, num); } } } private void ApplyWorldState(float dt) { StartOfRound instance = StartOfRound.Instance; bool flag = (Object)(object)instance != (Object)null && instance.shipHasLanded; if (flag && !_wasLanded) { CaptureExpeditionRoster(); _expeditionStartingCrewCount = _expeditionRoster.Count; _someoneLeftShipThisExpedition = false; _expeditionHadDeath = false; _reunionAwardedThisExpedition = false; } int num = DetectNewExpeditionDeaths(); if (num > 0) { _expeditionHadDeath = true; float num2 = DeathPenalty.Value * (float)num; ChangeMorale(0f - num2, "crew death"); ShowEvent("CREW MEMBER LOST", $"-{num2:0.#} MORALE"); } int num3 = CountLivingExpeditionPlayers(); int num4 = CountLivingExpeditionPlayersInShip(); bool flag2 = num3 > 0 && num4 == num3; if (flag && num3 > 0 && num4 < num3) { _someoneLeftShipThisExpedition = true; } if (flag && _someoneLeftShipThisExpedition && !_expeditionHadDeath && !_reunionAwardedThisExpedition && _expeditionStartingCrewCount > 0 && num3 == _expeditionStartingCrewCount && flag2) { ChangeMorale(ReunionReward.Value, "perfect crew reunion"); ShowEvent("CREW REUNITED", $"+{ReunionReward.Value:0.#} MORALE"); _reunionAwardedThisExpedition = true; } UpdateQuotaReward(); bool num5 = IsInOrbit(); float num6 = 0f; if (flag2) { num6 += FullCrewShipRecoveryPerSecond.Value; } if (num5) { num6 += OrbitRecoveryPerSecond.Value; } if (num6 > 0f) { MoveTowardMorale(DecorationBaseline, num6 * dt); } else if (num3 > 0 && num4 == 0 && EmptyShipDecayPerSecond.Value > 0f) { ChangeMorale((0f - EmptyShipDecayPerSecond.Value) * dt, "empty ship"); } _wasFullLivingCrewInShip = flag2; _wasLanded = flag; } private void UpdateQuotaReward() { try { TimeOfDay val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(TimeOfDay), "quotaFulfilled"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(TimeOfDay), "profitQuota"); if (fieldInfo == null || fieldInfo2 == null) { return; } int num = Convert.ToInt32(fieldInfo.GetValue(val)); int num2 = Mathf.Max(1, Convert.ToInt32(fieldInfo2.GetValue(val))); bool flag = num >= num2; if (!_quotaStateInitialized) { _quotaStateInitialized = true; _quotaWasFulfilled = flag; return; } if (flag && !_quotaWasFulfilled) { ChangeMorale(QuotaFulfilledReward.Value, "quota fulfilled"); ShowEvent("QUOTA FULFILLED", $"+{QuotaFulfilledReward.Value:0.#} MORALE"); } _quotaWasFulfilled = flag; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Quota morale check failed: " + ex.Message)); } } private void ShowEvent(string title, string detail, float seconds = 4f) { _eventTitle = title ?? ""; _eventDetail = detail ?? ""; _eventUntil = Time.unscaledTime + seconds; } internal static void ChangeMorale(float amount, string reason = null) { float morale = Morale; Morale = Clamp(Morale + amount); if ((Object)(object)Instance != (Object)null && Mathf.Abs(Morale - morale) >= 0.01f && reason != null) { ((BaseUnityPlugin)Instance).Logger.LogDebug((object)$"Morale {morale:0.0} -> {Morale:0.0} ({reason})"); } } private static void MoveTowardMorale(float target, float maxDelta) { target = Clamp(target); Morale = Mathf.MoveTowards(Morale, target, Mathf.Max(0f, maxDelta)); } private static float Clamp(float value) { return Mathf.Clamp(value, MinimumMorale?.Value ?? 0f, MaximumMorale?.Value ?? 100f); } private void RefreshDecorationBaseline() { try { StartOfRound instance = StartOfRound.Instance; if (instance?.unlockablesList?.unlockables == null) { return; } int num = 0; float num2 = 0f; foreach (UnlockableItem unlockable in instance.unlockablesList.unlockables) { if (unlockable != null && unlockable.unlockableType == 1 && !unlockable.alreadyUnlocked && unlockable.hasBeenUnlockedByPlayer && !unlockable.inStorage) { int num3 = 0; if ((Object)(object)unlockable.shopSelectionNode != (Object)null) { num3 = Mathf.Max(0, unlockable.shopSelectionNode.itemCost); } float num4 = Mathf.Max(1f, DecorationPriceScaleCredits.Value); float num5 = Mathf.Max(0.01f, DecorationPriceExponent.Value); float num6 = Mathf.Pow(Mathf.Max(0f, (float)num3) / num4, num5); num6 = Mathf.Clamp(num6, 0f, DecorationMaxMoraleEach.Value); num2 += num6; num++; } } DecorationCount = num; float num7 = Mathf.Min(DecorationBonusCap.Value, num2); DecorationBaseline = Clamp(StartingMorale.Value + num7); if (_previousDecorationBonus >= 0f && Mathf.Abs(num7 - _previousDecorationBonus) >= 0.1f) { float num8 = num7 - _previousDecorationBonus; if (num8 > 0f) { ShowEvent("SHIP DECOR IMPROVED", $"+{num8:0.##} MORALE • DECOR {num7:0.##}/{DecorationBonusCap.Value:0}"); } else { ShowEvent("DECORATION REMOVED", $"{num8:0.##} MORALE • DECOR {num7:0.##}/{DecorationBonusCap.Value:0}"); } } _previousDecorationBonus = num7; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogDebug((object)("Decoration scan failed: " + ex.Message)); } } private void CaptureExpeditionRoster() { _expeditionRoster.Clear(); _countedDeadPlayers.Clear(); PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return; } PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead) { _expeditionRoster.Add(val); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Captured expedition roster: {_expeditionRoster.Count} crew member(s)."); } private int DetectNewExpeditionDeaths() { int num = 0; foreach (PlayerControllerB item in _expeditionRoster) { if (!((Object)(object)item == (Object)null) && item.isPlayerDead && !_countedDeadPlayers.Contains(item)) { _countedDeadPlayers.Add(item); num++; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Crew death detected from expedition roster. Counted deaths: {_countedDeadPlayers.Count}/{_expeditionRoster.Count}"); } } return num; } private int CountLivingExpeditionPlayers() { int num = 0; foreach (PlayerControllerB item in _expeditionRoster) { if ((Object)(object)item != (Object)null && !item.isPlayerDead) { num++; } } return num; } private int CountLivingExpeditionPlayersInShip() { int num = 0; foreach (PlayerControllerB item in _expeditionRoster) { if (!((Object)(object)item == (Object)null) && !item.isPlayerDead && IsPlayerInShip(item)) { num++; } } return num; } private static int CountLivingPlayers() { PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return 0; } int num = 0; PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead) { num++; } } return num; } private static int CountDeadPlayers() { PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return 0; } int num = 0; PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && val.isPlayerDead) { num++; } } return num; } private static int CountLivingPlayersInShip() { PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts; if (array == null) { return 0; } int num = 0; PlayerControllerB[] array2 = array; foreach (PlayerControllerB val in array2) { if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead && IsPlayerInShip(val)) { num++; } } return num; } internal static bool IsPlayerInShip(PlayerControllerB player) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if (player.isInHangarShipRoom) { return true; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } Vector3 position = ((Component)player).transform.position; Bounds bounds; if ((Object)(object)instance.shipInnerRoomBounds != (Object)null) { bounds = instance.shipInnerRoomBounds.bounds; if (((Bounds)(ref bounds)).Contains(position)) { return true; } } if ((Object)(object)instance.shipBounds != (Object)null) { bounds = instance.shipBounds.bounds; if (((Bounds)(ref bounds)).Contains(position)) { return true; } } return false; } private static bool IsInOrbit() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (instance.inShipPhase) { return !instance.shipHasLanded; } return false; } private void TryPatchInsanityMod() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("InsanityMod.InsanityCalculator"); Type type2 = AccessTools.TypeByName("InsanityMod.Managers.InsanityModifiers"); Type type3 = AccessTools.TypeByName("InsanityMod.Managers.InsanityManager"); int num = 0; MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "TickDelta", (Type[])null, (Type[])null) : null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(InsanityIntegration), "ScaleTickDelta", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } MethodInfo methodInfo2 = ((type2 != null) ? AccessTools.Method(type2, "ComputeBonusRate", (Type[])null, (Type[])null) : null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(InsanityIntegration), "ScaleBonusRate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } MethodInfo methodInfo3 = ((type3 != null) ? AccessTools.Method(type3, "AddInsanity", (Type[])null, (Type[])null) : null); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(InsanityIntegration), "ScaleSpike", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } ((BaseUnityPlugin)this).Logger.LogInfo((object)((num > 0) ? $"InsanityMod integration active ({num}/3 hooks)." : "InsanityMod not detected; morale will run without sanity integration.")); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Could not patch InsanityMod: {arg}"); } } private void OnGUI() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) if (!ShowHud.Value) { return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val == (Object)null) && IsPlayerInShip(val) && !((Object)(object)HUDManager.Instance == (Object)null)) { EnsureGui(); float num = Mathf.Max(280f, HudWidth.Value); float num2 = Mathf.Max(12f, HudHeight.Value); float num3 = (float)Screen.width * HudX.Value - num * 0.5f; float num4 = (float)Screen.height * HudY.Value; float num5 = Mathf.Max(0f, DecorationBaseline - StartingMorale.Value); string arg = MoraleStatus(Morale); float num6 = InsanityIntegration.GainMultiplier(); float num7 = InsanityIntegration.RecoveryMultiplier(); GUI.Label(new Rect(num3, num4 - 37f, num, 18f), $"CREW MORALE {Morale:0.#} / 100 • {arg}", _labelStyle); GUI.Label(new Rect(num3, num4 - 19f, num, 16f), $"DECOR +{num5:0.##}/{DecorationBonusCap.Value:0} • SANITY ×{num6:0.00} GAIN / ×{num7:0.00} RECOVERY", _smallStyle); Rect val2 = new Rect(num3, num4, num, num2); GUI.color = new Color(0f, 0f, 0f, 0.76f); GUI.DrawTexture(val2, (Texture)(object)_pixel); float num8 = Mathf.InverseLerp(MinimumMorale.Value, MaximumMorale.Value, Morale); Rect val3 = new Rect(num3 + 2f, num4 + 2f, Mathf.Max(0f, (num - 4f) * num8), Mathf.Max(1f, num2 - 4f)); if (Morale >= 80f) { GUI.color = new Color(0.35f, 0.95f, 0.55f, 0.96f); } else if (Morale >= 60f) { GUI.color = new Color(0.25f, 0.88f, 0.72f, 0.96f); } else if (Morale >= 40f) { GUI.color = new Color(0.2f, 0.75f, 0.95f, 0.96f); } else if (Morale >= 20f) { GUI.color = new Color(0.95f, 0.58f, 0.2f, 0.96f); } else { GUI.color = new Color(0.95f, 0.25f, 0.2f, 0.96f); } GUI.DrawTexture(val3, (Texture)(object)_pixel); GUI.color = Color.white; if (Time.unscaledTime < _eventUntil) { float num9 = num4 + num2 + 10f; GUI.Label(new Rect(num3, num9, num, 22f), _eventTitle, _eventTitleStyle); GUI.Label(new Rect(num3, num9 + 21f, num, 18f), _eventDetail, _eventDetailStyle); } } } private static string MoraleStatus(float morale) { if (morale >= 85f) { return "THRIVING"; } if (morale >= 70f) { return "CONFIDENT"; } if (morale >= 50f) { return "STABLE"; } if (morale >= 35f) { return "UNEASY"; } if (morale >= 20f) { return "SHAKEN"; } return "BROKEN"; } private void EnsureGui() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown if ((Object)(object)_pixel == (Object)null) { _pixel = new Texture2D(1, 1); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); } if (_labelStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontSize = 13, fontStyle = (FontStyle)1 }; val.normal.textColor = Color.white; _labelStyle = val; } if (_smallStyle == null) { GUIStyle val2 = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontSize = 10, fontStyle = (FontStyle)0 }; val2.normal.textColor = new Color(0.88f, 0.92f, 0.95f, 1f); _smallStyle = val2; } if (_eventTitleStyle == null) { GUIStyle val3 = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontSize = 16, fontStyle = (FontStyle)1 }; val3.normal.textColor = Color.white; _eventTitleStyle = val3; } if (_eventDetailStyle == null) { GUIStyle val4 = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontSize = 12, fontStyle = (FontStyle)1 }; val4.normal.textColor = new Color(0.9f, 0.95f, 1f, 1f); _eventDetailStyle = val4; } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)_pixel != (Object)null) { Object.Destroy((Object)(object)_pixel); } } } internal static class InsanityIntegration { internal static float Morale01 => Mathf.Clamp01(CrewMoralePlugin.Morale / 100f); internal static float GainMultiplier() { return Mathf.Lerp(CrewMoralePlugin.LowMoraleSanityGainMultiplier.Value, CrewMoralePlugin.HighMoraleSanityGainMultiplier.Value, Morale01); } internal static float RecoveryMultiplier() { return Mathf.Lerp(CrewMoralePlugin.LowMoraleRecoveryMultiplier.Value, CrewMoralePlugin.HighMoraleRecoveryMultiplier.Value, Morale01); } public static void ScaleTickDelta(ref float __result) { __result *= ((__result >= 0f) ? GainMultiplier() : RecoveryMultiplier()); } public static void ScaleBonusRate(ref float __result) { __result *= ((__result >= 0f) ? GainMultiplier() : RecoveryMultiplier()); } public static void ScaleSpike(ref float amount) { if (amount > 0f) { amount *= GainMultiplier(); } else if (amount < 0f) { amount *= RecoveryMultiplier(); } } } [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class RoundStartPatch { [HarmonyPostfix] private static void Postfix() { CrewMoralePlugin.ChangeMorale(CrewMoralePlugin.StartingMorale.Value - CrewMoralePlugin.Morale, "round/session init"); } } }