Decompiled source of GambitPopQuiz v1.0.3

MathTeacherPlugin.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("FJX")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MathTeacherPlugin")]
[assembly: AssemblyTitle("MathTeacherPlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 MathTeacherPlugin
{
	public enum MathTeacherAnswerChoice
	{
		Left,
		Right
	}
	internal static class MathTeacherGameplayEffects
	{
		public static void ApplyToLocalPlayer(MathTeacherQuizResult result)
		{
			PlayerAvatar instance = PlayerAvatar.instance;
			if ((Object)(object)instance == (Object)null)
			{
				MathTeacherPlugin.Logger.LogWarning((object)"MathTeacher could not apply quiz result because local player was not found.");
			}
			else
			{
				Apply(result, instance);
			}
		}

		public static void Apply(MathTeacherQuizResult result, PlayerAvatar player)
		{
			switch (result.Outcome)
			{
			case MathTeacherQuizOutcome.Correct:
				SpawnReward(player, result.RewardValue);
				break;
			case MathTeacherQuizOutcome.Wrong:
			case MathTeacherQuizOutcome.Timeout:
				HurtPlayer(player, result.Damage);
				break;
			}
		}

		private static void HurtPlayer(PlayerAvatar player, int damage)
		{
			if (damage > 0)
			{
				player.playerHealth.Hurt(damage, false, -1, false);
				MathTeacherPlugin.Logger.LogInfo((object)$"MathTeacher dealt {damage} damage to {((Object)player).name}.");
			}
		}

		private static void SpawnReward(PlayerAvatar player, int rewardValue)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (rewardValue <= 0)
			{
				return;
			}
			if ((Object)(object)AssetManager.instance == (Object)null || (Object)(object)AssetManager.instance.surplusValuableSmall == (Object)null)
			{
				MathTeacherPlugin.Logger.LogWarning((object)"MathTeacher could not spawn reward because surplusValuableSmall was not available.");
				return;
			}
			if (SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient)
			{
				MathTeacherPlugin.Logger.LogWarning((object)"MathTeacher reward spawn skipped because this client is not the multiplayer master client.");
				return;
			}
			GameObject surplusValuableSmall = AssetManager.instance.surplusValuableSmall;
			Vector3 val = ((Component)player).transform.position + ((Component)player).transform.forward * 1.4f + Vector3.up * 0.6f;
			GameObject val2 = (SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject("Valuables/" + ((Object)surplusValuableSmall).name, val, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(surplusValuableSmall, val, Quaternion.identity));
			ValuableObject component = val2.GetComponent<ValuableObject>();
			if ((Object)(object)component != (Object)null)
			{
				component.dollarValueOverride = rewardValue;
			}
			MathTeacherPlugin.Logger.LogInfo((object)$"MathTeacher spawned reward valuable worth {rewardValue}.");
		}
	}
	[BepInPlugin("FJX.MathTeacherPlugin", "MathTeacherPlugin", "1.0")]
	public class MathTeacherPlugin : BaseUnityPlugin
	{
		internal static MathTeacherPlugin Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void OnDestroy()
		{
			MathTeacherSpinnyQuizController.DestroyActiveHud();
			Unpatch();
		}
	}
	public readonly struct MathTeacherQuestion
	{
		public string Prompt { get; }

		public int LeftAnswer { get; }

		public int RightAnswer { get; }

		public MathTeacherAnswerChoice CorrectChoice { get; }

		public int CorrectAnswer => (CorrectChoice == MathTeacherAnswerChoice.Left) ? LeftAnswer : RightAnswer;

		public MathTeacherQuestion(string prompt, int leftAnswer, int rightAnswer, MathTeacherAnswerChoice correctChoice)
		{
			Prompt = prompt;
			LeftAnswer = leftAnswer;
			RightAnswer = rightAnswer;
			CorrectChoice = correctChoice;
		}

		public bool IsCorrect(MathTeacherAnswerChoice choice)
		{
			return choice == CorrectChoice;
		}
	}
	public static class MathTeacherQuizHudLayout
	{
		public const float PromptX = 0f;

		public const float PromptY = 92f;

		public const float LeftChoiceX = -115f;

		public const float RightChoiceX = 115f;

		public const float ChoiceY = 32f;

		public const float ResultX = 0f;

		public const float ResultY = -24f;
	}
	public readonly struct MathTeacherQuizHudText
	{
		private const string AccentColor = "F2D56B";

		private const string CorrectColor = "78F28B";

		private const string WrongColor = "FF6B6B";

		public string Title { get; }

		public string Prompt { get; }

		public string LeftChoice { get; }

		public string RightChoice { get; }

		public string Result { get; }

		private MathTeacherQuizHudText(string title, string prompt, string leftChoice, string rightChoice, string result)
		{
			Title = title;
			Prompt = prompt;
			LeftChoice = leftChoice;
			RightChoice = rightChoice;
			Result = result;
		}

		public static MathTeacherQuizHudText Build(MathTeacherQuestion question, MathTeacherAnswerChoice? selectedChoice)
		{
			string result = string.Empty;
			if (selectedChoice.HasValue)
			{
				result = (question.IsCorrect(selectedChoice.Value) ? string.Format("<color=#{0}>CORRECT +{1}</color>", "78F28B", 10000) : string.Format("<color=#{0}>WRONG -{1} HP</color>", "FF6B6B", 50));
			}
			return new MathTeacherQuizHudText(string.Empty, question.Prompt, FormatChoice("A", question.LeftAnswer), FormatChoice("D", question.RightAnswer), result);
		}

		public static MathTeacherQuizHudText Build(MathTeacherQuizSession session)
		{
			string result = (session.Result.HasValue ? FormatResult(session.Result.Value) : $"TIME {session.RemainingSeconds:0.0}");
			return new MathTeacherQuizHudText(string.Empty, session.Question.Prompt, FormatChoice("A", session.Question.LeftAnswer), FormatChoice("D", session.Question.RightAnswer), result);
		}

		private static string FormatResult(MathTeacherQuizResult result)
		{
			MathTeacherQuizOutcome outcome = result.Outcome;
			if (1 == 0)
			{
			}
			string result2 = outcome switch
			{
				MathTeacherQuizOutcome.Correct => string.Format("<color=#{0}>CORRECT +{1}</color>", "78F28B", result.RewardValue), 
				MathTeacherQuizOutcome.Timeout => string.Format("<color=#{0}>TIME UP -{1} HP</color>", "FF6B6B", result.Damage), 
				_ => string.Format("<color=#{0}>WRONG -{1} HP</color>", "FF6B6B", result.Damage), 
			};
			if (1 == 0)
			{
			}
			return result2;
		}

		private static string FormatChoice(string key, int answer)
		{
			return string.Format("<color=#{0}>[{1}]</color> {2}", "F2D56B", key, answer);
		}
	}
	internal sealed class MathTeacherQuizHudView
	{
		private static readonly Color TitleColor = new Color(0.79f, 0.91f, 0.9f, 1f);

		private static readonly Color PromptColor = Color.white;

		private static readonly Color ChoiceColor = new Color(1f, 0.86f, 0.42f, 1f);

		private GameObject? root;

		private TextMeshProUGUI? promptText;

		private TextMeshProUGUI? leftChoiceText;

		private TextMeshProUGUI? rightChoiceText;

		private TextMeshProUGUI? resultText;

		public bool IsAlive => (Object)(object)root != (Object)null;

		public static bool TryCreate(out MathTeacherQuizHudView view)
		{
			view = new MathTeacherQuizHudView();
			return view.Create();
		}

		public void Render(MathTeacherQuizHudText text)
		{
			if (!((Object)(object)root == (Object)null))
			{
				((TMP_Text)promptText).text = text.Prompt;
				((TMP_Text)leftChoiceText).text = text.LeftChoice;
				((TMP_Text)rightChoiceText).text = text.RightChoice;
				((TMP_Text)resultText).text = text.Result;
				((Component)resultText).gameObject.SetActive(!string.IsNullOrEmpty(text.Result));
			}
		}

		public void Destroy()
		{
			if ((Object)(object)root != (Object)null)
			{
				Object.Destroy((Object)(object)root);
				root = null;
			}
		}

		private bool Create()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00a3: 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)
			//IL_00c5: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindHudParent();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			TMP_FontAsset val2 = FindHudFont();
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			root = new GameObject("MathTeacher Quiz HUD", new Type[1] { typeof(RectTransform) });
			root.SetActive(true);
			root.transform.SetParent(val, false);
			root.layer = ((Component)val).gameObject.layer;
			RectTransform val3 = (RectTransform)root.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.pivot = new Vector2(0.5f, 0.5f);
			val3.offsetMin = Vector2.zero;
			val3.offsetMax = Vector2.zero;
			((Transform)val3).localScale = Vector3.one;
			promptText = CreateCenteredText("Prompt", val2, root.transform, new Vector2(0f, 92f), new Vector2(620f, 52f), PromptColor, 34f);
			leftChoiceText = CreateCenteredText("Left Choice", val2, root.transform, new Vector2(-115f, 32f), new Vector2(230f, 42f), ChoiceColor, 26f);
			rightChoiceText = CreateCenteredText("Right Choice", val2, root.transform, new Vector2(115f, 32f), new Vector2(230f, 42f), ChoiceColor, 26f);
			resultText = CreateCenteredText("Result", val2, root.transform, new Vector2(0f, -24f), new Vector2(520f, 42f), PromptColor, 24f);
			return true;
		}

		private static Transform? FindHudParent()
		{
			GameObject val = GameObject.Find("Game Hud");
			return ((Object)(object)val != (Object)null) ? val.transform : null;
		}

		private static TMP_FontAsset? FindHudFont()
		{
			GameObject val = GameObject.Find("Tax Haul");
			if ((Object)(object)val != (Object)null)
			{
				TMP_Text component = val.GetComponent<TMP_Text>();
				if ((Object)(object)((component != null) ? component.font : null) != (Object)null)
				{
					return component.font;
				}
			}
			HealthUI instance = HealthUI.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				TextMeshProUGUI uiText = ((SemiUI)instance).uiText;
				obj = ((uiText != null) ? ((TMP_Text)uiText).font : null);
			}
			if ((Object)obj != (Object)null)
			{
				return ((TMP_Text)((SemiUI)HealthUI.instance).uiText).font;
			}
			TextMeshProUGUI obj2 = Object.FindObjectOfType<TextMeshProUGUI>();
			return (obj2 != null) ? ((TMP_Text)obj2).font : null;
		}

		private static TextMeshProUGUI CreateCenteredText(string name, TMP_FontAsset font, Transform parent, Vector2 position, Vector2 size, Color color, float fontSize)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0052: 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_007e: 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_0092: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			val.layer = ((Component)parent).gameObject.layer;
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = new Vector2(0.5f, 0.5f);
			val2.anchorMax = new Vector2(0.5f, 0.5f);
			val2.pivot = new Vector2(0.5f, 0.5f);
			val2.anchoredPosition = position;
			val2.sizeDelta = size;
			((Transform)val2).localScale = Vector3.one;
			TextMeshProUGUI val3 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val3).font = font;
			((Graphic)val3).color = color;
			((TMP_Text)val3).fontSize = fontSize;
			((TMP_Text)val3).enableAutoSizing = true;
			((TMP_Text)val3).fontSizeMin = 12f;
			((TMP_Text)val3).fontSizeMax = fontSize;
			((TMP_Text)val3).enableWordWrapping = false;
			((TMP_Text)val3).overflowMode = (TextOverflowModes)1;
			((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
			((Graphic)val3).raycastTarget = false;
			((TMP_Text)val3).richText = true;
			return val3;
		}
	}
	public enum MathTeacherQuizOutcome
	{
		Correct,
		Wrong,
		Timeout
	}
	public readonly struct MathTeacherQuizResult
	{
		public const int CorrectRewardValue = 10000;

		public const int WrongDamage = 50;

		public MathTeacherQuizOutcome Outcome { get; }

		public int RewardValue { get; }

		public int Damage { get; }

		private MathTeacherQuizResult(MathTeacherQuizOutcome outcome, int rewardValue, int damage)
		{
			Outcome = outcome;
			RewardValue = rewardValue;
			Damage = damage;
		}

		public static MathTeacherQuizResult FromAnswer(MathTeacherQuestion question, MathTeacherAnswerChoice answer)
		{
			return question.IsCorrect(answer) ? new MathTeacherQuizResult(MathTeacherQuizOutcome.Correct, 10000, 0) : new MathTeacherQuizResult(MathTeacherQuizOutcome.Wrong, 0, 50);
		}

		public static MathTeacherQuizResult Timeout()
		{
			return new MathTeacherQuizResult(MathTeacherQuizOutcome.Timeout, 0, 50);
		}
	}
	public sealed class MathTeacherQuizService
	{
		private readonly struct Problem
		{
			public int LeftOperand { get; }

			public string OperatorSymbol { get; }

			public int RightOperand { get; }

			public int CorrectAnswer { get; }

			public Problem(int leftOperand, string operatorSymbol, int rightOperand, int correctAnswer)
			{
				LeftOperand = leftOperand;
				OperatorSymbol = operatorSymbol;
				RightOperand = rightOperand;
				CorrectAnswer = correctAnswer;
			}
		}

		private readonly Random random;

		public MathTeacherQuizService(Random? random = null)
		{
			this.random = random ?? new Random();
		}

		public MathTeacherQuestion CreateQuestion()
		{
			Problem problem = CreateProblem();
			int num = CreateWrongAnswer(problem.CorrectAnswer);
			MathTeacherAnswerChoice mathTeacherAnswerChoice = ((random.Next(0, 2) != 0) ? MathTeacherAnswerChoice.Right : MathTeacherAnswerChoice.Left);
			int leftAnswer = ((mathTeacherAnswerChoice == MathTeacherAnswerChoice.Left) ? problem.CorrectAnswer : num);
			int rightAnswer = ((mathTeacherAnswerChoice == MathTeacherAnswerChoice.Right) ? problem.CorrectAnswer : num);
			return new MathTeacherQuestion($"{problem.LeftOperand} {problem.OperatorSymbol} {problem.RightOperand} = ?", leftAnswer, rightAnswer, mathTeacherAnswerChoice);
		}

		private Problem CreateProblem()
		{
			int num = random.Next(0, 3);
			if (1 == 0)
			{
			}
			Problem result = num switch
			{
				0 => CreateAdditionProblem(), 
				1 => CreateSubtractionProblem(), 
				_ => CreateMultiplicationProblem(), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		private Problem CreateAdditionProblem()
		{
			int num = random.Next(2, 31);
			int num2 = random.Next(2, 31);
			return new Problem(num, "+", num2, num + num2);
		}

		private Problem CreateSubtractionProblem()
		{
			int num = random.Next(8, 51);
			int num2 = random.Next(2, num);
			return new Problem(num, "-", num2, num - num2);
		}

		private Problem CreateMultiplicationProblem()
		{
			int num = random.Next(2, 13);
			int num2 = random.Next(2, 13);
			return new Problem(num, "x", num2, num * num2);
		}

		private int CreateWrongAnswer(int correctAnswer)
		{
			int num = random.Next(1, 7);
			if (random.Next(0, 2) == 0)
			{
				num = -num;
			}
			int num2 = correctAnswer + num;
			if (num2 < 0)
			{
				num2 = correctAnswer + Math.Abs(num) + 1;
			}
			if (num2 == correctAnswer)
			{
				num2++;
			}
			return num2;
		}
	}
	public sealed class MathTeacherQuizSession
	{
		public MathTeacherQuestion Question { get; }

		public float TimeLimitSeconds { get; }

		public float RemainingSeconds { get; private set; }

		public MathTeacherAnswerChoice? SelectedChoice { get; private set; }

		public MathTeacherQuizResult? Result { get; private set; }

		public bool IsFinished => Result.HasValue;

		public MathTeacherQuizSession(MathTeacherQuestion question, float timeLimitSeconds)
		{
			Question = question;
			TimeLimitSeconds = Math.Max(0.1f, timeLimitSeconds);
			RemainingSeconds = TimeLimitSeconds;
		}

		public void Tick(float deltaSeconds)
		{
			if (!IsFinished)
			{
				RemainingSeconds = Math.Max(0f, RemainingSeconds - Math.Max(0f, deltaSeconds));
				if (RemainingSeconds <= 0f)
				{
					Result = MathTeacherQuizResult.Timeout();
				}
			}
		}

		public void Choose(MathTeacherAnswerChoice choice)
		{
			if (!IsFinished)
			{
				SelectedChoice = choice;
				Result = MathTeacherQuizResult.FromAnswer(Question, choice);
			}
		}
	}
	internal sealed class MathTeacherResolvedInteractions
	{
		private readonly HashSet<int> resolvedIds = new HashSet<int>();

		public bool Contains(int id)
		{
			return resolvedIds.Contains(id);
		}

		public void MarkResolved(int id)
		{
			resolvedIds.Add(id);
		}

		public void Clear(int id)
		{
			resolvedIds.Remove(id);
		}

		public void ClearAll()
		{
			resolvedIds.Clear();
		}
	}
	[HarmonyPatch(typeof(EnemySpinnyAnim), "Update")]
	internal static class MathTeacherSpinnyAnimPatch
	{
		[HarmonyPostfix]
		private static void Postfix(EnemySpinnyAnim __instance)
		{
			if ((Object)(object)__instance.enemySpinny != (Object)null)
			{
				MathTeacherSpinnyQuizController.SuppressWheelGlow(__instance.enemySpinny);
			}
		}
	}
	[HarmonyPatch(typeof(EnemySpinny), "GetCurrentColorColor")]
	internal static class MathTeacherSpinnyColorPatch
	{
		[HarmonyPostfix]
		private static void Postfix(EnemySpinny __instance, ref Color __result)
		{
			//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 (MathTeacherSpinnyQuizController.ShouldHandle(__instance))
			{
				__result = MathTeacherSpinnyQuizController.WheelHighlightColor;
			}
		}
	}
	[HarmonyPatch(typeof(EnemySpinny), "Update")]
	internal static class MathTeacherSpinnyPatch
	{
		[HarmonyPrefix]
		private static void Prefix(EnemySpinny __instance)
		{
			MathTeacherSpinnyQuizController.BeforeSpinnyUpdate(__instance);
		}

		[HarmonyPostfix]
		private static void Postfix(EnemySpinny __instance)
		{
			MathTeacherSpinnyQuizController.AfterSpinnyUpdate(__instance);
		}
	}
	internal static class MathTeacherSpinnyQuizController
	{
		private const string MathTeacherEnemyName = "MathTeacher";

		private const float TimeLimitSeconds = 8f;

		private const float HoldRouletteStateSeconds = 0.25f;

		private static readonly MathTeacherQuizService QuizService = new MathTeacherQuizService();

		private static readonly Dictionary<int, MathTeacherQuizSession> Sessions = new Dictionary<int, MathTeacherQuizSession>();

		private static readonly MathTeacherResolvedInteractions ResolvedInteractions = new MathTeacherResolvedInteractions();

		private static readonly FieldInfo? StateTimerField = AccessTools.Field(typeof(EnemySpinny), "stateTimer");

		private static readonly MethodInfo? UpdateStateMethod = AccessTools.Method(typeof(EnemySpinny), "UpdateState", (Type[])null, (Type[])null);

		internal static readonly Color WheelHighlightColor = new Color(0f, 0f, 0f, 1f);

		private static MathTeacherQuizHudView? hudView;

		public static void BeforeSpinnyUpdate(EnemySpinny spinny)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (ShouldHandle(spinny) && (int)spinny.currentState == 8 && IsLocalTarget(spinny) && !IsResolved(spinny))
			{
				MathTeacherQuizSession orCreateSession = GetOrCreateSession(spinny);
				if (!orCreateSession.IsFinished)
				{
					HoldRouletteState(spinny);
				}
			}
		}

		public static void AfterSpinnyUpdate(EnemySpinny spinny)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			if (!ShouldHandle(spinny))
			{
				CleanupInteraction(spinny);
				return;
			}
			SuppressWheelGlow(spinny);
			if (IsResolved(spinny))
			{
				CleanupResolvedInteractionIfRouletteEnded(spinny);
				return;
			}
			if ((int)spinny.currentState != 8 || !IsLocalTarget(spinny))
			{
				CleanupIfInteractionEnded(spinny);
				return;
			}
			MathTeacherQuizSession orCreateSession = GetOrCreateSession(spinny);
			if (!orCreateSession.IsFinished)
			{
				orCreateSession.Tick(Time.deltaTime);
				HandleAnswerInput(orCreateSession);
			}
			Render(orCreateSession);
			if (orCreateSession.Result.HasValue)
			{
				MathTeacherGameplayEffects.Apply(orCreateSession.Result.Value, spinny.playerTarget);
				ResolvedInteractions.MarkResolved(((Object)spinny).GetInstanceID());
				ForceCloseMouth(spinny);
				CleanupSession(spinny);
			}
		}

		public static void DestroyActiveHud()
		{
			hudView?.Destroy();
			hudView = null;
			Sessions.Clear();
			ResolvedInteractions.ClearAll();
		}

		internal static bool ShouldHandle(EnemySpinny spinny)
		{
			Enemy component = ((Component)spinny).GetComponent<Enemy>();
			return (Object)(object)component?.EnemyParent != (Object)null && component.EnemyParent.enemyName == "MathTeacher";
		}

		internal static void SuppressWheelGlow(EnemySpinny spinny)
		{
			//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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!ShouldHandle(spinny))
			{
				return;
			}
			if (spinny.colors != null)
			{
				for (int i = 0; i < spinny.colors.Length; i++)
				{
					spinny.colors[i] = WheelHighlightColor;
				}
			}
			if (spinny.pieces != null)
			{
				Transform[] pieces = spinny.pieces;
				foreach (Transform val in pieces)
				{
					MeshRenderer val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<MeshRenderer>() : null);
					Material val3 = (((Object)(object)val2 != (Object)null) ? ((Renderer)val2).material : null);
					if (!((Object)(object)val3 == (Object)null))
					{
						val3.DisableKeyword("_EMISSION");
						if (val3.HasProperty("_EmissionColor"))
						{
							val3.SetColor("_EmissionColor", WheelHighlightColor);
						}
					}
				}
			}
			if (MathTeacherWheelVisualPolicy.DisablePointLight)
			{
				Light val4 = (((Object)(object)spinny.enemySpinnyAnim != (Object)null) ? spinny.enemySpinnyAnim.pointLight : null);
				if (!((Object)(object)val4 == (Object)null))
				{
					val4.color = WheelHighlightColor;
					val4.intensity = 0f;
					val4.range = 0f;
					((Behaviour)val4).enabled = false;
				}
			}
		}

		private static bool IsLocalTarget(EnemySpinny spinny)
		{
			return (Object)(object)spinny.playerTarget != (Object)null && spinny.playerTarget.isLocal;
		}

		private static bool IsResolved(EnemySpinny spinny)
		{
			return ResolvedInteractions.Contains(((Object)spinny).GetInstanceID());
		}

		private static MathTeacherQuizSession GetOrCreateSession(EnemySpinny spinny)
		{
			int instanceID = ((Object)spinny).GetInstanceID();
			if (Sessions.TryGetValue(instanceID, out MathTeacherQuizSession value))
			{
				return value;
			}
			value = new MathTeacherQuizSession(QuizService.CreateQuestion(), 8f);
			Sessions[instanceID] = value;
			MathTeacherPlugin.Logger.LogInfo((object)$"MathTeacher question started: {value.Question.Prompt} A={value.Question.LeftAnswer} D={value.Question.RightAnswer}");
			return value;
		}

		private static void HandleAnswerInput(MathTeacherQuizSession session)
		{
			if (Input.GetKeyDown((KeyCode)97))
			{
				session.Choose(MathTeacherAnswerChoice.Left);
			}
			else if (Input.GetKeyDown((KeyCode)100))
			{
				session.Choose(MathTeacherAnswerChoice.Right);
			}
		}

		private static void Render(MathTeacherQuizSession session)
		{
			if (EnsureHud())
			{
				hudView?.Render(MathTeacherQuizHudText.Build(session));
			}
		}

		private static bool EnsureHud()
		{
			MathTeacherQuizHudView mathTeacherQuizHudView = hudView;
			if (mathTeacherQuizHudView != null && mathTeacherQuizHudView.IsAlive)
			{
				return true;
			}
			hudView?.Destroy();
			hudView = null;
			if (!MathTeacherQuizHudView.TryCreate(out MathTeacherQuizHudView view))
			{
				return false;
			}
			hudView = view;
			return true;
		}

		private static void ForceCloseMouth(EnemySpinny spinny)
		{
			if (UpdateStateMethod == null)
			{
				MathTeacherPlugin.Logger.LogWarning((object)"MathTeacher could not force Spinny close-mouth state because UpdateState was not found.");
				return;
			}
			UpdateStateMethod.Invoke(spinny, new object[1] { (object)(State)12 });
		}

		private static void HoldRouletteState(EnemySpinny spinny)
		{
			if (StateTimerField == null)
			{
				MathTeacherPlugin.Logger.LogWarning((object)"MathTeacher could not hold Spinny roulette state because stateTimer was not found.");
			}
			else
			{
				StateTimerField.SetValue(spinny, 0.25f);
			}
		}

		private static void CleanupIfInteractionEnded(EnemySpinny spinny)
		{
			//IL_0002: 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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			State currentState = spinny.currentState;
			if (((int)currentState != 7 && currentState - 9 > 2) || 1 == 0)
			{
				CleanupInteraction(spinny);
			}
		}

		private static void CleanupResolvedInteractionIfRouletteEnded(EnemySpinny spinny)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)spinny.currentState != 8)
			{
				CleanupInteraction(spinny);
			}
		}

		private static void CleanupInteraction(EnemySpinny spinny)
		{
			int instanceID = ((Object)spinny).GetInstanceID();
			Sessions.Remove(instanceID);
			ResolvedInteractions.Clear(instanceID);
			DestroyHud();
		}

		private static void CleanupSession(EnemySpinny spinny)
		{
			Sessions.Remove(((Object)spinny).GetInstanceID());
			DestroyHud();
		}

		private static void DestroyHud()
		{
			hudView?.Destroy();
			hudView = null;
		}
	}
	public static class MathTeacherWheelVisualPolicy
	{
		public const float HighlightRed = 0f;

		public const float HighlightGreen = 0f;

		public const float HighlightBlue = 0f;

		public static bool DisablePointLight => true;
	}
}