Decompiled source of Exhausted Batteries v1.4.2

ExhaustedBatteries.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExhaustedBatteries")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+94f676050750c60ae337e4d70b57fb451c4822b0")]
[assembly: AssemblyProduct("Exhausted Batteries")]
[assembly: AssemblyTitle("ExhaustedBatteries")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ExhaustedBatteries
{
	internal static class EmptyTeleporterEffects
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHostMimicReq;

			public static HandleNamedMessageDelegate <1>__OnHostCurseReq;
		}

		private const string MimicReqMsg = "ExhaustedBatteries_MimicReq";

		private const string CurseReqMsg = "ExhaustedBatteries_CurseReq";

		private static MethodInfo spawnEnemy;

		private static bool spawnEnemyResolved;

		private static bool IsHost
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					return NetworkManager.Singleton.IsServer;
				}
				return false;
			}
		}

		internal static void OnLocalConnect()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				return;
			}
			CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
			string[] array = new string[2] { "ExhaustedBatteries_MimicReq", "ExhaustedBatteries_CurseReq" };
			foreach (string text in array)
			{
				try
				{
					customMessagingManager.UnregisterNamedMessageHandler(text);
				}
				catch
				{
				}
			}
			if (singleton.IsServer)
			{
				object obj2 = <>O.<0>__OnHostMimicReq;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val = OnHostMimicReq;
					<>O.<0>__OnHostMimicReq = val;
					obj2 = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_MimicReq", (HandleNamedMessageDelegate)obj2);
				object obj3 = <>O.<1>__OnHostCurseReq;
				if (obj3 == null)
				{
					HandleNamedMessageDelegate val2 = OnHostCurseReq;
					<>O.<1>__OnHostCurseReq = val2;
					obj3 = (object)val2;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_CurseReq", (HandleNamedMessageDelegate)obj3);
			}
			TeleporterCurse.Reset();
		}

		internal static void RequestMimic(Vector3 pos)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost)
			{
				SpawnMimic(pos);
			}
			else
			{
				SendVector("ExhaustedBatteries_MimicReq", pos);
			}
		}

		private static void OnHostMimicReq(ulong sender, FastBufferReader reader)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost && ((FastBufferReader)(ref reader)).TryBeginRead(12))
			{
				Vector3 pos = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref pos);
				SpawnMimic(pos);
			}
		}

		private static void SpawnMimic(Vector3 pos)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				RoundManager instance = RoundManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				EnemyType val = FindMaskedType(instance);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[Mimic] no Masked enemy type on this moon, nothing spawned.");
					return;
				}
				if (!spawnEnemyResolved)
				{
					spawnEnemyResolved = true;
					spawnEnemy = AccessTools.Method(typeof(RoundManager), "SpawnEnemyGameObject", (Type[])null, (Type[])null);
				}
				if (spawnEnemy == null)
				{
					Plugin.Log.LogWarning((object)"[Mimic] SpawnEnemyGameObject not found.");
					return;
				}
				spawnEnemy.Invoke(instance, new object[4] { pos, 0f, -1, val });
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)"[Mimic] depleted teleporter beamed a mimic aboard.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Mimic] spawn failed: {arg}");
			}
		}

		private static EnemyType FindMaskedType(RoundManager rm)
		{
			SelectableLevel currentLevel = rm.currentLevel;
			if ((Object)(object)currentLevel == (Object)null)
			{
				return null;
			}
			List<SpawnableEnemyWithRarity>[] array = new List<SpawnableEnemyWithRarity>[3] { currentLevel.Enemies, currentLevel.OutsideEnemies, currentLevel.DaytimeEnemies };
			foreach (List<SpawnableEnemyWithRarity> list in array)
			{
				if (list == null)
				{
					continue;
				}
				foreach (SpawnableEnemyWithRarity item in list)
				{
					EnemyType val = item?.enemyType;
					if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.enemyName) && val.enemyName.IndexOf("masked", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return val;
					}
				}
			}
			return null;
		}

		internal static void RequestCurse()
		{
			if (IsHost)
			{
				TeleporterCurse.Arm();
			}
			else
			{
				SendEmpty("ExhaustedBatteries_CurseReq");
			}
		}

		private static void OnHostCurseReq(ulong sender, FastBufferReader reader)
		{
			if (IsHost)
			{
				TeleporterCurse.Arm();
			}
		}

		private unsafe static void SendVector(string msg, Vector3 pos)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe(ref pos);
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void SendEmpty(string msg)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1);
			try
			{
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, 0uL, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}
	}
	internal static class TeleporterCurse
	{
		private static int roundsLeft;

		private static bool[] wasInShip = new bool[0];

		private static float nextAllowedFire;

		private static MethodInfo getInversePos;

		private static MethodInfo teleportOutClientRpc;

		private static bool resolved;

		private static bool IsHost
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					return NetworkManager.Singleton.IsServer;
				}
				return false;
			}
		}

		internal static void Reset()
		{
			roundsLeft = 0;
			wasInShip = new bool[0];
			nextAllowedFire = 0f;
		}

		internal static void Arm()
		{
			if (IsHost && Plugin.EmptyInverseTeleporterCurse.Value)
			{
				int num = Mathf.Min(Plugin.CurseMinRounds.Value, Plugin.CurseMaxRounds.Value);
				int num2 = Mathf.Max(Plugin.CurseMinRounds.Value, Plugin.CurseMaxRounds.Value);
				roundsLeft = Random.Range(num, num2 + 1);
				nextAllowedFire = Time.time + 3f;
				SnapshotPresence();
				Plugin.Log.LogInfo((object)$"[Curse] inverse teleporter cursed: {roundsLeft} round(s) armed.");
			}
		}

		internal static void Tick()
		{
			try
			{
				if (roundsLeft <= 0 || !IsHost || !ConfigSync.IsActive)
				{
					return;
				}
				PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null);
				if (array == null || array.Length == 0)
				{
					return;
				}
				if (wasInShip.Length != array.Length)
				{
					SnapshotPresence();
					return;
				}
				bool flag = false;
				for (int i = 0; i < array.Length; i++)
				{
					PlayerControllerB val = array[i];
					if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead)
					{
						wasInShip[i] = false;
						continue;
					}
					bool isInHangarShipRoom = val.isInHangarShipRoom;
					if (isInHangarShipRoom && !wasInShip[i])
					{
						flag = true;
					}
					wasInShip[i] = isInHangarShipRoom;
				}
				if (flag && Time.time >= nextAllowedFire)
				{
					nextAllowedFire = Time.time + 5f;
					FireRound(array);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Curse] tick error: {arg}");
				roundsLeft = 0;
			}
		}

		private static void SnapshotPresence()
		{
			PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null);
			if (array == null)
			{
				wasInShip = new bool[0];
				return;
			}
			wasInShip = new bool[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				PlayerControllerB val = array[i];
				wasInShip[i] = (Object)(object)val != (Object)null && val.isPlayerControlled && !val.isPlayerDead && val.isInHangarShipRoom;
			}
		}

		private static void FireRound(PlayerControllerB[] players)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			ShipTeleporter val = FindInverseTeleporter();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[Curse] no inverse teleporter found, curse cleared.");
				roundsLeft = 0;
				return;
			}
			if (!resolved)
			{
				resolved = true;
				getInversePos = AccessTools.Method(typeof(ShipTeleporter), "GetInverseTelePosition", (Type[])null, (Type[])null);
				teleportOutClientRpc = AccessTools.Method(typeof(ShipTeleporter), "TeleportPlayerOutClientRpc", (Type[])null, (Type[])null);
			}
			if (getInversePos == null || teleportOutClientRpc == null)
			{
				Plugin.Log.LogWarning((object)"[Curse] inverse teleport methods not found, curse cleared.");
				roundsLeft = 0;
				return;
			}
			int num = 0;
			for (int i = 0; i < players.Length; i++)
			{
				PlayerControllerB val2 = players[i];
				if (!((Object)(object)val2 == (Object)null) && val2.isPlayerControlled && !val2.isPlayerDead && val2.isInHangarShipRoom)
				{
					try
					{
						Vector3 val3 = (Vector3)getInversePos.Invoke(val, null);
						teleportOutClientRpc.Invoke(val, new object[2] { i, val3 });
						num++;
					}
					catch (Exception arg)
					{
						Plugin.Log.LogError((object)$"[Curse] failed to teleport player {i}: {arg}");
					}
				}
			}
			roundsLeft--;
			Plugin.Log.LogInfo((object)$"[Curse] fired on {num} player(s), {roundsLeft} round(s) left.");
		}

		private static ShipTeleporter FindInverseTeleporter()
		{
			ShipTeleporter[] array = Object.FindObjectsOfType<ShipTeleporter>();
			foreach (ShipTeleporter val in array)
			{
				if ((Object)(object)val != (Object)null && val.isInverseTeleporter)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal static class Loc
	{
		internal enum Language
		{
			Auto,
			English,
			Russian
		}

		private static bool resolved;

		private static bool russian;

		internal static bool IsRussianResolved => IsRussian;

		private static bool IsRussian
		{
			get
			{
				if (!resolved)
				{
					Resolve();
				}
				return russian;
			}
		}

		internal static string ChargerTipHeader
		{
			get
			{
				if (!IsRussian)
				{
					return "Charging Station";
				}
				return "Зарядная станция";
			}
		}

		internal static string NoChargesLeft
		{
			get
			{
				if (!IsRussian)
				{
					return "No charges left" + (Plugin.ResetChargesEachDay.Value ? " for today." : ".");
				}
				if (!Plugin.ResetChargesEachDay.Value)
				{
					return "Заряды закончились.";
				}
				return "Заряды на сегодня закончились.";
			}
		}

		internal static string SignalTranslatorTipHeader
		{
			get
			{
				if (!IsRussian)
				{
					return "Signal Translator";
				}
				return "Сигнальный транслятор";
			}
		}

		internal static void Invalidate()
		{
			resolved = false;
		}

		private static void Resolve()
		{
			resolved = true;
			switch ((Plugin.LanguageSetting != null) ? Plugin.LanguageSetting.Value : Language.Auto)
			{
			case Language.English:
				russian = false;
				break;
			case Language.Russian:
				russian = true;
				break;
			default:
				russian = DetectRussian();
				break;
			}
		}

		private static bool DetectRussian()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			try
			{
				foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
				{
					string s = ((pluginInfo.Key != null) ? pluginInfo.Key.ToLowerInvariant() : "");
					PluginInfo value = pluginInfo.Value;
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BepInPlugin metadata = value.Metadata;
						obj = ((metadata != null) ? metadata.Name : null);
					}
					string s2 = ((obj != null) ? pluginInfo.Value.Metadata.Name.ToLowerInvariant() : "");
					if (Marks(s) || Marks(s2))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			try
			{
				if ((int)Application.systemLanguage == 30)
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool Marks(string s)
		{
			if (!s.Contains("rtlc") && !s.Contains("rulethal") && !s.Contains("russian") && !s.Contains("русск"))
			{
				return s.Contains("russiantranslation");
			}
			return true;
		}

		internal static string TeleporterTipHeader(bool inverse)
		{
			if (!IsRussian)
			{
				if (!inverse)
				{
					return "Teleporter";
				}
				return "Inverse Teleporter";
			}
			if (!inverse)
			{
				return "Телепорт";
			}
			return "Инверсный телепорт";
		}
	}
	internal enum ChargePool
	{
		Charger,
		Teleporter,
		InverseTeleporter,
		SignalTranslator
	}
	internal static class ChargerSync
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHostUsed;

			public static HandleNamedMessageDelegate <1>__OnHostExplodeReq;

			public static HandleNamedMessageDelegate <2>__OnClientState;

			public static HandleNamedMessageDelegate <3>__OnClientExplode;
		}

		private const int PoolCount = 4;

		private const string StateMsg = "ExhaustedBatteries_PoolState";

		private const string UsedMsg = "ExhaustedBatteries_PoolUsed";

		private const string ExplodeReqMsg = "ExhaustedBatteries_ExplodeReq";

		private const string ExplodeMsg = "ExhaustedBatteries_Explode";

		private static readonly int[] charges = new int[4];

		private static bool IsHost
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					return NetworkManager.Singleton.IsServer;
				}
				return false;
			}
		}

		internal static int Charges => Get(ChargePool.Charger);

		internal static bool UnlimitedCharger => Unlimited(ChargePool.Charger);

		internal static int Get(ChargePool pool)
		{
			return charges[(int)pool];
		}

		internal static int MaxFor(ChargePool pool)
		{
			return pool switch
			{
				ChargePool.Charger => Plugin.MaxCharges.Value, 
				ChargePool.Teleporter => Plugin.MaxTeleporterCharges.Value, 
				ChargePool.InverseTeleporter => Plugin.MaxInverseTeleporterCharges.Value, 
				ChargePool.SignalTranslator => Plugin.MaxSignalTranslatorCharges.Value, 
				_ => 0, 
			};
		}

		internal static bool Unlimited(ChargePool pool)
		{
			return MaxFor(pool) <= 0;
		}

		internal static void OnLocalConnect()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null)
			{
				return;
			}
			CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
			Unregister(customMessagingManager);
			if (singleton.IsServer)
			{
				object obj = <>O.<0>__OnHostUsed;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnHostUsed;
					<>O.<0>__OnHostUsed = val;
					obj = (object)val;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_PoolUsed", (HandleNamedMessageDelegate)obj);
				object obj2 = <>O.<1>__OnHostExplodeReq;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnHostExplodeReq;
					<>O.<1>__OnHostExplodeReq = val2;
					obj2 = (object)val2;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_ExplodeReq", (HandleNamedMessageDelegate)obj2);
				for (int i = 0; i < 4; i++)
				{
					charges[i] = Mathf.Max(0, MaxFor((ChargePool)i));
				}
				Broadcast();
			}
			else
			{
				object obj3 = <>O.<2>__OnClientState;
				if (obj3 == null)
				{
					HandleNamedMessageDelegate val3 = OnClientState;
					<>O.<2>__OnClientState = val3;
					obj3 = (object)val3;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_PoolState", (HandleNamedMessageDelegate)obj3);
				object obj4 = <>O.<3>__OnClientExplode;
				if (obj4 == null)
				{
					HandleNamedMessageDelegate val4 = OnClientExplode;
					<>O.<3>__OnClientExplode = val4;
					obj4 = (object)val4;
				}
				customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_Explode", (HandleNamedMessageDelegate)obj4);
			}
		}

		internal static void OnDisconnect()
		{
			Unregister(((Object)(object)NetworkManager.Singleton != (Object)null) ? NetworkManager.Singleton.CustomMessagingManager : null);
			for (int i = 0; i < 4; i++)
			{
				charges[i] = 0;
			}
		}

		private static void Unregister(CustomMessagingManager cmm)
		{
			if (cmm == null)
			{
				return;
			}
			string[] array = new string[4] { "ExhaustedBatteries_PoolState", "ExhaustedBatteries_PoolUsed", "ExhaustedBatteries_ExplodeReq", "ExhaustedBatteries_Explode" };
			foreach (string text in array)
			{
				try
				{
					cmm.UnregisterNamedMessageHandler(text);
				}
				catch
				{
				}
			}
		}

		internal static void OnLocalUse(ChargePool pool)
		{
			if (IsHost)
			{
				if (charges[(int)pool] > 0)
				{
					charges[(int)pool]--;
					Broadcast();
				}
				return;
			}
			if (charges[(int)pool] > 0)
			{
				charges[(int)pool]--;
			}
			RefreshTips();
			SendPool("ExhaustedBatteries_PoolUsed", 0uL, pool);
		}

		internal static void OnLocalCharge()
		{
			OnLocalUse(ChargePool.Charger);
		}

		internal static void DayReset()
		{
			if (!IsHost || !Plugin.ResetChargesEachDay.Value)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				ChargePool pool = (ChargePool)i;
				if (!Unlimited(pool))
				{
					charges[i] = ((!Plugin.HardResetEachDay.Value && Plugin.CarryOverUnusedCharges.Value) ? (charges[i] + MaxFor(pool)) : MaxFor(pool));
				}
			}
			Broadcast();
		}

		internal static void AddFromLightning()
		{
			if (IsHost && (0u | (TryAddOne(ChargePool.Charger, Plugin.LightningChargesStation.Value) ? 1u : 0u) | (TryAddOne(ChargePool.Teleporter, Plugin.LightningChargesTeleporter.Value) ? 1u : 0u) | (TryAddOne(ChargePool.InverseTeleporter, Plugin.LightningChargesInverseTeleporter.Value) ? 1u : 0u) | (TryAddOne(ChargePool.SignalTranslator, Plugin.LightningChargesSignalTranslator.Value) ? 1u : 0u)) != 0)
			{
				Broadcast();
			}
		}

		private static bool TryAddOne(ChargePool pool, bool enabled)
		{
			if (!enabled || Unlimited(pool))
			{
				return false;
			}
			charges[(int)pool]++;
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"[Lightning] +1 {pool} (now {charges[(int)pool]})");
			}
			return true;
		}

		internal static void QuotaReset()
		{
			if (!IsHost || !Plugin.ResetChargesOnQuota.Value)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				ChargePool pool = (ChargePool)i;
				if (!Unlimited(pool))
				{
					charges[i] = MaxFor(pool);
				}
			}
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)"[Quota] fulfilled -> all counters refilled");
			}
			Broadcast();
		}

		internal static void TriggerExplosion(Vector3 pos)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost)
			{
				BroadcastExplode(pos);
			}
			else
			{
				SendVector("ExhaustedBatteries_ExplodeReq", 0uL, pos);
			}
		}

		private static void SpawnExplosion(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Landmine.SpawnExplosion(pos + Vector3.down * 0.7f, true, 5.7f, 6.4f, 50, 65f, (GameObject)null, false);
		}

		private static void RefreshTips()
		{
			ItemChargerPatch.RefreshAllTips();
			TeleporterPatch.RefreshAllTips();
		}

		private static void Broadcast()
		{
			RefreshTips();
			if (!IsHost)
			{
				return;
			}
			foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds)
			{
				if (connectedClientsId != 0L)
				{
					SendState(connectedClientsId);
				}
			}
		}

		internal static void SendStateTo(ulong clientId)
		{
			if (IsHost)
			{
				SendState(clientId);
			}
		}

		private unsafe static void SendState(ulong clientId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1);
			try
			{
				for (int i = 0; i < 4; i++)
				{
					int num = charges[i];
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				}
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ExhaustedBatteries_PoolState", clientId, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void BroadcastExplode(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			SpawnExplosion(pos);
			if (!IsHost)
			{
				return;
			}
			foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds)
			{
				if (connectedClientsId != 0L)
				{
					SendVector("ExhaustedBatteries_Explode", connectedClientsId, pos);
				}
			}
		}

		private static void OnHostUsed(ulong senderId, FastBufferReader reader)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsHost || !((FastBufferReader)(ref reader)).TryBeginRead(1))
			{
				return;
			}
			byte b = default(byte);
			((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
			if (b < 4)
			{
				if (charges[b] > 0)
				{
					charges[b]--;
				}
				Broadcast();
			}
		}

		private static void OnHostExplodeReq(ulong senderId, FastBufferReader reader)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost && ((FastBufferReader)(ref reader)).TryBeginRead(12))
			{
				Vector3 pos = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref pos);
				BroadcastExplode(pos);
			}
		}

		private static void OnClientState(ulong _, FastBufferReader reader)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (((FastBufferReader)(ref reader)).TryBeginRead(16))
			{
				int num = default(int);
				for (int i = 0; i < 4; i++)
				{
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
					charges[i] = num;
				}
				RefreshTips();
			}
		}

		private static void OnClientExplode(ulong _, FastBufferReader reader)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (((FastBufferReader)(ref reader)).TryBeginRead(12))
			{
				Vector3 pos = default(Vector3);
				((FastBufferReader)(ref reader)).ReadValueSafe(ref pos);
				SpawnExplosion(pos);
			}
		}

		private unsafe static void SendPool(string msg, ulong clientId, ChargePool pool)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			byte b = (byte)pool;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, clientId, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void SendVector(string msg, ulong clientId, Vector3 pos)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(12, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe(ref pos);
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(msg, clientId, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}
	}
	internal static class ConfigSync
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnHostReceivedRequest;

			public static HandleNamedMessageDelegate <1>__OnClientReceivedConfig;
		}

		private const string RequestMsg = "ExhaustedBatteries_RequestConfig";

		private const string ReceiveMsg = "ExhaustedBatteries_ReceiveConfig";

		private static byte[] localBlob;

		private static byte[] hostBlob;

		internal static bool IsActive { get; private set; }

		internal static bool Applying { get; private set; }

		internal static bool IsSyncedClient => localBlob != null;

		internal static void OnLocalConnect()
		{
			RevertToLocal();
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)singleton == (Object)null))
			{
				if (singleton.IsServer)
				{
					SetupHost();
				}
				else
				{
					SetupClient();
				}
			}
		}

		private static void SetupHost()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			SafeUnregister(customMessagingManager);
			object obj = <>O.<0>__OnHostReceivedRequest;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = OnHostReceivedRequest;
				<>O.<0>__OnHostReceivedRequest = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_RequestConfig", (HandleNamedMessageDelegate)obj);
			IsActive = true;
			Plugin.Log.LogInfo((object)"[Sync] Host: local config is authoritative.");
			Plugin.ReapplyAll();
		}

		private unsafe static void SetupClient()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			SafeUnregister(customMessagingManager);
			object obj = <>O.<1>__OnClientReceivedConfig;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = OnClientReceivedConfig;
				<>O.<1>__OnClientReceivedConfig = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("ExhaustedBatteries_ReceiveConfig", (HandleNamedMessageDelegate)obj);
			IsActive = false;
			FastBufferWriter val2 = default(FastBufferWriter);
			((FastBufferWriter)(ref val2))..ctor(4, (Allocator)2, -1);
			try
			{
				customMessagingManager.SendNamedMessage("ExhaustedBatteries_RequestConfig", 0uL, val2, (NetworkDelivery)4);
				Plugin.Log.LogInfo((object)"[Sync] Client: requested host config.");
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal static void RevertToLocal()
		{
			SafeUnregister(((Object)(object)NetworkManager.Singleton != (Object)null) ? NetworkManager.Singleton.CustomMessagingManager : null);
			if (localBlob != null)
			{
				Apply(localBlob);
				localBlob = null;
			}
			hostBlob = null;
			IsActive = false;
		}

		internal static void EnforceHostAuthority()
		{
			if (IsSyncedClient && hostBlob != null)
			{
				Apply(hostBlob);
			}
		}

		private unsafe static void OnHostReceivedRequest(ulong clientId, FastBufferReader reader)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer)
			{
				return;
			}
			byte[] array = Serialize();
			int num = array.Length;
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(num + 4, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteBytesSafe(array, num, 0);
				NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ExhaustedBatteries_ReceiveConfig", clientId, val, (NetworkDelivery)4);
				Plugin.Log.LogInfo((object)$"[Sync] Host: sent config to client {clientId} ({num} bytes).");
				ChargerSync.SendStateTo(clientId);
				DischargeSync.ScheduleJoinerResync();
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void OnClientReceivedConfig(ulong _, FastBufferReader reader)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((FastBufferReader)(ref reader)).TryBeginRead(4))
				{
					return;
				}
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				if (num >= 0 && ((FastBufferReader)(ref reader)).TryBeginRead(num))
				{
					byte[] data = new byte[num];
					((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
					if (localBlob == null)
					{
						localBlob = Serialize();
					}
					hostBlob = data;
					IsActive = true;
					Apply(data);
					Plugin.ReapplyAll();
					Plugin.Log.LogInfo((object)"[Sync] Client: applied host config.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Sync] receive error: {arg}");
			}
		}

		private static void SafeUnregister(CustomMessagingManager cmm)
		{
			if (cmm == null)
			{
				return;
			}
			try
			{
				cmm.UnregisterNamedMessageHandler("ExhaustedBatteries_RequestConfig");
			}
			catch
			{
			}
			try
			{
				cmm.UnregisterNamedMessageHandler("ExhaustedBatteries_ReceiveConfig");
			}
			catch
			{
			}
		}

		private static string F(float v)
		{
			return v.ToString("R", CultureInfo.InvariantCulture);
		}

		private static byte[] Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("gm=").Append(F(Plugin.GlobalMultiplier.Value)).Append('\n');
			stringBuilder.Append("ei=").Append(Plugin.EnableIndividualMultipliers.Value).Append('\n');
			stringBuilder.Append("sd=").Append(Plugin.SpawnStoreItemsDischarged.Value).Append('\n');
			stringBuilder.Append("ic=").Append(F(Plugin.InitialChargeMultiplier.Value)).Append('\n');
			stringBuilder.Append("mc=").Append(Plugin.MaxCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("mt=").Append(Plugin.MaxTeleporterCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("mi=").Append(Plugin.MaxInverseTeleporterCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("ms=").Append(Plugin.MaxSignalTranslatorCharges.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("rd=").Append(Plugin.ResetChargesEachDay.Value).Append('\n');
			stringBuilder.Append("co=").Append(Plugin.CarryOverUnusedCharges.Value).Append('\n');
			stringBuilder.Append("ex=").Append(Plugin.ExplodeWhenEmpty.Value).Append('\n');
			stringBuilder.Append("rq=").Append(Plugin.ResetChargesOnQuota.Value).Append('\n');
			stringBuilder.Append("hr=").Append(Plugin.HardResetEachDay.Value).Append('\n');
			stringBuilder.Append("em=").Append(Plugin.EmptyTeleporterSpawnsMimic.Value).Append('\n');
			stringBuilder.Append("ec=").Append(Plugin.EmptyInverseTeleporterCurse.Value).Append('\n');
			stringBuilder.Append("cn=").Append(Plugin.CurseMinRounds.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("cx=").Append(Plugin.CurseMaxRounds.Value.ToString(CultureInfo.InvariantCulture)).Append('\n');
			stringBuilder.Append("lt=").Append(Plugin.LightningChargesTeleporter.Value).Append('\n');
			stringBuilder.Append("lv=").Append(Plugin.LightningChargesInverseTeleporter.Value).Append('\n');
			stringBuilder.Append("lg=").Append(Plugin.LightningChargesSignalTranslator.Value).Append('\n');
			stringBuilder.Append("li=").Append(Plugin.LightningChargesItems.Value).Append('\n');
			stringBuilder.Append("ls=").Append(Plugin.LightningChargesStation.Value).Append('\n');
			stringBuilder.Append("fd=").Append(Plugin.EnableFlashlightDimming.Value).Append('\n');
			stringBuilder.Append("ds=").Append(F(Plugin.DimStartCharge.Value)).Append('\n');
			stringBuilder.Append("mb=").Append(F(Plugin.MinBrightness.Value)).Append('\n');
			foreach (ConfigEntry<float> itemEntry in Plugin.ItemEntries)
			{
				stringBuilder.Append("i:").Append(((ConfigEntryBase)itemEntry).Definition.Key).Append('=')
					.Append(F(itemEntry.Value))
					.Append('\n');
			}
			return Encoding.UTF8.GetBytes(stringBuilder.ToString());
		}

		private static void Apply(byte[] data)
		{
			Applying = true;
			bool saveOnConfigSet = Plugin.Cfg.SaveOnConfigSet;
			Plugin.Cfg.SaveOnConfigSet = false;
			try
			{
				string[] array = Encoding.UTF8.GetString(data).Split('\n');
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length != 0)
					{
						int num = text.IndexOf('=');
						if (num > 0)
						{
							ApplyOne(text.Substring(0, num), text.Substring(num + 1));
						}
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Sync] apply error: {arg}");
			}
			finally
			{
				Plugin.Cfg.SaveOnConfigSet = saveOnConfigSet;
				Applying = false;
			}
		}

		private static void ApplyOne(string key, string val)
		{
			if (key.StartsWith("i:", StringComparison.Ordinal))
			{
				string text = key.Substring(2);
				Plugin.EnsureIndividualEntry(text);
				ConfigEntry<float> val2 = Plugin.FindIndividual(text);
				if (val2 != null && TryF(val, out var f))
				{
					val2.Value = f;
				}
			}
			else
			{
				if (key == null)
				{
					return;
				}
				int length = key.Length;
				if (length != 2)
				{
					return;
				}
				switch (key[1])
				{
				case 'm':
				{
					float f4;
					if (!(key == "gm"))
					{
						if (key == "em" && bool.TryParse(val, out var result18))
						{
							Plugin.EmptyTeleporterSpawnsMimic.Value = result18;
						}
					}
					else if (TryF(val, out f4))
					{
						Plugin.GlobalMultiplier.Value = f4;
					}
					break;
				}
				case 'i':
					switch (key)
					{
					case "ei":
					{
						if (bool.TryParse(val, out var result8))
						{
							Plugin.EnableIndividualMultipliers.Value = result8;
						}
						break;
					}
					case "mi":
					{
						if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result9))
						{
							Plugin.MaxInverseTeleporterCharges.Value = result9;
						}
						break;
					}
					case "li":
					{
						if (bool.TryParse(val, out var result7))
						{
							Plugin.LightningChargesItems.Value = result7;
						}
						break;
					}
					}
					break;
				case 'd':
					switch (key)
					{
					case "sd":
					{
						if (bool.TryParse(val, out var result2))
						{
							Plugin.SpawnStoreItemsDischarged.Value = result2;
						}
						break;
					}
					case "rd":
					{
						if (bool.TryParse(val, out var result3))
						{
							Plugin.ResetChargesEachDay.Value = result3;
						}
						break;
					}
					case "fd":
					{
						if (bool.TryParse(val, out var result))
						{
							Plugin.EnableFlashlightDimming.Value = result;
						}
						break;
					}
					}
					break;
				case 'c':
					switch (key)
					{
					case "ic":
					{
						if (TryF(val, out var f3))
						{
							Plugin.InitialChargeMultiplier.Value = f3;
						}
						break;
					}
					case "mc":
					{
						if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result14))
						{
							Plugin.MaxCharges.Value = result14;
						}
						break;
					}
					case "ec":
					{
						if (bool.TryParse(val, out var result13))
						{
							Plugin.EmptyInverseTeleporterCurse.Value = result13;
						}
						break;
					}
					}
					break;
				case 't':
				{
					int result17;
					if (!(key == "mt"))
					{
						if (key == "lt" && bool.TryParse(val, out var result16))
						{
							Plugin.LightningChargesTeleporter.Value = result16;
						}
					}
					else if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out result17))
					{
						Plugin.MaxTeleporterCharges.Value = result17;
					}
					break;
				}
				case 's':
					switch (key)
					{
					case "ms":
					{
						if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result20))
						{
							Plugin.MaxSignalTranslatorCharges.Value = result20;
						}
						break;
					}
					case "ls":
					{
						if (bool.TryParse(val, out var result21))
						{
							Plugin.LightningChargesStation.Value = result21;
						}
						break;
					}
					case "ds":
					{
						if (TryF(val, out var f5))
						{
							Plugin.DimStartCharge.Value = f5;
						}
						break;
					}
					}
					break;
				case 'o':
				{
					if (key == "co" && bool.TryParse(val, out var result6))
					{
						Plugin.CarryOverUnusedCharges.Value = result6;
					}
					break;
				}
				case 'x':
				{
					bool result12;
					if (!(key == "ex"))
					{
						if (key == "cx" && int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result11))
						{
							Plugin.CurseMaxRounds.Value = result11;
						}
					}
					else if (bool.TryParse(val, out result12))
					{
						Plugin.ExplodeWhenEmpty.Value = result12;
					}
					break;
				}
				case 'q':
				{
					if (key == "rq" && bool.TryParse(val, out var result4))
					{
						Plugin.ResetChargesOnQuota.Value = result4;
					}
					break;
				}
				case 'r':
				{
					if (key == "hr" && bool.TryParse(val, out var result19))
					{
						Plugin.HardResetEachDay.Value = result19;
					}
					break;
				}
				case 'n':
				{
					if (key == "cn" && int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result15))
					{
						Plugin.CurseMinRounds.Value = result15;
					}
					break;
				}
				case 'v':
				{
					if (key == "lv" && bool.TryParse(val, out var result10))
					{
						Plugin.LightningChargesInverseTeleporter.Value = result10;
					}
					break;
				}
				case 'g':
				{
					if (key == "lg" && bool.TryParse(val, out var result5))
					{
						Plugin.LightningChargesSignalTranslator.Value = result5;
					}
					break;
				}
				case 'b':
				{
					if (key == "mb" && TryF(val, out var f2))
					{
						Plugin.MinBrightness.Value = f2;
					}
					break;
				}
				case 'e':
				case 'f':
				case 'h':
				case 'j':
				case 'k':
				case 'l':
				case 'p':
				case 'u':
				case 'w':
					break;
				}
			}
		}

		private static bool TryF(string s, out float f)
		{
			return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out f);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
	internal static class ConfigSyncConnectPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ConfigSync.OnLocalConnect();
			ChargerSync.OnLocalConnect();
			EmptyTeleporterEffects.OnLocalConnect();
		}
	}
	internal static class DischargeSync
	{
		private static MethodInfo syncClientRpc;

		private static FieldInfo isHeldField;

		private static bool resolved;

		private static bool IsHost
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton != (Object)null)
				{
					return NetworkManager.Singleton.IsServer;
				}
				return false;
			}
		}

		internal static void Schedule(GrabbableObject obj)
		{
			if (IsHost && !((Object)(object)obj == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(Pulse(obj));
			}
		}

		internal static void ScheduleJoinerResync()
		{
			if (IsHost && !((Object)(object)Plugin.Instance == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(JoinerResync());
			}
		}

		private static IEnumerator Pulse(GrabbableObject obj)
		{
			float[] array = new float[2] { 1f, 2f };
			float[] array2 = array;
			foreach (float num in array2)
			{
				yield return (object)new WaitForSeconds(num);
				if ((Object)(object)obj == (Object)null || !IsHost)
				{
					break;
				}
				Battery insertedBattery = obj.insertedBattery;
				if (insertedBattery == null)
				{
					break;
				}
				insertedBattery.charge = 0f;
				insertedBattery.empty = true;
				Broadcast(obj, 0);
			}
		}

		private static IEnumerator JoinerResync()
		{
			yield return (object)new WaitForSeconds(2.5f);
			if (!IsHost)
			{
				yield break;
			}
			int num = 0;
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			foreach (GrabbableObject val in array)
			{
				try
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.itemProperties == (Object)null) && val.itemProperties.requiresBattery && val.insertedBattery != null && !IsHeld(val))
					{
						Broadcast(val, Mathf.Clamp(Mathf.RoundToInt(val.insertedBattery.charge * 100f), 0, 100));
						num++;
					}
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[Discharge] joiner resync failed for an item: {arg}");
				}
			}
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"[Discharge] joiner resync: pushed {num} battery value(s).");
			}
		}

		private static void Resolve()
		{
			if (!resolved)
			{
				resolved = true;
				syncClientRpc = AccessTools.Method(typeof(GrabbableObject), "SyncBatteryClientRpc", (Type[])null, (Type[])null);
				isHeldField = AccessTools.Field(typeof(GrabbableObject), "isHeld");
			}
		}

		private static bool IsHeld(GrabbableObject obj)
		{
			Resolve();
			if (isHeldField == null)
			{
				return false;
			}
			try
			{
				return (bool)isHeldField.GetValue(obj);
			}
			catch
			{
				return false;
			}
		}

		private static void Broadcast(GrabbableObject obj, int charge)
		{
			Resolve();
			if (syncClientRpc == null)
			{
				Plugin.Log.LogWarning((object)"[Discharge] SyncBatteryClientRpc not found; clients keep their local value.");
				return;
			}
			try
			{
				syncClientRpc.Invoke(obj, new object[1] { charge });
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)$"[Discharge] host broadcast charge={charge} for '{obj.itemProperties?.itemName}'");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Discharge] broadcast failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(FlashlightItem), "Update")]
	internal static class FlashlightDimPatch
	{
		private static readonly Dictionary<Light, float> baseIntensities = new Dictionary<Light, float>();

		private static bool loggedOnce;

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Postfix(FlashlightItem __instance)
		{
			if (!ConfigSync.IsActive || !Plugin.EnableFlashlightDimming.Value)
			{
				return;
			}
			Battery insertedBattery = ((GrabbableObject)__instance).insertedBattery;
			if (insertedBattery != null)
			{
				float num = Brightness(insertedBattery.charge);
				Apply(__instance.flashlightBulb, num);
				Apply(__instance.flashlightBulbGlow, num);
				if (Plugin.VerboseLogging.Value && !loggedOnce)
				{
					loggedOnce = true;
					float num2 = (((Object)(object)__instance.flashlightBulb != (Object)null) ? __instance.flashlightBulb.intensity : (-1f));
					Plugin.Log.LogInfo((object)($"[Flashlight] dimming active: charge={insertedBattery.charge:0.##}, " + $"factor={num:0.##}, bulb.intensity={num2:0.##}"));
				}
			}
		}

		private static void Apply(Light light, float factor)
		{
			if (!((Object)(object)light == (Object)null))
			{
				if (!baseIntensities.TryGetValue(light, out var value) || light.intensity > value)
				{
					value = light.intensity;
					baseIntensities[light] = value;
				}
				light.intensity = value * factor;
			}
		}

		private static float Brightness(float charge)
		{
			float value = Plugin.DimStartCharge.Value;
			float value2 = Plugin.MinBrightness.Value;
			charge = Mathf.Clamp01(charge);
			if (value <= 0f)
			{
				return 1f;
			}
			if (charge >= value)
			{
				return 1f;
			}
			return Mathf.Lerp(value2, 1f, charge / value);
		}

		internal static void OnSettingsChanged()
		{
			if (Plugin.EnableFlashlightDimming.Value)
			{
				return;
			}
			foreach (KeyValuePair<Light, float> baseIntensity in baseIntensities)
			{
				if ((Object)(object)baseIntensity.Key != (Object)null)
				{
					baseIntensity.Key.intensity = baseIntensity.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(GrabbableObject), "Start")]
	internal static class GrabbableObjectPatch
	{
		private static readonly Dictionary<string, float> baseUsages = new Dictionary<string, float>(StringComparer.Ordinal);

		private static bool reapplying;

		private static string BaseKey(Item item)
		{
			if (!string.IsNullOrEmpty(item.itemName))
			{
				return item.itemName;
			}
			return "#" + ((Object)item).GetInstanceID();
		}

		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Postfix(GrabbableObject __instance)
		{
			try
			{
				if (!ConfigSync.IsActive)
				{
					return;
				}
				Item itemProperties = __instance.itemProperties;
				if ((Object)(object)itemProperties == (Object)null || !itemProperties.requiresBattery || __instance.insertedBattery == null || itemProperties.batteryUsage <= 0f)
				{
					return;
				}
				string usedKey;
				bool individual;
				float num = ResolveMultiplier(__instance, itemProperties, out usedKey, out individual);
				float num2 = ApplyCapacity(itemProperties, num);
				Battery insertedBattery = __instance.insertedBattery;
				bool flag = false;
				if (!itemProperties.isScrap && Plugin.SpawnStoreItemsDischarged.Value)
				{
					insertedBattery.charge = 0f;
					insertedBattery.empty = true;
					flag = true;
					DischargeSync.Schedule(__instance);
				}
				else
				{
					float value = Plugin.InitialChargeMultiplier.Value;
					if (Math.Abs(value - 1f) > 0.0001f)
					{
						insertedBattery.charge = Mathf.Clamp01(insertedBattery.charge * value);
						insertedBattery.empty = insertedBattery.charge <= 0f;
					}
				}
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)($"[Battery] {Describe(__instance, itemProperties)} | x{num:0.###} " + "(" + (individual ? ("individual:" + usedKey) : "global") + ") | " + $"usage {num2:0.#}s -> {itemProperties.batteryUsage:0.#}s | " + string.Format("charge={0:0.##}{1}", insertedBattery.charge, flag ? " (discharged)" : "")));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error applying battery settings: {arg}");
			}
		}

		private static float ApplyCapacity(Item item, float mult)
		{
			string key = BaseKey(item);
			if (!baseUsages.TryGetValue(key, out var value))
			{
				value = item.batteryUsage;
				baseUsages[key] = value;
			}
			item.batteryUsage = Mathf.Max(0.01f, value * mult);
			return value;
		}

		internal static void ReapplyAllCapacities()
		{
			if (!ConfigSync.IsActive || reapplying)
			{
				return;
			}
			reapplying = true;
			try
			{
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				foreach (GrabbableObject val in array)
				{
					Item val2 = (((Object)(object)val != (Object)null) ? val.itemProperties : null);
					if (!((Object)(object)val2 == (Object)null) && val2.requiresBattery && !(val2.batteryUsage <= 0f))
					{
						string usedKey;
						bool individual;
						float mult = ResolveMultiplier(val, val2, out usedKey, out individual);
						ApplyCapacity(val2, mult);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error while re-applying capacities: {arg}");
			}
			finally
			{
				reapplying = false;
			}
		}

		private static float ResolveMultiplier(GrabbableObject obj, Item item, out string usedKey, out bool individual)
		{
			usedKey = null;
			individual = false;
			Plugin.EnsureIndividualEntry(Plugin.SanitizeKey((!string.IsNullOrEmpty(item.itemName)) ? item.itemName : ((object)obj).GetType().Name));
			if (Plugin.EnableIndividualMultipliers.Value)
			{
				foreach (string item2 in CandidateKeys(obj, item))
				{
					ConfigEntry<float> val = Plugin.FindIndividual(item2);
					if (val != null && val.Value >= 0f)
					{
						usedKey = ((ConfigEntryBase)val).Definition.Key;
						individual = true;
						return val.Value;
					}
				}
			}
			return Plugin.GlobalMultiplier.Value;
		}

		private static IEnumerable<string> CandidateKeys(GrabbableObject obj, Item item)
		{
			if (!string.IsNullOrEmpty(item.itemName))
			{
				yield return item.itemName;
			}
			if ((Object)(object)((Component)obj).gameObject != (Object)null)
			{
				string text = ((Object)((Component)obj).gameObject).name.Replace("(Clone)", "").Trim();
				if (!string.IsNullOrEmpty(text))
				{
					yield return text;
				}
			}
			yield return ((object)obj).GetType().Name;
		}

		private static string Describe(GrabbableObject obj, Item item)
		{
			return (string.IsNullOrEmpty(item.itemName) ? "?" : item.itemName) + " " + $"[type={((object)obj).GetType().Name}, scrap={item.isScrap}]";
		}
	}
	[HarmonyPatch(typeof(ItemCharger), "ChargeItem")]
	internal static class ItemChargerPatch
	{
		private static readonly Dictionary<InteractTrigger, string> baseTips = new Dictionary<InteractTrigger, string>();

		[HarmonyPrefix]
		private static bool Prefix(ItemCharger __instance)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (!ConfigSync.IsActive)
			{
				return true;
			}
			if (ChargerSync.UnlimitedCharger)
			{
				return true;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			GrabbableObject val2 = (((Object)(object)val != (Object)null) ? val.currentlyHeldObjectServer : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.itemProperties == (Object)null || !val2.itemProperties.requiresBattery)
			{
				return true;
			}
			if (ChargerSync.Charges > 0)
			{
				ChargerSync.OnLocalCharge();
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)$"[Charger] charge used, ~{ChargerSync.Charges} left");
				}
				return true;
			}
			if (Plugin.ExplodeWhenEmpty.Value)
			{
				ChargerSync.TriggerExplosion(((Component)__instance).transform.position);
			}
			else if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip(Loc.ChargerTipHeader, Loc.NoChargesLeft, true, false, "LC_Tip1");
			}
			return false;
		}

		internal static void RefreshTip(ItemCharger charger)
		{
			if ((Object)(object)charger == (Object)null)
			{
				return;
			}
			InteractTrigger triggerScript = charger.triggerScript;
			if (!((Object)(object)triggerScript == (Object)null))
			{
				if (!baseTips.TryGetValue(triggerScript, out var value))
				{
					value = triggerScript.hoverTip;
					baseTips[triggerScript] = value;
				}
				if (ConfigSync.IsActive && !ChargerSync.UnlimitedCharger)
				{
					triggerScript.hoverTip = $"{value} [{Mathf.Max(0, ChargerSync.Charges)}]";
				}
				else
				{
					triggerScript.hoverTip = value;
				}
			}
		}

		internal static void RefreshAllTips()
		{
			ItemCharger[] array = Object.FindObjectsOfType<ItemCharger>();
			for (int i = 0; i < array.Length; i++)
			{
				RefreshTip(array[i]);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
	internal static class ChargerTakeoffResetPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			ChargerSync.DayReset();
			ItemChargerPatch.RefreshAllTips();
			TeleporterPatch.RefreshAllTips();
		}
	}
	[HarmonyPatch(typeof(StormyWeather), "LightningStrike")]
	internal static class LightningPatch
	{
		[HarmonyPostfix]
		private static void Postfix(bool useTargetedObject, GrabbableObject ___targetingMetalObject)
		{
			if (!ConfigSync.IsActive || !useTargetedObject || !Plugin.LightningChargesItems.Value)
			{
				return;
			}
			if (!((Object)(object)___targetingMetalObject == (Object)null) && !((Object)(object)___targetingMetalObject.itemProperties == (Object)null) && ___targetingMetalObject.itemProperties.requiresBattery && ___targetingMetalObject.insertedBattery != null)
			{
				___targetingMetalObject.insertedBattery.charge = 1f;
				___targetingMetalObject.insertedBattery.empty = false;
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("[Lightning] charged item '" + ___targetingMetalObject.itemProperties.itemName + "'"));
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "PowerSurgeShip")]
	internal static class ShipLightningRodPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (ConfigSync.IsActive)
			{
				ChargerSync.AddFromLightning();
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)"[Lightning] ship lightning rod struck");
				}
			}
		}
	}
	[HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")]
	internal static class QuotaResetPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (ConfigSync.IsActive)
			{
				ChargerSync.QuotaReset();
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "RunTerminalEvents")]
	internal static class SignalTranslatorPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(TerminalNode node)
		{
			try
			{
				return Check(node);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[SignalTranslator] prefix error, allowing vanilla event: {arg}");
				return true;
			}
		}

		private static bool Check(TerminalNode node)
		{
			if ((Object)(object)node == (Object)null || string.IsNullOrEmpty(node.terminalEvent))
			{
				return true;
			}
			if (node.terminalEvent.IndexOf("transmit", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return true;
			}
			if (!ConfigSync.IsActive)
			{
				return true;
			}
			if (ChargerSync.Unlimited(ChargePool.SignalTranslator))
			{
				return true;
			}
			if (ChargerSync.Get(ChargePool.SignalTranslator) > 0)
			{
				ChargerSync.OnLocalUse(ChargePool.SignalTranslator);
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)$"[SignalTranslator] transmission used, ~{ChargerSync.Get(ChargePool.SignalTranslator)} left");
				}
				return true;
			}
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip(Loc.SignalTranslatorTipHeader, Loc.NoChargesLeft, true, false, "LC_Tip1");
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter), "PressTeleportButtonOnLocalClient")]
	internal static class TeleporterPatch
	{
		private static readonly Dictionary<InteractTrigger, string> baseTips = new Dictionary<InteractTrigger, string>();

		private static MethodInfo canUseInverse;

		private static bool canUseInverseResolved;

		internal static ChargePool PoolOf(ShipTeleporter t)
		{
			if (!t.isInverseTeleporter)
			{
				return ChargePool.Teleporter;
			}
			return ChargePool.InverseTeleporter;
		}

		[HarmonyPrefix]
		private static bool Prefix(ShipTeleporter __instance, float ___cooldownTime)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!ConfigSync.IsActive)
				{
					return true;
				}
				ChargePool chargePool = PoolOf(__instance);
				if (ChargerSync.Unlimited(chargePool))
				{
					return true;
				}
				if (___cooldownTime > 0f)
				{
					return true;
				}
				if (__instance.isInverseTeleporter && !CanUseInverse(__instance))
				{
					return true;
				}
				if (ChargerSync.Get(chargePool) > 0)
				{
					ChargerSync.OnLocalUse(chargePool);
					if (Plugin.VerboseLogging.Value)
					{
						Plugin.Log.LogInfo((object)$"[Teleporter] {chargePool} used, ~{ChargerSync.Get(chargePool)} left");
					}
					return true;
				}
				bool isInverseTeleporter = __instance.isInverseTeleporter;
				if (!isInverseTeleporter && Plugin.EmptyTeleporterSpawnsMimic.Value)
				{
					EmptyTeleporterEffects.RequestMimic(((Component)__instance).transform.position);
				}
				else if (isInverseTeleporter && Plugin.EmptyInverseTeleporterCurse.Value)
				{
					EmptyTeleporterEffects.RequestCurse();
				}
				else if ((Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip(Loc.TeleporterTipHeader(isInverseTeleporter), Loc.NoChargesLeft, true, false, "LC_Tip1");
				}
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Teleporter] prefix error, allowing vanilla press: {arg}");
				return true;
			}
		}

		private static bool CanUseInverse(ShipTeleporter t)
		{
			if (!canUseInverseResolved)
			{
				canUseInverseResolved = true;
				canUseInverse = AccessTools.Method(typeof(ShipTeleporter), "CanUseInverseTeleporter", (Type[])null, (Type[])null);
			}
			if (canUseInverse == null)
			{
				return true;
			}
			try
			{
				return (bool)canUseInverse.Invoke(t, null);
			}
			catch
			{
				return true;
			}
		}

		internal static void RefreshTip(ShipTeleporter teleporter)
		{
			try
			{
				if ((Object)(object)teleporter == (Object)null)
				{
					return;
				}
				InteractTrigger buttonTrigger = teleporter.buttonTrigger;
				if (!((Object)(object)buttonTrigger == (Object)null))
				{
					if (!baseTips.TryGetValue(buttonTrigger, out var value))
					{
						value = buttonTrigger.hoverTip;
						baseTips[buttonTrigger] = value;
					}
					ChargePool pool = PoolOf(teleporter);
					if (ConfigSync.IsActive && !ChargerSync.Unlimited(pool))
					{
						buttonTrigger.hoverTip = $"{value} [{Mathf.Max(0, ChargerSync.Get(pool))}]";
					}
					else
					{
						buttonTrigger.hoverTip = value;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[Teleporter] hover tip error: {arg}");
			}
		}

		internal static void RefreshAllTips()
		{
			ShipTeleporter[] array = Object.FindObjectsOfType<ShipTeleporter>();
			for (int i = 0; i < array.Length; i++)
			{
				RefreshTip(array[i]);
			}
		}
	}
	internal static class ModInfo
	{
		public const string Guid = "ExhaustedBatteries";

		public const string Name = "Exhausted Batteries";

		public const string Version = "1.4.2";
	}
	[BepInPlugin("ExhaustedBatteries", "Exhausted Batteries", "1.4.2")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		public const string GeneralSection = "General";

		public const string ChargerSection = "ChargingStation";

		public const string LightningSection = "Lightning";

		public const string TeleporterSection = "Teleporter";

		public const string SignalSection = "SignalTranslator";

		public const string FlashlightSection = "Flashlight";

		public const string LocalizationSection = "Localization";

		public const string IndividualSection = "IndividualMultipliers";

		public const string ModdedSection = "ModdedItems";

		public static ConfigEntry<float> GlobalMultiplier;

		public static ConfigEntry<bool> EnableIndividualMultipliers;

		public static ConfigEntry<bool> SpawnStoreItemsDischarged;

		public static ConfigEntry<float> InitialChargeMultiplier;

		public static ConfigEntry<bool> VerboseLogging;

		public static ConfigEntry<int> MaxCharges;

		public static ConfigEntry<bool> ResetChargesEachDay;

		public static ConfigEntry<bool> CarryOverUnusedCharges;

		public static ConfigEntry<bool> ExplodeWhenEmpty;

		public static ConfigEntry<bool> ResetChargesOnQuota;

		public static ConfigEntry<bool> HardResetEachDay;

		public static ConfigEntry<bool> LightningChargesItems;

		public static ConfigEntry<bool> LightningChargesStation;

		public static ConfigEntry<bool> LightningChargesTeleporter;

		public static ConfigEntry<bool> LightningChargesInverseTeleporter;

		public static ConfigEntry<bool> LightningChargesSignalTranslator;

		public static ConfigEntry<int> MaxTeleporterCharges;

		public static ConfigEntry<int> MaxInverseTeleporterCharges;

		public static ConfigEntry<bool> EmptyTeleporterSpawnsMimic;

		public static ConfigEntry<bool> EmptyInverseTeleporterCurse;

		public static ConfigEntry<int> CurseMinRounds;

		public static ConfigEntry<int> CurseMaxRounds;

		public static ConfigEntry<int> MaxSignalTranslatorCharges;

		public static ConfigEntry<bool> EnableFlashlightDimming;

		public static ConfigEntry<float> DimStartCharge;

		public static ConfigEntry<float> MinBrightness;

		internal static ConfigEntry<Loc.Language> LanguageSetting;

		private static readonly Dictionary<string, ConfigEntry<float>> normalizedIndex = new Dictionary<string, ConfigEntry<float>>(StringComparer.Ordinal);

		private Harmony harmony;

		public static Plugin Instance { get; private set; }

		internal static ConfigFile Cfg => ((BaseUnityPlugin)Instance).Config;

		internal static IEnumerable<ConfigEntry<float>> ItemEntries => normalizedIndex.Values;

		private void Awake()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			BindGeneralConfig();
			BindChargerConfig();
			BindLightningConfig();
			BindTeleporterConfig();
			BindSignalConfig();
			BindFlashlightConfig();
			BindLocalizationConfig();
			BindModdedItems();
			ImportExistingIndividualKeys();
			harmony = new Harmony("ExhaustedBatteries");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				if (!ConfigSync.Applying)
				{
					ConfigSync.EnforceHostAuthority();
					ReapplyAll();
				}
			};
			Log.LogInfo((object)("Exhausted Batteries v1.4.2 loaded. " + $"Global={GlobalMultiplier.Value}, Individual={EnableIndividualMultipliers.Value}, " + $"DischargeStore={SpawnStoreItemsDischarged.Value}, MaxCharges={MaxCharges.Value}"));
			Log.LogInfo((object)string.Format("Language setting={0}, in-game messages will use {1}.", LanguageSetting.Value, Loc.IsRussianResolved ? "Russian" : "English"));
		}

		private void Update()
		{
			TeleporterCurse.Tick();
		}

		private void BindGeneralConfig()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			GlobalMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GlobalMultiplier", 1f, new ConfigDescription("Global battery-capacity multiplier applied to ALL items that use a battery. 1.0 = vanilla, 2.0 = lasts twice as long, 0.5 = half as long.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.001f, 1000f), Array.Empty<object>()));
			EnableIndividualMultipliers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableIndividualMultipliers", false, "Enable per-item multipliers from [IndividualMultipliers] and [ModdedItems]. A per-item multiplier takes priority over the global one.");
			SpawnStoreItemsDischarged = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SpawnStoreItemsDischarged", true, "Items with a battery bought from the store arrive fully discharged (charge = 0). Does not affect scrap/loot found on the map.");
			InitialChargeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "InitialChargeMultiplier", 1f, new ConfigDescription("Multiplier for the INITIAL charge of items that are NOT force-discharged (usually loot/scrap). 1.0 = vanilla. Result is clamped to 0..1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Verbose logging of applied multipliers to the BepInEx console (for debugging).");
		}

		private void BindChargerConfig()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			MaxCharges = ((BaseUnityPlugin)this).Config.Bind<int>("ChargingStation", "MaxCharges", 0, new ConfigDescription("Maximum number of times the ship's charging station can be used. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			ResetChargesEachDay = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ResetChargesEachDay", true, "If true, the charging-station counter refreshes every day (when the ship lands). If false, MaxCharges is a total limit for the whole session.");
			CarryOverUnusedCharges = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "CarryOverUnusedCharges", false, "Requires ResetChargesEachDay = true. If true, charges left unused at the end of a day carry over and add to the next day's allotment (instead of being lost).");
			ExplodeWhenEmpty = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ExplodeWhenEmpty", false, "If true, trying to use the charging station when it is out of charges makes it EXPLODE.");
			HardResetEachDay = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "HardResetEachDay", true, "Strict daily reset: on a new day every counter is set exactly back to its maximum and NOTHING from the previous day survives (leftovers and lightning bonuses are discarded). Takes priority over CarryOverUnusedCharges. Requires ResetChargesEachDay = true.");
			ResetChargesOnQuota = ((BaseUnityPlugin)this).Config.Bind<bool>("ChargingStation", "ResetChargesOnQuota", false, "If true, ALL counters (charging station, both teleporters, signal translator) are refilled to their maximum when the crew fulfils the profit quota and a new quota starts.");
		}

		private void BindLightningConfig()
		{
			LightningChargesItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesItems", false, "If true, a lightning bolt that strikes a battery item fully charges that item. Strikes on the ship/roof do not charge items.");
			LightningChargesStation = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesStation", false, "If true, when lightning strikes the ship's lightning rod (which happens when you bring a targeted conductive item onto the ship and the ship's power surges / lights flicker), the charging station gains 1 charge.");
			LightningChargesTeleporter = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesTeleporter", false, "If true, a lightning strike on the ship's lightning rod also adds 1 use to the regular Teleporter.");
			LightningChargesInverseTeleporter = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesInverseTeleporter", false, "If true, a lightning strike on the ship's lightning rod also adds 1 use to the Inverse Teleporter.");
			LightningChargesSignalTranslator = ((BaseUnityPlugin)this).Config.Bind<bool>("Lightning", "LightningChargesSignalTranslator", false, "If true, a lightning strike on the ship's lightning rod also adds 1 transmission to the Signal Translator.");
		}

		private void BindTeleporterConfig()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			MaxTeleporterCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "MaxTeleporterCharges", 0, new ConfigDescription("Maximum number of times the regular Teleporter can be used. 0 = unlimited (vanilla). Shares the same daily reset / carry-over settings as the charging station.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			MaxInverseTeleporterCharges = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "MaxInverseTeleporterCharges", 0, new ConfigDescription("Maximum number of times the Inverse Teleporter can be used. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
			EmptyTeleporterSpawnsMimic = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleporter", "EmptyTeleporterSpawnsMimic", false, "If true, pressing the regular Teleporter when it is out of charges teleports a MIMIC (Masked) onto the ship instead of a player.");
			EmptyInverseTeleporterCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleporter", "EmptyInverseTeleporterCurse", false, "If true, pressing the Inverse Teleporter when it is out of charges curses it: the next few times the crew returns to the ship, everyone standing in the ship is flung to a random spot with the vanilla inverse-teleport animation.");
			CurseMinRounds = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "CurseMinRounds", 2, new ConfigDescription("Minimum number of times the curse fires before it wears off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			CurseMaxRounds = ((BaseUnityPlugin)this).Config.Bind<int>("Teleporter", "CurseMaxRounds", 4, new ConfigDescription("Maximum number of times the curse fires before it wears off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
		}

		private void BindSignalConfig()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			MaxSignalTranslatorCharges = ((BaseUnityPlugin)this).Config.Bind<int>("SignalTranslator", "MaxSignalTranslatorCharges", 0, new ConfigDescription("Maximum number of transmissions the Signal Translator can send. 0 = unlimited (vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>()));
		}

		private void BindFlashlightConfig()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			EnableFlashlightDimming = ((BaseUnityPlugin)this).Config.Bind<bool>("Flashlight", "EnableFlashlightDimming", false, "Flashlights get dimmer as their battery drains (separate optional feature, off by default).");
			DimStartCharge = ((BaseUnityPlugin)this).Config.Bind<float>("Flashlight", "DimStartCharge", 1f, new ConfigDescription("Charge fraction (0..1) at/above which the flashlight stays at full brightness. Below it, brightness fades toward MinBrightness as the battery drops to empty. 1.0 = dim across the whole charge range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			MinBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Flashlight", "MinBrightness", 0.15f, new ConfigDescription("Brightness fraction (0..1) at empty battery. 0 = almost dark, 1 = no dimming.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}

		private void BindLocalizationConfig()
		{
			LanguageSetting = ((BaseUnityPlugin)this).Config.Bind<Loc.Language>("Localization", "Language", Loc.Language.Auto, "Language for this mod's in-game messages. Auto = Russian if a Russian localization mod (e.g. RTLC) is loaded or the system language is Russian, otherwise English. The config file itself stays in English.");
		}

		private void BindModdedItems()
		{
			RegisterItemEntry("ModdedItems", "Mapper", "Per-item capacity multiplier for the Mapper (mod: restoremapper). -1 = use GlobalMultiplier.");
			RegisterItemEntry("ModdedItems", "Geigercounter", "Per-item capacity multiplier for the Geiger counter (mod: facilitymeltdown). -1 = use GlobalMultiplier.");
		}

		private ConfigEntry<float> RegisterItemEntry(string section, string key, string description)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			ConfigEntry<float> val = ((BaseUnityPlugin)this).Config.Bind<float>(section, key, -1f, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1000f), Array.Empty<object>()));
			normalizedIndex[Normalize(key)] = val;
			return val;
		}

		public static void EnsureIndividualEntry(string canonicalKey)
		{
			if (!string.IsNullOrEmpty(canonicalKey) && !normalizedIndex.ContainsKey(Normalize(canonicalKey)))
			{
				Instance.RegisterItemEntry("IndividualMultipliers", canonicalKey, "Per-item capacity multiplier for '" + canonicalKey + "'. -1 = use GlobalMultiplier. Requires EnableIndividualMultipliers = true.");
			}
		}

		internal static void ReapplyAll()
		{
			Loc.Invalidate();
			GrabbableObjectPatch.ReapplyAllCapacities();
			ItemChargerPatch.RefreshAllTips();
			TeleporterPatch.RefreshAllTips();
			FlashlightDimPatch.OnSettingsChanged();
		}

		public static ConfigEntry<float> FindIndividual(string candidate)
		{
			if (string.IsNullOrEmpty(candidate))
			{
				return null;
			}
			if (!normalizedIndex.TryGetValue(Normalize(candidate), out var value))
			{
				return null;
			}
			return value;
		}

		public static string Normalize(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			return new string(s.Where(char.IsLetterOrDigit).ToArray()).ToLowerInvariant();
		}

		public static string SanitizeKey(string s)
		{
			if (string.IsNullOrWhiteSpace(s))
			{
				return "Unknown";
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			string text = s.Trim();
			foreach (char c in text)
			{
				stringBuilder.Append(("=\n\t\\\"'[]".IndexOf(c) >= 0) ? '_' : c);
			}
			string text2 = stringBuilder.ToString().Trim();
			if (text2.Length != 0)
			{
				return text2;
			}
			return "Unknown";
		}

		private void ImportExistingIndividualKeys()
		{
			try
			{
				if (!(typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(((BaseUnityPlugin)this).Config) is IDictionary<ConfigDefinition, string> dictionary))
				{
					return;
				}
				foreach (ConfigDefinition item in dictionary.Keys.ToList())
				{
					if (string.Equals(item.Section, "IndividualMultipliers", StringComparison.Ordinal))
					{
						EnsureIndividualEntry(item.Key);
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not import existing [IndividualMultipliers] keys: " + ex.Message + ". Prefer the keys the mod generates automatically."));
			}
		}
	}
}