Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Empress Gameboy Emulator v1.0.0
EmpressGameboy.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EmpressGameboy.Emulator; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EmpressGameboy")] [assembly: AssemblyTitle("EmpressGameboy")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmpressGameboy { internal sealed class EmpressGameboyConfig { internal ConfigEntry<bool> Enabled { get; } internal ConfigEntry<string> RomFolderPath { get; } internal ConfigEntry<string> PreferredRomFile { get; } internal ConfigEntry<string> BootRomPath { get; } internal ConfigEntry<string> SaveFolderPath { get; } internal ConfigEntry<int> FrameSyncFps { get; } internal ConfigEntry<float> InteractionDistance { get; } internal ConfigEntry<float> ScreenAssemblyOffsetY { get; } internal ConfigEntry<bool> EnableRomAudio { get; } internal ConfigEntry<float> RomAudioVolume { get; } internal ConfigEntry<float> RomAudioMinDistance { get; } internal ConfigEntry<float> RomAudioMaxDistance { get; } internal ConfigEntry<string> UpBinding { get; } internal ConfigEntry<string> DownBinding { get; } internal ConfigEntry<string> LeftBinding { get; } internal ConfigEntry<string> RightBinding { get; } internal ConfigEntry<string> ABinding { get; } internal ConfigEntry<string> BBinding { get; } internal ConfigEntry<string> StartBinding { get; } internal ConfigEntry<string> SelectBinding { get; } internal EmpressGameboyConfig(BaseUnityPlugin plugin) { //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Expected O, but got Unknown string? path = Path.GetDirectoryName(plugin.Info.Location) ?? Directory.GetCurrentDirectory(); string text = Path.Combine(path, "roms"); string text2 = Path.Combine(path, "saves"); Enabled = plugin.Config.Bind<bool>("General", "Enabled", true, "Enables the Empress Gameboy console."); RomFolderPath = plugin.Config.Bind<string>("Paths", "RomFolderPath", text, "Folder that contains user-supplied Game Boy ROM files."); PreferredRomFile = plugin.Config.Bind<string>("Paths", "PreferredRomFile", string.Empty, "Optional file name or absolute path for the ROM to load. Leave empty to auto-pick the first ROM found."); BootRomPath = plugin.Config.Bind<string>("Paths", "BootRomPath", string.Empty, "Optional file name or absolute path for a DMG boot ROM."); SaveFolderPath = plugin.Config.Bind<string>("Paths", "SaveFolderPath", text2, "Folder used for cartridge save files."); FrameSyncFps = plugin.Config.Bind<int>("Networking", "FrameSyncFps", 15, "How often the host sends screen updates to other players. Higher values are smoother but use more bandwidth."); InteractionDistance = plugin.Config.Bind<float>("Gameplay", "InteractionDistance", 2.4f, "Maximum distance to start using the Empress Gameboy."); ScreenAssemblyOffsetY = plugin.Config.Bind<float>("Appearance", "ScreenAssemblyOffsetY", 0.065f, "Raises or lowers the cabinet face and visible screen relative to the stand."); EnableRomAudio = plugin.Config.Bind<bool>("Audio", "EnableRomAudio", true, "Plays real ROM audio from the Empress Gameboy cabinet while someone is actively using it."); RomAudioVolume = plugin.Config.Bind<float>("Audio", "RomAudioVolume", 0.3f, new ConfigDescription("Volume multiplier for the Empress Gameboy speaker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); RomAudioMinDistance = plugin.Config.Bind<float>("Audio", "RomAudioMinDistance", 1.8f, new ConfigDescription("Distance where the Empress Gameboy speaker stays at full volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); RomAudioMaxDistance = plugin.Config.Bind<float>("Audio", "RomAudioMaxDistance", 3.85f, new ConfigDescription("Distance where the Empress Gameboy speaker becomes inaudible.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 40f), Array.Empty<object>())); UpBinding = plugin.Config.Bind<string>("Controls", "Up", "W,UpArrow", "Keys that act as Game Boy Up."); DownBinding = plugin.Config.Bind<string>("Controls", "Down", "S,DownArrow", "Keys that act as Game Boy Down."); LeftBinding = plugin.Config.Bind<string>("Controls", "Left", "A,LeftArrow", "Keys that act as Game Boy Left."); RightBinding = plugin.Config.Bind<string>("Controls", "Right", "D,RightArrow", "Keys that act as Game Boy Right."); ABinding = plugin.Config.Bind<string>("Controls", "AButton", "J,Z", "Keys that act as Game Boy A."); BBinding = plugin.Config.Bind<string>("Controls", "BButton", "K,X", "Keys that act as Game Boy B."); StartBinding = plugin.Config.Bind<string>("Controls", "Start", "Enter,NumpadEnter", "Keys that act as Game Boy Start."); SelectBinding = plugin.Config.Bind<string>("Controls", "Select", "RightShift,Space", "Keys that act as Game Boy Select."); } internal bool IsPressed(ConfigEntry<string> binding, Keyboard keyboard) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) foreach (Key item in ParseKeys(binding.Value)) { KeyControl obj = keyboard[item]; if (obj != null && ((ButtonControl)obj).isPressed) { return true; } } return false; } internal static string FormatBindingLabel(string configured) { string[] array = configured.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { array[i] = array[i].Trim(); } return string.Join("/", array); } private static IEnumerable<Key> ParseKeys(string configured) { string[] array = configured.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i].Trim(); if (text.Length != 0 && Enum.TryParse<Key>(text, ignoreCase: true, out Key result)) { yield return result; } } } } internal sealed class EmpressGameboyConsole : MonoBehaviour { private Material? _bodyMaterial; private Material? _screenMaterial; private Transform? _screenAssemblyRoot; internal Collider? InteractionCollider { get; private set; } internal Renderer? ScreenRenderer { get; private set; } internal void Initialize(Texture texture, float screenAssemblyOffsetY) { CreateGeometry(); SetScreenAssemblyOffset(screenAssemblyOffsetY); ApplyTexture(texture); } internal void ApplyTexture(Texture texture) { if ((Object)(object)_screenMaterial != (Object)null) { _screenMaterial.mainTexture = texture; } } internal void SetScreenAssemblyOffset(float offsetY) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_screenAssemblyRoot == (Object)null)) { Vector3 localPosition = _screenAssemblyRoot.localPosition; localPosition.y = offsetY; _screenAssemblyRoot.localPosition = localPosition; } } internal bool Contains(Collider collider) { if ((Object)(object)collider != (Object)null) { return ((Component)collider).transform.IsChildOf(((Component)this).transform); } return false; } private void CreateGeometry() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_021b: 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_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)InteractionCollider != (Object)null)) { _bodyMaterial = new Material(FindShader("Standard", "Sprites/Default")) { color = new Color(0.13f, 0.14f, 0.16f, 1f) }; _screenMaterial = new Material(FindShader("Unlit/Texture", "Sprites/Default")) { color = Color.white }; GameObject val = new GameObject("ScreenAssembly"); val.transform.SetParent(((Component)this).transform, false); _screenAssemblyRoot = val.transform; GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Body"; obj.transform.SetParent(_screenAssemblyRoot, false); obj.transform.localPosition = new Vector3(0f, 0.3f, 0f); obj.transform.localScale = new Vector3(0.7f, 0.48f, 0.16f); Renderer component = obj.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.material = _bodyMaterial; } BoxCollider component2 = obj.GetComponent<BoxCollider>(); if ((Object)(object)component2 != (Object)null) { ((Collider)component2).isTrigger = true; InteractionCollider = (Collider?)(object)component2; } GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj2).name = "Stand"; obj2.transform.SetParent(((Component)this).transform, false); obj2.transform.localPosition = new Vector3(0f, 0.08f, 0f); obj2.transform.localScale = new Vector3(0.28f, 0.12f, 0.24f); Renderer component3 = obj2.GetComponent<Renderer>(); if ((Object)(object)component3 != (Object)null) { component3.material = _bodyMaterial; } Collider component4 = obj2.GetComponent<Collider>(); if ((Object)(object)component4 != (Object)null) { component4.enabled = false; } GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val2).name = "Screen"; val2.transform.SetParent(_screenAssemblyRoot, false); val2.transform.localPosition = new Vector3(0f, 0.34f, 0.085f); val2.transform.localScale = new Vector3(0.56f, 0.4f, 1f); ScreenRenderer = val2.GetComponent<Renderer>(); if ((Object)(object)ScreenRenderer != (Object)null) { ScreenRenderer.material = _screenMaterial; } Collider component5 = val2.GetComponent<Collider>(); if ((Object)(object)component5 != (Object)null) { component5.enabled = false; } CreateButton(_screenAssemblyRoot, new Vector3(-0.19f, 0.08f, 0.085f), new Vector3(0.07f, 0.03f, 0.03f), new Color(0.86f, 0.27f, 0.33f, 1f)); CreateButton(_screenAssemblyRoot, new Vector3(0.19f, 0.08f, 0.085f), new Vector3(0.07f, 0.03f, 0.03f), new Color(0.27f, 0.76f, 0.61f, 1f)); CreateButton(_screenAssemblyRoot, new Vector3(0f, -0.02f, 0.085f), new Vector3(0.2f, 0.025f, 0.03f), new Color(0.36f, 0.38f, 0.42f, 1f)); } } private void CreateButton(Transform parent, Vector3 position, Vector3 scale, Color color) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); val.transform.SetParent(parent, false); val.transform.localPosition = position; val.transform.localScale = scale; Renderer component = val.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { Material material = new Material(FindShader("Standard", "Sprites/Default")) { color = color }; component.material = material; } Collider component2 = val.GetComponent<Collider>(); if ((Object)(object)component2 != (Object)null) { component2.enabled = false; } } private static Shader FindShader(params string[] names) { for (int i = 0; i < names.Length; i++) { Shader val = Shader.Find(names[i]); if ((Object)(object)val != (Object)null) { return val; } } throw new InvalidOperationException("Unable to find a shader for Empress Gameboy."); } private void OnDestroy() { if ((Object)(object)_bodyMaterial != (Object)null) { Object.Destroy((Object)(object)_bodyMaterial); _bodyMaterial = null; } if ((Object)(object)_screenMaterial != (Object)null) { Object.Destroy((Object)(object)_screenMaterial); _screenMaterial = null; } } } [BepInPlugin("com.empress.gameboy", "Empress Gameboy", "1.0.0")] public sealed class EmpressGameboyPlugin : BaseUnityPlugin { public const string PluginGuid = "com.empress.gameboy"; public const string PluginName = "Empress Gameboy"; public const string PluginVersion = "1.0.0"; private EmpressGameboyRuntime? _runtime; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown HideBepInExManagerObject(); EmpressGameboyConfig config = new EmpressGameboyConfig((BaseUnityPlugin)(object)this); GameObject val = new GameObject("EmpressGameboyRuntime"); Object.DontDestroyOnLoad((Object)(object)val); _runtime = val.AddComponent<EmpressGameboyRuntime>(); _runtime.Initialize(config, ((BaseUnityPlugin)this).Logger, Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Directory.GetCurrentDirectory()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Empress Gameboy loaded."); } private void HideBepInExManagerObject() { if (!((Object)(object)Chainloader.ManagerObject == (Object)null)) { ((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)Chainloader.ManagerObject); } } private void OnDestroy() { if ((Object)(object)_runtime != (Object)null) { Object.Destroy((Object)(object)((Component)_runtime).gameObject); _runtime = null; } } } internal sealed class EmpressGameboyRuntime : MonoBehaviour { private const byte ControlRequestEventCode = 190; private const byte InputStateEventCode = 191; private const byte FrameSyncEventCode = 192; private const byte StatusEventCode = 193; private const byte AudioSyncEventCode = 194; private const int FrameWidth = 160; private const int FrameHeight = 144; private const int FramePixelCount = 23040; private const int PackedFrameLength = 5760; private const float ConsoleScaleMultiplier = 2f; private static readonly FieldInfo? PlayerControllerAvatarField = AccessTools.Field(typeof(PlayerController), "playerAvatarScript"); private static readonly FieldInfo? PlayerAvatarIsDisabledField = AccessTools.Field(typeof(PlayerAvatar), "isDisabled"); private static readonly FieldInfo? GameDirectorCurrentStateField = AccessTools.Field(typeof(GameDirector), "currentState"); private static readonly FieldInfo? LevelGeneratorGeneratedField = AccessTools.Field(typeof(LevelGenerator), "Generated"); private static readonly FieldInfo? ShopManagerExtractionPointField = AccessTools.Field(typeof(ShopManager), "extractionPoint"); private static readonly FieldInfo? ExtractionPointSafetySpawnField = AccessTools.Field(typeof(ExtractionPoint), "safetySpawn"); private static readonly FieldInfo? ExtractionPointIsShopField = AccessTools.Field(typeof(ExtractionPoint), "isShop"); private static readonly FieldInfo? ExtractionPointInStartRoomField = AccessTools.Field(typeof(ExtractionPoint), "inStartRoom"); private static readonly Vector3 LevelConsoleHardcodedPosition = new Vector3(-2.031f, 1.738f, -19.573f); private static readonly Quaternion LevelConsoleHardcodedRotation = Quaternion.Euler(0f, 90f, 0f); private readonly Dictionary<int, string> _actorNameCache = new Dictionary<int, string>(); private EmpressGameboyConfig _config; private ManualLogSource _log; private string _pluginDirectory = string.Empty; private EmpressGameboyConsole? _console; private EmpressGameboySpeaker? _speaker; private Texture2D? _displayTexture; private Color32[]? _displayPixels; private Color32[] _palette = EmpressGameboyPalette.DefaultPalette; private byte[]? _lastPackedFrame; private EmpressGameboyHostEmulator? _hostEmulator; private float[]? _hostAudioScratch; private float[]? _networkAudioPacketBuffer; private float[]? _remoteAudioDecodeScratch; private string? _loadedRomPath; private string _sceneSignature = string.Empty; private string _statusMessage = "Waiting for a ROM."; private string _romDisplayName = "No ROM"; private bool _remoteMirrorDisplayInitialized; private bool _eventHookActive; private bool _hoveringConsole; private int _controllerActorNumber; private int _remoteInputMask; private int _localHeldInputMask; private int _lastSentInputMask = -1; private int _lastReceivedFrameId; private int _lastReceivedAudioPacketId; private int _broadcastFrameId; private int _broadcastAudioPacketId; private int _networkAudioPacketFill; private double _nextStatusSendTime; private double _nextFrameSendTime; private double _nextInputSendTime; private double _nextRomRetryTime; private double _nextSaveFlushTime; internal void Initialize(EmpressGameboyConfig config, ManualLogSource log, string pluginDirectory) { _config = config; _log = log; _pluginDirectory = pluginDirectory; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; ((Component)this).transform.parent = null; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); EnsureDisplayTexture(); } private void OnDestroy() { SetPhotonEventHook(active: false); CleanupConsole(); DisposeHostEmulator(); if ((Object)(object)_displayTexture != (Object)null) { Object.Destroy((Object)(object)_displayTexture); _displayTexture = null; } } private void Update() { if (!_config.Enabled.Value) { SetPhotonEventHook(active: false); CleanupConsole(); return; } SetPhotonEventHook(active: true); TickSceneBinding(); _speaker?.ApplySettings(_config.RomAudioVolume.Value, _config.RomAudioMinDistance.Value, _config.RomAudioMaxDistance.Value); RefreshSpeakerPlaybackState(); TickControllerInteraction(); TickHostEmulator(); TickControlLifecycle(); } private void OnGUI() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (_config.Enabled.Value && !((Object)(object)_displayTexture == (Object)null)) { string promptText = GetPromptText(); if (!string.IsNullOrWhiteSpace(promptText)) { GUIStyle val = new GUIStyle(GUI.skin.box) { fontSize = 16, alignment = (TextAnchor)4, wordWrap = true }; float num = Mathf.Min((float)Screen.width - 40f, 980f); GUI.Box(new Rect((float)Screen.width * 0.5f - num * 0.5f, (float)Screen.height - 130f, num, 92f), promptText, val); } } } private void TickSceneBinding() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.RunIsLobby()) { if (_sceneSignature != "lobby") { _sceneSignature = "lobby"; if (TryGetLobbyConsolePose(out var position, out var rotation)) { RebuildConsole(position, rotation); } else { CleanupConsole(); } } } else if (SemiFunc.RunIsLevel() && IsLevelGenerated()) { string text = $"level:{((Object)LevelGenerator.Instance).GetInstanceID()}"; if (_sceneSignature != text) { _sceneSignature = text; if (TryGetLevelConsolePose(out var position2, out var rotation2)) { RebuildConsole(position2, rotation2); } else { CleanupConsole(); } } } else if (SemiFunc.RunIsShop() && (Object)(object)ShopManager.instance != (Object)null) { string text2 = $"shop:{((Object)ShopManager.instance).GetInstanceID()}"; if (_sceneSignature != text2) { _sceneSignature = text2; if (TryGetShopConsolePose(out var position3, out var rotation3)) { RebuildConsole(position3, rotation3); } else { CleanupConsole(); } } } else if (_sceneSignature.Length > 0) { _sceneSignature = string.Empty; CleanupConsole(); ReleaseControlLocalOrNetwork(); } } private void TickControllerInteraction() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) _hoveringConsole = false; if ((Object)(object)_console == (Object)null || !CanUseConsolePrompt()) { return; } Camera val = SemiFunc.MainCamera(); Collider interactionCollider = _console.InteractionCollider; RaycastHit val2 = default(RaycastHit); if ((Object)(object)val == (Object)null || (Object)(object)interactionCollider == (Object)null || (Object)(object)PlayerController.instance == (Object)null || Vector3.Distance(((Component)PlayerController.instance).transform.position, ((Component)_console).transform.position) > _config.InteractionDistance.Value + 0.8f || !Physics.Raycast(((Component)val).transform.position, ((Component)val).transform.forward, ref val2, _config.InteractionDistance.Value + 1.2f, -5, (QueryTriggerInteraction)2) || !_console.Contains(((RaycastHit)(ref val2)).collider)) { return; } _hoveringConsole = true; if (SemiFunc.InputDown((InputKey)2)) { if (IsLocalController()) { ReleaseControlLocalOrNetwork(); } else { RequestControlLocalOrNetwork(); } } } private void TickControlLifecycle() { if (!IsLocalController()) { _localHeldInputMask = 0; return; } if ((Object)(object)_console == (Object)null || !CanMaintainControl()) { ReleaseControlLocalOrNetwork(); return; } SemiFunc.InputDisableMovement(); SemiFunc.InputDisableAiming(); PlayerController instance = PlayerController.instance; if (instance != null) { instance.InputDisable(0.12f); } if (SemiFunc.InputDown((InputKey)6) || SemiFunc.InputDown((InputKey)2)) { ReleaseControlLocalOrNetwork(); return; } _localHeldInputMask = ReadLocalInputMask(); if (HasHostAuthority()) { _hostEmulator?.SetInputMask(_localHeldInputMask); } else if (!(Time.unscaledTimeAsDouble < _nextInputSendTime) || _localHeldInputMask != _lastSentInputMask) { _nextInputSendTime = Time.unscaledTimeAsDouble + 0.05; _lastSentInputMask = _localHeldInputMask; SendInputState(_localHeldInputMask); } } private void TickHostEmulator() { if (!HasHostAuthority()) { EnterRemoteMirrorMode(); return; } _remoteMirrorDisplayInitialized = false; EnsureHostEmulator(); if (_hostEmulator == null) { if (PhotonNetwork.InRoom && Time.unscaledTimeAsDouble >= _nextStatusSendTime) { BroadcastStatus(force: true); } return; } if (!HasVisibleConsoleScene()) { if (PhotonNetwork.InRoom && Time.unscaledTimeAsDouble >= _nextStatusSendTime) { BroadcastStatus(force: true); } return; } int localActorNumber = GetLocalActorNumber(); int inputMask = 0; if (_controllerActorNumber == localActorNumber) { inputMask = _localHeldInputMask; } else if (_controllerActorNumber != 0) { inputMask = _remoteInputMask; } _hostEmulator.SetInputMask(inputMask); _hostEmulator.Step(Time.unscaledDeltaTime); TickHostAudio(); if (_hostEmulator.ConsumeFrameFlag()) { UpdateDisplayTexture(_hostEmulator.FrameBuffer); } if (Time.unscaledTimeAsDouble >= _nextSaveFlushTime) { _nextSaveFlushTime = Time.unscaledTimeAsDouble + 5.0; _hostEmulator.FlushSave(); } if (PhotonNetwork.InRoom && Time.unscaledTimeAsDouble >= _nextFrameSendTime) { _nextFrameSendTime = Time.unscaledTimeAsDouble + 1.0 / (double)Mathf.Clamp(_config.FrameSyncFps.Value, 4, 30); BroadcastFrame(); } if (PhotonNetwork.InRoom && Time.unscaledTimeAsDouble >= _nextStatusSendTime) { BroadcastStatus(force: true); } } private void EnterRemoteMirrorMode() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (_hostEmulator != null) { DisposeHostEmulator(); } _loadedRomPath = null; _networkAudioPacketFill = 0; if ((Object)(object)_speaker != (Object)null && _controllerActorNumber == 0) { _speaker.SetActive(active: false); } if (!_remoteMirrorDisplayInitialized) { _remoteMirrorDisplayInitialized = true; _romDisplayName = "Host Session"; _statusMessage = "Waiting for host sync."; _lastReceivedFrameId = 0; _lastReceivedAudioPacketId = 0; ClearDisplayTexture(new Color32((byte)18, (byte)22, (byte)24, byte.MaxValue)); } } private void TickHostAudio() { if (_hostEmulator == null) { return; } if (!_config.EnableRomAudio.Value || _controllerActorNumber == 0 || !((Object)(object)_speaker != (Object)null)) { _speaker?.SetActive(active: false); _hostEmulator.DiscardAudioSamples(); _networkAudioPacketFill = 0; return; } EnsureAudioScratchBuffers(); _speaker.SetActive(active: true); while (true) { int num = _hostEmulator.DequeueAudioSamples(_hostAudioScratch, _hostAudioScratch.Length); if (num > 0) { _speaker.QueueSamples(_hostAudioScratch, num); if (PhotonNetwork.InRoom) { AppendAudioPacketData(_hostAudioScratch, num); } continue; } break; } } private void EnsureHostEmulator() { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTimeAsDouble < _nextRomRetryTime) { return; } _nextRomRetryTime = Time.unscaledTimeAsDouble + 2.0; string text = ResolveRomPath(); if (string.IsNullOrWhiteSpace(text)) { if (_hostEmulator != null) { DisposeHostEmulator(); } _loadedRomPath = null; _statusMessage = "No ROM found in the configured folder."; _romDisplayName = "No ROM"; ClearDisplayTexture(new Color32((byte)18, (byte)22, (byte)24, byte.MaxValue)); return; } if (_hostEmulator != null && string.Equals(_loadedRomPath, text, StringComparison.OrdinalIgnoreCase)) { _statusMessage = "Ready"; _romDisplayName = _hostEmulator.DisplayName; return; } try { DisposeHostEmulator(); string text2 = ResolveConfiguredPath(_config.SaveFolderPath.Value, "saves"); string bootRomPath = ResolveBootRomPath(); Directory.CreateDirectory(Path.GetDirectoryName(text) ?? _pluginDirectory); Directory.CreateDirectory(text2); _hostEmulator = new EmpressGameboyHostEmulator(text, bootRomPath, text2); _loadedRomPath = text; _statusMessage = "Ready"; _romDisplayName = _hostEmulator.DisplayName; UpdateDisplayTexture(_hostEmulator.FrameBuffer); _log.LogInfo((object)("Empress Gameboy loaded ROM: " + _romDisplayName)); } catch (Exception ex) { DisposeHostEmulator(); _loadedRomPath = null; _statusMessage = "Failed to load ROM: " + ex.Message; _romDisplayName = "Load Error"; ClearDisplayTexture(new Color32((byte)54, (byte)18, (byte)18, byte.MaxValue)); _log.LogError((object)$"Empress Gameboy failed to load ROM: {ex}"); } } private void BroadcastFrame() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom && _hostEmulator != null) { byte[] array = PackFrame(_hostEmulator.FrameBuffer); if (_lastPackedFrame == null || !array.SequenceEqual(_lastPackedFrame)) { _lastPackedFrame = array; _broadcastFrameId++; object[] array2 = new object[2] { _broadcastFrameId, array }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)192, (object)array2, val, SendOptions.SendUnreliable); } } } private void BroadcastStatus(bool force) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom && (force || !(Time.unscaledTimeAsDouble < _nextStatusSendTime))) { _nextStatusSendTime = Time.unscaledTimeAsDouble + 1.0; object[] array = new object[4] { _controllerActorNumber, _romDisplayName, _statusMessage, (_hostEmulator != null) ? 1 : 0 }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)193, (object)array, val, SendOptions.SendReliable); } } private void RequestControlLocalOrNetwork() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (CanClaimControl()) { if (!PhotonNetwork.InRoom) { _controllerActorNumber = GetLocalActorNumber(); _statusMessage = "Ready"; _remoteInputMask = 0; RefreshSpeakerPlaybackState(); } else { object[] array = new object[1] { 1 }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)190, (object)array, val, SendOptions.SendReliable); } } } private void ReleaseControlLocalOrNetwork() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) _localHeldInputMask = 0; _lastSentInputMask = -1; _networkAudioPacketFill = 0; _speaker?.SetActive(active: false); if (!PhotonNetwork.InRoom) { if (_controllerActorNumber == GetLocalActorNumber()) { _controllerActorNumber = 0; } _hostEmulator?.SetInputMask(0); _hostEmulator?.DiscardAudioSamples(); } else if (_controllerActorNumber == GetLocalActorNumber()) { object[] array = new object[1] { 0 }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)190, (object)array, val, SendOptions.SendReliable); } } private void SendInputState(int inputMask) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom) { object[] array = new object[1] { inputMask }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)191, (object)array, val, SendOptions.SendUnreliable); } } private void SetPhotonEventHook(bool active) { if (active) { if (!_eventHookActive) { PhotonNetwork.NetworkingClient.EventReceived += OnPhotonEvent; _eventHookActive = true; } } else if (_eventHookActive) { PhotonNetwork.NetworkingClient.EventReceived -= OnPhotonEvent; _eventHookActive = false; } } private void OnPhotonEvent(EventData eventData) { switch (eventData.Code) { case 190: if (HasHostAuthority()) { HandleControlRequest(eventData.Sender, eventData.CustomData as object[]); } break; case 191: if (HasHostAuthority()) { HandleRemoteInputState(eventData.Sender, eventData.CustomData as object[]); } break; case 192: if (!HasHostAuthority()) { HandleFrameSync(eventData.CustomData as object[]); } break; case 193: if (!HasHostAuthority()) { HandleStatusSync(eventData.CustomData as object[]); } break; case 194: if (!HasHostAuthority()) { HandleAudioSync(eventData.CustomData as object[]); } break; } } private void HandleControlRequest(int senderActorNumber, object[]? payload) { if (payload == null || payload.Length == 0) { return; } if (Convert.ToInt32(payload[0]) == 1) { if (_hostEmulator == null) { _statusMessage = "Host has no ROM ready."; BroadcastStatus(force: true); return; } if (_controllerActorNumber == 0 || _controllerActorNumber == senderActorNumber) { _controllerActorNumber = senderActorNumber; _remoteInputMask = 0; } } else if (_controllerActorNumber == senderActorNumber) { _controllerActorNumber = 0; _remoteInputMask = 0; } RefreshSpeakerPlaybackState(); BroadcastStatus(force: true); } private void HandleRemoteInputState(int senderActorNumber, object[]? payload) { if (payload != null && payload.Length != 0 && _controllerActorNumber == senderActorNumber) { _remoteInputMask = Convert.ToInt32(payload[0]); } } private void HandleFrameSync(object[]? payload) { if (payload != null && payload.Length >= 2) { int num = Convert.ToInt32(payload[0]); if (num > _lastReceivedFrameId && payload[1] is byte[] array && array.Length == 5760) { _lastReceivedFrameId = num; UpdateDisplayTextureFromPackedFrame(array); } } } private void HandleStatusSync(object[]? payload) { if (payload != null && payload.Length >= 4) { _controllerActorNumber = Convert.ToInt32(payload[0]); _romDisplayName = Convert.ToString(payload[1]) ?? "Unknown ROM"; _statusMessage = Convert.ToString(payload[2]) ?? "Ready"; RefreshSpeakerPlaybackState(); } } private void HandleAudioSync(object[]? payload) { if (payload == null || payload.Length < 2) { return; } int num = Convert.ToInt32(payload[0]); if (num <= _lastReceivedAudioPacketId || !(payload[1] is byte[] array) || array.Length == 0 || ((uint)array.Length & (true ? 1u : 0u)) != 0) { return; } _lastReceivedAudioPacketId = num; if (!((Object)(object)_speaker == (Object)null) && _config.EnableRomAudio.Value && _controllerActorNumber != 0) { EnsureAudioScratchBuffers(); int num2 = array.Length / 2; for (int i = 0; i < num2; i++) { short num3 = (short)(array[i * 2] | (array[i * 2 + 1] << 8)); _remoteAudioDecodeScratch[i] = Mathf.Clamp((float)num3 / 32767f, -1f, 1f); } _speaker.SetActive(active: true); _speaker.QueueSamples(_remoteAudioDecodeScratch, num2); } } private void RebuildConsole(Vector3 position, Quaternion rotation) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) CleanupConsole(); EnsureDisplayTexture(); GameObject val = new GameObject("EmpressGameboyConsole"); val.transform.SetParent(((Component)this).transform, false); val.transform.position = position; val.transform.rotation = rotation; val.transform.localScale = Vector3.one * 2f; _console = val.AddComponent<EmpressGameboyConsole>(); _console.Initialize((Texture)(object)_displayTexture, _config.ScreenAssemblyOffsetY.Value); _speaker = val.AddComponent<EmpressGameboySpeaker>(); _speaker.Initialize(_config.RomAudioVolume.Value, _config.RomAudioMinDistance.Value, _config.RomAudioMaxDistance.Value); RefreshSpeakerPlaybackState(); } private void CleanupConsole() { if ((Object)(object)_console != (Object)null) { Object.Destroy((Object)(object)((Component)_console).gameObject); _console = null; } _speaker = null; _lastReceivedAudioPacketId = 0; _broadcastAudioPacketId = 0; _networkAudioPacketFill = 0; _remoteMirrorDisplayInitialized = false; _lastReceivedFrameId = 0; } private void EnsureAudioScratchBuffers() { if (_hostAudioScratch == null) { _hostAudioScratch = new float[512]; } if (_networkAudioPacketBuffer == null) { _networkAudioPacketBuffer = new float[512]; } if (_remoteAudioDecodeScratch == null) { _remoteAudioDecodeScratch = new float[512]; } } private void AppendAudioPacketData(float[] samples, int sampleCount) { EnsureAudioScratchBuffers(); int num = 0; while (num < sampleCount) { int num2 = Math.Min(sampleCount - num, _networkAudioPacketBuffer.Length - _networkAudioPacketFill); Array.Copy(samples, num, _networkAudioPacketBuffer, _networkAudioPacketFill, num2); _networkAudioPacketFill += num2; num += num2; if (_networkAudioPacketFill == _networkAudioPacketBuffer.Length) { BroadcastAudioSamples(_networkAudioPacketBuffer, _networkAudioPacketFill); _networkAudioPacketFill = 0; } } } private void BroadcastAudioSamples(float[] samples, int sampleCount) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom && sampleCount > 0) { byte[] array = new byte[sampleCount * 2]; for (int i = 0; i < sampleCount; i++) { short num = (short)Mathf.RoundToInt(Mathf.Clamp(samples[i], -1f, 1f) * 32767f); array[i * 2] = (byte)((uint)num & 0xFFu); array[i * 2 + 1] = (byte)((uint)(num >> 8) & 0xFFu); } _broadcastAudioPacketId++; object[] array2 = new object[2] { _broadcastAudioPacketId, array }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)194, (object)array2, val, SendOptions.SendUnreliable); } } private void RefreshSpeakerPlaybackState() { if (!((Object)(object)_speaker == (Object)null)) { bool active = _config.EnableRomAudio.Value && _controllerActorNumber != 0; _speaker.SetActive(active); } } private void DisposeHostEmulator() { if (_hostEmulator != null) { _hostEmulator.Dispose(); _hostEmulator = null; } } private void EnsureDisplayTexture() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_displayTexture != (Object)null)) { _displayTexture = new Texture2D(160, 144, (TextureFormat)4, false, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1, name = "EmpressGameboyDisplay" }; _displayPixels = (Color32[]?)(object)new Color32[23040]; ClearDisplayTexture(new Color32((byte)18, (byte)22, (byte)24, byte.MaxValue)); } } private void ClearDisplayTexture(Color32 color) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) EnsureDisplayTexture(); if (_displayPixels != null && !((Object)(object)_displayTexture == (Object)null)) { for (int i = 0; i < _displayPixels.Length; i++) { _displayPixels[i] = color; } _displayTexture.SetPixels32(_displayPixels); _displayTexture.Apply(false, false); } } private void UpdateDisplayTexture(IReadOnlyList<byte> frameBuffer) { EnsureDisplayTexture(); if (_displayPixels != null && !((Object)(object)_displayTexture == (Object)null) && frameBuffer.Count == 23040) { for (int i = 0; i < 23040; i++) { WriteDisplayPixel(i, frameBuffer[i]); } _displayTexture.SetPixels32(_displayPixels); _displayTexture.Apply(false, false); } } private void UpdateDisplayTextureFromPackedFrame(byte[] packedFrame) { EnsureDisplayTexture(); if (_displayPixels != null && !((Object)(object)_displayTexture == (Object)null)) { int num = 0; foreach (byte b in packedFrame) { WriteDisplayPixel(num++, (byte)(b & 3u)); WriteDisplayPixel(num++, (byte)((uint)(b >> 2) & 3u)); WriteDisplayPixel(num++, (byte)((uint)(b >> 4) & 3u)); WriteDisplayPixel(num++, (byte)((uint)(b >> 6) & 3u)); } _displayTexture.SetPixels32(_displayPixels); _displayTexture.Apply(false, false); } } private void WriteDisplayPixel(int sourcePixelIndex, byte paletteIndex) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (_displayPixels != null) { int num = sourcePixelIndex % 160; int num2 = sourcePixelIndex / 160; int num3 = (143 - num2) * 160 + (159 - num); _displayPixels[num3] = _palette[paletteIndex & 3]; } } private static byte[] PackFrame(IReadOnlyList<byte> frameBuffer) { byte[] array = new byte[5760]; int num = 0; for (int i = 0; i < 23040; i += 4) { array[num++] = (byte)((frameBuffer[i] & 3u) | (uint)((frameBuffer[i + 1] & 3) << 2) | (uint)((frameBuffer[i + 2] & 3) << 4) | (uint)((frameBuffer[i + 3] & 3) << 6)); } return array; } private bool TryGetLevelConsolePose(out Vector3 position, out Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) position = LevelConsoleHardcodedPosition; rotation = LevelConsoleHardcodedRotation; return true; } private bool TryGetLobbyConsolePose(out Vector3 position, out Quaternion rotation) { return TryGetTruckConsolePose(out position, out rotation); } private bool TryGetShopConsolePose(out Vector3 position, out Quaternion rotation) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) Transform val = GetShopExtractionAnchor(); if ((Object)(object)val == (Object)null) { ExtractionPoint val2 = ((IEnumerable<ExtractionPoint>)Object.FindObjectsOfType<ExtractionPoint>(true)).FirstOrDefault((Func<ExtractionPoint, bool>)IsShopExtractionPoint); val = (((Object)(object)val2 != (Object)null) ? ((Component)val2).transform : null); } if ((Object)(object)val != (Object)null) { Vector3 right = val.right; Vector3 val3; if (!(((Vector3)(ref right)).sqrMagnitude > 0.1f)) { val3 = Vector3.right; } else { right = val.right; val3 = ((Vector3)(ref right)).normalized; } Vector3 val4 = val3; position = val.position + val4 * 1.4f + Vector3.up * 0.45f; rotation = Quaternion.LookRotation(-val4, Vector3.up); return true; } position = Vector3.zero; rotation = Quaternion.identity; return false; } private static ExtractionPoint? FindStartRoomExtractionPoint() { return ((IEnumerable<ExtractionPoint>)Object.FindObjectsOfType<ExtractionPoint>(true)).FirstOrDefault((Func<ExtractionPoint, bool>)IsStartRoomExtractionPoint); } private bool TryGetTruckConsolePose(out Vector3 position, out Quaternion rotation) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TruckSafetySpawnPoint.instance != (Object)null) { Transform transform = ((Component)TruckSafetySpawnPoint.instance).transform; Vector3 val = FlattenDirection(transform.forward, Vector3.forward); Vector3 val2 = FlattenDirection(transform.right, Vector3.right); position = transform.position + val * 1.2f + val2 * 0.75f; rotation = Quaternion.LookRotation(-val, Vector3.up); return true; } if ((Object)(object)TruckScreenText.instance != (Object)null) { Transform transform2 = ((Component)TruckScreenText.instance).transform; Vector3 val3 = FlattenDirection(transform2.right, Vector3.right); position = transform2.position + val3 * 1.1f + Vector3.down * 0.78f; rotation = Quaternion.LookRotation(-val3, Vector3.up); return true; } position = Vector3.zero; rotation = Quaternion.identity; return false; } private bool CanUseConsolePrompt() { if (SemiFunc.NoTextInputsActive() && (Object)(object)GameDirector.instance != (Object)null && IsGameInMainState() && (Object)(object)PlayerController.instance != (Object)null) { return !IsLocalPlayerDisabled(); } return false; } private bool CanMaintainControl() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (CanUseConsolePrompt() && HasVisibleConsoleScene() && (Object)(object)_console != (Object)null) { return Vector3.Distance(((Component)PlayerController.instance).transform.position, ((Component)_console).transform.position) <= _config.InteractionDistance.Value + 1.4f; } return false; } private bool HasVisibleConsoleScene() { if (_sceneSignature.Length > 0) { return (Object)(object)_console != (Object)null; } return false; } private static bool IsLevelGenerated() { if ((Object)(object)LevelGenerator.Instance == (Object)null) { return false; } return ReadBoolField(LevelGeneratorGeneratedField, LevelGenerator.Instance); } private static bool IsGameInMainState() { if ((Object)(object)GameDirector.instance == (Object)null || GameDirectorCurrentStateField == null) { return false; } object value = GameDirectorCurrentStateField.GetValue(GameDirector.instance); if (value == null) { return false; } return Convert.ToInt32(value, CultureInfo.InvariantCulture) == 2; } private static bool IsLocalPlayerDisabled() { if ((Object)(object)PlayerController.instance == (Object)null) { return true; } object? obj = PlayerControllerAvatarField?.GetValue(PlayerController.instance); PlayerAvatar val = (PlayerAvatar)((obj is PlayerAvatar) ? obj : null); if ((Object)(object)val == (Object)null) { return true; } return ReadBoolField(PlayerAvatarIsDisabledField, val); } private static Transform? GetShopExtractionAnchor() { if (!((Object)(object)ShopManager.instance != (Object)null)) { return null; } object? obj = ShopManagerExtractionPointField?.GetValue(ShopManager.instance); return (Transform?)((obj is Transform) ? obj : null); } private static Transform? GetExtractionSafetySpawn(ExtractionPoint extractionPoint) { object? obj = ExtractionPointSafetySpawnField?.GetValue(extractionPoint); return (Transform?)((obj is Transform) ? obj : null); } private static bool IsShopExtractionPoint(ExtractionPoint? extractionPoint) { if ((Object)(object)extractionPoint != (Object)null) { return ReadBoolField(ExtractionPointIsShopField, extractionPoint); } return false; } private static bool IsStartRoomExtractionPoint(ExtractionPoint? extractionPoint) { if ((Object)(object)extractionPoint != (Object)null) { return ReadBoolField(ExtractionPointInStartRoomField, extractionPoint); } return false; } private static bool ReadBoolField(FieldInfo? field, object instance) { if (field == null) { return false; } object value = field.GetValue(instance); if (!(value is bool result)) { if (value is IConvertible convertible) { return convertible.ToBoolean(CultureInfo.InvariantCulture); } return false; } return result; } private static Vector3 FlattenDirection(Vector3 direction, Vector3 fallback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.ProjectOnPlane(direction, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude > 0.01f) { return ((Vector3)(ref val)).normalized; } return ((Vector3)(ref fallback)).normalized; } private bool HasHostAuthority() { if (!PhotonNetwork.InRoom) { return true; } return PhotonNetwork.IsMasterClient; } private bool CanClaimControl() { if ((Object)(object)_console == (Object)null) { return false; } if (!PhotonNetwork.InRoom) { return _hostEmulator != null; } if (_controllerActorNumber != 0 && _controllerActorNumber != GetLocalActorNumber()) { return false; } return true; } private bool IsLocalController() { if (_controllerActorNumber != 0) { return _controllerActorNumber == GetLocalActorNumber(); } return false; } private int GetLocalActorNumber() { if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) { return PhotonNetwork.LocalPlayer.ActorNumber; } return 1; } private string GetPromptText() { string text = "Controls: Up " + EmpressGameboyConfig.FormatBindingLabel(_config.UpBinding.Value) + " | Down " + EmpressGameboyConfig.FormatBindingLabel(_config.DownBinding.Value) + " | Left " + EmpressGameboyConfig.FormatBindingLabel(_config.LeftBinding.Value) + " | Right " + EmpressGameboyConfig.FormatBindingLabel(_config.RightBinding.Value) + "\nA " + EmpressGameboyConfig.FormatBindingLabel(_config.ABinding.Value) + " | B " + EmpressGameboyConfig.FormatBindingLabel(_config.BBinding.Value) + " | Start " + EmpressGameboyConfig.FormatBindingLabel(_config.StartBinding.Value) + " | Select " + EmpressGameboyConfig.FormatBindingLabel(_config.SelectBinding.Value); if (_hoveringConsole) { if (_controllerActorNumber == 0) { if (_hostEmulator != null || PhotonNetwork.InRoom) { return "Press E to play " + _romDisplayName + ".\n" + text; } return "Empress Gameboy is unavailable. Add a ROM to the configured folder."; } if (IsLocalController()) { return "Press E or Esc to stop playing " + _romDisplayName + ".\n" + text; } return "Empress Gameboy is in use by " + GetActorName(_controllerActorNumber) + ".\n" + text; } if (IsLocalController()) { return "Empress Gameboy is active.\n" + text; } return string.Empty; } private string GetActorName(int actorNumber) { if (actorNumber == 0) { return "Nobody"; } if (_actorNameCache.TryGetValue(actorNumber, out string value)) { return value; } if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.Players.TryGetValue(actorNumber, out var value2)) { string text = (string.IsNullOrWhiteSpace(value2.NickName) ? $"Player {actorNumber}" : value2.NickName); _actorNameCache[actorNumber] = text; return text; } return $"Player {actorNumber}"; } private int ReadLocalInputMask() { Keyboard current = Keyboard.current; if (current == null) { return 0; } int num = 0; if (_config.IsPressed(_config.ABinding, current)) { num |= 1; } if (_config.IsPressed(_config.BBinding, current)) { num |= 2; } if (_config.IsPressed(_config.StartBinding, current)) { num |= 8; } if (_config.IsPressed(_config.SelectBinding, current)) { num |= 4; } if (_config.IsPressed(_config.RightBinding, current)) { num |= 0x10; } if (_config.IsPressed(_config.LeftBinding, current)) { num |= 0x20; } if (_config.IsPressed(_config.UpBinding, current)) { num |= 0x40; } if (_config.IsPressed(_config.DownBinding, current)) { num |= 0x80; } return num; } private string ResolveRomPath() { string text = ResolveConfiguredPath(_config.RomFolderPath.Value, "roms"); Directory.CreateDirectory(text); string text2 = _config.PreferredRomFile.Value?.Trim() ?? string.Empty; if (!string.IsNullOrWhiteSpace(text2)) { string path2 = (Path.IsPathRooted(text2) ? text2 : Path.Combine(text, text2)); if (File.Exists(path2)) { return Path.GetFullPath(path2); } } string[] array = Directory.EnumerateFiles(text, "*.*", SearchOption.TopDirectoryOnly).Where(delegate(string path) { string text3 = Path.GetExtension(path).ToLowerInvariant(); return (text3 == ".gb" || text3 == ".gbc") ? true : false; }).OrderBy<string, string>((string path) => path, StringComparer.OrdinalIgnoreCase) .ToArray(); if (array.Length == 0) { return string.Empty; } return Path.GetFullPath(array[0]); } private string? ResolveBootRomPath() { string text = _config.BootRomPath.Value?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(text)) { return null; } string text2 = (Path.IsPathRooted(text) ? text : Path.GetFullPath(Path.Combine(_pluginDirectory, text))); if (!File.Exists(text2)) { return null; } return text2; } private string ResolveConfiguredPath(string configuredPath, string relativeFallback) { string text = (string.IsNullOrWhiteSpace(configuredPath) ? Path.Combine(_pluginDirectory, relativeFallback) : configuredPath.Trim()); if (!Path.IsPathRooted(text)) { return Path.GetFullPath(Path.Combine(_pluginDirectory, text)); } return text; } } internal sealed class EmpressGameboySpeaker : MonoBehaviour { private readonly object _bufferLock = new object(); private readonly float[] _sampleBuffer = new float[44100]; private AudioSource? _audioSource; private AudioClip? _streamClip; private int _readIndex; private int _writeIndex; private int _queuedSamples; private bool _active; internal void Initialize(float volume, float minDistance, float maxDistance) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown _audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); _audioSource.playOnAwake = false; _audioSource.loop = true; _audioSource.spatialBlend = 1f; _audioSource.rolloffMode = (AudioRolloffMode)1; _audioSource.dopplerLevel = 0f; _audioSource.spread = 0f; ApplySettings(volume, minDistance, maxDistance); _streamClip = AudioClip.Create("EmpressGameboyAudio", 11025, 1, 11025, true, new PCMReaderCallback(OnAudioRead)); _audioSource.clip = _streamClip; _audioSource.Play(); SetActive(active: false); } internal void ApplySettings(float volume, float minDistance, float maxDistance) { if (!((Object)(object)_audioSource == (Object)null)) { _audioSource.volume = Mathf.Clamp01(volume); _audioSource.minDistance = Mathf.Max(0.1f, minDistance); _audioSource.maxDistance = Mathf.Max(_audioSource.minDistance + 0.1f, maxDistance); } } internal void SetActive(bool active) { _active = active; if ((Object)(object)_audioSource != (Object)null) { _audioSource.mute = !active; } if (!active) { ClearQueuedSamples(); } } internal void QueueSamples(float[] samples, int sampleCount) { if (!_active || samples == null || sampleCount <= 0) { return; } lock (_bufferLock) { int num = Mathf.Min(sampleCount, samples.Length); for (int i = 0; i < num; i++) { if (_queuedSamples == _sampleBuffer.Length) { _readIndex = (_readIndex + 1) % _sampleBuffer.Length; _queuedSamples--; } _sampleBuffer[_writeIndex] = samples[i]; _writeIndex = (_writeIndex + 1) % _sampleBuffer.Length; _queuedSamples++; } } } internal void ClearQueuedSamples() { lock (_bufferLock) { _readIndex = 0; _writeIndex = 0; _queuedSamples = 0; } } private void OnAudioRead(float[] data) { Array.Clear(data, 0, data.Length); if (!_active) { return; } lock (_bufferLock) { for (int i = 0; i < data.Length; i++) { if (_queuedSamples <= 0) { break; } data[i] = _sampleBuffer[_readIndex]; _readIndex = (_readIndex + 1) % _sampleBuffer.Length; _queuedSamples--; } } } private void OnDestroy() { if ((Object)(object)_audioSource != (Object)null) { _audioSource.Stop(); _audioSource.clip = null; _audioSource = null; } if ((Object)(object)_streamClip != (Object)null) { Object.Destroy((Object)(object)_streamClip); _streamClip = null; } } } } namespace EmpressGameboy.Emulator { internal sealed class CPU { public byte A; public byte B; public byte C; public byte D; public byte E; public byte H; public byte L; public byte F; public ushort PC; public ushort SP; public bool zero; public bool negative; public bool halfCarry; public bool carry; public bool IME; private bool halted; private MMU mmu; public CPU(MMU mmu) { A = (B = (C = (D = (E = (H = (L = (F = 0))))))); PC = 0; SP = 0; zero = (negative = (halfCarry = (carry = false))); IME = false; this.mmu = mmu; } public void Reset() { A = 1; F = 176; UpdateFlagsFromF(); B = 0; C = 19; D = 0; E = 216; H = 1; L = 77; PC = 256; SP = 65534; mmu.JOYP = 207; mmu.DIV = 24; mmu.TIMA = 0; mmu.TMA = 0; mmu.TAC = 248; mmu.IF = 225; mmu.IE = 0; mmu.LCDC = 145; mmu.STAT = 133; mmu.SCY = 0; mmu.SCX = 0; mmu.LY = 0; mmu.LYC = 0; mmu.BGP = 252; mmu.OBP0 = byte.MaxValue; mmu.OBP1 = byte.MaxValue; mmu.WY = 0; mmu.WX = 0; mmu.Write(65360, A); } public int HandleInterrupts() { byte b = mmu.Read(65295); byte b2 = mmu.Read(ushort.MaxValue); byte b3 = (byte)(b & b2); if (b3 != 0) { halted = false; if (IME) { IME = false; for (int i = 0; i < 5; i++) { if ((b3 & (1 << i)) != 0) { mmu.Write(65295, (byte)(b & ~(1 << i))); SP--; mmu.Write(SP, (byte)((uint)(PC >> 8) & 0xFFu)); SP--; mmu.Write(SP, (byte)(PC & 0xFFu)); PC = GetInterruptHandlerAddress(i); return 20; } } } return 0; } if (halted && b3 != 0) { halted = false; } return 0; } private ushort GetInterruptHandlerAddress(int bit) { return bit switch { 0 => 64, 1 => 72, 2 => 80, 3 => 88, 4 => 96, _ => 0, }; } private void UpdateFFromFlags() { F = 0; if (zero) { F |= 128; } if (negative) { F |= 64; } if (halfCarry) { F |= 32; } if (carry) { F |= 16; } } public void UpdateFlagsFromF() { zero = (F & 0x80) != 0; negative = (F & 0x40) != 0; halfCarry = (F & 0x20) != 0; carry = (F & 0x10) != 0; } private ushort Get16BitReg(string pair) { return pair.ToLower() switch { "bc" => (ushort)((B << 8) | C), "de" => (ushort)((D << 8) | E), "hl" => (ushort)((H << 8) | L), "af" => (ushort)((A << 8) | F), _ => 0, }; } private void Load16BitReg(string pair, ushort value) { switch (pair.ToLower()) { case "bc": B = (byte)(value >> 8); C = (byte)(value & 0xFFu); break; case "de": D = (byte)(value >> 8); E = (byte)(value & 0xFFu); break; case "hl": H = (byte)(value >> 8); L = (byte)(value & 0xFFu); break; case "af": A = (byte)(value >> 8); F = (byte)(value & 0xFFu); break; } } public void Log() { } private byte Fetch() { return mmu.Read(PC++); } public int ExecuteInstruction() { int num = HandleInterrupts(); if (num > 0) { return num; } if (halted) { return 4; } byte b = Fetch(); return b switch { 0 => NOP(), 1 => LD_RR_U16(ref B, ref C), 2 => LD_ARR_R(ref A, "bc"), 3 => INC_RR("bc"), 4 => INC_R(ref B), 5 => DEC_R(ref B), 6 => LD_R_U8(ref B), 7 => RLCA(), 8 => LD_AU16_SP(), 9 => ADD_HL_RR("bc"), 10 => LD_R_ARR(ref A, "bc"), 11 => DEC_RR("bc"), 12 => INC_R(ref C), 13 => DEC_R(ref C), 14 => LD_R_U8(ref C), 15 => RRCA(), 16 => STOP(), 17 => LD_RR_U16(ref D, ref E), 18 => LD_ARR_R(ref A, "de"), 19 => INC_RR("de"), 20 => INC_R(ref D), 21 => DEC_R(ref D), 22 => LD_R_U8(ref D), 23 => RLA(), 24 => JR_CON_I8(flag: true), 25 => ADD_HL_RR("de"), 26 => LD_R_ARR(ref A, "de"), 27 => DEC_RR("de"), 28 => INC_R(ref E), 29 => DEC_R(ref E), 30 => LD_R_U8(ref E), 31 => RRA(), 32 => JR_CON_I8(!zero), 33 => LD_RR_U16(ref H, ref L), 34 => LD_AHLI_A(), 35 => INC_RR("hl"), 36 => INC_R(ref H), 37 => DEC_R(ref H), 38 => LD_R_U8(ref H), 39 => DAA(), 40 => JR_CON_I8(zero), 41 => ADD_HL_RR("hl"), 42 => LD_A_AHLI(), 43 => DEC_RR("hl"), 44 => INC_R(ref L), 45 => DEC_R(ref L), 46 => LD_R_U8(ref L), 47 => CPL(), 48 => JR_CON_I8(!carry), 49 => LD_SP_U16(), 50 => LD_AHLM_A(), 51 => INC_SP(), 52 => INC_AHL(), 53 => DEC_AHL(), 54 => LD_AHL_U8(), 55 => SCF(), 56 => JR_CON_I8(carry), 57 => ADD_HL_SP(), 58 => LD_A_AHLM(), 59 => DEC_SP(), 60 => INC_R(ref A), 61 => DEC_R(ref A), 62 => LD_R_U8(ref A), 63 => CCF(), 64 => LD_R1_R2(ref B, ref B), 65 => LD_R1_R2(ref B, ref C), 66 => LD_R1_R2(ref B, ref D), 67 => LD_R1_R2(ref B, ref E), 68 => LD_R1_R2(ref B, ref H), 69 => LD_R1_R2(ref B, ref L), 70 => LD_R_ARR(ref B, "hl"), 71 => LD_R1_R2(ref B, ref A), 72 => LD_R1_R2(ref C, ref B), 73 => LD_R1_R2(ref C, ref C), 74 => LD_R1_R2(ref C, ref D), 75 => LD_R1_R2(ref C, ref E), 76 => LD_R1_R2(ref C, ref H), 77 => LD_R1_R2(ref C, ref L), 78 => LD_R_ARR(ref C, "hl"), 79 => LD_R1_R2(ref C, ref A), 80 => LD_R1_R2(ref D, ref B), 81 => LD_R1_R2(ref D, ref C), 82 => LD_R1_R2(ref D, ref D), 83 => LD_R1_R2(ref D, ref E), 84 => LD_R1_R2(ref D, ref H), 85 => LD_R1_R2(ref D, ref L), 86 => LD_R_ARR(ref D, "hl"), 87 => LD_R1_R2(ref D, ref A), 88 => LD_R1_R2(ref E, ref B), 89 => LD_R1_R2(ref E, ref C), 90 => LD_R1_R2(ref E, ref D), 91 => LD_R1_R2(ref E, ref E), 92 => LD_R1_R2(ref E, ref H), 93 => LD_R1_R2(ref E, ref L), 94 => LD_R_ARR(ref E, "hl"), 95 => LD_R1_R2(ref E, ref A), 96 => LD_R1_R2(ref H, ref B), 97 => LD_R1_R2(ref H, ref C), 98 => LD_R1_R2(ref H, ref D), 99 => LD_R1_R2(ref H, ref E), 100 => LD_R1_R2(ref H, ref H), 101 => LD_R1_R2(ref H, ref L), 102 => LD_R_ARR(ref H, "hl"), 103 => LD_R1_R2(ref H, ref A), 104 => LD_R1_R2(ref L, ref B), 105 => LD_R1_R2(ref L, ref C), 106 => LD_R1_R2(ref L, ref D), 107 => LD_R1_R2(ref L, ref E), 108 => LD_R1_R2(ref L, ref H), 109 => LD_R1_R2(ref L, ref L), 110 => LD_R_ARR(ref L, "hl"), 111 => LD_R1_R2(ref L, ref A), 112 => LD_ARR_R(ref B, "hl"), 113 => LD_ARR_R(ref C, "hl"), 114 => LD_ARR_R(ref D, "hl"), 115 => LD_ARR_R(ref E, "hl"), 116 => LD_ARR_R(ref H, "hl"), 117 => LD_ARR_R(ref L, "hl"), 118 => HALT(), 119 => LD_ARR_R(ref A, "hl"), 120 => LD_R1_R2(ref A, ref B), 121 => LD_R1_R2(ref A, ref C), 122 => LD_R1_R2(ref A, ref D), 123 => LD_R1_R2(ref A, ref E), 124 => LD_R1_R2(ref A, ref H), 125 => LD_R1_R2(ref A, ref L), 126 => LD_R_ARR(ref A, "hl"), 127 => LD_R1_R2(ref A, ref A), 128 => ADD_A_R(ref B), 129 => ADD_A_R(ref C), 130 => ADD_A_R(ref D), 131 => ADD_A_R(ref E), 132 => ADD_A_R(ref H), 133 => ADD_A_R(ref L), 134 => ADD_A_ARR("hl"), 135 => ADD_A_R(ref A), 136 => ADC_A_R(ref B), 137 => ADC_A_R(ref C), 138 => ADC_A_R(ref D), 139 => ADC_A_R(ref E), 140 => ADC_A_R(ref H), 141 => ADC_A_R(ref L), 142 => ADC_A_ARR("hl"), 143 => ADC_A_R(ref A), 144 => SUB_A_R(ref B), 145 => SUB_A_R(ref C), 146 => SUB_A_R(ref D), 147 => SUB_A_R(ref E), 148 => SUB_A_R(ref H), 149 => SUB_A_R(ref L), 150 => SUB_A_ARR("hl"), 151 => SUB_A_R(ref A), 152 => SBC_A_R(ref B), 153 => SBC_A_R(ref C), 154 => SBC_A_R(ref D), 155 => SBC_A_R(ref E), 156 => SBC_A_R(ref H), 157 => SBC_A_R(ref L), 158 => SBC_A_ARR("hl"), 159 => SBC_A_R(ref A), 160 => AND_A_R(ref B), 161 => AND_A_R(ref C), 162 => AND_A_R(ref D), 163 => AND_A_R(ref E), 164 => AND_A_R(ref H), 165 => AND_A_R(ref L), 166 => AND_A_ARR("hl"), 167 => AND_A_R(ref A), 168 => XOR_A_R(ref B), 169 => XOR_A_R(ref C), 170 => XOR_A_R(ref D), 171 => XOR_A_R(ref E), 172 => XOR_A_R(ref H), 173 => XOR_A_R(ref L), 174 => XOR_A_ARR("hl"), 175 => XOR_A_R(ref A), 176 => OR_A_R(ref B), 177 => OR_A_R(ref C), 178 => OR_A_R(ref D), 179 => OR_A_R(ref E), 180 => OR_A_R(ref H), 181 => OR_A_R(ref L), 182 => OR_A_ARR("hl"), 183 => OR_A_R(ref A), 184 => CP_A_R(ref B), 185 => CP_A_R(ref C), 186 => CP_A_R(ref D), 187 => CP_A_R(ref E), 188 => CP_A_R(ref H), 189 => CP_A_R(ref L), 190 => CP_A_ARR("hl"), 191 => CP_A_R(ref A), 192 => RET_CON(!zero), 193 => POP_RR("bc"), 194 => JP_CON_U16(!zero), 195 => JP_CON_U16(flag: true), 196 => CALL_CON_U16(!zero), 197 => PUSH_RR("bc"), 198 => ADD_A_U8(), 199 => RST(0), 200 => RET_CON(zero), 201 => RET(), 202 => JP_CON_U16(zero), 203 => ExecuteCB(), 204 => CALL_CON_U16(zero), 205 => CALL_U16(), 206 => ADC_A_U8(), 207 => RST(8), 208 => RET_CON(!carry), 209 => POP_RR("de"), 210 => JP_CON_U16(!carry), 211 => DMG_EXIT(b), 212 => CALL_CON_U16(!carry), 213 => PUSH_RR("de"), 214 => SUB_A_U8(), 215 => RST(16), 216 => RET_CON(carry), 217 => RETI(), 218 => JP_CON_U16(carry), 219 => DMG_EXIT(b), 220 => CALL_CON_U16(carry), 221 => DMG_EXIT(b), 222 => SBC_A_U8(), 223 => RST(24), 224 => LD_FF00_U8_A(), 225 => POP_RR("hl"), 226 => LD_FF00_C_A(), 227 => DMG_EXIT(b), 228 => DMG_EXIT(b), 229 => PUSH_RR("hl"), 230 => AND_A_U8(), 231 => RST(32), 232 => ADD_SP_I8(), 233 => JP_HL(), 234 => LD_AU16_A(), 235 => DMG_EXIT(b), 236 => DMG_EXIT(b), 237 => DMG_EXIT(b), 238 => XOR_A_U8(), 239 => RST(40), 240 => LD_A_FF00_U8(), 241 => POP_AF(), 242 => LD_A_FF00_C(), 243 => DI(), 244 => DMG_EXIT(b), 245 => PUSH_RR("af"), 246 => OR_A_U8(), 247 => RST(48), 248 => LD_HL_SP_I8(), 249 => LD_SP_HL(), 250 => LD_A_AU16(), 251 => EI(), 252 => DMG_EXIT(b), 253 => DMG_EXIT(b), 254 => CP_A_U8(), _ => RST(56), }; } public int ExecuteCB() { return Fetch() switch { 0 => RLC_R(ref B), 1 => RLC_R(ref C), 2 => RLC_R(ref D), 3 => RLC_R(ref E), 4 => RLC_R(ref H), 5 => RLC_R(ref L), 6 => RLC_AHL(), 7 => RLC_R(ref A), 8 => RRC_R(ref B), 9 => RRC_R(ref C), 10 => RRC_R(ref D), 11 => RRC_R(ref E), 12 => RRC_R(ref H), 13 => RRC_R(ref L), 14 => RRC_AHL(), 15 => RRC_R(ref A), 16 => RL_R(ref B), 17 => RL_R(ref C), 18 => RL_R(ref D), 19 => RL_R(ref E), 20 => RL_R(ref H), 21 => RL_R(ref L), 22 => RL_AHL(), 23 => RL_R(ref A), 24 => RR_R(ref B), 25 => RR_R(ref C), 26 => RR_R(ref D), 27 => RR_R(ref E), 28 => RR_R(ref H), 29 => RR_R(ref L), 30 => RR_AHL(), 31 => RR_R(ref A), 32 => SLA_R(ref B), 33 => SLA_R(ref C), 34 => SLA_R(ref D), 35 => SLA_R(ref E), 36 => SLA_R(ref H), 37 => SLA_R(ref L), 38 => SLA_AHL(), 39 => SLA_R(ref A), 40 => SRA_R(ref B), 41 => SRA_R(ref C), 42 => SRA_R(ref D), 43 => SRA_R(ref E), 44 => SRA_R(ref H), 45 => SRA_R(ref L), 46 => SRA_AHL(), 47 => SRA_R(ref A), 48 => SWAP_R(ref B), 49 => SWAP_R(ref C), 50 => SWAP_R(ref D), 51 => SWAP_R(ref E), 52 => SWAP_R(ref H), 53 => SWAP_R(ref L), 54 => SWAP_AHL(), 55 => SWAP_R(ref A), 56 => SRL_R(ref B), 57 => SRL_R(ref C), 58 => SRL_R(ref D), 59 => SRL_R(ref E), 60 => SRL_R(ref H), 61 => SRL_R(ref L), 62 => SRL_AHL(), 63 => SRL_R(ref A), 64 => BIT_N_R(0, ref B), 65 => BIT_N_R(0, ref C), 66 => BIT_N_R(0, ref D), 67 => BIT_N_R(0, ref E), 68 => BIT_N_R(0, ref H), 69 => BIT_N_R(0, ref L), 70 => BIT_N_AHL(0), 71 => BIT_N_R(0, ref A), 72 => BIT_N_R(1, ref B), 73 => BIT_N_R(1, ref C), 74 => BIT_N_R(1, ref D), 75 => BIT_N_R(1, ref E), 76 => BIT_N_R(1, ref H), 77 => BIT_N_R(1, ref L), 78 => BIT_N_AHL(1), 79 => BIT_N_R(1, ref A), 80 => BIT_N_R(2, ref B), 81 => BIT_N_R(2, ref C), 82 => BIT_N_R(2, ref D), 83 => BIT_N_R(2, ref E), 84 => BIT_N_R(2, ref H), 85 => BIT_N_R(2, ref L), 86 => BIT_N_AHL(2), 87 => BIT_N_R(2, ref A), 88 => BIT_N_R(3, ref B), 89 => BIT_N_R(3, ref C), 90 => BIT_N_R(3, ref D), 91 => BIT_N_R(3, ref E), 92 => BIT_N_R(3, ref H), 93 => BIT_N_R(3, ref L), 94 => BIT_N_AHL(3), 95 => BIT_N_R(3, ref A), 96 => BIT_N_R(4, ref B), 97 => BIT_N_R(4, ref C), 98 => BIT_N_R(4, ref D), 99 => BIT_N_R(4, ref E), 100 => BIT_N_R(4, ref H), 101 => BIT_N_R(4, ref L), 102 => BIT_N_AHL(4), 103 => BIT_N_R(4, ref A), 104 => BIT_N_R(5, ref B), 105 => BIT_N_R(5, ref C), 106 => BIT_N_R(5, ref D), 107 => BIT_N_R(5, ref E), 108 => BIT_N_R(5, ref H), 109 => BIT_N_R(5, ref L), 110 => BIT_N_AHL(5), 111 => BIT_N_R(5, ref A), 112 => BIT_N_R(6, ref B), 113 => BIT_N_R(6, ref C), 114 => BIT_N_R(6, ref D), 115 => BIT_N_R(6, ref E), 116 => BIT_N_R(6, ref H), 117 => BIT_N_R(6, ref L), 118 => BIT_N_AHL(6), 119 => BIT_N_R(6, ref A), 120 => BIT_N_R(7, ref B), 121 => BIT_N_R(7, ref C), 122 => BIT_N_R(7, ref D), 123 => BIT_N_R(7, ref E), 124 => BIT_N_R(7, ref H), 125 => BIT_N_R(7, ref L), 126 => BIT_N_AHL(7), 127 => BIT_N_R(7, ref A), 128 => RES_N_R(0, ref B), 129 => RES_N_R(0, ref C), 130 => RES_N_R(0, ref D), 131 => RES_N_R(0, ref E), 132 => RES_N_R(0, ref H), 133 => RES_N_R(0, ref L), 134 => RES_N_AHL(0), 135 => RES_N_R(0, ref A), 136 => RES_N_R(1, ref B), 137 => RES_N_R(1, ref C), 138 => RES_N_R(1, ref D), 139 => RES_N_R(1, ref E), 140 => RES_N_R(1, ref H), 141 => RES_N_R(1, ref L), 142 => RES_N_AHL(1), 143 => RES_N_R(1, ref A), 144 => RES_N_R(2, ref B), 145 => RES_N_R(2, ref C), 146 => RES_N_R(2, ref D), 147 => RES_N_R(2, ref E), 148 => RES_N_R(2, ref H), 149 => RES_N_R(2, ref L), 150 => RES_N_AHL(2), 151 => RES_N_R(2, ref A), 152 => RES_N_R(3, ref B), 153 => RES_N_R(3, ref C), 154 => RES_N_R(3, ref D), 155 => RES_N_R(3, ref E), 156 => RES_N_R(3, ref H), 157 => RES_N_R(3, ref L), 158 => RES_N_AHL(3), 159 => RES_N_R(3, ref A), 160 => RES_N_R(4, ref B), 161 => RES_N_R(4, ref C), 162 => RES_N_R(4, ref D), 163 => RES_N_R(4, ref E), 164 => RES_N_R(4, ref H), 165 => RES_N_R(4, ref L), 166 => RES_N_AHL(4), 167 => RES_N_R(4, ref A), 168 => RES_N_R(5, ref B), 169 => RES_N_R(5, ref C), 170 => RES_N_R(5, ref D), 171 => RES_N_R(5, ref E), 172 => RES_N_R(5, ref H), 173 => RES_N_R(5, ref L), 174 => RES_N_AHL(5), 175 => RES_N_R(5, ref A), 176 => RES_N_R(6, ref B), 177 => RES_N_R(6, ref C), 178 => RES_N_R(6, ref D), 179 => RES_N_R(6, ref E), 180 => RES_N_R(6, ref H), 181 => RES_N_R(6, ref L), 182 => RES_N_AHL(6), 183 => RES_N_R(6, ref A), 184 => RES_N_R(7, ref B), 185 => RES_N_R(7, ref C), 186 => RES_N_R(7, ref D), 187 => RES_N_R(7, ref E), 188 => RES_N_R(7, ref H), 189 => RES_N_R(7, ref L), 190 => RES_N_AHL(7), 191 => RES_N_R(7, ref A), 192 => SET_N_R(0, ref B), 193 => SET_N_R(0, ref C), 194 => SET_N_R(0, ref D), 195 => SET_N_R(0, ref E), 196 => SET_N_R(0, ref H), 197 => SET_N_R(0, ref L), 198 => SET_N_AHL(0), 199 => SET_N_R(0, ref A), 200 => SET_N_R(1, ref B), 201 => SET_N_R(1, ref C), 202 => SET_N_R(1, ref D), 203 => SET_N_R(1, ref E), 204 => SET_N_R(1, ref H), 205 => SET_N_R(1, ref L), 206 => SET_N_AHL(1), 207 => SET_N_R(1, ref A), 208 => SET_N_R(2, ref B), 209 => SET_N_R(2, ref C), 210 => SET_N_R(2, ref D), 211 => SET_N_R(2, ref E), 212 => SET_N_R(2, ref H), 213 => SET_N_R(2, ref L), 214 => SET_N_AHL(2), 215 => SET_N_R(2, ref A), 216 => SET_N_R(3, ref B), 217 => SET_N_R(3, ref C), 218 => SET_N_R(3, ref D), 219 => SET_N_R(3, ref E), 220 => SET_N_R(3, ref H), 221 => SET_N_R(3, ref L), 222 => SET_N_AHL(3), 223 => SET_N_R(3, ref A), 224 => SET_N_R(4, ref B), 225 => SET_N_R(4, ref C), 226 => SET_N_R(4, ref D), 227 => SET_N_R(4, ref E), 228 => SET_N_R(4, ref H), 229 => SET_N_R(4, ref L), 230 => SET_N_AHL(4), 231 => SET_N_R(4, ref A), 232 => SET_N_R(5, ref B), 233 => SET_N_R(5, ref C), 234 => SET_N_R(5, ref D), 235 => SET_N_R(5, ref E), 236 => SET_N_R(5, ref H), 237 => SET_N_R(5, ref L), 238 => SET_N_AHL(5), 239 => SET_N_R(5, ref A), 240 => SET_N_R(6, ref B), 241 => SET_N_R(6, ref C), 242 => SET_N_R(6, ref D), 243 => SET_N_R(6, ref E), 244 => SET_N_R(6, ref H), 245 => SET_N_R(6, ref L), 246 => SET_N_AHL(6), 247 => SET_N_R(6, ref A), 248 => SET_N_R(7, ref B), 249 => SET_N_R(7, ref C), 250 => SET_N_R(7, ref D), 251 => SET_N_R(7, ref E), 252 => SET_N_R(7, ref H), 253 => SET_N_R(7, ref L), 254 => SET_N_AHL(7), _ => SET_N_R(7, ref A), }; } private int LD_ARR_R(ref byte r, string regPair) { ushort address = Get16BitReg(regPair); mmu.Write(address, r); return 8; } private int LD_AHLM_A() { ushort num = Get16BitReg("hl"); mmu.Write(num, A); num--; Load16BitReg("hl", num); return 8; } private int LD_AHLI_A() { ushort num = Get16BitReg("hl"); mmu.Write(num, A); num++; Load16BitReg("hl", num); return 8; } private int LD_R_U8(ref byte r) { byte b = Fetch(); r = b; return 8; } private int LD_AHL_U8() { ushort address = Get16BitReg("hl"); byte value = Fetch(); mmu.Write(address, value); return 12; } private int LD_R_ARR(ref byte r, string regPair) { ushort address = Get16BitReg(regPair); r = mmu.Read(address); return 8; } private int LD_A_AHLM() { ushort num = Get16BitReg("hl"); A = mmu.Read(num); num--; Load16BitReg("hl", num); return 8; } private int LD_A_AHLI() { ushort num = Get16BitReg("hl"); A = mmu.Read(num); num++; Load16BitReg("hl", num); return 8; } private int LD_R1_R2(ref byte r1, ref byte r2) { r1 = r2; return 4; } private int LD_FF00_U8_A() { byte b = Fetch(); ushort address = (ushort)(65280 + b); mmu.Write(address, A); return 12; } private int LD_A_FF00_U8() { byte b = Fetch(); ushort address = (ushort)(65280 + b); A = mmu.Read(address); return 12; } private int LD_FF00_C_A() { ushort address = (ushort)(65280 + C); mmu.Write(address, A); return 8; } private int LD_A_FF00_C() { ushort address = (ushort)(65280 + C); A = mmu.Read(address); return 8; } private int LD_AU16_A() { byte b = Fetch(); ushort address = (ushort)((Fetch() << 8) | b); mmu.Write(address, A); return 16; } private int LD_A_AU16() { byte b = Fetch(); ushort address = (ushort)((Fetch() << 8) | b); A = mmu.Read(address); return 16; } private int LD_SP_U16() { byte b = Fetch(); ushort sP = (ushort)((Fetch() << 8) | b); SP = sP; return 12; } private int LD_RR_U16(ref byte r1, ref byte r2) { r2 = Fetch(); r1 = Fetch(); return 12; } private int LD_AU16_SP() { byte b = Fetch(); ushort num = (ushort)((Fetch() << 8) | b); byte value = (byte)(SP & 0xFFu); byte value2 = (byte)((uint)(SP >> 8) & 0xFFu); mmu.Write(num, value); mmu.Write((ushort)(num + 1), value2); return 20; } private int PUSH_RR(string regPair) { ushort num = Get16BitReg(regPair); SP--; mmu.Write(SP, (byte)(num >> 8)); SP--; mmu.Write(SP, (byte)(num & 0xFFu)); return 16; } private int POP_RR(string regPair) { byte b = mmu.Read(SP); SP++; ushort value = (ushort)((mmu.Read(SP) << 8) | b); Load16BitReg(regPair, value); SP++; return 12; } private int POP_AF() { byte b = mmu.Read(SP); SP++; byte a = mmu.Read(SP); A = a; F = (byte)(b & 0xF0u); UpdateFlagsFromF(); SP++; return 12; } private int LD_SP_HL() { SP = Get16BitReg("hl"); return 8; } private int INC_R(ref byte r) { int num = r + 1; zero = (num & 0xFF) == 0; negative = false; halfCarry = (num & 0xF) == 0; UpdateFFromFlags(); r = (byte)num; return 4; } private int INC_AHL() { ushort address = Get16BitReg("hl"); int num = mmu.Read(address) + 1; zero = (num & 0xFF) == 0; negative = false; halfCarry = (num & 0xF) == 0; UpdateFFromFlags(); mmu.Write(address, (byte)num); return 12; } private int DEC_R(ref byte r) { int num = r - 1; zero = (num & 0xFF) == 0; negative = true; halfCarry = (r & 0xF) == 0; UpdateFFromFlags(); r = (byte)num; return 4; } private int DEC_AHL() { ushort address = Get16BitReg("hl"); byte b = mmu.Read(address); int num = b - 1; zero = (num & 0xFF) == 0; negative = true; halfCarry = (b & 0xF) == 0; UpdateFFromFlags(); mmu.Write(address, (byte)num); return 12; } private int ADD_A_R(ref byte r) { int num = A + r; zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (r & 0xF) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)((uint)num & 0xFFu); return 4; } private int ADD_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A + b; zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (b & 0xF) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)num; return 8; } private int ADD_A_U8() { byte b = Fetch(); int num = A + b; zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (b & 0xF) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)((uint)num & 0xFFu); return 8; } private int ADC_A_R(ref byte r) { int num = A + r + (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (r & 0xF) + (carry ? 1 : 0) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)((uint)num & 0xFFu); return 4; } private int ADC_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A + b + (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (b & 0xF) + (carry ? 1 : 0) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)num; return 8; } private int ADC_A_U8() { byte b = Fetch(); int num = A + b + (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = false; halfCarry = (A & 0xF) + (b & 0xF) + (carry ? 1 : 0) > 15; carry = num > 255; UpdateFFromFlags(); A = (byte)((uint)num & 0xFFu); return 8; } private int SUB_A_R(ref byte r) { int num = A - r; zero = num == 0; negative = true; halfCarry = (A & 0xF) < (r & 0xF); carry = A < r; UpdateFFromFlags(); A = (byte)num; return 4; } private int SUB_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A - b; zero = (num & 0xFF) == 0; negative = true; halfCarry = (A & 0xF) < (b & 0xF); carry = num < 0; UpdateFFromFlags(); A = (byte)num; return 8; } private int SUB_A_U8() { byte b = Fetch(); int num = A - b; zero = num == 0; negative = true; halfCarry = (A & 0xF) < (b & 0xF); carry = A < b; UpdateFFromFlags(); A = (byte)num; return 8; } private int SBC_A_R(ref byte r) { int num = A - r - (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = true; halfCarry = (A & 0xF) - (r & 0xF) - (carry ? 1 : 0) < 0; carry = num < 0; UpdateFFromFlags(); A = (byte)num; return 4; } private int SBC_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A - b - (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = true; halfCarry = (A & 0xF) - (b & 0xF) - (carry ? 1 : 0) < 0; carry = num < 0; UpdateFFromFlags(); A = (byte)num; return 8; } private int SBC_A_U8() { byte b = Fetch(); int num = A - b - (carry ? 1 : 0); zero = (num & 0xFF) == 0; negative = true; halfCarry = (A & 0xF) - (b & 0xF) - (carry ? 1 : 0) < 0; carry = num < 0; UpdateFFromFlags(); A = (byte)num; return 8; } private int AND_A_R(ref byte r) { int num = A & r; zero = (num & 0xFF) == 0; negative = false; halfCarry = true; carry = false; UpdateFFromFlags(); A = (byte)num; return 4; } private int AND_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A & b; zero = (num & 0xFF) == 0; negative = false; halfCarry = true; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int AND_A_U8() { byte b = Fetch(); int num = A & b; zero = (num & 0xFF) == 0; negative = false; halfCarry = true; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int XOR_A_R(ref byte r) { int num = A ^ r; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 4; } private int XOR_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A ^ b; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int XOR_A_U8() { byte b = Fetch(); int num = A ^ b; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int OR_A_R(ref byte r) { int num = A | r; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 4; } private int OR_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A | b; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int OR_A_U8() { byte b = Fetch(); int num = A | b; zero = (num & 0xFF) == 0; negative = false; halfCarry = false; carry = false; UpdateFFromFlags(); A = (byte)num; return 8; } private int CP_A_R(ref byte r) { int num = A - r; zero = (num & 0xFF) == 0; negative = true; halfCarry = (A & 0xF) < (r & 0xF); carry = num < 0; UpdateFFromFlags(); return 4; } private int CP_A_ARR(string regPair) { ushort address = Get16BitReg(regPair); byte b = mmu.Read(address); int num = A - b; zero = num == 0; negative = true; halfCarry = (A & 0xF) < (b & 0xF); carry = A < b; UpdateFFromFlags(); return 8; } private int CP_A_U8() { byte b = Fetch(); int num = A - b; zero = num == 0; negative = true; halfCarry = (A & 0xF) < (b & 0xF); carry = A < b; UpdateFFromFlags(); return 8; } private int CPL() { A = (byte)(~A); negative = true; halfCarry = true; UpdateFFromFlags(); return 4; } private int SCF() { carry = true; negative = false; halfCarry = false; UpdateFFromFlags(); return 4; } private int CCF() { carry = !carry; negative = false; halfCarry = false; UpdateFFromFlags(); return 4; } private int DAA() { byte b = (byte)(carry ? 96u : 0u); if (halfCarry) { b = (byte)(b | 6u); } if (negative) { A -= b; } else { if ((A & 0xF) > 9) { b = (byte)(b | 6u); } if (A > 153) { b = (byte)(b | 0x60u); } A += b; } zero = A == 0; halfCarry = false; carry = b >= 96; UpdateFFromFlags(); return 4; } private int INC_RR(string regPair) { ushort num = Get16BitReg(regPair); num++; Load16BitReg(regPair, num); return 8; } private int INC_SP() { SP++; return 8; } private int DEC_RR(string regPair) { ushort num = Get16BitReg(regPair); num--; Load16BitReg(regPair, num); return 8; } private int DEC_SP() { SP--; return 8; } private int ADD_HL_RR(string regPair) { ushort num = Get16BitReg("hl"); ushort num2 = Get16BitReg(regPair); int num3 = num + num2; negative = false; halfCarry = (num & 0xFFF) + (num2 & 0xFFF) > 4095; carry = num3 > 65535; UpdateFFromFlags(); Load16BitReg("hl", (ushort)num3); return 8; } private int ADD_HL_SP() { ushort num = Get16BitReg("hl"); int num2 = num + SP; negative = false; halfCarry = (num & 0xFFF) + (SP & 0xFFF) > 4095; carry = num2 > 65535; UpdateFFromFlags(); Load16BitReg("hl", (ushort)num2); return 8; } private int ADD_SP_I8() { _ = SP; _ = SP; sbyte b = (sbyte)Fetch(); int num = SP + (ushort)b; zero = false; negative = false; halfCarry = ((SP ^ b ^ (num & 0xFFFF)) & 0x10) == 16; carry = ((SP ^ b ^ (num & 0xFFFF)) & 0x100) == 256; UpdateFFromFlags(); SP = (ushort)num; return 16; } private int LD_HL_SP_I8() { sbyte b = (sbyte)Fetch(); int num = SP + b; zero = false; negative = false; halfCarry = ((SP ^ b ^ (num & 0xFFFF)) & 0x10) == 16; carry = ((SP ^ b ^ (num & 0xFFFF)) & 0x100) == 256; UpdateFFromFlags(); Load16BitReg("hl", (ushort)num); return 12; } private int RLCA() { byte b = (byte)(A & 0x80u); byte a = (byte)((A << 1) | (b >> 7)); zero = false; negative = false; halfCarry = false; carry = (A & 0x80) != 0; UpdateFFromFlags(); A = a; return 4; } private int RRCA() { byte b = (byte)(A & 1u); byte a = (byte)((A >> 1) | (b << 7)); zero = false; negative = false; halfCarry = false; carry = (A & 1) != 0; UpdateFFromFlags(); A = a; return 4; } private int RLA() { byte b = (carry ? ((byte)1) : ((byte)0)); byte a = (byte)((A << 1) | b); zero = false; negative = false; halfCarry = false; carry = (A & 0x80) != 0; UpdateFFromFlags(); A = a; return 4; } private int RRA() { byte b = (carry ? ((byte)1) : ((byte)0)); byte a = (byte)((A >> 1) | (b << 7)); zero = false; negative = false; halfCarry = false; carry = (A & 1) != 0; UpdateFFromFlags(); A = a; return 4; } private int RLC_R(ref byte r) { byte b = (byte)(r & 0x80u); byte b2 = (byte)((r << 1) | (b >> 7)); zero = b2 == 0; negative = false; halfCarry = false; carry = (r & 0x80) != 0; UpdateFFromFlags(); r = b2; return 8; } private int RLC_AHL() { ushort address = Get16BitReg("hl"); byte b = mmu.Read(address); byte b2 = (byte)(b & 0x80u); byte b3 = (byte)((b << 1) | (b2 >> 7)); zero = b3 == 0; negative = false; halfCarry = false; carry = (b & 0x80) != 0; UpdateFFromFlags(); mmu.Write(address, b3); return 16; } private int RRC_R(ref byte r) { byte b = (byte)(r & 1u); byte b2 = (byte)((r >> 1) | (b << 7)); zero = b2 == 0; negative = false; halfCarry = false; carry = (r & 1) != 0; UpdateFFromFlags(); r = b2; return 8; } private int RRC_AHL() { ushort address = Get16BitReg("hl"); byte b = mmu.Read(address); byte b2 = (byte)(b & 1u); byte b3 = (byte)((b >> 1) | (b2 << 7)); zero = b3 == 0; negative = false; halfCarry = false; carry = (b & 1) != 0; UpdateFFromFlags(); mmu.Write(address, b3); return 16; } private int RL_R(ref byte r) { byte b = (carry ? ((byte)1) : ((byte)0)); byte b2 = (byte)((r << 1) | b); zero = b2 == 0; negative = false; halfCarry = false; carry = (r & 0x80) != 0; UpdateFFromFlags(); r = b2; return 8; } private int RL_AHL() { usho