Decompiled source of Tamarush v1.1.1

TamaRush.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using CommonAPI.Phone;
using HarmonyLib;
using Reptile;
using Reptile.Phone;
using TMPro;
using TamaRush.Phone;
using TamaRush.TMEmulator;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("TamaRush")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TamaRush")]
[assembly: AssemblyTitle("TamaRush")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TamaRush
{
	[RequireComponent(typeof(AudioSource))]
	public sealed class TamaRushAudio : MonoBehaviour
	{
		private AudioSource _audioSource;

		private TamaEmulator _emu;

		private double _phase;

		private void Awake()
		{
			_audioSource = ((Component)this).GetComponent<AudioSource>();
			_audioSource.playOnAwake = true;
			_audioSource.loop = true;
			_audioSource.volume = 1f;
			_audioSource.pitch = 1f;
			_audioSource.spatialBlend = 0f;
			_audioSource.bypassEffects = true;
			_audioSource.bypassListenerEffects = true;
			_audioSource.bypassReverbZones = true;
			_audioSource.outputAudioMixerGroup = null;
			if (!_audioSource.isPlaying)
			{
				_audioSource.Play();
			}
		}

		public void SetEmulator(TamaEmulator emu)
		{
			_emu = emu;
		}

		private void OnAudioFilterRead(float[] data, int channels)
		{
			if (_emu != null && _emu.BuzzerEnabled)
			{
				ConfigEntry<bool> audioEnabled = TamaRushPlugin.AudioEnabled;
				if (audioEnabled == null || audioEnabled.Value)
				{
					float buzzerFreqHz = _emu.BuzzerFreqHz;
					if (buzzerFreqHz <= 0f)
					{
						for (int i = 0; i < data.Length; i++)
						{
							data[i] = 0f;
						}
						return;
					}
					int outputSampleRate = AudioSettings.outputSampleRate;
					double num = buzzerFreqHz / (float)outputSampleRate;
					int num2 = data.Length / channels;
					float num3 = Mathf.Clamp01((float)(TamaRushPlugin.AudioVolume?.Value ?? 5) / 10f) * 0.5f;
					for (int j = 0; j < num2; j++)
					{
						float num4 = ((_phase < 0.5) ? num3 : (0f - num3));
						for (int k = 0; k < channels; k++)
						{
							data[j * channels + k] = num4;
						}
						_phase += num;
						if (_phase >= 1.0)
						{
							_phase -= 1.0;
						}
					}
					return;
				}
			}
			for (int l = 0; l < data.Length; l++)
			{
				data[l] = 0f;
			}
			_phase = 0.0;
		}
	}
	public class TamaRushPlayMode : MonoBehaviour
	{
		public static Action OnExitPlayMode;

		private GameObject _canvasGo;

		private TextMeshProUGUI _label;

		public static bool IsActive { get; private set; }

		public static TamaRushPlayMode Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void EnsureUICreated()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00e1: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvasGo != (Object)null))
			{
				Core instance = Core.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					UIManager uIManager = instance.UIManager;
					obj = ((uIManager != null) ? ((Component)uIManager).transform : null);
				}
				Transform val = (Transform)obj;
				if (!((Object)(object)val == (Object)null))
				{
					_canvasGo = new GameObject("TamaRush_PlayModeHint");
					_canvasGo.transform.SetParent(val, false);
					Canvas obj2 = _canvasGo.AddComponent<Canvas>();
					obj2.renderMode = (RenderMode)0;
					obj2.sortingOrder = 200;
					_canvasGo.AddComponent<CanvasScaler>();
					_canvasGo.AddComponent<GraphicRaycaster>();
					GameObject val2 = new GameObject("HintLabel");
					val2.transform.SetParent(_canvasGo.transform, false);
					_label = val2.AddComponent<TextMeshProUGUI>();
					((TMP_Text)_label).text = "-Dance Button To Exit Play Mode";
					((TMP_Text)_label).fontSize = 22f;
					((Graphic)_label).color = Color.green;
					((TMP_Text)_label).alignment = (TextAlignmentOptions)260;
					((TMP_Text)_label).enableWordWrapping = true;
					RectTransform component = val2.GetComponent<RectTransform>();
					component.anchorMin = new Vector2(1f, 1f);
					component.anchorMax = new Vector2(1f, 1f);
					component.pivot = new Vector2(1f, 1f);
					component.sizeDelta = new Vector2(400f, 80f);
					component.anchoredPosition = new Vector2(-16f, -10f);
					GameObject val3 = new GameObject("ControlsLabel");
					val3.transform.SetParent(_canvasGo.transform, false);
					TextMeshProUGUI obj3 = val3.AddComponent<TextMeshProUGUI>();
					((TMP_Text)obj3).text = "-Phone Left: Left Button\n-Phone Up: Center Button\n-Phone Right: Right Button\n-Phone Down: Tap";
					((TMP_Text)obj3).fontSize = 20f;
					((Graphic)obj3).color = Color.yellow;
					((TMP_Text)obj3).alignment = (TextAlignmentOptions)260;
					((TMP_Text)obj3).enableWordWrapping = false;
					RectTransform component2 = val3.GetComponent<RectTransform>();
					component2.anchorMin = new Vector2(1f, 1f);
					component2.anchorMax = new Vector2(1f, 1f);
					component2.pivot = new Vector2(1f, 1f);
					component2.sizeDelta = new Vector2(400f, 100f);
					component2.anchoredPosition = new Vector2(-16f, -90f);
					_canvasGo.SetActive(false);
				}
			}
		}

		public static void Enter()
		{
			IsActive = true;
			Instance?.EnsureUICreated();
			if ((Object)(object)Instance?._canvasGo != (Object)null)
			{
				Instance._canvasGo.SetActive(true);
			}
		}

		public static void Exit()
		{
			if (IsActive)
			{
				IsActive = false;
				if ((Object)(object)Instance?._canvasGo != (Object)null)
				{
					Instance._canvasGo.SetActive(false);
				}
				OnExitPlayMode?.Invoke();
			}
		}

		private void Update()
		{
			if (IsActive)
			{
				WorldHandler instance = WorldHandler.instance;
				Player val = ((instance != null) ? instance.GetCurrentPlayer() : null);
				if (!((Object)(object)val == (Object)null) && val.danceButtonNew)
				{
					Exit();
				}
			}
		}
	}
	[BepInPlugin("com.tamarush", "TamaRush", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class TamaRushPlugin : BaseUnityPlugin
	{
		private static string _modFolder;

		private Harmony _harmony;

		public static ConfigEntry<bool> RunInBackground { get; private set; }

		public static ConfigEntry<int> GameSpeed { get; private set; }

		public static ConfigEntry<bool> AutoSave { get; private set; }

		public static ConfigEntry<int> LcdOption { get; private set; }

		public static ConfigEntry<string> SelectedBackground { get; private set; }

		public static ConfigEntry<string> SelectedIcons { get; private set; }

		public static ConfigEntry<bool> AudioEnabled { get; private set; }

		public static ConfigEntry<int> AudioVolume { get; private set; }

		public static ConfigEntry<int> PixelSize { get; private set; }

		public static ConfigEntry<string> SelectedRom { get; private set; }

		public static ConfigEntry<bool> DebugMode { get; private set; }

		public static string TamaRushFolderPath { get; private set; }

		public static string TamaRushAssetsFolderPath { get; private set; }

		public static string GetAppIconPath(string filename)
		{
			if (!string.IsNullOrEmpty(_modFolder))
			{
				return Path.Combine(_modFolder, filename);
			}
			return null;
		}

		private void Awake()
		{
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			_modFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			RunInBackground = ((BaseUnityPlugin)this).Config.Bind<bool>("Game/ROM", "RunInBackground", false, "When enabled, the Tamagotchi keeps running after you leave play mode.");
			GameSpeed = ((BaseUnityPlugin)this).Config.Bind<int>("Game/ROM", "GameSpeed", 1, "Emulation speed multiplier. 1=Normal, 2=2x, 4=4x, 6=6x.");
			AutoSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Saves", "AutoSave", true, "When enabled, automatically saves every 3 minutes while the emulator is running.");
			LcdOption = ((BaseUnityPlugin)this).Config.Bind<int>("Game/ROM", "LcdOption", 0, "LCD color scheme. 0=Mono, 1=Classic, 2=Green, 3=Inverted.");
			SelectedBackground = ((BaseUnityPlugin)this).Config.Bind<string>("Customize", "SelectedBackground", "", "Full path to the background image file.");
			SelectedIcons = ((BaseUnityPlugin)this).Config.Bind<string>("Customize", "SelectedIcons", "", "Full path to the icons spritesheet file.");
			AudioEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "AudioEnabled", true, "When enabled, the Tamagotchi buzzer sound plays.");
			AudioVolume = ((BaseUnityPlugin)this).Config.Bind<int>("Audio", "AudioVolume", 1, "Buzzer volume level 1-10.");
			PixelSize = ((BaseUnityPlugin)this).Config.Bind<int>("Game/ROM", "PixelSize", 32, "LCD pixel size in Unity units.");
			SelectedRom = ((BaseUnityPlugin)this).Config.Bind<string>("Game/ROM", "SelectedRom", "", "Full path to the ROM to load.");
			DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("DEBUG", "DebugMode", false, "Extra options that may run bad on lower end devices.");
			TamaRushFolderPath = Path.Combine(Paths.BepInExRootPath, "TamaRush");
			Directory.CreateDirectory(TamaRushFolderPath);
			Directory.CreateDirectory(Path.Combine(TamaRushFolderPath, "Saves"));
			Directory.CreateDirectory(Path.Combine(TamaRushFolderPath, "Roms"));
			Directory.CreateDirectory(Path.Combine(TamaRushFolderPath, "Assets"));
			TamaRushAssetsFolderPath = Path.Combine(TamaRushFolderPath, "Assets");
			Directory.CreateDirectory(Path.Combine(TamaRushAssetsFolderPath, "Icons"));
			Directory.CreateDirectory(Path.Combine(TamaRushAssetsFolderPath, "Background"));
			RenameBFilesToBin();
			_harmony = new Harmony("com.tamarush");
			_harmony.PatchAll();
			new GameObject("TamaRush_PlayMode").AddComponent<TamaRushPlayMode>();
			AppTamaRush.Initialize();
		}

		public static string GetAssetSubfolderPath()
		{
			if (!string.IsNullOrEmpty(TamaRushAssetsFolderPath))
			{
				return TamaRushAssetsFolderPath;
			}
			return null;
		}

		public static string GetAssetFolderFile(string subfolder)
		{
			if (string.IsNullOrEmpty(TamaRushAssetsFolderPath))
			{
				return null;
			}
			string text = ((!(subfolder == "Background")) ? ((!(subfolder == "Icons")) ? null : SelectedIcons?.Value) : SelectedBackground?.Value);
			if (!string.IsNullOrEmpty(text) && File.Exists(text))
			{
				return text;
			}
			string path = Path.Combine(TamaRushAssetsFolderPath, subfolder);
			if (!Directory.Exists(path))
			{
				return null;
			}
			string[] files = Directory.GetFiles(path, "*.*");
			foreach (string text2 in files)
			{
				switch (Path.GetExtension(text2).ToLowerInvariant())
				{
				case ".png":
				case ".jpg":
				case ".jpeg":
					return text2;
				}
			}
			return null;
		}

		private static void RenameBFilesToBin()
		{
			string text = Path.Combine(TamaRushFolderPath, "Roms");
			if (!Directory.Exists(text))
			{
				return;
			}
			string[] files = Directory.GetFiles(text, "*.b");
			foreach (string text2 in files)
			{
				try
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2);
					string text3 = Path.Combine(text, fileNameWithoutExtension + ".bin");
					if (!File.Exists(text3))
					{
						File.Move(text2, text3);
					}
				}
				catch (Exception)
				{
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.tamarush";

		public const string PLUGIN_NAME = "TamaRush";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "TamaRush";

		public const string PLUGIN_NAME = "TamaRush";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace TamaRush.TMEmulator
{
	public enum TamaButton
	{
		Left,
		Middle,
		Right,
		Tap
	}
	public class TamaEmulator
	{
		public readonly bool[,] LcdMatrix = new bool[32, 16];

		public readonly bool[] LcdIcons = new bool[8];

		public readonly object Lock = new object();

		public volatile bool LcdDirty;

		public volatile bool BuzzerEnabled;

		public volatile float BuzzerFreqHz;

		public const int LCD_W = 32;

		public const int LCD_H = 16;

		public const int ICON_NUM = 8;

		private const int TICK_FREQ = 32768;

		private const int OSC1_FREQ = 32768;

		private const int OSC3_FREQ = 1000000;

		private const int TIMER_2HZ = 16384;

		private const int TIMER_4HZ = 8192;

		private const int TIMER_8HZ = 4096;

		private const int TIMER_16HZ = 2048;

		private const int TIMER_32HZ = 1024;

		private const int TIMER_64HZ = 512;

		private const int TIMER_128HZ = 256;

		private const int TIMER_256HZ = 128;

		private const int MEM_RAM_ADDR = 0;

		private const int MEM_RAM_SIZE = 640;

		private const int MEM_DISP1_ADDR = 3584;

		private const int MEM_DISP1_SIZE = 80;

		private const int MEM_DISP2_ADDR = 3712;

		private const int MEM_DISP2_SIZE = 80;

		private const int MEM_IO_ADDR = 3840;

		private const int MEM_IO_SIZE = 128;

		private const int MEM_BUF_SIZE = 464;

		private readonly byte[] _mem = new byte[464];

		private const int REG_CLK_INT_FACTOR = 3840;

		private const int REG_SW_INT_FACTOR = 3841;

		private const int REG_PROG_INT_FACTOR = 3842;

		private const int REG_SERIAL_INT_FACTOR = 3843;

		private const int REG_K00_INT_FACTOR = 3844;

		private const int REG_K10_INT_FACTOR = 3845;

		private const int REG_CLK_INT_MASK = 3856;

		private const int REG_SW_INT_MASK = 3857;

		private const int REG_PROG_INT_MASK = 3858;

		private const int REG_SERIAL_INT_MASK = 3859;

		private const int REG_K00_INT_MASK = 3860;

		private const int REG_K10_INT_MASK = 3861;

		private const int REG_CLK_TIMER_DATA1 = 3872;

		private const int REG_CLK_TIMER_DATA2 = 3873;

		private const int REG_PROG_TIMER_DATA_L = 3876;

		private const int REG_PROG_TIMER_DATA_H = 3877;

		private const int REG_PROG_TIMER_RLD_L = 3878;

		private const int REG_PROG_TIMER_RLD_H = 3879;

		private const int REG_K00_INPUT_PORT = 3904;

		private const int REG_K00_INPUT_REL = 3905;

		private const int REG_K10_INPUT_PORT = 3906;

		private const int REG_CPU_OSC3_CTRL = 3952;

		private const int REG_LCD_CTRL = 3953;

		private const int REG_SVD_CTRL = 3955;

		private const int REG_BUZZER_CTRL1 = 3956;

		private const int REG_BUZZER_CTRL2 = 3957;

		private const int REG_PROG_TIMER_CTRL = 3960;

		private const int REG_PROG_TIMER_CLK = 3961;

		private const int REG_R40_BZ_OUTPUT = 3924;

		private int _pc;

		private int _nextPc;

		private int _x;

		private int _y;

		private byte _a;

		private byte _b;

		private byte _np;

		private byte _sp;

		private byte _flags;

		private const byte FLAG_C = 1;

		private const byte FLAG_Z = 2;

		private const byte FLAG_D = 4;

		private const byte FLAG_I = 8;

		private const int INT_PROG = 0;

		private const int INT_SERIAL = 1;

		private const int INT_K10 = 2;

		private const int INT_K00 = 3;

		private const int INT_SW = 4;

		private const int INT_CLK = 5;

		private const int INT_NUM = 6;

		private readonly byte[] _intFactor = new byte[6];

		private readonly byte[] _intMask = new byte[6];

		private readonly bool[] _intTriggered = new bool[6];

		private readonly byte[] _intVector = new byte[6] { 12, 10, 8, 6, 4, 2 };

		private uint _tickCounter;

		private uint _clk2hz;

		private uint _clk4hz;

		private uint _clk8hz;

		private uint _clk16hz;

		private uint _clk32hz;

		private uint _clk64hz;

		private uint _clk128hz;

		private uint _clk256hz;

		private uint _progTimerTs;

		private bool _progTimerEnabled;

		private byte _progTimerData;

		private byte _progTimerRld;

		private long _refTicks;

		private uint _scaledCycleAcc;

		private int _cpuFreq = 32768;

		private byte _prevCycles;

		private bool _cpuHalted;

		private byte _inputK0 = 15;

		private byte _inputK1 = 15;

		private ushort[] _rom;

		private static readonly byte[] SegPos;

		private static readonly float[] _buzzerFreqTable;

		private readonly Stopwatch _sw = Stopwatch.StartNew();

		private static readonly (int code, int mask, int shiftArg0, int maskArg0, byte cycles)[] _ops;

		private static readonly byte[] _opCycles;

		public int LcdWriteCount { get; private set; }

		public long StepCount { get; private set; }

		public int PC_Snapshot { get; private set; }

		public int IntCount { get; private set; }

		public bool InterruptsEnabled => (_flags & 8) != 0;

		public int PC
		{
			get
			{
				return _pc;
			}
			set
			{
				_pc = value;
			}
		}

		public int X
		{
			get
			{
				return _x;
			}
			set
			{
				_x = value;
			}
		}

		public int Y
		{
			get
			{
				return _y;
			}
			set
			{
				_y = value;
			}
		}

		public byte A
		{
			get
			{
				return _a;
			}
			set
			{
				_a = (byte)(value & 0xFu);
			}
		}

		public byte B
		{
			get
			{
				return _b;
			}
			set
			{
				_b = (byte)(value & 0xFu);
			}
		}

		public byte NP
		{
			get
			{
				return _np;
			}
			set
			{
				_np = (byte)(value & 0x1Fu);
			}
		}

		public byte SP
		{
			get
			{
				return _sp;
			}
			set
			{
				_sp = value;
			}
		}

		public byte Flags
		{
			get
			{
				return _flags;
			}
			set
			{
				_flags = (byte)(value & 0xFu);
			}
		}

		public uint TickCounter
		{
			get
			{
				return _tickCounter;
			}
			set
			{
				_tickCounter = value;
			}
		}

		public uint Clk2Hz
		{
			get
			{
				return _clk2hz;
			}
			set
			{
				_clk2hz = value;
			}
		}

		public uint Clk4Hz
		{
			get
			{
				return _clk4hz;
			}
			set
			{
				_clk4hz = value;
			}
		}

		public uint Clk8Hz
		{
			get
			{
				return _clk8hz;
			}
			set
			{
				_clk8hz = value;
			}
		}

		public uint Clk16Hz
		{
			get
			{
				return _clk16hz;
			}
			set
			{
				_clk16hz = value;
			}
		}

		public uint Clk32Hz
		{
			get
			{
				return _clk32hz;
			}
			set
			{
				_clk32hz = value;
			}
		}

		public uint Clk64Hz
		{
			get
			{
				return _clk64hz;
			}
			set
			{
				_clk64hz = value;
			}
		}

		public uint Clk128Hz
		{
			get
			{
				return _clk128hz;
			}
			set
			{
				_clk128hz = value;
			}
		}

		public uint Clk256Hz
		{
			get
			{
				return _clk256hz;
			}
			set
			{
				_clk256hz = value;
			}
		}

		public uint ProgTimerTs
		{
			get
			{
				return _progTimerTs;
			}
			set
			{
				_progTimerTs = value;
			}
		}

		public bool ProgTimerEnabled
		{
			get
			{
				return _progTimerEnabled;
			}
			set
			{
				_progTimerEnabled = value;
			}
		}

		public byte ProgTimerData
		{
			get
			{
				return _progTimerData;
			}
			set
			{
				_progTimerData = value;
			}
		}

		public byte ProgTimerRld
		{
			get
			{
				return _progTimerRld;
			}
			set
			{
				_progTimerRld = value;
			}
		}

		public byte[] IntFactor => _intFactor;

		public byte[] IntMask => _intMask;

		public bool[] IntTriggered => _intTriggered;

		private byte PCS => (byte)((uint)_pc & 0xFFu);

		private byte PCSL => (byte)((uint)_pc & 0xFu);

		private byte PCSH => (byte)((uint)(_pc >> 4) & 0xFu);

		private byte PCP => (byte)((uint)(_pc >> 8) & 0xFu);

		private byte PCB => (byte)((uint)(_pc >> 12) & 1u);

		private byte NBP => (byte)((uint)(_np >> 4) & 1u);

		private byte NPP => (byte)(_np & 0xFu);

		private byte XHL => (byte)((uint)_x & 0xFFu);

		private byte XL => (byte)((uint)_x & 0xFu);

		private byte XH => (byte)((uint)(_x >> 4) & 0xFu);

		private byte XP => (byte)((uint)(_x >> 8) & 0xFu);

		private byte YHL => (byte)((uint)_y & 0xFFu);

		private byte YL => (byte)((uint)_y & 0xFu);

		private byte YH => (byte)((uint)(_y >> 4) & 0xFu);

		private byte YP => (byte)((uint)(_y >> 8) & 0xFu);

		private byte SPL => (byte)(_sp & 0xFu);

		private byte SPH => (byte)((uint)(_sp >> 4) & 0xFu);

		private bool C => (_flags & 1) != 0;

		private bool Z => (_flags & 2) != 0;

		private bool D => (_flags & 4) != 0;

		public byte GetRamNibble(int i)
		{
			return GetNibble(RamIdx(i), i);
		}

		public void SetRamNibble(int i, byte v)
		{
			SetNibble(RamIdx(i), i, v);
		}

		public byte GetIONibble(int i)
		{
			return GetIOMem(3840 + i);
		}

		public void SetIONibble(int i, byte v)
		{
			SetIOMem(3840 + i, v);
		}

		public void Init(ushort[] rom)
		{
			_rom = rom;
			Reset();
		}

		public void Reset()
		{
			Array.Clear(_mem, 0, _mem.Length);
			Array.Clear(_intFactor, 0, 6);
			Array.Clear(_intMask, 0, 6);
			Array.Clear(_intTriggered, 0, 6);
			_pc = ToPC(0, 1, 0);
			_np = ToNP(0, 1);
			_a = (_b = 0);
			_x = (_y = 0);
			_sp = 0;
			_flags = 0;
			_tickCounter = 0u;
			_clk2hz = (_clk4hz = (_clk8hz = (_clk16hz = 0u)));
			_clk32hz = (_clk64hz = (_clk128hz = (_clk256hz = 0u)));
			_progTimerTs = 0u;
			_progTimerEnabled = false;
			_progTimerData = (_progTimerRld = 0);
			_cpuHalted = false;
			_cpuFreq = 32768;
			_scaledCycleAcc = 0u;
			_prevCycles = 0;
			SetIOMem(3953, 8);
			SetIOMem(3905, 15);
			SetIOMem(3924, 15);
			_inputK0 = 15;
			_inputK1 = 15;
			_refTicks = _sw.ElapsedTicks;
		}

		public void Step(int speedMultiplier = 1)
		{
			int num = 12;
			if (!_cpuHalted)
			{
				int num2 = _pc & 0x1FFF;
				ushort op = (ushort)((num2 < _rom.Length) ? _rom[num2] : 4091);
				num = FindOp(op);
				if (num < 0)
				{
					num = 12;
				}
				_nextPc = (_pc + 1) & 0x1FFF;
				_refTicks = WaitForCycles(_refTicks, _prevCycles, speedMultiplier);
				ExecuteOp(num, op);
				_pc = _nextPc;
				_prevCycles = _opCycles[num];
				if (num != 0)
				{
					_np = (byte)((uint)(_pc >> 8) & 0x1Fu);
				}
			}
			else
			{
				_refTicks = WaitForCycles(_refTicks, 5, speedMultiplier);
				_prevCycles = 0;
				num = -1;
			}
			HandleTimers();
			if ((_flags & 8u) != 0 && num != 0 && num != 58)
			{
				ProcessInterrupts(speedMultiplier);
			}
			StepCount++;
			PC_Snapshot = _pc;
		}

		public void SetButton(TamaButton btn, bool pressed)
		{
			byte state = (byte)((!pressed) ? 1 : 0);
			switch (btn)
			{
			case TamaButton.Left:
				SetInputPin(0, 0, state);
				break;
			case TamaButton.Middle:
				SetInputPin(0, 1, state);
				break;
			case TamaButton.Right:
				SetInputPin(0, 2, state);
				break;
			case TamaButton.Tap:
				SetInputPin(0, 3, state);
				break;
			}
		}

		private int RamIdx(int n)
		{
			return n / 2;
		}

		private int Disp1Idx(int n)
		{
			return (n - 3584 + 640) / 2;
		}

		private int Disp2Idx(int n)
		{
			return (n - 3712 + 640 + 80) / 2;
		}

		private int IOIdx(int n)
		{
			return (n - 3840 + 640 + 80 + 80) / 2;
		}

		private byte GetNibble(int bufIdx, int addr)
		{
			int num = (addr & 1) << 2;
			return (byte)((uint)(_mem[bufIdx] >> num) & 0xFu);
		}

		private void SetNibble(int bufIdx, int addr, byte v)
		{
			int num = (addr & 1) << 2;
			_mem[bufIdx] = (byte)((_mem[bufIdx] & ~(15 << num)) | ((v & 0xF) << num));
		}

		private byte GetMem(int n)
		{
			if (n < 640)
			{
				return GetNibble(RamIdx(n), n);
			}
			if (n >= 3584 && n < 3664)
			{
				return GetNibble(Disp1Idx(n), n);
			}
			if (n >= 3712 && n < 3792)
			{
				return GetNibble(Disp2Idx(n), n);
			}
			if (n >= 3840 && n < 3968)
			{
				return GetIO(n);
			}
			return 0;
		}

		private void SetMem(int n, byte v)
		{
			if (n < 640)
			{
				SetNibble(RamIdx(n), n, v);
			}
			else if (n >= 3584 && n < 3664)
			{
				SetNibble(Disp1Idx(n), n, v);
				SetLcd(n, v);
			}
			else if (n >= 3712 && n < 3792)
			{
				SetNibble(Disp2Idx(n), n, v);
				SetLcd(n, v);
			}
			else if (n >= 3840 && n < 3968)
			{
				SetNibble(IOIdx(n), n, v);
				SetIO(n, v);
			}
		}

		private byte GetIOMem(int n)
		{
			return GetNibble(IOIdx(n), n);
		}

		private void SetIOMem(int n, byte v)
		{
			SetNibble(IOIdx(n), n, v);
		}

		private byte GetIO(int n)
		{
			switch (n)
			{
			case 3840:
			{
				byte result2 = _intFactor[5];
				_intFactor[5] = 0;
				return result2;
			}
			case 3841:
			{
				byte result = _intFactor[4];
				_intFactor[4] = 0;
				return result;
			}
			case 3842:
			{
				byte result3 = _intFactor[0];
				_intFactor[0] = 0;
				return result3;
			}
			case 3843:
			{
				byte result6 = _intFactor[1];
				_intFactor[1] = 0;
				return result6;
			}
			case 3844:
			{
				byte result5 = _intFactor[3];
				_intFactor[3] = 0;
				return result5;
			}
			case 3845:
			{
				byte result4 = _intFactor[2];
				_intFactor[2] = 0;
				return result4;
			}
			case 3856:
				return _intMask[5];
			case 3857:
				return (byte)(_intMask[4] & 3u);
			case 3858:
				return (byte)(_intMask[0] & 1u);
			case 3859:
				return (byte)(_intMask[1] & 1u);
			case 3860:
				return _intMask[3];
			case 3861:
				return _intMask[2];
			case 3872:
				return GetIOMem(n);
			case 3873:
				return GetIOMem(n);
			case 3876:
				return (byte)(_progTimerData & 0xFu);
			case 3877:
				return (byte)((uint)(_progTimerData >> 4) & 0xFu);
			case 3878:
				return (byte)(_progTimerRld & 0xFu);
			case 3879:
				return (byte)((uint)(_progTimerRld >> 4) & 0xFu);
			case 3904:
				return _inputK0;
			case 3905:
				return GetIOMem(n);
			case 3906:
				return _inputK1;
			case 3952:
				return GetIOMem(n);
			case 3953:
				return GetIOMem(n);
			case 3955:
				return (byte)(GetIOMem(n) & 7u);
			case 3960:
				return (byte)(_progTimerEnabled ? 1u : 0u);
			default:
				return 0;
			}
		}

		private void SetIO(int n, byte v)
		{
			switch (n)
			{
			case 3856:
				_intMask[5] = v;
				break;
			case 3857:
				_intMask[4] = v;
				break;
			case 3858:
				_intMask[0] = v;
				break;
			case 3859:
				_intMask[1] = v;
				break;
			case 3860:
				_intMask[3] = v;
				break;
			case 3861:
				_intMask[2] = v;
				break;
			case 3878:
				_progTimerRld = (byte)((_progTimerRld & 0xF0u) | (v & 0xFu));
				break;
			case 3879:
				_progTimerRld = (byte)((_progTimerRld & 0xFu) | (uint)((v & 0xF) << 4));
				break;
			case 3952:
				if ((v & 8u) != 0 && _cpuFreq != 1000000)
				{
					_cpuFreq = 1000000;
					_scaledCycleAcc = 0u;
				}
				if ((v & 8) == 0 && _cpuFreq != 32768)
				{
					_cpuFreq = 32768;
					_scaledCycleAcc = 0u;
				}
				break;
			case 3924:
				BuzzerEnabled = (v & 8) == 0;
				break;
			case 3956:
				BuzzerFreqHz = _buzzerFreqTable[v & 7];
				break;
			case 3960:
				if ((v & 2u) != 0)
				{
					_progTimerData = _progTimerRld;
				}
				if (((uint)v & (true ? 1u : 0u)) != 0 && !_progTimerEnabled)
				{
					_progTimerTs = _tickCounter;
				}
				_progTimerEnabled = (v & 1) != 0;
				break;
			}
		}

		private void SetLcd(int n, byte v)
		{
			LcdWriteCount++;
			int seg = (n & 0x7F) >> 1;
			int num = ((n & 0x80) >> 7) * 8 + (n & 1) * 4;
			for (int i = 0; i < 4; i++)
			{
				SetLcdPin(seg, num + i, (byte)((uint)(v >> i) & 1u));
			}
		}

		private void SetLcdPin(int seg, int com, byte val)
		{
			if (seg >= SegPos.Length)
			{
				return;
			}
			int num = SegPos[seg];
			if (num < 32)
			{
				lock (Lock)
				{
					LcdMatrix[num, com] = val != 0;
					LcdDirty = true;
					return;
				}
			}
			if (seg == 8 && com < 4)
			{
				lock (Lock)
				{
					LcdIcons[com] = val != 0;
					LcdDirty = true;
					return;
				}
			}
			if (seg != 28 || com < 12)
			{
				return;
			}
			lock (Lock)
			{
				LcdIcons[com - 8] = val != 0;
				LcdDirty = true;
			}
		}

		private void SetInputPin(int port, int bit, byte state)
		{
			if (port == 0)
			{
				byte b = (byte)((uint)(_inputK0 >> bit) & 1u);
				if (state != b)
				{
					byte iOMem = GetIOMem(3905);
					if (state != ((iOMem >> bit) & 1))
					{
						GenerateInterrupt(3, bit);
					}
				}
				_inputK0 = (byte)((_inputK0 & ~(1 << bit)) | (state << bit));
			}
			else
			{
				byte b2 = (byte)((uint)(_inputK1 >> bit) & 1u);
				if (state != b2 && state == 0)
				{
					GenerateInterrupt(2, bit);
				}
				_inputK1 = (byte)((_inputK1 & ~(1 << bit)) | (state << bit));
			}
		}

		private void GenerateInterrupt(int slot, int bit)
		{
			_intFactor[slot] |= (byte)(1 << bit);
			if ((_intMask[slot] & (1 << bit)) != 0)
			{
				_intTriggered[slot] = true;
			}
		}

		private void HandleTimers()
		{
			TickTimer(ref _clk2hz, 16384u, delegate
			{
				SetIOMem(3873, (byte)(GetIOMem(3873) ^ 8u));
				if ((GetIOMem(3873) & 8) == 0)
				{
					GenerateInterrupt(5, 3);
				}
			});
			TickTimer(ref _clk4hz, 8192u, delegate
			{
				SetIOMem(3873, (byte)(GetIOMem(3873) ^ 4u));
				if ((GetIOMem(3873) & 4) == 0)
				{
					GenerateInterrupt(5, 2);
				}
			});
			TickTimer(ref _clk8hz, 4096u, delegate
			{
				SetIOMem(3873, (byte)(GetIOMem(3873) ^ 2u));
			});
			TickTimer(ref _clk16hz, 2048u, delegate
			{
				SetIOMem(3873, (byte)(GetIOMem(3873) ^ 1u));
				if ((GetIOMem(3873) & 1) == 0)
				{
					GenerateInterrupt(5, 1);
				}
			});
			TickTimer(ref _clk32hz, 1024u, delegate
			{
				SetIOMem(3872, (byte)(GetIOMem(3872) ^ 8u));
			});
			TickTimer(ref _clk64hz, 512u, delegate
			{
				SetIOMem(3872, (byte)(GetIOMem(3872) ^ 4u));
				if ((GetIOMem(3872) & 4) == 0)
				{
					GenerateInterrupt(5, 0);
				}
			});
			TickTimer(ref _clk128hz, 256u, delegate
			{
				SetIOMem(3872, (byte)(GetIOMem(3872) ^ 2u));
			});
			TickTimer(ref _clk256hz, 128u, delegate
			{
				SetIOMem(3872, (byte)(GetIOMem(3872) ^ 1u));
			});
			if (!_progTimerEnabled)
			{
				return;
			}
			while (_tickCounter - _progTimerTs >= 128)
			{
				_progTimerTs += 128u;
				_progTimerData--;
				if (_progTimerData == 0)
				{
					_progTimerData = _progTimerRld;
					GenerateInterrupt(0, 0);
				}
			}
		}

		private void TickTimer(ref uint ts, uint period, Action onTick)
		{
			if (_tickCounter - ts >= period)
			{
				do
				{
					ts += period;
				}
				while (_tickCounter - ts >= period);
				onTick();
			}
		}

		private void ProcessInterrupts(int speedMultiplier = 1)
		{
			for (int i = 0; i < 6; i++)
			{
				if (_intTriggered[i])
				{
					SetMem((_sp - 1) & 0xFF, PCP);
					SetMem((_sp - 2) & 0xFF, PCSH);
					SetMem((_sp - 3) & 0xFF, PCSL);
					_sp = (byte)((uint)(_sp - 3) & 0xFFu);
					_flags &= 247;
					_np = ToNP(NBP, 1);
					_pc = ToPC(PCB, 1, _intVector[i]);
					_cpuHalted = false;
					IntCount++;
					_refTicks = WaitForCycles(_refTicks, 12, speedMultiplier);
					_intTriggered[i] = false;
					break;
				}
			}
		}

		private long GetTimestampUs()
		{
			return _sw.ElapsedTicks * 1000000 / Stopwatch.Frequency;
		}

		private long WaitForCycles(long sinceTicks, byte cycles, int speedMultiplier = 1)
		{
			if (cycles == 0)
			{
				return sinceTicks;
			}
			_scaledCycleAcc += (uint)(cycles * 32768);
			uint num = _scaledCycleAcc / (uint)_cpuFreq;
			if (num != 0)
			{
				_tickCounter += num;
				_scaledCycleAcc -= (uint)((int)num * _cpuFreq);
			}
			int num2 = ((speedMultiplier <= 0) ? 1 : speedMultiplier);
			long num3 = sinceTicks + cycles * Stopwatch.Frequency / (_cpuFreq * num2);
			if (speedMultiplier == 0)
			{
				return _sw.ElapsedTicks;
			}
			long num4 = num3 - _sw.ElapsedTicks;
			if (num4 > 0)
			{
				long num5 = num4 * 1000 / Stopwatch.Frequency;
				if (num5 > 1)
				{
					Thread.Sleep((int)(num5 - 1));
				}
				while (_sw.ElapsedTicks < num3)
				{
				}
			}
			return num3;
		}

		private static int ToPC(int bank, int page, int step)
		{
			return (step & 0xFF) | ((page & 0xF) << 8) | ((bank & 1) << 12);
		}

		private static byte ToNP(int bank, int page)
		{
			return (byte)(((uint)page & 0xFu) | (uint)((bank & 1) << 4));
		}

		private byte GetRQ(int rq)
		{
			return (rq & 3) switch
			{
				0 => _a, 
				1 => _b, 
				2 => GetMem(_x), 
				3 => GetMem(_y), 
				_ => 0, 
			};
		}

		private void SetRQ(int rq, byte v)
		{
			switch (rq & 3)
			{
			case 0:
				_a = (byte)(v & 0xFu);
				break;
			case 1:
				_b = (byte)(v & 0xFu);
				break;
			case 2:
				SetMem(_x, v);
				break;
			case 3:
				SetMem(_y, v);
				break;
			}
		}

		static TamaEmulator()
		{
			SegPos = new byte[40]
			{
				0, 1, 2, 3, 4, 5, 6, 7, 32, 8,
				9, 10, 11, 12, 13, 14, 15, 33, 34, 35,
				31, 30, 29, 28, 27, 26, 25, 24, 36, 23,
				22, 21, 20, 19, 18, 17, 16, 37, 38, 39
			};
			_buzzerFreqTable = new float[8] { 4096f, 3276.8f, 2730.7f, 2340.6f, 2048f, 1638.4f, 1365.3f, 1170.3f };
			_ops = new(int, int, int, int, byte)[108]
			{
				(3648, 4064, 0, 0, 5),
				(0, 3840, 0, 0, 5),
				(512, 3840, 0, 0, 5),
				(768, 3840, 0, 0, 5),
				(1536, 3840, 0, 0, 5),
				(1792, 3840, 0, 0, 5),
				(4072, 4095, 0, 0, 5),
				(1024, 3840, 0, 0, 7),
				(1280, 3840, 0, 0, 7),
				(4063, 4095, 0, 0, 7),
				(4062, 4095, 0, 0, 12),
				(256, 3840, 0, 0, 12),
				(4091, 4095, 0, 0, 5),
				(4095, 4095, 0, 0, 7),
				(4088, 4095, 0, 0, 5),
				(3808, 4095, 0, 0, 5),
				(3824, 4095, 0, 0, 5),
				(2816, 3840, 0, 0, 5),
				(2048, 3840, 0, 0, 5),
				(3712, 4092, 0, 0, 5),
				(3716, 4092, 0, 0, 5),
				(3720, 4092, 0, 0, 5),
				(3728, 4092, 0, 0, 5),
				(3732, 4092, 0, 0, 5),
				(3736, 4092, 0, 0, 5),
				(3744, 4092, 0, 0, 5),
				(3748, 4092, 0, 0, 5),
				(3752, 4092, 0, 0, 5),
				(3760, 4092, 0, 0, 5),
				(3764, 4092, 0, 0, 5),
				(3768, 4092, 0, 0, 5),
				(2560, 4080, 0, 0, 7),
				(2576, 4080, 0, 0, 7),
				(2592, 4080, 0, 0, 7),
				(2608, 4080, 0, 0, 7),
				(2624, 4080, 0, 0, 7),
				(2640, 4080, 0, 0, 7),
				(2656, 4080, 0, 0, 7),
				(2672, 4080, 0, 0, 7),
				(3584, 4032, 4, 48, 5),
				(3776, 4080, 2, 12, 5),
				(4000, 4080, 0, 0, 5),
				(4016, 4080, 0, 0, 5),
				(3968, 4080, 0, 0, 5),
				(3984, 4080, 0, 0, 5),
				(3680, 4080, 0, 0, 5),
				(3808, 4080, 2, 12, 5),
				(3696, 4080, 0, 0, 5),
				(3824, 4080, 2, 12, 5),
				(2304, 3840, 0, 0, 5),
				(3904, 4080, 0, 0, 7),
				(3920, 4080, 0, 0, 7),
				(3905, 4095, 0, 0, 7),
				(3934, 4095, 0, 0, 7),
				(3906, 4095, 0, 0, 7),
				(3933, 4095, 0, 0, 7),
				(3908, 4095, 0, 0, 7),
				(3931, 4095, 0, 0, 7),
				(3912, 4095, 0, 0, 7),
				(3927, 4095, 0, 0, 7),
				(4059, 4095, 0, 0, 5),
				(4043, 4095, 0, 0, 5),
				(4032, 4092, 0, 0, 5),
				(4036, 4095, 0, 0, 5),
				(4037, 4095, 0, 0, 5),
				(4038, 4095, 0, 0, 5),
				(4039, 4095, 0, 0, 5),
				(4040, 4095, 0, 0, 5),
				(4041, 4095, 0, 0, 5),
				(4042, 4095, 0, 0, 5),
				(4048, 4092, 0, 0, 5),
				(4052, 4095, 0, 0, 5),
				(4053, 4095, 0, 0, 5),
				(4054, 4095, 0, 0, 5),
				(4055, 4095, 0, 0, 5),
				(4056, 4095, 0, 0, 5),
				(4057, 4095, 0, 0, 5),
				(4058, 4095, 0, 0, 5),
				(4064, 4092, 0, 0, 5),
				(4080, 4092, 0, 0, 5),
				(4068, 4092, 0, 0, 5),
				(4084, 4092, 0, 0, 5),
				(3072, 4032, 4, 48, 7),
				(2688, 4080, 2, 12, 7),
				(3136, 4032, 4, 48, 7),
				(2704, 4080, 2, 12, 7),
				(2720, 4080, 2, 12, 7),
				(3392, 4032, 4, 48, 7),
				(2736, 4080, 2, 12, 7),
				(3200, 4032, 4, 48, 7),
				(2752, 4080, 2, 12, 7),
				(3264, 4032, 4, 48, 7),
				(2768, 4080, 2, 12, 7),
				(3328, 4032, 4, 48, 7),
				(2784, 4080, 2, 12, 7),
				(3520, 4032, 4, 48, 7),
				(3840, 4080, 2, 12, 7),
				(3456, 4032, 4, 48, 7),
				(3856, 4080, 2, 12, 7),
				(2800, 4080, 0, 0, 7),
				(3724, 4092, 0, 0, 5),
				(3936, 4080, 0, 0, 7),
				(3952, 4080, 0, 0, 7),
				(3880, 4092, 0, 0, 7),
				(3884, 4092, 0, 0, 7),
				(3896, 4092, 0, 0, 7),
				(3900, 4092, 0, 0, 7),
				(3343, 4047, 4, 0, 7)
			};
			_opCycles = new byte[_ops.Length];
			for (int i = 0; i < _ops.Length; i++)
			{
				_opCycles[i] = _ops[i].cycles;
			}
		}

		private int FindOp(ushort op)
		{
			for (int i = 0; i < _ops.Length; i++)
			{
				if ((op & _ops[i].mask) == _ops[i].code)
				{
					return i;
				}
			}
			return -1;
		}

		private void ExecuteOp(int opIdx, int op)
		{
			(int, int, int, int, byte) tuple = _ops[opIdx];
			int num = ((tuple.Item4 != 0) ? ((op & tuple.Item4) >> tuple.Item3) : ((op & ~tuple.Item2) >> tuple.Item3));
			int num2 = ((tuple.Item4 != 0) ? (op & ~(tuple.Item2 | tuple.Item4)) : 0);
			switch (opIdx)
			{
			case 0:
				_np = (byte)((uint)num & 0x1Fu);
				break;
			case 1:
				_nextPc = (op & 0xFF) | (_np << 8);
				break;
			case 2:
				if (C)
				{
					_nextPc = (op & 0xFF) | (_np << 8);
				}
				break;
			case 3:
				if (!C)
				{
					_nextPc = (op & 0xFF) | (_np << 8);
				}
				break;
			case 4:
				if (Z)
				{
					_nextPc = (op & 0xFF) | (_np << 8);
				}
				break;
			case 5:
				if (!Z)
				{
					_nextPc = (op & 0xFF) | (_np << 8);
				}
				break;
			case 6:
				_nextPc = _a | (_b << 4) | (_np << 8);
				break;
			case 7:
			{
				int num24 = (_pc + 1) & 0x1FFF;
				SetMem((_sp - 1) & 0xFF, (byte)((uint)(num24 >> 8) & 0xFu));
				SetMem((_sp - 2) & 0xFF, (byte)((uint)(num24 >> 4) & 0xFu));
				SetMem((_sp - 3) & 0xFF, (byte)((uint)num24 & 0xFu));
				_sp = (byte)((uint)(_sp - 3) & 0xFFu);
				_nextPc = ToPC(PCB, NPP, op & 0xFF);
				break;
			}
			case 8:
			{
				int num21 = (_pc + 1) & 0x1FFF;
				SetMem((_sp - 1) & 0xFF, (byte)((uint)(num21 >> 8) & 0xFu));
				SetMem((_sp - 2) & 0xFF, (byte)((uint)(num21 >> 4) & 0xFu));
				SetMem((_sp - 3) & 0xFF, (byte)((uint)num21 & 0xFu));
				_sp = (byte)((uint)(_sp - 3) & 0xFFu);
				_nextPc = ToPC(PCB, 0, op & 0xFF);
				break;
			}
			case 9:
				_nextPc = GetMem(_sp) | (GetMem((_sp + 1) & 0xFF) << 4) | (GetMem((_sp + 2) & 0xFF) << 8) | (PCB << 12);
				_sp = (byte)((uint)(_sp + 3) & 0xFFu);
				break;
			case 10:
				_nextPc = GetMem(_sp) | (GetMem((_sp + 1) & 0xFF) << 4) | (GetMem((_sp + 2) & 0xFF) << 8) | (PCB << 12);
				_sp = (byte)((uint)(_sp + 3) & 0xFFu);
				_nextPc = (_nextPc + 1) & 0x1FFF;
				break;
			case 11:
			{
				_nextPc = GetMem(_sp) | (GetMem((_sp + 1) & 0xFF) << 4) | (GetMem((_sp + 2) & 0xFF) << 8) | (PCB << 12);
				_sp = (byte)((uint)(_sp + 3) & 0xFFu);
				byte b3 = (byte)((uint)op & 0xFFu);
				SetMem(_x, (byte)(b3 & 0xFu));
				SetMem(((_x + 1) & 0xFF) | (XP << 8), (byte)((uint)(b3 >> 4) & 0xFu));
				_x = ((_x + 2) & 0xFF) | (XP << 8);
				break;
			}
			case 14:
				_cpuHalted = true;
				break;
			case 15:
				_x = ((_x + 1) & 0xFF) | (XP << 8);
				break;
			case 16:
				_y = ((_y + 1) & 0xFF) | (YP << 8);
				break;
			case 17:
				_x = (op & 0xFF) | (XP << 8);
				break;
			case 18:
				_y = (op & 0xFF) | (YP << 8);
				break;
			case 19:
				_x = XHL | (GetRQ(op & 3) << 8);
				break;
			case 20:
				_x = XL | (GetRQ(op & 3) << 4) | (XP << 8);
				break;
			case 21:
				_x = GetRQ(op & 3) | (XH << 4) | (XP << 8);
				break;
			case 22:
				_y = YHL | (GetRQ(op & 3) << 8);
				break;
			case 23:
				_y = YL | (GetRQ(op & 3) << 4) | (YP << 8);
				break;
			case 24:
				_y = GetRQ(op & 3) | (YH << 4) | (YP << 8);
				break;
			case 25:
				SetRQ(op & 3, XP);
				break;
			case 26:
				SetRQ(op & 3, XH);
				break;
			case 27:
				SetRQ(op & 3, XL);
				break;
			case 28:
				SetRQ(op & 3, YP);
				break;
			case 29:
				SetRQ(op & 3, YH);
				break;
			case 30:
				SetRQ(op & 3, YL);
				break;
			case 31:
			{
				int num22 = XH + (op & 0xF) + (C ? 1 : 0);
				_x = XL | ((num22 & 0xF) << 4) | (XP << 8);
				if (num22 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num22 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 32:
			{
				int num18 = XL + (op & 0xF) + (C ? 1 : 0);
				_x = (num18 & 0xF) | (XH << 4) | (XP << 8);
				if (num18 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num18 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 33:
			{
				int num4 = YH + (op & 0xF) + (C ? 1 : 0);
				_y = YL | ((num4 & 0xF) << 4) | (YP << 8);
				if (num4 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num4 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 34:
			{
				int num26 = YL + (op & 0xF) + (C ? 1 : 0);
				_y = (num26 & 0xF) | (YH << 4) | (YP << 8);
				if (num26 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num26 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 35:
			{
				int num23 = op & 0xF;
				if (XH < num23)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (XH == num23)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 36:
			{
				int num20 = op & 0xF;
				if (XL < num20)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (XL == num20)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 37:
			{
				int num17 = op & 0xF;
				if (YH < num17)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (YH == num17)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 38:
			{
				int num14 = op & 0xF;
				if (YL < num14)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (YL == num14)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 39:
				SetRQ(num, (byte)((uint)num2 & 0xFu));
				break;
			case 40:
				SetRQ(num, GetRQ(num2));
				break;
			case 41:
				_a = (byte)(GetMem(op & 0xF) & 0xFu);
				break;
			case 42:
				_b = (byte)(GetMem(op & 0xF) & 0xFu);
				break;
			case 43:
				SetMem(op & 0xF, _a);
				break;
			case 44:
				SetMem(op & 0xF, _b);
				break;
			case 45:
				SetMem(_x, (byte)((uint)op & 0xFu));
				_x = ((_x + 1) & 0xFF) | (XP << 8);
				break;
			case 46:
				SetRQ(num, GetRQ(num2));
				_x = ((_x + 1) & 0xFF) | (XP << 8);
				break;
			case 47:
				SetMem(_y, (byte)((uint)op & 0xFu));
				_y = ((_y + 1) & 0xFF) | (YP << 8);
				break;
			case 48:
				SetRQ(num, GetRQ(num2));
				_y = ((_y + 1) & 0xFF) | (YP << 8);
				break;
			case 49:
			{
				byte b2 = (byte)((uint)op & 0xFFu);
				SetMem(_x, (byte)(b2 & 0xFu));
				SetMem(((_x + 1) & 0xFF) | (XP << 8), (byte)((uint)(b2 >> 4) & 0xFu));
				_x = ((_x + 2) & 0xFF) | (XP << 8);
				break;
			}
			case 50:
				_flags |= (byte)(op & 0xF);
				break;
			case 51:
				_flags &= (byte)(op & 0xF);
				break;
			case 52:
				_flags |= 1;
				break;
			case 53:
				_flags &= 254;
				break;
			case 54:
				_flags |= 2;
				break;
			case 55:
				_flags &= 253;
				break;
			case 56:
				_flags |= 4;
				break;
			case 57:
				_flags &= 251;
				break;
			case 58:
				_flags |= 8;
				break;
			case 59:
				_flags &= 247;
				break;
			case 60:
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 61:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				break;
			case 62:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, GetRQ(op & 3));
				break;
			case 63:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, XP);
				break;
			case 64:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, XH);
				break;
			case 65:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, XL);
				break;
			case 66:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, YP);
				break;
			case 67:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, YH);
				break;
			case 68:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, YL);
				break;
			case 69:
				_sp = (byte)((uint)(_sp - 1) & 0xFFu);
				SetMem(_sp, _flags);
				break;
			case 70:
				SetRQ(op & 3, GetMem(_sp));
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 71:
				_x = XL | (XH << 4) | (GetMem(_sp) << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 72:
				_x = XL | (GetMem(_sp) << 4) | (XP << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 73:
				_x = GetMem(_sp) | (XH << 4) | (XP << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 74:
				_y = YL | (YH << 4) | (GetMem(_sp) << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 75:
				_y = YL | (GetMem(_sp) << 4) | (YP << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 76:
				_y = GetMem(_sp) | (YH << 4) | (YP << 8);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 77:
				_flags = (byte)(GetMem(_sp) & 0xFu);
				_sp = (byte)((uint)(_sp + 1) & 0xFFu);
				break;
			case 78:
				_sp = (byte)(SPL | (GetRQ(op & 3) << 4));
				break;
			case 79:
				_sp = (byte)(GetRQ(op & 3) | (SPH << 4));
				break;
			case 80:
				SetRQ(op & 3, SPH);
				break;
			case 81:
				SetRQ(op & 3, SPL);
				break;
			case 82:
			{
				int num27 = GetRQ(num) + num2;
				if (D)
				{
					if (num27 >= 10)
					{
						SetRQ(num, (byte)((uint)(num27 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetRQ(num, (byte)num27);
						_flags &= 254;
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num27 & 0xFu));
					if (num27 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 83:
			{
				int num25 = GetRQ(num) + GetRQ(num2);
				if (D)
				{
					if (num25 >= 10)
					{
						SetRQ(num, (byte)((uint)(num25 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetRQ(num, (byte)num25);
						_flags &= 254;
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num25 & 0xFu));
					if (num25 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 84:
			{
				int num16 = GetRQ(num) + num2 + (C ? 1 : 0);
				if (D)
				{
					if (num16 >= 10)
					{
						SetRQ(num, (byte)((uint)(num16 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetRQ(num, (byte)num16);
						_flags &= 254;
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num16 & 0xFu));
					if (num16 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 85:
			{
				int num11 = GetRQ(num) + GetRQ(num2) + (C ? 1 : 0);
				if (D)
				{
					if (num11 >= 10)
					{
						SetRQ(num, (byte)((uint)(num11 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetRQ(num, (byte)num11);
						_flags &= 254;
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num11 & 0xFu));
					if (num11 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 86:
			{
				int num10 = GetRQ(num) - GetRQ(num2);
				if (D)
				{
					if (num10 >> 4 != 0)
					{
						SetRQ(num, (byte)((uint)(num10 - 6) & 0xFu));
					}
					else
					{
						SetRQ(num, (byte)((uint)num10 & 0xFu));
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num10 & 0xFu));
				}
				if (num10 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 87:
			{
				int num7 = GetRQ(num) - num2 - (C ? 1 : 0);
				if (D)
				{
					if (num7 >> 4 != 0)
					{
						SetRQ(num, (byte)((uint)(num7 - 6) & 0xFu));
					}
					else
					{
						SetRQ(num, (byte)((uint)num7 & 0xFu));
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num7 & 0xFu));
				}
				if (num7 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 88:
			{
				int num5 = GetRQ(num) - GetRQ(num2) - (C ? 1 : 0);
				if (D)
				{
					if (num5 >> 4 != 0)
					{
						SetRQ(num, (byte)((uint)(num5 - 6) & 0xFu));
					}
					else
					{
						SetRQ(num, (byte)((uint)num5 & 0xFu));
					}
				}
				else
				{
					SetRQ(num, (byte)((uint)num5 & 0xFu));
				}
				if (num5 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 89:
				SetRQ(num, (byte)(GetRQ(num) & num2));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 90:
				SetRQ(num, (byte)(GetRQ(num) & GetRQ(num2)));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 91:
				SetRQ(num, (byte)(GetRQ(num) | num2));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 92:
				SetRQ(num, (byte)(GetRQ(num) | GetRQ(num2)));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 93:
				SetRQ(num, (byte)(GetRQ(num) ^ num2));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 94:
				SetRQ(num, (byte)(GetRQ(num) ^ GetRQ(num2)));
				if (GetRQ(num) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 95:
				if (GetRQ(num) < num2)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetRQ(num) == num2)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 96:
				if (GetRQ(num) < GetRQ(num2))
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetRQ(num) == GetRQ(num2))
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 97:
				if ((GetRQ(num) & num2) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 98:
				if ((GetRQ(num) & GetRQ(num2)) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			case 99:
			{
				byte rQ2 = GetRQ(op & 3);
				byte num19 = (byte)((rQ2 >> 3) & 1);
				SetRQ(op & 3, (byte)(((uint)(rQ2 << 1) | (C ? 1u : 0u)) & 0xFu));
				if (num19 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				break;
			}
			case 100:
			{
				byte rQ = GetRQ(op & 3);
				byte num15 = (byte)(rQ & 1);
				SetRQ(op & 3, (byte)((uint)((rQ >> 1) | ((C ? 1 : 0) << 3)) & 0xFu));
				if (num15 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				break;
			}
			case 101:
			{
				int num13 = GetMem(op & 0xF) + 1;
				SetMem(op & 0xF, (byte)((uint)num13 & 0xFu));
				if (num13 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num13 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 102:
			{
				int num12 = GetMem(op & 0xF) - 1;
				SetMem(op & 0xF, (byte)((uint)num12 & 0xFu));
				if (num12 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if ((num12 & 0xF) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 103:
			{
				int num9 = GetMem(_x) + GetRQ(op & 3) + (C ? 1 : 0);
				if (D)
				{
					if (num9 >= 10)
					{
						SetMem(_x, (byte)((uint)(num9 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetMem(_x, (byte)((uint)num9 & 0xFu));
						_flags &= 254;
					}
				}
				else
				{
					SetMem(_x, (byte)((uint)num9 & 0xFu));
					if (num9 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetMem(_x) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				_x = ((_x + 1) & 0xFF) | (XP << 8);
				break;
			}
			case 104:
			{
				int num8 = GetMem(_y) + GetRQ(op & 3) + (C ? 1 : 0);
				if (D)
				{
					if (num8 >= 10)
					{
						SetMem(_y, (byte)((uint)(num8 - 10) & 0xFu));
						_flags |= 1;
					}
					else
					{
						SetMem(_y, (byte)((uint)num8 & 0xFu));
						_flags &= 254;
					}
				}
				else
				{
					SetMem(_y, (byte)((uint)num8 & 0xFu));
					if (num8 >> 4 != 0)
					{
						_flags |= 1;
					}
					else
					{
						_flags &= 254;
					}
				}
				if (GetMem(_y) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				_y = ((_y + 1) & 0xFF) | (YP << 8);
				break;
			}
			case 105:
			{
				int num6 = GetMem(_x) - GetRQ(op & 3) - (C ? 1 : 0);
				if (D)
				{
					if (num6 >> 4 != 0)
					{
						SetMem(_x, (byte)((uint)(num6 - 6) & 0xFu));
					}
					else
					{
						SetMem(_x, (byte)((uint)num6 & 0xFu));
					}
				}
				else
				{
					SetMem(_x, (byte)((uint)num6 & 0xFu));
				}
				if (num6 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetMem(_x) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				_x = ((_x + 1) & 0xFF) | (XP << 8);
				break;
			}
			case 106:
			{
				int num3 = GetMem(_y) - GetRQ(op & 3) - (C ? 1 : 0);
				if (D)
				{
					if (num3 >> 4 != 0)
					{
						SetMem(_y, (byte)((uint)(num3 - 6) & 0xFu));
					}
					else
					{
						SetMem(_y, (byte)((uint)num3 & 0xFu));
					}
				}
				else
				{
					SetMem(_y, (byte)((uint)num3 & 0xFu));
				}
				if (num3 >> 4 != 0)
				{
					_flags |= 1;
				}
				else
				{
					_flags &= 254;
				}
				if (GetMem(_y) == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				_y = ((_y + 1) & 0xFF) | (YP << 8);
				break;
			}
			case 107:
			{
				byte b = (byte)((uint)(~GetRQ(num)) & 0xFu);
				SetRQ(num, b);
				if (b == 0)
				{
					_flags |= 2;
				}
				else
				{
					_flags &= 253;
				}
				break;
			}
			case 12:
			case 13:
				break;
			}
		}
	}
	public static class TamaState
	{
		private const string Magic = "TLST";

		private const byte Version = 3;

		private const int INT_SLOT_NUM = 6;

		private const int MEM_RAM_SIZE = 640;

		private const int MEM_IO_SIZE = 128;

		private const int MEM_IO_ADDR = 3840;

		private const int MaxSaveSlots = 5;

		public static byte[] Snapshot(TamaEmulator emu)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter w = new BinaryWriter(memoryStream);
			WriteState(w, emu);
			return memoryStream.ToArray();
		}

		public static void WriteSnapshot(byte[] snapshot, string savesFolder, string romName)
		{
			if (!Directory.Exists(savesFolder))
			{
				Directory.CreateDirectory(savesFolder);
			}
			File.WriteAllBytes(NextSavePath(savesFolder, romName), snapshot);
			List<string> sortedSlots = GetSortedSlots(savesFolder, romName);
			while (sortedSlots.Count > 5)
			{
				File.Delete(sortedSlots[0]);
				sortedSlots.RemoveAt(0);
			}
		}

		public static void Save(TamaEmulator emu, string savesFolder, string romName)
		{
			WriteSnapshot(Snapshot(emu), savesFolder, romName);
		}

		public static bool Load(TamaEmulator emu, string savesFolder, string romName)
		{
			string text = LastSavePath(savesFolder, romName);
			if (text == null)
			{
				return false;
			}
			return LoadFrom(emu, text);
		}

		public static bool LoadFrom(TamaEmulator emu, string path)
		{
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				using (FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read))
				{
					using BinaryReader binaryReader = new BinaryReader(input);
					byte[] array = binaryReader.ReadBytes(4);
					for (int i = 0; i < 4; i++)
					{
						if (array[i] != (byte)"TLST"[i])
						{
							return false;
						}
					}
					if (binaryReader.ReadByte() != 3)
					{
						return false;
					}
					lock (emu.Lock)
					{
						emu.PC = binaryReader.ReadByte() | ((binaryReader.ReadByte() & 0x1F) << 8);
						emu.X = binaryReader.ReadByte() | ((binaryReader.ReadByte() & 0xF) << 8);
						emu.Y = binaryReader.ReadByte() | ((binaryReader.ReadByte() & 0xF) << 8);
						emu.A = (byte)(binaryReader.ReadByte() & 0xFu);
						emu.B = (byte)(binaryReader.ReadByte() & 0xFu);
						emu.NP = (byte)(binaryReader.ReadByte() & 0x1Fu);
						emu.SP = binaryReader.ReadByte();
						emu.Flags = (byte)(binaryReader.ReadByte() & 0xFu);
						emu.TickCounter = ReadU32(binaryReader);
						emu.Clk2Hz = ReadU32(binaryReader);
						emu.Clk4Hz = ReadU32(binaryReader);
						emu.Clk8Hz = ReadU32(binaryReader);
						emu.Clk16Hz = ReadU32(binaryReader);
						emu.Clk32Hz = ReadU32(binaryReader);
						emu.Clk64Hz = ReadU32(binaryReader);
						emu.Clk128Hz = ReadU32(binaryReader);
						emu.Clk256Hz = ReadU32(binaryReader);
						emu.ProgTimerTs = ReadU32(binaryReader);
						emu.ProgTimerEnabled = binaryReader.ReadByte() != 0;
						emu.ProgTimerData = binaryReader.ReadByte();
						emu.ProgTimerRld = binaryReader.ReadByte();
						ReadU32(binaryReader);
						for (int j = 0; j < 6; j++)
						{
							emu.IntFactor[j] = (byte)(binaryReader.ReadByte() & 0xFu);
							emu.IntMask[j] = (byte)(binaryReader.ReadByte() & 0xFu);
							emu.IntTriggered[j] = binaryReader.ReadByte() != 0;
						}
						for (int k = 0; k < 640; k++)
						{
							emu.SetRamNibble(k, (byte)(binaryReader.ReadByte() & 0xFu));
						}
						for (int l = 0; l < 128; l++)
						{
							emu.SetIONibble(l, (byte)(binaryReader.ReadByte() & 0xFu));
						}
					}
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void WriteState(BinaryWriter w, TamaEmulator emu)
		{
			string text = "TLST";
			foreach (char c in text)
			{
				w.Write((byte)c);
			}
			w.Write((byte)3);
			lock (emu.Lock)
			{
				w.Write((byte)((uint)emu.PC & 0xFFu));
				w.Write((byte)((uint)(emu.PC >> 8) & 0x1Fu));
				w.Write((byte)((uint)emu.X & 0xFFu));
				w.Write((byte)((uint)(emu.X >> 8) & 0xFu));
				w.Write((byte)((uint)emu.Y & 0xFFu));
				w.Write((byte)((uint)(emu.Y >> 8) & 0xFu));
				w.Write((byte)(emu.A & 0xFu));
				w.Write((byte)(emu.B & 0xFu));
				w.Write((byte)(emu.NP & 0x1Fu));
				w.Write((byte)(emu.SP & 0xFFu));
				w.Write((byte)(emu.Flags & 0xFu));
				WriteU32(w, emu.TickCounter);
				WriteU32(w, emu.Clk2Hz);
				WriteU32(w, emu.Clk4Hz);
				WriteU32(w, emu.Clk8Hz);
				WriteU32(w, emu.Clk16Hz);
				WriteU32(w, emu.Clk32Hz);
				WriteU32(w, emu.Clk64Hz);
				WriteU32(w, emu.Clk128Hz);
				WriteU32(w, emu.Clk256Hz);
				WriteU32(w, emu.ProgTimerTs);
				w.Write((byte)(emu.ProgTimerEnabled ? 1u : 0u));
				w.Write((byte)(emu.ProgTimerData & 0xFFu));
				w.Write((byte)(emu.ProgTimerRld & 0xFFu));
				WriteU32(w, 0u);
				for (int j = 0; j < 6; j++)
				{
					w.Write((byte)(emu.IntFactor[j] & 0xFu));
					w.Write((byte)(emu.IntMask[j] & 0xFu));
					w.Write((byte)(emu.IntTriggered[j] ? 1u : 0u));
				}
				for (int k = 0; k < 640; k++)
				{
					w.Write((byte)(emu.GetRamNibble(k) & 0xFu));
				}
				for (int l = 0; l < 128; l++)
				{
					w.Write((byte)(emu.GetIONibble(l) & 0xFu));
				}
			}
		}

		public static string NextSavePath(string savesFolder, string romName)
		{
			List<string> sortedSlots = GetSortedSlots(savesFolder, romName);
			int slot = ((sortedSlots.Count != 0) ? (ParseSlot(sortedSlots[sortedSlots.Count - 1], romName) + 1) : 0);
			return SavePath(savesFolder, romName, slot);
		}

		public static string LastSavePath(string savesFolder, string romName)
		{
			List<string> sortedSlots = GetSortedSlots(savesFolder, romName);
			if (sortedSlots.Count != 0)
			{
				return sortedSlots[sortedSlots.Count - 1];
			}
			return null;
		}

		private static List<string> GetSortedSlots(string savesFolder, string romName)
		{
			if (!Directory.Exists(savesFolder))
			{
				return new List<string>();
			}
			List<string> list = new List<string>(Directory.GetFiles(savesFolder, romName + "_save*.bin"));
			list.Sort((string a, string b) => ParseSlot(a, romName).CompareTo(ParseSlot(b, romName)));
			return list;
		}

		private static int ParseSlot(string path, string romName)
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
			string text = romName + "_save";
			if (fileNameWithoutExtension.StartsWith(text) && int.TryParse(fileNameWithoutExtension.Substring(text.Length), out var result))
			{
				return result;
			}
			return 0;
		}

		public static string SavePath(string savesFolder, string romName, int slot)
		{
			return Path.Combine(savesFolder, $"{romName}_save{slot}.bin");
		}

		private static void WriteU32(BinaryWriter w, uint v)
		{
			w.Write((byte)(v & 0xFFu));
			w.Write((byte)((v >> 8) & 0xFFu));
			w.Write((byte)((v >> 16) & 0xFFu));
			w.Write((byte)((v >> 24) & 0xFFu));
		}

		private static uint ReadU32(BinaryReader r)
		{
			byte num = r.ReadByte();
			uint num2 = r.ReadByte();
			uint num3 = r.ReadByte();
			uint num4 = r.ReadByte();
			return num | (num2 << 8) | (num3 << 16) | (num4 << 24);
		}
	}
}
namespace TamaRush.Phone
{
	public class AppTamaRush : CustomApp
	{
		private TamaEmulator _emu;

		private Thread _emuThread;

		private volatile bool _emuRunning;

		private TamaRushAudio _audio;

		private GameObject _gameScreen;

		private RawImage _lcdImage;

		private Texture2D _lcdTex;

		private Image[] _iconImages;

		private const int IconSheetCols = 4;

		private const int IconSrcSize = 64;

		private const float IconSize = 144f;

		private const float IconRowGap = 8f;

		private string _romName;

		private GameObject _canvasGo;

		private TextMeshProUGUI _label;

		private Coroutine _hideCoroutine;

		private readonly Color32[] _lcdPixels = (Color32[])(object)new Color32[512];

		private readonly bool[] _iconStates = new bool[8];

		private float _autoSaveTimer;

		private bool _emuStartedThisSession;

		private const float AutoSaveInterval = 180f;

		private volatile int _cachedGameSpeed = 1;

		private static float LcdDisplayW => TamaRushPlugin.PixelSize.Value * 32;

		private static float LcdDisplayH => TamaRushPlugin.PixelSize.Value * 16;

		private static float TotalH => LcdDisplayH + 304f;

		public static void Initialize()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0062: 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)
			Sprite val = null;
			string appIconPath = TamaRushPlugin.GetAppIconPath("AppIcon.png");
			if (!string.IsNullOrEmpty(appIconPath) && File.Exists(appIconPath))
			{
				try
				{
					byte[] array = File.ReadAllBytes(appIconPath);
					Texture2D val2 = new Texture2D(2, 2);
					if (ImageConversion.LoadImage(val2, array))
					{
						((Texture)val2).wrapMode = (TextureWrapMode)1;
						((Texture)val2).filterMode = (FilterMode)1;
						val2.Apply();
						val = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f));
					}
				}
				catch
				{
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				PhoneAPI.RegisterApp<AppTamaRush>("TamaRush", val);
			}
			else
			{
				PhoneAPI.RegisterApp<AppTamaRush>("TamaRush", (Sprite)null);
			}
		}

		public override void OnAppInit()
		{
			((CustomApp)this).OnAppInit();
			((CustomApp)this).CreateIconlessTitleBar("TamaRush", 80f);
			base.ScrollView = PhoneScrollView.Create((CustomApp)(object)this, 275f, 1600f);
			TamaRushPlayMode.OnExitPlayMode = (Action)Delegate.Combine(TamaRushPlayMode.OnExitPlayMode, new Action(OnExitPlayMode));
			_audio = ((Component)TamaRushPlayMode.Instance).gameObject.GetComponent<TamaRushAudio>() ?? ((Component)TamaRushPlayMode.Instance).gameObject.AddComponent<TamaRushAudio>();
			ShowMainMenu();
		}

		public override void OnAppEnable()
		{
			((App)this).OnAppEnable();
			if (!TamaRushPlayMode.IsActive)
			{
				ShowMainMenu();
			}
		}

		public override void OnAppDisable()
		{
			((App)this).OnAppDisable();
			if (!TamaRushPlugin.RunInBackground.Value)
			{
				StopEmulator();
			}
		}

		public override void OnPressLeft()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Left, pressed: true);
			}
			else
			{
				((App)this).OnPressLeft();
			}
		}

		public override void OnReleaseLeft()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Left, pressed: false);
			}
			else
			{
				((App)this).OnReleaseLeft();
			}
		}

		public override void OnPressUp()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Middle, pressed: true);
			}
			else
			{
				((CustomApp)this).OnPressUp();
			}
		}

		public override void OnReleaseUp()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Middle, pressed: false);
			}
			else
			{
				((CustomApp)this).OnReleaseUp();
			}
		}

		public override void OnPressRight()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Right, pressed: true);
			}
			else
			{
				((CustomApp)this).OnPressRight();
			}
		}

		public override void OnReleaseRight()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Right, pressed: false);
			}
			else
			{
				((CustomApp)this).OnReleaseRight();
			}
		}

		public override void OnPressDown()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Tap, pressed: true);
			}
			else
			{
				((CustomApp)this).OnPressDown();
			}
		}

		public override void OnReleaseDown()
		{
			if (TamaRushPlayMode.IsActive)
			{
				_emu?.SetButton(TamaButton.Tap, pressed: false);
			}
			else
			{
				((CustomApp)this).OnReleaseDown();
			}
		}

		private void Update()
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			if (_emuStartedThisSession && _emuRunning && _emu != null && _romName != null && TamaRushPlugin.AutoSave.Value)
			{
				_autoSaveTimer += Time.deltaTime;
				if (_autoSaveTimer >= 180f)
				{
					_autoSaveTimer = 0f;
					SaveAsync();
				}
			}
			_cachedGameSpeed = TamaRushPlugin.GameSpeed?.Value ?? 1;
			if (_cachedGameSpeed < 0)
			{
				_cachedGameSpeed = 1;
			}
			if (!TamaRushPlayMode.IsActive || _emu == null || (Object)(object)_lcdTex == (Object)null || !_emuRunning || !_emu.LcdDirty)
			{
				return;
			}
			_emu.LcdDirty = false;
			bool[] array = ((_iconImages != null) ? _iconStates : null);
			int option = TamaRushPlugin.LcdOption?.Value ?? 0;
			lock (_emu.Lock)
			{
				for (int i = 0; i < 32; i++)
				{
					for (int j = 0; j < 16; j++)
					{
						int num = 15 - j;
						_lcdPixels[num * 32 + i] = GetLcdPixelColor(_emu.LcdMatrix[i, j], option);
					}
				}
				if (array != null)
				{
					for (int k = 0; k < 8; k++)
					{
						array[k] = _emu.LcdIcons[k];
					}
				}
			}
			_lcdTex.SetPixels32(_lcdPixels);
			_lcdTex.Apply(false, false);
			if (array != null)
			{
				for (int l = 0; l < 8; l++)
				{
					((Graphic)_iconImages[l]).color = (array[l] ? new Color(1f, 1f, 1f, 1f) : new Color(1f, 1f, 1f, 0.5f));
				}
			}
		}

		private void ShowMainMenu()
		{
			SetGameScreenVisible(visible: false);
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Play");
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(OnPlay));
			base.ScrollView.AddButton((PhoneButton)(object)val);
			if (_emuRunning && _emu != null)
			{
				SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Save Game");
				((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, (Action)delegate
				{
					SaveAsync();
				});
				base.ScrollView.AddButton((PhoneButton)(object)val2);
			}
			SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton("Settings");
			((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, new Action(ShowSettingsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val3);
		}

		private void ShowSettingsMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Game/ROM Options");
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(ShowGameRomOptionsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val);
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Save Options");
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, new Action(ShowSaveOptionsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val2);
			SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton("Customize Options");
			((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, new Action(ShowCustomizeMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val3);
			SimplePhoneButton val4 = PhoneUIUtility.CreateSimpleButton("Audio Options");
			((PhoneButton)val4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val4).OnConfirm, new Action(ShowAudioOptionsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val4);
			if (TamaRushPlugin.DebugMode.Value)
			{
				SimplePhoneButton val5 = PhoneUIUtility.CreateSimpleButton("Debug Options");
				((PhoneButton)val5).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val5).OnConfirm, new Action(ShowDebugOptionsMenu));
				base.ScrollView.AddButton((PhoneButton)(object)val5);
			}
			SimplePhoneButton val6 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val6).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val6).OnConfirm, new Action(ShowMainMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val6);
		}

		private void ShowSaveOptionsMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton autoSaveBtn = PhoneUIUtility.CreateSimpleButton(GetAutoSaveLabel());
			SimplePhoneButton obj = autoSaveBtn;
			((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate
			{
				TamaRushPlugin.AutoSave.Value = !TamaRushPlugin.AutoSave.Value;
				((TMP_Text)autoSaveBtn.Label).text = GetAutoSaveLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)autoSaveBtn);
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Backup Save");
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(SaveFileBackedUp));
			base.ScrollView.AddButton((PhoneButton)(object)val);
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Open Saves Folder");
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, new Action(OpenSavesFolder));
			base.ScrollView.AddButton((PhoneButton)(object)val2);
			SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton("Open Backups Folder");
			((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, new Action(OpenBackupsFolder));
			base.ScrollView.AddButton((PhoneButton)(object)val3);
			SimplePhoneButton val4 = PhoneUIUtility.CreateSimpleButton("Delete Save File");
			((PhoneButton)val4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val4).OnConfirm, new Action(SaveFileDeleted));
			base.ScrollView.AddButton((PhoneButton)(object)val4);
			SimplePhoneButton val5 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val5).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val5).OnConfirm, new Action(ShowMainMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val5);
		}

		private void ShowGameRomOptionsMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(GetSelectedRomLabel());
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(ShowRomSelectMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val);
			SimplePhoneButton ribBtn = PhoneUIUtility.CreateSimpleButton(GetRunInBackgroundLabel());
			SimplePhoneButton obj = ribBtn;
			((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate
			{
				TamaRushPlugin.RunInBackground.Value = !TamaRushPlugin.RunInBackground.Value;
				((TMP_Text)ribBtn.Label).text = GetRunInBackgroundLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)ribBtn);
			SimplePhoneButton speedBtn = PhoneUIUtility.CreateSimpleButton(GetGameSpeedLabel());
			SimplePhoneButton obj2 = speedBtn;
			((PhoneButton)obj2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj2).OnConfirm, (Action)delegate
			{
				int value = TamaRushPlugin.GameSpeed.Value;
				TamaRushPlugin.GameSpeed.Value = value switch
				{
					4 => 6, 
					2 => 4, 
					1 => 2, 
					_ => 1, 
				};
				((TMP_Text)speedBtn.Label).text = GetGameSpeedLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)speedBtn);
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Game Folder");
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, new Action(OpenRomsFolder));
			base.ScrollView.AddButton((PhoneButton)(object)val2);
			SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, new Action(ShowSettingsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val3);
		}

		private void ShowRomSelectMenu()
		{
			base.ScrollView.RemoveAllButtons();
			string path = Path.Combine(TamaRushPlugin.TamaRushFolderPath, "Roms");
			string[] array = (Directory.Exists(path) ? Directory.GetFiles(path, "*.bin") : new string[0]);
			if (array.Length == 0)
			{
				base.ScrollView.AddButton((PhoneButton)(object)PhoneUIUtility.CreateSimpleButton("No ROMs found"));
			}
			else
			{
				string effectiveRomPath = GetEffectiveRomPath();
				string[] array2 = array;
				foreach (string text in array2)
				{
					string captured = text;
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
					SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton((string.Equals(captured, effectiveRomPath, StringComparison.OrdinalIgnoreCase) ? "> " : "") + fileNameWithoutExtension);
					((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate
					{
						TamaRushPlugin.SelectedRom.Value = captured;
						ShowGameRomOptionsMenu();
					});
					base.ScrollView.AddButton((PhoneButton)(object)val);
				}
			}
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, new Action(ShowGameRomOptionsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val2);
		}

		private void ShowDebugOptionsMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton DebugspeedBtn = PhoneUIUtility.CreateSimpleButton(GetDebugGameSpeedLabel());
			SimplePhoneButton obj = DebugspeedBtn;
			((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate
			{
				int value = TamaRushPlugin.GameSpeed.Value;
				TamaRushPlugin.GameSpeed.Value = value switch
				{
					6 => 0, 
					4 => 6, 
					2 => 4, 
					1 => 2, 
					_ => 1, 
				};
				((TMP_Text)DebugspeedBtn.Label).text = GetDebugGameSpeedLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)DebugspeedBtn);
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(ShowSettingsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val);
		}

		private void ShowAssetSelectMenu(string subfolder, ConfigEntry<string> config, Action onSelected)
		{
			base.ScrollView.RemoveAllButtons();
			string path = Path.Combine(TamaRushPlugin.GetAssetSubfolderPath(), subfolder);
			List<string> list = new List<string>();
			if (Directory.Exists(path))
			{
				string[] files = Directory.GetFiles(path, "*.*");
				foreach (string text in files)
				{
					switch (Path.GetExtension(text).ToLowerInvariant())
					{
					case ".png":
					case ".jpg":
					case ".jpeg":
						list.Add(text);
						break;
					}
				}
			}
			if (list.Count == 0)
			{
				base.ScrollView.AddButton((PhoneButton)(object)PhoneUIUtility.CreateSimpleButton("No files found"));
			}
			else
			{
				string assetFolderFile = TamaRushPlugin.GetAssetFolderFile(subfolder);
				foreach (string item in list)
				{
					string captured = item;
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item);
					SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton((string.Equals(captured, assetFolderFile, StringComparison.OrdinalIgnoreCase) ? "> " : "") + fileNameWithoutExtension);
					((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate
					{
						config.Value = captured;
						onSelected?.Invoke();
						ShowCustomizeMenu();
					});
					base.ScrollView.AddButton((PhoneButton)(object)val);
				}
			}
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, new Action(ShowCustomizeMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val2);
		}

		private void RebuildGameScreen()
		{
			if ((Object)(object)_gameScreen != (Object)null)
			{
				Object.Destroy((Object)(object)_gameScreen);
				_gameScreen = null;
				_lcdImage = null;
				_lcdTex = null;
				_iconImages = null;
			}
			Transform val = ((Transform)((App)this).Content).Find("TamaRush_BG");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			if (_emuRunning)
			{
				EnsureGameScreen();
				SetGameScreenVisible(visible: true);
			}
		}

		private static string GetRunInBackgroundLabel()
		{
			return "Run In Background: " + (TamaRushPlugin.RunInBackground.Value ? "On" : "Off");
		}

		private static string GetGameSpeedLabel()
		{
			int value = TamaRushPlugin.GameSpeed.Value;
			return "Game Speed: " + ((value >= 6) ? "6x" : ((value >= 4) ? "4x" : ((value >= 2) ? "2x" : "Normal")));
		}

		private static string GetDebugGameSpeedLabel()
		{
			int value = TamaRushPlugin.GameSpeed.Value;
			return "Game Speed: " + ((value == 0) ? "Unlimited" : ((value >= 6) ? "6x" : ((value >= 4) ? "4x" : ((value >= 2) ? "2x" : "Normal"))));
		}

		private void ShowCustomizeMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton lcdBtn = PhoneUIUtility.CreateSimpleButton(GetLcdOptionLabel());
			SimplePhoneButton obj = lcdBtn;
			((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate
			{
				TamaRushPlugin.LcdOption.Value = (TamaRushPlugin.LcdOption.Value + 1) % 18;
				((TMP_Text)lcdBtn.Label).text = GetLcdOptionLabel();
				if (_emu != null)
				{
					_emu.LcdDirty = true;
				}
			});
			base.ScrollView.AddButton((PhoneButton)(object)lcdBtn);
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton(GetSelectedAssetLabel("Background", TamaRushPlugin.SelectedBackground?.Value));
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, (Action)delegate
			{
				ShowAssetSelectMenu("Background", TamaRushPlugin.SelectedBackground, RebuildGameScreen);
			});
			base.ScrollView.AddButton((PhoneButton)(object)val);
			SimplePhoneButton val2 = PhoneUIUtility.CreateSimpleButton(GetSelectedAssetLabel("Icons", TamaRushPlugin.SelectedIcons?.Value));
			((PhoneButton)val2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val2).OnConfirm, (Action)delegate
			{
				ShowAssetSelectMenu("Icons", TamaRushPlugin.SelectedIcons, RebuildGameScreen);
			});
			base.ScrollView.AddButton((PhoneButton)(object)val2);
			SimplePhoneButton pixelBtn = PhoneUIUtility.CreateSimpleButton(GetPixelSizeLabel());
			SimplePhoneButton obj2 = pixelBtn;
			((PhoneButton)obj2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj2).OnConfirm, (Action)delegate
			{
				int[] array = new int[10] { 8, 10, 12, 14, 16, 18, 20, 24, 28, 32 };
				int value = TamaRushPlugin.PixelSize.Value;
				int num = Array.IndexOf(array, value);
				TamaRushPlugin.PixelSize.Value = array[(num + 1) % array.Length];
				((TMP_Text)pixelBtn.Label).text = GetPixelSizeLabel();
				RebuildGameScreen();
			});
			base.ScrollView.AddButton((PhoneButton)(object)pixelBtn);
			SimplePhoneButton val3 = PhoneUIUtility.CreateSimpleButton("Background Folder");
			((PhoneButton)val3).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val3).OnConfirm, new Action(OpenBackgroundFolder));
			base.ScrollView.AddButton((PhoneButton)(object)val3);
			SimplePhoneButton val4 = PhoneUIUtility.CreateSimpleButton("Icons Folder");
			((PhoneButton)val4).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val4).OnConfirm, new Action(OpenIconsFolder));
			base.ScrollView.AddButton((PhoneButton)(object)val4);
			SimplePhoneButton val5 = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val5).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val5).OnConfirm, new Action(ShowSettingsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val5);
		}

		private void ShowAudioOptionsMenu()
		{
			base.ScrollView.RemoveAllButtons();
			SimplePhoneButton audioBtn = PhoneUIUtility.CreateSimpleButton(GetAudioLabel());
			SimplePhoneButton obj = audioBtn;
			((PhoneButton)obj).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj).OnConfirm, (Action)delegate
			{
				TamaRushPlugin.AudioEnabled.Value = !TamaRushPlugin.AudioEnabled.Value;
				((TMP_Text)audioBtn.Label).text = GetAudioLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)audioBtn);
			SimplePhoneButton volumeBtn = PhoneUIUtility.CreateSimpleButton(GetVolumeLabel());
			SimplePhoneButton obj2 = volumeBtn;
			((PhoneButton)obj2).OnConfirm = (Action)Delegate.Combine(((PhoneButton)obj2).OnConfirm, (Action)delegate
			{
				int value = TamaRushPlugin.AudioVolume.Value;
				TamaRushPlugin.AudioVolume.Value = ((value >= 10) ? 1 : (value + 1));
				((TMP_Text)volumeBtn.Label).text = GetVolumeLabel();
			});
			base.ScrollView.AddButton((PhoneButton)(object)volumeBtn);
			SimplePhoneButton val = PhoneUIUtility.CreateSimpleButton("Back");
			((PhoneButton)val).OnConfirm = (Action)Delegate.Combine(((PhoneButton)val).OnConfirm, new Action(ShowSettingsMenu));
			base.ScrollView.AddButton((PhoneButton)(object)val);
		}

		private static string GetAutoSaveLabel()
		{
			return "Auto Save: " + (TamaRushPlugin.AutoSave.Value ? "On" : "Off");
		}

		private static string GetAudioLabel()
		{
			return "Audio: " + (TamaRushPlugin.AudioEnabled.Value ? "On" : "Off");
		}

		private static string GetVolumeLabel()
		{
			return $"Volume: {TamaRushPlugin.AudioVolume.Value}/10";
		}

		private static string GetPixelSizeLabel()
		{
			return "Pixel Size: " + ((TamaRushPlugin.PixelSize.Value == 32) ? "Default" : TamaRushPlugin.PixelSize.Value.ToString());
		}

		private static string GetLcdOptionLabel()
		{
			string[] array = new string[18]
			{
				"Mono", "Classic", "Green", "Inverted", "Blue", "Red", "Lime", "Cyan", "Yellow", "Grey",
				"HotPink", "Orange", "Purple", "Pink", "Crimson", "Bisque", "SaddleBrown", "SpringGreen"
			};
			return "LCD: " + array[(TamaRushPlugin.LcdOption?.Value ?? 0) % array.Length];
		}

		private static string GetSelectedRomLabel()
		{
			string effectiveRomPath = GetEffectiveRomPath();
			return "Selected ROM: " + ((effectiveRomPath != null) ? Path.GetFileNameWithoutExtension(effectiveRomPath) : "None");
		}

		private static string GetSelectedAssetLabel(string assetType, string path)
		{
			if (!string.IsNullOrEmpty(path) && File.Exists(path))
			{
				return assetType + ": " + Path.GetFileNameWithoutExtension(path);
			}
			string assetFolderFile = TamaRushPlugin.GetAssetFolderFile(assetType);
			return assetType + ": " + ((assetFolderFile != null) ? Path.GetFileNameWithoutExtension(assetFolderFile) : "None");
		}

		private static string GetEffectiveRomPath()
		{
			string path = Path.Combine(TamaRushPlugin.TamaRushFolderPath, "Roms");
			string value = TamaRushPlugin.SelectedRom.Value;
			if (!string.IsNullOrEmpty(value) && File.Exists(value))
			{
				return value;
			}
			if (!Directory.Exists(path))
			{
				return null;
			}
			string[] files = Directory.GetFiles(path, "*.bin");
			if (files.Length == 0)
			{
				return null;
			}
			return files[0];
		}

		private static Color32 GetLcdPixelColor(bool on, int option)
		{
			//IL_007a: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			switch (option)
			{
			case 1:
				if (!on)
				{
					return new Color32((byte)216, (byte)216, (byte)192, byte.MaxValue);
				}
				return new Color32((byte)0, (byte)0, (byte)128, byte.MaxValue);
			case 2:
				if (!on)
				{
					return new Color32((byte)139, (byte)172, (byte)15, byte.MaxValue);
				}
				return new Color32((byte)15, (byte)56, (byte)15, byte.MaxValue);
			case 3:
				if (!on)
				{
					return new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			case 4:
				if (!on)
				{
					return new Color32((byte)0, (byte)20, (byte)40, byte.MaxValue);
				}
				return new Color32((byte)0, (byte)100, byte.MaxValue, byte.MaxValue);
			case 5:
				if (!on)
				{
					return new Color32((byte)40, (byte)0, (byte)0, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, (byte)0, (byte)0, byte.MaxValue);
			case 6:
				if (!on)
				{
					return new Color32((byte)0, (byte)40, (byte)0, byte.MaxValue);
				}
				return new Color32((byte)0, byte.MaxValue, (byte)0, byte.MaxValue);
			case 7:
				if (!on)
				{
					return new Color32((byte)0, (byte)40, (byte)40, byte.MaxValue);
				}
				return new Color32((byte)0, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			case 8:
				if (!on)
				{
					return new Color32((byte)40, (byte)40, (byte)0, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, byte.MaxValue, (byte)0, byte.MaxValue);
			case 9:
				if (!on)
				{
					return new Color32((byte)32, (byte)32, (byte)32, byte.MaxValue);
				}
				return new Color32((byte)192, (byte)192, (byte)192, byte.MaxValue);
			case 10:
				if (!on)
				{
					return new Color32((byte)60, (byte)20, (byte)40, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, (byte)105, (byte)180, byte.MaxValue);
			case 11:
				if (!on)
				{
					return new Color32((byte)50, (byte)30, (byte)0, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, (byte)165, (byte)0, byte.MaxValue);
			case 12:
				if (!on)
				{
					return new Color32((byte)30, (byte)0, (byte)50, byte.MaxValue);
				}
				return new Color32((byte)148, (byte)0, (byte)211, byte.MaxValue);
			case 13:
				if (!on)
				{
					return new Color32((byte)50, (byte)30, (byte)35, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, (byte)192, (byte)203, byte.MaxValue);
			case 14:
				if (!on)
				{
					return new Color32((byte)45, (byte)5, (byte)15, byte.MaxValue);
				}
				return new Color32((byte)220, (byte)20, (byte)60, byte.MaxValue);
			case 15:
				if (!on)
				{
					return new Color32((byte)50, (byte)40, (byte)35, byte.MaxValue);
				}
				return new Color32(byte.MaxValue, (byte)228, (byte)196, byte.MaxValue);
			case 16:
				if (!on)
				{
					return new Color32((byte)30, (byte)15, (byte)5, byte.MaxValue);
				}
				return new Color32((byte)139, (byte)69, (byte)19, byte.MaxValue);
			case 17:
				if (!on)
				{
					return new Color32((byte)0, (byte)50, (byte)25, byte.MaxValue);
				}
				return new Color32((byte)0, byte.MaxValue, (byte)127, byte.MaxValue);
			default:
				if (!on)
				{
					return new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
				}
				return new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
			}
		}

		private void OnPlay()
		{
			if (_emuRunning && _emu != null)
			{
				SetGameScreenVisible(visible: true);
				TamaRushPlayMode.Enter();
				return;
			}
			string effectiveRomPath = GetEffectiveRomPath();
			if (effectiveRomPath != null)
			{
				_romName = Path.GetFileNameWithoutExtension(effectiveRomPath);
				byte[] array = File.ReadAllBytes(effectiveRomPath);
				ushort[] array2 = new ushort[array.Length / 2];
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i] = (ushort)(array[i * 2 + 1] | ((array[i * 2] & 0xF) << 8));
				}
				_emu = new TamaEmulator();
				_emu.Init(array2);
				TamaState.Load(_emu, GetSavesFolder(), _romName);
				EnsureGameScreen();
				SetGameScreenVisible(visible: true);
				TamaRushPlayMode.Enter();
				_audio?.SetEmulator(_emu);
				StartEmulator();
			}
		}

		private void OnExitPlayMode()
		{
			if (TamaRushPlugin.RunInBackground.Value)
			{
				SetGameScreenVisible(visible: false);
				ShowMainMenu();
				return;
			}
			if (_emu != null && _romName != null)
			{
				SaveAsync();
			}
			StopEmulator();
			ShowMainMenu();
		}

		private string GetSavesFolder()
		{
			return Path.Combine(TamaRushPlugin.TamaRushFolderPath, "Saves", _romName ?? "unknown");
		}

		private void SaveAsync()
		{
			if (_emu == null || _romName == null)
			{
				return;
			}
			string savesFolder = GetSavesFolder();
			byte[] snapshot = TamaState.Snapshot(_emu);
			ThreadPool.QueueUserWorkItem(delegate
			{
				try
				{
					TamaState.WriteSnapshot(snapshot, savesFolder, _romName);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[TamaRush] Save failed: " + ex));
				}
			});
		}

		private void StartEmulator()
		{
			_emuRunning = true;
			_emuStartedThisSession = true;
			_emuThread = new Thread((ThreadStart)delegate
			{
				try
				{
					while (_emuRunning)
					{
						_emu.Step(_cachedGameSpeed);
					}
				}
				catch (Exception ex)
				{
					_emuRunning = false;
					Debug.LogError((object)("[TamaRush] Emulator thread crashed: " + ex));
				}
			});
			_emuThread.IsBackground = true;
			_emuThread.Start();
		}

		private void StopEmulator()
		{
			_emuRunning = false;
			_emuThread?.Join(200);
			_emuThread = null;
			_audio?.SetEmulator(null);
		}

		private void EnsureGameScreen()
		{
			//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_006d: 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_0076: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_014d: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			//IL_01e9: 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)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Expected O, but got Unknown
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_gameScreen != (Object)null)
			{
				return;
			}
			GameObject val = new GameObject("TamaRush_BG", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(RawImage)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)((App)this).Content, false);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component.pivot = val2;
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(0f, -40f);
			component.sizeDelta = new Vector2(2000f, 2000f);
			((Transform)component).SetAsFirstSibling();
			RawImage component2 = val.GetComponent<RawImage>();
			((Graphic)component2).raycastTarget = false;
			Texture2D val4 = LoadTexture(TamaRushPlugin.GetAssetFolderFile("Background"));
			if ((Object)(object)val4 != (Object)null)
			{
				component2.texture = (Texture)(object)val4;
			}
			else
			{
				((Graphic)component2).color = new Color(0.85f, 0.85f, 0.75f);
			}
			_gameScreen = new GameObject("TamaRush_GameScreen", new Type[1] { typeof(RectTransform) });
			RectTransform component3 = _gameScreen.GetComponent<RectTransform>();
			((Transform)component3).SetParent((Transform)(object)((App)this).Content, false);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component3.pivot = val2;
			anchorMin = (component3.anchorMax = val2);
			component3.anchorMin = anchorMin;
			component3.anchoredPosition = new Vector2(0f, -70f);
			component3.sizeDelta = new Vector2(LcdDisplayW, TotalH);
			GameObject val6 = new GameObject("LCD", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(RawImage)
			});
			RectTransform component4 = val6.GetComponent<RectTransform>();
			((Transform)component4).SetParent((Transform)(object)component3, false);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component4.pivot = val2;
			anchorMin = (component4.anchorMax = val2);
			component4.anchorMin = anchorMin;
			component4.anchoredPosition = Vector2.zero;
			component4.sizeDelta = new Vector2(LcdDisplayW, LcdDisplayH);
			_lcdImage = val6.GetComponent<RawImage>();
			((Graphic)_lcdImage).color = Color.white;
			((Graphic)_lcdImage).raycastTarget = false;
			_lcdTex = new Texture2D(32, 16, (TextureFormat)4, false);
			((Texture)_lcdTex).filterMode = (FilterMode)0;
			((Texture)_lcdTex).wrapMode = (TextureWrapMode)1;
			Color32[] array = (Color32[])(object)new Color32[512];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			}
			_lcdTex.SetPixels32(array);
			_lcdTex.Apply(false, false);
			_lcdImage.texture = (Texture)(object)_lcdTex;
			Texture2D val8 = LoadTexture(TamaRushPlugin.GetAssetFolderFile("Icons"));
			_iconImages = (Image[])(object)new Image[8];
			float num = LcdDisplayH * 0.5f + 8f + 72f;
			float num2 = 0f - LcdDisplayH * 0.5f - 8f - 72f;
			float num3 = LcdDisplayW / 4f;
			Sprite[] array2 = null;
			if ((Object)(object)val8 != (Object)null)
			{
				array2 = (Sprite[])(object)new Sprite[8];
				int num4 = ((Texture)val8).height / 64;
				Rect val9 = default(Rect);
				for (int j = 0; j < 8; j++)
				{
					int num5 = j % 4;
					int num6 = j / 4;
					int num7 = num4 - 1 - num6;
					((Rect)(ref val9))..ctor((float)(num5 * 64), (float)(num7 * 64), 64f, 64f);
					array2[j] = Sprite.Create(val8, val9, new Vector2(0.5f, 0.5f));
				}
			}
			for (int k = 0; k < 8; k++)
			{
				int num8 = k % 4;
				int num9 = k / 4;
				float num10 = (0f - LcdDisplayW) * 0.5f + num3 * (float)num8 + num3 * 0.5f;
				float num11 = ((num9 == 1) ? num2 : num);
				GameObject val10 = new GameObject($"Icon{k}", new Type[3]
				{
					typeof(RectTra