Decompiled source of TobaccoPotAndCigar v1.0.0

BepInEx/plugins/TobaccoPotAndCigar/TobaccoPotAndCigar.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TobaccoPotAndCigar.Compatibility;
using TobaccoPotAndCigar.Prefabs;
using TobaccoPotAndCigar.Runtime;
using TobaccoPotAndCigar.Shops;
using TobaccoPotAndCigar.Smoking;
using UnityEngine;
using UnityEngine.PostProcessing;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("TobaccoPotAndCigar")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TobaccoPotAndCigar")]
[assembly: AssemblyTitle("TobaccoPotAndCigar")]
[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 TobaccoPotAndCigar
{
	[BepInPlugin("DogEggz.Cigar", "Tobacco pot and cigar", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "DogEggz.Cigar";

		public const string PluginName = "Tobacco pot and cigar";

		public const string PluginVersion = "1.0.0";

		private Harmony harmony;

		internal static ManualLogSource LogSource { get; private set; }

		internal static string PluginDirectory { get; private set; }

		private void Awake()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			LogSource = ((BaseUnityPlugin)this).Logger;
			PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty;
			RuntimeDiagnostics.InfoSink = delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
			};
			RuntimeDiagnostics.WarningSink = delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)message);
			};
			RuntimeDiagnostics.ErrorSink = delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)message);
			};
			CigarAssetBundle.Load(PluginDirectory);
			harmony = new Harmony("DogEggz.Cigar");
			harmony.PatchAll(typeof(Plugin).Assembly);
			ShopPlacement.ResetDiagnostics();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Tobacco pot and cigar 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			CigarEffectService.Reset();
			RadRefinementsCompatibility.Reset();
			CigarPrefabRegistrar.Reset();
			CigarAssetBundle.Unload();
			ShopPlacement.ResetDiagnostics();
			RuntimeDiagnostics.Reset();
			PluginDirectory = null;
			LogSource = null;
		}
	}
}
namespace TobaccoPotAndCigar.Smoking
{
	internal static class CigarEffectService
	{
		private sealed class DoseChannel
		{
			internal CigarTobaccoType Type;

			internal float Charge;
		}

		private sealed class DoseGroup
		{
			internal readonly List<DoseChannel> Channels = new List<DoseChannel>(3);
		}

		private static readonly Dictionary<int, DoseGroup> Doses = new Dictionary<int, DoseGroup>();

		private static readonly List<int> RemovalBuffer = new List<int>();

		internal static void ApplyInhale(CigarRuntimeState source, TobaccoBlend blend, float deltaTime)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Invalid comparison between Unknown and I4
			if (!((Object)(object)source == (Object)null) && !(deltaTime <= 0f))
			{
				DoseGroup orCreateDose = GetOrCreateDose(source, blend);
				BlueEffectProfile blueEffectProfile = RadRefinementsCompatibility.GetBlueEffectProfile();
				CigarEffectTotals val = CigarEffectMath.Calculate(blend, blueEffectProfile.ImmediateSleepChange, blueEffectProfile.GreenVisualChargeRate);
				PlayerNeeds.sleep += deltaTime * val.ImmediateSleepPerSecond;
				for (int i = 0; i < orCreateDose.Channels.Count; i++)
				{
					DoseChannel doseChannel = orCreateDose.Channels[i];
					float num = (((int)doseChannel.Type == 5) ? blueEffectProfile.GreenVisualChargeRate : 2f);
					doseChannel.Charge += deltaTime * num;
				}
			}
		}

		internal static void TickAndCompose(PlayerTobacco vanilla, float deltaTime)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected I4, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)vanilla == (Object)null || Doses.Count == 0 || deltaTime <= 0f)
			{
				return;
			}
			float num = vanilla.white;
			float num2 = vanilla.green;
			float num3 = vanilla.black;
			RemovalBuffer.Clear();
			foreach (KeyValuePair<int, DoseGroup> dose in Doses)
			{
				bool flag = false;
				List<DoseChannel> channels = dose.Value.Channels;
				for (int i = 0; i < channels.Count; i++)
				{
					DoseChannel doseChannel = channels[i];
					if (!(doseChannel.Charge <= 0f))
					{
						flag = true;
						doseChannel.Charge = Mathf.Max(0f, doseChannel.Charge - deltaTime * 0.5f);
						CigarTobaccoType type = doseChannel.Type;
						switch (type - 1)
						{
						case 0:
							num += doseChannel.Charge;
							PlayerNeeds.sleep -= deltaTime * 0.165f;
							break;
						case 1:
							num2 += doseChannel.Charge;
							PlayerNeeds.sleep -= deltaTime * 0.055f;
							break;
						case 4:
							num2 += doseChannel.Charge;
							PlayerNeeds.sleep -= deltaTime * 0.055f;
							break;
						case 2:
							num3 += doseChannel.Charge;
							PlayerNeeds.sleep -= deltaTime * 0.3f;
							break;
						case 3:
							PlayerNeeds.sleep -= deltaTime * 0.2f;
							break;
						}
					}
				}
				if (!flag)
				{
					RemovalBuffer.Add(dose.Key);
				}
			}
			for (int j = 0; j < RemovalBuffer.Count; j++)
			{
				Doses.Remove(RemovalBuffer[j]);
			}
			PlayerTobacco.saturationOverride = 1f + (num2 - num) / 100f;
			if ((Object)(object)vanilla.postProcessing != (Object)null)
			{
				Settings settings = vanilla.postProcessing.bloom.settings;
				settings.bloom.intensity = Mathf.Lerp(0.66f, 0f, Mathf.Clamp01(num3 / 100f));
				vanilla.postProcessing.bloom.settings = settings;
			}
		}

		internal static void Reset()
		{
			Doses.Clear();
			RemovalBuffer.Clear();
			CigarSmokeContext.Current = null;
		}

		private static DoseGroup GetOrCreateDose(CigarRuntimeState source, TobaccoBlend blend)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)source).GetInstanceID();
			if (Doses.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			value = new DoseGroup();
			AddChannels(value, (CigarTobaccoType)1, blend.White);
			AddChannels(value, (CigarTobaccoType)2, blend.Green);
			AddChannels(value, (CigarTobaccoType)3, blend.Black);
			AddChannels(value, (CigarTobaccoType)4, blend.Brown);
			AddChannels(value, (CigarTobaccoType)5, blend.Blue);
			Doses.Add(instanceID, value);
			return value;
		}

		private static void AddChannels(DoseGroup group, CigarTobaccoType type, int count)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < count; i++)
			{
				group.Channels.Add(new DoseChannel
				{
					Type = type
				});
			}
		}
	}
	internal static class CigarSmokeContext
	{
		internal static CigarRuntimeState Current;
	}
}
namespace TobaccoPotAndCigar.Shops
{
	internal static class ShopPlacement
	{
		private const string GoldRockScene = "island 1 A Gold Rock";

		private const string DragonCliffsScene = "island 9 E Dragon Cliffs";

		private const string SageHillsScene = "island 13 E (Sage Hills)";

		private const string FortAestrinScene = "island 15 M (Fort)";

		private static readonly HashSet<string> LoggedIdentityFailures = new HashSet<string>();

		internal static void ResetDiagnostics()
		{
			LoggedIdentityFailures.Clear();
		}

		internal static void ConfigureSpawnerBeforeStart(ShopItemSpawner spawner)
		{
			//IL_0016: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!CigarPrefabRegistrar.IsReady || (Object)(object)spawner == (Object)null)
			{
				return;
			}
			Scene scene = ((Component)spawner).gameObject.scene;
			if (!((Scene)(ref scene)).IsValid())
			{
				return;
			}
			scene = ((Component)spawner).gameObject.scene;
			string name = ((Scene)(ref scene)).name;
			string name2 = ((Object)((Component)spawner).gameObject).name;
			if ((name == "island 1 A Gold Rock" && (name2 == "shop item (171)" || name2 == "shop item (173)")) || (name == "island 9 E Dragon Cliffs" && name2 == "shop item spawner (184)"))
			{
				if (!IsUniqueSpawner(spawner))
				{
					LogIdentityFailure(name + "/" + name2);
				}
				else
				{
					spawner.itemPrefab = CigarAssetBundle.GetPrefab(613);
				}
			}
		}

		internal static void AddRelativeDisplaysAfterStart(ShopItemSpawner anchor)
		{
			//IL_0016: 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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			if (!CigarPrefabRegistrar.IsReady || (Object)(object)anchor == (Object)null)
			{
				return;
			}
			Scene scene = ((Component)anchor).gameObject.scene;
			if (((Scene)(ref scene)).IsValid() && IsUniqueSpawner(anchor))
			{
				scene = ((Component)anchor).gameObject.scene;
				string name = ((Scene)(ref scene)).name;
				string name2 = ((Object)((Component)anchor).gameObject).name;
				if (name == "island 9 E Dragon Cliffs" && name2 == "shop item spawner (184)")
				{
					CreateRelativeSpawner(anchor, "DogEggz.Cigar.DriedLeaf.DragonCliffs.2", new Vector3(0.058f, 0.082f, -0.411f), new Vector3(8.804f, -13.728f, -7.962f), 613);
					Vector3 localPosition = ((Component)anchor).transform.localPosition;
					localPosition.y = 3.453f;
					((Component)anchor).transform.localPosition = localPosition;
					((Component)anchor).transform.localEulerAngles = new Vector3(90f, 28.584f, 0f);
				}
				else if (name == "island 15 M (Fort)" && name2 == "shop item (24)")
				{
					CreateRelativeSpawner(anchor, "DogEggz.Cigar.DriedLeaf.Fort.1", new Vector3(-0.734f, 0f, 0f), new Vector3(90f, 0f, 0f), 613);
					CreateRelativeSpawner(anchor, "DogEggz.Cigar.DriedLeaf.Fort.2", new Vector3(-0.734f, 0f, -0.367f), new Vector3(90f, 0f, 0f), 613);
					CreateRelativeSpawner(anchor, "DogEggz.Cigar.DriedLeaf.Fort.3", new Vector3(-0.734f, 0f, -0.734f), new Vector3(90f, 0f, 0f), 613);
				}
			}
		}

		internal static void AddSageHillsPotAfterStart(Shopkeeper shopkeeper)
		{
			//IL_0016: 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)
			//IL_002b: 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)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if (!CigarPrefabRegistrar.IsReady || (Object)(object)shopkeeper == (Object)null)
			{
				return;
			}
			Scene scene = ((Component)shopkeeper).gameObject.scene;
			if (!((Scene)(ref scene)).IsValid())
			{
				return;
			}
			scene = ((Component)shopkeeper).gameObject.scene;
			if (!(((Scene)(ref scene)).name != "island 13 E (Sage Hills)") && !(((Object)((Component)shopkeeper).gameObject).name != "shopkeeper (2)") && IsUniqueShopkeeper(shopkeeper))
			{
				Transform val = FindDirectChild(((Component)shopkeeper).transform.parent, "shop area (3)");
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).GetComponent<ShopArea>() == (Object)null)
				{
					LogIdentityFailure("island 13 E (Sage Hills)/shopkeeper (2)+shop area (3)");
				}
				else
				{
					CreateRelativeSpawner(((Component)shopkeeper).transform, availableAtNight: false, 1f, "DogEggz.Cigar.TobaccoPot.SageHills", new Vector3(-2.175f, 0.6f, 3.931f), Vector3.zero, 610);
				}
			}
		}

		private static void CreateRelativeSpawner(ShopItemSpawner anchor, string hostName, Vector3 localPosition, Vector3 localEuler, int prefabIndex)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			CreateRelativeSpawner(((Component)anchor).transform, anchor.availableAtNight, anchor.priceMult, hostName, localPosition, localEuler, prefabIndex);
		}

		private static void CreateRelativeSpawner(Transform anchor, bool availableAtNight, float priceMultiplier, string hostName, Vector3 localPosition, Vector3 localEuler, int prefabIndex)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = anchor.parent;
			if (!((Object)(object)parent == (Object)null) && !((Object)(object)FindDirectChild(parent, hostName) != (Object)null))
			{
				GameObject val = new GameObject(hostName)
				{
					layer = ((Component)anchor).gameObject.layer
				};
				val.transform.SetParent(parent, true);
				val.transform.position = anchor.TransformPoint(localPosition);
				val.transform.rotation = anchor.rotation * Quaternion.Euler(localEuler);
				val.transform.localScale = Vector3.one;
				val.AddComponent<MeshFilter>();
				val.AddComponent<MeshRenderer>();
				ShopItemSpawner obj = val.AddComponent<ShopItemSpawner>();
				obj.itemPrefab = CigarAssetBundle.GetPrefab(prefabIndex);
				obj.availableAtNight = availableAtNight;
				obj.priceMult = priceMultiplier;
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					string[] obj2 = new string[5] { "Added shop display ", hostName, " in ", null, null };
					Scene scene = ((Component)anchor).gameObject.scene;
					obj2[3] = ((Scene)(ref scene)).name;
					obj2[4] = ".";
					logSource.LogInfo((object)string.Concat(obj2));
				}
			}
		}

		private static bool IsUniqueSpawner(ShopItemSpawner target)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			ShopItemSpawner[] array = Resources.FindObjectsOfTypeAll<ShopItemSpawner>();
			for (int i = 0; i < array.Length; i++)
			{
				if (!((Object)(object)array[i] != (Object)null))
				{
					continue;
				}
				Scene scene = ((Component)array[i]).gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					scene = ((Component)array[i]).gameObject.scene;
					int handle = ((Scene)(ref scene)).handle;
					scene = ((Component)target).gameObject.scene;
					if (handle == ((Scene)(ref scene)).handle && ((Object)((Component)array[i]).gameObject).name == ((Object)((Component)target).gameObject).name)
					{
						num++;
					}
				}
			}
			return num == 1;
		}

		private static bool IsUniqueShopkeeper(Shopkeeper target)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Shopkeeper[] array = Resources.FindObjectsOfTypeAll<Shopkeeper>();
			for (int i = 0; i < array.Length; i++)
			{
				if (!((Object)(object)array[i] != (Object)null))
				{
					continue;
				}
				Scene scene = ((Component)array[i]).gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					scene = ((Component)array[i]).gameObject.scene;
					int handle = ((Scene)(ref scene)).handle;
					scene = ((Component)target).gameObject.scene;
					if (handle == ((Scene)(ref scene)).handle && ((Object)((Component)array[i]).gameObject).name == ((Object)((Component)target).gameObject).name)
					{
						num++;
					}
				}
			}
			return num == 1;
		}

		private static Transform FindDirectChild(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (((Object)child).name == name)
				{
					return child;
				}
			}
			return null;
		}

		private static void LogIdentityFailure(string identity)
		{
			if (LoggedIdentityFailures.Add(identity))
			{
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogError((object)("Shop placement identity did not resolve exactly once: " + identity + ". That display was skipped."));
				}
			}
		}
	}
}
namespace TobaccoPotAndCigar.Prefabs
{
	internal static class CigarAssetBundle
	{
		internal const string BundleName = "dogeggz.cigar.assets";

		private static readonly Dictionary<int, GameObject> Prefabs = new Dictionary<int, GameObject>();

		private static AssetBundle bundle;

		internal static bool IsLoaded
		{
			get
			{
				if ((Object)(object)bundle != (Object)null)
				{
					return Prefabs.Count == 4;
				}
				return false;
			}
		}

		internal static void Load(string pluginDirectory)
		{
			if (IsLoaded)
			{
				return;
			}
			string text = Path.Combine(pluginDirectory, "assets", "dogeggz.cigar.assets");
			if (!File.Exists(text))
			{
				throw new FileNotFoundException("Cigar AssetBundle is missing.", text);
			}
			bundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)bundle == (Object)null)
			{
				throw new InvalidOperationException("Unity could not load " + text);
			}
			Prefabs.Clear();
			GameObject[] array = bundle.LoadAllAssets<GameObject>();
			for (int i = 0; i < array.Length; i++)
			{
				SaveablePrefab component = array[i].GetComponent<SaveablePrefab>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				int prefabIndex = component.prefabIndex;
				if (prefabIndex >= 610 && prefabIndex <= 613)
				{
					if (Prefabs.ContainsKey(prefabIndex))
					{
						throw new InvalidOperationException("AssetBundle contains duplicate prefab index " + prefabIndex + ".");
					}
					Prefabs.Add(prefabIndex, array[i]);
				}
			}
			for (int j = 610; j <= 613; j++)
			{
				if (!Prefabs.ContainsKey(j))
				{
					throw new InvalidOperationException("AssetBundle is missing prefab index " + j + ".");
				}
			}
		}

		internal static GameObject GetPrefab(int index)
		{
			if (!Prefabs.TryGetValue(index, out var value))
			{
				return null;
			}
			return value;
		}

		internal static void Unload()
		{
			Prefabs.Clear();
			if ((Object)(object)bundle != (Object)null)
			{
				bundle.Unload(false);
			}
			bundle = null;
		}
	}
	internal static class CigarPrefabRegistrar
	{
		private const int RequiredDirectoryLength = 614;

		private static bool registered;

		internal static bool IsReady => registered;

		internal static void EnsureRegistered(PrefabsDirectory directory)
		{
			if (registered)
			{
				return;
			}
			if ((Object)(object)directory == (Object)null || directory.directory == null)
			{
				throw new InvalidOperationException("PrefabsDirectory is unavailable.");
			}
			if (!CigarAssetBundle.IsLoaded)
			{
				throw new InvalidOperationException("Cigar AssetBundle is not loaded.");
			}
			GameObject[] array = directory.directory;
			if (array.Length < 614)
			{
				Array.Resize(ref array, 614);
			}
			for (int i = 610; i <= 613; i++)
			{
				GameObject prefab = CigarAssetBundle.GetPrefab(i);
				GameObject val = array[i];
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)prefab)
				{
					throw new InvalidOperationException("Prefab index " + i + " is already occupied by " + ((Object)val).name + "; registration aborted without overwriting it.");
				}
				ValidateBundledPrefab(i, prefab);
			}
			directory.directory = array;
			for (int j = 610; j <= 613; j++)
			{
				GameObject prefab2 = CigarAssetBundle.GetPrefab(j);
				directory.directory[j] = prefab2;
				PrefabReplacement.RegisterCustomPrefab(j, prefab2);
			}
			registered = true;
		}

		internal static void ValidateAndConfigure(PrefabsDirectory directory)
		{
			if (!registered || (Object)(object)directory == (Object)null || directory.shipItems == null || directory.shipItems.Length < 614)
			{
				throw new InvalidOperationException("PrefabsDirectory ship-item cache was not populated for indices 610-613.");
			}
			for (int i = 610; i <= 613; i++)
			{
				if ((Object)(object)directory.directory[i] != (Object)(object)CigarAssetBundle.GetPrefab(i) || (Object)(object)directory.shipItems[i] == (Object)null)
				{
					throw new InvalidOperationException("Runtime prefab cache validation failed at index " + i + ".");
				}
			}
			for (int j = 300; j <= 302; j++)
			{
				VanillaPipeSmokeProfile.ApplyRequired(directory.directory[j], j);
			}
			ConfigureTobaccoHint(directory.directory[310], 310);
			ConfigureTobaccoHint(directory.directory[312], 312);
			ConfigureTobaccoHint(directory.directory[314], 314);
			ConfigureTobaccoHint(directory.directory[316], 316);
			ConfigureTobaccoHint(directory.directory[318], 318);
			ConfigureVanillaDrying(directory.directory[312], 310);
			ConfigureVanillaDrying(directory.directory[310], 316);
			ConfigureVanillaDrying(directory.directory[316], 314);
			ManualLogSource logSource = Plugin.LogSource;
			if (logSource != null)
			{
				logSource.LogInfo((object)"Registered bundled prefabs 610-613 and rack-only tobacco drying.");
			}
		}

		internal static void Reset()
		{
			registered = false;
			PrefabReplacement.ClearCustomPrefabs();
		}

		private static void ConfigureVanillaDrying(GameObject prefab, int resultPrefabIndex)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				throw new InvalidOperationException("Vanilla drying source for result " + resultPrefabIndex + " is missing.");
			}
			RackOnlyDrying val = prefab.GetComponent<RackOnlyDrying>();
			if ((Object)(object)val == (Object)null)
			{
				val = prefab.AddComponent<RackOnlyDrying>();
			}
			val.ConfigureResultPrefab(resultPrefabIndex);
		}

		private static void ConfigureTobaccoHint(GameObject prefab, int prefabIndex)
		{
			ShipItemTobacco val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ShipItemTobacco>() : null);
			if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(((ShipItem)val).name))
			{
				throw new InvalidOperationException("Tobacco prefab " + prefabIndex + " cannot provide its pointer hint name.");
			}
			((GoPointerButton)val).description = ((ShipItem)val).name;
		}

		private static void ValidateBundledPrefab(int index, GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<ShipItem>() == (Object)null || (Object)(object)prefab.GetComponent<SaveablePrefab>() == (Object)null)
			{
				throw new InvalidOperationException("Bundled prefab " + index + " is missing its item/save contract.");
			}
			int num;
			if (index != 610)
			{
				if (index != 611)
				{
					num = (((index == 612) ? ((Object)(object)prefab.GetComponent<CigarRuntimeState>() != (Object)null) : ((Object)(object)prefab.GetComponent<DriedTobaccoLeafState>() != (Object)null)) ? 1 : 0);
				}
				else
				{
					if (!((Object)(object)prefab.GetComponent<FreshTobaccoLeafState>() != (Object)null))
					{
						goto IL_00a2;
					}
					num = (((Object)(object)prefab.GetComponent<RackOnlyDrying>() != (Object)null) ? 1 : 0);
				}
			}
			else
			{
				num = (((Object)(object)prefab.GetComponent<TobaccoPlantPotState>() != (Object)null) ? 1 : 0);
			}
			if (num != 0)
			{
				return;
			}
			goto IL_00a2;
			IL_00a2:
			throw new InvalidOperationException("Bundled prefab " + index + " does not contain its authored runtime component.");
		}
	}
	internal static class VanillaPipeSmokeProfile
	{
		internal const float EmissionRate = 300f;

		internal const float MaximumLifetime = 20f;

		internal const int MaximumParticles = 5000;

		internal static void ApplyRequired(GameObject prefab, int prefabIndex)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				throw new InvalidOperationException("Vanilla pipe prefab " + prefabIndex + " is missing.");
			}
			SaveablePrefab component = prefab.GetComponent<SaveablePrefab>();
			ShipItemPipe component2 = prefab.GetComponent<ShipItemPipe>();
			if ((Object)(object)component == (Object)null || component.prefabIndex != prefabIndex || (Object)(object)component2 == (Object)null || !Apply(component2))
			{
				throw new InvalidOperationException("Vanilla pipe prefab " + prefabIndex + " does not expose its expected smoke profile.");
			}
		}

		internal static bool ApplyIfVanilla(ShipItemPipe pipe)
		{
			if ((Object)(object)pipe == (Object)null)
			{
				return false;
			}
			SaveablePrefab component = ((Component)pipe).GetComponent<SaveablePrefab>();
			if ((Object)(object)component == (Object)null || component.prefabIndex < 300 || component.prefabIndex > 302)
			{
				return false;
			}
			return Apply(pipe);
		}

		private static bool Apply(ShipItemPipe pipe)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem componentInChildren = ((Component)pipe).GetComponentInChildren<ParticleSystem>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return false;
			}
			pipe.maxLifetime = 20f;
			pipe.maxEmission = 300f;
			MainModule main = componentInChildren.main;
			((MainModule)(ref main)).maxParticles = 5000;
			EmissionModule emission = componentInChildren.emission;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(300f);
			return true;
		}
	}
}
namespace TobaccoPotAndCigar.Patches
{
	[HarmonyPatch(typeof(ShipItem), "OnItemClick")]
	internal static class CustomItemClickPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ShipItem __instance, PickupableItem heldItem, ref bool __result)
		{
			TobaccoPlantPotState component = ((Component)__instance).GetComponent<TobaccoPlantPotState>();
			if ((Object)(object)component != (Object)null)
			{
				__result = false;
				if ((Object)(object)heldItem != (Object)null)
				{
					component.TryAcceptWater(((Component)heldItem).GetComponent<ShipItemBottle>());
				}
				return false;
			}
			DriedTobaccoLeafState component2 = ((Component)__instance).GetComponent<DriedTobaccoLeafState>();
			if ((Object)(object)component2 != (Object)null)
			{
				__result = false;
				if ((Object)(object)heldItem != (Object)null)
				{
					component2.TryInsert(((Component)heldItem).GetComponent<ShipItemTobacco>());
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ShipItem), "OnAltActivate")]
	internal static class CustomAltInteractionPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ShipItem __instance)
		{
			TobaccoPlantPotState component = ((Component)__instance).GetComponent<TobaccoPlantPotState>();
			if ((Object)(object)component != (Object)null && __instance.sold)
			{
				component.TryHarvest();
				return false;
			}
			DriedTobaccoLeafState component2 = ((Component)__instance).GetComponent<DriedTobaccoLeafState>();
			if ((Object)(object)component2 != (Object)null && __instance.sold)
			{
				component2.TryRoll();
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ShipItemBottle), "AllowOnItemClick")]
	internal static class PotWaterTargetPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ShipItemBottle __instance, GoPointerButton lookedAtButton, ref bool __result)
		{
			if (!__result && !((Object)(object)lookedAtButton == (Object)null) && ((ShipItem)__instance).sold)
			{
				TobaccoPlantPotState component = ((Component)lookedAtButton).GetComponent<TobaccoPlantPotState>();
				if ((Object)(object)component != (Object)null && component.StoredWater < 15f && (Object)(object)((Component)lookedAtButton).GetComponent<ShipItem>() != (Object)null && ((Component)lookedAtButton).GetComponent<ShipItem>().sold && ((ShipItem)__instance).amount == 1f && ((ShipItem)__instance).health > 0f)
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemTobacco), "AllowOnItemClick")]
	internal static class TobaccoTargetPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ShipItemTobacco __instance, GoPointerButton lookedAtButton, ref bool __result)
		{
			if ((Object)(object)lookedAtButton == (Object)null)
			{
				return;
			}
			if ((Object)(object)((Component)lookedAtButton).GetComponent<CigarRuntimeState>() != (Object)null)
			{
				__result = false;
				return;
			}
			DriedTobaccoLeafState component = ((Component)lookedAtButton).GetComponent<DriedTobaccoLeafState>();
			ShipItem component2 = ((Component)lookedAtButton).GetComponent<ShipItem>();
			if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null && component2.sold && ((ShipItem)__instance).sold && component.FillCount < 3)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemKnife), "AllowOnItemClick")]
	internal static class TobaccoLeafKnifeTargetPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ShipItemKnife __instance, GoPointerButton lookedAtButton, ref bool __result)
		{
			if (!__result && ((ShipItem)__instance).sold && (Object)(object)lookedAtButton != (Object)null)
			{
				ShipItem component = ((Component)lookedAtButton).GetComponent<ShipItem>();
				__result = (Object)(object)component != (Object)null && component.sold && (Object)(object)((Component)component).GetComponent<FreshTobaccoLeafState>() != (Object)null;
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemKnife), "OnAltActivate")]
	internal static class TobaccoLeafKnifePatch
	{
		private const int SliceCount = 3;

		[HarmonyPostfix]
		private static void Postfix(ShipItemKnife __instance, ref bool ___animating, ref float ___heldRotationOffset, ref float ___cutTimer)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			if (!((ShipItem)__instance).sold || (Object)(object)((PickupableItem)__instance).held == (Object)null)
			{
				return;
			}
			ShipItem pointedAtItem = ((PickupableItem)__instance).held.GetPointedAtItem();
			if ((Object)(object)pointedAtItem == (Object)null || !pointedAtItem.sold || (Object)(object)((Component)pointedAtItem).GetComponent<FreshTobaccoLeafState>() == (Object)null || !PrefabReplacement.CanSpawn(312))
			{
				return;
			}
			___animating = true;
			___heldRotationOffset = 0f;
			___cutTimer = 0.25f;
			List<ShipItem> list = new List<ShipItem>(3);
			float num = -0.03f;
			for (int i = 0; i < 3; i++)
			{
				ShipItem val = PrefabReplacement.SpawnOwned(312, ((Component)pointedAtItem).transform.position + ((Component)pointedAtItem).transform.right * num, ((Component)pointedAtItem).transform.rotation * Quaternion.Euler(0f, 90f, 0f), pointedAtItem, 0f, 0f);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
				num += 0.02f;
			}
			if (list.Count == 3)
			{
				pointedAtItem.DestroyItem();
				return;
			}
			for (int j = 0; j < list.Count; j++)
			{
				list[j].DestroyItem();
			}
			RuntimeDiagnostics.Error("Knife cut could not create all three green tobaccos; partial output was rolled back and the leaf was preserved.");
		}
	}
	[HarmonyPatch(typeof(ShipItemPipe), "OnItemClick")]
	internal static class CigarRefillBlockPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ShipItemPipe __instance, ref bool __result)
		{
			if ((Object)(object)((Component)__instance).GetComponent<CigarRuntimeState>() == (Object)null)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(ShipItemPipe), "ExtraLateUpdate")]
	internal static class CigarPipeContextPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ShipItemPipe __instance, out CigarRuntimeState __state)
		{
			__state = ((Component)__instance).GetComponent<CigarRuntimeState>();
			CigarSmokeContext.Current = __state;
		}

		[HarmonyPostfix]
		private static void Postfix(CigarRuntimeState __state, float ___currentHeat, bool ___inhaling)
		{
			if ((Object)(object)__state != (Object)null && !__state.TryDestroyIfConsumed())
			{
				__state.SyncVisuals(false, ___currentHeat / 100f, ___inhaling);
			}
			if ((Object)(object)CigarSmokeContext.Current == (Object)(object)__state)
			{
				CigarSmokeContext.Current = null;
			}
		}
	}
	[HarmonyPatch(typeof(ShipItemPipe), "OnLoad")]
	internal static class CigarPipeLoadPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ShipItemPipe __instance)
		{
			VanillaPipeSmokeProfile.ApplyIfVanilla(__instance);
			CigarRuntimeState component = ((Component)__instance).GetComponent<CigarRuntimeState>();
			if ((Object)(object)component != (Object)null && !component.TryDestroyIfConsumed())
			{
				component.RefreshValue();
				component.SyncVisuals(true, 0f, false);
			}
		}
	}
	[HarmonyPatch(typeof(PrefabsDirectory), "Start")]
	internal static class PrefabRegistrationPatches
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		private static void Prefix(PrefabsDirectory __instance)
		{
			CigarPrefabRegistrar.EnsureRegistered(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix(PrefabsDirectory __instance)
		{
			CigarPrefabRegistrar.ValidateAndConfigure(__instance);
		}
	}
	[HarmonyPatch(typeof(SaveablePrefab), "Load")]
	internal static class SaveLoadSyncPatches
	{
		[HarmonyPostfix]
		private static void Postfix(SaveablePrefab __instance)
		{
			RuntimeStateSynchronizer.Sync(((Component)__instance).GetComponent<ShipItem>(), true);
		}
	}
	[HarmonyPatch(typeof(ShopItemSpawner), "Start")]
	internal static class ShopItemSpawnerPlacementPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ShopItemSpawner __instance)
		{
			ShopPlacement.ConfigureSpawnerBeforeStart(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(ShopItemSpawner __instance)
		{
			ShopPlacement.AddRelativeDisplaysAfterStart(__instance);
		}
	}
	[HarmonyPatch(typeof(Shopkeeper), "Start")]
	internal static class SageHillsPotPlacementPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Shopkeeper __instance)
		{
			ShopPlacement.AddSageHillsPotAfterStart(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerTobacco), "Smoke")]
	internal static class CigarSmokeRecipePatch
	{
		[HarmonyPrefix]
		private static bool Prefix(int tobaccoType)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (tobaccoType >= 0)
			{
				return true;
			}
			CigarRuntimeState current = CigarSmokeContext.Current;
			TobaccoBlend blend = default(TobaccoBlend);
			if ((Object)(object)current == (Object)null || !TobaccoBlendCodec.TryDecode(-tobaccoType, ref blend))
			{
				RuntimeDiagnostics.Error("Rejected a cigar smoke call with no valid cigar recipe context.");
				return false;
			}
			CigarEffectService.ApplyInhale(current, blend, Time.deltaTime);
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerTobacco), "Update")]
	internal static class CigarEffectUpdatePatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerTobacco __instance)
		{
			CigarEffectService.TickAndCompose(__instance, Time.deltaTime);
		}
	}
}
namespace TobaccoPotAndCigar.Compatibility
{
	internal struct BlueEffectProfile
	{
		internal float ImmediateSleepChange;

		internal float GreenVisualChargeRate;

		internal static BlueEffectProfile VanillaGreen => new BlueEffectProfile
		{
			ImmediateSleepChange = -0.11f,
			GreenVisualChargeRate = 2f
		};

		internal static BlueEffectProfile RadEnhanced(int multiplier)
		{
			multiplier = Math.Max(0, multiplier);
			return new BlueEffectProfile
			{
				ImmediateSleepChange = -0.11f * (float)multiplier,
				GreenVisualChargeRate = 2f * (float)multiplier * 0.33f
			};
		}
	}
	internal static class RadRefinementsCompatibility
	{
		internal const string PluginGuid = "com.raddude.radrefinements";

		private static ConfigEntry<bool> enableBlueTobacco;

		private static ConfigEntry<int> bluePotencyMult;

		private static bool warnedAboutIncompatibleVersion;

		internal static BlueEffectProfile GetBlueEffectProfile()
		{
			if (!Chainloader.PluginInfos.TryGetValue("com.raddude.radrefinements", out var value))
			{
				return BlueEffectProfile.VanillaGreen;
			}
			if ((enableBlueTobacco == null || bluePotencyMult == null) && !TryBindConfigEntries(((object)value.Instance).GetType().Assembly))
			{
				WarnOnce();
				return BlueEffectProfile.VanillaGreen;
			}
			if (!enableBlueTobacco.Value)
			{
				return BlueEffectProfile.VanillaGreen;
			}
			return BlueEffectProfile.RadEnhanced(bluePotencyMult.Value);
		}

		internal static void Reset()
		{
			enableBlueTobacco = null;
			bluePotencyMult = null;
			warnedAboutIncompatibleVersion = false;
		}

		private static bool TryBindConfigEntries(Assembly assembly)
		{
			Type type = assembly.GetType("RadRefinements.Configs", throwOnError: false);
			if (type == null)
			{
				return false;
			}
			FieldInfo field = type.GetField("enableBlueTobacco", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo field2 = type.GetField("bluePotencyMult", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			enableBlueTobacco = ((field == null) ? null : (field.GetValue(null) as ConfigEntry<bool>));
			bluePotencyMult = ((field2 == null) ? null : (field2.GetValue(null) as ConfigEntry<int>));
			if (enableBlueTobacco != null)
			{
				return bluePotencyMult != null;
			}
			return false;
		}

		private static void WarnOnce()
		{
			if (!warnedAboutIncompatibleVersion)
			{
				warnedAboutIncompatibleVersion = true;
				ManualLogSource logSource = Plugin.LogSource;
				if (logSource != null)
				{
					logSource.LogWarning((object)"Rad Refinements was detected but its blue-tobacco settings could not be read. Cigar blue tobacco will use vanilla green effects.");
				}
			}
		}
	}
}

BepInEx/plugins/TobaccoPotAndCigar/TobaccoPotAndCigar.Runtime.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("TobaccoPotAndCigar.Runtime")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TobaccoPotAndCigar.Runtime")]
[assembly: AssemblyTitle("TobaccoPotAndCigar.Runtime")]
[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 TobaccoPotAndCigar.Runtime
{
	public struct CigarEffectTotals
	{
		public float ImmediateSleepPerSecond;

		public float LingeringSleepPerSecond;

		public float WhiteVisualInputPerSecond;

		public float GreenVisualInputPerSecond;

		public float BlackVisualInputPerSecond;
	}
	public static class CigarEffectMath
	{
		public static CigarEffectTotals Calculate(TobaccoBlend blend, float blueImmediateSleepPerSecond, float blueGreenVisualInputPerSecond)
		{
			return new CigarEffectTotals
			{
				ImmediateSleepPerSecond = (float)blend.White * 0.66f - (float)blend.Green * 0.11f + (float)blend.Blue * blueImmediateSleepPerSecond + (float)blend.Black * 1.2f + (float)blend.Brown * 0.8f,
				LingeringSleepPerSecond = (float)blend.White * -0.165f + (float)blend.Green * -0.055f + (float)blend.Blue * -0.055f + (float)blend.Black * -0.3f + (float)blend.Brown * -0.2f,
				WhiteVisualInputPerSecond = (float)blend.White * 2f,
				GreenVisualInputPerSecond = (float)blend.Green * 2f + (float)blend.Blue * blueGreenVisualInputPerSecond,
				BlackVisualInputPerSecond = (float)blend.Black * 2f
			};
		}
	}
	public enum CigarEmberCoolingPhase
	{
		Dark,
		YellowToOrange,
		OrangeToRed,
		RedToDark
	}
	public static class CigarEmberMath
	{
		private const float BoundaryEpsilon = 0.0001f;

		public const float YellowToOrangeSeconds = 2f;

		public const float OrangeToRedSeconds = 12f;

		public const float RedToDarkSeconds = 36f;

		public const float FullHeatCoolingSeconds = 50f;

		public static CigarEmberCoolingPhase GetCoolingPhase(float currentHeat01, float coolingStartHeat01)
		{
			if (currentHeat01 <= 0f || coolingStartHeat01 <= 0f)
			{
				return CigarEmberCoolingPhase.Dark;
			}
			float profileSeconds = GetProfileSeconds(currentHeat01, coolingStartHeat01);
			if (profileSeconds + 0.0001f < 2f)
			{
				return CigarEmberCoolingPhase.YellowToOrange;
			}
			if (profileSeconds + 0.0001f < 14f)
			{
				return CigarEmberCoolingPhase.OrangeToRed;
			}
			return CigarEmberCoolingPhase.RedToDark;
		}

		public static float GetPhaseProgress(CigarEmberCoolingPhase phase, float currentHeat01, float coolingStartHeat01)
		{
			if (currentHeat01 <= 0f || coolingStartHeat01 <= 0f)
			{
				if (phase != CigarEmberCoolingPhase.RedToDark)
				{
					return 0f;
				}
				return 1f;
			}
			float profileSeconds = GetProfileSeconds(currentHeat01, coolingStartHeat01);
			return phase switch
			{
				CigarEmberCoolingPhase.YellowToOrange => Mathf.Clamp01(profileSeconds / 2f), 
				CigarEmberCoolingPhase.OrangeToRed => Mathf.Clamp01((profileSeconds - 2f) / 12f), 
				CigarEmberCoolingPhase.RedToDark => Mathf.Clamp01((profileSeconds - 2f - 12f) / 36f), 
				_ => 0f, 
			};
		}

		public static float GetProfileSeconds(float currentHeat01, float coolingStartHeat01)
		{
			if (coolingStartHeat01 <= 0f)
			{
				return 50f;
			}
			float num = Mathf.Clamp01(currentHeat01 / coolingStartHeat01);
			return (1f - num) * 50f;
		}
	}
	public static class CigarHintText
	{
		public const string GreenHex = "3FAF45";

		public const string BrownHex = "8B5A2B";

		public const string BlueHex = "3F7FFF";

		public const string BlackHex = "202020";

		public static string Build(TobaccoRecipe recipe)
		{
			if (recipe.Count <= 0)
			{
				return "cigar";
			}
			if (recipe.IsFullSingleType)
			{
				return "Full " + GetName(recipe.GetAt(0)) + " Cigar";
			}
			string text = "";
			for (int i = 0; i < recipe.Count; i++)
			{
				text += GetColoredLetter(recipe.GetAt(i));
			}
			return text + " Cigar";
		}

		private static string GetName(CigarTobaccoType tobaccoType)
		{
			return tobaccoType switch
			{
				CigarTobaccoType.White => "White", 
				CigarTobaccoType.Green => "Green", 
				CigarTobaccoType.Black => "Black", 
				CigarTobaccoType.Brown => "Brown", 
				CigarTobaccoType.Blue => "Blue", 
				_ => "Unknown", 
			};
		}

		private static string GetColoredLetter(CigarTobaccoType tobaccoType)
		{
			return tobaccoType switch
			{
				CigarTobaccoType.White => "W", 
				CigarTobaccoType.Green => Color("G", "3FAF45"), 
				CigarTobaccoType.Brown => Color("B", "8B5A2B"), 
				CigarTobaccoType.Blue => Color("B", "3F7FFF"), 
				CigarTobaccoType.Black => Color("B", "202020"), 
				_ => "?", 
			};
		}

		private static string Color(string letter, string hex)
		{
			return "<color=#" + hex + ">" + letter + "</color>";
		}
	}
	public static class CigarValueMath
	{
		public const int WrapperValue = 200;

		public static int Calculate(TobaccoBlend blend, int whiteValue, int greenValue, int blackValue, int brownValue, int blueValue)
		{
			return 200 + blend.White * whiteValue + blend.Green * greenValue + blend.Black * blackValue + blend.Brown * brownValue + blend.Blue * blueValue;
		}

		public static int ScaleByRemainingHealth(int fullValue, float currentHealth, float initialHealth)
		{
			if (fullValue <= 0)
			{
				return 0;
			}
			if (initialHealth <= 0f || float.IsNaN(initialHealth))
			{
				return fullValue;
			}
			if (currentHealth <= 0f || float.IsNaN(currentHealth))
			{
				return 0;
			}
			if (currentHealth >= initialHealth)
			{
				return fullValue;
			}
			double value = (double)fullValue * (double)currentHealth / (double)initialHealth;
			return Math.Max(0, (int)Math.Round(value, MidpointRounding.AwayFromZero));
		}
	}
	public sealed class CigarRuntimeState : MonoBehaviour
	{
		[SerializeField]
		private CigarVisualController cigarVisual;

		private ShipItemPipe pipe;

		private int fullRecipeValue;

		private bool valueInitialized;

		private bool destructionQueued;

		public ShipItemPipe Pipe => pipe;

		private void Awake()
		{
			pipe = ((Component)this).GetComponent<ShipItemPipe>();
			if ((Object)(object)cigarVisual == (Object)null)
			{
				cigarVisual = ((Component)this).GetComponentInChildren<CigarVisualController>(true);
			}
			if ((Object)(object)cigarVisual != (Object)null)
			{
				cigarVisual.BindRoot(pipe);
			}
		}

		private void Start()
		{
			RefreshValue();
			SyncVisuals(snap: true, 0f, inhaling: false);
		}

		public bool TryGetBlend(out TobaccoBlend blend)
		{
			blend = default(TobaccoBlend);
			if (!TryGetRecipe(out var recipe))
			{
				return false;
			}
			blend = recipe.ToBlend();
			return true;
		}

		public bool TryGetRecipe(out TobaccoRecipe recipe)
		{
			recipe = default(TobaccoRecipe);
			bool wasLegacy;
			if ((Object)(object)pipe != (Object)null)
			{
				return TobaccoRecipeCodec.TryDecodeCigar(((ShipItem)pipe).amount, out recipe, out wasLegacy);
			}
			return false;
		}

		public float GetInitialHealth()
		{
			if (!TryGetRecipe(out var recipe))
			{
				return 0f;
			}
			return (float)recipe.Count * 100f;
		}

		public void SyncVisuals(bool snap, float heat01, bool inhaling)
		{
			if ((Object)(object)pipe == (Object)null)
			{
				pipe = ((Component)this).GetComponent<ShipItemPipe>();
			}
			if (!((Object)(object)pipe == (Object)null))
			{
				float initialHealth = GetInitialHealth();
				SyncValueFromHealth(initialHealth);
				if (!((Object)(object)cigarVisual == (Object)null))
				{
					float remaining = ((initialHealth > 0f) ? Mathf.Clamp01(((ShipItem)pipe).health / initialHealth) : 0f);
					cigarVisual.SetRemaining01(remaining, ((ShipItem)pipe).health > 0f && initialHealth > 0f, Mathf.Clamp01(heat01), inhaling, snap);
				}
			}
		}

		public void RefreshValue()
		{
			if ((Object)(object)pipe == (Object)null)
			{
				pipe = ((Component)this).GetComponent<ShipItemPipe>();
			}
			if (!((Object)(object)pipe == (Object)null))
			{
				if (!TryGetRecipe(out var recipe))
				{
					fullRecipeValue = 200;
					valueInitialized = true;
					((GoPointerButton)pipe).description = "cigar";
					SyncValueFromHealth(0f);
				}
				else
				{
					TobaccoBlend blend = recipe.ToBlend();
					fullRecipeValue = CigarValueMath.Calculate(blend, GetPrefabValue(310), GetPrefabValue(312), GetPrefabValue(314), GetPrefabValue(316), GetPrefabValue(318));
					valueInitialized = true;
					((GoPointerButton)pipe).description = CigarHintText.Build(recipe);
					SyncValueFromHealth((float)blend.Count * 100f);
				}
			}
		}

		public bool TryDestroyIfConsumed()
		{
			if (destructionQueued)
			{
				return true;
			}
			if ((Object)(object)pipe == (Object)null)
			{
				pipe = ((Component)this).GetComponent<ShipItemPipe>();
			}
			if ((Object)(object)pipe == (Object)null || ((ShipItem)pipe).health > 0f)
			{
				return false;
			}
			destructionQueued = true;
			((ShipItem)pipe).DestroyItem();
			return true;
		}

		private void SyncValueFromHealth(float initialHealth)
		{
			if (valueInitialized && !((Object)(object)pipe == (Object)null))
			{
				int num = CigarValueMath.ScaleByRemainingHealth(fullRecipeValue, ((ShipItem)pipe).health, initialHealth);
				if (((ShipItem)pipe).value != num)
				{
					((ShipItem)pipe).value = num;
				}
			}
		}

		private static int GetPrefabValue(int prefabIndex)
		{
			PrefabsDirectory instance = PrefabsDirectory.instance;
			if ((Object)(object)instance == (Object)null || instance.directory == null || prefabIndex < 0 || prefabIndex >= instance.directory.Length || (Object)(object)instance.directory[prefabIndex] == (Object)null)
			{
				return 0;
			}
			ShipItem component = instance.directory[prefabIndex].GetComponent<ShipItem>();
			if (!((Object)(object)component != (Object)null))
			{
				return 0;
			}
			return component.value;
		}
	}
	public sealed class CigarVisualController : MonoBehaviour
	{
		private const float BurnVisualLerpSpeed = 12f;

		private const float SpentFrontClearance = 0.008f;

		private const float MinimumPhysicalColliderRatio = 0.05f;

		private const float MinimumPickupLength = 0.04f;

		private const float MaximumEmberLightIntensity = 0.15f;

		private const int IgnoreRaycastLayer = 2;

		private static readonly int ColorProperty = Shader.PropertyToID("_Color");

		private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor");

		private static readonly Color YellowColor = new Color(1f, 0.42f, 0.025f, 1f);

		private static readonly Color OrangeColor = new Color(0.92f, 0.12f, 0.008f, 1f);

		private static readonly Color YellowEmission = new Color(3.2f, 0.85f, 0.04f, 1f);

		private static readonly Color OrangeEmission = new Color(2.6f, 0.22f, 0.012f, 1f);

		private static readonly Color YellowLightColor = new Color(1f, 0.38f, 0.04f, 1f);

		private static readonly Color OrangeLightColor = new Color(1f, 0.12f, 0.015f, 1f);

		private static readonly Color RedLightColor = new Color(1f, 0.025f, 0.008f, 1f);

		[SerializeField]
		private Transform mouthAnchor;

		[SerializeField]
		private Transform burnableBody;

		[SerializeField]
		private Transform burnFront;

		[SerializeField]
		private GameObject band;

		[SerializeField]
		private Renderer emberRenderer;

		[SerializeField]
		private Light emberLight;

		[SerializeField]
		private BoxCollider rootCollider;

		[SerializeField]
		private BoxCollider pickupCollider;

		[SerializeField]
		private Collider mouthSmokingTrigger;

		private ShipItemPipe pipe;

		private BoxCollider physicalCollider;

		private Vector3 fullBodyScale;

		private Vector3 fullBurnFrontPosition;

		private Vector3 spentBurnFrontPosition;

		private Vector3 fullRootColliderCenter;

		private Vector3 fullRootColliderSize;

		private Vector3 fullPickupColliderCenter;

		private Vector3 fullPickupColliderSize;

		private float rootColliderMouthEndY;

		private float pickupColliderMouthEndY;

		private float burnDirectionSign;

		private float bandThresholdY;

		private float targetRemaining01;

		private float visibleRemaining01;

		private float heat01;

		private float coolingStartHeat01;

		private bool inhaling;

		private bool wasInhaling;

		private bool hasCoolingStartHeat;

		private bool available;

		private bool initialized;

		private MaterialPropertyBlock emberProperties;

		private Color emberBaseColor = Color.white;

		private Color emberBaseEmission = Color.black;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			fullBodyScale = (((Object)(object)burnableBody != (Object)null) ? burnableBody.localScale : Vector3.one);
			fullBurnFrontPosition = (((Object)(object)burnFront != (Object)null) ? burnFront.localPosition : Vector3.zero);
			burnDirectionSign = (((Object)(object)mouthAnchor != (Object)null && (Object)(object)burnFront != (Object)null) ? Mathf.Sign(burnFront.localPosition.y - mouthAnchor.localPosition.y) : 1f);
			if (Mathf.Approximately(burnDirectionSign, 0f))
			{
				burnDirectionSign = 1f;
			}
			spentBurnFrontPosition = fullBurnFrontPosition;
			if ((Object)(object)mouthAnchor != (Object)null)
			{
				spentBurnFrontPosition.y = mouthAnchor.localPosition.y + burnDirectionSign * 0.008f;
			}
			bandThresholdY = (((Object)(object)band != (Object)null) ? band.transform.localPosition.y : spentBurnFrontPosition.y);
			CacheRootColliderGeometry();
			CachePickupColliderGeometry();
			if ((Object)(object)emberRenderer != (Object)null && (Object)(object)emberRenderer.sharedMaterial != (Object)null)
			{
				Material sharedMaterial = emberRenderer.sharedMaterial;
				if (sharedMaterial.HasProperty(ColorProperty))
				{
					emberBaseColor = sharedMaterial.GetColor(ColorProperty);
				}
				if (sharedMaterial.HasProperty(EmissionColorProperty))
				{
					emberBaseEmission = sharedMaterial.GetColor(EmissionColorProperty);
				}
				emberProperties = new MaterialPropertyBlock();
			}
		}

		public void BindRoot(ShipItemPipe newPipe)
		{
			pipe = newPipe;
			SyncInteractionLayers();
			if ((Object)(object)rootCollider == (Object)null && (Object)(object)pipe != (Object)null)
			{
				rootCollider = ((Component)pipe).GetComponent<BoxCollider>();
				CacheRootColliderGeometry();
			}
			CachePickupColliderGeometry();
		}

		public void SetRemaining01(float remaining, bool isAvailable, float newHeat01, bool isInhaling, bool snap)
		{
			targetRemaining01 = Mathf.Clamp01(remaining);
			available = isAvailable;
			heat01 = Mathf.Clamp01(newHeat01);
			UpdateInhaleState(isInhaling, snap);
			if (!available)
			{
				ResetEmberTimeline();
			}
			if (!initialized || snap)
			{
				visibleRemaining01 = targetRemaining01;
				initialized = true;
				ApplyVisualState();
			}
		}

		private void LateUpdate()
		{
			SyncInteractionLayers();
			if (initialized)
			{
				TryBindPhysicalCollider();
				float num = 1f - Mathf.Exp(-12f * Time.deltaTime);
				visibleRemaining01 = Mathf.Lerp(visibleRemaining01, targetRemaining01, num);
				if (Mathf.Abs(visibleRemaining01 - targetRemaining01) < 0.0001f)
				{
					visibleRemaining01 = targetRemaining01;
				}
				ApplyVisualState();
			}
		}

		private void UpdateInhaleState(bool newInhaling, bool snap)
		{
			inhaling = newInhaling;
			if (snap)
			{
				wasInhaling = newInhaling;
				hasCoolingStartHeat = false;
				coolingStartHeat01 = 0f;
			}
			else if (newInhaling)
			{
				wasInhaling = true;
				hasCoolingStartHeat = false;
				coolingStartHeat01 = 0f;
			}
			else if (wasInhaling)
			{
				wasInhaling = false;
				coolingStartHeat01 = heat01;
				hasCoolingStartHeat = coolingStartHeat01 > 0f;
			}
		}

		private void ResetEmberTimeline()
		{
			inhaling = false;
			wasInhaling = false;
			coolingStartHeat01 = 0f;
			hasCoolingStartHeat = false;
		}

		private void SyncInteractionLayers()
		{
			if ((Object)(object)mouthSmokingTrigger != (Object)null && ((Component)mouthSmokingTrigger).gameObject.layer != 2)
			{
				((Component)mouthSmokingTrigger).gameObject.layer = 2;
			}
		}

		private void TryBindPhysicalCollider()
		{
			if (!((Object)(object)physicalCollider != (Object)null) && !((Object)(object)pipe == (Object)null) && !((Object)(object)((ShipItem)pipe).itemRigidbodyC == (Object)null))
			{
				physicalCollider = ((Component)((ShipItem)pipe).itemRigidbodyC).GetComponent<BoxCollider>();
			}
		}

		private void CacheRootColliderGeometry()
		{
			//IL_0016: 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)
			//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)
			if (!((Object)(object)rootCollider == (Object)null))
			{
				fullRootColliderCenter = rootCollider.center;
				fullRootColliderSize = rootCollider.size;
				rootColliderMouthEndY = fullRootColliderCenter.y - burnDirectionSign * fullRootColliderSize.y * 0.5f;
			}
		}

		private void CachePickupColliderGeometry()
		{
			//IL_0016: 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)
			//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)
			if (!((Object)(object)pickupCollider == (Object)null))
			{
				fullPickupColliderCenter = pickupCollider.center;
				fullPickupColliderSize = pickupCollider.size;
				pickupColliderMouthEndY = fullPickupColliderCenter.y - burnDirectionSign * fullPickupColliderSize.y * 0.5f;
			}
		}

		private void ApplyVisualState()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)burnableBody != (Object)null)
			{
				Vector3 localScale = fullBodyScale;
				localScale.y = fullBodyScale.y * visibleRemaining01;
				burnableBody.localScale = localScale;
			}
			if ((Object)(object)burnFront != (Object)null)
			{
				burnFront.localPosition = Vector3.Lerp(spentBurnFrontPosition, fullBurnFrontPosition, visibleRemaining01);
				((Component)burnFront).gameObject.SetActive(available);
			}
			if ((Object)(object)band != (Object)null && (Object)(object)burnFront != (Object)null)
			{
				bool flag = ((burnDirectionSign > 0f) ? (burnFront.localPosition.y > bandThresholdY) : (burnFront.localPosition.y < bandThresholdY));
				band.SetActive(available && flag);
			}
			ApplyPhysicalCollider(rootCollider);
			ApplyPhysicalCollider(physicalCollider);
			ApplyPickupCollider();
			ApplyEmber();
		}

		private void ApplyPhysicalCollider(BoxCollider collider)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)collider == (Object)null) && !(fullRootColliderSize.y <= 0f))
			{
				float num = Mathf.Max(0.05f, visibleRemaining01);
				Vector3 val = fullRootColliderSize;
				val.y = fullRootColliderSize.y * num;
				Vector3 center = fullRootColliderCenter;
				center.y = rootColliderMouthEndY + burnDirectionSign * val.y * 0.5f;
				collider.size = val;
				collider.center = center;
			}
		}

		private void ApplyPickupCollider()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)pickupCollider == (Object)null) && !(fullPickupColliderSize.y <= 0f))
			{
				Vector3 val = fullPickupColliderSize;
				val.y = Mathf.Max(0.04f, fullPickupColliderSize.y * visibleRemaining01);
				Vector3 center = fullPickupColliderCenter;
				center.y = pickupColliderMouthEndY + burnDirectionSign * val.y * 0.5f;
				pickupCollider.size = val;
				pickupCollider.center = center;
			}
		}

		private void ApplyEmber()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			float num = (available ? heat01 : 0f);
			Color val;
			Color val2;
			Color color;
			if (num > 0f && inhaling)
			{
				val = YellowColor;
				val2 = YellowEmission;
				color = YellowLightColor;
			}
			else
			{
				if (num > 0f && !hasCoolingStartHeat)
				{
					coolingStartHeat01 = num;
					hasCoolingStartHeat = true;
				}
				CigarEmberCoolingPhase coolingPhase = CigarEmberMath.GetCoolingPhase(num, coolingStartHeat01);
				float phaseProgress = CigarEmberMath.GetPhaseProgress(coolingPhase, num, coolingStartHeat01);
				Color val3 = Color.Lerp(Color.black, emberBaseColor, 0.08f);
				switch (coolingPhase)
				{
				case CigarEmberCoolingPhase.YellowToOrange:
					val = Color.Lerp(YellowColor, OrangeColor, phaseProgress);
					val2 = Color.Lerp(YellowEmission, OrangeEmission, phaseProgress);
					color = Color.Lerp(YellowLightColor, OrangeLightColor, phaseProgress);
					break;
				case CigarEmberCoolingPhase.OrangeToRed:
					val = Color.Lerp(OrangeColor, emberBaseColor, phaseProgress);
					val2 = Color.Lerp(OrangeEmission, emberBaseEmission, phaseProgress);
					color = Color.Lerp(OrangeLightColor, RedLightColor, phaseProgress);
					break;
				case CigarEmberCoolingPhase.RedToDark:
					val = Color.Lerp(emberBaseColor, val3, phaseProgress);
					val2 = Color.Lerp(emberBaseEmission, Color.black, phaseProgress);
					color = Color.Lerp(RedLightColor, Color.black, phaseProgress);
					break;
				default:
					val = val3;
					val2 = Color.black;
					color = RedLightColor;
					break;
				}
			}
			if ((Object)(object)emberRenderer != (Object)null && emberProperties != null)
			{
				emberRenderer.GetPropertyBlock(emberProperties);
				emberProperties.SetColor(ColorProperty, val);
				emberProperties.SetColor(EmissionColorProperty, val2);
				emberRenderer.SetPropertyBlock(emberProperties);
			}
			if ((Object)(object)emberLight != (Object)null)
			{
				emberLight.color = color;
				emberLight.intensity = 0.15f * num;
				((Behaviour)emberLight).enabled = num > 0.001f;
			}
		}
	}
	public sealed class DriedTobaccoLeafState : MonoBehaviour
	{
		public const float RolledCigarSpawnHeight = 0.1f;

		[SerializeField]
		private DriedTobaccoLeafVisual leafVisual;

		private ShipItem item;

		public int FillCount
		{
			get
			{
				if (!((Object)(object)item == (Object)null))
				{
					return Mathf.Clamp(Mathf.RoundToInt(item.health), 0, 3);
				}
				return 0;
			}
		}

		public void BindVisual(DriedTobaccoLeafVisual newLeafVisual)
		{
			leafVisual = newLeafVisual;
		}

		private void Awake()
		{
			item = ((Component)this).GetComponent<ShipItem>();
			if ((Object)(object)leafVisual == (Object)null)
			{
				leafVisual = ((Component)this).GetComponentInChildren<DriedTobaccoLeafVisual>(true);
			}
		}

		private void Start()
		{
			SyncFromSavedState();
		}

		public bool TryInsert(ShipItemTobacco tobacco)
		{
			if ((Object)(object)tobacco == (Object)null || !((ShipItem)tobacco).sold || FillCount >= 3)
			{
				return false;
			}
			TobaccoRecipe recipe;
			bool wasLegacy;
			if (FillCount == 0)
			{
				recipe = default(TobaccoRecipe);
			}
			else if (!TobaccoRecipeCodec.TryDecode(Mathf.RoundToInt(item.amount), out recipe, out wasLegacy))
			{
				return false;
			}
			if (!recipe.TryAdd(tobacco))
			{
				return false;
			}
			item.health = recipe.Count;
			item.amount = TobaccoRecipeCodec.Encode(recipe);
			if ((Object)(object)leafVisual != (Object)null)
			{
				leafVisual.SetFillCount(recipe.Count);
			}
			((ShipItem)tobacco).DestroyItem();
			if ((Object)(object)UISoundPlayer.instance != (Object)null)
			{
				UISoundPlayer.instance.PlayUISound((UISounds)4, 0.5f, 0.5f);
			}
			RefreshDescription(recipe.Count);
			return true;
		}

		public bool TryRoll()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!TobaccoRecipeCodec.TryDecode(Mathf.RoundToInt(item.amount), out var recipe, out var _) || recipe.Count != FillCount)
			{
				return false;
			}
			int num = TobaccoRecipeCodec.Encode(recipe);
			return PrefabReplacement.ReplaceOwnedItem(item, 612, 100f * (float)recipe.Count, -num, Vector3.up * 0.1f);
		}

		public void SyncFromSavedState()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItem>();
			}
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			item.health = Mathf.Clamp(Mathf.RoundToInt(item.health), 0, 3);
			TobaccoRecipe recipe;
			bool wasLegacy;
			if (FillCount == 0)
			{
				item.health = 0f;
				item.amount = 0f;
				if ((Object)(object)leafVisual != (Object)null)
				{
					leafVisual.SetFillCount(0);
				}
				((GoPointerButton)item).description = "dried tobacco leaf\nempty (0 / 3)";
			}
			else if (!TobaccoRecipeCodec.TryDecode(Mathf.RoundToInt(item.amount), out recipe, out wasLegacy) || recipe.Count != FillCount)
			{
				RuntimeDiagnostics.Error("Invalid dried-leaf recipe state on instance " + ((Object)this).GetInstanceID() + "; input is disabled until the save is corrected.");
				if ((Object)(object)leafVisual != (Object)null)
				{
					leafVisual.SetFillCount(0);
				}
				((GoPointerButton)item).description = "dried tobacco leaf\ninvalid recipe state";
			}
			else
			{
				if ((Object)(object)leafVisual != (Object)null)
				{
					leafVisual.SetFillCount(recipe.Count);
				}
				RefreshDescription(recipe.Count);
			}
		}

		private void RefreshDescription(int count)
		{
			((GoPointerButton)item).description = "dried tobacco leaf\nfilled: " + count + " / 3\n(R) roll cigar";
		}
	}
	public sealed class DriedTobaccoLeafVisual : MonoBehaviour
	{
		[SerializeField]
		private GameObject fill0Empty;

		[SerializeField]
		private GameObject fill1OneThird;

		[SerializeField]
		private GameObject fill2TwoThirds;

		[SerializeField]
		private GameObject fill3Full;

		public void Configure(GameObject newFill0Empty, GameObject newFill1OneThird, GameObject newFill2TwoThirds, GameObject newFill3Full)
		{
			fill0Empty = newFill0Empty;
			fill1OneThird = newFill1OneThird;
			fill2TwoThirds = newFill2TwoThirds;
			fill3Full = newFill3Full;
		}

		public void SetFillCount(int fillCount)
		{
			fillCount = Mathf.Clamp(fillCount, 0, 3);
			if ((Object)(object)fill0Empty != (Object)null)
			{
				fill0Empty.SetActive(fillCount == 0);
			}
			if ((Object)(object)fill1OneThird != (Object)null)
			{
				fill1OneThird.SetActive(fillCount == 1);
			}
			if ((Object)(object)fill2TwoThirds != (Object)null)
			{
				fill2TwoThirds.SetActive(fillCount == 2);
			}
			if ((Object)(object)fill3Full != (Object)null)
			{
				fill3Full.SetActive(fillCount == 3);
			}
		}
	}
	public sealed class FreshTobaccoLeafState : MonoBehaviour
	{
		[SerializeField]
		private FreshTobaccoLeafVisual leafVisual;

		private ShipItem item;

		private void Awake()
		{
			item = ((Component)this).GetComponent<ShipItem>();
			if ((Object)(object)leafVisual == (Object)null)
			{
				leafVisual = ((Component)this).GetComponentInChildren<FreshTobaccoLeafVisual>(true);
			}
		}

		private void Start()
		{
			SyncDryingVisual();
		}

		public void BindVisual(FreshTobaccoLeafVisual newLeafVisual)
		{
			leafVisual = newLeafVisual;
		}

		public void SyncDryingVisual()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItem>();
			}
			if ((Object)(object)item != (Object)null && (Object)(object)leafVisual != (Object)null)
			{
				leafVisual.SetDryingHours(item.health);
			}
		}

		public void RemoveFreshVisualDetails()
		{
			if (!((Object)(object)leafVisual == (Object)null))
			{
				FreshTobaccoLeafVisual freshTobaccoLeafVisual = leafVisual;
				leafVisual = null;
				freshTobaccoLeafVisual.RemoveFreshDetails();
				Object.Destroy((Object)(object)freshTobaccoLeafVisual);
			}
		}
	}
	public sealed class FreshTobaccoLeafVisual : MonoBehaviour
	{
		public const float GameHoursPerDay = 24f;

		public const float WhiteColorGameHours = 72f;

		public const float FullyDriedGameHours = 144f;

		public const int VeinsHiddenPerDay = 2;

		private static readonly int ColorProperty = Shader.PropertyToID("_Color");

		[SerializeField]
		private Renderer bladeRenderer;

		[SerializeField]
		private GameObject[] lateralVeins;

		[SerializeField]
		private GameObject centralMidrib;

		[SerializeField]
		private Renderer[] lateralVeinRenderers;

		[SerializeField]
		private Renderer centralMidribRenderer;

		[SerializeField]
		private Color freshColor = Color.white;

		[SerializeField]
		private Color whiteTobaccoColor = Color.white;

		[SerializeField]
		private Color driedLeafColor = Color.white;

		private MaterialPropertyBlock colorProperties;

		[SerializeField]
		private float[] lateralVeinBrightness;

		[SerializeField]
		private float centralMidribBrightness = 1f;

		private float displayedHours = float.NaN;

		public int LateralVeinCount
		{
			get
			{
				if (lateralVeins == null)
				{
					return 0;
				}
				return lateralVeins.Length;
			}
		}

		private void Awake()
		{
			CacheDetailRenderersAndBrightness(refreshBrightness: false);
		}

		public void Configure(Renderer newBladeRenderer, GameObject[] newLateralVeins, GameObject newCentralMidrib, Color newFreshColor, Color newWhiteTobaccoColor, Color newDriedLeafColor)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			bladeRenderer = newBladeRenderer;
			lateralVeins = newLateralVeins;
			centralMidrib = newCentralMidrib;
			freshColor = newFreshColor;
			whiteTobaccoColor = newWhiteTobaccoColor;
			driedLeafColor = newDriedLeafColor;
			CacheDetailRenderersAndBrightness(refreshBrightness: true);
			displayedHours = float.NaN;
		}

		public void SetDryingHours(float gameHours)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(gameHours, 0f, 144f);
			if (!float.IsNaN(displayedHours) && Mathf.Abs(displayedHours - num) < 0.0001f)
			{
				return;
			}
			displayedHours = num;
			ApplyColor(EvaluateDryingColor(num, freshColor, whiteTobaccoColor, driedLeafColor));
			int hiddenVeinCount = GetHiddenVeinCount(num, LateralVeinCount);
			for (int i = 0; i < LateralVeinCount; i++)
			{
				if ((Object)(object)lateralVeins[i] != (Object)null)
				{
					lateralVeins[i].SetActive(i >= hiddenVeinCount);
				}
			}
			if ((Object)(object)centralMidrib != (Object)null)
			{
				centralMidrib.SetActive(true);
			}
		}

		public void RemoveFreshDetails()
		{
			if (lateralVeins != null)
			{
				for (int i = 0; i < lateralVeins.Length; i++)
				{
					if ((Object)(object)lateralVeins[i] != (Object)null)
					{
						Object.Destroy((Object)(object)lateralVeins[i]);
					}
				}
			}
			if ((Object)(object)centralMidrib != (Object)null)
			{
				Object.Destroy((Object)(object)centralMidrib);
			}
		}

		public static Color EvaluateDryingColor(float gameHours, Color fresh, Color white, Color dried)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(gameHours, 0f, 144f);
			if (num <= 72f)
			{
				return Color.Lerp(fresh, white, num / 72f);
			}
			return Color.Lerp(white, dried, (num - 72f) / 72f);
		}

		public static int GetHiddenVeinCount(float gameHours, int veinCount)
		{
			return Mathf.Clamp(Mathf.FloorToInt(Mathf.Max(0f, gameHours) / 24f) * 2, 0, Mathf.Max(0, veinCount));
		}

		private void ApplyColor(Color color)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (colorProperties == null)
			{
				colorProperties = new MaterialPropertyBlock();
			}
			ApplyRendererColor(bladeRenderer, color);
			if (lateralVeinRenderers != null)
			{
				for (int i = 0; i < lateralVeinRenderers.Length; i++)
				{
					float brightness = ((lateralVeinBrightness != null && i < lateralVeinBrightness.Length) ? lateralVeinBrightness[i] : 1f);
					ApplyRendererColor(lateralVeinRenderers[i], ApplyBrightness(color, brightness));
				}
			}
			ApplyRendererColor(centralMidribRenderer, ApplyBrightness(color, centralMidribBrightness));
		}

		public static Color ApplyBrightness(Color color, float brightness)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			return new Color(Mathf.Clamp01(color.r * brightness), Mathf.Clamp01(color.g * brightness), Mathf.Clamp01(color.b * brightness), color.a);
		}

		private void ApplyRendererColor(Renderer target, Color color)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null))
			{
				colorProperties.Clear();
				target.GetPropertyBlock(colorProperties);
				colorProperties.SetColor(ColorProperty, color);
				target.SetPropertyBlock(colorProperties);
			}
		}

		private void CacheDetailRenderersAndBrightness(bool refreshBrightness)
		{
			int lateralVeinCount = LateralVeinCount;
			if (lateralVeinRenderers == null || lateralVeinRenderers.Length != lateralVeinCount)
			{
				lateralVeinRenderers = (Renderer[])(object)new Renderer[lateralVeinCount];
			}
			bool flag = lateralVeinBrightness == null || lateralVeinBrightness.Length != lateralVeinCount;
			if (flag)
			{
				lateralVeinBrightness = new float[lateralVeinCount];
			}
			for (int i = 0; i < lateralVeinCount; i++)
			{
				if ((Object)(object)lateralVeinRenderers[i] == (Object)null && (Object)(object)lateralVeins[i] != (Object)null)
				{
					lateralVeinRenderers[i] = lateralVeins[i].GetComponentInChildren<Renderer>(true);
				}
				if (refreshBrightness || flag)
				{
					lateralVeinBrightness[i] = GetBrightnessRatio(lateralVeinRenderers[i]);
				}
			}
			if ((Object)(object)centralMidribRenderer == (Object)null && (Object)(object)centralMidrib != (Object)null)
			{
				centralMidribRenderer = centralMidrib.GetComponentInChildren<Renderer>(true);
			}
			if (refreshBrightness || flag)
			{
				centralMidribBrightness = GetBrightnessRatio(centralMidribRenderer);
			}
		}

		private float GetBrightnessRatio(Renderer target)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null || (Object)(object)target.sharedMaterial == (Object)null || !target.sharedMaterial.HasProperty(ColorProperty))
			{
				return 1f;
			}
			Color color = target.sharedMaterial.GetColor(ColorProperty);
			float luminance = GetLuminance(freshColor);
			if (!(luminance > 0.001f))
			{
				return 1f;
			}
			return Mathf.Clamp(GetLuminance(color) / luminance, 0f, 4f);
		}

		private static float GetLuminance(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			return color.r * 0.2126f + color.g * 0.7152f + color.b * 0.0722f;
		}
	}
	public sealed class RackOnlyDrying : MonoBehaviour
	{
		public const float LooseTobaccoRequiredGameHours = 72f;

		public const float FreshLeafRequiredGameHours = 144f;

		[SerializeField]
		private int resultPrefabIndex;

		private readonly HashSet<DryingRackCol> racks = new HashSet<DryingRackCol>();

		private ShipItem item;

		private Coroutine dryingRoutine;

		public int ResultPrefabIndex => resultPrefabIndex;

		public float CurrentRequiredGameHours => GetRequiredGameHours();

		private void Awake()
		{
			item = ((Component)this).GetComponent<ShipItem>();
		}

		private void Start()
		{
			SyncFromSavedState();
		}

		private void OnDisable()
		{
			StopDrying();
			racks.Clear();
		}

		private void OnTriggerEnter(Collider other)
		{
			RegisterRack(other);
		}

		private void OnTriggerStay(Collider other)
		{
			RegisterRack(other);
		}

		private void OnTriggerExit(Collider other)
		{
			DryingRackCol val = FindRack(other);
			if (!((Object)(object)val == (Object)null) && racks.Remove(val) && racks.Count == 0)
			{
				StopDrying();
			}
		}

		public void ConfigureResultPrefab(int newResultPrefabIndex)
		{
			resultPrefabIndex = newResultPrefabIndex;
		}

		public void SyncFromSavedState()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItem>();
			}
			if (!((Object)(object)item == (Object)null))
			{
				item.health = Mathf.Clamp(item.health, 0f, GetRequiredGameHours());
				FreshTobaccoLeafState component = ((Component)item).GetComponent<FreshTobaccoLeafState>();
				if ((Object)(object)component != (Object)null)
				{
					component.SyncDryingVisual();
				}
			}
		}

		private void RegisterRack(Collider other)
		{
			DryingRackCol val = FindRack(other);
			if ((Object)(object)val != (Object)null && racks.Add(val) && dryingRoutine == null)
			{
				dryingRoutine = ((MonoBehaviour)this).StartCoroutine(DryWhileRacked());
			}
		}

		private static DryingRackCol FindRack(Collider other)
		{
			if ((Object)(object)other == (Object)null)
			{
				return null;
			}
			DryingRackCol component = ((Component)other).GetComponent<DryingRackCol>();
			if (!((Object)(object)component != (Object)null))
			{
				return ((Component)other).GetComponentInParent<DryingRackCol>();
			}
			return component;
		}

		private IEnumerator DryWhileRacked()
		{
			while (racks.Count > 0)
			{
				Sun sun = Sun.sun;
				if ((Object)(object)item != (Object)null && item.sold && (Object)(object)sun != (Object)null && !Sun.SunPaused() && resultPrefabIndex > 0)
				{
					float requiredGameHours = GetRequiredGameHours();
					item.health = Mathf.Min(requiredGameHours, item.health + Time.deltaTime * sun.timescale);
					FreshTobaccoLeafState component = ((Component)item).GetComponent<FreshTobaccoLeafState>();
					if ((Object)(object)component != (Object)null)
					{
						component.SyncDryingVisual();
					}
					if (item.health >= requiredGameHours)
					{
						if (TryAdvanceFreshLeafInPlace() || TryAdvanceLooseTobaccoInPlace())
						{
							if (resultPrefabIndex <= 0)
							{
								dryingRoutine = null;
								((Behaviour)this).enabled = false;
								yield break;
							}
							yield return null;
							continue;
						}
						RuntimeDiagnostics.Error("Could not advance rack drying from prefab " + GetCurrentPrefabIndex() + " to " + resultPrefabIndex + " in place. The physical item was preserved; replacement spawning was not attempted.");
						dryingRoutine = null;
						((Behaviour)this).enabled = false;
						yield break;
					}
				}
				yield return null;
			}
			dryingRoutine = null;
		}

		private bool TryAdvanceFreshLeafInPlace()
		{
			FreshTobaccoLeafState freshTobaccoLeafState = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<FreshTobaccoLeafState>() : null);
			SaveablePrefab val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
			if ((Object)(object)freshTobaccoLeafState == (Object)null || (Object)(object)val == (Object)null || !TobaccoDryingChain.IsStageTransition(val.prefabIndex, resultPrefabIndex))
			{
				return false;
			}
			if (!TryResolveTarget(resultPrefabIndex, out var targetPrefab, out var targetItem, out var targetRenderer) || (Object)(object)targetPrefab.GetComponent<DriedTobaccoLeafState>() == (Object)null)
			{
				return false;
			}
			Renderer component = ((Component)item).GetComponent<Renderer>();
			MeshFilter component2 = ((Component)item).GetComponent<MeshFilter>();
			MeshFilter component3 = targetPrefab.GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || (Object)(object)component3.sharedMesh == (Object)null)
			{
				return false;
			}
			Transform val2 = CloneDirectChild(targetPrefab.transform, "Fill0_Empty");
			Transform val3 = CloneDirectChild(targetPrefab.transform, "Fill1_OneThird");
			Transform val4 = CloneDirectChild(targetPrefab.transform, "Fill2_TwoThirds");
			Transform val5 = CloneDirectChild(targetPrefab.transform, "Fill3_Full");
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null)
			{
				DestroyClone(val2);
				DestroyClone(val3);
				DestroyClone(val4);
				DestroyClone(val5);
				return false;
			}
			component2.sharedMesh = component3.sharedMesh;
			CopyRenderer(component, targetRenderer);
			CopyItemPresentation(item, targetItem);
			item.health = 0f;
			item.amount = 0f;
			val.prefabIndex = resultPrefabIndex;
			((Object)((Component)item).gameObject).name = ((Object)targetPrefab).name + "(Clone)";
			val2.SetParent(((Component)item).transform, false);
			val3.SetParent(((Component)item).transform, false);
			val4.SetParent(((Component)item).transform, false);
			val5.SetParent(((Component)item).transform, false);
			DriedTobaccoLeafVisual driedTobaccoLeafVisual = ((Component)item).gameObject.AddComponent<DriedTobaccoLeafVisual>();
			driedTobaccoLeafVisual.Configure(((Component)val2).gameObject, ((Component)val3).gameObject, ((Component)val4).gameObject, ((Component)val5).gameObject);
			DriedTobaccoLeafState driedTobaccoLeafState = ((Component)item).gameObject.AddComponent<DriedTobaccoLeafState>();
			driedTobaccoLeafState.BindVisual(driedTobaccoLeafVisual);
			driedTobaccoLeafState.SyncFromSavedState();
			if ((Object)(object)item.itemRigidbodyC != (Object)null)
			{
				item.itemRigidbodyC.UpdateMass();
			}
			freshTobaccoLeafState.RemoveFreshVisualDetails();
			Object.Destroy((Object)(object)freshTobaccoLeafState);
			resultPrefabIndex = 0;
			RuntimeDiagnostics.Info("Dried fresh tobacco leaf in place while preserving its collider, rack contact, pose, and save identity.");
			return true;
		}

		private bool TryAdvanceLooseTobaccoInPlace()
		{
			ShipItem obj = item;
			ShipItemTobacco val = (ShipItemTobacco)(object)((obj is ShipItemTobacco) ? obj : null);
			SaveablePrefab val2 = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || !TobaccoDryingChain.IsStageTransition(val2.prefabIndex, resultPrefabIndex))
			{
				return false;
			}
			if (!TryResolveTarget(resultPrefabIndex, out var targetPrefab, out var targetItem, out var targetRenderer))
			{
				return false;
			}
			ShipItemTobacco val3 = (((Object)(object)targetPrefab != (Object)null) ? targetPrefab.GetComponent<ShipItemTobacco>() : null);
			Renderer component = ((Component)item).GetComponent<Renderer>();
			if ((Object)(object)val3 == (Object)null || (Object)(object)component == (Object)null || (Object)(object)targetRenderer == (Object)null)
			{
				return false;
			}
			int num = resultPrefabIndex;
			CopyRenderer(component, targetRenderer);
			MeshFilter component2 = ((Component)item).GetComponent<MeshFilter>();
			MeshFilter component3 = targetPrefab.GetComponent<MeshFilter>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
			{
				component2.sharedMesh = component3.sharedMesh;
			}
			((Object)((Component)item).gameObject).name = ((Object)targetPrefab).name + "(Clone)";
			CopyItemPresentation(item, targetItem);
			item.amount = ((ShipItem)val3).amount;
			item.health = 0f;
			val.tobaccoType = val3.tobaccoType;
			val2.prefabIndex = num;
			if ((Object)(object)item.itemRigidbodyC != (Object)null)
			{
				item.itemRigidbodyC.UpdateMass();
			}
			resultPrefabIndex = (TobaccoDryingChain.TryGetNextStage(num, out var num2) ? num2 : 0);
			RuntimeDiagnostics.Info("Advanced loose tobacco to prefab " + num + " in place while preserving its rack contact and save identity.");
			return true;
		}

		private Transform CloneDirectChild(Transform targetRoot, string childName)
		{
			Transform val = targetRoot.Find(childName);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject);
			((Object)obj).name = ((Object)val).name;
			return obj.transform;
		}

		private static void DestroyClone(Transform clone)
		{
			if ((Object)(object)clone != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)clone).gameObject);
			}
		}

		private static bool TryResolveTarget(int prefabIndex, out GameObject targetPrefab, out ShipItem targetItem, out Renderer targetRenderer)
		{
			targetPrefab = null;
			targetItem = null;
			targetRenderer = null;
			PrefabsDirectory instance = PrefabsDirectory.instance;
			if ((Object)(object)instance == (Object)null || instance.directory == null || prefabIndex < 0 || prefabIndex >= instance.directory.Length)
			{
				return false;
			}
			targetPrefab = instance.directory[prefabIndex];
			if ((Object)(object)targetPrefab == (Object)null)
			{
				return false;
			}
			targetItem = targetPrefab.GetComponent<ShipItem>();
			targetRenderer = targetPrefab.GetComponent<Renderer>();
			if ((Object)(object)targetItem != (Object)null)
			{
				return (Object)(object)targetRenderer != (Object)null;
			}
			return false;
		}

		private int GetCurrentPrefabIndex()
		{
			SaveablePrefab val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<SaveablePrefab>() : null);
			if (!((Object)(object)val != (Object)null))
			{
				return -1;
			}
			return val.prefabIndex;
		}

		private float GetRequiredGameHours()
		{
			if (!((Object)(object)item != (Object)null) || !((Object)(object)((Component)item).GetComponent<FreshTobaccoLeafState>() != (Object)null))
			{
				return 72f;
			}
			return 144f;
		}

		private static void CopyRenderer(Renderer target, Renderer source)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			target.sharedMaterials = source.sharedMaterials;
			target.enabled = source.enabled;
			target.shadowCastingMode = source.shadowCastingMode;
			target.receiveShadows = source.receiveShadows;
			target.lightProbeUsage = source.lightProbeUsage;
			target.reflectionProbeUsage = source.reflectionProbeUsage;
		}

		private static void CopyItemPresentation(ShipItem target, ShipItem source)
		{
			//IL_0026: 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)
			target.name = source.name;
			target.mass = source.mass;
			target.value = source.value;
			target.category = source.category;
			target.inventoryScale = source.inventoryScale;
			target.inventoryRotation = source.inventoryRotation;
			target.inventoryRotationX = source.inventoryRotationX;
			target.floaterHeight = source.floaterHeight;
			target.wallAttachment = source.wallAttachment;
			target.delayLook = source.delayLook;
			((PickupableItem)target).big = ((PickupableItem)source).big;
			((PickupableItem)target).holdDistance = ((PickupableItem)source).holdDistance;
			((PickupableItem)target).furniturePlaceHeight = ((PickupableItem)source).furniturePlaceHeight;
			((PickupableItem)target).holdHeight = ((PickupableItem)source).holdHeight;
			((PickupableItem)target).itemClickDistance = ((PickupableItem)source).itemClickDistance;
		}

		private void StopDrying()
		{
			if (dryingRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(dryingRoutine);
				dryingRoutine = null;
			}
		}
	}
	public sealed class TobaccoPlantPotState : MonoBehaviour
	{
		[SerializeField]
		private TobaccoPlantVisual plantVisual;

		private ShipItem item;

		private Coroutine growthRoutine;

		public float StoredWater
		{
			get
			{
				if (!((Object)(object)item == (Object)null))
				{
					return Mathf.Clamp(item.health, 0f, 15f);
				}
				return 0f;
			}
		}

		public float GrowthGameHours
		{
			get
			{
				if (!((Object)(object)item == (Object)null))
				{
					return Mathf.Clamp(item.amount, 0f, 360f);
				}
				return 0f;
			}
		}

		public int CompletedGrowthDays => Mathf.Clamp(Mathf.FloorToInt(GrowthGameHours / 24f), 0, 15);

		public bool FullyGrown => GrowthGameHours >= 360f;

		private void Awake()
		{
			item = ((Component)this).GetComponent<ShipItem>();
			if ((Object)(object)plantVisual == (Object)null)
			{
				plantVisual = ((Component)this).GetComponentInChildren<TobaccoPlantVisual>(true);
			}
		}

		private void Start()
		{
			SyncFromSavedState();
		}

		private void OnEnable()
		{
			if (growthRoutine == null)
			{
				growthRoutine = ((MonoBehaviour)this).StartCoroutine(GrowUsingGameTime());
			}
		}

		private void OnDisable()
		{
			if (growthRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(growthRoutine);
				growthRoutine = null;
			}
		}

		public void SyncFromSavedState()
		{
			if ((Object)(object)item == (Object)null)
			{
				item = ((Component)this).GetComponent<ShipItem>();
			}
			if (!((Object)(object)item == (Object)null))
			{
				item.health = Mathf.Clamp(item.health, 0f, 15f);
				item.amount = Mathf.Clamp(item.amount, 0f, 360f);
				if ((Object)(object)plantVisual != (Object)null)
				{
					plantVisual.SetHarvestReady(FullyGrown);
				}
				RefreshDescription();
			}
		}

		public bool TryAcceptWater(ShipItemBottle source)
		{
			if ((Object)(object)source == (Object)null || !((ShipItem)source).sold || !Mathf.Approximately(((ShipItem)source).amount, 1f) || ((ShipItem)source).health <= 0f || StoredWater >= 15f)
			{
				return false;
			}
			Good component = ((Component)source).GetComponent<Good>();
			if ((Object)(object)component != (Object)null && component.GetMissionIndex() > -1)
			{
				return false;
			}
			float num = Mathf.Min(((ShipItem)source).health, 15f - item.health);
			((ShipItem)source).health = ((ShipItem)source).health - num;
			ShipItem obj = item;
			obj.health += num;
			if (((ShipItem)source).health <= 0f)
			{
				source.EmptyBottle();
			}
			else
			{
				((ShipItem)source).UpdateLookText();
			}
			if ((Object)(object)((ShipItem)source).itemRigidbodyC != (Object)null)
			{
				((ShipItem)source).itemRigidbodyC.UpdateMass();
			}
			if ((Object)(object)UISoundPlayer.instance != (Object)null)
			{
				UISoundPlayer.instance.PlayLiquidPourSound();
			}
			RefreshDescription();
			return true;
		}

		public bool TryHarvest()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_006a: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (!FullyGrown || !PrefabReplacement.CanSpawn(611))
			{
				return false;
			}
			List<ShipItem> list = new List<ShipItem>(2);
			for (int i = 0; i < 2; i++)
			{
				Vector3 val = ((Component)this).transform.right * (((i == 0) ? (-1f) : 1f) * 0.04f);
				ShipItem val2 = PrefabReplacement.SpawnOwned(611, ((Component)this).transform.position + ((Component)this).transform.up * 0.5f + val, ((Component)this).transform.rotation, item, 0f, 0f);
				if ((Object)(object)val2 != (Object)null)
				{
					list.Add(val2);
				}
			}
			if (list.Count != 2)
			{
				for (int j = 0; j < list.Count; j++)
				{
					list[j].DestroyItem();
				}
				RuntimeDiagnostics.Error("Tobacco harvest could not create both leaves; partial output was rolled back and growth was not reset.");
				return false;
			}
			item.amount = 0f;
			SyncFromSavedState();
			return true;
		}

		private IEnumerator GrowUsingGameTime()
		{
			while (true)
			{
				Sun sun = Sun.sun;
				if ((Object)(object)item != (Object)null && item.sold && (Object)(object)sun != (Object)null && !Sun.SunPaused() && !FullyGrown && item.health >= 1f)
				{
					float storedWater = item.health;
					float growthGameHours = item.amount;
					int num = GrowthMath.Advance(ref storedWater, ref growthGameHours, Time.deltaTime * sun.timescale);
					item.health = storedWater;
					item.amount = growthGameHours;
					if (num > 0 || FullyGrown)
					{
						SyncFromSavedState();
					}
				}
				yield return null;
			}
		}

		private void RefreshDescription()
		{
			if (!((Object)(object)item == (Object)null))
			{
				((GoPointerButton)item).description = (FullyGrown ? ("tobacco pot\nfully grown\nwater: " + item.health.ToString("0") + " / 15\n(R) harvest") : ("tobacco pot\ngrowth: " + CompletedGrowthDays + " / 15 days\nwater: " + item.health.ToString("0") + " / 15"));
			}
		}
	}
	public sealed class TobaccoPlantVisual : MonoBehaviour
	{
		[SerializeField]
		private GameObject plantBase;

		[SerializeField]
		private GameObject harvestLeaves;

		public void SetHarvestReady(bool ready)
		{
			if ((Object)(object)plantBase != (Object)null && !plantBase.activeSelf)
			{
				plantBase.SetActive(true);
			}
			if ((Object)(object)harvestLeaves != (Object)null)
			{
				harvestLeaves.SetActive(ready);
			}
		}
	}
	public static class GrowthMath
	{
		public const float Capacity = 15f;

		public const float GameHoursPerDay = 24f;

		public const int RequiredDays = 15;

		public const float RequiredGameHours = 360f;

		public static int Advance(ref float storedWater, ref float growthGameHours, float availableGameHours)
		{
			storedWater = Mathf.Clamp(storedWater, 0f, 15f);
			growthGameHours = Mathf.Clamp(growthGameHours, 0f, 360f);
			availableGameHours = Mathf.Max(0f, availableGameHours);
			int num = 0;
			while (availableGameHours > 1E-05f && storedWater >= 1f && growthGameHours < 360f)
			{
				float num2 = Mathf.Min((float)(Mathf.FloorToInt(growthGameHours / 24f) + 1) * 24f, 360f);
				float num3 = Mathf.Min(availableGameHours, num2 - growthGameHours);
				if (num3 <= 0f)
				{
					break;
				}
				growthGameHours += num3;
				availableGameHours -= num3;
				if (growthGameHours >= num2 - 0.0001f)
				{
					growthGameHours = num2;
					storedWater = Mathf.Max(0f, storedWater - 1f);
					num++;
				}
			}
			return num;
		}
	}
	public static class PrefabReplacement
	{
		private static readonly GameObject[] CustomPrefabs = (GameObject[])(object)new GameObject[4];

		public static void RegisterCustomPrefab(int index, GameObject prefab)
		{
			int num = index - 610;
			if (num < 0 || num >= CustomPrefabs.Length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			CustomPrefabs[num] = prefab;
		}

		public static void ClearCustomPrefabs()
		{
			for (int i = 0; i < CustomPrefabs.Length; i++)
			{
				CustomPrefabs[i] = null;
			}
		}

		public static bool CanSpawn(int prefabIndex)
		{
			if ((Object)(object)ResolvePrefab(prefabIndex) != (Object)null)
			{
				return (Object)(object)SaveLoadManager.instance != (Object)null;
			}
			return false;
		}

		public static ShipItem SpawnOwned(int prefabIndex, Vector3 position, Quaternion rotation, ShipItem context, float health, float amount)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ResolvePrefab(prefabIndex);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if ((Object)(object)SaveLoadManager.instance == (Object)null)
			{
				RuntimeDiagnostics.Error("Cannot spawn prefab " + prefabIndex + ": SaveLoadManager is unavailable.");
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, position, rotation);
			ShipItem component = val2.GetComponent<ShipItem>();
			SaveablePrefab component2 = val2.GetComponent<SaveablePrefab>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
			{
				RuntimeDiagnostics.Error("Registered prefab " + prefabIndex + " lost its ShipItem/SaveablePrefab contract.");
				Object.Destroy((Object)(object)val2);
				return null;
			}
			if ((Object)(object)context != (Object)null)
			{
				SaveablePrefab component3 = ((Component)context).GetComponent<SaveablePrefab>();
				if ((Object)(object)component3 != (Object)null)
				{
					component2.SetParentObject(component3.GetParentObject());
					component2.currentCrateId = component3.currentCrateId;
				}
				if ((Object)(object)((Component)context).transform.parent != (Object)null)
				{
					val2.transform.SetParent(((Component)context).transform.parent, true);
				}
			}
			component.sold = true;
			component.health = health;
			component.amount = amount;
			RuntimeStateSynchronizer.Sync(component, snapCigar: true);
			component2.RegisterToSave();
			return component;
		}

		public static bool ReplaceOwnedItem(ShipItem source, int resultPrefabIndex, float replacementHealth, float replacementAmount)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return ReplaceOwnedItem(source, resultPrefabIndex, replacementHealth, replacementAmount, Vector3.zero);
		}

		public static bool ReplaceOwnedItem(ShipItem source, int resultPrefabIndex, float replacementHealth, float replacementAmount, Vector3 worldPositionOffset)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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)
			if (!CanTransform(source))
			{
				return false;
			}
			if ((Object)(object)SpawnOwned(resultPrefabIndex, ((Component)source).transform.position + worldPositionOffset, ((Component)source).transform.rotation, source, replacementHealth, replacementAmount) == (Object)null)
			{
				return false;
			}
			if ((Object)(object)source.itemRigidbodyC != (Object)null)
			{
				source.FreezeItem();
			}
			else
			{
				Collider component = ((Component)source).GetComponent<Collider>();
				if ((Object)(object)component != (Object)null)
				{
					component.enabled = false;
				}
			}
			source.DestroyItem();
			return true;
		}

		private static bool CanTransform(ShipItem source)
		{
			if ((Object)(object)source == (Object)null || !source.sold)
			{
				return false;
			}
			SaveablePrefab component = ((Component)source).GetComponent<SaveablePrefab>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if (component.currentCrateId > 0)
			{
				RuntimeDiagnostics.Error("Refusing to transform crate-contained item " + source.name + ".");
				return false;
			}
			if ((Object)(object)source.itemRigidbodyC != (Object)null && source.GetCurrentInventorySlot() >= 0)
			{
				RuntimeDiagnostics.Error("Refusing to transform inventory-held item " + source.name + ".");
				return false;
			}
			return true;
		}

		private static GameObject ResolvePrefab(int prefabIndex)
		{
			PrefabsDirectory instance = PrefabsDirectory.instance;
			if ((Object)(object)instance == (Object)null || instance.directory == null || prefabIndex < 0 || prefabIndex >= instance.directory.Length)
			{
				RuntimeDiagnostics.Error("Prefab directory cannot resolve index " + prefabIndex + ".");
				return null;
			}
			GameObject val = instance.directory[prefabIndex];
			int num = prefabIndex - 610;
			if (num >= 0 && num < CustomPrefabs.Length && (Object)(object)val != (Object)(object)CustomPrefabs[num])
			{
				RuntimeDiagnostics.Error("Custom prefab index " + prefabIndex + " is not the registered bundled asset.");
				return null;
			}
			return val;
		}
	}
	public static class RuntimeConstants
	{
		public const int FirstVanillaPipePrefabIndex = 300;

		public const int LastVanillaPipePrefabIndex = 302;

		public const int TobaccoPotPrefabIndex = 610;

		public const int FreshTobaccoLeafPrefabIndex = 611;

		public const int CigarPrefabIndex = 612;

		public const int DriedTobaccoLeafPrefabIndex = 613;

		public const int WhiteTobaccoPrefabIndex = 310;

		public const int GreenTobaccoPrefabIndex = 312;

		public const int BlackTobaccoPrefabIndex = 314;

		public const int BrownTobaccoPrefabIndex = 316;

		public const int BlueTobaccoPrefabIndex = 318;
	}
	public static class RuntimeDiagnostics
	{
		public static Action<string> InfoSink;

		public static Action<string> WarningSink;

		public static Action<string> ErrorSink;

		public static void Info(string message)
		{
			if (InfoSink != null)
			{
				InfoSink(message);
			}
			else
			{
				Debug.Log((object)("Tobacco pot and cigar: " + message));
			}
		}

		public static void Warning(string message)
		{
			if (WarningSink != null)
			{
				WarningSink(message);
			}
			else
			{
				Debug.LogWarning((object)("Tobacco pot and cigar: " + message));
			}
		}

		public static void Error(string message)
		{
			if (ErrorSink != null)
			{
				ErrorSink(message);
			}
			else
			{
				Debug.LogError((object)("Tobacco pot and cigar: " + message));
			}
		}

		public static void Reset()
		{
			InfoSink = null;
			WarningSink = null;
			ErrorSink = null;
		}
	}
	public static class RuntimeStateSynchronizer
	{
		public static void Sync(ShipItem item, bool snapCigar)
		{
			if (!((Object)(object)item == (Object)null))
			{
				TobaccoPlantPotState component = ((Component)item).GetComponent<TobaccoPlantPotState>();
				if ((Object)(object)component != (Object)null)
				{
					component.SyncFromSavedState();
				}
				RackOnlyDrying component2 = ((Component)item).GetComponent<RackOnlyDrying>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.SyncFromSavedState();
				}
				DriedTobaccoLeafState component3 = ((Component)item).GetComponent<DriedTobaccoLeafState>();
				if ((Object)(object)component3 != (Object)null)
				{
					component3.SyncFromSavedState();
				}
				CigarRuntimeState component4 = ((Component)item).GetComponent<CigarRuntimeState>();
				if ((Object)(object)component4 != (Object)null && !component4.TryDestroyIfConsumed())
				{
					component4.RefreshValue();
					component4.SyncVisuals(snapCigar, 0f, inhaling: false);
				}
			}
		}
	}
	public enum CigarTobaccoType
	{
		White = 1,
		Green,
		Black,
		Brown,
		Blue
	}
	public struct TobaccoBlend
	{
		public int White;

		public int Green;

		public int Black;

		public int Brown;

		public int Blue;

		public int Count => White + Green + Black + Brown + Blue;

		public bool TryAdd(ShipItemTobacco tobacco)
		{
			if (TobaccoTypeResolver.TryResolve(tobacco, out var tobaccoType))
			{
				return TryAdd(tobaccoType);
			}
			return false;
		}

		public bool TryAdd(CigarTobaccoType tobaccoType)
		{
			if (Count >= 3)
			{
				return false;
			}
			switch (tobaccoType)
			{
			case CigarTobaccoType.White:
				White++;
				return true;
			case CigarTobaccoType.Green:
				Green++;
				return true;
			case CigarTobaccoType.Black:
				Black++;
				return true;
			case CigarTobaccoType.Brown:
				Brown++;
				return true;
			case CigarTobaccoType.Blue:
				Blue++;
				return true;
			default:
				return false;
			}
		}
	}
	public static class TobaccoBlendCodec
	{
		public static int Encode(TobaccoBlend blend)
		{
			if (blend.Count < 1 || blend.Count > 3 || blend.White < 0 || blend.White > 3 || blend.Green < 0 || blend.Green > 3 || blend.Black < 0 || blend.Black > 3 || blend.Brown < 0 || blend.Brown > 3 || blend.Blue < 0 || blend.Blue > 3)
			{
				throw new ArgumentOutOfRangeException("blend");
			}
			return 1 + blend.White + (blend.Green << 2) + (blend.Black << 4) + (blend.Brown << 6) + (blend.Blue << 8);
		}

		public static bool TryDecode(int code, out TobaccoBlend blend)
		{
			if (TobaccoRecipeCodec.TryDecodeOrdered(code, out var recipe))
			{
				blend = recipe.ToBlend();
				return true;
			}
			return TryDecodeLegacy(code, out blend);
		}

		internal static bool TryDecodeLegacy(int code, out TobaccoBlend blend)
		{
			blend = default(TobaccoBlend);
			if (code <= 0 || code >= 4096)
			{
				return false;
			}
			int num = code - 1;
			blend.White = num & 3;
			blend.Green = (num >> 2) & 3;
			blend.Black = (num >> 4) & 3;
			blend.Brown = (num >> 6) & 3;
			blend.Blue = (num >> 8) & 3;
			int num2 = 1023;
			if ((num & ~num2) == 0 && blend.Count >= 1)
			{
				return blend.Count <= 3;
			}
			return false;
		}

		public static bool TryDecodeCigar(float itemAmount, out TobaccoBlend blend)
		{
			blend = default(TobaccoBlend);
			int num = Mathf.RoundToInt(itemAmount);
			if (num < 0)
			{
				return TryDecode(-num, out blend);
			}
			return false;
		}
	}
	public static class TobaccoDryingChain
	{
		public static bool TryGetNextStage(int sourcePrefabIndex, out int resultPrefabIndex)
		{
			switch (sourcePrefabIndex)
			{
			case 611:
				resultPrefabIndex = 613;
				return true;
			case 312:
				resultPrefabIndex = 310;
				return true;
			case 310:
				resultPrefabIndex = 316;
				return true;
			case 316:
				resultPrefabIndex = 314;
				return true;
			default:
				resultPrefabIndex = 0;
				return false;
			}
		}

		public static bool IsStageTransition(int sourcePrefabIndex, int resultPrefabIndex)
		{
			if (TryGetNextStage(sourcePrefabIndex, out var resultPrefabIndex2))
			{
				return resultPrefabIndex2 == resultPrefabIndex;
			}
			return false;
		}
	}
	public struct TobaccoRecipe
	{
		private CigarTobaccoType first;

		private CigarTobaccoType second;

		private CigarTobaccoType third;

		private int count;

		public int Count => count;

		public bool IsFullSingleType
		{
			get
			{
				if (count == 3 && first == second)
				{
					return second == third;
				}
				return false;
			}
		}

		public CigarTobaccoType GetAt(int index)
		{
			switch (index)
			{
			case 0:
				if (count > 0)
				{
					return first;
				}
				break;
			case 1:
				if (count > 1)
				{
					return second;
				}
				break;
			case 2:
				if (count > 2)
				{
					return third;
				}
				break;
			}
			throw new ArgumentOutOfRangeException("index");
		}

		public bool TryAdd(CigarTobaccoType tobaccoType)
		{
			if (count >= 3 || !TobaccoTypeResolver.IsSupported(tobaccoType))
			{
				return false;
			}
			if (count == 0)
			{
				first = tobaccoType;
			}
			else if (count == 1)
			{
				second = tobaccoType;
			}
			else
			{
				third = tobaccoType;
			}
			count++;
			return true;
		}

		public bool TryAdd(ShipItemTobacco tobacco)
		{
			if (TobaccoTypeResolver.TryResolve(tobacco, out var tobaccoType))
			{
				return TryAdd(tobaccoType);
			}
			return false;
		}

		public TobaccoBlend ToBlend()
		{
			TobaccoBlend result = default(TobaccoBlend);
			for (int i = 0; i < count; i++)
			{
				result.TryAdd(GetAt(i));
			}
			return result;
		}

		internal static TobaccoRecipe FromLegacyBlend(TobaccoBlend blend)
		{
			TobaccoRecipe recipe = default(TobaccoRecipe);
			AddCopies(ref recipe, CigarTobaccoType.Green, blend.Green);
			AddCopies(ref recipe, CigarTobaccoType.White, blend.White);
			AddCopies(ref recipe, CigarTobaccoType.Brown, blend.Brown);
			AddCopies(ref recipe, CigarTobaccoType.Blue, blend.Blue);
			AddCopies(ref recipe, CigarTobaccoType.Black, blend.Black);
			return recipe;
		}

		private static void AddCopies(ref TobaccoRecipe recipe, CigarTobaccoType tobaccoType, int copies)
		{
			for (int i = 0; i < copies; i++)
			{
				recipe.TryAdd(tobaccoType);
			}
		}
	}
	public static class TobaccoRecipeCodec
	{
		public const int OrderedRecipeMarker = 4096;

		private const int Radix = 6;

		private const int MaximumPayload = 216;

		public static int Encode(TobaccoRecipe recipe)
		{
			if (recipe.Count < 1 || recipe.Count > 3)
			{
				throw new ArgumentOutOfRangeException("recipe");
			}
			int num = 0;
			int num2 = 1;
			for (int i = 0; i < recipe.Count; i++)
			{
				num += (int)recipe.GetAt(i) * num2;
				num2 *= 6;
			}
			return 4096 + num;
		}

		public static bool TryDecode(int code, out TobaccoRecipe recipe, out bool wasLegacy)
		{
			wasLegacy = false;
			if (TryDecodeOrdered(code, out recipe))
			{
				return true;
			}
			if (!TobaccoBlendCodec.TryDecodeLegacy(code, out var blend))
			{
				recipe = default(TobaccoRecipe);
				return false;
			}
			recipe = TobaccoRecipe.FromLegacyBlend(blend);
			wasLegacy = true;
			return recipe.Count == blend.Count;
		}

		public static bool TryDecodeCigar(float itemAmount, out TobaccoRecipe recipe, out bool wasLegacy)
		{
			recipe = default(TobaccoRecipe);
			wasLegacy = false;
			int num = Mathf.RoundToInt(itemAmount);
			if (num < 0)
			{
				return TryDecode(-num, out recipe, out wasLegacy);
			}
			return false;
		}

		internal static bool TryDecodeOrdered(int code, out TobaccoRecipe recipe)
		{
			recipe = default(TobaccoRecipe);
			int num = code - 4096;
			if (num <= 0 || num >= 216)
			{
				return false;
			}
			int num2 = num % 6;
			int num3 = num / 6 % 6;
			int num4 = num / 36 % 6;
			if (!IsValidDigit(num2) || (num3 == 0 && num4 != 0) || (num3 != 0 && !IsValidDigit(num3)) || (num4 != 0 && !IsValidDigit(num4)))
			{
				return false;
			}
			recipe.TryAdd((CigarTobaccoType)num2);
			if (num3 != 0)
			{
				recipe.TryAdd((CigarTobaccoType)num3);
			}
			if (num4 != 0)
			{
				recipe.TryAdd((CigarTobaccoType)num4);
			}
			return true;
		}

		private static bool IsValidDigit(int value)
		{
			if (value >= 1)
			{
				return value <= 5;
			}
			return false;
		}
	}
	public static class TobaccoTypeResolver
	{
		public static bool TryResolve(ShipItemTobacco tobacco, out CigarTobaccoType tobaccoType)
		{
			tobaccoType = (CigarTobaccoType)0;
			if ((Object)(object)tobacco == (Object)null)
			{
				return false;
			}
			SaveablePrefab component = ((Component)tobacco).GetComponent<SaveablePrefab>();
			if (((Object)(object)component != (Object)null && component.prefabIndex == 318) || tobacco.tobaccoType == 5)
			{
				tobaccoType = CigarTobaccoType.Blue;
				return true;
			}
			tobaccoType = (CigarTobaccoType)tobacco.tobaccoType;
			return IsSupported(tobaccoType);
		}

		public static bool IsSupported(CigarTobaccoType tobaccoType)
		{
			if (tobaccoType >= CigarTobaccoType.White)
			{
				return tobaccoType <= CigarTobaccoType.Blue;
			}
			return false;
		}
	}
}