Decompiled source of FAndCDaveCo v1.4.2

tesinormed.FAndCDaveCo.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Extensions;
using CSync.Lib;
using GameNetcodeStuff;
using HarmonyLib;
using InteractiveTerminalAPI.UI;
using InteractiveTerminalAPI.UI.Application;
using InteractiveTerminalAPI.UI.Cursor;
using InteractiveTerminalAPI.UI.Screen;
using LethalModDataLib.Attributes;
using LethalModDataLib.Base;
using LethalModDataLib.Events;
using LethalNetworkAPI;
using LobbyCompatibility.Attributes;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using tesinormed.FAndCDaveCo.Bank;
using tesinormed.FAndCDaveCo.Bank.UI;
using tesinormed.FAndCDaveCo.Extensions;
using tesinormed.FAndCDaveCo.Insurance;
using tesinormed.FAndCDaveCo.Insurance.UI;
using tesinormed.FAndCDaveCo.Network;

[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("tesinormed.FAndCDaveCo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.2.0")]
[assembly: AssemblyInformationalVersion("1.4.2+d24323540fc75b59040a1f529092f9be9d56ec09")]
[assembly: AssemblyProduct("FAndCDaveCo")]
[assembly: AssemblyTitle("tesinormed.FAndCDaveCo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 tesinormed.FAndCDaveCo
{
	public class Config : SyncedConfig2<Config>
	{
		[SyncedEntryField]
		public readonly SyncedEntry<bool> GameDisableDeathCreditPenalty;

		[SyncedEntryField]
		public readonly SyncedEntry<double> EconomicBasePremium;

		[SyncedEntryField]
		public readonly SyncedEntry<double> EconomicDeductible;

		[SyncedEntryField]
		public readonly SyncedEntry<double> EconomicDeductibleMaximum;

		[SyncedEntryField]
		public readonly SyncedEntry<double> EconomicDeductibleMinimum;

		[SyncedEntryField]
		public readonly SyncedEntry<double> StandardBasePremium;

		[SyncedEntryField]
		public readonly SyncedEntry<double> StandardDeductible;

		[SyncedEntryField]
		public readonly SyncedEntry<double> StandardDeductibleMaximum;

		[SyncedEntryField]
		public readonly SyncedEntry<double> StandardDeductibleMinimum;

		[SyncedEntryField]
		public readonly SyncedEntry<double> BespokeBasePremium;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption00;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption01;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption02;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption03;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption04;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption05;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption06;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption07;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption08;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption09;

		[SyncedEntryField]
		public readonly SyncedEntry<int> CoverageOption10;

		[SyncedEntryField]
		public readonly SyncedEntry<int> ClaimRetentionDays;

		[SyncedEntryField]
		public readonly SyncedEntry<double> ClaimPremiumIncrease;

		[SyncedEntryField]
		public readonly SyncedEntry<int> PenaltyStartDaysFromIssuance;

		[SyncedEntryField]
		public readonly SyncedEntry<double> PenaltyAmount;

		[SyncedEntryField]
		public readonly SyncedEntry<double> InterestAmount;

		public Config(ConfigFile configFile)
			: base("tesinormed.FAndCDaveCo")
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0032: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0066: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_009a: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00ce: Expected O, but got Unknown
			//IL_00df: 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_0102: Expected O, but got Unknown
			//IL_0102: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0136: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_016a: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_019e: Expected O, but got Unknown
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_01d2: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_0206: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Expected O, but got Unknown
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Expected O, but got Unknown
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Expected O, but got Unknown
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Expected O, but got Unknown
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Expected O, but got Unknown
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Expected O, but got Unknown
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Expected O, but got Unknown
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Expected O, but got Unknown
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Expected O, but got Unknown
			//IL_03a5: Expected O, but got Unknown
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Expected O, but got Unknown
			//IL_03d2: Expected O, but got Unknown
			//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Expected O, but got Unknown
			//IL_03fe: Expected O, but got Unknown
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Expected O, but got Unknown
			//IL_0432: Expected O, but got Unknown
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_045c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Expected O, but got Unknown
			//IL_0466: Expected O, but got Unknown
			GameDisableDeathCreditPenalty = SyncedBindingExtensions.BindSyncedEntry<bool>(configFile, new ConfigDefinition("Game", "DisableDeathCreditPenalty"), true, new ConfigDescription("Whether to disable the death credit penalty (only if there is a current insurance policy)", (AcceptableValueBase)null, Array.Empty<object>()));
			EconomicBasePremium = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Economic", "BasePremium"), 0.07, new ConfigDescription("Initial premiums before any additional penalties due to submitted claims", (AcceptableValueBase)null, Array.Empty<object>()));
			EconomicDeductible = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Economic", "Deductible"), 0.25, new ConfigDescription("Percent of claim amount that must be paid before a payout is made", (AcceptableValueBase)null, Array.Empty<object>()));
			EconomicDeductibleMinimum = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Economic", "DeductibleMinimum"), 0.15, new ConfigDescription("Percent of coverage that sets the deductible minimum amount", (AcceptableValueBase)null, Array.Empty<object>()));
			EconomicDeductibleMaximum = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Economic", "DeductibleMaximum"), 0.6, new ConfigDescription("Percent of coverage that sets the deductible maximum amount", (AcceptableValueBase)null, Array.Empty<object>()));
			StandardBasePremium = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Standard", "BasePremium"), 0.15, new ConfigDescription("Initial premiums before any additional penalties due to submitted claims", (AcceptableValueBase)null, Array.Empty<object>()));
			StandardDeductible = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Standard", "Deductible"), 0.1, new ConfigDescription("Percent of claim amount that must be paid before a payout is made", (AcceptableValueBase)null, Array.Empty<object>()));
			StandardDeductibleMinimum = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Standard", "DeductibleMinimum"), 0.1, new ConfigDescription("Percent of coverage that sets the deductible minimum amount", (AcceptableValueBase)null, Array.Empty<object>()));
			StandardDeductibleMaximum = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Standard", "DeductibleMaximum"), 0.3, new ConfigDescription("Percent of coverage that sets the deductible maximum amount", (AcceptableValueBase)null, Array.Empty<object>()));
			BespokeBasePremium = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Policies.Bespoke", "BasePremium"), 0.35, new ConfigDescription("Initial premiums before any additional penalties due to submitted claims", (AcceptableValueBase)null, Array.Empty<object>()));
			CoverageOption00 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option00"), 150, (ConfigDescription)null);
			CoverageOption01 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option01"), 400, (ConfigDescription)null);
			CoverageOption02 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option02"), 800, (ConfigDescription)null);
			CoverageOption03 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option03"), 1500, (ConfigDescription)null);
			CoverageOption04 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option04"), 2250, (ConfigDescription)null);
			CoverageOption05 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option05"), 3600, (ConfigDescription)null);
			CoverageOption06 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option06"), 5500, (ConfigDescription)null);
			CoverageOption07 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option07"), 8000, (ConfigDescription)null);
			CoverageOption08 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option08"), 11125, (ConfigDescription)null);
			CoverageOption09 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option09"), 15250, (ConfigDescription)null);
			CoverageOption10 = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Coverage", "Option10"), 18000, (ConfigDescription)null);
			ClaimPremiumIncrease = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Insurance.Claims", "PremiumIncrease"), 0.25, new ConfigDescription("Percent of the cumulative premium increase for each submitted claim", (AcceptableValueBase)null, Array.Empty<object>()));
			ClaimRetentionDays = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Insurance.Claims", "RetentionDays"), 10, new ConfigDescription("Days that claims are retained in the save (sets the maximum increase for premiums)", (AcceptableValueBase)null, Array.Empty<object>()));
			PenaltyStartDaysFromIssuance = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, new ConfigDefinition("Bank.Loan.Penalty", "StartDaysFromIssuance"), 4, new ConfigDescription("Start of the late penalty in days from the issuance date", (AcceptableValueBase)null, Array.Empty<object>()));
			PenaltyAmount = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Bank.Loan.Penalty", "Amount"), 0.1, new ConfigDescription("Percent of the credits garnished each day", (AcceptableValueBase)null, Array.Empty<object>()));
			InterestAmount = SyncedBindingExtensions.BindSyncedEntry<double>(configFile, new ConfigDefinition("Bank.Loan", "InterestAmount"), 0.05, new ConfigDescription("Percent of the principal added on for interest (only added once)", (AcceptableValueBase)null, Array.Empty<object>()));
			ConfigManager.Register<Config>((SyncedConfig2<Config>)(object)this);
		}
	}
	[BepInPlugin("tesinormed.FAndCDaveCo", "FAndCDaveCo", "1.4.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("com.sigurd.csync", "5.0.0")]
	[LobbyCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Action<Policy> <>9__32_0;

			public static Action<Dictionary<int, PolicyClaim>> <>9__32_1;

			public static Action<Loan> <>9__32_2;

			public static PostSaveGameEventHandler <>9__33_0;

			public static PostLoadGameEventHandler <>9__33_1;

			public static PostDeleteSaveEventHandler <>9__33_2;

			public static PostResetSavedGameValuesEventHandler <>9__33_3;

			internal void <InitNetworkVariables>b__32_0(Policy data)
			{
				PolicyState.Policy = data;
				Logger.LogDebug((object)$"synced policy state policy {data}");
			}

			internal void <InitNetworkVariables>b__32_1(Dictionary<int, PolicyClaim> data)
			{
				PolicyState.Claims = data;
				Logger.LogDebug((object)("synced policy state claims [" + string.Join(", ", data) + "]"));
			}

			internal void <InitNetworkVariables>b__32_2(Loan data)
			{
				BankState.Loan = data;
				Logger.LogDebug((object)$"synced bank state loan {data}");
			}

			internal void <InitState>b__33_0(bool _, string _)
			{
				((ModDataContainer)PolicyState).Save();
				((ModDataContainer)BankState).Save();
			}

			internal void <InitState>b__33_1(bool _, string _)
			{
				((ModDataContainer)PolicyState).Load();
				((ModDataContainer)BankState).Load();
			}

			internal void <InitState>b__33_2(string _)
			{
				PolicyState.ResetAndSync();
				BankState.ResetAndSync();
				HUDManagerEvents.QueuedHudTips.Clear();
			}

			internal void <InitState>b__33_3()
			{
				PolicyState.ResetAndSync();
				BankState.ResetAndSync();
				HUDManagerEvents.QueuedHudTips.Clear();
				((ModDataContainer)PolicyState).Save();
				((ModDataContainer)BankState).Save();
			}
		}

		public static readonly LethalNetworkVariable<Policy> SyncedPolicy = new LethalNetworkVariable<Policy>("Policy");

		public static readonly LethalNetworkVariable<Dictionary<int, PolicyClaim>> SyncedClaims = new LethalNetworkVariable<Dictionary<int, PolicyClaim>>("Claims");

		public static readonly LethalNetworkVariable<Loan> SyncedLoan = new LethalNetworkVariable<Loan>("Loan");

		internal static ManualLogSource Logger { get; private set; } = null;


		public static Plugin Instance { get; private set; } = null;


		internal static Config Config { get; private set; } = null;


		internal static Harmony? Harmony { get; set; }

		public static Terminal Terminal { get; set; } = null;


		public static PolicyState PolicyState { get; private set; } = null;


		public static BankState BankState { get; private set; } = null;


		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Config = new Config(((BaseUnityPlugin)this).Config);
			InitNetworkVariables();
			InitState();
			RegisterTerminal();
			NetworkVariableEvents.Init();
			CreditEvents.Init();
			HUDManagerEvents.Init();
			Patch();
			Logger.LogInfo((object)"tesinormed.FAndCDaveCo (FAndCDaveCo) version 1.4.2 loaded");
		}

		private void InitNetworkVariables()
		{
			SyncedPolicy.OnValueChanged += delegate(Policy data)
			{
				PolicyState.Policy = data;
				Logger.LogDebug((object)$"synced policy state policy {data}");
			};
			SyncedClaims.OnValueChanged += delegate(Dictionary<int, PolicyClaim> data)
			{
				PolicyState.Claims = data;
				Logger.LogDebug((object)("synced policy state claims [" + string.Join(", ", data) + "]"));
			};
			SyncedLoan.OnValueChanged += delegate(Loan data)
			{
				BankState.Loan = data;
				Logger.LogDebug((object)$"synced bank state loan {data}");
			};
		}

		private void InitState()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//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_009f: Expected O, but got Unknown
			PolicyState = new PolicyState();
			BankState = new BankState();
			object obj = <>c.<>9__33_0;
			if (obj == null)
			{
				PostSaveGameEventHandler val = delegate
				{
					((ModDataContainer)PolicyState).Save();
					((ModDataContainer)BankState).Save();
				};
				<>c.<>9__33_0 = val;
				obj = (object)val;
			}
			SaveLoadEvents.PostSaveGameEvent += (PostSaveGameEventHandler)obj;
			object obj2 = <>c.<>9__33_1;
			if (obj2 == null)
			{
				PostLoadGameEventHandler val2 = delegate
				{
					((ModDataContainer)PolicyState).Load();
					((ModDataContainer)BankState).Load();
				};
				<>c.<>9__33_1 = val2;
				obj2 = (object)val2;
			}
			SaveLoadEvents.PostLoadGameEvent += (PostLoadGameEventHandler)obj2;
			object obj3 = <>c.<>9__33_2;
			if (obj3 == null)
			{
				PostDeleteSaveEventHandler val3 = delegate
				{
					PolicyState.ResetAndSync();
					BankState.ResetAndSync();
					HUDManagerEvents.QueuedHudTips.Clear();
				};
				<>c.<>9__33_2 = val3;
				obj3 = (object)val3;
			}
			SaveLoadEvents.PostDeleteSaveEvent += (PostDeleteSaveEventHandler)obj3;
			object obj4 = <>c.<>9__33_3;
			if (obj4 == null)
			{
				PostResetSavedGameValuesEventHandler val4 = delegate
				{
					PolicyState.ResetAndSync();
					BankState.ResetAndSync();
					HUDManagerEvents.QueuedHudTips.Clear();
					((ModDataContainer)PolicyState).Save();
					((ModDataContainer)BankState).Save();
				};
				<>c.<>9__33_3 = val4;
				obj4 = (object)val4;
			}
			SaveLoadEvents.PostResetSavedGameValuesEvent += (PostResetSavedGameValuesEventHandler)obj4;
		}

		private void RegisterTerminal()
		{
			InteractiveTerminalManager.RegisterApplication<PolicyInformationTerminal>(new string[3] { "insurance info", "insurance information", "insurance policy" });
			InteractiveTerminalManager.RegisterApplication<PolicySelectTerminal>(new string[2] { "insurance select", "insurance get" });
			InteractiveTerminalManager.RegisterApplication<PolicyClaimTerminal>(new string[3] { "insurance claim", "insurance claims", "insurance make claim" });
			InteractiveTerminalManager.RegisterApplication<BankLoanInformationTerminal>(new string[2] { "bank loan info", "bank loan information" });
			InteractiveTerminalManager.RegisterApplication<BankLoanGetTerminal>(new string[2] { "bank loan get", "bank loan" });
			InteractiveTerminalManager.RegisterApplication<BankLoanPaymentTerminal>(new string[2] { "bank loan pay", "bank loan payment" });
		}

		internal static void Patch()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("tesinormed.FAndCDaveCo");
			}
			Logger.LogDebug((object)"patching in progress");
			Harmony.PatchAll(Assembly.GetExecutingAssembly());
			Logger.LogDebug((object)"finished patching");
		}

		internal static void Unpatch()
		{
			Logger.LogDebug((object)"unpatching in progress");
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogDebug((object)"finished unpatching");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "tesinormed.FAndCDaveCo";

		public const string PLUGIN_NAME = "FAndCDaveCo";

		public const string PLUGIN_VERSION = "1.4.2";
	}
}
namespace tesinormed.FAndCDaveCo.Patches
{
	[HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")]
	public static class RoundManager_DespawnPropsAtEndOfRound_Patch
	{
		public static void Prefix(ref RoundManager __instance)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)__instance).IsServer || !StartOfRound.Instance.allPlayersDead || Plugin.PolicyState.Policy.Tier == PolicyTier.None)
			{
				return;
			}
			int lootValue = (from grabbableObject in GameObject.Find("/Environment/HangarShip").GetComponentsInChildren<GrabbableObject>()
				where grabbableObject.itemProperties.isScrap && !(grabbableObject is RagdollGrabbableObject)
				select grabbableObject).Sum((GrabbableObject grabbableObject) => grabbableObject.scrapValue);
			if (lootValue > 0)
			{
				Plugin.PolicyState.UpdateAndSyncClaims(delegate(Dictionary<int, PolicyClaim> claims)
				{
					claims[StartOfRound.Instance.gameStats.daysSpent - 1] = new PolicyClaim(lootValue);
				});
				Plugin.Logger.LogInfo((object)$"crew all dead, recording pending claim with value of {lootValue} for day {StartOfRound.Instance.gameStats.daysSpent - 1}");
				new LethalServerEvent("ClaimAvailable", (Action<ulong>)null).InvokeAllClients(true);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "EndOfGame")]
	public static class StartOfRound_EndOfGame_Patch
	{
		public static void Prefix(ref StartOfRound __instance)
		{
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound val = __instance;
			if (val == null || !((NetworkBehaviour)val).IsServer || val.isChallengeFile)
			{
				return;
			}
			foreach (KeyValuePair<int, PolicyClaim> keyValuePair in Plugin.PolicyState.Claims.Where<KeyValuePair<int, PolicyClaim>>((KeyValuePair<int, PolicyClaim> pair) => StartOfRound.Instance.gameStats.daysSpent - pair.Key > SyncedEntry<int>.op_Implicit(Plugin.Config.ClaimRetentionDays)))
			{
				Plugin.PolicyState.UpdateAndSyncClaims(delegate(Dictionary<int, PolicyClaim> claims)
				{
					claims.Remove(keyValuePair.Key);
				});
				Plugin.Logger.LogInfo((object)$"deleted old claim from day {keyValuePair.Key}: {keyValuePair.Value}");
			}
			if (Plugin.PolicyState.Policy != Policy.None)
			{
				if (Plugin.Terminal.groupCredits >= Plugin.PolicyState.TotalPremium)
				{
					new LethalClientMessage<int>("DeductGroupCredits", (Action<int>)null, (Action<int, ulong>)null).SendServer(Plugin.PolicyState.TotalPremium);
					new LethalServerMessage<int>("InsuranceRenewalSuccess", (Action<int, ulong>)null).SendAllClients(Plugin.PolicyState.TotalPremium, true);
					Plugin.Logger.LogDebug((object)$"insurance successfully renewed with premium of {Plugin.PolicyState.TotalPremium}");
				}
				else
				{
					Plugin.PolicyState.SetAndSyncPolicy(Policy.None);
					new LethalServerEvent("InsuranceRenewalFail", (Action<ulong>)null).InvokeAllClients(true);
					Plugin.Logger.LogDebug((object)"insurance failed to renew");
				}
			}
			if (Plugin.BankState.Loan.AmountUnpaid <= 0 || Plugin.BankState.Loan.DaysSinceIssuance < SyncedEntry<int>.op_Implicit(Plugin.Config.PenaltyStartDaysFromIssuance))
			{
				return;
			}
			int amountGarnished = Math.Min((int)((double)Plugin.Terminal.groupCredits * SyncedEntry<double>.op_Implicit(Plugin.Config.PenaltyAmount)), Plugin.BankState.Loan.AmountUnpaid);
			new LethalClientMessage<int>("DeductGroupCredits", (Action<int>)null, (Action<int, ulong>)null).SendServer(amountGarnished);
			Plugin.Logger.LogDebug((object)$"garnished ${amountGarnished} from group credits due to loan nonpayment");
			if (Plugin.BankState.Loan.AmountUnpaid - amountGarnished == 0)
			{
				Plugin.BankState.SetAndSyncLoan(Loan.None);
				Plugin.Logger.LogDebug((object)"loan fully paid off due to garnishment");
			}
			else
			{
				Plugin.BankState.UpdateAndSyncLoan(delegate(Loan loan)
				{
					loan.AmountPaid += amountGarnished;
				});
				Plugin.Logger.LogDebug((object)$"loan amount paid increased by {amountGarnished}");
			}
			new LethalServerMessage<int>("BankLoanCreditsGarnished", (Action<int, ulong>)null).SendAllClients(amountGarnished, true);
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			CodeMatcher obj = new CodeMatcher(instructions, generator).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, AccessTools.Method(typeof(HUDManager), "ApplyPenalty", (Type[])null, (Type[])null)))).SearchBack((Func<CodeInstruction, bool>)((CodeInstruction instruction) => CodeInstructionExtensions.LoadsField(instruction, AccessTools.Field(typeof(StartOfRound), "isChallengeFile"), false))).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction instruction) => instruction.opcode == OpCodes.Brtrue));
			object operand = obj.Operand;
			return obj.Advance(1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(PolicyState), "DisableDeathCreditPenalty")),
				new CodeInstruction(OpCodes.Brtrue, operand)
			}).InstructionEnumeration();
		}

		public static IEnumerator Postfix(IEnumerator values, StartOfRound __instance)
		{
			do
			{
				yield return values.Current;
			}
			while (values.MoveNext());
			if (__instance != null && ((NetworkBehaviour)__instance).IsServer && !__instance.isChallengeFile && !((double)TimeOfDay.Instance.timeUntilDeadline <= 0.0))
			{
				new LethalServerEvent("RunQueuedHudTips", (Action<ulong>)null).InvokeAllClients(true);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "Awake")]
	public static class Terminal_Awake_Patch
	{
		public static void Postfix(ref Terminal __instance)
		{
			Plugin.Terminal = __instance;
		}
	}
}
namespace tesinormed.FAndCDaveCo.Network
{
	public static class CreditEvents
	{
		public const string DeductGroupCreditsIdentifier = "DeductGroupCredits";

		public const string SpawnGoldBarIdentifier = "SpawnGoldBar";

		public const string SyncItemScrapValue = "SyncItemScrapValue";

		public const string TakeOutLoan = "TakeOutLoan";

		public static void Init()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			new LethalServerMessage<int>("DeductGroupCredits", (Action<int, ulong>)delegate(int amount, ulong _)
			{
				if (Plugin.Terminal.groupCredits < amount)
				{
					Plugin.Logger.LogError((object)$"could not deduct {amount} credits; balance would be under 0");
				}
				else
				{
					Terminal terminal = Plugin.Terminal;
					terminal.groupCredits -= amount;
					Plugin.Terminal.SyncGroupCreditsServerRpc(Plugin.Terminal.groupCredits, Plugin.Terminal.numberOfItemsInDropship);
					Plugin.Logger.LogDebug((object)$"deducted {amount} credits");
				}
			});
			new LethalServerMessage<int>("SpawnGoldBar", (Action<int, ulong>)delegate(int value, ulong client)
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: 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_010a: Unknown result type (might be due to invalid IL or missing references)
				Item val = StartOfRound.Instance.allItemsList.itemsList.Single((Item item) => item.itemName.ToLower() == "gold bar");
				PlayerControllerB playerController = LethalNetworkExtensions.GetPlayerController(client);
				if ((Object)(object)playerController == (Object)null)
				{
					Plugin.Logger.LogError((object)$"could not get player controller for client {client}");
				}
				else
				{
					Vector3 position = ((Component)playerController).transform.position;
					GameObject val2 = Object.Instantiate<GameObject>(val.spawnPrefab, position, Quaternion.identity, GameObject.Find("/Environment/HangarShip").transform);
					val2.GetComponent<GrabbableObject>().itemProperties.isScrap = true;
					val2.GetComponent<GrabbableObject>().itemProperties.creditsWorth = value;
					val2.GetComponent<GrabbableObject>().SetScrapValue(value);
					playerController.SetItemInElevator(true, true, val2.GetComponent<GrabbableObject>());
					val2.GetComponent<NetworkObject>().Spawn(true);
					Plugin.Logger.LogDebug((object)$"spawned gold bar with value of {value} at client {LethalNetworkExtensions.GetClientId(playerController)}");
					new LethalServerMessage<Tuple<NetworkObjectReference, int>>("SyncItemScrapValue", (Action<Tuple<NetworkObjectReference, int>, ulong>)null).SendAllClients(new Tuple<NetworkObjectReference, int>(NetworkObjectReference.op_Implicit(val2.GetComponent<NetworkObject>()), value), true);
				}
			});
			new LethalClientMessage<Tuple<NetworkObjectReference, int>>("SyncItemScrapValue", (Action<Tuple<NetworkObjectReference, int>>)delegate(Tuple<NetworkObjectReference, int> value)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				NetworkObjectReference.op_Implicit(value.Item1).GetComponent<GrabbableObject>().SetScrapValue(value.Item2);
			}, (Action<Tuple<NetworkObjectReference, int>, ulong>)null);
			new LethalServerEvent("TakeOutLoan", (Action<ulong>)delegate
			{
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				Loan loan = new Loan(StartOfRound.Instance.gameStats.daysSpent, TimeOfDay.Instance.profitQuota - TimeOfDay.Instance.quotaFulfilled);
				Plugin.BankState.SetAndSyncLoan(loan);
				Plugin.Logger.LogDebug((object)$"took out a loan for {loan.Principal}");
				TimeOfDay.Instance.quotaFulfilled = TimeOfDay.Instance.profitQuota;
				new LethalServerEvent("TakeOutLoan", (Action<ulong>)null).InvokeAllClients(true);
			});
			new LethalClientEvent("TakeOutLoan", (Action)delegate
			{
				TimeOfDay.Instance.quotaFulfilled = TimeOfDay.Instance.profitQuota;
				TimeOfDay.Instance.UpdateProfitQuotaCurrentTime();
				StartOfRound.Instance.AutoSaveShipData();
			}, (Action<ulong>)null);
		}
	}
	public static class HUDManagerEvents
	{
		public const string InsuranceRenewalSuccessIdentifier = "InsuranceRenewalSuccess";

		public const string InsuranceRenewalFailIdentifier = "InsuranceRenewalFail";

		public const string InsuranceClaimAvailableIdentifier = "ClaimAvailable";

		public const string BankLoanCreditsGarnishedIdentifier = "BankLoanCreditsGarnished";

		public const string RunQueuedHudTipsIdentifier = "RunQueuedHudTips";

		internal static readonly List<Action> QueuedHudTips = new List<Action>();

		public static void Init()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			new LethalClientMessage<int>("InsuranceRenewalSuccess", (Action<int>)delegate(int value)
			{
				QueuedHudTips.Add(delegate
				{
					HUDManager.Instance.DisplayTip("Insurance renewed", $"▮{value} has been deducted.", false, false, "LC_Tip1");
				});
				Plugin.Logger.LogDebug((object)"queued insurance renewal success on HUD");
			}, (Action<int, ulong>)null);
			new LethalClientEvent("InsuranceRenewalFail", (Action)delegate
			{
				QueuedHudTips.Add(delegate
				{
					HUDManager.Instance.DisplayTip("Insurance canceled", "You do not have sufficient credits.", true, false, "LC_Tip1");
				});
				Plugin.Logger.LogDebug((object)"queued insurance renewal fail on HUD");
			}, (Action<ulong>)null);
			new LethalClientEvent("ClaimAvailable", (Action)delegate
			{
				QueuedHudTips.Add(delegate
				{
					HUDManager.Instance.DisplayTip("Insurance claim", "Confirm the pending claim at the terminal.", false, false, "LC_Tip1");
				});
				Plugin.Logger.LogDebug((object)"queued insurance claim available on HUD");
			}, (Action<ulong>)null);
			new LethalClientMessage<int>("BankLoanCreditsGarnished", (Action<int>)delegate(int value)
			{
				QueuedHudTips.Add(delegate
				{
					HUDManager.Instance.DisplayTip("Credits garnished", $"Due to loan nonpayment, {(int)(SyncedEntry<double>.op_Implicit(Plugin.Config.PenaltyAmount) * 100.0)}% of your credits (▮{value}) have been garnished.", true, false, "LC_Tip1");
				});
				Plugin.Logger.LogDebug((object)"queued loan credit garnishing warning on HUD");
			}, (Action<int, ulong>)null);
			new LethalClientEvent("RunQueuedHudTips", (Action)delegate
			{
				((MonoBehaviour)HUDManager.Instance).StartCoroutine(RunQueuedHudTips());
			}, (Action<ulong>)null);
		}

		private static IEnumerator RunQueuedHudTips()
		{
			for (int index = 0; index < QueuedHudTips.Count; index++)
			{
				Action tip = QueuedHudTips[index];
				if (index == 0)
				{
					yield return (object)new WaitForSeconds(3f);
				}
				tip();
				Plugin.Logger.LogDebug((object)"displayed queued HUD tip");
				yield return (object)new WaitForSeconds(7.5f);
			}
			QueuedHudTips.Clear();
		}
	}
	public static class NetworkVariableEvents
	{
		public const string UpdatePolicyIdentifier = "UpdatePolicy";

		public const string UpdateClaimsIdentifier = "UpdateClaims";

		public const string UpdateLoanIdentifier = "UpdateLoan";

		public static void Init()
		{
			new LethalServerMessage<Policy>("UpdatePolicy", (Action<Policy, ulong>)delegate(Policy value, ulong _)
			{
				Plugin.SyncedPolicy.Value = value;
			});
			new LethalServerMessage<Dictionary<int, PolicyClaim>>("UpdateClaims", (Action<Dictionary<int, PolicyClaim>, ulong>)delegate(Dictionary<int, PolicyClaim> value, ulong _)
			{
				Plugin.SyncedClaims.Value = value;
			});
			new LethalServerMessage<Loan>("UpdateLoan", (Action<Loan, ulong>)delegate(Loan value, ulong _)
			{
				Plugin.SyncedLoan.Value = value;
			});
		}
	}
}
namespace tesinormed.FAndCDaveCo.Insurance
{
	[ES3Serializable]
	public record Policy
	{
		[ES3NonSerializable]
		public int BasePremium => Tier switch
		{
			PolicyTier.HighDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.EconomicBasePremium)), 
			PolicyTier.LowDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.StandardBasePremium)), 
			PolicyTier.NoDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.BespokeBasePremium)), 
			_ => 0, 
		};

		[ES3NonSerializable]
		public double DeductiblePercent => Tier switch
		{
			PolicyTier.HighDeductible => SyncedEntry<double>.op_Implicit(Plugin.Config.EconomicDeductible), 
			PolicyTier.LowDeductible => SyncedEntry<double>.op_Implicit(Plugin.Config.StandardDeductible), 
			_ => 0.0, 
		};

		[ES3NonSerializable]
		public int DeductibleMinimum => Tier switch
		{
			PolicyTier.HighDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.EconomicDeductibleMinimum)), 
			PolicyTier.LowDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.StandardDeductibleMinimum)), 
			_ => 0, 
		};

		[ES3NonSerializable]
		public int DeductibleMaximum => Tier switch
		{
			PolicyTier.HighDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.EconomicDeductibleMaximum)), 
			PolicyTier.LowDeductible => (int)Math.Floor((double)Coverage * SyncedEntry<double>.op_Implicit(Plugin.Config.StandardDeductibleMaximum)), 
			_ => 0, 
		};

		[ES3NonSerializable]
		public static readonly Policy None = new Policy(PolicyTier.None, 0);

		public int Coverage;

		public PolicyTier Tier;

		public Policy(PolicyTier tier, int coverage)
		{
			if (coverage < 0)
			{
				throw new ArgumentOutOfRangeException("coverage", "nonnegative number required");
			}
			Tier = tier;
			Coverage = coverage;
		}

		public int CalculatePayout(int value)
		{
			if (value < 0)
			{
				throw new ArgumentOutOfRangeException("value", "nonnegative number required");
			}
			return Math.Min(value, Coverage);
		}

		public int CalculateDeductible(int value)
		{
			if (value < 0)
			{
				throw new ArgumentOutOfRangeException("value", "nonnegative number required");
			}
			return Math.Clamp((int)Math.Floor((double)CalculatePayout(value) * DeductiblePercent), DeductibleMinimum, DeductibleMaximum);
		}

		[CompilerGenerated]
		protected virtual bool PrintMembers(StringBuilder builder)
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			builder.Append("Coverage = ");
			builder.Append(Coverage.ToString());
			builder.Append(", Tier = ");
			builder.Append(Tier.ToString());
			builder.Append(", BasePremium = ");
			builder.Append(BasePremium.ToString());
			builder.Append(", DeductiblePercent = ");
			builder.Append(DeductiblePercent.ToString());
			builder.Append(", DeductibleMinimum = ");
			builder.Append(DeductibleMinimum.ToString());
			builder.Append(", DeductibleMaximum = ");
			builder.Append(DeductibleMaximum.ToString());
			return true;
		}

		[CompilerGenerated]
		protected Policy(Policy original)
		{
			Coverage = original.Coverage;
			Tier = original.Tier;
		}
	}
	public static class PolicyExtensions
	{
		public static Policy CreatePolicy(this PolicyTier policyTier, int coverage)
		{
			return new Policy(policyTier, coverage);
		}
	}
	[ES3Serializable]
	public record PolicyClaim
	{
		public bool Claimed;

		public int Value;

		public PolicyClaim(int value, bool claimed = false)
		{
			if (value < 0)
			{
				throw new ArgumentOutOfRangeException("value", "nonnegative number required");
			}
			Value = value;
			Claimed = claimed;
		}
	}
	public class PolicyState : ModDataContainer
	{
		public Policy Policy { get; set; } = tesinormed.FAndCDaveCo.Insurance.Policy.None;


		public Dictionary<int, PolicyClaim> Claims { get; set; } = new Dictionary<int, PolicyClaim>();


		[ModDataIgnore(/*Could not decode attribute arguments.*/)]
		public Dictionary<int, PolicyClaim> ClaimedClaims => Claims.Where<KeyValuePair<int, PolicyClaim>>((KeyValuePair<int, PolicyClaim> pair) => pair.Value.Claimed).ToDictionary();

		[ModDataIgnore(/*Could not decode attribute arguments.*/)]
		public Dictionary<int, PolicyClaim> UnclaimedClaims => Claims.Where<KeyValuePair<int, PolicyClaim>>((KeyValuePair<int, PolicyClaim> pair) => !pair.Value.Claimed).ToDictionary();

		[ModDataIgnore(/*Could not decode attribute arguments.*/)]
		public double FractionalPremiumIncrease => (double)ClaimedClaims.Count * SyncedEntry<double>.op_Implicit(Plugin.Config.ClaimPremiumIncrease);

		[ModDataIgnore(/*Could not decode attribute arguments.*/)]
		public int TotalPremium => (int)((double)Policy.BasePremium * (1.0 + FractionalPremiumIncrease));

		public static bool DisableDeathCreditPenalty
		{
			get
			{
				if (Plugin.PolicyState.Policy.Tier == PolicyTier.None)
				{
					return false;
				}
				return SyncedEntry<bool>.op_Implicit(Plugin.Config.GameDisableDeathCreditPenalty);
			}
		}

		protected override void PostSave()
		{
			Plugin.Logger.LogDebug((object)$"saved policy state {this}");
		}

		protected override void PostLoad()
		{
			Plugin.Logger.LogDebug((object)$"loaded policy state {this}");
			Plugin.SyncedPolicy.Value = Policy;
			Plugin.SyncedClaims.Value = Claims;
		}

		public void SetAndSyncPolicy(Policy policy)
		{
			Policy = policy;
			new LethalClientMessage<Policy>("UpdatePolicy", (Action<Policy>)null, (Action<Policy, ulong>)null).SendServer(policy);
		}

		public void UpdateAndSyncClaims(Action<Dictionary<int, PolicyClaim>> action)
		{
			action(Claims);
			new LethalClientMessage<Dictionary<int, PolicyClaim>>("UpdateClaims", (Action<Dictionary<int, PolicyClaim>>)null, (Action<Dictionary<int, PolicyClaim>, ulong>)null).SendServer(Claims);
		}

		public void ResetAndSync()
		{
			SetAndSyncPolicy(tesinormed.FAndCDaveCo.Insurance.Policy.None);
			UpdateAndSyncClaims(delegate(Dictionary<int, PolicyClaim> claims)
			{
				claims.Clear();
			});
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("PolicyState(");
			stringBuilder.Append($"policy: {Policy}");
			if (Claims.Count > 0)
			{
				stringBuilder.Append(", claims: [" + string.Join(", ", Claims) + "]");
			}
			stringBuilder.Append(")");
			return stringBuilder.ToString();
		}
	}
	public enum PolicyTier : byte
	{
		None,
		HighDeductible,
		LowDeductible,
		NoDeductible
	}
	public static class PolicyTierExtensions
	{
		public static string ToFriendlyString(this PolicyTier policyTier)
		{
			return policyTier switch
			{
				PolicyTier.HighDeductible => "Economic", 
				PolicyTier.LowDeductible => "Standard", 
				PolicyTier.NoDeductible => "Bespoke", 
				PolicyTier.None => "No Policy?", 
				_ => throw new ArgumentOutOfRangeException("policyTier", $"unexpected value: {policyTier}"), 
			};
		}
	}
}
namespace tesinormed.FAndCDaveCo.Insurance.UI
{
	public class PolicyClaimTerminal : InteractiveTerminalApplication
	{
		protected override string Title => "F&C Dave Co. Insurance: Make a claim";

		private CursorElement CreateCursorElement(int day, PolicyClaim claim)
		{
			PolicyClaim claim2 = claim;
			return CursorElement.Create($"Day {day}: ${claim2.Value}", "", (Action)delegate
			{
				ConfirmClaim(day, claim2);
			}, (Func<CursorElement, bool>)((CursorElement _) => true), false);
		}

		public override void Initialization()
		{
			if (Plugin.PolicyState.Policy.Tier == PolicyTier.None)
			{
				LockedNotification((ITextElement)TextElement.Create("You do not have an active insurance policy."));
				return;
			}
			if (Plugin.PolicyState.UnclaimedClaims.Count == 0)
			{
				LockedNotification((ITextElement)TextElement.Create("You do not have any claims."));
				return;
			}
			CursorElement[] seed = Array.Empty<CursorElement>();
			seed = Plugin.PolicyState.UnclaimedClaims.Aggregate<KeyValuePair<int, PolicyClaim>, CursorElement[]>(seed, delegate(CursorElement[] current, KeyValuePair<int, PolicyClaim> pair)
			{
				int num = 0;
				CursorElement[] array = (CursorElement[])(object)new CursorElement[1 + current.Length];
				ReadOnlySpan<CursorElement> readOnlySpan = new ReadOnlySpan<CursorElement>(current);
				readOnlySpan.CopyTo(new Span<CursorElement>(array).Slice(num, readOnlySpan.Length));
				num += readOnlySpan.Length;
				array[num] = CreateCursorElement(pair.Key, pair.Value);
				num++;
				return array;
			});
			(base.MainScreen, base.MainCursorMenu) = Selection("Select a pending claim.", seed);
		}

		private void ConfirmClaim(int day, PolicyClaim claim)
		{
			PolicyClaim claim2 = claim;
			int deductible = Plugin.PolicyState.Policy.CalculateDeductible(claim2.Value);
			int payout = Plugin.PolicyState.Policy.CalculatePayout(claim2.Value);
			Confirm(delegate
			{
				ProcessClaim(day, deductible, payout, claim2);
			}, delegate
			{
				ConfirmDeleteClaim(day);
			}, (ITextElement[])(object)new ITextElement[2]
			{
				(ITextElement)TextElement.Create($"Are you sure you want to confirm this claim? You will need to pay a deductible of ${deductible}."),
				(ITextElement)TextElement.Create($"You will be given back ${payout}.")
			});
		}

		private void ConfirmDeleteClaim(int day)
		{
			Confirm(delegate
			{
				DeleteClaim(day);
			}, base.PreviousMainScreenAction, (ITextElement)TextElement.Create($"Do you want to delete this claim for day {day}?"));
		}

		private void DeleteClaim(int day)
		{
			Plugin.PolicyState.UpdateAndSyncClaims(delegate(Dictionary<int, PolicyClaim> claims)
			{
				claims.Remove(day);
			});
			LockedNotification((ITextElement)TextElement.Create($"The claim for day {day} has been deleted."));
		}

		private void ProcessClaim(int day, int deductible, int payout, PolicyClaim claim)
		{
			PolicyClaim claim2 = claim;
			if (((TerminalApplication)this).terminal.groupCredits < deductible)
			{
				Notification(base.PreviousMainScreenAction, (ITextElement)TextElement.Create("You do not have enough credits to continue with this claim."));
				return;
			}
			Plugin.PolicyState.UpdateAndSyncClaims(delegate(Dictionary<int, PolicyClaim> claims)
			{
				claims[day] = new PolicyClaim(claim2.Value, claimed: true);
			});
			new LethalClientMessage<int>("DeductGroupCredits", (Action<int>)null, (Action<int, ulong>)null).SendServer(deductible);
			new LethalClientMessage<int>("SpawnGoldBar", (Action<int>)null, (Action<int, ulong>)null).SendServer(payout);
			LockedNotification((ITextElement)TextElement.Create($"You have been given a gold bar worth ${payout}."), (ITextElement)TextElement.Create($"You have been charged ${deductible}."), (ITextElement)TextElement.Create($"Your premiums have increased by {(int)(Plugin.PolicyState.FractionalPremiumIncrease * 100.0)}%."));
		}
	}
	public class PolicyInformationTerminal : TerminalApplication
	{
		public override void Initialization()
		{
			List<ITextElement> list = new List<ITextElement>();
			if (Plugin.PolicyState.Policy.Tier == PolicyTier.None)
			{
				list.Add((ITextElement)(object)TextElement.Create("You do not currently have an insurance policy."));
			}
			else
			{
				list.Add((ITextElement)(object)TextElement.Create($"You currently have the {Plugin.PolicyState.Policy.Tier.ToFriendlyString()} policy (${Plugin.PolicyState.Policy.Coverage})."));
				list.Add((ITextElement)(object)TextElement.Create($"You have made {Plugin.PolicyState.ClaimedClaims.Count} claim(s) recently (within {Plugin.Config.ClaimRetentionDays.Value} days)."));
				list.Add((ITextElement)(object)((Plugin.PolicyState.FractionalPremiumIncrease == 0.0) ? TextElement.Create($"You pay ${Plugin.PolicyState.TotalPremium} per day.") : TextElement.Create($"You pay ${Plugin.PolicyState.TotalPremium} (+{(int)(Plugin.PolicyState.FractionalPremiumIncrease * 100.0)}%) per day.")));
				list.Add((ITextElement)(object)((Plugin.PolicyState.Policy.DeductiblePercent != 0.0) ? TextElement.Create($"Your deductible is currently {(int)(Plugin.PolicyState.Policy.DeductiblePercent * 100.0)}% (minimum: ${Plugin.PolicyState.Policy.DeductibleMinimum}, maximum: ${Plugin.PolicyState.Policy.DeductibleMaximum}).") : TextElement.Create("You do not pay deductibles.")));
			}
			BoxedScreen currentScreen = BoxedScreen.Create("F&C Dave Co. Insurance: Policy information", list.ToArray());
			((TerminalApplication)this).currentScreen = (IScreen)(object)currentScreen;
		}
	}
	public class PolicySelectTerminal : InteractiveTerminalApplication
	{
		protected override string Title => "F&C Dave Co. Insurance: Selection";

		private CursorElement CreatePolicyTierCursorElement(PolicyTier policyTier, string description)
		{
			return CursorElement.Create(policyTier.ToFriendlyString() + ": " + description, "", (Action)delegate
			{
				SelectCoverage(policyTier);
			}, (Func<CursorElement, bool>)((CursorElement _) => true), false);
		}

		private CursorElement CreateCoverageCursorElement(Policy policy)
		{
			PolicyState policyState = new PolicyState
			{
				Policy = policy,
				Claims = Plugin.PolicyState.Claims
			};
			return CursorElement.Create($"${policy.Coverage}", "", (Action)delegate
			{
				ConfirmEverything(policyState);
			}, (Func<CursorElement, bool>)((CursorElement _) => ((TerminalApplication)this).terminal.groupCredits >= policyState.TotalPremium), true);
		}

		public override void Initialization()
		{
			if (StartOfRound.Instance.isChallengeFile)
			{
				LockedNotification((ITextElement)TextElement.Create("You cannot get an insurance policy while doing a challenge moon."));
				Plugin.Logger.LogDebug((object)"local player tried to get an insurance policy while doing a challenge moon");
				return;
			}
			(base.MainScreen, base.MainCursorMenu) = Selection("Select a policy tier.", CreatePolicyTierCursorElement(PolicyTier.HighDeductible, "High deductible, low premium"), CreatePolicyTierCursorElement(PolicyTier.LowDeductible, "Low deductible, medium premium"), CreatePolicyTierCursorElement(PolicyTier.NoDeductible, "No deductible, high premium"), CursorElement.Create("Cancel policy", "", (Action)ConfirmCancelPolicy, (Func<CursorElement, bool>)((CursorElement _) => Plugin.PolicyState.Policy.Tier != PolicyTier.None), true));
		}

		private void ConfirmCancelPolicy()
		{
			if (Plugin.PolicyState.Policy.Tier == PolicyTier.None)
			{
				Notification(base.PreviousScreenAction, (ITextElement)TextElement.Create("You do not currently have a policy."));
			}
			else
			{
				Confirm(CancelPolicy, base.PreviousScreenAction, (ITextElement)TextElement.Create("Are you sure you want to cancel your current policy?"), (ITextElement)TextElement.Create($"Your current policy is {Plugin.PolicyState.Policy.Tier.ToFriendlyString()} (${Plugin.PolicyState.Policy.Coverage})."));
			}
		}

		private void CancelPolicy()
		{
			Plugin.PolicyState.SetAndSyncPolicy(Policy.None);
			LockedNotification((ITextElement)TextElement.Create("Your policy has been canceled."));
		}

		private void SelectCoverage(PolicyTier policyTier)
		{
			SelectionWithBack("Select the coverage amount.", base.PreviousMainScreenAction, CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption00))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption01))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption02))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption03))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption04))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption05))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption06))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption07))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption08))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption09))), CreateCoverageCursorElement(policyTier.CreatePolicy(SyncedEntry<int>.op_Implicit(Plugin.Config.CoverageOption10))));
		}

		private void ConfirmEverything(PolicyState state)
		{
			PolicyState state2 = state;
			if (state2.Policy == Plugin.PolicyState.Policy)
			{
				Notification(base.PreviousScreenAction, (ITextElement)TextElement.Create("You already have this policy."));
				return;
			}
			if (((TerminalApplication)this).terminal.groupCredits < state2.TotalPremium)
			{
				Notification(base.PreviousScreenAction, (ITextElement)TextElement.Create("You do not have enough credits to purchase this policy."));
				return;
			}
			Confirm(delegate
			{
				SetEverything(state2.Policy, state2.TotalPremium);
			}, base.PreviousScreenAction, (ITextElement)TextElement.Create($"Are you sure you want to pick {state2.Policy.Tier.ToFriendlyString()} (${state2.Policy.Coverage})?"), (ITextElement)TextElement.Create((state2.Policy.DeductiblePercent == 0.0) ? "This policy has no deductibles." : $"The deductibles are {(int)(state2.Policy.DeductiblePercent * 100.0)}%, with a minimum of ${state2.Policy.DeductibleMinimum} and a maximum of ${state2.Policy.DeductibleMaximum}."), (ITextElement)TextElement.Create($"You will be charged ${state2.TotalPremium}."));
		}

		private void SetEverything(Policy policy, int cost)
		{
			Plugin.PolicyState.SetAndSyncPolicy(policy);
			new LethalClientMessage<int>("DeductGroupCredits", (Action<int>)null, (Action<int, ulong>)null).SendServer(cost);
			LockedNotification((ITextElement)TextElement.Create($"Your policy has been updated to {policy.Tier.ToFriendlyString()} (${policy.Coverage})."), (ITextElement)TextElement.Create($"You have been charged ${cost}."));
		}
	}
	internal static class PolicyTerminal
	{
		internal const string Title = "F&C Dave Co. Insurance";
	}
}
namespace tesinormed.FAndCDaveCo.Extensions
{
	public static class DictionaryExtensions
	{
		public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
		{
			return dictionary.ToDictionary<KeyValuePair<TKey, TValue>, TKey, TValue>((KeyValuePair<TKey, TValue> keyValuePair) => keyValuePair.Key, (KeyValuePair<TKey, TValue> keyValuePair) => keyValuePair.Value);
		}
	}
	public abstract class InteractiveTerminalApplication : InteractiveTerminalApplication
	{
		protected abstract string Title { get; }

		protected IScreen MainScreen { get; set; }

		protected CursorMenu MainCursorMenu { get; set; }

		private IScreen PreviousScreen { get; set; }

		private CursorMenu PreviousCursorMenu { get; set; }

		protected Action PreviousMainScreenAction => delegate
		{
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen(MainScreen, MainCursorMenu, true);
		};

		protected Action PreviousScreenAction => delegate
		{
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen(PreviousScreen, PreviousCursorMenu, true);
		};

		protected override void SwitchScreen(IScreen screen, CursorMenu cursorMenu, bool previous)
		{
			PreviousScreen = ((TerminalApplication)this).currentScreen;
			PreviousCursorMenu = ((BaseInteractiveApplication<CursorMenu, CursorElement>)this).currentCursorMenu;
			((BaseInteractiveApplication<CursorMenu, CursorElement>)this).SwitchScreen(screen, cursorMenu, previous);
		}

		protected (IScreen, CursorMenu) Selection(string prompt, params CursorElement[] options)
		{
			CursorMenu val = CursorMenu.Create(0, '>', options, (Func<CursorElement, CursorElement, int>[])null);
			ITextElement[] array = (ITextElement[])(object)new ITextElement[3]
			{
				(ITextElement)TextElement.Create(prompt),
				(ITextElement)TextElement.Create(" "),
				(ITextElement)val
			};
			BoxedScreen val2 = BoxedScreen.Create(Title, array);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val2, val, false);
			return ((IScreen)(object)val2, val);
		}

		protected void SelectionWithBack(string prompt, Action backAction, params CursorElement[] options)
		{
			CursorElement[] array = options;
			int num = 0;
			CursorElement[] array2 = (CursorElement[])(object)new CursorElement[1 + array.Length];
			ReadOnlySpan<CursorElement> readOnlySpan = new ReadOnlySpan<CursorElement>(array);
			readOnlySpan.CopyTo(new Span<CursorElement>(array2).Slice(num, readOnlySpan.Length));
			num += readOnlySpan.Length;
			array2[num] = CursorElement.Create("Back", "", backAction, (Func<CursorElement, bool>)((CursorElement _) => true), false);
			num++;
			options = array2;
			CursorMenu val = CursorMenu.Create(0, '>', options, (Func<CursorElement, CursorElement, int>[])null);
			ITextElement[] array3 = (ITextElement[])(object)new ITextElement[3]
			{
				(ITextElement)TextElement.Create(prompt),
				(ITextElement)TextElement.Create(" "),
				(ITextElement)val
			};
			BoxedScreen val2 = BoxedScreen.Create(Title, array3);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val2, val, false);
		}

		protected void Confirm(Action confirmAction, params ITextElement[] text)
		{
			CursorMenu val = CursorMenu.Create(0, '>', (CursorElement[])(object)new CursorElement[1] { CursorElement.Create("Confirm", "", confirmAction, (Func<CursorElement, bool>)null, true) }, (Func<CursorElement, CursorElement, int>[])null);
			int num = 0;
			ITextElement[] array = (ITextElement[])(object)new ITextElement[2 + text.Length];
			ReadOnlySpan<ITextElement> readOnlySpan = new ReadOnlySpan<ITextElement>(text);
			readOnlySpan.CopyTo(new Span<ITextElement>(array).Slice(num, readOnlySpan.Length));
			num += readOnlySpan.Length;
			array[num] = (ITextElement)(object)TextElement.Create(" ");
			num++;
			array[num] = (ITextElement)(object)val;
			num++;
			ITextElement[] array2 = array;
			BoxedScreen val2 = BoxedScreen.Create(Title, array2);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val2, val, false);
		}

		protected void Confirm(Action confirmAction, Action declineAction, params ITextElement[] text)
		{
			CursorMenu val = CursorMenu.Create(0, '>', (CursorElement[])(object)new CursorElement[2]
			{
				CursorElement.Create("Confirm", "", confirmAction, (Func<CursorElement, bool>)null, true),
				CursorElement.Create("Decline", "", declineAction, (Func<CursorElement, bool>)null, true)
			}, (Func<CursorElement, CursorElement, int>[])null);
			int num = 0;
			ITextElement[] array = (ITextElement[])(object)new ITextElement[2 + text.Length];
			ReadOnlySpan<ITextElement> readOnlySpan = new ReadOnlySpan<ITextElement>(text);
			readOnlySpan.CopyTo(new Span<ITextElement>(array).Slice(num, readOnlySpan.Length));
			num += readOnlySpan.Length;
			array[num] = (ITextElement)(object)TextElement.Create(" ");
			num++;
			array[num] = (ITextElement)(object)val;
			num++;
			ITextElement[] array2 = array;
			BoxedScreen val2 = BoxedScreen.Create(Title, array2);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val2, val, false);
		}

		protected void Notification(Action backAction, params ITextElement[] text)
		{
			CursorMenu val = CursorMenu.Create(0, '>', (CursorElement[])(object)new CursorElement[1] { CursorElement.Create("Back", "", backAction, (Func<CursorElement, bool>)null, true) }, (Func<CursorElement, CursorElement, int>[])null);
			int num = 0;
			ITextElement[] array = (ITextElement[])(object)new ITextElement[2 + text.Length];
			ReadOnlySpan<ITextElement> readOnlySpan = new ReadOnlySpan<ITextElement>(text);
			readOnlySpan.CopyTo(new Span<ITextElement>(array).Slice(num, readOnlySpan.Length));
			num += readOnlySpan.Length;
			array[num] = (ITextElement)(object)TextElement.Create(" ");
			num++;
			array[num] = (ITextElement)(object)val;
			num++;
			ITextElement[] array2 = array;
			BoxedScreen val2 = BoxedScreen.Create(Title, array2);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val2, val, false);
		}

		protected void LockedNotification(params ITextElement[] text)
		{
			BoxedScreen val = BoxedScreen.Create(Title, text);
			CursorMenu val2 = CursorMenu.Create(0, '>', (CursorElement[])null, (Func<CursorElement, CursorElement, int>[])null);
			((BaseInteractiveApplication<CursorMenu, CursorElement>)(object)this).SwitchScreen((IScreen)(object)val, val2, false);
		}
	}
	public static class InteractiveTerminalManager
	{
		public static void RegisterApplication<T>(params string[] commands) where T : TerminalApplication, new()
		{
			for (int i = 0; i < commands.Length; i++)
			{
				InteractiveTerminalManager.RegisterApplication<T>(commands[i]);
			}
		}
	}
	public abstract class TerminalApplication : TerminalApplication
	{
		protected override string GetApplicationText()
		{
			return ((ITextElement)base.currentScreen).GetText(51);
		}

		protected override Action PreviousScreen()
		{
			return delegate
			{
			};
		}
	}
}
namespace tesinormed.FAndCDaveCo.Bank
{
	public class BankState : ModDataContainer
	{
		public Loan Loan { get; set; } = tesinormed.FAndCDaveCo.Bank.Loan.None;


		protected override void PostSave()
		{
			Plugin.Logger.LogDebug((object)$"saved bank state {this}");
		}

		protected override void PostLoad()
		{
			Plugin.Logger.LogDebug((object)$"loaded bank state {this}");
			Plugin.SyncedLoan.Value = Loan;
		}

		public void SetAndSyncLoan(Loan loan)
		{
			Loan = loan;
			new LethalClientMessage<Loan>("UpdateLoan", (Action<Loan>)null, (Action<Loan, ulong>)null).SendServer(loan);
		}

		public void UpdateAndSyncLoan(Action<Loan> action)
		{
			action(Loan);
			new LethalClientMessage<Loan>("UpdateLoan", (Action<Loan>)null, (Action<Loan, ulong>)null).SendServer(Loan);
		}

		public void ResetAndSync()
		{
			SetAndSyncLoan(tesinormed.FAndCDaveCo.Bank.Loan.None);
		}

		public override string ToString()
		{
			return $"BankState(loan: {Loan})";
		}
	}
	[ES3Serializable]
	public record Loan
	{
		[ES3NonSerializable]
		public int DaysSinceIssuance => StartOfRound.Instance.gameStats.daysSpent - IssuanceDate;

		[ES3NonSerializable]
		public int Interest => (int)((double)Principal * SyncedEntry<double>.op_Implicit(Plugin.Config.InterestAmount));

		[ES3NonSerializable]
		public int Total => Principal + Interest;

		[ES3NonSerializable]
		public int AmountUnpaid => Total - AmountPaid;

		[ES3NonSerializable]
		public static readonly Loan None = new Loan(0, 0);

		public int IssuanceDate;

		public int Principal;

		public int AmountPaid;

		public Loan(int issuanceDate, int principal, int amountPaid = 0)
		{
			if (issuanceDate < 0)
			{
				throw new ArgumentOutOfRangeException("issuanceDate", "nonnegative number required");
			}
			if (principal < 0)
			{
				throw new ArgumentOutOfRangeException("principal", "nonnegative number required");
			}
			if (amountPaid < 0)
			{
				throw new ArgumentOutOfRangeException("amountPaid", "nonnegative number required");
			}
			IssuanceDate = issuanceDate;
			Principal = principal;
			AmountPaid = amountPaid;
		}

		[CompilerGenerated]
		protected virtual bool PrintMembers(StringBuilder builder)
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			builder.Append("IssuanceDate = ");
			builder.Append(IssuanceDate.ToString());
			builder.Append(", DaysSinceIssuance = ");
			builder.Append(DaysSinceIssuance.ToString());
			builder.Append(", Principal = ");
			builder.Append(Principal.ToString());
			builder.Append(", Interest = ");
			builder.Append(Interest.ToString());
			builder.Append(", Total = ");
			builder.Append(Total.ToString());
			builder.Append(", AmountPaid = ");
			builder.Append(AmountPaid.ToString());
			builder.Append(", AmountUnpaid = ");
			builder.Append(AmountUnpaid.ToString());
			return true;
		}

		[CompilerGenerated]
		protected Loan(Loan original)
		{
			IssuanceDate = original.IssuanceDate;
			Principal = original.Principal;
			AmountPaid = original.AmountPaid;
		}
	}
}
namespace tesinormed.FAndCDaveCo.Bank.UI
{
	public class BankLoanGetTerminal : InteractiveTerminalApplication
	{
		protected override string Title => "F&C Dave Co. Banking: Get a loan";

		public override void Initialization()
		{
			if (!StartOfRound.Instance.inShipPhase || !GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom)
			{
				LockedNotification((ITextElement)TextElement.Create("You can only get a loan while you are in orbit."));
				Plugin.Logger.LogDebug((object)"local player tried to get a loan when not in orbit");
				return;
			}
			if (StartOfRound.Instance.isChallengeFile)
			{
				LockedNotification((ITextElement)TextElement.Create("You cannot get a loan while doing a challenge moon."));
				Plugin.Logger.LogDebug((object)"local player tried to get a loan while doing a challenge moon");
				return;
			}
			if (Plugin.BankState.Loan.Principal != 0)
			{
				LockedNotification((ITextElement)TextElement.Create("You can only have one loan at a time."));
				Plugin.Logger.LogDebug((object)"local player tried to get a loan when there already was a loan");
				return;
			}
			Loan loan = new Loan(0, TimeOfDay.Instance.profitQuota - TimeOfDay.Instance.quotaFulfilled);
			Confirm(delegate
			{
				GetLoan(loan);
			}, (ITextElement)TextElement.Create($"Are you sure you want to get a loan for ${loan.Principal}? The total cost will be ${loan.Total}."));
		}

		private void GetLoan(Loan loan)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			new LethalClientEvent("TakeOutLoan", (Action)null, (Action<ulong>)null).InvokeServer();
			LockedNotification((ITextElement)TextElement.Create($"You have successfully taken out a loan for ${loan.Principal}."));
		}
	}
	public class BankLoanInformationTerminal : TerminalApplication
	{
		public override void Initialization()
		{
			List<ITextElement> list = new List<ITextElement>();
			if (Plugin.BankState.Loan.Principal == 0)
			{
				list.Add((ITextElement)(object)TextElement.Create("You do not currently have an unpaid loan."));
			}
			else
			{
				list.Add((ITextElement)(object)TextElement.Create($"You currently have an unpaid loan from {Plugin.BankState.Loan.DaysSinceIssuance} day(s) ago."));
				list.Add((ITextElement)(object)TextElement.Create($"The loan is for ${Plugin.BankState.Loan.Principal} with ${Plugin.BankState.Loan.Interest} added as interest."));
				list.Add((ITextElement)(object)TextElement.Create($"Amount paid: ${Plugin.BankState.Loan.AmountPaid}, amount left: ${Plugin.BankState.Loan.AmountUnpaid}, total: ${Plugin.BankState.Loan.Total}."));
				if (Plugin.BankState.Loan.DaysSinceIssuance >= SyncedEntry<int>.op_Implicit(Plugin.Config.PenaltyStartDaysFromIssuance))
				{
					list.Add((ITextElement)(object)TextElement.Create($"{(int)(SyncedEntry<double>.op_Implicit(Plugin.Config.PenaltyAmount) * 100.0)}% of your credits are currently being garnished each day."));
				}
			}
			BoxedScreen currentScreen = BoxedScreen.Create("F&C Dave Co. Banking: Loan information", list.ToArray());
			((TerminalApplication)this).currentScreen = (IScreen)(object)currentScreen;
		}
	}
	public class BankLoanPaymentTerminal : InteractiveTerminalApplication
	{
		protected override string Title => "F&C Dave Co. Banking: Submit loan payment";

		private CursorElement CreateCursorElement(double amount)
		{
			int cost = Math.Min((int)((double)Plugin.BankState.Loan.Total * amount), Plugin.BankState.Loan.AmountUnpaid);
			return CursorElement.Create($"{(int)(amount * 100.0)}% (${cost})", "", (Action)delegate
			{
				ConfirmPayLoan(cost);
			}, (Func<CursorElement, bool>)((CursorElement _) => ((TerminalApplication)this).terminal.groupCredits >= cost), true);
		}

		public override void Initialization()
		{
			if (Plugin.BankState.Loan.Principal == 0)
			{
				LockedNotification((ITextElement)TextElement.Create("You can only submit a loan payment if you have a loan."));
				Plugin.Logger.LogDebug((object)"local player tried to submit a loan payment when there was no loan");
				return;
			}
			(base.MainScreen, base.MainCursorMenu) = Selection("Pick an amount to pay towards the loan.", CreateCursorElement(0.1), CreateCursorElement(0.25), CreateCursorElement(0.5), CreateCursorElement(0.75), CreateCursorElement(1.0));
		}

		private void ConfirmPayLoan(int amount)
		{
			if (((TerminalApplication)this).terminal.groupCredits < amount)
			{
				Notification(base.PreviousScreenAction, (ITextElement)TextElement.Create($"You do not have enough credits to submit a payment of ${amount} for the loan."));
				return;
			}
			Confirm(delegate
			{
				PayLoan(amount);
			}, base.PreviousScreenAction, (ITextElement)TextElement.Create($"Are you sure you want to pay ${amount}?"));
		}

		private void PayLoan(int amount)
		{
			new LethalClientMessage<int>("DeductGroupCredits", (Action<int>)null, (Action<int, ulong>)null).SendServer(amount);
			if (Plugin.BankState.Loan.AmountUnpaid - amount == 0)
			{
				Plugin.BankState.SetAndSyncLoan(Loan.None);
				Plugin.Logger.LogDebug((object)"loan paid off fully; removed");
				LockedNotification((ITextElement)TextElement.Create("You have paid off your loan fully."));
				return;
			}
			Plugin.BankState.UpdateAndSyncLoan(delegate(Loan loan)
			{
				loan.AmountPaid += amount;
			});
			Plugin.Logger.LogDebug((object)$"paid {amount} towards the current loan");
			LockedNotification((ITextElement)TextElement.Create($"You have paid ${amount}; ${Plugin.BankState.Loan.AmountUnpaid} must still be paid."));
		}
	}
	internal static class BankTerminal
	{
		internal const string Title = "F&C Dave Co. Banking";
	}
}