Decompiled source of BindingLectern v0.1.3

BepInEx/plugins/BindingLectern/BindingLectern.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using On.RoR2;
using ProperSave;
using R2API;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace BindingLectern;

internal sealed class LecternPlacement : IPlacementSurface
{
	private readonly TrialGongInteraction gong;

	private readonly Scene scene;

	private readonly Vector3 anchor;

	private readonly Quaternion rotation;

	private readonly int mask = LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.world)).mask) | LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.defaultLayer)).mask);

	private LecternPlacement(TrialGongInteraction gong, Scene scene)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: 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_0034: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: 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_0084: 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)
		this.gong = gong;
		this.scene = scene;
		anchor = (Object.op_Implicit((Object)(object)gong.mainHurtBox) ? ((Component)gong.mainHurtBox).transform.position : ((Component)gong).transform.position);
		rotation = Quaternion.Euler(0f, ((Component)gong).transform.eulerAngles.y, 0f);
	}

	private bool IsSceneSolid(Collider c)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)c) && ((Component)c).gameObject.scene == scene && !c.isTrigger && !Object.op_Implicit((Object)(object)c.attachedRigidbody))
		{
			return !Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<CharacterBody>());
		}
		return false;
	}

	private bool IsGround(Collider c)
	{
		if (IsSceneSolid(c) && !((Component)c).transform.IsChildOf(((Component)gong).transform))
		{
			return !Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent<NetworkIdentity>());
		}
		return false;
	}

	public SurfacePoint? Sample(float x, float z)
	{
		//IL_0013: 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_005b: 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_0072: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		foreach (RaycastHit item in from h in Physics.RaycastAll(new Vector3(x, anchor.y + 6f, z), Vector3.down, 26f, mask, (QueryTriggerInteraction)1)
			orderby ((RaycastHit)(ref h)).distance
			select h)
		{
			RaycastHit current = item;
			if (IsGround(((RaycastHit)(ref current)).collider) && ((RaycastHit)(ref current)).point.y <= anchor.y + 2f && ((RaycastHit)(ref current)).point.y >= anchor.y - 16f)
			{
				return new SurfacePoint(((RaycastHit)(ref current)).point.y, ((RaycastHit)(ref current)).normal.y);
			}
		}
		return null;
	}

	public bool IsClear(float x, float y, float z)
	{
		//IL_0009: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		Collider[] array = Physics.OverlapBox(new Vector3(x, y + 0.98f, z), new Vector3(0.46f, 0.72f, 0.45f), rotation, mask, (QueryTriggerInteraction)1);
		foreach (Collider val in array)
		{
			if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.scene == scene && !val.isTrigger && !Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<CharacterBody>()))
			{
				return false;
			}
		}
		Transform preferredSpawnPosition = gong.preferredSpawnPosition;
		if (Object.op_Implicit((Object)(object)preferredSpawnPosition))
		{
			Vector3 val2 = Vector3.ProjectOnPlane(new Vector3(x, y, z) - preferredSpawnPosition.position, Vector3.up);
			if (((Vector3)(ref val2)).sqrMagnitude < 2.25f)
			{
				return false;
			}
		}
		return true;
	}

	public static bool TryFind(TrialGongInteraction gong, Scene scene, out Vector3 position, out string diagnostics)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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_0054: 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_0065: Unknown result type (might be due to invalid IL or missing references)
		LecternPlacement lecternPlacement = new LecternPlacement(gong, scene);
		PlacementResult result2;
		bool result = PlacementRules.Find(lecternPlacement, lecternPlacement.anchor.x, lecternPlacement.anchor.z, ((Component)gong).transform.eulerAngles.y * ((float)Math.PI / 180f), out result2);
		position = new Vector3(result2.X, result2.Y, result2.Z);
		string? text = ((object)lecternPlacement.anchor/*cast due to .constrained prefix*/).ToString();
		PlacementResult placementResult = result2;
		diagnostics = "anchor=" + text + " " + placementResult.ToString();
		return result;
	}
}
public static class Model
{
	public static void Load(Transform parent, string folder)
	{
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Expected O, but got Unknown
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(folder, "lectern.mesh")));
		if (binaryReader.ReadInt32() != 1279607636)
		{
			throw new InvalidDataException("Invalid lectern mesh");
		}
		int num = binaryReader.ReadInt32();
		for (int i = 0; i < num; i++)
		{
			int num2 = binaryReader.ReadInt32();
			Vector3[] array = (Vector3[])(object)new Vector3[num2];
			Vector2[] array2 = (Vector2[])(object)new Vector2[num2];
			for (int j = 0; j < num2; j++)
			{
				array[j] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
				array2[j] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			int num3 = binaryReader.ReadInt32();
			int[] array3 = new int[num3];
			for (int k = 0; k < num3; k++)
			{
				array3[k] = binaryReader.ReadInt32();
			}
			Mesh val = new Mesh
			{
				name = "Meshy6Lectern"
			};
			val.indexFormat = (IndexFormat)1;
			val.vertices = array;
			val.uv = array2;
			val.triangles = array3;
			val.RecalculateNormals();
			val.RecalculateBounds();
			GameObject val2 = new GameObject("Lectern mesh " + i);
			val2.transform.SetParent(parent, false);
			val2.AddComponent<MeshFilter>().sharedMesh = val;
			Material val3 = new Material(Shader.Find("Hopoo Games/Deferred/Standard") ?? Shader.Find("Standard"));
			Texture2D val4 = new Texture2D(2, 2);
			ImageConversion.LoadImage(val4, File.ReadAllBytes(Path.Combine(folder, "texture" + i + ".jpg")));
			val3.mainTexture = (Texture)(object)val4;
			val3.color = Color.white;
			val3.SetFloat("_Glossiness", 0.12f);
			((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = val3;
		}
	}
}
public sealed class OfferVisual : MonoBehaviour
{
	private Lectern lectern;

	private PickupDisplay display;

	private TextMesh label;

	private int displayed = -1;

	private void Start()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: 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_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		lectern = ((Component)this).GetComponent<Lectern>();
		GameObject val = new GameObject("Floating offered page");
		val.transform.SetParent(((Component)this).transform, false);
		val.transform.localPosition = new Vector3(0f, 2.35f, 0f);
		display = val.AddComponent<PickupDisplay>();
		display.coloredParticleSystems = Array.Empty<ParticleSystem>();
		display.verticalWave = new Wave
		{
			amplitude = 0.12f,
			frequency = 0.35f
		};
		display.spinSpeed = 35f;
		display.onModelDiscovered += OnModelReady;
		GameObject val2 = new GameObject("Offer name and price");
		val2.transform.SetParent(((Component)this).transform, false);
		val2.transform.localPosition = new Vector3(0f, 3.15f, 0f);
		label = val2.AddComponent<TextMesh>();
		label.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
		((Renderer)((Component)label).GetComponent<MeshRenderer>()).sharedMaterial = label.font.material;
		label.characterSize = 0.025f;
		label.fontSize = 48;
		label.anchor = (TextAnchor)4;
		label.alignment = (TextAlignment)1;
		label.color = new Color(0.65f, 0.92f, 1f);
		val2.AddComponent<FaceViewingCamera>();
	}

	private void Update()
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Invalid comparison between Unknown and I4
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: 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_0073: 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_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)lectern) || !Object.op_Implicit((Object)(object)display) || lectern.Output < 0 || lectern.Output >= Plugin.Names.Length || displayed == lectern.Output)
		{
			return;
		}
		ItemIndex val = ItemCatalog.FindItemIndex(Plugin.Names[lectern.Output]);
		if ((int)val != -1)
		{
			PickupIndex val2 = PickupCatalog.FindPickupIndex(val);
			if (!(val2 == PickupIndex.none))
			{
				UniquePickup val3 = default(UniquePickup);
				((UniquePickup)(ref val3))..ctor(val2);
				display.SetPickup(ref val3, false);
				displayed = lectern.Output;
				label.text = Language.GetString(ItemCatalog.GetItemDef(val).nameToken) + "\n2 pages";
			}
		}
	}

	private void OnModelReady(PickupDisplay ready)
	{
		Collider[] componentsInChildren = ((Component)ready).GetComponentsInChildren<Collider>();
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			componentsInChildren[i].enabled = false;
		}
	}

	private void OnDestroy()
	{
		if (Object.op_Implicit((Object)(object)display))
		{
			display.onModelDiscovered -= OnModelReady;
		}
	}
}
public sealed class FaceViewingCamera : MonoBehaviour
{
	private void OnWillRenderObject()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)Camera.current))
		{
			((Component)this).transform.rotation = ((Component)Camera.current).transform.rotation;
		}
	}
}
internal static class PageBias
{
	private static Run run;

	private static ReincarnationRules rules;

	private static PickupIndex[] pickups;

	private static int generationDepth;

	private static bool installed;

	internal static bool SaveEnabled;

	private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly FieldInfo basicSelector = typeof(BasicPickupDropTable).GetField("selector", Fields);

	private static readonly FieldInfo explicitSelector = typeof(ExplicitPickupDropTable).GetField("weightedSelection", Fields);

	internal static bool HasAppeared
	{
		get
		{
			if (Ready())
			{
				return rules.HasAppeared;
			}
			return false;
		}
	}

	internal static void RestoreSeen()
	{
		if (Ready())
		{
			rules.Observe(0);
		}
	}

	private static bool Ready()
	{
		if (!NetworkServer.active || !Object.op_Implicit((Object)(object)Run.instance))
		{
			return false;
		}
		bool num = (Object)(object)run != (Object)(object)Run.instance;
		if (num)
		{
			run = Run.instance;
			rules = new ReincarnationRules((int)run.seed ^ (int)(run.seed >> 32) ^ 0x5245494E);
			pickups = null;
		}
		if (SaveEnabled && !rules.HasAppeared && SaveBridge.SeenWhileLoading())
		{
			rules.Observe(0);
		}
		if (num)
		{
			Plugin.Instance.LogBias(rules.HasAppeared ? "Restored used Reincarnation boost; normal page odds remain active." : "Reincarnation boost armed: 50% for eligible random pages until first appearance.");
		}
		if (pickups == null)
		{
			ItemIndex[] source = ((IEnumerable<string>)Plugin.Names).Select((Func<string, ItemIndex>)ItemCatalog.FindItemIndex).ToArray();
			if (source.Any((ItemIndex i) => (int)i == -1))
			{
				return false;
			}
			pickups = ((IEnumerable<ItemIndex>)source).Select((Func<ItemIndex, PickupIndex>)PickupCatalog.FindPickupIndex).ToArray();
			if (pickups.Any((PickupIndex i) => i == PickupIndex.none))
			{
				pickups = null;
				return false;
			}
		}
		return true;
	}

	internal static int NextOffer(OutputDeck deck)
	{
		if (!Ready())
		{
			return deck.Next();
		}
		return deck.Next(rules);
	}

	internal static void ObserveOffer(int output)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		if (Ready())
		{
			Observe(pickups[output], "lectern offer");
		}
	}

	private static void Observe(PickupIndex pickup, string source)
	{
		//IL_0007: 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)
		if (Ready() && !(pickup != pickups[0]) && rules.Observe(0))
		{
			Plugin.Instance.LogBias("First Reincarnation appeared (" + source + "); normal page odds restored for the rest of this run.");
		}
	}

	private static List<int> Eligible(PickupDropTable table)
	{
		//IL_00be: 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_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: 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)
		WeightedSelection<UniquePickup> val = ((table is BasicPickupDropTable) ? basicSelector : ((table is ExplicitPickupDropTable) ? explicitSelector : null))?.GetValue(table) as WeightedSelection<UniquePickup>;
		List<int> list = new List<int>();
		if (val != null)
		{
			for (int i = 0; i < val.Count; i++)
			{
				ChoiceInfo<UniquePickup> choice = val.GetChoice(i);
				int num = Array.IndexOf(pickups, choice.value.pickupIndex);
				if (choice.weight > 0f && num >= 0 && !list.Contains(num) && run.IsPickupAvailable(choice.value.pickupIndex))
				{
					list.Add(num);
				}
			}
		}
		else
		{
			for (int j = 0; j < pickups.Length; j++)
			{
				if (run.availablePageTierDropList.Contains(pickups[j]) && run.IsPickupAvailable(pickups[j]))
				{
					list.Add(j);
				}
			}
		}
		return list;
	}

	private static UniquePickup Reweight(UniquePickup result, PickupDropTable table)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (generationDepth != 0 || !Ready() || rules.HasAppeared)
		{
			return result;
		}
		int num = Array.IndexOf(pickups, result.pickupIndex);
		if (num < 0)
		{
			return result;
		}
		return ((UniquePickup)(ref result)).WithPickupIndex(pickups[rules.Choose(num, Eligible(table))]);
	}

	private static void ReweightDistinct(List<UniquePickup> results, PickupDropTable table)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		if (generationDepth != 0 || !Ready() || rules.HasAppeared)
		{
			return;
		}
		int[] array = results.Select((UniquePickup p) => Array.IndexOf(pickups, p.pickupIndex)).ToArray();
		rules.ChooseDistinct(array, Eligible(table));
		for (int num = 0; num < array.Length; num++)
		{
			if (array[num] >= 0)
			{
				int index = num;
				UniquePickup val = results[num];
				results[index] = ((UniquePickup)(ref val)).WithPickupIndex(pickups[array[num]]);
			}
		}
	}

	private static UniquePickup Generate(orig_GeneratePickup orig, PickupDropTable self, Xoroshiro128Plus rng)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: 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)
		generationDepth++;
		UniquePickup result;
		try
		{
			result = orig.Invoke(self, rng);
		}
		finally
		{
			generationDepth--;
		}
		return Reweight(result, self);
	}

	private static void Distinct(orig_GenerateDistinctPickups orig, PickupDropTable self, List<UniquePickup> output, int count, Xoroshiro128Plus rng, bool allowLoop)
	{
		generationDepth++;
		try
		{
			orig.Invoke(self, output, count, rng, allowLoop);
		}
		finally
		{
			generationDepth--;
		}
		ReweightDistinct(output, self);
	}

	private static PickupIndex Legacy(orig_GenerateDrop orig, PickupDropTable self, Xoroshiro128Plus rng)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		generationDepth++;
		PickupIndex val;
		try
		{
			val = orig.Invoke(self, rng);
		}
		finally
		{
			generationDepth--;
		}
		return Reweight(new UniquePickup(val), self).pickupIndex;
	}

	private static PickupIndex[] LegacyDistinct(orig_GenerateUniqueDrops orig, PickupDropTable self, int count, Xoroshiro128Plus rng)
	{
		generationDepth++;
		PickupIndex[] source;
		try
		{
			source = orig.Invoke(self, count, rng);
		}
		finally
		{
			generationDepth--;
		}
		List<UniquePickup> list = ((IEnumerable<PickupIndex>)source).Select((Func<PickupIndex, UniquePickup>)((PickupIndex p) => new UniquePickup(p))).ToList();
		ReweightDistinct(list, self);
		return list.Select((UniquePickup p) => p.pickupIndex).ToArray();
	}

	private static void Droplet(orig_CreatePickupDroplet_CreatePickupInfo_Vector3_Vector3 orig, CreatePickupInfo info, Vector3 position, Vector3 velocity)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		orig.Invoke(info, position, velocity);
		Observe(((CreatePickupInfo)(ref info)).pickup.pickupIndex, "spawned droplet");
	}

	private static void Assigned(orig_OnPickupAssigned orig, GenericPickupController self)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		orig.Invoke(self);
		if (((Component)self).gameObject.activeInHierarchy)
		{
			Observe(self.pickup.pickupIndex, "world pickup/reroll");
		}
	}

	private static void Options(orig_SetOptionsServer orig, PickupPickerController self, Option[] options)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		orig.Invoke(self, options);
		if (!((Component)self).gameObject.activeInHierarchy || options == null)
		{
			return;
		}
		foreach (Option val in options)
		{
			if (val.available)
			{
				Observe(val.pickup.pickupIndex, "page choice");
			}
		}
	}

	private static void Shop(orig_SetPickup orig, ShopTerminalBehavior self, UniquePickup pickup, bool hidden)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		orig.Invoke(self, pickup, hidden);
		if (((Component)self).gameObject.activeInHierarchy && !hidden)
		{
			Observe(pickup.pickupIndex, "shop offer");
		}
	}

	private static void Given(Inventory inventory, ItemIndex item, int count)
	{
		//IL_0031: 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_0051: 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_0044: Unknown result type (might be due to invalid IL or missing references)
		if (count > 0 && Ready() && PlayerCharacterMasterController.instances.Any((PlayerCharacterMasterController p) => Object.op_Implicit((Object)(object)p.master) && (Object)(object)p.master.inventory == (Object)(object)inventory) && (item == ItemCatalog.FindItemIndex("PageDie") || item == ItemCatalog.FindItemIndex("PageDieConsumed")))
		{
			Observe(pickups[0], "inventory award");
		}
	}

	private static void EndRun(Run ended)
	{
		if ((Object)(object)run == (Object)(object)ended)
		{
			run = null;
			rules = null;
			pickups = null;
		}
	}

	internal static void Install()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		if (!installed)
		{
			installed = true;
			PickupDropTable.GeneratePickup += new hook_GeneratePickup(Generate);
			PickupDropTable.GenerateDistinctPickups += new hook_GenerateDistinctPickups(Distinct);
			PickupDropTable.GenerateDrop += new hook_GenerateDrop(Legacy);
			PickupDropTable.GenerateUniqueDrops += new hook_GenerateUniqueDrops(LegacyDistinct);
			PickupDropletController.CreatePickupDroplet_CreatePickupInfo_Vector3_Vector3 += new hook_CreatePickupDroplet_CreatePickupInfo_Vector3_Vector3(Droplet);
			GenericPickupController.OnPickupAssigned += new hook_OnPickupAssigned(Assigned);
			PickupPickerController.SetOptionsServer += new hook_SetOptionsServer(Options);
			ShopTerminalBehavior.SetPickup += new hook_SetPickup(Shop);
			Inventory.onServerItemGiven += Given;
			Run.onRunDestroyGlobal += EndRun;
		}
	}

	internal static void Uninstall()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Expected O, but got Unknown
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		if (installed)
		{
			installed = false;
			PickupDropTable.GeneratePickup -= new hook_GeneratePickup(Generate);
			PickupDropTable.GenerateDistinctPickups -= new hook_GenerateDistinctPickups(Distinct);
			PickupDropTable.GenerateDrop -= new hook_GenerateDrop(Legacy);
			PickupDropTable.GenerateUniqueDrops -= new hook_GenerateUniqueDrops(LegacyDistinct);
			PickupDropletController.CreatePickupDroplet_CreatePickupInfo_Vector3_Vector3 -= new hook_CreatePickupDroplet_CreatePickupInfo_Vector3_Vector3(Droplet);
			GenericPickupController.OnPickupAssigned -= new hook_OnPickupAssigned(Assigned);
			PickupPickerController.SetOptionsServer -= new hook_SetOptionsServer(Options);
			ShopTerminalBehavior.SetPickup -= new hook_SetPickup(Shop);
			Inventory.onServerItemGiven -= Given;
			Run.onRunDestroyGlobal -= EndRun;
			run = null;
			rules = null;
			pickups = null;
		}
	}
}
public struct SurfacePoint
{
	public float Y;

	public float NormalY;

	public SurfacePoint(float y, float normalY = 1f)
	{
		Y = y;
		NormalY = normalY;
	}
}
public interface IPlacementSurface
{
	SurfacePoint? Sample(float x, float z);

	bool IsClear(float x, float y, float z);
}
public struct PlacementResult
{
	public float X;

	public float Y;

	public float Z;

	public int Tried;

	public int NoGround;

	public int Steep;

	public int Unsupported;

	public int Uneven;

	public int Blocked;

	public override string ToString()
	{
		return $"tried={Tried} noGround={NoGround} steep={Steep} unsupported={Unsupported} uneven={Uneven} blocked={Blocked}";
	}
}
public static class PlacementRules
{
	public const float HalfFootprint = 0.44f;

	public static bool Find(IPlacementSurface surface, float x, float z, float yaw, out PlacementResult result)
	{
		result = default(PlacementResult);
		float num = (float)Math.Cos(yaw);
		float num2 = (float)Math.Sin(yaw);
		float[] array = new float[7] { 1.8f, 2.3f, 2.8f, 3.4f, 4f, 4.8f, 5.6f };
		foreach (float num3 in array)
		{
			for (int j = 0; j < 24; j++)
			{
				double num4 = (double)j * Math.PI / 12.0;
				float num5 = (float)Math.Cos(num4) * num3;
				float num6 = (float)Math.Sin(num4) * num3;
				float num7 = x + num * num5 + num2 * num6;
				float num8 = z - num2 * num5 + num * num6;
				result.Tried++;
				SurfacePoint? surfacePoint = surface.Sample(num7, num8);
				if (!surfacePoint.HasValue)
				{
					result.NoGround++;
					continue;
				}
				if (surfacePoint.Value.NormalY < 0.85f)
				{
					result.Steep++;
					continue;
				}
				float num9 = surfacePoint.Value.Y;
				float num10 = num9;
				bool flag = true;
				int[] array2 = new int[2] { -1, 1 };
				foreach (int num11 in array2)
				{
					int[] array3 = new int[2] { -1, 1 };
					foreach (int num12 in array3)
					{
						float num13 = 0.44f * (float)num11;
						float num14 = 0.44f * (float)num12;
						SurfacePoint? surfacePoint2 = surface.Sample(num7 + num * num13 + num2 * num14, num8 - num2 * num13 + num * num14);
						if (!surfacePoint2.HasValue || surfacePoint2.Value.NormalY < 0.85f)
						{
							flag = false;
							continue;
						}
						num9 = Math.Min(num9, surfacePoint2.Value.Y);
						num10 = Math.Max(num10, surfacePoint2.Value.Y);
					}
				}
				if (!flag)
				{
					result.Unsupported++;
					continue;
				}
				if (num10 - num9 > 0.22f)
				{
					result.Uneven++;
					continue;
				}
				float y = num10 + 0.015f;
				if (!surface.IsClear(num7, y, num8))
				{
					result.Blocked++;
					continue;
				}
				result.X = num7;
				result.Y = y;
				result.Z = num8;
				return true;
			}
		}
		return false;
	}
}
[BepInPlugin("com.rodanius.bindinglectern", "Binding Lectern", "0.1.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	internal static Plugin Instance;

	internal static readonly string[] Names = new string[7] { "PageDie", "PageWarpGate", "PageTeamInvisibility", "PageUpgradeItem", "PageClarity", "PageSummonFeralToddlers", "PagePurify" };

	internal static ItemIndex[] Pages;

	internal static ItemIndex[] Spent;

	internal static ItemIndex Scrap;

	internal static Random Rng;

	private GameObject prefab;

	private OutputDeck deck;

	private Run activeRun;

	private void Awake()
	{
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		PageBias.Install();
		if (Chainloader.PluginInfos.ContainsKey("com.KingEnderBrine.ProperSave"))
		{
			SaveBridge.Install();
			PageBias.SaveEnabled = true;
		}
		try
		{
			prefab = PrefabAPI.CreateEmptyPrefab("BindingLectern");
			prefab.AddComponent<Lectern>();
			prefab.AddComponent<EntityLocator>().entity = prefab;
			prefab.layer = LayerIndex.defaultLayer.intVal;
			BoxCollider obj = prefab.AddComponent<BoxCollider>();
			obj.center = new Vector3(0f, 0.85f, 0f);
			obj.size = new Vector3(0.88f, 1.7f, 0.86f);
			Model.Load(prefab.transform, Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "assets"));
			NetworkModCompatibilityHelper.networkModList = NetworkModCompatibilityHelper.networkModList.Concat(new string[1] { "com.rodanius.bindinglectern;0.1.3" }).ToArray();
			SceneManager.sceneLoaded += SceneLoaded;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Lectern initialization failed; no scene modifications made. " + ex));
		}
	}

	internal void LogBias(string text)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)text);
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= SceneLoaded;
		PageBias.Uninstall();
		if (PageBias.SaveEnabled)
		{
			SaveBridge.Uninstall();
			PageBias.SaveEnabled = false;
		}
	}

	private void SceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if (((Scene)(ref scene)).name == "bazaar")
		{
			((MonoBehaviour)this).StartCoroutine(Spawn(scene));
		}
	}

	private unsafe IEnumerator Spawn(Scene scene)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		if (!NetworkServer.active)
		{
			yield break;
		}
		TrialGongInteraction gong = null;
		for (int n = 0; n < 100; n++)
		{
			if (Object.op_Implicit((Object)(object)gong))
			{
				break;
			}
			if (!((Scene)(ref scene)).isLoaded || !NetworkServer.active)
			{
				yield break;
			}
			gong = (from g in Object.FindObjectsOfType<TrialGongInteraction>()
				where ((Component)g).gameObject.scene == scene
				orderby ((Component)g).transform.position.y
				select g).FirstOrDefault();
			if (!Object.op_Implicit((Object)(object)gong))
			{
				yield return (object)new WaitForSeconds(0.1f);
			}
		}
		if (!((Scene)(ref scene)).isLoaded || !Object.op_Implicit((Object)(object)gong) || !Object.op_Implicit((Object)(object)Run.instance) || !Object.op_Implicit((Object)(object)prefab))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"No Bazaar gong found; lectern not spawned.");
		}
		else
		{
			if (Object.FindObjectsOfType<Lectern>().Any((Lectern l) => ((Component)l).gameObject.scene == scene))
			{
				yield break;
			}
			Pages = ((IEnumerable<string>)Names).Select((Func<string, ItemIndex>)ItemCatalog.FindItemIndex).ToArray();
			Spent = Names.Select((string text) => ItemCatalog.FindItemIndex(text + "Consumed")).ToArray();
			Scrap = ItemCatalog.FindItemIndex("PageShredded");
			if (Pages.Any((ItemIndex p) => (int)p == -1) || Spent.Any((ItemIndex p) => (int)p == -1) || (int)Scrap == -1)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Missing Hallowed Concepts page catalog; no lectern spawned.");
				yield break;
			}
			if ((Object)(object)activeRun != (Object)(object)Run.instance)
			{
				activeRun = Run.instance;
				deck = new OutputDeck(Names.Length, (int)activeRun.seed ^ 0x4C454354);
				Rng = new Random((int)(activeRun.seed >> 32) ^ 0x50414745);
			}
			yield return (object)new WaitForFixedUpdate();
			Vector3 position = Vector3.zero;
			bool found = false;
			string diagnostics = "";
			for (int n = 0; n < 4; n++)
			{
				if (found)
				{
					break;
				}
				if (!((Scene)(ref scene)).isLoaded || !NetworkServer.active || !Object.op_Implicit((Object)(object)gong))
				{
					yield break;
				}
				Physics.SyncTransforms();
				found = LecternPlacement.TryFind(gong, scene, out position, out diagnostics);
				if (!found)
				{
					yield return (object)new WaitForSecondsRealtime(0.5f);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Lectern placement: gong=" + ((object)((Component)gong).transform.position/*cast due to .constrained prefix*/).ToString() + " " + diagnostics));
			if (!found)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("No supported clear lectern position near gong after expanded search; " + diagnostics));
				yield break;
			}
			int num = PageBias.NextOffer(deck);
			GameObject obj = Object.Instantiate<GameObject>(prefab, position, Quaternion.Euler(0f, ((Component)gong).transform.eulerAngles.y, 0f));
			obj.GetComponent<Lectern>().Output = num;
			SceneManager.MoveGameObjectToScene(obj, scene);
			obj.SetActive(true);
			NetworkServer.Spawn(obj);
			PageBias.ObserveOffer(num);
			ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
			Vector3 val = position;
			logger.LogInfo((object)("Spawned Binding Lectern near existing gong at " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + " output=" + Names[num]));
		}
	}
}
public class Lectern : NetworkBehaviour, IInteractable
{
	public int Output = -1;

	private float nextTrade;

	private Collider interactionCollider;

	private string OutputName
	{
		get
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (Output < 0 || Output >= Plugin.Names.Length)
			{
				return "page";
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(ItemCatalog.FindItemIndex(Plugin.Names[Output]));
			if (!Object.op_Implicit((Object)(object)itemDef))
			{
				return "page";
			}
			return Language.GetString(itemDef.nameToken);
		}
	}

	private void Awake()
	{
		interactionCollider = ((Component)this).GetComponent<Collider>();
	}

	private void Start()
	{
		((Component)this).gameObject.AddComponent<OfferVisual>();
	}

	public override bool OnSerialize(NetworkWriter writer, bool initialState)
	{
		writer.Write(Output);
		return true;
	}

	public override void OnDeserialize(NetworkReader reader, bool initialState)
	{
		Output = reader.ReadInt32();
	}

	public string GetContextString(Interactor activator)
	{
		return "Bind 2 pages into " + OutputName + " (Shredded Pages first)";
	}

	private static Inventory InventoryOf(Interactor actor)
	{
		CharacterBody val = (Object.op_Implicit((Object)(object)actor) ? ((Component)actor).GetComponent<CharacterBody>() : null);
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.healthComponent) || !val.healthComponent.alive)
		{
			return null;
		}
		return val.inventory;
	}

	private static ItemIndex[] Inputs()
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Expected I4, but got Unknown
		return ((IEnumerable<string>)Plugin.Names).Select((Func<string, ItemIndex>)ItemCatalog.FindItemIndex).Concat(Plugin.Names.Select((string n) => ItemCatalog.FindItemIndex(n + "Consumed"))).Concat((IEnumerable<ItemIndex>)(object)new ItemIndex[1] { (ItemIndex)(int)ItemCatalog.FindItemIndex("PageShredded") })
			.ToArray();
	}

	public Interactability GetInteractability(Interactor actor)
	{
		Inventory inv = InventoryOf(actor);
		if (Output >= 0 && Output < Plugin.Names.Length && Object.op_Implicit((Object)(object)inv) && (from i in Inputs()
			where (int)i != -1
			select i).Sum((ItemIndex i) => inv.GetItemCountPermanent(i)) >= 2)
		{
			return (Interactability)2;
		}
		return (Interactability)1;
	}

	public void OnInteractionBegin(Interactor actor)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Invalid comparison between Unknown and I4
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0114: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Expected O, but got Unknown
		if (!NetworkServer.active || Output < 0 || Time.fixedTime < nextTrade || (int)GetInteractability(actor) != 2 || !Object.op_Implicit((Object)(object)interactionCollider))
		{
			return;
		}
		Vector3 val = ((Component)actor).transform.position - interactionCollider.ClosestPoint(((Component)actor).transform.position);
		if (((Vector3)(ref val)).sqrMagnitude > Mathf.Pow(actor.maxInteractionDistance + 1f, 2f))
		{
			return;
		}
		Inventory val2 = InventoryOf(actor);
		ItemIndex[] array = Inputs();
		int[] array2 = TradeRules.Select(((IEnumerable<ItemIndex>)array).Select((Func<ItemIndex, int>)val2.GetItemCountPermanent).ToArray(), array.Length - 1, Plugin.Rng);
		if (array2 != null)
		{
			nextTrade = Time.fixedTime + 0.75f;
			bool flag = array2.Any((int i) => i >= 7 && i < 14) || val2.GetItemCountPermanent(Plugin.Spent[Output]) > 0;
			if (Output == 0 && val2.GetItemCountPermanent(ItemCatalog.FindItemIndex("PageDieCooldown")) > 0)
			{
				flag = true;
			}
			int[] array3 = array2;
			foreach (int num2 in array3)
			{
				val2.RemoveItemPermanent(array[num2], 1);
			}
			val2.GiveItemPermanent(flag ? Plugin.Spent[Output] : Plugin.Pages[Output], 1);
			Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
			{
				baseToken = "Bound two pages into " + OutputName + (flag ? " (spent until its normal recharge)." : ".")
			});
		}
	}

	public bool ShouldIgnoreSpherecastForInteractibility(Interactor a)
	{
		return false;
	}

	public bool ShouldShowOnScanner()
	{
		return true;
	}

	public bool ShouldProximityHighlight()
	{
		return true;
	}

	public int GetInteractablePriority(Interactor a)
	{
		return 0;
	}

	public bool ShouldSpawnLesserInteractionRewards(Interactor a)
	{
		return false;
	}
}
public sealed class ReincarnationRules
{
	private readonly Random rng;

	public bool HasAppeared { get; private set; }

	public ReincarnationRules(int seed)
	{
		rng = new Random(seed);
	}

	public bool Observe(int page)
	{
		if (page != 0 || HasAppeared)
		{
			return false;
		}
		HasAppeared = true;
		return true;
	}

	public int Choose(int original, IList<int> eligible)
	{
		if (HasAppeared || original < 0 || !eligible.Contains(original) || !eligible.Contains(0) || eligible.Count < 2)
		{
			return original;
		}
		if (rng.NextDouble() < 0.5)
		{
			return 0;
		}
		int[] array = eligible.Where((int i) => i != 0).Distinct().ToArray();
		return array[rng.Next(array.Length)];
	}

	public void ChooseDistinct(int[] outputs, IList<int> eligible)
	{
		if (HasAppeared || !eligible.Contains(0) || eligible.Count < 2)
		{
			return;
		}
		List<int> list = eligible.Distinct().ToList();
		List<int> list2 = new List<int>(list);
		for (int i = 0; i < outputs.Length; i++)
		{
			if (list.Contains(outputs[i]))
			{
				if (list2.Count == 0)
				{
					list2.AddRange(list);
				}
				int original = (list2.Contains(outputs[i]) ? outputs[i] : list2[rng.Next(list2.Count)]);
				outputs[i] = Choose(original, list2);
				list2.Remove(outputs[i]);
			}
		}
	}
}
internal static class SaveBridge
{
	private const string Key = "com.rodanius.bindinglectern.reincarnationSeen.v1";

	private static SaveFile cached;

	private static bool seen;

	[MethodImpl(MethodImplOptions.NoInlining)]
	internal static void Install()
	{
		SaveFile.OnGatherSaveData += Gather;
		Loading.OnLoadingEnded += Loaded;
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	internal static void Uninstall()
	{
		SaveFile.OnGatherSaveData -= Gather;
		Loading.OnLoadingEnded -= Loaded;
		cached = null;
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	internal static bool SeenWhileLoading()
	{
		if (!Loading.IsLoading)
		{
			return false;
		}
		return Read(Loading.CurrentSave);
	}

	private static bool Read(SaveFile file)
	{
		if (file == null)
		{
			return false;
		}
		if (file != cached)
		{
			cached = file;
			seen = file.TryGetModdedData<string>("com.rodanius.bindinglectern.reincarnationSeen.v1") == "seen";
		}
		return seen;
	}

	private static void Gather(Dictionary<string, object> data)
	{
		data["com.rodanius.bindinglectern.reincarnationSeen.v1"] = (PageBias.HasAppeared ? "seen" : "armed");
	}

	private static void Loaded(SaveFile file)
	{
		if (Read(file))
		{
			PageBias.RestoreSeen();
		}
		cached = null;
	}
}
public sealed class OutputDeck
{
	private readonly int count;

	private readonly Random rng;

	private readonly List<int> bag = new List<int>();

	public OutputDeck(int count, int seed)
	{
		if (count < 1)
		{
			throw new ArgumentOutOfRangeException("count");
		}
		this.count = count;
		rng = new Random(seed);
	}

	public int Next(ReincarnationRules bias = null)
	{
		if (bag.Count == 0)
		{
			for (int i = 0; i < count; i++)
			{
				bag.Add(i);
			}
			TradeRules.Shuffle(bag, rng);
		}
		int index = bag.Count - 1;
		int num = bias?.Choose(bag[index], bag) ?? bag[index];
		bag.Remove(num);
		return num;
	}
}
public static class TradeRules
{
	public static int[] Select(int[] counts, int scrap, Random rng)
	{
		int[] array = (int[])counts.Clone();
		int[] array2 = new int[2];
		for (int i = 0; i < 2; i++)
		{
			if (array[scrap] > 0)
			{
				array2[i] = scrap;
				array[scrap]--;
				continue;
			}
			int num = 0;
			for (int j = 0; j < array.Length; j++)
			{
				if (j != scrap)
				{
					num += array[j];
				}
			}
			if (num == 0)
			{
				return null;
			}
			int num2 = rng.Next(num);
			for (int k = 0; k < array.Length; k++)
			{
				if (k != scrap)
				{
					num2 -= array[k];
					if (num2 < 0)
					{
						array2[i] = k;
						array[k]--;
						break;
					}
				}
			}
		}
		return array2;
	}

	public static void Shuffle(List<int> bag, Random rng)
	{
		for (int num = bag.Count - 1; num > 0; num--)
		{
			int index = rng.Next(num + 1);
			int value = bag[num];
			bag[num] = bag[index];
			bag[index] = value;
		}
	}
}