Decompiled source of Rebirth v1.1.5

plugins/rebirth/Rebirth.dll

Decompiled 6 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using COTL_API.CustomFollowerCommand;
using COTL_API.CustomInventory;
using COTL_API.CustomMission;
using COTL_API.CustomObjectives;
using COTL_API.CustomSettings;
using COTL_API.Helpers;
using COTL_API.Saves;
using HarmonyLib;
using I2.Loc;
using Lamb.UI;
using Lamb.UI.FollowerInteractionWheel;
using Microsoft.CodeAnalysis;
using MonoMod.Utils;
using Shared;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("p1xel8ted")]
[assembly: AssemblyConfiguration("Release-Thunderstore")]
[assembly: AssemblyDescription("Rebirth")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5+f7ac2caf14bd7f6ad27b1dc9ed7e30d5a2596c3a")]
[assembly: AssemblyProduct("Rebirth")]
[assembly: AssemblyTitle("Rebirth")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.5.0")]
[module: UnverifiableCode]
[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;
		}
	}
}
internal sealed class ConfigurationManagerAttributes
{
	public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);

	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public CustomHotkeyDrawerFunc CustomHotkeyDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
namespace Rebirth
{
	public static class Helper
	{
		public static bool IsOld(Follower follower)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (Plugin.RebirthOldFollowers.Value)
			{
				return false;
			}
			if ((int)follower.Outfit.CurrentOutfit == 7)
			{
				if (!follower.Brain.Info.OldAge)
				{
					return follower.Brain.HasThought((Thought)146);
				}
				return true;
			}
			return false;
		}

		public static bool DoHalfStats()
		{
			return Random.Range(0f, 1f) <= (float)Plugin.XpPenaltyChance.Value / 100f;
		}

		public static bool IsUniqueFollower(FollowerBrainInfo brainInfo)
		{
			FollowerInfo info = brainInfo._info;
			if (info.Traits.Any((TraitType t) => FollowerTrait.UniqueTraits.Contains(t)))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(info.SkinName) && new string[21]
			{
				"Webber", "Sozo", "Ratau", "Baal", "Aym", "Haro", "Klunko", "Bop", "Jalala", "Rinor",
				"Flinky", "Helob", "Leshy", "Heket", "Kallamar", "Shamura", "Narinder", "Plimbo", "Chemach", "Fox",
				"Cthulhu"
			}.Any((string s) => info.SkinName.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))
			{
				return true;
			}
			return false;
		}
	}
	public class MissionItem : CustomMission
	{
		public override string InternalName => "REBIRTH_MISSION_1";

		public override ITEM_TYPE RewardType => Plugin.RebirthItem;

		public override int BaseChance => Plugin.MissionBaseChance.Value;

		public override IntRange RewardRange => new IntRange(Plugin.MissionRewardMin.Value, Plugin.MissionRewardMax.Value);
	}
	[HarmonyPatch]
	[HarmonyWrapSafe]
	public static class Patches
	{
		private static readonly HashSet<int> RebirthingFollowers = new HashSet<int>();

		private static readonly Dictionary<string, string> RebirthDeathMessages = new Dictionary<string, string>
		{
			{ "English", "<color=#FFD201>{0}</color> succumbed to unknown forces..." },
			{ "French", "<color=#FFD201>{0}</color> a succombé à des forces inconnues..." },
			{ "German", "<color=#FFD201>{0}</color> erlag unbekannten Mächten..." },
			{ "Spanish", "<color=#FFD201>{0}</color> sucumbió a fuerzas desconocidas..." },
			{ "Italian", "<color=#FFD201>{0}</color> è soccombuto a forze sconosciute..." },
			{ "Portuguese(Brazil)", "<color=#FFD201>{0}</color> sucumbiu a forças desconhecidas..." },
			{ "Russian", "<color=#FFD201>{0}</color> пал жертвой неведомых сил..." },
			{ "Japanese", "<color=#FFD201>{0}</color>は未知の力に屈した..." },
			{ "Korean", "<color=#FFD201>{0}</color>이(가) 알 수 없는 힘에 굴복했습니다..." },
			{ "SimplifiedChinese", "<color=#FFD201>{0}</color>屈服于未知的力量..." },
			{ "TraditionalChinese", "<color=#FFD201>{0}</color>屈服於未知的力量..." }
		};

		public static void MarkFollowerForRebirth(int followerId)
		{
			RebirthingFollowers.Add(followerId);
			Plugin.Log.LogInfo((object)$"[Rebirth] Marked follower ID {followerId} for rebirth. Total marked: {RebirthingFollowers.Count}");
		}

		public static void UnmarkFollowerRebirth(int followerId)
		{
			bool flag = RebirthingFollowers.Remove(followerId);
			Plugin.Log.LogInfo((object)$"[Rebirth] Unmarked follower ID {followerId} (removed: {flag}). Remaining marked: {RebirthingFollowers.Count}");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FollowerInfo), "GetDeathText")]
		public static void FollowerInfo_GetDeathText_Postfix(FollowerInfo __instance, ref string __result)
		{
			Plugin.Log.LogInfo((object)$"[Rebirth] GetDeathText called for follower '{__instance.Name}' (ID: {__instance.ID})");
			Plugin.Log.LogInfo((object)("[Rebirth] Currently marked follower IDs: [" + string.Join(", ", RebirthingFollowers) + "]"));
			Plugin.Log.LogInfo((object)$"[Rebirth] Is follower in rebirth set? {RebirthingFollowers.Contains(__instance.ID)}");
			Plugin.Log.LogInfo((object)("[Rebirth] Original death text: " + __result));
			if (RebirthingFollowers.Contains(__instance.ID))
			{
				string currentLanguage = LocalizationManager.CurrentLanguage;
				Plugin.Log.LogInfo((object)("[Rebirth] Current language: " + currentLanguage));
				string value;
				string text = (RebirthDeathMessages.TryGetValue(currentLanguage, out value) ? value : RebirthDeathMessages["English"]);
				Plugin.Log.LogInfo((object)("[Rebirth] Using message template: " + text));
				string text2 = __result;
				__result = string.Format(text, __instance.Name);
				Plugin.Log.LogInfo((object)("[Rebirth] Changed death text from '" + text2 + "' to '" + __result + "'"));
				UnmarkFollowerRebirth(__instance.ID);
			}
			else
			{
				Plugin.Log.LogInfo((object)"[Rebirth] Follower not in rebirth set - using vanilla death text");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(DropLootOnDeath), "OnDie")]
		public static void DropLootOnDeath_OnDie(DropLootOnDeath __instance, Health Victim)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Victim.team == 2)
			{
				if (Random.Range(0, 101) <= Plugin.EnemyDropRate.Value)
				{
					Plugin.Log.LogInfo((object)("Got a Rebirth token from " + ((Object)__instance).name + "!"));
					InventoryItem.Spawn(Plugin.RebirthItem, Random.Range(Plugin.DropMinQuantity.Value, Plugin.DropMaxQuantity.Value + 1), ((Component)__instance).transform.position, 4f, (Action<PickUp>)null);
				}
			}
			else if (((Object)Victim).name.ToLower(CultureInfo.InvariantCulture).Contains("breakable body pile") && Random.Range(0, 101) <= Plugin.EnemyDropRate.Value)
			{
				Plugin.Log.LogInfo((object)("Got a Rebirth token from " + ((Object)__instance).name + "!"));
				InventoryItem.Spawn(Plugin.RebirthItem, Random.Range(Plugin.DropMinQuantity.Value, Plugin.DropMaxQuantity.Value + 1), ((Component)__instance).transform.position, 4f, (Action<PickUp>)null);
			}
		}
	}
	[BepInPlugin("p1xel8ted.cotl.rebirth", "Rebirth", "1.1.5")]
	[BepInDependency("io.github.xhayper.COTL_API", "0.3.1")]
	[BepInDependency("com.bepis.bepinex.configurationmanager", "18.4.1")]
	[HarmonyPatch]
	public class Plugin : BaseUnityPlugin
	{
		private const string PluginGuid = "p1xel8ted.cotl.rebirth";

		private const string PluginName = "Rebirth";

		private const string PluginVer = "1.1.5";

		private const string RebirthSection = "── Rebirth ──";

		private const string TokenDropsSection = "── Token Drops ──";

		private const string DungeonChestsSection = "── Dungeon Chests ──";

		private const string RefinerySection = "── Refinery ──";

		private const string MissionsSection = "── Missions ──";

		public static readonly ModdedSaveData<List<int>> RebirthSaveData = new ModdedSaveData<List<int>>("p1xel8ted.cotl.rebirth");

		public static ManualLogSource Log { get; private set; }

		public static string PluginPath { get; private set; }

		public static ITEM_TYPE RebirthItem { get; private set; }

		private CustomObjective RebirthCollectItemQuest { get; set; }

		internal static ConfigEntry<bool> RebirthOldFollowers { get; private set; }

		internal static ConfigEntry<bool> PreserveUniqueFollowers { get; private set; }

		internal static ConfigEntry<int> XpPenaltyChance { get; private set; }

		internal static ConfigEntry<int> XpPenaltyMultiplier { get; private set; }

		internal static ConfigEntry<int> TokenCost { get; private set; }

		internal static ConfigEntry<int> EnemyDropRate { get; private set; }

		internal static ConfigEntry<int> DropMinQuantity { get; private set; }

		internal static ConfigEntry<int> DropMaxQuantity { get; private set; }

		internal static ConfigEntry<int> ChestSpawnChance { get; private set; }

		internal static ConfigEntry<int> ChestMinAmount { get; private set; }

		internal static ConfigEntry<int> ChestMaxAmount { get; private set; }

		internal static ConfigEntry<int> BoneCost { get; private set; }

		internal static ConfigEntry<int> RefineryDuration { get; private set; }

		internal static ConfigEntry<int> MissionRewardMin { get; private set; }

		internal static ConfigEntry<int> MissionRewardMax { get; private set; }

		internal static ConfigEntry<int> MissionBaseChance { get; private set; }

		private void Awake()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			((BaseModdedSaveData)RebirthSaveData).LoadOrder = (ModdedSaveLoadOrder)0;
			ModdedSaveManager.RegisterModdedSave((BaseModdedSaveData)(object)RebirthSaveData);
			Log = ((BaseUnityPlugin)this).Logger;
			PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? throw new DirectoryNotFoundException();
			BindConfig();
			CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new RebirthFollowerCommand());
			CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new RebirthSubCommand());
			RebirthItem = CustomItemManager.Add((CustomInventoryItem)(object)new RebirthItem());
			CustomMissionManager.Add((CustomMission)(object)new MissionItem());
			RebirthCollectItemQuest = CustomObjectiveManager.CollectItem(RebirthItem, Random.Range(15, 26), false, (FollowerLocation)7, 4800f);
			RebirthCollectItemQuest.InitialQuestText = "Please leader, please! I'm " + StringExtensions.Wave("weary of this existence") + " and seek to be reborn! I will do anything for you! Can you please help me?";
			RegisterSettings();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "p1xel8ted.cotl.rebirth");
			ModLogging.Init(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
		}

		private void BindConfig()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Expected O, but got Unknown
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Expected O, but got Unknown
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Expected O, but got Unknown
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Expected O, but got Unknown
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Expected O, but got Unknown
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Expected O, but got Unknown
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Expected O, but got Unknown
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Expected O, but got Unknown
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Expected O, but got Unknown
			RebirthOldFollowers = ((BaseUnityPlugin)this).Config.Bind<bool>("── Rebirth ──", "Rebirth Old Followers", false, new ConfigDescription("Allow old followers to be reborn.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 5
				}
			}));
			PreserveUniqueFollowers = ((BaseUnityPlugin)this).Config.Bind<bool>("── Rebirth ──", "Preserve Unique Followers", true, new ConfigDescription("When enabled, unique followers (Webber, Sozo, Ratau, etc.) retain their original skin and traits when reborn. Names are always randomized.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 4
				}
			}));
			XpPenaltyChance = ((BaseUnityPlugin)this).Config.Bind<int>("── Rebirth ──", "XP Penalty Chance", 20, new ConfigDescription("Chance (%) of losing XP during rebirth.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 3
				}
			}));
			XpPenaltyMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("── Rebirth ──", "XP Kept On Penalty", 50, new ConfigDescription("Percentage of XP kept when penalty triggers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 90), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2,
					DispName = "    └ XP Kept On Penalty"
				}
			}));
			TokenCost = ((BaseUnityPlugin)this).Config.Bind<int>("── Rebirth ──", "Token Cost", 25, new ConfigDescription("Tokens required for subsequent rebirths.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1
				}
			}));
			EnemyDropRate = ((BaseUnityPlugin)this).Config.Bind<int>("── Token Drops ──", "Enemy Drop Rate", 5, new ConfigDescription("Chance (%) of tokens dropping from enemies.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 3
				}
			}));
			DropMinQuantity = ((BaseUnityPlugin)this).Config.Bind<int>("── Token Drops ──", "Drop Min Quantity", 1, new ConfigDescription("Minimum tokens per drop.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2,
					DispName = "    └ Drop Min Quantity"
				}
			}));
			DropMaxQuantity = ((BaseUnityPlugin)this).Config.Bind<int>("── Token Drops ──", "Drop Max Quantity", 2, new ConfigDescription("Maximum tokens per drop.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1,
					DispName = "    └ Drop Max Quantity"
				}
			}));
			ChestSpawnChance = ((BaseUnityPlugin)this).Config.Bind<int>("── Dungeon Chests ──", "Chest Spawn Chance", 5, new ConfigDescription("Chance (%) of tokens appearing in dungeon chests.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 3
				}
			}));
			ChestMinAmount = ((BaseUnityPlugin)this).Config.Bind<int>("── Dungeon Chests ──", "Chest Min Amount", 4, new ConfigDescription("Minimum tokens per chest.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2,
					DispName = "    └ Chest Min Amount"
				}
			}));
			ChestMaxAmount = ((BaseUnityPlugin)this).Config.Bind<int>("── Dungeon Chests ──", "Chest Max Amount", 7, new ConfigDescription("Maximum tokens per chest.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1,
					DispName = "    └ Chest Max Amount"
				}
			}));
			BoneCost = ((BaseUnityPlugin)this).Config.Bind<int>("── Refinery ──", "Bone Cost", 15, new ConfigDescription("Bones required to refine a token.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2
				}
			}));
			RefineryDuration = ((BaseUnityPlugin)this).Config.Bind<int>("── Refinery ──", "Refinery Duration", 256, new ConfigDescription("Refinery duration in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 600), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1
				}
			}));
			MissionBaseChance = ((BaseUnityPlugin)this).Config.Bind<int>("── Missions ──", "Mission Base Chance", 50, new ConfigDescription("Mission appearance chance (%).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 3
				}
			}));
			MissionRewardMin = ((BaseUnityPlugin)this).Config.Bind<int>("── Missions ──", "Mission Reward Min", 15, new ConfigDescription("Minimum token reward from missions.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 2,
					DispName = "    └ Mission Reward Min"
				}
			}));
			MissionRewardMax = ((BaseUnityPlugin)this).Config.Bind<int>("── Missions ──", "Mission Reward Max", 25, new ConfigDescription("Maximum token reward from missions.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Order = 1,
					DispName = "    └ Mission Reward Max"
				}
			}));
		}

		private static void RegisterSettings()
		{
			CustomSettingsManager.AddBepInExConfig("Rebirth", "Rebirth Old Followers", RebirthOldFollowers, (Action<bool>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth", "Preserve Unique Followers", PreserveUniqueFollowers, (Action<bool>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth", "XP Penalty Chance", XpPenaltyChance, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth", "XP Kept On Penalty", XpPenaltyMultiplier, 5, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth", "Token Cost", TokenCost, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Drops", "Enemy Drop Rate", EnemyDropRate, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Drops", "Drop Min Quantity", DropMinQuantity, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Drops", "Drop Max Quantity", DropMaxQuantity, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Chests", "Chest Spawn Chance", ChestSpawnChance, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Chests", "Chest Min Amount", ChestMinAmount, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Chests", "Chest Max Amount", ChestMaxAmount, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Refinery", "Bone Cost", BoneCost, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Refinery", "Refinery Duration", RefineryDuration, 10, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Missions", "Mission Reward Min", MissionRewardMin, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Missions", "Mission Reward Max", MissionRewardMax, 1, (ValueDisplayFormat)1, (Action<int>)null);
			CustomSettingsManager.AddBepInExConfig("Rebirth - Missions", "Mission Base Chance", MissionBaseChance, 1, (ValueDisplayFormat)1, (Action<int>)null);
		}
	}
	internal class RebirthFollowerCommand : CustomFollowerCommand
	{
		public override string InternalName => "REBIRTH_COMMAND";

		public override Sprite CommandIcon => TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "assets", "rebirth_command.png"));

		private static bool BornAgainFollower { get; set; }

		public override string GetTitle(Follower follower)
		{
			return "Rebirth";
		}

		public RebirthFollowerCommand()
		{
			((CommandItem)this).SubCommands = FollowerCommandGroups.AreYouSureCommands();
		}

		public override string GetDescription(Follower follower)
		{
			return "This follower getting you down? Order a rebirth!";
		}

		public override string GetLockedDescription(Follower follower)
		{
			if (DataManager.Instance.Followers_Recruit.Count > 0)
			{
				return "You already have a follower awaiting indoctrination!";
			}
			if (Helper.IsOld(follower))
			{
				return "Not enough life essence left to satisfy those below.";
			}
			return "Yeah, you shouldn't be seeing this...";
		}

		public override bool IsAvailable(Follower follower)
		{
			if (DataManager.Instance.Followers_Recruit.Count > 0)
			{
				return false;
			}
			if (Helper.IsOld(follower))
			{
				return false;
			}
			BornAgainFollower = SaveData.FollowerBornAgain(follower.Brain._directInfoAccess);
			return !BornAgainFollower;
		}

		public override bool ShouldAppearFor(Follower follower)
		{
			return !SaveData.FollowerBornAgain(follower.Brain._directInfoAccess);
		}

		private static IEnumerator GiveFollowerIE(FollowerInfo f, Follower old)
		{
			yield return DieRoutine(old);
			yield return (object)new WaitForSeconds(3f);
			BiomeBaseManager.Instance.SpawnExistingRecruits = false;
			yield return (object)new WaitForEndOfFrame();
			yield return (object)new WaitForSeconds(3f);
			DataManager.Instance.Followers_Recruit.Add(f);
			FollowerManager.SpawnExistingRecruitsInBase(BiomeBaseManager.Instance.RecruitSpawnLocation.transform.position);
			FollowerRecruit obj = Object.FindObjectOfType<FollowerRecruit>();
			if (obj != null)
			{
				obj.ManualTriggerAnimateIn();
			}
			BiomeBaseManager.Instance.SpawnExistingRecruits = true;
			NotificationCentre.NotificationsEnabled = true;
			yield return (object)new WaitForSeconds(2f);
		}

		internal static void SpawnRecruit(Follower follower)
		{
			FollowerBrainInfo info = follower.Brain.Info;
			FollowerInfo info2 = info._info;
			bool flag = Plugin.PreserveUniqueFollowers.Value && Helper.IsUniqueFollower(info);
			BiomeBaseManager.Instance.SpawnExistingRecruits = true;
			NotificationCentre.NotificationsEnabled = false;
			string name = info.Name;
			int iD = info.ID;
			int xPLevel = info.XPLevel;
			int num = Mathf.CeilToInt((float)(xPLevel * Plugin.XpPenaltyMultiplier.Value) / 100f);
			bool flag2 = Helper.DoHalfStats();
			FollowerInfo val = (flag ? FollowerInfo.NewCharacter((FollowerLocation)1, info2.SkinName) : FollowerInfo.NewCharacter((FollowerLocation)1, ""));
			if (val != null)
			{
				if (flag)
				{
					val.SkinColour = info2.SkinColour;
					val.Traits = new List<TraitType>(info2.Traits);
					Plugin.Log.LogInfo((object)("Unique follower rebirth: " + name + " -> " + val.Name + " (skin: " + info2.SkinName + ", traits: " + string.Join(", ", info2.Traits) + ")"));
				}
				((MonoBehaviour)GameManager.GetInstance()).StartCoroutine(GiveFollowerIE(val, follower));
				Plugin.Log.LogInfo((object)$"New follower: {val.Name} (unique: {flag})");
				SaveData.AddBornAgainFollower(val);
				val.XPLevel = (flag2 ? num : xPLevel);
			}
			else
			{
				Plugin.Log.LogWarning((object)"New follower is null!");
				NotificationCentre.NotificationsEnabled = true;
			}
			((MonoBehaviour)GameManager.GetInstance()).StartCoroutine(ShowMessages(name, flag2));
			RemoveFromDeadLists(iD);
		}

		private static IEnumerator ShowMessages(string name, bool halfXp)
		{
			yield return (object)new WaitForSeconds(3f);
			NotificationCentreScreen.Play(name + " died to be reborn! All hail " + name + "!");
			yield return (object)new WaitForSeconds(5f);
			if (halfXp)
			{
				NotificationCentre.Instance.PlayGenericNotification("Oh no! " + name + " lost half of their XP during Rebirth!", (Flair)0);
				yield return (object)new WaitForSeconds(3f);
			}
		}

		private static void RemoveFromDeadLists(int id)
		{
			Follower.Followers.RemoveAll((Follower a) => a.Brain._directInfoAccess.ID == id);
			DataManager.Instance.Followers_Dead.RemoveAll((FollowerInfo a) => a.ID == id);
			DataManager.Instance.Followers_Dead_IDs.RemoveAll((int a) => a == id);
		}

		private static IEnumerator DieRoutine(Follower follower)
		{
			int followerId = follower.Brain.Info.ID;
			string followerName = follower.Brain.Info.Name;
			Plugin.Log.LogInfo((object)$"[Rebirth] DieRoutine started for '{followerName}' (ID: {followerId})");
			Patches.MarkFollowerForRebirth(followerId);
			follower.HideAllFollowerIcons();
			yield return (object)new WaitForSeconds(0.5f);
			follower.State.CURRENT_STATE = (State)49;
			yield return (object)new WaitForSeconds(1f);
			follower.SetBodyAnimation("wave", true);
			yield return (object)new WaitForSeconds(0.75f);
			follower.Brain._directInfoAccess.DiedOfOldAge = true;
			Plugin.Log.LogInfo((object)$"[Rebirth] Calling Die() for '{followerName}' (ID: {followerId})");
			follower.Die((NotificationType)79, true, 1, "die", "dead", (Action<GameObject>)null, true);
			Plugin.Log.LogInfo((object)$"[Rebirth] Die() completed for '{followerName}' (ID: {followerId})");
			Plugin.Log.LogInfo((object)"[Rebirth] Follower will be unmarked when GetDeathText is called during death animation");
		}

		public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)finalCommand == 40)
			{
				interaction.Close(true, true, false);
				SpawnRecruit(interaction.follower);
			}
		}
	}
	public sealed class RebirthItem : CustomInventoryItem
	{
		public override Sprite InventoryIcon { get; } = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "assets", "rebirth_item.png"));

		public override Sprite Sprite { get; } = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "assets", "rebirth_item.png"));

		public override string InternalName => "REBIRTH_ITEM";

		public override bool AddItemToDungeonChests => true;

		public override int DungeonChestSpawnChance => Plugin.ChestSpawnChance.Value;

		public override int DungeonChestMinAmount => Plugin.ChestMinAmount.Value;

		public override int DungeonChestMaxAmount => Plugin.ChestMaxAmount.Value;

		public override Vector3 LocalScale { get; } = new Vector3(0.5f, 0.5f, 0.5f);

		public override ITEM_TYPE ItemPickUpToImitate => (ITEM_TYPE)20;

		public override ItemRarity Rarity => (ItemRarity)1;

		public override bool AddItemToOfferingShrine => true;

		public override bool CanBeRefined => true;

		public override ITEM_TYPE RefineryInput => (ITEM_TYPE)9;

		public override int RefineryInputQty => Plugin.BoneCost.Value;

		public override float CustomRefineryDuration => Plugin.RefineryDuration.Value;

		public override ITEM_CATEGORIES ItemCategory => (ITEM_CATEGORIES)8;

		public override bool IsCurrency => true;

		public override string LocalizedDescription()
		{
			return "A special token obtained while on crusades that are used as currency to Rebirth followers.";
		}

		public override string LocalizedName()
		{
			return "Rebirth Token";
		}

		public override string LocalizedLore()
		{
			return "Said to be dropped by Death herself.";
		}
	}
	internal class RebirthSubCommand : CustomFollowerCommand
	{
		private static int ItemQty => Plugin.TokenCost.Value;

		public override string InternalName => "REBIRTH_SUB_COMMAND";

		public override Sprite CommandIcon { get; } = TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "assets", "rebirth_command.png"));

		public override string GetTitle(Follower follower)
		{
			return $"Rebirth for {ItemQty} tokens.";
		}

		public RebirthSubCommand()
		{
			((CommandItem)this).SubCommands = FollowerCommandGroups.AreYouSureCommands();
		}

		public override string GetDescription(Follower follower)
		{
			return "Perform a Rebirth using special tokens obtained while on crusades.";
		}

		public override string GetLockedDescription(Follower follower)
		{
			if (DataManager.Instance.Followers_Recruit.Count > 0)
			{
				return "You already have a follower awaiting indoctrination!";
			}
			if (Helper.IsOld(follower))
			{
				return "Not enough life essence left to satisfy those below.";
			}
			return "Requires 25 Rebirth tokens to perform.";
		}

		public override bool ShouldAppearFor(Follower follower)
		{
			return SaveData.FollowerBornAgain(follower.Brain._directInfoAccess);
		}

		public override bool IsAvailable(Follower follower)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected I4, but got Unknown
			if (DataManager.Instance.Followers_Recruit.Count > 0)
			{
				return false;
			}
			if (Helper.IsOld(follower))
			{
				return false;
			}
			return Inventory.GetItemQuantity((int)Plugin.RebirthItem) >= ItemQty;
		}

		public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)finalCommand == 40)
			{
				interaction.Close(true, true, false);
				RebirthFollowerCommand.SpawnRecruit(interaction.follower);
				Inventory.ChangeItemQuantity(Plugin.RebirthItem, -ItemQty, 0);
			}
		}
	}
	public static class SaveData
	{
		public static bool FollowerBornAgain(FollowerInfo followerInfo)
		{
			if (Plugin.RebirthSaveData.Data != null)
			{
				return Plugin.RebirthSaveData.Data.Exists((int a) => a == followerInfo.ID);
			}
			return false;
		}

		public static void AddBornAgainFollower(FollowerInfo followerInfo)
		{
			Plugin.RebirthSaveData.Data?.Add(followerInfo.ID);
			((BaseModdedSaveData)Plugin.RebirthSaveData).Save(true, true);
			Plugin.Log.LogInfo((object)("Saved follower data for " + followerInfo.Name));
		}
	}
}
namespace Shared
{
	public static class Helpers
	{
		internal static List<Follower> AllFollowers => FollowerManager.Followers.SelectMany((KeyValuePair<FollowerLocation, List<Follower>> followerList) => followerList.Value).ToList();

		private static bool ContainsIgnoreCase(this string source, string value)
		{
			if (source == null)
			{
				return false;
			}
			return source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		public static bool IsMultiplierActive(float value)
		{
			return !Mathf.Approximately(value, 1f);
		}

		public static IEnumerator FilterEnumerator(IEnumerator original, Type[] typesToRemove)
		{
			while (original.MoveNext())
			{
				object current = original.Current;
				if (current != null && !ArrayExtensions.Contains<Type>(typesToRemove, current.GetType()))
				{
					yield return current;
				}
			}
		}

		public static void LogCallStack(ManualLogSource logger, int skipFrames = 3, int maxFrames = 10)
		{
			StackTrace stackTrace = new StackTrace(fNeedFileInfo: false);
			int frameCount = stackTrace.FrameCount;
			for (int i = skipFrames; i < frameCount && i < maxFrames; i++)
			{
				MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
				logger.LogWarning((object)string.Format(arg1: (methodBase?.DeclaringType)?.FullName, format: "[Frame {0}] {1}.{2}", arg0: i, arg2: methodBase?.Name));
			}
		}

		public static Type GetCallingType(ICollection<Type> targetTypes, int skipFrames = 3, int maxFrames = 10)
		{
			StackTrace stackTrace = new StackTrace(fNeedFileInfo: false);
			int frameCount = stackTrace.FrameCount;
			for (int i = skipFrames; i < frameCount && i < maxFrames; i++)
			{
				Type type = stackTrace.GetFrame(i)?.GetMethod()?.DeclaringType;
				if (type != null && targetTypes.Contains(type))
				{
					return type;
				}
			}
			return null;
		}

		public static bool IsCalledFrom(string typeNameContains, string methodNameContains = null, int skipFrames = 3, int maxFrames = 10)
		{
			StackTrace stackTrace = new StackTrace(fNeedFileInfo: false);
			int frameCount = stackTrace.FrameCount;
			for (int i = skipFrames; i < frameCount && i < maxFrames; i++)
			{
				MethodBase methodBase = stackTrace.GetFrame(i)?.GetMethod();
				Type type = methodBase?.DeclaringType;
				if (!(type == null))
				{
					bool num = type.FullName.ContainsIgnoreCase(typeNameContains);
					bool flag = methodNameContains == null || methodBase.Name.ContainsIgnoreCase(methodNameContains);
					if (num && flag)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	internal static class StartupLogger
	{
		private const string LogSourceName = "Cult of the Lamb Mods";

		private static bool _scheduled;

		private static readonly string[] PiracyFiles = new string[76]
		{
			"SmartSteamEmu.ini", "steam_emu.ini", "goldberg_emulator.dll", "steamclient_loader.dll", "steam_api64_o.dll", "steam_api.cdx", "steam_api64.cdx.dll", "steam_interfaces.txt", "local_save.txt", "valve.ini",
			"coldclient.dll", "ColdClientLoader.ini", "steamless.dll", "GreenLuma", "SteamFix.dll", "SteamFix64.dll", "LumaEmu.ini", "Lumaplay", "account_name.txt", "user_steam_id.txt",
			"force_listen_port.txt", "goldberg_steam_appid.txt", "CreamAPI.dll", "creamapi.dll", "cream_api.ini", "ScreamAPI.dll", "UnlockAll.dll", "Koaloader.dll", "Koaloader64.dll", "OnlineFix.dll",
			"OnlineFix.url", "online-fix.me", "codex.ini", "codex64.dll", "CODEX", "SKIDROW", "SKIDROW.ini", "CPY", "PLAZA", "HOODLUM",
			"EMPRESS", "TENOKE", "PROPHET", "REVOLT", "DARKSiDERS", "RAZOR1911", "FLT", "FLT.dll", "RUNE", "RUNE.ini",
			"TiNYiSO", "RELOADED", "RLD!", "DOGE", "CHRONOS", "DINOByTES", "I_KnoW", "ElAmigos", "FitGirl", "DODI",
			"xatab", "KaOs", "IGG", "Masquerade", "3dmgame.dll", "ALI213.dll", "crack.exe", "Crack.nfo", "crackfix", "CrackOnly",
			"gamefix.dll", "nosTEAM", "NoSteam", "FCKDRM", "NoDRM", "VALVEEMPRESS"
		};

		public static void EnsureStarted()
		{
			if (_scheduled)
			{
				return;
			}
			_scheduled = true;
			try
			{
				GameObject managerObject = Chainloader.ManagerObject;
				if ((Object)(object)managerObject == (Object)null)
				{
					return;
				}
				MonoBehaviour[] components = managerObject.GetComponents<MonoBehaviour>();
				foreach (MonoBehaviour val in components)
				{
					if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "StartupLoggerRunner")
					{
						return;
					}
				}
				managerObject.AddComponent<StartupLoggerRunner>();
			}
			catch (Exception arg)
			{
				Logger.CreateLogSource("Cult of the Lamb Mods").LogError((object)$"StartupLogger.EnsureStarted failed: {arg}");
			}
		}

		internal static void LogSummary()
		{
			//IL_0030: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string version = Application.version;
				Version version2 = typeof(Chainloader).Assembly.GetName().Version;
				GameObject managerObject = Chainloader.ManagerObject;
				bool flag = (Object)(object)managerObject != (Object)null && ((Enum)((Object)managerObject).hideFlags).HasFlag((Enum)(object)(HideFlags)61);
				string buildGUID = Application.buildGUID;
				Platform current = PlatformHelper.Current;
				string text = DetectStorefront();
				ManualLogSource val = Logger.CreateLogSource("Cult of the Lamb Mods");
				val.LogInfo((object)"==========================================");
				val.LogInfo((object)"  Cult of the Lamb Mod Summary");
				val.LogInfo((object)"==========================================");
				val.LogInfo((object)("  Game      : ver. " + version + " (BuildGUID: " + buildGUID + ")"));
				val.LogInfo((object)$"  BepInEx   : v{version2} (Manager Hidden: {flag})");
				val.LogInfo((object)$"  Platform  : {current}");
				val.LogInfo((object)("  Storefront: " + text));
				if (!flag)
				{
					val.LogWarning((object)"  BepInEx Manager GameObject is NOT hidden - Unity event methods (Awake, Start, Update) will not fire on plugins!");
					val.LogWarning((object)"  To fix: open BepInEx/config/BepInEx.cfg, find [Chainloader] section, set HideManagerGameObject = true");
				}
				val.LogInfo((object)"------------------------------------------");
				val.LogInfo((object)"  Loaded plugins:");
				foreach (PluginInfo item in Chainloader.PluginInfos.Values.OrderBy((PluginInfo p) => p.Metadata.Name))
				{
					val.LogInfo((object)$"    {item.Metadata.Name} v{item.Metadata.Version} | {item.Metadata.GUID}");
				}
				val.LogInfo((object)"------------------------------------------");
				val.LogInfo((object)$"  Total: {Chainloader.PluginInfos.Count} plugins");
				val.LogInfo((object)"------------------------------------------");
				val.LogInfo((object)"  Plugin configurations:");
				LogPluginConfigs(val);
				val.LogInfo((object)"==========================================");
				if (!Chainloader.ConfigHideBepInExGOs.Value)
				{
					val.LogWarning((object)"  BepInEx HideManagerGameObject was disabled - enabling it to prevent Unity event methods from failing");
					Chainloader.ConfigHideBepInExGOs.Value = true;
					if (Object.op_Implicit((Object)(object)managerObject))
					{
						((Object)managerObject).hideFlags = (HideFlags)61;
						Object.DontDestroyOnLoad((Object)(object)managerObject);
					}
				}
				Logger.Sources.Remove((ILogSource)(object)val);
			}
			catch (Exception arg)
			{
				Logger.CreateLogSource("Cult of the Lamb Mods").LogError((object)$"StartupLogger failed: {arg}");
			}
		}

		private static void LogPluginConfigs(ManualLogSource log)
		{
			foreach (PluginInfo item in Chainloader.PluginInfos.Values.OrderBy((PluginInfo p) => p.Metadata.Name))
			{
				try
				{
					BaseUnityPlugin instance = item.Instance;
					if (instance == null)
					{
						log.LogInfo((object)("  [" + item.Metadata.Name + "] (instance not available)"));
						continue;
					}
					ConfigFile config = instance.Config;
					if (config == null || config.Keys.Count == 0)
					{
						log.LogInfo((object)("  [" + item.Metadata.Name + "] (no config entries)"));
						continue;
					}
					log.LogInfo((object)("  [" + item.Metadata.Name + "]"));
					foreach (IGrouping<string, ConfigDefinition> item2 in from k in config.Keys
						group k by k.Section into g
						orderby g.Key
						select g)
					{
						log.LogInfo((object)("    " + item2.Key));
						foreach (ConfigDefinition item3 in item2.OrderBy((ConfigDefinition k) => k.Key))
						{
							object arg;
							try
							{
								arg = config[item3].BoxedValue;
							}
							catch (Exception ex)
							{
								arg = "<error reading value: " + ex.Message + ">";
							}
							log.LogInfo((object)$"      {item3.Key} = {arg}");
						}
					}
				}
				catch (Exception ex2)
				{
					log.LogInfo((object)("  [" + item.Metadata.Name + "] (config dump failed: " + ex2.Message + ")"));
				}
			}
		}

		private static string[] GetSearchDirs()
		{
			string currentDirectory = Directory.GetCurrentDirectory();
			List<string> list = new List<string> { currentDirectory };
			try
			{
				string[] directories = Directory.GetDirectories(currentDirectory, "*_Data");
				for (int i = 0; i < directories.Length; i++)
				{
					string text = Path.Combine(directories[i], "Plugins");
					if (Directory.Exists(text))
					{
						list.Add(text);
						list.AddRange(Directory.GetDirectories(text));
					}
				}
			}
			catch
			{
			}
			return list.ToArray();
		}

		private static bool FileExistsInAny(string[] dirs, string filename)
		{
			return dirs.Any((string d) => File.Exists(Path.Combine(d, filename)));
		}

		private static bool DirExistsInAny(string[] dirs, string dirname)
		{
			return dirs.Any((string d) => Directory.Exists(Path.Combine(d, dirname)));
		}

		private static string DetectStorefront()
		{
			string currentDirectory = Directory.GetCurrentDirectory();
			string[] dirs = GetSearchDirs();
			string text = "Unknown";
			if (FileExistsInAny(dirs, "steam_api.dll") || FileExistsInAny(dirs, "steam_api64.dll") || File.Exists(Path.Combine(currentDirectory, "steam_appid.txt")))
			{
				text = "Steam";
			}
			else if (Directory.GetFiles(currentDirectory, "goggame-*.info").Any() || FileExistsInAny(dirs, "galaxy.dll") || FileExistsInAny(dirs, "Galaxy64.dll") || FileExistsInAny(dirs, "GalaxyPeer.dll"))
			{
				text = "GOG";
			}
			else if (FileExistsInAny(dirs, "EOSSDK-Win64-Shipping.dll") || FileExistsInAny(dirs, "EpicOnlineServices.dll") || Directory.Exists(Path.Combine(currentDirectory, ".egstore")))
			{
				text = "Epic";
			}
			else if (currentDirectory.Contains("WindowsApps") || File.Exists(Path.Combine(currentDirectory, "appxmanifest.xml")) || File.Exists(Path.Combine(currentDirectory, "microsoft.gameconfig")))
			{
				text = "Xbox/Microsoft Store";
			}
			else if (IsProcessRunning("steam"))
			{
				text = "Steam (process only)";
			}
			else if (IsProcessRunning("GalaxyClient"))
			{
				text = "GOG (process only)";
			}
			else if (IsProcessRunning("EpicGamesLauncher"))
			{
				text = "Epic (process only)";
			}
			else if (IsProcessRunning("XboxApp") || IsProcessRunning("GamingServices"))
			{
				text = "Xbox (process only)";
			}
			bool flag = PiracyFiles.Any((string pirate) => FileExistsInAny(dirs, pirate) || DirExistsInAny(dirs, pirate));
			if (!flag && Directory.Exists(Path.Combine(currentDirectory, "steam_settings")))
			{
				string path = Path.Combine(currentDirectory, "steam_settings");
				flag = File.Exists(Path.Combine(path, "force_account_name.txt")) || File.Exists(Path.Combine(path, "force_steamid.txt")) || File.Exists(Path.Combine(path, "force_language.txt"));
			}
			if (flag)
			{
				text += " + Possible Pirated/Cracked Files Found!";
			}
			return text;
		}

		private static bool IsProcessRunning(string name)
		{
			return Process.GetProcessesByName(name).Length != 0;
		}
	}
	internal sealed class StartupLoggerRunner : MonoBehaviour
	{
		private IEnumerator Start()
		{
			yield return null;
			StartupLogger.LogSummary();
		}
	}
	internal static class SettingsChangeLogger
	{
		public static void Register(ConfigFile config, TimestampedLogger log)
		{
			if (config == null || log == null)
			{
				return;
			}
			try
			{
				Dictionary<ConfigDefinition, object> snapshot = new Dictionary<ConfigDefinition, object>();
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
				{
					snapshot[item.Key] = item.Value.BoxedValue;
				}
				config.SettingChanged += delegate(object _, SettingChangedEventArgs args)
				{
					try
					{
						ConfigEntryBase val = ((args != null) ? args.ChangedSetting : null);
						if (val != null)
						{
							ConfigDefinition definition = val.Definition;
							object boxedValue = val.BoxedValue;
							snapshot.TryGetValue(definition, out var value);
							if (!object.Equals(value, boxedValue))
							{
								log.LogInfo("Setting changed: [" + definition.Section + "/" + definition.Key + "] '" + Format(value) + "' -> '" + Format(boxedValue) + "'");
								snapshot[definition] = boxedValue;
							}
						}
					}
					catch
					{
					}
				};
				config.ConfigReloaded += delegate
				{
					try
					{
						foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in config)
						{
							if (!snapshot.ContainsKey(item2.Key))
							{
								snapshot[item2.Key] = item2.Value.BoxedValue;
							}
						}
					}
					catch
					{
					}
				};
			}
			catch (Exception ex)
			{
				try
				{
					log.LogWarning("SettingsChangeLogger.Register failed: " + ex.GetType().Name + ": " + ex.Message);
				}
				catch
				{
				}
			}
		}

		private static string Format(object value)
		{
			if (value != null)
			{
				return value.ToString();
			}
			return "null";
		}
	}
	internal sealed class TimestampedLogger
	{
		private static readonly Stopwatch ProcessClock = Stopwatch.StartNew();

		private readonly ManualLogSource _source;

		internal TimestampedLogger(ManualLogSource source)
		{
			_source = source;
		}

		private static string Prefix()
		{
			return $"[{DateTime.Now:HH:mm:ss.fff} | T+{ProcessClock.Elapsed.TotalSeconds:0.000}] ";
		}

		internal void LogInfo(object data)
		{
			_source.LogInfo((object)(Prefix() + data));
		}

		internal void LogWarning(object data)
		{
			_source.LogWarning((object)(Prefix() + data));
		}

		internal void LogError(object data)
		{
			_source.LogError((object)(Prefix() + data));
		}

		internal void LogDebug(object data)
		{
			_source.LogDebug((object)(Prefix() + data));
		}
	}
	internal static class ModLogging
	{
		public static void Init(ConfigFile config, ManualLogSource logger)
		{
			SettingsChangeLogger.Register(config, new TimestampedLogger(logger));
			StartupLogger.EnsureStarted();
		}
	}
}