Decompiled source of Ragnaroll v1.4.0

Ragnaroll.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Ragnaroll.Assets;
using Ragnaroll.Content;
using Ragnaroll.Core;
using Ragnaroll.Cultivation;
using Ragnaroll.Gui;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[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 Ragnaroll
{
	[BepInPlugin("grogui.Ragnaroll", "Ragnaroll", "1.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal sealed class RagnarollPlugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "grogui.Ragnaroll";

		internal const string PluginName = "Ragnaroll";

		internal const string PluginVersion = "1.4.0";

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			Log.Init(((BaseUnityPlugin)this).Logger);
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			StrainRegistry.Initialize();
			Translations.Register();
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			GUIManager.OnCustomGUIAvailable += StonedOverlay.Create;
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SeedsCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ClearSaturationCommand());
			_harmony = new Harmony("grogui.Ragnaroll");
			_harmony.PatchAll();
			Log.Info("Ragnaroll 1.4.0 chargé.");
		}

		private void OnVanillaPrefabsAvailable()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			ContentFactory.CreateAll();
			ModConfig.GrowTimeMultiplier.SettingChanged += OnGrowTimeChanged;
		}

		private static void OnGrowTimeChanged(object sender, EventArgs args)
		{
			ContentFactory.ApplyGrowTimes();
		}

		private void Update()
		{
			RainWatering.Tick();
			HarvestMessage.Tick();
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			if (ModConfig.GrowTimeMultiplier != null)
			{
				ModConfig.GrowTimeMultiplier.SettingChanged -= OnGrowTimeChanged;
			}
			GUIManager.OnCustomGUIAvailable -= StonedOverlay.Create;
			StrainSheetPanel.Close();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			RagnarollAssets.Unload();
		}
	}
}
namespace Ragnaroll.Patches
{
	[HarmonyPatch(typeof(Character), "OnDeath")]
	internal static class BossPatch
	{
		private static void Prefix(Character __instance, ZNetView ___m_nview)
		{
			string defeatSetGlobalKey = __instance.m_defeatSetGlobalKey;
			if (!string.IsNullOrEmpty(defeatSetGlobalKey) && (!Object.op_Implicit((Object)(object)___m_nview) || ___m_nview.IsOwner()))
			{
				Strain strain = StrainRegistry.FromUnlockKey(defeatSetGlobalKey);
				if (strain != null)
				{
					ZoneSystem.instance.SetGlobalKey(strain.ModUnlockKey);
				}
			}
		}
	}
	internal static class CultivationPatches
	{
		[HarmonyPatch(typeof(Plant), "Awake")]
		internal static class PlantAwake
		{
			private static void Postfix(ZNetView ___m_nview)
			{
				Strain strain = StrainRegistry.FromZNetView(___m_nview);
				if (strain != null)
				{
					PlantState plantState = PlantState.From(___m_nview);
					if (plantState != null && string.IsNullOrEmpty(plantState.StrainId))
					{
						plantState.Plant(strain.Id, FertilizerBench.Current(Player.m_localPlayer, strain.Id));
						Log.Debug($"Plantation de « {strain.Id} » avec le dosage {plantState.Npk}.");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Plant), "Grow")]
		internal static class PlantGrow
		{
			private static void Prefix(Plant __instance, ZNetView ___m_nview, out PlantState.Snapshot __state)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				__state = default(PlantState.Snapshot);
				if (StrainRegistry.FromZNetView(___m_nview) != null && (int)__instance.GetStatus() == 0)
				{
					PlantState plantState = PlantState.From(___m_nview);
					if (plantState != null)
					{
						__state = plantState.Capture();
					}
				}
			}

			private static void Postfix(GameObject __result, PlantState.Snapshot __state)
			{
				if (!((Object)(object)__result == (Object)null) && __state.IsCultivated)
				{
					PlantState plantState = PlantState.From(__result);
					if (plantState != null)
					{
						string text = Pollination.NearestOtherStrain(__result, __state.StrainId);
						plantState.Restore(__state, text);
						Log.Debug((text.Length == 0) ? ("« " + __state.StrainId + " » arrivée à maturité.") : ("« " + __state.StrainId + " » arrivée à maturité, pollinisée par « " + text + " »."));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "Interact")]
		internal static class PickableInteract
		{
			private static void Prefix(Humanoid character, ZNetView ___m_nview, bool ___m_picked, bool ___m_pickedLocal)
			{
				if (___m_picked || ___m_pickedLocal)
				{
					return;
				}
				Strain strain = StrainRegistry.FromZNetView(___m_nview);
				if (strain == null)
				{
					return;
				}
				Player val = (Player)(object)((character is Player) ? character : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				PlantState plantState = PlantState.From(___m_nview);
				if (plantState == null)
				{
					return;
				}
				HarvestOutcome outcome = HarvestOutcome.Of(plantState, strain);
				GrowerJournal.Record(val, strain.Id, plantState.Npk, outcome.FertilizerScore, outcome.Yield);
				Strain strain2 = ((outcome.SeedStrain != strain) ? outcome.SeedStrain : null);
				bool discovery = false;
				if (outcome.Pollen != null && outcome.LockedHybrid == null)
				{
					discovery = CrossingJournal.Record(val, strain.Id, outcome.Pollen.Id, strain2) && strain2 != null;
				}
				if (!((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					HarvestMessage.Add(strain, outcome.Tier, outcome.Yield, outcome.Seeds);
					if (outcome.Pollen != null)
					{
						AnnounceCross(val, strain, outcome, strain2, discovery);
					}
				}
			}

			private static void AnnounceCross(Player player, Strain strain, HarvestOutcome outcome, Strain hybrid, bool discovery)
			{
				Strain pollen = outcome.Pollen;
				if (outcome.LockedHybrid != null)
				{
					((Character)player).Message((MessageType)1, string.Format(Translations.Get("$ragnaroll_harvest_cross_locked"), Translations.Get(pollen.NameToken), Translations.Get(outcome.LockedHybrid.UnlockBossToken)), 0, BudIcon(pollen), false);
				}
				else if (discovery && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.QueueUnlockMsg(BudIcon(hybrid), Translations.Get(hybrid.NameToken), string.Format(Translations.Get("$ragnaroll_cross_discovered"), Translations.Get(strain.NameToken), Translations.Get(pollen.NameToken)));
				}
				else if (hybrid != null)
				{
					((Character)player).Message((MessageType)1, string.Format(Translations.Get("$ragnaroll_harvest_cross"), Translations.Get(pollen.NameToken), Translations.Get(hybrid.NameToken)), 0, BudIcon(hybrid), false);
				}
				else
				{
					((Character)player).Message((MessageType)1, string.Format(Translations.Get("$ragnaroll_harvest_cross_none"), Translations.Get(pollen.NameToken)), 0, BudIcon(pollen), false);
				}
			}

			private static Sprite BudIcon(Strain strain)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(strain.BudItemName);
				ItemDrop val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<ItemDrop>());
				Sprite[] array = (((Object)(object)val == (Object)null) ? null : val.m_itemData.m_shared.m_icons);
				if (array == null || array.Length == 0)
				{
					return null;
				}
				return array[0];
			}
		}

		[HarmonyPatch(typeof(Pickable), "RPC_Pick")]
		internal static class PickableRpcPick
		{
			private static void Prefix(Pickable __instance, ZNetView ___m_nview, bool ___m_picked, out ItemData __state)
			{
				__state = null;
				Strain strain = StrainRegistry.FromZNetView(___m_nview);
				if (strain == null || ___m_picked || !___m_nview.IsOwner())
				{
					return;
				}
				PlantState plantState = PlantState.From(___m_nview);
				if (plantState != null)
				{
					HarvestOutcome harvestOutcome = HarvestOutcome.Of(plantState, strain);
					__instance.m_amount = harvestOutcome.Yield;
					SetSeedReturn(__instance, harvestOutcome.SeedStrain, harvestOutcome.Seeds);
					ItemDrop component = __instance.m_itemPrefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null))
					{
						component.m_itemData.m_quality = (int)harvestOutcome.Tier;
						__state = component.m_itemData;
					}
				}
			}

			private static void Finalizer(ItemData __state)
			{
				if (__state != null)
				{
					__state.m_quality = 2;
				}
			}

			private static void SetSeedReturn(Pickable pickable, Strain seedStrain, int seeds)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Expected O, but got Unknown
				//IL_0038: 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)
				pickable.m_extraDrops = new DropTable();
				if (seeds > 0)
				{
					GameObject prefab = PrefabManager.Instance.GetPrefab(seedStrain.SeedItemName);
					if (!((Object)(object)prefab == (Object)null))
					{
						pickable.m_extraDrops.m_drops.Add(new DropData
						{
							m_item = prefab,
							m_stackMin = seeds,
							m_stackMax = seeds,
							m_weight = 1f,
							m_dontScale = true
						});
						pickable.m_extraDrops.m_dropMin = 1;
						pickable.m_extraDrops.m_dropMax = 1;
						pickable.m_extraDrops.m_dropChance = 1f;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Pickable), "GetHoverText")]
		internal static class PickableHover
		{
			private static void Postfix(ZNetView ___m_nview, ref string __result)
			{
				if (!string.IsNullOrEmpty(__result) && StrainRegistry.FromZNetView(___m_nview) != null)
				{
					Strain strain = StrainRegistry.ById(PlantState.From(___m_nview)?.PollenStrainId);
					if (strain != null)
					{
						__result = __result + "\n" + Translations.Get("$ragnaroll_hover_pollinated") + " " + Translations.Get(strain.NameToken);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Plant), "GetHoverText")]
		internal static class PlantHover
		{
			private const string UseKey = "[<color=yellow><b>$KEY_Use</b></color>]";

			private static void Postfix(Plant __instance, ZNetView ___m_nview, ref string __result)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				Strain strain = StrainRegistry.FromZNetView(___m_nview);
				if (strain == null || (int)__instance.GetStatus() != 0)
				{
					return;
				}
				PlantState plantState = PlantState.From(___m_nview);
				if (plantState != null)
				{
					CareAction careAction = PlantCare.Pending(plantState, strain);
					GrowthStage stage = PlantCare.StageOf(plantState, strain);
					__result = __result + "\n" + Translations.Get(StageToken(stage)) + ", " + Translations.Get(CareToken(careAction));
					if (careAction != CareAction.None)
					{
						__result = __result + "\n" + Translations.Get("[<color=yellow><b>$KEY_Use</b></color>]") + " " + Translations.Get(ActionToken(careAction));
					}
				}
			}

			private static string StageToken(GrowthStage stage)
			{
				return stage switch
				{
					GrowthStage.Sprout => "$ragnaroll_hover_stage_sprout", 
					GrowthStage.Growing => "$ragnaroll_hover_stage_growing", 
					_ => "$ragnaroll_hover_stage_ripening", 
				};
			}

			private static string CareToken(CareAction pending)
			{
				return pending switch
				{
					CareAction.Water => "$ragnaroll_hover_care_thirsty", 
					CareAction.Prune => "$ragnaroll_hover_care_prune", 
					_ => "$ragnaroll_hover_care_none", 
				};
			}

			private static string ActionToken(CareAction pending)
			{
				if (pending != CareAction.Water)
				{
					return "$ragnaroll_hover_prune";
				}
				return "$ragnaroll_hover_water";
			}
		}
	}
	internal static class EffectPatches
	{
		[HarmonyPatch(typeof(Player), "CanConsumeItem")]
		internal static class IntakeCheck
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_004b: 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_006b: Expected O, but got Unknown
				MethodInfo haveStatusEffect = AccessTools.Method(typeof(SEMan), "HaveStatusEffect", new Type[1] { typeof(int) }, (Type[])null);
				if (haveStatusEffect == null)
				{
					ReportUnpatched();
					return instructions;
				}
				CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1]
				{
					new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, haveStatusEffect)), (string)null)
				});
				if (val.IsInvalid)
				{
					ReportUnpatched();
					return val.InstructionEnumeration();
				}
				return val.SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(EffectPatches), "BlocksIntake", (Type[])null, (Type[])null)).InstructionEnumeration();
			}

			private static void ReportUnpatched()
			{
				Log.Error("Player.CanConsumeItem a changé : reprendre un joint de la variété déjà active sera refusé.");
			}
		}

		[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
		{
			typeof(StatusEffect),
			typeof(bool),
			typeof(int),
			typeof(float),
			typeof(short)
		})]
		internal static class OneStrainAtATime
		{
			private static void Prefix(SEMan __instance, StatusEffect statusEffect)
			{
				if (statusEffect is StrainEffect strainEffect)
				{
					if (strainEffect.Strain != null && strainEffect.Strain.IsCbd)
					{
						return;
					}
				}
				else if (!(statusEffect is SE_Puke))
				{
					return;
				}
				RemoveStrainEffects(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeItem")]
		internal static class IntakeDuration
		{
			private static void Prefix(Player __instance, ItemData item, out Smoking.Intake __state)
			{
				__state = default(Smoking.Intake);
				Strain strain = StrainRegistry.FromJoint(item);
				StatusEffect val = ((strain == null) ? null : item.m_shared.m_consumeStatusEffect);
				if (!((Object)(object)val == (Object)null))
				{
					__state = Smoking.Begin(__instance, strain, Tiers.Of(item), val);
				}
			}

			private static void Postfix(Player __instance, bool __result, Smoking.Intake __state)
			{
				if (__result)
				{
					Smoking.Complete(__instance, __state);
				}
			}

			private static void Finalizer()
			{
				Smoking.End();
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		internal static class SilentIntake
		{
			private static readonly EffectList Silence = new EffectList();

			private static EffectList s_chewing;

			private static void Prefix(Humanoid __instance, ItemData item)
			{
				if (StrainRegistry.FromJoint(item) != null)
				{
					s_chewing = __instance.m_consumeItemEffects;
					__instance.m_consumeItemEffects = Silence;
				}
			}

			private static void Finalizer(Humanoid __instance)
			{
				if (s_chewing != null)
				{
					__instance.m_consumeItemEffects = s_chewing;
					s_chewing = null;
				}
			}
		}

		private static void RemoveStrainEffects(SEMan seman)
		{
			IReadOnlyList<int> replaceableEffectHashes = StrainRegistry.ReplaceableEffectHashes;
			for (int i = 0; i < replaceableEffectHashes.Count; i++)
			{
				seman.RemoveStatusEffect(replaceableEffectHashes[i], true);
			}
		}

		private static bool BlocksIntake(SEMan seman, int nameHash)
		{
			if (!StrainRegistry.IsEffectHash(nameHash))
			{
				return seman.HaveStatusEffect(nameHash);
			}
			return false;
		}
	}
	internal static class JointRoll
	{
		private static Action<InventoryGui, ItemData, Inventory, int> s_setupDragItem;

		private static Action<InventoryGui, bool> s_setSplitDropping;

		private static Action<InventoryGui, bool> s_updateCraftingPanel;

		private static bool s_resolved;

		private static InventoryGui s_gui;

		private static Inventory s_inventory;

		private static ItemData s_papers;

		private static ItemData s_bud;

		private static bool s_papersTargeted;

		private static Strain s_strain;

		private static int s_count;

		private static float s_duration;

		private static float s_elapsed;

		private static CraftingStation s_workbench;

		private static bool s_workbenchMissing;

		private static FieldRef<Character, ZSyncAnimation> s_zanim;

		private static Player s_player;

		private const string CraftingAnimation = "crafting";

		private const float RollSeconds = 3f;

		internal static bool Running => s_papers != null;

		internal static bool Resolve()
		{
			if (!s_resolved)
			{
				s_resolved = true;
				ResolveDelegates();
				RollProgress.Resolve();
			}
			if (s_setupDragItem != null && s_setSplitDropping != null)
			{
				return s_updateCraftingPanel != null;
			}
			return false;
		}

		private static void ResolveDelegates()
		{
			try
			{
				s_setupDragItem = Open<Action<InventoryGui, ItemData, Inventory, int>>(AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3]
				{
					typeof(ItemData),
					typeof(Inventory),
					typeof(int)
				}, (Type[])null));
				s_setSplitDropping = Open<Action<InventoryGui, bool>>(AccessTools.PropertySetter(typeof(InventoryGui), "IsSplitDropping"));
				s_updateCraftingPanel = Open<Action<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null));
			}
			catch (Exception arg)
			{
				Log.Error($"InventoryGui : délégués du glisser impossibles à créer : {arg}");
				s_setupDragItem = null;
			}
			if (s_setupDragItem == null || s_setSplitDropping == null || s_updateCraftingPanel == null)
			{
				Log.Error("InventoryGui a changé : les joints ne se rouleront pas, la pipe ne se bourrera ni ne se videra, et des feuilles lâchées sur une tête s'échangeront avec elle.");
			}
			try
			{
				s_zanim = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim");
			}
			catch (Exception ex)
			{
				Log.Warning("Character.m_zanim introuvable : le joueur roulera et fumera la pipe sans geste. " + ex.Message);
			}
		}

		private static T Open<T>(MethodInfo method) where T : Delegate
		{
			if (!(method == null))
			{
				return AccessTools.MethodDelegate<T>(method, (object)null, true);
			}
			return null;
		}

		internal static bool IsRolling(ItemData item)
		{
			if (item != null)
			{
				return item == s_papers;
			}
			return false;
		}

		internal static bool Busy(InventoryGui gui)
		{
			if (!Running)
			{
				return false;
			}
			if ((Object)(object)s_gui == (Object)(object)gui)
			{
				return true;
			}
			Clear();
			return false;
		}

		internal static ItemDrop JointOf(Strain strain)
		{
			GameObject val = (((Object)(object)ObjectDB.instance == (Object)null) ? null : ObjectDB.instance.GetItemPrefab(strain.JointItemName));
			if (!((Object)(object)val == (Object)null))
			{
				return val.GetComponent<ItemDrop>();
			}
			return null;
		}

		internal static bool HasRoom(Inventory inventory, ItemData bud, ItemData papers, int count, SharedData jointShared, int quality)
		{
			int maxStackSize = jointShared.m_maxStackSize;
			int num = ((count == bud.m_stack) ? 1 : 0) + ((count == papers.m_stack) ? 1 : 0);
			return Tiers.RoomIn(inventory, jointShared.m_name, quality, (byte)Game.m_worldLevel, maxStackSize) + num * maxStackSize >= count;
		}

		internal static void EndDrag(InventoryGui gui, InventoryGrid grid, Vector2i pos)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			s_setSplitDropping(gui, arg2: false);
			if (ZInput.IsTouchActive())
			{
				grid.SetTouchSelection(pos);
			}
			s_setupDragItem(gui, null, null, 1);
		}

		private static CraftingStation Workbench()
		{
			if ((Object)(object)s_workbench != (Object)null || s_workbenchMissing)
			{
				return s_workbench;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab("piece_workbench");
			s_workbench = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<CraftingStation>());
			if ((Object)(object)s_workbench == (Object)null)
			{
				s_workbenchMissing = true;
				Log.Warning("« piece_workbench » introuvable ou sans CraftingStation : le roulage prendra les sons de la fabrication dans l'inventaire.");
			}
			return s_workbench;
		}

		internal static void Start(InventoryGui gui, Player player, ItemData papers, ItemData bud, bool papersTargeted, Strain strain, int count)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			s_gui = gui;
			s_inventory = ((Humanoid)player).GetInventory();
			s_papers = papers;
			s_bud = bud;
			s_papersTargeted = papersTargeted;
			s_strain = strain;
			s_count = count;
			s_elapsed = 0f;
			s_duration = 3f;
			if ((Object)(object)gui.CraftingVibration != (Object)null)
			{
				Object.Instantiate<GameObject>(gui.CraftingVibration);
			}
			CraftingStation val = Workbench();
			(((Object)(object)val != (Object)null) ? val.m_craftItemEffects : gui.m_craftItemEffects).Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			s_player = player;
			if ((Object)(object)val != (Object)null)
			{
				Animate(player, val.m_useAnimation);
			}
			Log.Debug($"Roulage de {count} joints de « {strain.Id} » lancé, {s_duration:0.0} s.");
		}

		internal static void Advance(InventoryGui gui, Player player, float dt, ItemData dragItem)
		{
			if ((Object)(object)gui != (Object)(object)s_gui)
			{
				Cancel("interface remplacée");
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory != s_inventory || !inventory.ContainsItem(s_papers) || !inventory.ContainsItem(s_bud))
			{
				Cancel("une des deux piles a quitté sa case");
				return;
			}
			s_elapsed += dt;
			if (s_elapsed < s_duration)
			{
				RollProgress.Show(gui, inventory, s_papers, s_elapsed / s_duration);
			}
			else
			{
				Finish(gui, player, inventory, dragItem);
			}
		}

		private static void Finish(InventoryGui gui, Player player, Inventory inventory, ItemData dragItem)
		{
			//IL_00d8: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: 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)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = s_papers;
			ItemData val2 = s_bud;
			ItemData val3 = (s_papersTargeted ? val : val2);
			ItemData val4 = (s_papersTargeted ? val2 : val);
			Strain strain = s_strain;
			int num = Mathf.Min(s_count, Mathf.Min(val2.m_stack, val.m_stack));
			Clear();
			if (num <= 0 || val2.m_equipped || val.m_equipped || ((Character)player).IsTeleporting())
			{
				return;
			}
			ItemDrop val5 = JointOf(strain);
			if ((Object)(object)val5 == (Object)null)
			{
				return;
			}
			SharedData shared = val5.m_itemData.m_shared;
			int maxStackSize = shared.m_maxStackSize;
			int num2 = (int)Tiers.Of(val2);
			if (!HasRoom(inventory, val2, val, num, shared, num2))
			{
				((Character)player).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false);
				return;
			}
			Vector2i gridPos = default(Vector2i);
			((Vector2i)(ref gridPos))..ctor(-1, -1);
			if (num <= maxStackSize)
			{
				if (num == val3.m_stack)
				{
					gridPos = val3.m_gridPos;
				}
				else if (num == val4.m_stack)
				{
					gridPos = val4.m_gridPos;
				}
			}
			bool flag = (val2.m_cheated || val.m_cheated) && !PlayerProfile.s_bypassCheatChecks;
			if (flag)
			{
				((Vector2i)(ref gridPos))..ctor(-1, -1);
			}
			if (dragItem == val2 || dragItem == val)
			{
				s_setupDragItem(gui, null, null, 1);
			}
			inventory.RemoveItem(val3, num);
			inventory.RemoveItem(val4, num);
			inventory.AddItem(strain.JointItemName, num, num2, 0, 0L, "", gridPos, flag, false, true);
			CraftingStation val6 = Workbench();
			(((Object)(object)val6 != (Object)null) ? val6.m_craftItemDoneEffects : gui.m_craftItemDoneEffects).Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			s_updateCraftingPanel(gui, arg2: false);
			((Character)player).Message((MessageType)1, Translations.Count(num, "$ragnaroll_roll_one", "$ragnaroll_roll"), 0, TierIcons.IconOf(shared, num2), false);
			Log.Debug($"{num} joints de « {strain.Id} » roulés, {Tiers.Of(num2)}.");
		}

		internal static void CancelFromClick(InventoryGui gui)
		{
			if ((Object)(object)gui.CraftingVibration != (Object)null)
			{
				Object.Instantiate<GameObject>(gui.CraftingVibration);
			}
			Cancel("clic sur les feuilles");
		}

		internal static void Cancel(string reason)
		{
			Log.Debug("Roulage annulé : " + reason + ".");
			Clear();
		}

		internal static ZSyncAnimation Animator(Character character)
		{
			if (s_zanim != null && !((Object)(object)character == (Object)null))
			{
				return s_zanim.Invoke(character);
			}
			return null;
		}

		private static void Animate(Player player, int animation)
		{
			if (s_zanim != null && !((Object)(object)player == (Object)null) && !((Object)(object)player.GetCurrentCraftingStation() != (Object)null))
			{
				ZSyncAnimation val = s_zanim.Invoke((Character)(object)player);
				if ((Object)(object)val != (Object)null)
				{
					val.SetInt("crafting", animation);
				}
			}
		}

		private static void Clear()
		{
			Animate(s_player, 0);
			s_player = null;
			s_gui = null;
			s_inventory = null;
			s_papers = null;
			s_bud = null;
			s_strain = null;
			RollProgress.Hide();
		}
	}
	internal static class PipePatches
	{
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		internal static class Use
		{
			private static bool Prepare()
			{
				PipeUse.Resolve();
				return true;
			}

			private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui)
			{
				if (!Pipe.Is(item))
				{
					return true;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)localPlayer)
				{
					return true;
				}
				Inventory inventory2 = ((Humanoid)localPlayer).GetInventory();
				if ((inventory ?? inventory2) != inventory2 || !inventory2.ContainsItem(item))
				{
					return true;
				}
				PipeUse.Use(localPlayer, item, fromInventoryGui);
				return false;
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		})]
		internal static class Tooltip
		{
			private static void Postfix(ItemData item, bool crafting, ref string __result)
			{
				if (!Pipe.Is(item))
				{
					return;
				}
				if (!Pipe.TryRead(item, out var strain, out var tier, out var count))
				{
					__result += "\n$ragnaroll_pipe_contents: <color=orange>$ragnaroll_pipe_contents_empty</color>";
					return;
				}
				__result = __result + "\n$ragnaroll_pipe_contents: <color=orange>" + Pipe.Describe(strain, tier, count) + "</color>";
				StatusEffect val = Smoking.EffectOf(strain);
				if ((Object)(object)val != (Object)null)
				{
					val.SetLevel((int)tier, 0f);
					__result = __result + "\n\n<color=orange>" + val.m_name + "</color>\n" + val.GetTooltipString();
				}
				if (!crafting)
				{
					__result += "\n$ragnaroll_pipe_help";
				}
			}
		}

		[HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")]
		internal static class HotbarCount
		{
			private static FieldRef<object, TMP_Text> s_amount;

			private static FieldRef<object, int> s_stackText;

			private static bool Prepare()
			{
				if (s_amount != null)
				{
					return true;
				}
				string text = "";
				try
				{
					Type type = AccessTools.Inner(typeof(HotkeyBar), "ElementData");
					if (type != null)
					{
						s_amount = AccessTools.FieldRefAccess<TMP_Text>(type, "m_amount");
						s_stackText = AccessTools.FieldRefAccess<int>(type, "m_stackText");
					}
				}
				catch (Exception ex)
				{
					text = " " + ex.Message;
				}
				if (s_amount != null && s_stackText != null)
				{
					return true;
				}
				s_amount = null;
				Log.Warning("HotkeyBar.ElementData a changé : une pipe remplie ne montrera pas son compte dans la barre rapide." + text);
				return false;
			}

			private static void Postfix(List<ItemData> ___m_items, IList ___m_elements)
			{
				for (int i = 0; i < ___m_items.Count; i++)
				{
					ItemData val = ___m_items[i];
					int num = Pipe.LoadedCount(val);
					if (num != 0)
					{
						int x = val.m_gridPos.x;
						if (x >= 0 && x < ___m_elements.Count)
						{
							object obj = ___m_elements[x];
							TMP_Text obj2 = s_amount.Invoke(obj);
							((Component)obj2).gameObject.SetActive(true);
							obj2.text = Pipe.HotbarCount(num);
							s_stackText.Invoke(obj) = -1;
						}
					}
				}
			}
		}
	}
	internal static class PipeUse
	{
		private const string SmokeAnimation = "eat";

		private static Action<Humanoid, GameObject> s_interactAnimation;

		private static bool s_resolved;

		internal static void Resolve()
		{
			if (s_resolved)
			{
				return;
			}
			s_resolved = true;
			string text = "";
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "DoInteractAnimation", new Type[1] { typeof(GameObject) }, (Type[])null);
				if (methodInfo != null)
				{
					s_interactAnimation = AccessTools.MethodDelegate<Action<Humanoid, GameObject>>(methodInfo, (object)null, true);
				}
			}
			catch (Exception ex)
			{
				text = " " + ex.Message;
			}
			if (s_interactAnimation == null)
			{
				Log.Warning("Humanoid.DoInteractAnimation introuvable : la pipe utilisée sur un objet le sera sans que le joueur se tourne vers lui." + text);
			}
		}

		internal static bool Load(InventoryGui gui, InventoryGrid grid, Vector2i pos, Player player, Inventory inventory, ItemData pipe, ItemData bud, int offered, Strain strain)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			Tier tier = Tiers.Of(bud);
			int num = 0;
			if (Pipe.TryRead(pipe, out var strain2, out var tier2, out var count))
			{
				if (strain2 != strain || tier2 != tier)
				{
					((Character)player).Message((MessageType)2, string.Format(Translations.Get("$ragnaroll_pipe_holds"), Pipe.Describe(strain2, tier2, count)), 0, (Sprite)null, false);
					return false;
				}
				num = count;
			}
			int num2 = Mathf.Min(offered, 10 - num);
			if (num2 <= 0)
			{
				((Character)player).Message((MessageType)2, string.Format(Translations.Get("$ragnaroll_pipe_full"), Pipe.Describe(strain, tier, num)), 0, (Sprite)null, false);
				return false;
			}
			bool num3 = bud.m_cheated && !PlayerProfile.s_bypassCheatChecks;
			Sprite icon = bud.GetIcon();
			inventory.RemoveItem(bud, num2);
			Pipe.Write(pipe, strain, tier, num + num2);
			if (num3)
			{
				pipe.m_cheated = true;
			}
			gui.m_moveItemEffects.Create(((Component)gui).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			((Character)player).Message((MessageType)1, Translations.Count(num2, "$ragnaroll_pipe_loaded_one", "$ragnaroll_pipe_loaded"), 0, icon, false);
			JointRoll.EndDrag(gui, grid, pos);
			Log.Debug($"Pipe bourrée de {num2} têtes de « {strain.Id} », {tier} : {num + num2} / {10}.");
			return false;
		}

		internal static bool Unload(InventoryGui gui, InventoryGrid grid, ItemData pipe)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (grid.GetInventory() != inventory || !inventory.ContainsItem(pipe))
			{
				return false;
			}
			if (!Pipe.TryRead(pipe, out var strain, out var tier, out var count))
			{
				return false;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(strain.BudItemName);
			ItemDrop val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>());
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			SharedData shared = val.m_itemData.m_shared;
			int num = (int)tier;
			if (Tiers.RoomIn(inventory, shared.m_name, num, (byte)Game.m_worldLevel, shared.m_maxStackSize) < count)
			{
				((Character)localPlayer).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false);
				return true;
			}
			bool flag = pipe.m_cheated && !PlayerProfile.s_bypassCheatChecks;
			Pipe.Clear(pipe);
			inventory.AddItem(strain.BudItemName, count, num, 0, 0L, "", new Vector2i(-1, -1), flag, false, true);
			gui.m_moveItemEffects.Create(((Component)gui).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			((Character)localPlayer).Message((MessageType)1, Translations.Count(count, "$ragnaroll_pipe_unloaded_one", "$ragnaroll_pipe_unloaded"), 0, TierIcons.IconOf(shared, num), false);
			Log.Debug($"Pipe vidée : {count} têtes de « {strain.Id} », {tier}.");
			return true;
		}

		internal static void Use(Player player, ItemData pipe, bool fromInventoryGui)
		{
			if (!fromInventoryGui && UseOnHovered(player, pipe))
			{
				return;
			}
			if (!Pipe.TryRead(pipe, out var strain, out var tier, out var count))
			{
				((Character)player).Message((MessageType)2, "$ragnaroll_pipe_nothing", 0, (Sprite)null, false);
			}
			else if (Smoking.Smoke(player, strain, tier))
			{
				ZSyncAnimation val = JointRoll.Animator((Character)(object)player);
				if ((Object)(object)val != (Object)null)
				{
					val.SetTrigger("eat");
				}
				Pipe.Write(pipe, strain, tier, count - 1);
			}
		}

		private static bool UseOnHovered(Player player, ItemData pipe)
		{
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null || hoverObject.GetComponentInParent<Hoverable>() == null)
			{
				return false;
			}
			Interactable componentInParent = hoverObject.GetComponentInParent<Interactable>();
			if (componentInParent == null || !componentInParent.UseItem((Humanoid)(object)player, pipe))
			{
				return false;
			}
			s_interactAnimation?.Invoke((Humanoid)(object)player, hoverObject);
			return true;
		}
	}
	internal static class RollingPatches
	{
		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		internal static class Roll
		{
			private static bool Prepare()
			{
				return JointRoll.Resolve();
			}

			[HarmonyPriority(800)]
			private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod, GameObject ___m_dragGo, ItemData ___m_dragItem, Inventory ___m_dragInventory, int ___m_dragAmount, float ___m_craftTimer)
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Invalid comparison between Unknown and I4
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0129: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
				if (JointRoll.Running && !Object.op_Implicit((Object)(object)___m_dragGo) && JointRoll.IsRolling(item))
				{
					JointRoll.CancelFromClick(__instance);
					return false;
				}
				if ((int)mod == 1 && !Object.op_Implicit((Object)(object)___m_dragGo) && Pipe.Is(item))
				{
					return !PipeUse.Unload(__instance, grid, item);
				}
				if (___m_dragItem == null || item == null || item == ___m_dragItem)
				{
					return true;
				}
				ItemData val;
				ItemData val2;
				if (RollingPapers.Is(___m_dragItem) || Pipe.Is(___m_dragItem))
				{
					val = ___m_dragItem;
					val2 = item;
				}
				else
				{
					if (!RollingPapers.Is(item) && !Pipe.Is(item))
					{
						return true;
					}
					val = item;
					val2 = ___m_dragItem;
				}
				Strain strain = StrainRegistry.FromBud(val2);
				if (strain == null || !Object.op_Implicit((Object)(object)___m_dragGo))
				{
					return true;
				}
				if (val2.m_equipped || val.m_equipped)
				{
					return true;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
				{
					return true;
				}
				Inventory inventory = ((Humanoid)localPlayer).GetInventory();
				if (___m_dragInventory != inventory || grid.GetInventory() != inventory)
				{
					return true;
				}
				if (!inventory.ContainsItem(___m_dragItem))
				{
					return true;
				}
				if (___m_craftTimer >= 0f || JointRoll.Busy(__instance))
				{
					JointRoll.EndDrag(__instance, grid, pos);
					return false;
				}
				if (Pipe.Is(val))
				{
					int offered = ((val2 == ___m_dragItem) ? Mathf.Min(___m_dragAmount, val2.m_stack) : val2.m_stack);
					return PipeUse.Load(__instance, grid, pos, localPlayer, inventory, val, val2, offered, strain);
				}
				ItemData val3 = val;
				ItemDrop val4 = JointRoll.JointOf(strain);
				if ((Object)(object)val4 == (Object)null)
				{
					return true;
				}
				int num = Mathf.Min(___m_dragAmount, Mathf.Min(___m_dragItem.m_stack, item.m_stack));
				if (num <= 0)
				{
					return true;
				}
				if (!JointRoll.HasRoom(inventory, val2, val3, num, val4.m_itemData.m_shared, (int)Tiers.Of(val2)))
				{
					((Character)localPlayer).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false);
					return false;
				}
				JointRoll.Start(__instance, localPlayer, val3, val2, item == val3, strain, num);
				JointRoll.EndDrag(__instance, grid, pos);
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
		internal static class Advance
		{
			private static bool Prepare()
			{
				return JointRoll.Resolve();
			}

			private static void Postfix(InventoryGui __instance, Player player, float dt, ItemData ___m_dragItem)
			{
				if (JointRoll.Running)
				{
					JointRoll.Advance(__instance, player, dt, ___m_dragItem);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		internal static class CancelOnHide
		{
			private static bool Prepare()
			{
				return JointRoll.Resolve();
			}

			private static void Prefix()
			{
				if (JointRoll.Running)
				{
					JointRoll.Cancel("inventaire fermé");
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
		internal static class CancelOnCraft
		{
			private static bool Prepare()
			{
				return JointRoll.Resolve();
			}

			private static void Postfix(float ___m_craftTimer)
			{
				if (JointRoll.Running && ___m_craftTimer >= 0f)
				{
					JointRoll.Cancel("fabrication lancée");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Recipe),
			typeof(bool),
			typeof(int),
			typeof(int)
		})]
		internal static class PapersDiscovery
		{
			private static void Postfix(Player __instance, Recipe recipe, bool discover, ref bool __result)
			{
				if (__result && discover && (RollingPapers.IsRecipe(recipe) || Pipe.IsRecipe(recipe)))
				{
					__result = RollingPapers.KnowsAnyBud(__instance);
				}
			}
		}
	}
	internal static class SaturationPatches
	{
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		internal static class Spawned
		{
			private static void Postfix(Player __instance)
			{
				SaturationEffect.Restore(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		internal static class Died
		{
			private static void Prefix(Player __instance)
			{
				SaturationEffect.Clear(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "SetSleeping")]
		internal static class Slept
		{
			private static void Postfix(Player __instance, bool sleep)
			{
				if (sleep)
				{
					SaturationEffect.Clear(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(SE_Puke), "Setup")]
		internal static class Puked
		{
			private static void Postfix(Character character)
			{
				SaturationEffect.Clear((Player)(object)((character is Player) ? character : null));
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal static class StrainSheetPatch
	{
		private static bool Prefix(Humanoid __instance, ItemData item, bool fromInventoryGui)
		{
			if (!fromInventoryGui || item == null)
			{
				return true;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			Strain strain = StrainRegistry.FromSeed(item);
			if (strain == null)
			{
				return true;
			}
			Widgets.PlayClick();
			StrainSheetPanel.Open(strain);
			return false;
		}
	}
	internal static class TierPatches
	{
		[HarmonyPatch(typeof(StoreGui), "SellItem")]
		internal static class SellPrice
		{
			private const string Unpatched = "StoreGui.SellItem a changé : les têtes se vendront au prix de la qualité normale, quel que soit leur tier.";

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Expected O, but got Unknown
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Expected O, but got Unknown
				FieldInfo fieldInfo = AccessTools.Field(typeof(ItemData), "m_shared");
				FieldInfo fieldInfo2 = AccessTools.Field(typeof(SharedData), "m_value");
				MethodInfo methodInfo = AccessTools.Method(typeof(TierPatches), "SalePrice", (Type[])null, (Type[])null);
				if (fieldInfo == null || fieldInfo2 == null || methodInfo == null)
				{
					Log.Error("StoreGui.SellItem a changé : les têtes se vendront au prix de la qualité normale, quel que soit leur tier.");
					return instructions;
				}
				CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[2]
				{
					new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo, (string)null),
					new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo2, (string)null)
				});
				if (val.IsInvalid)
				{
					Log.Error("StoreGui.SellItem a changé : les têtes se vendront au prix de la qualité normale, quel que soit leur tier.");
					return val.InstructionEnumeration();
				}
				return val.SetAndAdvance(OpCodes.Call, (object)methodInfo).RemoveInstruction().InstructionEnumeration();
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		})]
		internal static class Tooltip
		{
			private static void Postfix(ItemData item, int qualityLevel, ref string __result)
			{
				if (item?.m_shared == null || item.m_shared.m_maxQuality <= 1)
				{
					return;
				}
				bool flag = StrainRegistry.FromBud(item) != null;
				if (flag || StrainRegistry.FromJoint(item) != null)
				{
					if (flag)
					{
						int num = UnitPrice(item);
						__result = __result.Replace($"$item_value: <color=orange>{item.m_shared.m_value} ({item.GetValue()} $item_total)</color>", $"$item_value: <color=orange>{num} ({num * item.m_stack} $item_total)</color>");
					}
					__result = __result.Replace($"$item_quality: <color=orange>{qualityLevel}</color>", "$item_quality: <color=orange>" + Tiers.NameToken(Tiers.Of(item)) + "</color>");
				}
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetIcon")]
		internal static class Icon
		{
			private static void Postfix(ItemData __instance, ref Sprite __result)
			{
				SharedData shared = __instance.m_shared;
				Sprite sprite;
				if (shared.m_maxQuality <= 1)
				{
					Sprite val = PipeIcons.LoadedOf(__instance);
					if ((Object)(object)val != (Object)null)
					{
						__result = val;
					}
				}
				else if (TierIcons.TryGet(shared.m_name, __instance.m_quality, out sprite))
				{
					__result = sprite;
				}
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "Awake")]
		internal static class LevelStar
		{
			private static void Postfix(EnemyHud __instance)
			{
				TierIcons.ComposeAll(__instance.m_baseHud);
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		internal static class SlotText
		{
			private static void Postfix(Inventory ___m_inventory, List<InventoryElement> ___m_elements)
			{
				if (___m_inventory == null || ___m_elements == null)
				{
					return;
				}
				List<ItemData> allItems = ___m_inventory.GetAllItems();
				int width = ___m_inventory.GetWidth();
				for (int i = 0; i < allItems.Count; i++)
				{
					ItemData val = allItems[i];
					if (val.m_shared.m_maxQuality > 1)
					{
						if (TierIcons.Has(val.m_shared.m_name))
						{
							InventoryElement val2 = ElementOf(val, width, ___m_elements);
							if ((Object)(object)val2 != (Object)null)
							{
								((Behaviour)val2.m_quality).enabled = false;
							}
						}
						continue;
					}
					int num = Pipe.LoadedCount(val);
					if (num != 0)
					{
						InventoryElement val3 = ElementOf(val, width, ___m_elements);
						if (!((Object)(object)val3 == (Object)null))
						{
							((Behaviour)val3.m_amount).enabled = true;
							val3.m_amount.text = Pipe.GridCount(num);
						}
					}
				}
			}

			private static InventoryElement ElementOf(ItemData item, int width, List<InventoryElement> elements)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: 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_0024: 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)
				Vector2i gridPos = item.m_gridPos;
				if (gridPos.x < 0 || gridPos.y < 0 || gridPos.x >= width)
				{
					return null;
				}
				int num = gridPos.y * width + gridPos.x;
				if (num >= elements.Count)
				{
					return null;
				}
				return elements[num];
			}
		}

		[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		internal static class RoomForTier
		{
			private static void Postfix(Inventory __instance, ItemData item, int stack, ref bool __result)
			{
				if (__result && item?.m_shared != null && item.m_shared.m_maxQuality > 1 && StrainRegistry.FromTiered(item) != null)
				{
					int num = ((stack <= 0) ? item.m_stack : stack);
					__result = Tiers.RoomIn(__instance, item.m_shared.m_name, item.m_quality, item.m_worldLevel, item.m_shared.m_maxStackSize) >= num;
				}
			}
		}

		private static int UnitPrice(ItemData item)
		{
			return StrainRegistry.FromBud(item)?.PriceForTier(Tiers.Of(item)) ?? item.m_shared.m_value;
		}

		private static int SalePrice(ItemData item)
		{
			Strain strain = StrainRegistry.FromBud(item);
			if (strain != null)
			{
				MarketJournal.Record(Player.m_localPlayer, strain.Id);
			}
			return UnitPrice(item);
		}
	}
	[HarmonyPatch(typeof(Trader), "GetAvailableItems")]
	internal static class TraderPatch
	{
		private static readonly Dictionary<string, TradeItem> Offers = new Dictionary<string, TradeItem>();

		private static readonly int HaldorHash = StringExtensionMethods.GetStableHashCode("Haldor");

		private static void Postfix(Trader __instance, List<TradeItem> __result)
		{
			if (__result == null || !ModConfig.SeedsSoldByTrader.Value || !IsHaldor(__instance))
			{
				return;
			}
			foreach (Strain item in StrainRegistry.All)
			{
				if (item.IsHybrid || !item.IsUnlocked())
				{
					continue;
				}
				GameObject prefab = PrefabManager.Instance.GetPrefab(item.SeedItemName);
				if (!((Object)(object)prefab == (Object)null))
				{
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && !Stocks(__result, component))
					{
						TradeItem val = OfferFor(item, component);
						val.m_price = item.SeedPrice();
						__result.Add(val);
					}
				}
			}
		}

		private static bool IsHaldor(Trader trader)
		{
			ZNetView component = ((Component)trader).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetPrefab() == HaldorHash;
			}
			return false;
		}

		private static TradeItem OfferFor(Strain strain, ItemDrop itemDrop)
		{
			//IL_0024: 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_0030: 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_0043: 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_005a: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_0095: Expected O, but got Unknown
			if (Offers.TryGetValue(strain.Id, out var value) && (Object)(object)value.m_prefab == (Object)(object)itemDrop)
			{
				return value;
			}
			value = new TradeItem
			{
				m_prefab = itemDrop,
				m_stack = 5,
				m_price = strain.SeedPrice(),
				m_name = strain.NameToken,
				m_tooltip = string.Empty,
				m_requiredGlobalKey = string.Empty,
				m_buyKey = string.Empty,
				m_incrementKey = string.Empty,
				m_incrementAmount = 0,
				m_levelUpEffect = false,
				m_buyPlayerEffects = new EffectList()
			};
			Offers[strain.Id] = value;
			return value;
		}

		private static bool Stocks(List<TradeItem> items, ItemDrop itemDrop)
		{
			for (int i = 0; i < items.Count; i++)
			{
				if ((Object)(object)items[i].m_prefab == (Object)(object)itemDrop)
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace Ragnaroll.Gui
{
	internal static class CollectionView
	{
		private const int Columns = 5;

		private const float GridTop = -76f;

		private const float SlotGap = 7f;

		private const float IconInset = 7f;

		private const float NameHeight = 24f;

		private const float RowGap = 3f;

		private static readonly Color SeenTint = new Color(0.45f, 0.45f, 0.45f, 1f);

		private const int CatalogueSize = 24;

		private static float Pitch => (StrainSheetPanel.Width - 44f) / 5f;

		private static float SlotSize => Pitch - 7f;

		internal static void Build(Transform root, Player player, Action<Strain> select)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<Strain> all = StrainRegistry.All;
			int num = Mathf.Max(24, all.Count);
			HashSet<string> grownStrains = GrowerJournal.GrownStrains(player);
			int num2 = 0;
			int num3 = 0;
			Discovery[] array = new Discovery[all.Count];
			for (int i = 0; i < all.Count; i++)
			{
				array[i] = Collection.Of(player, all[i], grownStrains);
				if (array[i] != Discovery.Unknown)
				{
					num2++;
				}
				if (array[i] == Discovery.Grown)
				{
					num3++;
				}
			}
			Widgets.Label(root, Translations.Get("$ragnaroll_collection_title"), new Vector2(0f, -20f), StrainSheetPanel.Width - 60f, 28f, 18, GUIManager.Instance.AveriaSerifBold, (TextAnchor)1, centered: true);
			string text = string.Format(Translations.Get("$ragnaroll_collection_count"), Translations.Count(num2, "$ragnaroll_collection_seen_none", "$ragnaroll_collection_seen_one", "$ragnaroll_collection_seen"), num, Translations.Count(num3, "$ragnaroll_collection_grown_none", "$ragnaroll_collection_grown_one", "$ragnaroll_collection_grown"));
			Widgets.Label(root, text, new Vector2(0f, -48f), StrainSheetPanel.Width - 70f, 20f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)1, centered: true);
			Vector2 position = default(Vector2);
			for (int j = 0; j < num; j++)
			{
				((Vector2)(ref position))..ctor(25.5f + (float)(j % 5) * Pitch, -76f - (float)(j / 5) * (SlotSize + 24f + 3f));
				Image slot = Widgets.Slot(root, "RagnarollCollectionSlot", position, SlotSize);
				if (j < all.Count && array[j] != Discovery.Unknown)
				{
					Fill(root, slot, all[j], array[j], position, select);
				}
			}
			Log.Debug($"Collection : {num2} variétés vues sur {all.Count} du code, {num3} cultivées.");
		}

		private static void Fill(Transform root, Image slot, Strain strain, Discovery discovery, Vector2 position, Action<Strain> select)
		{
			//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_0051: 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_005c: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00ff: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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)
			GameObject val = new GameObject("RagnarollCollectionIcon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(((Component)slot).transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = new Vector2(7f, 7f);
			val2.offsetMax = new Vector2(-7f, -7f);
			Image component = val.GetComponent<Image>();
			component.sprite = RagnarollAssets.LoadSprite("icon_bud_" + strain.Id);
			component.preserveAspect = true;
			((Graphic)component).raycastTarget = false;
			((Graphic)component).color = ((discovery == Discovery.Grown) ? Color.white : SeenTint);
			((UnityEvent)Widgets.SlotButton(slot).onClick).AddListener((UnityAction)delegate
			{
				select(strain);
			});
			Widgets.Label(root, Translations.Get(strain.NameToken), new Vector2(position.x - 3.5f, position.y - SlotSize - 1f), Pitch, 24f, 10, GUIManager.Instance.AveriaSerif, (TextAnchor)1);
		}
	}
	internal static class HarvestMessage
	{
		private static int _frame;

		private static int _plants;

		private static int _buds;

		private static int _seeds;

		private static Strain _strain;

		private static Tier _tier;

		internal static void Add(Strain strain, Tier tier, int buds, int seeds)
		{
			Tick();
			if (_plants == 0)
			{
				_frame = Time.frameCount;
				_strain = strain;
				_tier = tier;
			}
			_plants++;
			_buds += buds;
			_seeds += seeds;
		}

		internal static void Tick()
		{
			if (_plants != 0 && _frame != Time.frameCount)
			{
				Show();
				_plants = (_buds = (_seeds = 0));
			}
		}

		private static void Show()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				string text = Translations.Count(_buds, "$ragnaroll_harvest_buds_one", "$ragnaroll_harvest_buds");
				string text2 = Translations.Count(_seeds, "$ragnaroll_harvest_seeds_none", "$ragnaroll_harvest_seeds_one", "$ragnaroll_harvest_seeds");
				string text3 = ((_plants == 1) ? string.Format(Translations.Get("$ragnaroll_harvest_result"), Translations.Get(_strain.NameToken), Translations.Get(Tiers.NameToken(_tier)), text, text2) : string.Format(Translations.Get("$ragnaroll_harvest_batch"), _plants, text, text2));
				((Character)localPlayer).Message((MessageType)2, text3, 0, (Sprite)null, false);
			}
		}
	}
	internal sealed class PanelWatcher : MonoBehaviour
	{
		internal Action Closed;

		private int _openBefore;

		private void Awake()
		{
			_openBefore = OpenGamePanels();
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			int num = OpenGamePanels();
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !InventoryGui.IsVisible() || Input.GetKeyDown((KeyCode)27) || (num & ~_openBefore) != 0)
			{
				Closed?.Invoke();
			}
			else
			{
				_openBefore &= num;
			}
		}

		private static int OpenGamePanels()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0;
			}
			int num = 0;
			if (instance.IsSkillsPanelOpen)
			{
				num |= 1;
			}
			if (instance.IsTextPanelOpen)
			{
				num |= 2;
			}
			if (instance.IsTrophisPanelOpen)
			{
				num |= 4;
			}
			if (instance.IsAchievementsPanelOpen)
			{
				num |= 8;
			}
			return num;
		}
	}
	internal static class RollProgress
	{
		private static readonly Color BarOrange = new Color(1f, 0.71f, 0.36f);

		private const float Alpha = 0.85f;

		private static FieldRef<InventoryGrid, List<InventoryElement>> s_elements;

		private static bool s_resolved;

		private static Image s_fill;

		private static InventoryElement s_element;

		internal static void Resolve()
		{
			if (s_resolved)
			{
				return;
			}
			s_resolved = true;
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(InventoryGrid), "m_elements");
				if (fieldInfo != null && fieldInfo.FieldType == typeof(List<InventoryElement>))
				{
					s_elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>(fieldInfo);
				}
			}
			catch (Exception arg)
			{
				Log.Error($"InventoryGrid : accès aux cases impossible : {arg}");
				s_elements = null;
			}
			if (s_elements == null)
			{
				Log.Error("InventoryGrid a changé : un roulage en cours ne se verra pas sur la case des feuilles.");
			}
		}

		internal static void Show(InventoryGui gui, Inventory inventory, ItemData papers, float progress)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			InventoryElement val = ElementAt(gui.m_playerGrid, inventory, papers.m_gridPos);
			if ((Object)(object)val == (Object)null || (Object)(object)val.m_icon == (Object)null)
			{
				Hide();
				return;
			}
			if ((Object)(object)s_fill == (Object)null || (Object)(object)s_element != (Object)(object)val)
			{
				Create(gui, val);
			}
			s_fill.sprite = val.m_icon.sprite;
			s_fill.fillAmount = Mathf.Clamp01(progress);
		}

		internal static void Hide()
		{
			if ((Object)(object)s_fill != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)s_fill).gameObject);
			}
			s_fill = null;
			s_element = null;
		}

		private static InventoryElement ElementAt(InventoryGrid grid, Inventory inventory, Vector2i pos)
		{
			//IL_0029: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (s_elements == null || (Object)(object)grid == (Object)null)
			{
				return null;
			}
			List<InventoryElement> list = s_elements.Invoke(grid);
			int width = inventory.GetWidth();
			if (list == null || pos.x < 0 || pos.y < 0 || pos.x >= width)
			{
				return null;
			}
			int num = pos.y * width + pos.x;
			if (num >= list.Count)
			{
				return null;
			}
			return list[num];
		}

		private static void Create(InventoryGui gui, InventoryElement element)
		{
			//IL_0031: 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_0047: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006b: 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_0076: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			Hide();
			Image icon = element.m_icon;
			GameObject val = new GameObject("RagnarollRollProgress", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			})
			{
				layer = ((Component)icon).gameObject.layer
			};
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent((Transform)(object)((Graphic)icon).rectTransform, false);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			Image component = val.GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			component.preserveAspect = icon.preserveAspect;
			component.type = (Type)3;
			component.fillMethod = (FillMethod)1;
			component.fillOrigin = 0;
			component.fillAmount = 0f;
			((Graphic)component).color = Tint(gui);
			s_fill = component;
			s_element = element;
		}

		private static Color Tint(InventoryGui gui)
		{
			//IL_003e: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			GuiBar craftProgressBar = gui.m_craftProgressBar;
			Image val = (((Object)(object)craftProgressBar != (Object)null && (Object)(object)craftProgressBar.m_bar != (Object)null) ? ((Component)craftProgressBar.m_bar).GetComponent<Image>() : null);
			Color result = (((Object)(object)val != (Object)null) ? ((Graphic)val).color : BarOrange);
			result.a = 0.85f;
			return result;
		}
	}
	internal static class SliderFactory
	{
		private const float KnobOverhang = 4f;

		internal static Slider Create(Transform parent, string name, int min, int max, int value, float width, float height, UnityAction<float> onValueChanged)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = DefaultControls.CreateSlider(GUIManager.Instance.ValheimControlResources);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			((Object)val).name = name;
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.sizeDelta = new Vector2(width, height);
			Slider component = val.GetComponent<Slider>();
			component.wholeNumbers = true;
			component.minValue = min;
			component.maxValue = max;
			component.SetValueWithoutNotify((float)value);
			GUIManager.Instance.ApplySliderStyle(component, new Vector2(height + 4f, 4f));
			if (onValueChanged != null)
			{
				((UnityEvent<float>)(object)component.onValueChanged).AddListener(onValueChanged);
			}
			return component;
		}
	}
	internal sealed class StonedOverlay : MonoBehaviour
	{
		private const int SortingOrder = 50;

		private const float HeightAtThreshold = 0.16f;

		private const float HeightBeyond = 0.04f;

		private const float WaverHeight = 0.015f;

		private const float WaverSpeed = 1.1f;

		private const float FeatherHeight = 0.06f;

		private const float EaseRate = 2.2f;

		private const float Closed = 0.5f;

		private const float ReopenSeconds = 12f;

		private static Sprite _feather;

		private RectTransform _topBar;

		private RectTransform _topFeather;

		private RectTransform _bottomBar;

		private RectTransform _bottomFeather;

		private float _height;

		private bool _wasClosing;

		private float _reopening = -1f;

		internal static void Create()
		{
			//IL_004a: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GUIManager.CustomGUIBack == (Object)null)
			{
				Log.Warning("Paupières : pas de canvas Jötunn, rien à afficher.");
				return;
			}
			GameObject val = new GameObject("RagnarollStonedOverlay", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(StonedOverlay)
			})
			{
				layer = GUIManager.CustomGUIBack.layer
			};
			val.transform.SetParent(GUIManager.CustomGUIBack.transform.parent, false);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 50;
			Log.Debug($"Paupières posées à côté de « {((Object)GUIManager.CustomGUIBack).name} », ordre {50}.");
		}

		private void Awake()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			_topBar = Bar("TopBar", null);
			_topFeather = Bar("TopFeather", Feather());
			_bottomBar = Bar("BottomBar", null);
			_bottomFeather = Bar("BottomFeather", Feather());
			((Transform)_topFeather).localScale = new Vector3(1f, -1f, 1f);
			Apply(0f);
			Show(visible: false);
		}

		private RectTransform Bar(string name, Sprite sprite)
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_004a: 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)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Component)this).transform, false);
			val2.pivot = new Vector2(0.5f, 0.5f);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = Color.black;
			component.sprite = sprite;
			((Graphic)component).raycastTarget = false;
			return val2;
		}

		private static Sprite Feather()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_feather != (Object)null)
			{
				return _feather;
			}
			Texture2D val = new Texture2D(1, 64, (TextureFormat)4, false)
			{
				wrapMode = (TextureWrapMode)1
			};
			for (int i = 0; i < 64; i++)
			{
				float num = (float)i / 63f;
				val.SetPixel(0, i, new Color(0f, 0f, 0f, 1f - num * num));
			}
			val.Apply();
			_feather = Sprite.Create(val, new Rect(0f, 0f, 1f, 64f), new Vector2(0.5f, 0.5f));
			return _feather;
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			_height = (((Object)(object)localPlayer == (Object)null || !ModConfig.Eyelids.Value) ? Reset() : Height(localPlayer));
			bool flag = _height > 0.0005f;
			if (((Component)_topBar).gameObject.activeSelf != flag)
			{
				Show(flag);
				Log.Debug(flag ? $"Paupières : descendent, saturation {SaturationEffect.RatioOf(localPlayer):0.00} de la tolérance." : "Paupières : relevées.");
			}
			if (flag)
			{
				Apply(_height);
			}
		}

		private void Show(bool visible)
		{
			((Component)_topBar).gameObject.SetActive(visible);
			((Component)_topFeather).gameObject.SetActive(visible);
			((Component)_bottomBar).gameObject.SetActive(visible);
			((Component)_bottomFeather).gameObject.SetActive(visible);
		}

		private static float TargetHeight(Player player)
		{
			float num = SaturationEffect.RatioOf(player);
			if (num <= 0f)
			{
				return 0f;
			}
			float num2 = 0.16f * Mathf.Clamp01(num);
			if (num < 1f)
			{
				return num2;
			}
			float num3 = Mathf.Clamp01(num - 1f);
			float num4 = (Mathf.Sin(Time.time * 1.1f) + 1f) * 0.5f * 0.015f;
			return num2 + 0.04f * num3 + num4;
		}

		private float Height(Player player)
		{
			if (SaturationEffect.OverdoseElapsedOf(player) >= 0f)
			{
				_wasClosing = true;
				return Mathf.MoveTowards(_height, 0.5f, 1f / 6f * Time.deltaTime);
			}
			if (_wasClosing)
			{
				_wasClosing = false;
				_reopening = 0f;
			}
			if (_reopening >= 0f)
			{
				_reopening += Time.deltaTime;
				float num = _reopening / 12f;
				if (num >= 1f)
				{
					_reopening = -1f;
				}
				return 0.5f * (1f - Mathf.Clamp01(num));
			}
			return Mathf.Lerp(_height, TargetHeight(player), 1f - Mathf.Exp(-2.2f * Time.deltaTime));
		}

		private float Reset()
		{
			_wasClosing = false;
			_reopening = -1f;
			return 0f;
		}

		private void Apply(float height)
		{
			Stretch(_topBar, 1f - height, 1f);
			Stretch(_topFeather, 1f - height - 0.06f, 1f - height);
			Stretch(_bottomBar, 0f, height);
			Stretch(_bottomFeather, height, height + 0.06f);
		}

		private static void Stretch(RectTransform rect, float fromY, float toY)
		{
			//IL_0007: 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)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, fromY);
			rect.anchorMax = new Vector2(1f, toY);
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
		}
	}
	internal static class StrainSheetPanel
	{
		private enum View
		{
			Strain,
			Collection
		}

		private enum Tab
		{
			Infos,
			Nutrition,
			Crosses
		}

		private sealed class NpkSlider
		{
			private const float LetterWidth = 18f;

			private const float ValueInset = 4f;

			private const float ValueWidth = 15f;

			private const float LetterGlyph = 6.8f;

			private const float DigitGlyph = 3.8f;

			private const float TrackGap = 11.2f;

			private const float CapCenter = 6.5f;

			private const float SliderHeight = 18f;

			private readonly Slider _slider;

			private readonly Text _value;

			internal int Value
			{
				get
				{
					if (!((Object)(object)_slider == (Object)null))
					{
						return Mathf.RoundToInt(_slider.value);
					}
					return 0;
				}
			}

			internal NpkSlider(string letter, int initial, float y)
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: 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_0111: 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_0126: 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_014d: Unknown result type (might be due to invalid IL or missing references)
				float num = 22f + ContentWidth - 4f;
				float width = num - 3.8f - 11.2f - 40f;
				Label(letter, new Vector2(22f, y), 18f, 20f, 13, GUIManager.Instance.AveriaSerifBold, (TextAnchor)0);
				_value = Label(initial.ToString(), new Vector2(num - 15f, y), 15f, 20f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)2).GetComponent<Text>();
				_slider = SliderFactory.Create(_root.transform, "RagnarollSlider_" + letter, 0, 10, initial, width, 18f, delegate(float v)
				{
					_value.text = Mathf.RoundToInt(v).ToString();
				});
				if ((Object)(object)_slider == (Object)null)
				{
					Log.Error("Curseur « " + letter + " » non créé : le dosage ne sera pas réglable.");
					return;
				}
				RectTransform val = (RectTransform)((Component)_slider).transform;
				val.anchorMin = new Vector2(0f, 1f);
				val.anchorMax = new Vector2(0f, 1f);
				val.pivot = new Vector2(0f, 1f);
				val.anchoredPosition = new Vector2(40f, y - 6.5f + 9f);
				((Component)_slider).gameObject.AddComponent<ReleaseNotifier>().Released = CommitDosage;
			}
		}

		private sealed class ReleaseNotifier : MonoBehaviour, IPointerUpHandler, IEventSystemHandler, IDeselectHandler
		{
			internal Action Released;

			public void OnPointerUp(PointerEventData eventData)
			{
				Released?.Invoke();
			}

			public void OnDeselect(BaseEventData eventData)
			{
				Released?.Invoke();
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__Close;

			public static UnityAction <1>__Close;
		}

		private const float DesignWidth = 458f;

		private const float DesignHeight = 657f;

		private const int SortingOrder = 1000;

		internal const float Margin = 22f;

		private const float Indent = 28f;

		private const float LineHeight = 19f;

		private const float BandGap = 2f;

		private const float ViewTabWidth = 118f;

		private const float ViewTabHeight = 28f;

		private const float ViewTabOverlap = 7f;

		private const float TabsTop = -294f;

		private const float TabHeight = 28f;

		private const float TabGap = 8f;

		private const float BodyTop = -332f;

		private const float FactHeight = 20f;

		private const int MaxJournalRows = 7;

		private const float JournalTop = -466f;

		private const int MaxTrialRows = 13;

		private const float TrialsTop = -356f;

		private const float PortraitSize = 130f;

		private const float PortraitTop = -70f;

		private const float LoreGap = 4f;

		private static float _shift;

		private static GameObject _canvas;

		private static GameObject _root;

		private static string _strainId;

		private static View _view = View.Strain;

		private static Tab _tab = Tab.Infos;

		private static NpkSlider _sliderN;

		private static NpkSlider _sliderP;

		private static NpkSlider _sliderK;

		private static Vector2 _position;

		private const string More = "...";

		internal static float Width { get; private set; } = 458f;

		private static float ContentWidth => Width - 44f;

		private static string Unknown => Translations.Get("$ragnaroll_sheet_unknown");

		internal static void Open(Strain strain)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				_position = Vector2.zero;
			}
			_view = View.Strain;
			Show(strain);
		}

		internal static void Close()
		{
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			CommitDosage();
			_strainId = null;
			_sliderN = (_sliderP = (_sliderK = null));
			if ((Object)(object)_root != (Object)null)
			{
				_position = ((RectTransform)_root.transform).anchoredPosition;
			}
			if ((Object)(object)_canvas != (Object)null)
			{
				Object.Destroy((Object)(object)_canvas);
			}
			_canvas = null;
			_root = null;
		}

		private static void Show(Strain strain)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			Close();
			Player localPlayer = Player.m_localPlayer;
			if (strain == null || (Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			_strainId = strain.Id;
			if (GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null)
			{
				Log.Warning("Interface de Jötunn indisponible : la fiche de variété ne peut pas s'ouvrir.");
				return;
			}
			float num = 657f;
			float num2 = 1f;
			RectTransform val = SkillsFrame();
			if ((Object)(object)val != (Object)null)
			{
				Rect rect = val.rect;
				Width = ((Rect)(ref rect)).width;
				rect = val.rect;
				num = ((Rect)(ref rect)).height;
				num2 = ((Transform)val).lossyScale.x;
			}
			_canvas = new GameObject("RagnarollSheetCanvas", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			_canvas.layer = GUIManager.CustomGUIFront.layer;
			Canvas component = _canvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 1000;
			CanvasScaler component2 = _canvas.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)0;
			component2.scaleFactor = num2;
			component2.referencePixelsPerUnit = 50f;
			_root = GUIManager.Instance.CreateWoodpanel(_canvas.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), _position, Width, num, true);
			if ((Object)(object)_root == (Object)null)
			{
				Log.Error("Le panneau de la fiche de variété n'a pas pu être créé.");
				Close();
				return;
			}
			BuildViewTabs(strain);
			if (_view == View.Collection)
			{
				CollectionView.Build(_root.transform, localPlayer, delegate(Strain selected)
				{
					_view = View.Strain;
					Show(selected);
				});
			}
			else
			{
				BuildStrainView(localPlayer, strain);
			}
			BuildCloseButton();
			_root.AddComponent<PanelWatcher>().Closed = Close;
			Log.Debug($"Fenêtre ouverte sur « {strain.Id} », vue {_view}, onglet {_tab}, {Width:0}x{num:0} à l'échelle {num2:0.00}.");
		}

		private static RectTransform SkillsFrame()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			SkillsDialog val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_skillsDialog : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			foreach (Transform item in ((Component)val).transform)
			{
				object obj = (object)item;
				RectTransform val2 = (RectTransform)((obj is RectTransform) ? obj : null);
				if (val2 != null && val2.sizeDelta.x > 0f && val2.sizeDelta.y > 0f)
				{
					return val2;
				}
			}
			return null;
		}

		private static void BuildStrainView(Player player, Strain strain)
		{
			StrainSheet sheet = StrainSheet.Build(player, strain);
			Sprite val = LoadPortrait(strain);
			_shift = (((Object)(object)val != (Object)null) ? 0f : 130f);
			BuildHeader(sheet);
			if ((Object)(object)val != (Object)null)
			{
				BuildPortrait(val);
			}
			BuildLore(strain);
			BuildTabs(strain);
			switch (_tab)
			{
			case Tab.Infos:
				BuildInfos(sheet);
				break;
			case Tab.Nutrition:
				BuildDosage(sheet);
				BuildJournal(sheet);
				break;
			default:
				BuildCrosses(CrossingSheet.Build(player, strain));
				break;
			}
		}

		private static void BuildViewTabs(Strain strain)
		{
			//IL_003e: 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_0078: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			Vector2 anchor = default(Vector2);
			((Vector2)(ref anchor))..ctor(1f, 1f);
			float num = 7f;
			float num2 = -81f;
			Button val = Widgets.Tab(_root.transform, Translations.Get("$ragnaroll_sheet_view_strain"), anchor, new Vector2(num, num2), 118f, 28f, _view == View.Strain, -90f);
			Button obj = Widgets.Tab(_root.transform, Translations.Get("$ragnaroll_sheet_collection"), anchor, new Vector2(num, num2 - 118f - 6f), 118f, 28f, _view == View.Collection, -90f);
			((UnityEvent)val.onClick).AddListener((UnityAction)delegate
			{
				SwitchView(View.Strain, strain);
			});
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				SwitchView(View.Collection, strain);
			});
		}

		private static void SwitchView(View view, Strain strain)
		{
			_view = view;
			Show(strain);
		}

		private static void BuildHeader(StrainSheet sheet)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Label(Translations.Get(sheet.Strain.NameToken), new Vector2(0f, -20f), Width - 60f, 28f, 18, GUIManager.Instance.AveriaSerifBold, (TextAnchor)1, centered: true);
			Label(Translations.Get(Families.DescriptionToken(sheet.Strain.Family)), new Vector2(0f, -46f), Width - 70f, 20f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)1, centered: true);
		}

		private static Sprite LoadPortrait(Strain strain)
		{
			string name = "portrait_" + strain.Id;
			if (!RagnarollAssets.Contains(name))
			{
				return null;
			}
			return RagnarollAssets.LoadSprite(name);
		}

		private static void BuildPortrait(Sprite portrait)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0039: 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)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0059: 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)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("RagnarollPortrait", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_root.transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 1f);
			val2.pivot = val3;
			Vector2 anchorMin = (val2.anchorMax = val3);
			val2.anchorMin = anchorMin;
			val2.anchoredPosition = new Vector2(0f, -70f);
			val2.sizeDelta = new Vector2(130f, 130f);
			Image obj = val.AddComponent<Image>();
			obj.sprite = portrait;
			obj.preserveAspect = true;
			((Graphic)obj).raycastTarget = false;
			Shadow obj2 = val.AddComponent<Shadow>();
			obj2.effectColor = new Color(0f, 0f, 0f, 0.55f);
			obj2.effectDistance = new Vector2(2f, -4f);
		}

		private static void BuildLore(Strain strain)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			string text = strain.NameToken + "_lore";
			string text2 = Translations.Get(text);
			if (!(text2 == text) && !text2.StartsWith("["))
			{
				float num = -204f;
				float height = num - -294f - 4f;
				Label(text2, new Vector2(0f, Below(num)), Width - 70f, height, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)4, centered: true);
			}
		}

		private static float Below(float y)
		{
			return y + _shift;
		}

		private static void BuildInfos(StrainSheet sheet)
		{
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			Strain strain = sheet.Strain;
			bool isKnown = sheet.IsKnown;
			float num = Below(-332f);
			Fact(string.Format(Translations.Get("$ragnaroll_sheet_growtime"), (!isKnown) ? Unknown : string.Format(Translations.Get("$ragnaroll_sheet_minutes"), Mathf.RoundToInt(strain.GrowSeconds() / 60f))), num);
			Fact(string.Format(Translations.Get("$ragnaroll_sheet_value"), (!sheet.IsSold) ? Unknown : string.Format(Translations.Get("$ragnaroll_sheet_value_range"), strain.PriceForTier(Tier.Poor), strain.PriceForTier(Tier.Legendary))), num -= 20f);
			Fact(string.Format(Translations.Get("$ragnaroll_sheet_yield"), YieldLabel(sheet.ObservedYield)), num -= 20f);
			Fact(string.Format(Translations.Get("$ragnaroll_sheet_best"), sheet.BestMix?.ToLabel() ?? Unknown), num -= 20f);
			num -= 34f;
			if (!isKnown)
			{
				Fact(string.Format(Translations.Get("$ragnaroll_sheet_effect"), Unknown), num);
				return;
			}
			Label(Translations.Get(strain.EffectNameToken), new Vector2(22f, num), ContentWidth, 20f, 13, GUIManager.Instance.AveriaSerifBold, (TextAnchor)0);
			StringBuilder stringBuilder = new StringBuilder(128);
			foreach (Lever lever in strain.Levers)
			{
				lever.AppendTooltipRange(stringBuilder, strain.PowerFor(Tier.Poor), strain.PowerFor(Tier.Legendary));
			}
			AppendDuration(stringBuilder, strain);
			string[] array = Translations.Get(stringBuilder.ToString()).Split(new char[1] { '\n' });
			foreach (string text in array)
			{
				if (text.Length != 0)
				{
					Label(text, new Vector2(28f, num -= 20f), ContentWidth - 6f, 18f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)0);
				}
			}
		}

		private static void AppendDuration(StringBuilder text, Strain strain)
		{
			string value = ItemData.GetDurationString(strain.EffectSeconds(Tier.Poor)).TrimEnd(Array.Empty<char>());
			string value2 = ItemData.GetDurationString(strain.EffectSeconds(Tier.Legendary)).TrimEnd(Array.Empty<char>());
			text.Append("$se_ttl: <color=orange>").Append(value);
			if (strain.IsCbd)
			{
				text.Append("</color> $ragnaroll_sheet_duration_fixed\n");
			}
			else
			{
				text.Append(" $ragnaroll_to ").Append(value2).Append("</color>\n");
			}
		}

		private static void BuildTabs(Strain strain)
		{
			TabButton(strain, Tab.Infos, "$ragnaroll_sheet_tab_infos", 0);
			TabButton(strain, Tab.Nutrition, "$ragnaroll_sheet_tab_nutrition", 1);
			TabButton(strain, Tab.Crosses, "$ragnaroll_sheet_tab_crosses", 2);
		}

		private static void TabButton(Strain strain, Tab tab, string token, int index)
		{
			//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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			float num = (ContentWidth - 16f) / 3f;
			Vector2 center = default(Vector2);
			((Vector2)(ref center))..ctor(22f + (float)index * (num + 8f) + num / 2f, Below(-294f) - 14f);
			((UnityEvent)Widgets.Tab(_root.transform, Translations.Get(token), new Vector2(0f, 1f), center, num, 28f, _tab == tab).onClick).AddListener((UnityAction)delegate
			{
				SwitchTab(tab, strain);
			});
		}

		private static void SwitchTab(Tab tab, Strain strain)
		{
			_tab = tab;
			Show(strain);
		}

		private static void BuildDosage(StrainSheet sheet)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Label(Translations.Get("$ragnaroll_sheet_dosage"), new Vector2(22f, Below(-332f)), ContentWidth, 20f, 13, GUIManager.Instance.AveriaSerifBold, (TextAnchor)0);
			_sliderN = new NpkSlider("N", sheet.CurrentMix.N, Below(-358f));
			_sliderP = new NpkSlider("P", sheet.CurrentMix.P, Below(-384f));
			_sliderK = new NpkSlider("K", sheet.CurrentMix.K, Below(-410f));
		}

		private static void BuildJournal(StrainSheet sheet)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Label(Translations.Get("$ragnaroll_sheet_journal"), new Vector2(22f, Below(-444f)), ContentWidth, 20f, 13, GUIManager.Instance.AveriaSerifBold, (TextAnchor)0);
			if (sheet.Attempts.Count == 0)
			{
				Line(Translations.Get("$ragnaroll_sheet_journal_empty"), Below(-466f));
				return;
			}
			Lines(sheet.Attempts.Count, 7, Below(-466f), delegate(int i)
			{
				GrowerJournal.Attempt attempt = sheet.Attempts[i];
				return string.Format(Translations.Get("$ragnaroll_sheet_journal_line"), attempt.Ratio.ToLabel(), GrowerJournal.PercentOf(attempt.Score));
			});
		}

		private static void BuildCrosses(CrossingSheet crosses)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Label(Translations.Get("$ragnaroll_sheet_crosses"), new Vector2(22f, Below(-332f)), ContentWidth, 20f, 13, GUIManager.Instance.AveriaSerifBold, (TextAnchor)0);
			if (crosses.Trials.Count == 0)
			{
				Line(Translations.Get("$ragnaroll_sheet_crosses_empty"), Below(-356f));
				return;
			}
			Lines(crosses.Trials.Count, 13, Below(-356f), delegate(int i)
			{
				CrossingSheet.Trial trial = crosses.Trials[i];
				string arg = ((trial.Hybrid != null) ? Translations.Get(trial.Hybrid.NameToken) : Translations.Get("$ragnaroll_sheet_cross_none"));
				return string.Format(Translations.Get("$ragnaroll_sheet_cross_line"), Translations.Get(trial.Partner.NameToken), arg);
			});
		}

		private static void BuildCloseButton()
		{
			//IL_001e: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			ButtonClickedEvent onClick = Widgets.GameButton(Translations.Get("$ragnaroll_sheet_close"), _root.transform, new Vector2(0.5f, 0f), new Vector2(0f, 22f), 120f, 30f).onClick;
			object obj = <>O.<1>__Close;
			if (obj == null)
			{
				UnityAction val = Close;
				<>O.<1>__Close = val;
				obj = (object)val;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
		}

		private static void CommitDosage()
		{
			if ((Object)(object)_root == (Object)null || _strainId == null || _sliderN == null || _sliderP == null || _sliderK == null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				NpkRatio ratio = new NpkRatio(_sliderN.Value, _sliderP.Value, _sliderK.Value);
				if (!ratio.Equals(FertilizerBench.Current(localPlayer, _strainId)))
				{
					FertilizerBench.Set(localPlayer, _strainId, ratio);
				}
			}
		}

		private static string YieldLabel(GrowerJournal.YieldRange observed)
		{
			if (!observed.HasData)
			{
				return Unknown;
			}
			if (observed.Min == observed.Max)
			{
				return Translations.Count(observed.Min, "$ragnaroll_harvest_buds_one", "$ragnaroll_harvest_buds");
			}
			return string.Format(Translations.Get("$ragnaroll_sheet_yield_range"), observed.Min, observed.Max);
		}

		private static void Fact(string text, float y)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Label(text, new Vector2(22f, y), ContentWidth, 18f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)0);
		}

		private static void Line(string text, float y)
		{
			//IL_0010: 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)
			Widgets.Band(_root.transform, new Vector2(22f, y), ContentWidth, 17f);
			Label(text, new Vector2(28f, y), ContentWidth - 6f, 17f, 12, GUIManager.Instance.AveriaSerif, (TextAnchor)3);
		}

		private static void Lines(int count, int maxRows, float top, Func<int, string> text)
		{
			int num = ((count <= maxRows) ? count : (maxRows - 1));
			for (int i = 0; i < num; i++)
			{
				Line(text(i), top - (float)i * 19f);
			}
			if (num < count)
			{
				Line("...", top - (float)num * 19f);
			}
		}

		private static GameObject Label(string text, Vector2 position, float width, float height, int fontSize, Font font, TextAnchor alignment, bool centered = false)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return Widgets.Label(_root.transform, text, position, width, height, fontSize, font, alignment, centered);
		}
	}
	internal static class Widgets
	{
		private static readonly FieldRef<ButtonTextColor, Color> RestColor = AccessTools.FieldRefAccess<ButtonTextColor, Color>("m_defaultColor");

		private static readonly FieldRef<ButtonTextColor, Color> RestMeshColor = AccessTools.FieldRefAccess<ButtonTextColor, Color>("m_defaultMeshColor");

		private static readonly Color BandColor = new Color(0f, 0f, 0f, 0.32f);

		internal const float ReferencePixelsPerUnit = 50f;

		private const string SlotSprite = "item_background";

		internal static GameObject Label(Transform parent, string text, Vector2 position, float width, float height, int fontSize, Font font, TextAnchor alignment, bool centered = false)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_002c: 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_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_0039: 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_0052: 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)
			Vector2 val = (centered ? new Vector2(0.5f, 1f) : new Vector2(0f, 1f));
			GameObject obj = GUIManager.Instance.CreateText(text, parent, val, val, position, font, fontSize, Color.white, true, Color.black, width, height, false);
			((RectTransform)obj.transform).pivot = val;
			obj.GetComponent<Text>().alignment = alignment;
			return obj;
		}

		internal static Button Tab(Transform parent, string text, Vector2 anchor, Vector2 center, float width, float height, bool selected, float rotation = 0f)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			//IL_00c0: Expected O, but got Unknown
			//IL_0026: Un