diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity.meta
new file mode 100644
index 00000000..d701a927
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9604fb0f1487b95488164f5dc29a00ba
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs
new file mode 100644
index 00000000..b11d0a5b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace StoicGooseUnity
+{
+    public static class StoicGooseUnityAxiMem
+    {
+        public static void Init() => AxiMemoryEx.Init();
+        public static void FreeAllGCHandle() => AxiMemoryEx.FreeAllGCHandle();
+    }
+    internal unsafe static class AxiMemoryEx
+    {
+        static HashSet<GCHandle> GCHandles = new HashSet<GCHandle>();
+
+        public static void Init()
+        {
+            FreeAllGCHandle();
+            set_TempBuffer = new byte[0x100000];
+        }
+
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref uint* ptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
+            ptr = (uint*)intptr;
+        }
+
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref short* ptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
+            ptr = (short*)intptr;
+        }
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref ushort* ptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
+            ptr = (ushort*)intptr;
+        }
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref int* ptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
+            ptr = (int*)intptr;
+        }
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out IntPtr intptr);
+            ptr = (byte*)intptr;
+        }
+
+        public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref byte* ptr, out IntPtr intptr)
+        {
+            GetObjectPtr(srcObj, ref handle, out intptr);
+            ptr = (byte*)intptr;
+        }
+
+        static void GetObjectPtr(this object srcObj, ref GCHandle handle, out IntPtr intptr)
+        {
+            ReleaseGCHandle(ref handle);
+            handle = GCHandle.Alloc(srcObj, GCHandleType.Pinned);
+            GCHandles.Add(handle);
+            intptr = handle.AddrOfPinnedObject();
+        }
+
+        public static void ReleaseGCHandle(this ref GCHandle handle)
+        {
+            if (handle.IsAllocated)
+                handle.Free();
+            GCHandles.Remove(handle);
+        }
+
+        public static void FreeAllGCHandle()
+        {
+            foreach (var handle in GCHandles)
+            {
+                if (handle.IsAllocated)
+                    handle.Free();
+            }
+            GCHandles.Clear();
+        }
+
+        #region 指针化 TempBuffer
+        static byte[] TempBuffer_src;
+        static GCHandle TempBuffer_handle;
+        public static byte* TempBuffer;
+        public static byte[] set_TempBuffer
+        {
+            set
+            {
+                TempBuffer_handle.ReleaseGCHandle();
+                if (value == null)
+                    return;
+                TempBuffer_src = value;
+                TempBuffer_src.GetObjectPtr(ref TempBuffer_handle, ref TempBuffer);
+            }
+        }
+        #endregion
+
+        public static void Write(this BinaryWriter bw, byte* bufferPtr, int offset, int count)
+        {
+            // 使用指针复制数据到临时数组
+            Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
+            // 使用BinaryWriter写入临时数组
+            bw.Write(TempBuffer_src, 0, count);
+        }
+        public static void Write(this FileStream fs, byte* bufferPtr, int offset, int count)
+        {
+            // 使用指针复制数据到临时数组
+            Buffer.MemoryCopy(bufferPtr + offset, TempBuffer, 0, count);
+            // 使用BinaryWriter写入临时数组
+            fs.Write(TempBuffer_src, 0, count);
+        }
+        public static int Read(this FileStream fs, byte* bufferPtr, int offset, int count)
+        {
+            // 使用BinaryWriter写入临时数组
+            count = fs.Read(TempBuffer_src, offset, count);
+            // 使用指针复制数据到临时数组
+            Buffer.MemoryCopy(TempBuffer, bufferPtr + offset, 0, count);
+            return count;
+        }
+    }
+
+    internal unsafe static class AxiArray
+    {
+
+        public static void Copy(byte* src, int srcindex, byte* target, int targetindex, int count)
+        {
+            int singlesize = sizeof(byte);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
+        }
+        public static void Copy(short* src, int srcindex, short* target, int targetindex, int count)
+        {
+            int singlesize = sizeof(short);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
+        }
+        public static void Copy(ushort* src, int srcindex, ushort* target, int targetindex, int count)
+        {
+            int singlesize = sizeof(ushort);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(&src[srcindex], &target[targetindex], totalBytesToCopy, totalBytesToCopy);
+        }
+
+        public static void Copy(byte* src, byte* target, int index, int count)
+        {
+            int singlesize = sizeof(byte);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
+        }
+
+        public static void Copy(ushort* src, ushort* target, int index, int count)
+        {
+            int singlesize = sizeof(ushort);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(&src[index], &target[index], totalBytesToCopy, totalBytesToCopy);
+        }
+        public static void Copy(ushort* src, ushort* target, int count)
+        {
+            int singlesize = sizeof(ushort);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
+        }
+        public static void Copy(byte* src, byte* target, int count)
+        {
+            int singlesize = sizeof(byte);
+            long totalBytesToCopy = count * singlesize;
+            Buffer.MemoryCopy(src, target, totalBytesToCopy, totalBytesToCopy);
+        }
+        public static void Clear(byte* data, int index, int lenght)
+        {
+            for (int i = index; i < lenght; i++, index++)
+                data[index] = 0;
+        }
+        public static void Clear(ushort* data, int index, int lenght)
+        {
+            for (int i = index; i < lenght; i++, index++)
+                data[index] = 0;
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta
new file mode 100644
index 00000000..236e26be
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/AxiMemory.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 920eb4ce49315964e9537a20e38e6151
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta
new file mode 100644
index 00000000..35f0f21c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7e1e5391f68e92f4db7f61cf8ed9557e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta
new file mode 100644
index 00000000..e4480159
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 70afb0cb69f156a4b877a6dd0462fa04
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs
new file mode 100644
index 00000000..ae8b0a08
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace StoicGoose.Common.Attributes
+{
+	[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+	public class BitDescriptionAttribute : Attribute
+	{
+		public string Description { get; set; } = string.Empty;
+		public int LowBit { get; set; } = -1;
+		public int HighBit { get; set; } = -1;
+
+		public string BitString => LowBit != -1 ? $"B{LowBit}{(HighBit > LowBit ? $"-{HighBit}" : string.Empty)}: " : string.Empty;
+
+		public BitDescriptionAttribute(string desc, int low = -1, int high = -1)
+		{
+			Description = desc;
+			LowBit = low;
+			HighBit = high;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta
new file mode 100644
index 00000000..3200b069
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d881068effe996b459fdd198b8e7b046
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs
new file mode 100644
index 00000000..104658b2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace StoicGoose.Common.Attributes
+{
+	[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+	public class FormatAttribute : Attribute
+	{
+		public string Format { get; set; } = string.Empty;
+		public int Shift { get; set; } = 0;
+
+		public FormatAttribute(string format, int shift = 0)
+		{
+			Format = format;
+			Shift = shift;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta
new file mode 100644
index 00000000..3a7ff488
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 2e358d7d3a0a0dd4a835853c38de5b88
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs
new file mode 100644
index 00000000..c774966c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace StoicGoose.Common.Attributes
+{
+	[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+	public class PortAttribute : Attribute
+	{
+		public string Name { get; set; } = string.Empty;
+		public List<ushort> Numbers { get; set; } = new();
+
+		public PortAttribute(string name, params ushort[] numbers)
+		{
+			Name = name;
+			Numbers.AddRange(numbers);
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta
new file mode 100644
index 00000000..4f0df209
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e622fd59969209c48842cc5f6951d34f
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta
new file mode 100644
index 00000000..f6c99610
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 62a562265df1f9b41949fb0a0d5d4491
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs
new file mode 100644
index 00000000..556a8098
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs
@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using System.Linq;
+
+namespace StoicGoose.Common.Drawing
+{
+	/* RGBA bitmap file format -- https://github.com/bzotto/rgba_bitmap
+	 * ".rgba is the dumbest possible image interchange format, now available for your programming pleasure."
+	 */
+
+	public class RgbaFile
+	{
+		const string expectedMagic = "RGBA";
+
+		public string MagicNumber { get; protected set; }
+		public uint Width { get; protected set; }
+		public uint Height { get; protected set; }
+		public byte[] PixelData { get; protected set; }
+
+		public RgbaFile(string filename) : this(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { }
+
+		public RgbaFile(Stream stream)
+		{
+			MagicNumber = ReadString(stream, 4);
+			Width = ReadUInt32(stream);
+			Height = ReadUInt32(stream);
+			PixelData = new byte[Width * Height * 4];
+			stream.Read(PixelData);
+		}
+
+		public RgbaFile(uint width, uint height, byte[] pixelData)
+		{
+			MagicNumber = expectedMagic;
+			Width = width;
+			Height = height;
+			PixelData = pixelData;
+		}
+
+		public void Save(string filename) => Save(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
+
+		public void Save(Stream stream)
+		{
+			WriteString(stream, MagicNumber);
+			WriteUInt32(stream, Width);
+			WriteUInt32(stream, Height);
+			stream.Write(PixelData);
+		}
+
+		private static string ReadString(Stream stream, int length) => new(Enumerable.Range(0, length).Select(_ => (char)stream.ReadByte()).ToArray());
+		private static uint ReadUInt32(Stream stream) => (uint)(((stream.ReadByte() & 0xFF) << 24) | ((stream.ReadByte() & 0xFF) << 16) | ((stream.ReadByte() & 0xFF) << 8) | ((stream.ReadByte() & 0xFF) << 0));
+
+		private static void WriteString(Stream stream, string str) => Array.ForEach(str.ToCharArray(), (x) => stream.WriteByte((byte)x));
+		private static void WriteUInt32(Stream stream, uint val) { stream.WriteByte((byte)((val >> 24) & 0xFF)); stream.WriteByte((byte)((val >> 16) & 0xFF)); stream.WriteByte((byte)((val >> 8) & 0xFF)); stream.WriteByte((byte)((val >> 0) & 0xFF)); }
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta
new file mode 100644
index 00000000..53fab104
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 319acc894b323fd4f90b8e025383be58
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta
new file mode 100644
index 00000000..c0129c15
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d8d552996c36ed1478421faa10628ce6
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs
new file mode 100644
index 00000000..effa8c94
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs
@@ -0,0 +1,20 @@
+//using Newtonsoft.Json;
+
+//namespace StoicGoose.Common.Extensions
+//{
+//	public static class ObjectExtensionMethods
+//	{
+//		/* https://dotnetcoretutorials.com/2020/09/09/cloning-objects-in-c-and-net-core/ */
+//		public static T Clone<T>(this T source)
+//		{
+//			if (source is null) return default;
+//			return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, new JsonSerializerSettings()
+//			{
+//				ReferenceLoopHandling = ReferenceLoopHandling.Ignore
+//			}), new JsonSerializerSettings()
+//			{
+//				ObjectCreationHandling = ObjectCreationHandling.Replace
+//			});
+//		}
+//	}
+//}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta
new file mode 100644
index 00000000..63fc6a43
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 6e4fde992b04dbe42be66c0ea83bb7c1
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs
new file mode 100644
index 00000000..27d82399
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs
@@ -0,0 +1,31 @@
+//using System.IO;
+
+//using Newtonsoft.Json;
+
+//namespace StoicGoose.Common.Extensions
+//{
+//	public static class SerializationExtensionMethods
+//	{
+//		public static void SerializeToFile(this object obj, string jsonFileName)
+//		{
+//			SerializeToFile(obj, jsonFileName, new JsonSerializerSettings() { Formatting = Formatting.Indented });
+//		}
+
+//		public static void SerializeToFile(this object obj, string jsonFileName, JsonSerializerSettings serializerSettings)
+//		{
+//			using var writer = new StreamWriter(jsonFileName);
+//			writer.Write(JsonConvert.SerializeObject(obj, serializerSettings));
+//		}
+
+//		public static T DeserializeFromFile<T>(this string jsonFileName)
+//		{
+//			using var reader = new StreamReader(jsonFileName);
+//			return (T)JsonConvert.DeserializeObject(reader.ReadToEnd(), typeof(T), new JsonSerializerSettings() { Formatting = Formatting.Indented });
+//		}
+
+//		public static T DeserializeObject<T>(this string jsonString)
+//		{
+//			return (T)JsonConvert.DeserializeObject(jsonString, typeof(T), new JsonSerializerSettings() { Formatting = Formatting.Indented });
+//		}
+//	}
+//}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta
new file mode 100644
index 00000000..1f73c71e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 07c7fb2a5f53f2f4aaa60f1673087d9c
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs
new file mode 100644
index 00000000..e58ac637
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace StoicGoose.Common.Extensions
+{
+	public static class StringExtensionMethods
+	{
+		/* Modified from https://stackoverflow.com/a/2641383 */
+		public static List<int> IndexOfAll(this string str, string value)
+		{
+			if (string.IsNullOrEmpty(value))
+				throw new ArgumentException("Search string is null or empty", nameof(value));
+
+			var idxs = new List<int>();
+			for (var i = 0; ; i += value.Length)
+			{
+				i = str.IndexOf(value, i);
+				if (i == -1) return idxs;
+				idxs.Add(i);
+			}
+		}
+
+		public static string EnsureEndsWithPeriod(this string str) => str + (!str.EndsWith('.') ? "." : string.Empty);
+
+		/* Regex via https://superuser.com/a/380778 */
+		public static string RemoveAnsi(this string str) => Regex.Replace(str, @"\x1b\[[0-9;]*[mGKHF]", "");
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta
new file mode 100644
index 00000000..d76f28a9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: da7cb8ba3dd19cb4e96fedb8dd687ab0
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta
new file mode 100644
index 00000000..10622fa7
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2df240a96bd839c46a5d441273339c11
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs
new file mode 100644
index 00000000..82cb21c6
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs
@@ -0,0 +1,37 @@
+//using System;
+//using System.Globalization;
+//using System.Linq;
+//using System.Text.RegularExpressions;
+
+//using Newtonsoft.Json;
+//using Newtonsoft.Json.Linq;
+
+//namespace StoicGoose.Common.Localization
+//{
+//	public static class Localizer
+//	{
+//		public static string FallbackCulture { get; set; } = "en";
+
+//		static JObject source = default;
+
+//		public static void Initialize(string jsonData) => source = JsonConvert.DeserializeObject(jsonData) as JObject;
+
+//		public static CultureInfo[] GetSupportedLanguages() => source?.Children().Select(x => new CultureInfo((x as JProperty).Name)).ToArray() ?? Array.Empty<CultureInfo>();
+
+//		private static JToken GetToken(string path) => source?.SelectToken($"{CultureInfo.CurrentUICulture.TwoLetterISOLanguageName}.{path}") ?? source?.SelectToken($"{FallbackCulture}.{path}");
+//		public static string GetString(string path) => GetToken(path)?.Value<string>() ?? path[(path.LastIndexOf('.') + 1)..];
+//		public static string GetString(string path, object parameters)
+//		{
+//			var result = GetString(path);
+//			var properties = parameters.GetType().GetProperties();
+//			foreach (Match match in Regex.Matches(result, @"{(?<param>[^}:]*):*(?<format>[^}]*)}").Where(x => x.Success))
+//			{
+//				var property = properties.First(x => x.Name == match.Groups["param"].Value);
+//				var format = match.Groups["format"].Value;
+//				var formattedValue = string.IsNullOrEmpty(format) ? $"{property.GetValue(parameters)}" : string.Format($"{{0:{format}}}", property.GetValue(parameters));
+//				result = result.Replace(match.Value, formattedValue);
+//			}
+//			return result;
+//		}
+//	}
+//}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta
new file mode 100644
index 00000000..11254055
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e82b9629c32ff9f46bfd29ee8db43083
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta
new file mode 100644
index 00000000..2c0d21f2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6d169728b1f850a4db4171c5dab2507c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs
new file mode 100644
index 00000000..d928ac47
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace StoicGoose.Common.Utilities
+{
+	public static class Ansi
+	{
+		public readonly static string Reset = "\x1B[0m";
+		public readonly static string Black = "\x1B[30m";
+		public readonly static string Red = "\x1B[31m";
+		public readonly static string Green = "\x1B[32m";
+		public readonly static string Yellow = "\x1B[33m";
+		public readonly static string Blue = "\x1B[34m";
+		public readonly static string Magenta = "\x1B[35m";
+		public readonly static string Cyan = "\x1B[36m";
+		public readonly static string White = "\x1B[37m";
+
+		public static string RGB(byte r, byte g, byte b) => $"\x1B[38;2;{r};{g};{b}m";
+
+		// Such a stupid gimmick... but hey, I like stupid gimmicks and I especially like making them, so whatever~
+		public static string Gradient(string text, bool useHsl, params (byte r, byte g, byte b)[] colors)
+		{
+			var stepsPerColor = (int)Math.Round(text.Length / (colors.Length - 1f), MidpointRounding.AwayFromZero);
+			var steps = Math.Max(stepsPerColor * (colors.Length - 1), text.Length);
+
+			List<(byte r, byte g, byte b)> gradient = new();
+
+			for (int i = 0, c = 0; i < steps; i += stepsPerColor, c++)
+			{
+				// TODO: this is a workaround for a out-of-range bug, but ugh, it's for a mere gimmick barely anyone will ever see, soooooo... whatever!
+				if (c + 1 >= colors.Length) c--;
+
+				if (useHsl)
+				{
+					var (h1, s1, l1) = RgbToHsl(colors[c + 0].r, colors[c + 0].g, colors[c + 0].b);
+					var (h2, s2, l2) = RgbToHsl(colors[c + 1].r, colors[c + 1].g, colors[c + 1].b);
+
+					for (var j = 0; j < stepsPerColor; j++)
+					{
+						var by = Math.Clamp(j / 1f / ((stepsPerColor - 1) / 1f), 0f, 1f);
+						var (h, s, l) = Lerp(h1, s1, l1, h2, s2, l2, by);
+						gradient.Add(HslToRgb(h, s, l));
+					}
+				}
+				else
+				{
+					var (r1, g1, b1) = (colors[c + 0].r / 255f, colors[c + 0].g / 255f, colors[c + 0].b / 255f);
+					var (r2, g2, b2) = (colors[c + 1].r / 255f, colors[c + 1].g / 255f, colors[c + 1].b / 255f);
+
+					for (var j = 0; j < stepsPerColor; j++)
+					{
+						var by = Math.Clamp(j / 1f / ((stepsPerColor - 1) / 1f), 0f, 1f);
+						gradient.Add(((byte)(Lerp(r1, r2, by) * 255), (byte)(Lerp(g1, g2, by) * 255), (byte)(Lerp(b1, b2, by) * 255)));
+					}
+				}
+			}
+
+			var builder = new StringBuilder();
+			for (var i = 0; i < Math.Min(gradient.Count, text.Length); i++)
+				builder.Append($"{RGB(gradient[i].r, gradient[i].g, gradient[i].b)}{text[i]}");
+			return builder.ToString();
+		}
+
+		private static float Lerp(float v1, float v2, float by) => v1 * (1f - by) + v2 * by;
+		private static (float h, float s, float l) Lerp(float h1, float s1, float l1, float h2, float s2, float l2, float by) => (Lerp(h1, h2, by) % 360f, Math.Clamp(Lerp(s1, s2, by), 0f, 1f), Math.Clamp(Lerp(l1, l2, by), 0f, 1f));
+
+		// http://www.easyrgb.com/en/math.php
+		private static (float h, float s, float l) RgbToHsl(byte red, byte green, byte blue)
+		{
+			float h = 0f, s, l;
+
+			var r = red / 255f;
+			var g = green / 255f;
+			var b = blue / 255f;
+
+			var min = Math.Min(Math.Min(r, g), b);
+			var max = Math.Max(Math.Max(r, g), b);
+			var deltaMax = max - min;
+
+			l = (max + min) / 2f;
+
+			if (deltaMax == 0)
+			{
+				h = 0;
+				s = 0;
+			}
+			else
+			{
+				if (l < 0.5f) s = deltaMax / (max + min);
+				else s = deltaMax / (2f - max - min);
+
+				var deltaR = ((max - r) / 6f + deltaMax / 2f) / deltaMax;
+				var deltaG = ((max - g) / 6f + deltaMax / 2f) / deltaMax;
+				var deltaB = ((max - b) / 6f + deltaMax / 2f) / deltaMax;
+
+				if (r == max) h = deltaB - deltaG;
+				else if (g == max) h = 1f / 3f + deltaR - deltaB;
+				else if (b == max) h = 2f / 3f + deltaG - deltaR;
+
+				if (h < 0f) h++;
+				if (h > 1f) h--;
+			}
+
+			return (h, s, l);
+		}
+
+		// http://www.easyrgb.com/en/math.php
+		private static (byte r, byte g, byte b) HslToRgb(float hue, float saturation, float lightness)
+		{
+			byte r, g, b;
+
+			if (saturation == 0f)
+			{
+				r = (byte)(lightness * 255);
+				g = (byte)(lightness * 255);
+				b = (byte)(lightness * 255);
+			}
+			else
+			{
+				float v1, v2;
+
+				if (lightness < 0.5f) v2 = lightness * (1f + saturation);
+				else v2 = lightness + saturation - saturation * lightness;
+
+				v1 = 2f * lightness - v2;
+
+				r = (byte)(255 * HueToRgb(v1, v2, hue + 1f / 3f));
+				g = (byte)(255 * HueToRgb(v1, v2, hue));
+				b = (byte)(255 * HueToRgb(v1, v2, hue - 1f / 3f));
+			}
+
+			return (r, g, b);
+		}
+
+		private static float HueToRgb(float v1, float v2, float vh)
+		{
+			if (vh < 0f) vh++;
+			if (vh > 1) vh--;
+
+			if (6f * vh < 1f) return v1 + (v2 - v1) * 6f * vh;
+			if (2f * vh < 1f) return v2;
+			if (3f * vh < 2f) return v1 + (v2 - v1) * (2f / 3f - vh) * 6f;
+			return v1;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta
new file mode 100644
index 00000000..5bf3b212
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 0f30cf7d655b21e49a24ff276bbc9861
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs
new file mode 100644
index 00000000..e9031e15
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs
@@ -0,0 +1,8 @@
+namespace StoicGoose.Common.Utilities
+{
+	public static class Bcd
+	{
+		public static int DecimalToBcd(int value) => ((value / 10) << 4) + (value % 10);
+		public static int BcdToDecimal(int value) => ((value >> 4) * 10) + value % 16;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta
new file mode 100644
index 00000000..959d47de
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e71734276750fc04990a5d08f116ee5d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs
new file mode 100644
index 00000000..2254857c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs
@@ -0,0 +1,15 @@
+namespace StoicGoose.Common.Utilities
+{
+	public static class BitHandling
+	{
+		public static void ChangeBit(ref byte value, int bit, bool state)
+		{
+			if (state)
+				value |= (byte)(1 << bit);
+			else
+				value &= (byte)~(1 << bit);
+		}
+
+		public static bool IsBitSet(byte value, int bit) => (value & (1 << bit)) != 0;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta
new file mode 100644
index 00000000..e3d4641d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d00bd13e7a297b34683f7c739fc50d46
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs
new file mode 100644
index 00000000..a835de9a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace StoicGoose.Common.Utilities
+{
+	public abstract class ConfigurationBase<T> where T : class, new()
+	{
+		public static readonly Dictionary<string, object> Defaults = default;
+
+		static ConfigurationBase()
+		{
+			Defaults = GetDefaultValues();
+		}
+
+		private static Dictionary<string, object> GetDefaultValues()
+		{
+			var dict = new Dictionary<string, object>();
+			var instance = new T();
+
+			foreach (var property in typeof(T).GetProperties().Where(x => x.CanWrite))
+			{
+				var value = property.GetValue(instance);
+				if (value == null || (property.PropertyType == typeof(string) && string.IsNullOrEmpty(value as string))) continue;
+				dict.Add(property.Name, value);
+			}
+
+			return dict;
+		}
+
+		public void ResetToDefault(string name)
+		{
+			var property = GetType().GetProperty(name);
+			if (property == null) throw new ArgumentException($"Setting '{name}' not found in {GetType().Name}", nameof(name));
+			property.SetValue(this, Defaults[name]);
+		}
+	}
+
+	public static class ConfigurationBase
+	{
+		public static void CopyConfiguration(object source, object destination)
+		{
+			if (source == null) throw new ArgumentNullException(nameof(source), "Source cannot be null");
+			if (destination == null) throw new ArgumentNullException(nameof(destination), "Destination cannot be null");
+
+			var sourceType = source.GetType();
+			var destType = destination.GetType();
+
+			foreach (var sourceProperty in sourceType.GetProperties().Where(x => x.CanRead))
+			{
+				var destProperty = destType.GetProperty(sourceProperty.Name);
+				if (destProperty == null || !destProperty.CanWrite || destProperty.GetSetMethod(true) == null || destProperty.GetSetMethod(true).IsPrivate ||
+					destProperty.GetSetMethod(true).Attributes.HasFlag(System.Reflection.MethodAttributes.Static) ||
+					!destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
+					continue;
+
+				var sourceValue = sourceProperty.GetValue(source, null);
+				var destValue = destProperty.GetValue(destination, null);
+
+				if ((sourceProperty.PropertyType.BaseType.IsGenericType ? sourceProperty.PropertyType.BaseType.GetGenericTypeDefinition() : sourceProperty.PropertyType.BaseType) == typeof(ConfigurationBase<>))
+					CopyConfiguration(sourceValue, destValue);
+				else
+					destProperty.SetValue(destination, sourceValue);
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta
new file mode 100644
index 00000000..0d0d6693
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 76e83b1a596480f48a7afe097d979b83
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs
new file mode 100644
index 00000000..e7dbfb5b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs
@@ -0,0 +1,82 @@
+using System;
+using System.IO;
+
+namespace StoicGoose.Common.Utilities
+{
+	public static class Crc32
+	{
+		static readonly uint[] crcTable;
+		static readonly uint crcPolynomial = 0xEDB88320;
+		static readonly uint crcSeed = 0xFFFFFFFF;
+
+		static Crc32()
+		{
+			crcTable = new uint[256];
+
+			for (var i = 0; i < 256; i++)
+			{
+				var entry = (uint)i;
+				for (int j = 0; j < 8; j++)
+				{
+					if ((entry & 0x00000001) == 0x00000001) entry = (entry >> 1) ^ crcPolynomial;
+					else entry >>= 1;
+				}
+				crcTable[i] = entry;
+			}
+		}
+
+		private static void VerifyStartAndLength(int dataLength, int segmentStart, int segmentLength)
+		{
+			if (segmentStart >= dataLength) throw new Exception("Segment start offset is greater than total length");
+			if (segmentLength > dataLength) throw new Exception("Segment length is greater than total length");
+			if ((segmentStart + segmentLength) > dataLength) throw new Exception("Segment end offset is greater than total length");
+		}
+
+		public static uint Calculate(FileInfo fileInfo)
+		{
+			return Calculate(fileInfo, 0, (int)fileInfo.Length);
+		}
+
+		public static uint Calculate(FileInfo fileInfo, int start, int length)
+		{
+			VerifyStartAndLength((int)fileInfo.Length, start, length);
+
+			using FileStream file = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+			return Calculate(file, start, length);
+		}
+
+		public static uint Calculate(Stream stream)
+		{
+			return Calculate(stream, 0, (int)stream.Length);
+		}
+
+		public static uint Calculate(Stream stream, int start, int length)
+		{
+			VerifyStartAndLength((int)stream.Length, start, length);
+
+			var lastStreamPosition = stream.Position;
+			var data = new byte[length];
+			stream.Position = start;
+			stream.Read(data, 0, length);
+			var crc = Calculate(data, 0, data.Length);
+			stream.Position = lastStreamPosition;
+
+			return crc;
+		}
+
+		public static uint Calculate(byte[] data)
+		{
+			return Calculate(data, 0, data.Length);
+		}
+
+		public static uint Calculate(byte[] data, int start, int length)
+		{
+			VerifyStartAndLength(data.Length, start, length);
+
+			uint crc = crcSeed;
+			for (var i = start; i < (start + length); i++)
+				crc = ((crc >> 8) ^ crcTable[data[i] ^ (crc & 0x000000FF)]);
+			return ~crc;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta
new file mode 100644
index 00000000..3ace5b40
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: afa4b03878ac3704bb52cae6e463f1f0
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs
new file mode 100644
index 00000000..37fafa20
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs
@@ -0,0 +1,87 @@
+using System.Collections.Generic;
+
+namespace StoicGoose.Common.Utilities
+{
+    public enum LogSeverity { Verbose, Debug, Information, Warning, Error, Fatal }
+    public enum LogType { Debug, Warning, Error }
+
+    public interface IStoicGooseLogger
+    {
+        public void Log(LogType logtype, string message);
+        public void Debug(string message);
+        public void Warning(string message);
+        public void Err(string message);
+    }
+
+    public static class Log
+	{
+		const string defaultTemplate = "{Message}{NewLine}{Exception}";
+
+		readonly static Dictionary<LogSeverity, LogType> severityToEventLevelMapping = new()
+		{
+			{ LogSeverity.Verbose, LogType.Debug },
+			{ LogSeverity.Debug, LogType.Debug },
+			{ LogSeverity.Information, LogType.Debug },
+			{ LogSeverity.Warning, LogType.Warning },
+			{ LogSeverity.Error, LogType.Error },
+			{ LogSeverity.Fatal, LogType.Error }
+		};
+
+		readonly static Dictionary<LogSeverity, string> logSeverityAnsiColors = new()
+		{
+			{ LogSeverity.Verbose, Ansi.White },
+			{ LogSeverity.Debug, Ansi.Cyan },
+			{ LogSeverity.Information, Ansi.Green },
+			{ LogSeverity.Warning, Ansi.Yellow },
+			{ LogSeverity.Error, Ansi.Magenta },
+			{ LogSeverity.Fatal, Ansi.Red }
+		};
+
+		static IStoicGooseLogger mainLogger;
+
+		public static void Initialize(IStoicGooseLogger logger)
+		{
+			mainLogger = logger;
+		}
+
+
+		public static void WriteLine(string message) => mainLogger.Debug(message);
+		//public static void WriteFatal(string message) => Write(LogEventLevel.Fatal, message);
+
+		//private static void Write(LogEventLevel logEventLevel, string message)
+		//{
+		//	mainLogger?.Write(logEventLevel, message);
+		//	fileLogger?.Write(logEventLevel, message.RemoveAnsi());
+		//}
+
+		public static void WriteEvent(LogSeverity severity, object source, string message)
+		{
+			var eventLevel = severityToEventLevelMapping.ContainsKey(severity) ? severityToEventLevelMapping[severity] : LogType.Debug;
+			var logMessage = $"{logSeverityAnsiColors[severity]}[{source?.GetType().Name ?? string.Empty}]{Ansi.Reset}: {message}";
+			mainLogger.Log(eventLevel, logMessage);
+		}
+	}
+
+	//class TextWriterSink : ILogEventSink
+	//{
+	//	readonly TextWriter textWriter = default;
+	//	readonly ITextFormatter textFormatter = default;
+
+	//	readonly object syncRoot = new();
+
+	//	//public TextWriterSink(TextWriter writer, ITextFormatter formatter)
+	//	//{
+	//	//	textWriter = writer;
+	//	//	textFormatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
+	//	//}
+
+	//	public void Emit(LogEvent logEvent)
+	//	{
+	//		lock (syncRoot)
+	//		{
+	//			textFormatter.Format(logEvent ?? throw new ArgumentNullException(nameof(logEvent)), textWriter);
+	//			textWriter.Flush();
+	//		}
+	//	}
+	//}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta
new file mode 100644
index 00000000..fae0e83c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 916e8e9742f5dfc41823c7eb3a544606
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs
new file mode 100644
index 00000000..cf8747b8
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs
@@ -0,0 +1,41 @@
+using System.IO;
+using System.Reflection;
+
+using StoicGoose.Common.Drawing;
+
+namespace StoicGoose.Common.Utilities
+{
+	public static class Resources
+	{
+		private static Stream GetEmbeddedResourceStream(string name)
+		{
+			var assembly = Assembly.GetEntryAssembly();
+			name = $"{assembly.GetName().Name}.{name}";
+			return assembly.GetManifestResourceStream(name);
+		}
+
+		public static RgbaFile GetEmbeddedRgbaFile(string name)
+		{
+			using var stream = GetEmbeddedResourceStream(name);
+			if (stream == null) return null;
+			return new RgbaFile(stream);
+		}
+
+		public static string GetEmbeddedText(string name)
+		{
+			using var stream = GetEmbeddedResourceStream(name);
+			if (stream == null) return string.Empty;
+			using var reader = new StreamReader(stream);
+			return reader.ReadToEnd();
+		}
+
+		public static byte[] GetEmbeddedRawData(string name)
+		{
+			using var stream = GetEmbeddedResourceStream(name);
+			if (stream == null) return null;
+			var buffer = new byte[stream.Length];
+			stream.Read(buffer, 0, buffer.Length);
+			return buffer;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta
new file mode 100644
index 00000000..bd9abd7c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 20f7f2e2f16528949b80073b5e8778f9
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta
new file mode 100644
index 00000000..87a21f1b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b4feaaee1d7195a46a3aa956e4128489
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs
new file mode 100644
index 00000000..6c8291d5
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs
@@ -0,0 +1,41 @@
+using System;
+
+using StoicGoose.Core.Interfaces;
+
+namespace StoicGoose.Core
+{
+	public class Bootstrap : IComponent
+	{
+		readonly byte[] rom = Array.Empty<byte>();
+		readonly uint romMask = 0;
+
+		public Bootstrap(int size)
+		{
+			rom = new byte[size];
+			romMask = (uint)(rom.Length - 1);
+		}
+
+		public void Reset()
+		{
+			//
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public void LoadRom(byte[] data)
+		{
+			if (data.Length != rom.Length)
+				throw new Exception("Data size mismatch error");
+
+			Buffer.BlockCopy(data, 0, rom, 0, data.Length);
+		}
+
+		public byte ReadMemory(uint address)
+		{
+			return rom[address & romMask];
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta
new file mode 100644
index 00000000..81f3bd4d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d194949ecf04a5341b082bac647c847d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta
new file mode 100644
index 00000000..89957c08
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c1c58bce2e7f29f419b70dc124e97204
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs
new file mode 100644
index 00000000..7d24034f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs
@@ -0,0 +1,96 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		private byte ReadOpcodeEb()
+		{
+			ReadModRM();
+			if (modRm.Mod == ModRM.Modes.Register)
+				return GetRegister8((RegisterNumber8)modRm.Mem);
+			else
+				return ReadMemory8(modRm.Segment, modRm.Offset);
+		}
+
+		private ushort ReadOpcodeEw()
+		{
+			ReadModRM();
+			if (modRm.Mod == ModRM.Modes.Register)
+				return GetRegister16((RegisterNumber16)modRm.Mem);
+			else
+				return ReadMemory16(modRm.Segment, modRm.Offset);
+		}
+
+		private void WriteOpcodeEb(byte value)
+		{
+			ReadModRM();
+			if (modRm.Mod == ModRM.Modes.Register)
+				SetRegister8((RegisterNumber8)modRm.Mem, value);
+			else
+				WriteMemory8(modRm.Segment, modRm.Offset, value);
+		}
+
+		private void WriteOpcodeEw(ushort value)
+		{
+			ReadModRM();
+			if (modRm.Mod == ModRM.Modes.Register)
+				SetRegister16((RegisterNumber16)modRm.Mem, value);
+			else
+				WriteMemory16(modRm.Segment, modRm.Offset, value);
+		}
+
+		private byte ReadOpcodeGb()
+		{
+			ReadModRM();
+			return GetRegister8((RegisterNumber8)modRm.Reg);
+		}
+
+		private ushort ReadOpcodeGw()
+		{
+			ReadModRM();
+			return GetRegister16((RegisterNumber16)modRm.Reg);
+		}
+
+		private void WriteOpcodeGb(byte value)
+		{
+			ReadModRM();
+			SetRegister8((RegisterNumber8)modRm.Reg, value);
+		}
+
+		private void WriteOpcodeGw(ushort value)
+		{
+			ReadModRM();
+			SetRegister16((RegisterNumber16)modRm.Reg, value);
+		}
+
+		private ushort ReadOpcodeSw()
+		{
+			ReadModRM();
+			return GetSegment((SegmentNumber)modRm.Reg);
+		}
+
+		private void WriteOpcodeSw(ushort value)
+		{
+			ReadModRM();
+			SetSegment((SegmentNumber)modRm.Reg, value);
+		}
+
+		private byte ReadOpcodeIb()
+		{
+			return ReadMemory8(cs, ip++);
+		}
+
+		private ushort ReadOpcodeIw()
+		{
+			var value = ReadMemory16(cs, ip);
+			ip += 2;
+			return value;
+		}
+
+		private ushort ReadOpcodeJb()
+		{
+			var tmp1 = (ushort)(ip + 1);
+			var tmp2 = (sbyte)ReadOpcodeIb();
+			return (ushort)(tmp1 + tmp2);
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta
new file mode 100644
index 00000000..896b0df7
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e1f6daccd87f15e48a0e766b94f6d27f
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs
new file mode 100644
index 00000000..6176b021
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		[Flags]
+		public enum Flags : ushort
+		{
+			Carry = 1 << 0,            /* CF */
+			ReservedB1 = 1 << 1,       /* (reserved) */
+			Parity = 1 << 2,           /* PF */
+			ReservedB3 = 1 << 3,       /* (reserved) */
+			Auxiliary = 1 << 4,        /* AF */
+			ReservedB5 = 1 << 5,       /* (reserved) */
+			Zero = 1 << 6,             /* ZF */
+			Sign = 1 << 7,             /* SF */
+			Trap = 1 << 8,             /* TF */
+			InterruptEnable = 1 << 9,  /* IF */
+			Direction = 1 << 10,       /* DF */
+			Overflow = 1 << 11,        /* OF */
+			ReservedB12 = 1 << 12,     /* (reserved) */
+			ReservedB13 = 1 << 13,     /* (reserved) */
+			ReservedB14 = 1 << 14,     /* (reserved) */
+			ReservedB15 = 1 << 15      /* (reserved) */
+		}
+
+		private void SetFlags(Flags flags)
+		{
+			this.flags |= flags;
+		}
+
+		private void ClearFlags(Flags flags)
+		{
+			this.flags &= ~flags;
+		}
+
+		public bool IsFlagSet(Flags flags)
+		{
+			return (this.flags & flags) == flags;
+		}
+
+		private void SetClearFlagConditional(Flags flags, bool condition)
+		{
+			if (condition) this.flags |= flags;
+			else this.flags &= ~flags;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta
new file mode 100644
index 00000000..df94a71a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 8d3774b3b6efb724ca93707535be9a35
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs
new file mode 100644
index 00000000..bf54af7b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs
@@ -0,0 +1,527 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		private byte Add8(bool withCarry, byte a, byte b)
+		{
+			int result = a + b + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0);
+
+			// CF, PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, (result & 0x100) != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ b) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Add16(bool withCarry, ushort a, ushort b)
+		{
+			int result = a + b + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0);
+
+			// CF, PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, (result & 0x10000) != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ b) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private byte Or8(byte a, byte b)
+		{
+			int result = a | b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (byte)result;
+		}
+
+		private ushort Or16(ushort a, ushort b)
+		{
+			int result = a | b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (ushort)result;
+		}
+
+		private byte Sub8(bool withBorrow, byte a, byte b)
+		{
+			int result = a - (b + (withBorrow && IsFlagSet(Flags.Carry) ? 1 : 0));
+
+			// CF, PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, (result & 0x100) != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ b) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Sub16(bool withBorrow, ushort a, ushort b)
+		{
+			int result = a - (b + (withBorrow && IsFlagSet(Flags.Carry) ? 1 : 0));
+
+			// CF, PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, (result & 0x10000) != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ b) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private byte And8(byte a, byte b)
+		{
+			int result = a & b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (byte)result;
+		}
+
+		private ushort And16(ushort a, ushort b)
+		{
+			int result = a & b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (ushort)result;
+		}
+
+		private void Daa(bool isSubtract)
+		{
+			byte oldAl = ax.Low;
+
+			if (((oldAl & 0x0F) > 0x09) || IsFlagSet(Flags.Auxiliary))
+			{
+				ax.Low += (byte)(isSubtract ? -0x06 : 0x06);
+				SetFlags(Flags.Auxiliary);
+			}
+			else
+				ClearFlags(Flags.Auxiliary);
+
+			if ((oldAl > 0x99) || IsFlagSet(Flags.Carry))
+			{
+				ax.Low += (byte)(isSubtract ? -0x60 : 0x60);
+				SetFlags(Flags.Carry);
+			}
+			else
+				ClearFlags(Flags.Carry);
+
+			SetClearFlagConditional(Flags.Parity, CalculateParity(ax.Low & 0xFF));
+			SetClearFlagConditional(Flags.Zero, (ax.Low & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (ax.Low & 0x80) != 0);
+		}
+
+		private byte Xor8(byte a, byte b)
+		{
+			int result = a ^ b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (byte)result;
+		}
+
+		private ushort Xor16(ushort a, ushort b)
+		{
+			int result = a ^ b;
+
+			// CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined
+			ClearFlags(Flags.Carry);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			ClearFlags(Flags.Overflow);
+
+			return (ushort)result;
+		}
+
+		private void Aaa(bool isSubtract)
+		{
+			if (((ax.Low & 0x0F) > 0x09) || IsFlagSet(Flags.Auxiliary))
+			{
+				ax.Low = (byte)(ax.Low + (isSubtract ? -0x06 : 0x06));
+				ax.High = (byte)(ax.High + (isSubtract ? -0x01 : 0x01));
+
+				SetFlags(Flags.Auxiliary);
+				SetFlags(Flags.Carry);
+			}
+			else
+			{
+				ClearFlags(Flags.Auxiliary);
+				ClearFlags(Flags.Carry);
+			}
+
+			ax.Low &= 0x0F;
+		}
+
+		private byte Inc8(byte a)
+		{
+			int result = a + 1;
+
+			// PF, AF, ZF, SF, OF = according to result, CF = undefined
+			//Carry
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ 1) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Inc16(ushort a)
+		{
+			int result = a + 1;
+
+			// PF, AF, ZF, SF, OF = according to result, CF = undefined
+			//Carry
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ 1) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private byte Dec8(byte a)
+		{
+			int result = a - 1;
+
+			// PF, AF, ZF, SF, OF = according to result, CF = undefined
+			//Carry
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ 1) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Dec16(ushort a)
+		{
+			int result = a - 1;
+
+			// PF, AF, ZF, SF, OF = according to result, CF = undefined
+			//Carry
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ 1) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private byte Rol8(bool withCarry, byte a, byte b)
+		{
+			int result;
+
+			if (withCarry)
+			{
+				result = a;
+				for (var n = 0; n < b; n++)
+				{
+					var carry = result & 0x80;
+					result = (result << 1) | (IsFlagSet(Flags.Carry) ? 0x01 : 0);
+					SetClearFlagConditional(Flags.Carry, carry != 0);
+				}
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0);
+				result &= 0xFF;
+			}
+			else
+			{
+				result = (a << b) | (a >> (8 - b));
+				SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 8)) != 0);
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0);
+				result &= 0xFF;
+			}
+
+			return (byte)result;
+		}
+
+		private ushort Rol16(bool withCarry, ushort a, ushort b)
+		{
+			int result;
+
+			if (withCarry)
+			{
+				result = a;
+				for (var n = 0; n < b; n++)
+				{
+					var carry = result & 0x80;
+					result = (result << 1) | (IsFlagSet(Flags.Carry) ? 0x0001 : 0);
+					SetClearFlagConditional(Flags.Carry, carry != 0);
+				}
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0);
+				result &= 0xFFFF;
+			}
+			else
+			{
+				result = (a << b) | (a >> (16 - b));
+				SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 16)) != 0);
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0);
+				result &= 0xFFFF;
+			}
+
+			return (ushort)result;
+		}
+
+		private byte Ror8(bool withCarry, byte a, byte b)
+		{
+			int result;
+
+			if (withCarry)
+			{
+				result = a;
+				for (var n = 0; n < b; n++)
+				{
+					var carry = result & 0x01;
+					result = (IsFlagSet(Flags.Carry) ? 0x80 : 0) | (result >> 1);
+					SetClearFlagConditional(Flags.Carry, carry != 0);
+				}
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0);
+				result &= 0xFF;
+			}
+			else
+			{
+				result = (a >> b) | (a << (8 - b));
+				SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & 0x01) != 0);
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0);
+				result &= 0xFF;
+			}
+
+			return (byte)result;
+		}
+
+		private ushort Ror16(bool withCarry, ushort a, ushort b)
+		{
+			int result;
+
+			if (withCarry)
+			{
+				result = a;
+				for (var n = 0; n < b; n++)
+				{
+					var carry = result & 0x01;
+					result = (IsFlagSet(Flags.Carry) ? 0x8000 : 0) | (result >> 1);
+					SetClearFlagConditional(Flags.Carry, carry != 0);
+				}
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0);
+				result &= 0xFFFF;
+			}
+			else
+			{
+				result = (a >> b) | (a << (16 - b));
+				SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & 0x01) != 0);
+				SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0);
+				result &= 0xFFFF;
+			}
+
+			return (ushort)result;
+		}
+
+		private byte Shl8(byte a, byte b)
+		{
+			int result = (a << b) & 0xFF;
+
+			if (b != 0)
+			{
+				SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 8)) != 0);
+				SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+				//Aux
+				SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+				SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+				if (b == 1) SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0);
+			}
+
+			return (byte)result;
+		}
+
+		private ushort Shl16(ushort a, ushort b)
+		{
+			int result = (a << b) & 0xFFFF;
+
+			if (b != 0)
+			{
+				SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 16)) != 0);
+				SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+				//Aux
+				SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+				SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+				if (b == 1) SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0);
+			}
+
+			return (ushort)result;
+		}
+
+		private byte Shr8(bool signed, byte a, byte b)
+		{
+			if (signed && (b & 16) != 0)
+			{
+				SetClearFlagConditional(Flags.Carry, (a & 0x80) != 0);
+				return (byte)(0 - (IsFlagSet(Flags.Carry) ? 1 : 0));
+			}
+
+			int result = (a >> b) & 0xFF;
+
+			SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & (1 << 0)) != 0);
+			if (signed && (a & 0x80) != 0) result |= 0xFF << (8 - b);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, !signed && ((a ^ result) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Shr16(bool signed, ushort a, ushort b)
+		{
+			if (signed && (b & 16) != 0)
+			{
+				SetClearFlagConditional(Flags.Carry, (a & 0x8000) != 0);
+				return (ushort)(0 - (IsFlagSet(Flags.Carry) ? 1 : 0));
+			}
+
+			int result = (a >> b) & 0xFFFF;
+
+			SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & (1 << 0)) != 0);
+			if (signed && (a & 0x8000) != 0) result |= 0xFFFF << (16 - b);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			//Aux
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, !signed && ((a ^ result) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private byte Neg8(byte b)
+		{
+			int result = -b & 0xFF;
+
+			// CF = is operand non-zero?; PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, b != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((0 ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ 0) & (0 ^ b) & 0x80) != 0);
+
+			return (byte)result;
+		}
+
+		private ushort Neg16(ushort b)
+		{
+			int result = -b & 0xFFFF;
+
+			// CF = is operand non-zero?; PF, AF, ZF, SF, OF = according to result
+			SetClearFlagConditional(Flags.Carry, b != 0);
+			SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF));
+			SetClearFlagConditional(Flags.Auxiliary, ((0 ^ b ^ result) & 0x10) != 0);
+			SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0);
+			SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0);
+			SetClearFlagConditional(Flags.Overflow, ((result ^ 0) & (0 ^ b) & 0x8000) != 0);
+
+			return (ushort)result;
+		}
+
+		private ushort Mul8(bool signed, byte a, byte b)
+		{
+			uint result = (uint)(signed ? ((sbyte)a * (sbyte)b) : (a * b));
+
+			// CF, OF = is upper half of result non-zero?; PF, AF, ZF, SF = undefined
+			SetClearFlagConditional(Flags.Overflow, (result >> 8) != 0);
+			SetClearFlagConditional(Flags.Carry, (result >> 8) != 0);
+
+			return (ushort)result;
+		}
+
+		private uint Mul16(bool signed, ushort a, ushort b)
+		{
+			uint result = (uint)(signed ? ((short)a * (short)b) : (a * b));
+
+			// CF, OF = is upper half of result non-zero?; PF, AF, ZF, SF = undefined
+			SetClearFlagConditional(Flags.Overflow, (result >> 16) != 0);
+			SetClearFlagConditional(Flags.Carry, (result >> 16) != 0);
+
+			return (uint)result;
+		}
+
+		private ushort Div8(bool signed, ushort a, byte b)
+		{
+			if (b == 0)
+			{
+				Interrupt(0);
+				return a;
+			}
+
+			int quotient = signed ? ((short)a / (sbyte)b) : (a / b);
+			int remainder = signed ? ((short)a % (sbyte)b) : (a % b);
+
+			// CF, PF, AF, ZF, SF, OF = undefined
+
+			return (ushort)(((remainder & 0xFF) << 8) | (quotient & 0xFF));
+		}
+
+		private uint Div16(bool signed, uint a, ushort b)
+		{
+			if (b == 0)
+			{
+				Interrupt(0);
+				return a;
+			}
+
+			int quotient = signed ? ((int)a / (short)b) : (int)(a / b);
+			int remainder = signed ? ((int)a % (short)b) : (int)(a % b);
+
+			// CF, PF, AF, ZF, SF, OF = undefined
+
+			return (uint)(((remainder & 0xFFFF) << 16) | (quotient & 0xFFFF));
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta
new file mode 100644
index 00000000..6d72ba97
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5828627e3b453af4f9d1280493414226
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs
new file mode 100644
index 00000000..bec472ff
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs
@@ -0,0 +1,37 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		private byte ReadMemory8(ushort segment, ushort offset)
+		{
+			return machine.ReadMemory((uint)((segment << 4) + offset));
+		}
+
+		private ushort ReadMemory16(ushort segment, ushort offset)
+		{
+			return (ushort)((machine.ReadMemory((uint)((segment << 4) + offset + 1)) << 8) | machine.ReadMemory((uint)((segment << 4) + offset)));
+		}
+
+		private void WriteMemory8(ushort segment, ushort offset, byte value)
+		{
+			machine.WriteMemory((uint)((segment << 4) + offset), value);
+		}
+
+		private void WriteMemory16(ushort segment, ushort offset, ushort value)
+		{
+			machine.WriteMemory((uint)((segment << 4) + offset), (byte)(value & 0xFF));
+			machine.WriteMemory((uint)((segment << 4) + offset + 1), (byte)(value >> 8));
+		}
+
+		private ushort ReadPort16(ushort port)
+		{
+			return (ushort)(machine.ReadPort((ushort)(port + 1)) << 8 | machine.ReadPort(port));
+		}
+
+		private void WritePort16(ushort port, ushort value)
+		{
+			machine.WritePort(port, (byte)(value & 0xFF));
+			machine.WritePort((ushort)(port + 1), (byte)(value >> 8));
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta
new file mode 100644
index 00000000..dd169ae1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 9fbe65ebef4c3df439fcb960d59e10f6
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs
new file mode 100644
index 00000000..85fd8c26
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs
@@ -0,0 +1,48 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		private void Push(ushort value)
+		{
+			sp -= 2;
+			WriteMemory16(ss, sp, value);
+		}
+
+		private ushort Pop()
+		{
+			var value = ReadMemory16(ss, sp);
+			sp += 2;
+			return value;
+		}
+
+		private int Loop()
+		{
+			if (--cx.Word != 0) { ip = ReadOpcodeJb(); return 4; }
+			else { ip++; return 1; }
+		}
+
+		private int LoopWhile(bool condition)
+		{
+			if (--cx.Word != 0 && condition) { ip = ReadOpcodeJb(); return 5; }
+			else { ip++; return 2; }
+		}
+
+		private int JumpConditional(bool condition)
+		{
+			if (condition) { ip = ReadOpcodeJb(); return 4; }
+			else { ip++; return 1; }
+		}
+
+		private static bool CalculateParity(int result)
+		{
+			int bitsSet = 0;
+			while (result != 0) { bitsSet += result & 0x01; result >>= 1; }
+			return bitsSet == 0 || (bitsSet % 2) == 0;
+		}
+
+		private static void Exchange(ref ushort a, ref ushort b)
+		{
+			(b, a) = (a, b);
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta
new file mode 100644
index 00000000..38796998
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 253866b049a8cb445ab91a6c6cbb65e7
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs
new file mode 100644
index 00000000..6e56bae2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs
@@ -0,0 +1,103 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		ModRM modRm;
+
+		private void ReadModRM()
+		{
+			if (modRm.IsSet) return;
+
+			modRm.Set(ReadMemory8(cs, ip++));
+			switch (modRm.Mod)
+			{
+				case ModRM.Modes.NoDisplacement:
+					switch (modRm.Mem)
+					{
+						case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si); break;
+						case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di); break;
+						case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si); break;
+						case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di); break;
+						case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = si; break;
+						case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = di; break;
+						case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = ReadMemory16(cs, ip); ip += 2; break;
+						case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = bx.Word; break;
+					}
+					break;
+
+				case ModRM.Modes.OneByteDisplacement:
+					{
+						var displacement = (sbyte)ReadMemory8(cs, ip);
+						ip++;
+						switch (modRm.Mem)
+						{
+							case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si + displacement); break;
+							case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di + displacement); break;
+							case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si + displacement); break;
+							case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di + displacement); break;
+							case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(si + displacement); break;
+							case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(di + displacement); break;
+							case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + displacement); break;
+							case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + displacement); break;
+						}
+					}
+					break;
+
+				case ModRM.Modes.TwoByteDisplacement:
+					{
+						var displacement = (short)ReadMemory16(cs, ip);
+						ip += 2;
+						switch (modRm.Mem)
+						{
+							case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si + displacement); break;
+							case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di + displacement); break;
+							case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si + displacement); break;
+							case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di + displacement); break;
+							case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(si + displacement); break;
+							case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(di + displacement); break;
+							case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + displacement); break;
+							case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + displacement); break;
+						}
+					}
+					break;
+			}
+		}
+
+		struct ModRM
+		{
+			public enum Modes : byte
+			{
+				NoDisplacement = 0b00,
+				OneByteDisplacement = 0b01,
+				TwoByteDisplacement = 0b10,
+				Register = 0b11
+			}
+
+			byte data;
+
+			public Modes Mod => (Modes)((data >> 6) & 0b11);
+			public byte Reg => (byte)((data >> 3) & 0b111);
+			public byte Mem => (byte)((data >> 0) & 0b111);
+
+			public ushort Segment, Offset;
+
+			public bool IsSet;
+
+			public void Set(byte value)
+			{
+				data = value;
+
+				IsSet = true;
+			}
+
+			public void Reset()
+			{
+				data = 0;
+				Segment = 0;
+				Offset = 0;
+
+				IsSet = false;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta
new file mode 100644
index 00000000..f6572ae1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a81e97a11c345494da1d600ffa5e81c2
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs
new file mode 100644
index 00000000..ec4a90ad
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs
@@ -0,0 +1,905 @@
+using System;
+
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		delegate int Instruction(V30MZ cpu);
+		readonly static Instruction[] instructions = new Instruction[256]
+		{
+			/* 0x00 */      /* ADD Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.Add8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* ADD Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* ADD Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.Add8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* ADD Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.Add16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x04 */      /* ADD AL Ib */                 (cpu) => { cpu.ax.Low = cpu.Add8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* ADD AX Iw */                 (cpu) => { cpu.ax.Word = cpu.Add16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* PUSH ES */                   (cpu) => { cpu.Push(cpu.es); return 1; },
+							/* POP ES */                    (cpu) => { cpu.es = cpu.Pop(); return 1; },
+			/* 0x08 */      /* OR Eb Gb */                  (cpu) => { cpu.WriteOpcodeEb(cpu.Or8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* OR Ew Gw */                  (cpu) => { cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* OR Gb Eb */                  (cpu) => { cpu.WriteOpcodeGb(cpu.Or8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* OR Gw Ew */                  (cpu) => { cpu.WriteOpcodeGw(cpu.Or16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x0C */      /* OR AL Ib */                  (cpu) => { cpu.ax.Low = cpu.Or8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* OR AX Iw */                  (cpu) => { cpu.ax.Word = cpu.Or16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* PUSH CS */                   (cpu) => { cpu.Push(cpu.cs); return 1; },
+							/* (Invalid; NOP?) */			(cpu) => 3,
+
+			/* 0x10 */      /* ADC Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.Add8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* ADC Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* ADC Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.Add8(true, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* ADC Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.Add16(true, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x14 */      /* ADC AL Ib */                 (cpu) => { cpu.ax.Low = cpu.Add8(true, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* ADC AX Iw */                 (cpu) => { cpu.ax.Word = cpu.Add16(true, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* PUSH SS */                   (cpu) => { cpu.Push(cpu.ss); return 1; },
+							/* POP SS */                    (cpu) => { cpu.ss = cpu.Pop(); return 1; },
+			/* 0x18 */      /* SBB Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.Sub8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* SBB Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* SBB Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.Sub8(true, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* SBB Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.Sub16(true, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x1C */      /* SBB AL Ib */                 (cpu) => { cpu.ax.Low = cpu.Sub8(true, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* SBB AX Iw */                 (cpu) => { cpu.ax.Word = cpu.Sub16(true, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* PUSH DS */                   (cpu) => { cpu.Push(cpu.ds); return 1; },
+							/* POP DS */                    (cpu) => { cpu.ds = cpu.Pop(); return 1; },
+                            
+			/* 0x20 */      /* AND Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* AND Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* AND Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.And8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* AND Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.And16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x24 */      /* AND AL Ib */                 (cpu) => { cpu.ax.Low = cpu.And8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* AND AX Iw */                 (cpu) => { cpu.ax.Word = cpu.And16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* (Prefix ES) */               (cpu) => 0,
+							/* DAA */                       (cpu) => { cpu.Daa(false); return 10; },
+			/* 0x28 */      /* SUB Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* SUB Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* SUB Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.Sub8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* SUB Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.Sub16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x2C */      /* SUB AL Ib */                 (cpu) => { cpu.ax.Low = cpu.Sub8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* SUB AX Iw */                 (cpu) => { cpu.ax.Word = cpu.Sub16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* (Prefix CS) */               (cpu) => 0,
+							/* DAS */                       (cpu) => { cpu.Daa(true); return 10; },
+                            
+			/* 0x30 */      /* XOR Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.Xor8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; },
+							/* XOR Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; },
+							/* XOR Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.Xor8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; },
+							/* XOR Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.Xor16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; },
+			/* 0x34 */      /* XOR AL Ib */                 (cpu) => { cpu.ax.Low = cpu.Xor8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* XOR AX Iw */                 (cpu) => { cpu.ax.Word = cpu.Xor16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* (Prefix SS) */               (cpu) => 0,
+							/* AAA */                       (cpu) => { cpu.Aaa(false); return 9; },
+			/* 0x38 */      /* CMP Eb Gb */                 (cpu) => { cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb()); return 1; },
+							/* CMP Ew Gw */                 (cpu) => { cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw()); return 1; },
+							/* CMP Gb Eb */                 (cpu) => { cpu.Sub8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb()); return 1; },
+							/* CMP Gw Ew */                 (cpu) => { cpu.Sub16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw()); return 1; },
+			/* 0x3C */      /* CMP AL Ib */                 (cpu) => { cpu.Sub8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* CMP AX Iw */                 (cpu) => { cpu.Sub16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* (Prefix DS) */               (cpu) => 0,
+							/* AAS */                       (cpu) => { cpu.Aaa(true); return 9; },
+
+			/* 0x40 */      /* INC AX */                    (cpu) => { cpu.ax.Word = cpu.Inc16(cpu.ax.Word); return 1; },
+							/* INC CX */                    (cpu) => { cpu.cx.Word = cpu.Inc16(cpu.cx.Word); return 1; },
+							/* INC DX */                    (cpu) => { cpu.dx.Word = cpu.Inc16(cpu.dx.Word); return 1; },
+							/* INC BX */                    (cpu) => { cpu.bx.Word = cpu.Inc16(cpu.bx.Word); return 1; },
+			/* 0x44 */      /* INC SP */                    (cpu) => { cpu.sp = cpu.Inc16(cpu.sp); return 1; },
+							/* INC BP */                    (cpu) => { cpu.bp = cpu.Inc16(cpu.bp); return 1; },
+							/* INC SI */                    (cpu) => { cpu.si = cpu.Inc16(cpu.si); return 1; },
+							/* INC DI */                    (cpu) => { cpu.di = cpu.Inc16(cpu.di); return 1; },
+			/* 0x48 */      /* DEC AX */                    (cpu) => { cpu.ax.Word = cpu.Dec16(cpu.ax.Word); return 1; },
+							/* DEC CX */                    (cpu) => { cpu.cx.Word = cpu.Dec16(cpu.cx.Word); return 1; },
+							/* DEC DX */                    (cpu) => { cpu.dx.Word = cpu.Dec16(cpu.dx.Word); return 1; },
+							/* DEC BX */                    (cpu) => { cpu.bx.Word = cpu.Dec16(cpu.bx.Word); return 1; },
+			/* 0x4C */      /* DEC SP */                    (cpu) => { cpu.sp = cpu.Dec16(cpu.sp); return 1; },
+							/* DEC BP */                    (cpu) => { cpu.bp = cpu.Dec16(cpu.bp); return 1; },
+							/* DEC SI */                    (cpu) => { cpu.si = cpu.Dec16(cpu.si); return 1; },
+							/* DEC DI */                    (cpu) => { cpu.di = cpu.Dec16(cpu.di); return 1; },
+
+			/* 0x50 */      /* PUSH AX */                   (cpu) => { cpu.Push(cpu.ax.Word); return 1; },
+							/* PUSH CX */                   (cpu) => { cpu.Push(cpu.cx.Word); return 1; },
+							/* PUSH DX */                   (cpu) => { cpu.Push(cpu.dx.Word); return 1; },
+							/* PUSH BX */                   (cpu) => { cpu.Push(cpu.bx.Word); return 1; },
+			/* 0x54 */      /* PUSH SP */                   (cpu) => { cpu.Push(cpu.sp); return 1; },
+							/* PUSH BP */                   (cpu) => { cpu.Push(cpu.bp); return 1; },
+							/* PUSH SI */                   (cpu) => { cpu.Push(cpu.si); return 1; },
+							/* PUSH DI */                   (cpu) => { cpu.Push(cpu.di); return 1; },
+			/* 0x58 */      /* POP AX */                    (cpu) => { cpu.ax.Word = cpu.Pop(); return 1; },
+							/* POP CX */                    (cpu) => { cpu.cx.Word = cpu.Pop(); return 1; },
+							/* POP DX */                    (cpu) => { cpu.dx.Word = cpu.Pop(); return 1; },
+							/* POP BX */                    (cpu) => { cpu.bx.Word = cpu.Pop(); return 1; },
+			/* 0x5C */      /* POP SP */                    (cpu) => { cpu.sp = cpu.Pop(); return 1; },
+							/* POP BP */                    (cpu) => { cpu.bp = cpu.Pop(); return 1; },
+							/* POP SI */                    (cpu) => { cpu.si = cpu.Pop(); return 1; },
+							/* POP DI */                    (cpu) => { cpu.di = cpu.Pop(); return 1; },
+
+			/* 0x60 */      /* PUSHA */                     Opcode0x60,
+							/* POPA */                      Opcode0x61,
+							/* BOUND Gw E */                Opcode0x62,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+			/* 0x64 */      /* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+			/* 0x68 */      /* PUSH Iw */                   (cpu) => { cpu.Push(cpu.ReadOpcodeIw()); return 1; },
+							/* IMUL Gw Ew Iw */             (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeGw((ushort)cpu.Mul16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); return 4; },
+							/* PUSH Ib */                   (cpu) => { cpu.Push((ushort)(sbyte)cpu.ReadOpcodeIb()); return 1; },
+							/* IMUL Gb Eb Ib */             (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeGw((ushort)cpu.Mul16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); return 4; },
+			/* 0x6C */      /* INSB */                      Opcode0x6C,
+							/* INSW */                      Opcode0x6D,
+							/* OUTSB */                     Opcode0x6E,
+							/* OUTSW */                     Opcode0x6F,
+
+			/* 0x70 */      /* JO */                        (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Overflow)),
+							/* JNO */                       (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Overflow)),
+							/* JB */                        (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Carry)),
+							/* JNB */                       (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Carry)),
+			/* 0x74 */      /* JZ */                        (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero)),
+							/* JNZ */                       (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero)),
+							/* JBE */                       (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Carry) || cpu.IsFlagSet(Flags.Zero)),
+							/* JA */                        (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Carry) && !cpu.IsFlagSet(Flags.Zero)),
+			/* 0x78 */      /* JS */                        (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Sign)),
+							/* JNS */                       (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Sign)),
+							/* JPE */                       (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Parity)),
+							/* JPO */                       (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Parity)),
+			/* 0x7C */      /* JL */                        (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero) && cpu.IsFlagSet(Flags.Sign) != cpu.IsFlagSet(Flags.Overflow)),
+							/* JGE */                       (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero) || cpu.IsFlagSet(Flags.Sign) == cpu.IsFlagSet(Flags.Overflow)),
+							/* JLE */                       (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero) || cpu.IsFlagSet(Flags.Sign) != cpu.IsFlagSet(Flags.Overflow)),
+							/* JG */                        (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero) && cpu.IsFlagSet(Flags.Sign) == cpu.IsFlagSet(Flags.Overflow)),
+
+			/* 0x80 */      /* GRP1 Eb Ib */                Opcode0x80,
+							/* GRP1 Ew Iw */                Opcode0x81,
+							/* GRP1 Eb Ib */                Opcode0x80,
+							/* GRP1 Ew Ib */                Opcode0x83,
+			/* 0x84 */      /* TEST Gb Eb */                (cpu) => { cpu.And8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb()); return 1; },
+							/* TEST Gw Ew */                (cpu) => { cpu.And16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw()); return 1; },
+							/* XCHG Gb Eb */                (cpu) => { var temp = cpu.ReadOpcodeGb(); cpu.WriteOpcodeGb(cpu.ReadOpcodeEb()); cpu.WriteOpcodeEb(temp); return 3; },
+							/* XCHG Gw Ew */                (cpu) => { var temp = cpu.ReadOpcodeGw(); cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); cpu.WriteOpcodeEw(temp); return 3; },
+			/* 0x88 */      /* MOV Eb Gb */                 (cpu) => { cpu.WriteOpcodeEb(cpu.ReadOpcodeGb()); return 1; },
+							/* MOV Ew Gw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.ReadOpcodeGw()); return 1; },
+							/* MOV Gb Eb */                 (cpu) => { cpu.WriteOpcodeGb(cpu.ReadOpcodeEb()); return 1; },
+							/* MOV Gw Ew */                 (cpu) => { cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); return 1; },
+			/* 0x8C */      /* MOV Ew Sw */                 (cpu) => { cpu.WriteOpcodeEw(cpu.ReadOpcodeSw()); return 1; },
+							/* LEA Gw M */                  Opcode0x8D,
+							/* MOV Sw Ew */                 (cpu) => { cpu.WriteOpcodeSw(cpu.ReadOpcodeEw()); return 1; },
+							/* POP Ew */                    (cpu) => { cpu.WriteOpcodeEw(cpu.Pop()); return 1; },
+
+			/* 0x90 */      /* NOP (XCHG AX AX) */          (cpu) => { Exchange(ref cpu.ax.Word, ref cpu.ax.Word); return 3; },
+							/* XCHG CX AX */                (cpu) => { Exchange(ref cpu.cx.Word, ref cpu.ax.Word); return 3; },
+							/* XCHG DX AX */                (cpu) => { Exchange(ref cpu.dx.Word, ref cpu.ax.Word); return 3; },
+							/* XCHG BX AX */                (cpu) => { Exchange(ref cpu.bx.Word, ref cpu.ax.Word); return 3; },
+			/* 0x94 */      /* XCHG SP AX */                (cpu) => { Exchange(ref cpu.sp, ref cpu.ax.Word); return 3; },
+							/* XCHG BP AX */                (cpu) => { Exchange(ref cpu.bp, ref cpu.ax.Word); return 3; },
+							/* XCHG SI AX */                (cpu) => { Exchange(ref cpu.si, ref cpu.ax.Word); return 3; },
+							/* XCHG DI AX */                (cpu) => { Exchange(ref cpu.di, ref cpu.ax.Word); return 3; },
+			/* 0x98 */      /* CBW */                       (cpu) => { cpu.ax.Word = (ushort)(sbyte)cpu.ax.Low; return 2; },
+							/* CWD */                       (cpu) => { var value = (uint)(short)cpu.ax.Word; cpu.dx.Word = (ushort)((value >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((value >> 0) & 0xFFFF); return 2; },
+							/* CALL Ap */                   Opcode0x9A,
+							/* WAIT */                      (cpu) => 1,
+			/* 0x9C */      /* PUSHF */                     (cpu) => { cpu.Push((ushort)cpu.flags); return 1; },
+							/* POPF */                      (cpu) => { cpu.flags = (Flags)cpu.Pop(); return 1; },
+							/* SAHF */                      Opcode0x9E,
+							/* LAHF */                      (cpu) => { cpu.ax.High = (byte)cpu.flags; return 2; },
+
+			/* 0xA0 */      /* MOV AL Aw */                 (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw()); return 1; },
+							/* MOV AX Aw */                 (cpu) => { cpu.ax.Word = cpu.ReadMemory16(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw()); return 1; },
+							/* MOV Aw AL */                 (cpu) => { cpu.WriteMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw(), cpu.ax.Low); return 1; },
+							/* MOV Aw AX */                 (cpu) => { cpu.WriteMemory16(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw(), cpu.ax.Word); return 1; },
+			/* 0xA4 */      /* MOVSB */                     Opcode0xA4,
+							/* MOVSW */                     Opcode0xA5,
+							/* CMPSB */                     Opcode0xA6,
+							/* CMPSW */                     Opcode0xA7,
+			/* 0xA8 */      /* TEST AL Ib */                (cpu) => { cpu.And8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; },
+							/* TEST AX Iw */                (cpu) => { cpu.And16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; },
+							/* STOSB */                     Opcode0xAA,
+							/* STOSW */                     Opcode0xAB,
+			/* 0xAC */      /* LODSB */                     Opcode0xAC,
+							/* LODSW */                     Opcode0xAD,
+							/* SCASB */                     Opcode0xAE,
+							/* SCASW */                     Opcode0xAF,
+
+			/* 0xB0 */      /* MOV AL Ib */                 (cpu) => { cpu.ax.Low = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV CL Ib */                 (cpu) => { cpu.cx.Low = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV DL Ib */                 (cpu) => { cpu.dx.Low = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV BL Ib */                 (cpu) => { cpu.bx.Low = cpu.ReadOpcodeIb(); return 1; },
+			/* 0xB4 */      /* MOV AH Ib */                 (cpu) => { cpu.ax.High = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV CH Ib */                 (cpu) => { cpu.cx.High = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV DH Ib */                 (cpu) => { cpu.dx.High = cpu.ReadOpcodeIb(); return 1; },
+							/* MOV BH Ib */                 (cpu) => { cpu.bx.High = cpu.ReadOpcodeIb(); return 1; },
+			/* 0xB8 */      /* MOV AX Iw */                 (cpu) => { cpu.ax.Word = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV CX Iw */                 (cpu) => { cpu.cx.Word = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV DX Iw */                 (cpu) => { cpu.dx.Word = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV BX Iw */                 (cpu) => { cpu.bx.Word = cpu.ReadOpcodeIw(); return 1; },
+			/* 0xBC */      /* MOV SP Iw */                 (cpu) => { cpu.sp = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV BP Iw */                 (cpu) => { cpu.bp = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV SI Iw */                 (cpu) => { cpu.si = cpu.ReadOpcodeIw(); return 1; },
+							/* MOV DI Iw */                 (cpu) => { cpu.di = cpu.ReadOpcodeIw(); return 1; },
+
+			/* 0xC0 */      /* GRP2 Eb Ib */                Opcode0xC0,
+							/* GRP2 Ew Ib */                Opcode0xC1,
+							/* RET Iw */                    (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip = cpu.Pop(); cpu.sp += offset; return 5; },
+							/* RET */                       (cpu) => { cpu.ip = cpu.Pop(); return 5; },
+			/* 0xC4 */      /* LES Gw Mp */                 Opcode0xC4,
+							/* LDS Gw Mp */                 Opcode0xC5,
+							/* MOV Eb Ib */                 (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeEb(cpu.ReadOpcodeIb()); return 1; },
+							/* MOV Ew Iw */                 (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeEw(cpu.ReadOpcodeIw()); return 1; },
+			/* 0xC8 */      /* ENTER */                     Opcode0xC8,
+							/* LEAVE */                     (cpu) => { cpu.sp = cpu.bp; cpu.bp = cpu.Pop(); return 1; },
+							/* RETF Iw */                   (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); cpu.sp += offset; return 8; },
+							/* RETF */                      (cpu) => { cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); return 7; },
+			/* 0xCC */      /* INT 3 */                     (cpu) => { cpu.Interrupt(3); return 8; },
+							/* INT Ib */                    (cpu) => { cpu.Interrupt(cpu.ReadOpcodeIb()); return 9; },
+							/* INTO */                      (cpu) => { if (cpu.IsFlagSet(Flags.Overflow)) cpu.Interrupt(4); return 5; },
+							/* IRET */                      (cpu) => { cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); cpu.flags = (Flags)cpu.Pop(); return 9; },
+
+			/* 0xD0 */      /* GRP2 Eb 1 */                 Opcode0xD0,
+							/* GRP2 Ew 1 */                 Opcode0xD1,
+							/* GRP2 Eb CL */                Opcode0xD2,
+							/* GRP2 Ew CL */                Opcode0xD3,
+			/* 0xD4 */      /* AAM */                       Opcode0xD4,
+							/* AAD */                       Opcode0xD5,
+							/* (undocumented XLAT) */       (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), (ushort)(cpu.bx.Word + cpu.ax.Low)); return 4; },
+							/* XLAT */                      (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), (ushort)(cpu.bx.Word + cpu.ax.Low)); return 4; },
+			/* 0xD8 */      /* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+			/* 0xDC */      /* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+
+			/* 0xE0 */      /* LOOPNZ Jb */                 (cpu) => { return cpu.LoopWhile(!cpu.IsFlagSet(Flags.Zero)); },
+							/* LOOPZ Jb */                  (cpu) => { return cpu.LoopWhile(cpu.IsFlagSet(Flags.Zero)); },
+							/* LOOP Jb */                   (cpu) => { return cpu.Loop(); },
+							/* JCXZ */                      (cpu) => { return cpu.JumpConditional(cpu.cx.Word == 0); },
+			/* 0xE4 */      /* IN Ib AL */                  (cpu) => { cpu.ax.Low = cpu.machine.ReadPort(cpu.ReadOpcodeIb()); return 6; },
+							/* IN Ib AX */                  (cpu) => { cpu.ax.Word = cpu.ReadPort16(cpu.ReadOpcodeIb()); return 6; },
+							/* OUT Ib AL */                 (cpu) => { cpu.machine.WritePort(cpu.ReadOpcodeIb(), cpu.ax.Low); return 6; },
+							/* OUT Ib AX */                 (cpu) => { cpu.WritePort16(cpu.ReadOpcodeIb(), cpu.ax.Word); return 6; },
+			/* 0xE8 */      /* CALL Jv */                   (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.Push(cpu.ip); cpu.ip += offset; return 4; },
+							/* JMP Jv */                    (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip += offset; return 3; },
+							/* JMP Ap */                    (cpu) => { var newIp = cpu.ReadOpcodeIw(); var newCs = cpu.ReadOpcodeIw(); cpu.ip = newIp; cpu.cs = newCs; return 5; },
+							/* JMP Jb */                    (cpu) => { cpu.ip = cpu.ReadOpcodeJb(); return 3; },
+			/* 0xEC */      /* IN AL DX */                  (cpu) => { cpu.ax.Low = cpu.machine.ReadPort(cpu.dx.Word); return 4; },
+							/* IN AX DX */                  (cpu) => { cpu.ax.Word = cpu.ReadPort16(cpu.dx.Word); return 4; },
+							/* OUT DX AL */                 (cpu) => { cpu.machine.WritePort(cpu.dx.Word, cpu.ax.Low); return 4; },
+							/* OUT DX AX */                 (cpu) => { cpu.WritePort16(cpu.dx.Word, cpu.ax.Word); return 4; },
+
+			/* 0xF0 */      /* (Prefix LOCK) */             (cpu) => 0,
+							/* (Invalid; NOP?) */			(cpu) => 3,
+							/* (Prefix REPNZ) */            (cpu) => 0,
+							/* (Prefix REPZ) */             (cpu) => 0,
+			/* 0xF4 */      /* HLT */                       (cpu) => { cpu.halted = true; return 8; },
+							/* CMC */                       (cpu) => { cpu.SetClearFlagConditional(Flags.Carry, !cpu.IsFlagSet(Flags.Carry)); return 4; },
+							/* GRP3 Eb */                   Opcode0xF6,
+							/* GRP3 Ew */                   Opcode0xF7,
+			/* 0xF8 */      /* CLC */                       (cpu) => { cpu.ClearFlags(Flags.Carry); return 4; },
+							/* STC */                       (cpu) => { cpu.SetFlags(Flags.Carry); return 4; },
+							/* CLI */                       (cpu) => { cpu.ClearFlags(Flags.InterruptEnable); return 4; },
+							/* STI */                       (cpu) => { cpu.SetFlags(Flags.InterruptEnable); return 4; },
+			/* 0xFC */      /* CLD */                       (cpu) => { cpu.ClearFlags(Flags.Direction); return 4; },
+							/* STD */                       (cpu) => { cpu.SetFlags(Flags.Direction); return 4; },
+							/* GRP4 Eb */                   Opcode0xFE,
+							/* GRP4 Ew */                   Opcode0xFF
+		};
+
+		private static int Opcode0x60(V30MZ cpu)
+		{
+			/* PUSHA */
+			var oldSp = cpu.sp;
+			cpu.Push(cpu.ax.Word);
+			cpu.Push(cpu.cx.Word);
+			cpu.Push(cpu.dx.Word);
+			cpu.Push(cpu.bx.Word);
+			cpu.Push(oldSp);
+			cpu.Push(cpu.bp);
+			cpu.Push(cpu.si);
+			cpu.Push(cpu.di);
+			return 8;
+		}
+
+		private static int Opcode0x61(V30MZ cpu)
+		{
+			/* POPA */
+			cpu.di = cpu.Pop();
+			cpu.si = cpu.Pop();
+			cpu.bp = cpu.Pop();
+			cpu.Pop(); /* don't restore SP */
+			cpu.bx.Word = cpu.Pop();
+			cpu.dx.Word = cpu.Pop();
+			cpu.cx.Word = cpu.Pop();
+			cpu.ax.Word = cpu.Pop();
+			return 8;
+		}
+
+		private static int Opcode0x62(V30MZ cpu)
+		{
+			/* BOUND Gw E */
+			cpu.ReadModRM();
+			var lo = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0));
+			var hi = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2));
+			var reg = cpu.GetRegister16((RegisterNumber16)cpu.modRm.Mem);
+			if (reg < lo || reg > hi) cpu.Interrupt(5);
+			return 12;
+		}
+
+		private static int Opcode0x6C(V30MZ cpu)
+		{
+			/* INSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.InString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.InString(false); cycles += 5; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x6D(V30MZ cpu)
+		{
+			/* INSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.InString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.InString(true); cycles += 5; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x6E(V30MZ cpu)
+		{
+			/* OUTSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.OutString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.OutString(false); cycles += 6; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x6F(V30MZ cpu)
+		{
+			/* OUTSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.OutString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.OutString(true); cycles += 6; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x80(V30MZ cpu)
+		{
+			/* GRP1 Eb Ib */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ADD */ cpu.WriteOpcodeEb(cpu.Add8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x1: /* OR  */ cpu.WriteOpcodeEb(cpu.Or8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x2: /* ADC */ cpu.WriteOpcodeEb(cpu.Add8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x3: /* SBB */ cpu.WriteOpcodeEb(cpu.Sub8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x4: /* AND */ cpu.WriteOpcodeEb(cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x5: /* SUB */ cpu.WriteOpcodeEb(cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x6: /* XOR */ cpu.WriteOpcodeEb(cpu.Xor8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x7: /* CMP */ cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb()); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x81(V30MZ cpu)
+		{
+			/* GRP1 Ew Iw */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ADD */ cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x1: /* OR  */ cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x2: /* ADC */ cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x3: /* SBB */ cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x4: /* AND */ cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x5: /* SUB */ cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x6: /* XOR */ cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break;
+				case 0x7: /* CMP */ cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw()); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x83(V30MZ cpu)
+		{
+			/* GRP1 Ew Ib */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ADD */ cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x1: /* OR  */ cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x2: /* ADC */ cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x3: /* SBB */ cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x4: /* AND */ cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x5: /* SUB */ cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x6: /* XOR */ cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break;
+				case 0x7: /* CMP */ cpu.Sub16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb()); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0x8D(V30MZ cpu)
+		{
+			/* LEA Gw M */
+			cpu.ReadModRM();
+			if (cpu.modRm.Mod != ModRM.Modes.Register)
+			{
+				cpu.WriteOpcodeGw(cpu.modRm.Offset);
+			}
+			return 8;
+		}
+
+		private static int Opcode0x9A(V30MZ cpu)
+		{
+			/* CALL Ap */
+			var newIp = cpu.ReadOpcodeIw();
+			var newCs = cpu.ReadOpcodeIw();
+
+			cpu.Push(cpu.cs);
+			cpu.Push(cpu.ip);
+
+			cpu.ip = newIp;
+			cpu.cs = newCs;
+
+			return 9;
+		}
+
+		private static int Opcode0x9E(V30MZ cpu)
+		{
+			/* SAHF */
+			cpu.SetClearFlagConditional(Flags.Sign, ((Flags)cpu.ax.High & Flags.Sign) == Flags.Sign);
+			cpu.SetClearFlagConditional(Flags.Zero, ((Flags)cpu.ax.High & Flags.Zero) == Flags.Zero);
+			cpu.SetClearFlagConditional(Flags.Auxiliary, ((Flags)cpu.ax.High & Flags.Auxiliary) == Flags.Auxiliary);
+			cpu.SetClearFlagConditional(Flags.Parity, ((Flags)cpu.ax.High & Flags.Parity) == Flags.Parity);
+			cpu.SetClearFlagConditional(Flags.Carry, ((Flags)cpu.ax.High & Flags.Carry) == Flags.Carry);
+			return 4;
+		}
+
+		private static int Opcode0xA4(V30MZ cpu)
+		{
+			/* MOVSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.MoveString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.MoveString(false); cycles += 5; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xA5(V30MZ cpu)
+		{
+			/* MOVSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.MoveString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.MoveString(true); cycles += 5; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xA6(V30MZ cpu)
+		{
+			/* CMPSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.CompareString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.CompareString(false); cycles += 4; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero)));
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xA7(V30MZ cpu)
+		{
+			/* CMPSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.CompareString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.CompareString(true); cycles += 4; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero)));
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAA(V30MZ cpu)
+		{
+			/* STOSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.StoreString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.StoreString(false); cycles += 2; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAB(V30MZ cpu)
+		{
+			/* STOSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.StoreString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.StoreString(true); cycles += 2; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAC(V30MZ cpu)
+		{
+			/* LODSB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.LoadString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.LoadString(false); cycles += 2; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAD(V30MZ cpu)
+		{
+			/* LODSW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.LoadString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.LoadString(true); cycles += 2; } while (--cpu.cx.Word != 0);
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAE(V30MZ cpu)
+		{
+			/* SCASB */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.ScanString(false);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.ScanString(false); cycles += 3; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero)));
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xAF(V30MZ cpu)
+		{
+			/* SCASW */
+			var cycles = 5;
+			if (!cpu.prefixHasRepeat)
+				cpu.ScanString(true);
+			else if (cpu.cx.Word != 0)
+			{
+				do { cpu.ScanString(true); cycles += 3; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero)));
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xC0(V30MZ cpu)
+		{
+			/* GRP2 Eb Ib */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xC1(V30MZ cpu)
+		{
+			/* GRP2 Ew Ib */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xC4(V30MZ cpu)
+		{
+			/* LES Gw Mp */
+			cpu.ReadModRM();
+			if (cpu.modRm.Mod != ModRM.Modes.Register)
+			{
+				cpu.WriteOpcodeGw(cpu.ReadOpcodeEw());
+				cpu.es = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2));
+			}
+			return 8;
+		}
+
+		private static int Opcode0xC5(V30MZ cpu)
+		{
+			/* LDS Gw Mp */
+			cpu.ReadModRM();
+			if (cpu.modRm.Mod != ModRM.Modes.Register)
+			{
+				cpu.WriteOpcodeGw(cpu.ReadOpcodeEw());
+				cpu.ds = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2));
+			}
+			return 8;
+		}
+
+		private static int Opcode0xC8(V30MZ cpu)
+		{
+			/* ENTER */
+			var offset = cpu.ReadOpcodeIw();
+			var length = (byte)(cpu.ReadOpcodeIb() & 0x1F);
+
+			cpu.Push(cpu.bp);
+			cpu.bp = cpu.sp;
+			cpu.sp -= offset;
+
+			if (length != 0)
+			{
+				for (var i = 1; i < length; i++)
+					cpu.Push(cpu.ReadMemory16(cpu.ss, (ushort)(cpu.bp - i * 2)));
+				cpu.Push(cpu.bp);
+			}
+			return 7;
+		}
+
+		private static int Opcode0xD0(V30MZ cpu)
+		{
+			/* GRP2 Eb 1 */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xD1(V30MZ cpu)
+		{
+			/* GRP2 Ew 1 */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xD2(V30MZ cpu)
+		{
+			/* GRP2 Eb CL */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xD3(V30MZ cpu)
+		{
+			/* GRP2 Ew CL */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				case 0x6: /* --- */ cycles = 3; break;
+				case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		/* NOTE: AAM/AAD: While NEC V20/V30 do ignore immediate & always use base 10 (1), V30MZ does *not* ignore the immediate (2)
+		 * (1): https://www.vcfed.org/forum/forum/technical-support/vintage-computer-programming/36551/
+		 * (2): https://github.com/xdanieldzd/StoicGoose/issues/9
+		 */
+
+		private static int Opcode0xD4(V30MZ cpu)
+		{
+			/* AAM */
+			var value = cpu.ReadOpcodeIb();
+			if (value == 0)
+			{
+				/* Division-by-zero exception */
+				cpu.Interrupt(0);
+			}
+			else
+			{
+				cpu.ax.High = (byte)(cpu.ax.Low / value);
+				cpu.ax.Low = (byte)(cpu.ax.Low % value);
+				cpu.SetClearFlagConditional(Flags.Parity, CalculateParity(cpu.ax.Low));
+				cpu.SetClearFlagConditional(Flags.Zero, (cpu.ax.Word & 0xFFFF) == 0);
+				cpu.SetClearFlagConditional(Flags.Sign, (cpu.ax.Word & 0x8000) != 0);
+			}
+			return 16;
+		}
+
+		private static int Opcode0xD5(V30MZ cpu)
+		{
+			/* AAD */
+			var value = cpu.ReadOpcodeIb();
+			cpu.ax.Low = (byte)(cpu.ax.High * value + cpu.ax.Low);
+			cpu.ax.High = 0;
+			cpu.SetClearFlagConditional(Flags.Parity, CalculateParity(cpu.ax.Low));
+			cpu.SetClearFlagConditional(Flags.Zero, (cpu.ax.Word & 0xFFFF) == 0);
+			cpu.SetClearFlagConditional(Flags.Sign, (cpu.ax.Word & 0x8000) != 0);
+			return 6;
+		}
+
+		private static int Opcode0xF6(V30MZ cpu)
+		{
+			/* GRP3 Eb */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* TEST */ cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb()); cycles = 1; break;
+				case 0x1: /* --- */ cycles = 3; break;
+				case 0x2: /* NOT */ cpu.WriteOpcodeEb((byte)~cpu.ReadOpcodeEb()); cycles = 1; break;
+				case 0x3: /* NEG */ cpu.WriteOpcodeEb(cpu.Neg8(cpu.ReadOpcodeEb())); cycles = 1; break;
+				case 0x4: /* MUL */ cpu.ax.Word = cpu.Mul8(false, cpu.ax.Low, cpu.ReadOpcodeEb()); cycles = 3; break;
+				case 0x5: /* IMUL */ cpu.ax.Word = cpu.Mul8(true, cpu.ax.Low, cpu.ReadOpcodeEb()); cycles = 3; break;
+				case 0x6: /* DIV */ cpu.ax.Word = cpu.Div8(false, cpu.ax.Word, cpu.ReadOpcodeEb()); cycles = 15; break;
+				case 0x7: /* IDIV */ cpu.ax.Word = cpu.Div8(true, cpu.ax.Word, cpu.ReadOpcodeEb()); cycles = 17; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xF7(V30MZ cpu)
+		{
+			/* GRP3 Ew */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* TEST */ cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw()); cycles = 1; break;
+				case 0x1: /* --- */ cycles = 3; break;
+				case 0x2: /* NOT */ cpu.WriteOpcodeEw((ushort)~cpu.ReadOpcodeEw()); cycles = 1; break;
+				case 0x3: /* NEG */ cpu.WriteOpcodeEw(cpu.Neg16(cpu.ReadOpcodeEw())); cycles = 1; break;
+				case 0x4: /* MUL */ { var result = cpu.Mul16(false, cpu.ax.Word, cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 3; } break;
+				case 0x5: /* IMUL */ { var result = cpu.Mul16(true, cpu.ax.Word, cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 3; } break;
+				case 0x6: /* DIV */ { var result = cpu.Div16(false, (uint)(cpu.dx.Word << 16 | cpu.ax.Word), cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 23; } break;
+				case 0x7: /* IDIV */ { var result = cpu.Div16(true, (uint)(cpu.dx.Word << 16 | cpu.ax.Word), cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 24; } break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xFE(V30MZ cpu)
+		{
+			/* GRP4 Eb */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* INC */ cpu.WriteOpcodeEb(cpu.Inc8(cpu.ReadOpcodeEb())); cycles = 1; break;
+				case 0x1: /* DEC */ cpu.WriteOpcodeEb(cpu.Dec8(cpu.ReadOpcodeEb())); cycles = 1; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+
+		private static int Opcode0xFF(V30MZ cpu)
+		{
+			/* GRP4 Ew */
+			int cycles;
+			cpu.ReadModRM();
+			switch (cpu.modRm.Reg)
+			{
+				case 0x0: /* INC */ cpu.WriteOpcodeEw(cpu.Inc16(cpu.ReadOpcodeEw())); cycles = 1; break;
+				case 0x1: /* DEC */ cpu.WriteOpcodeEw(cpu.Dec16(cpu.ReadOpcodeEw())); cycles = 1; break;
+				case 0x2: /* CALL */
+					{
+						var offset = cpu.ReadOpcodeEw();
+						cpu.Push(cpu.ip);
+						cpu.ip = offset;
+						cycles = 5;
+					}
+					break;
+				case 0x3: /* CALL Mp */
+					{
+						if (cpu.modRm.Mod != ModRM.Modes.Register)
+						{
+							var offset = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0));
+							var segment = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2));
+							cpu.Push(cpu.cs);
+							cpu.Push(cpu.ip);
+							cpu.cs = segment;
+							cpu.ip = offset;
+						}
+						cycles = 11;
+					}
+					break;
+				case 0x4: /* JMP */ cpu.ip = cpu.ReadOpcodeEw(); cycles = 4; break;
+				case 0x5: /* JMP Mp */
+					{
+						if (cpu.modRm.Mod != ModRM.Modes.Register)
+						{
+							cpu.ip = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0));
+							cpu.cs = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2));
+						}
+						cycles = 9;
+					}
+					break;
+				case 0x6: /* PUSH */ cpu.Push(cpu.ReadOpcodeEw()); cycles = 3; break;
+				case 0x7: /* --- */ cycles = 3; break;
+				default: throw new Exception("Invalid opcode");
+			}
+			return cycles;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta
new file mode 100644
index 00000000..038ed7ce
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 7f721c42886f2904c9a7eda1c94b6d14
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs
new file mode 100644
index 00000000..053e42cf
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs
@@ -0,0 +1,71 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		SegmentNumber prefixSegOverride;
+		bool prefixHasRepeat;
+		bool prefixRepeatOnNotEqual;
+
+		private void ResetPrefixes()
+		{
+			prefixSegOverride = SegmentNumber.Unset;
+			prefixHasRepeat = false;
+			prefixRepeatOnNotEqual = false;
+		}
+
+		private bool HandlePrefixes(byte op)
+		{
+			var isOpcode = true;
+
+			switch (op)
+			{
+				/* Prefixes */
+				case 0x26:
+					/* :ES */
+					prefixSegOverride = SegmentNumber.ES;
+					isOpcode = false;
+					break;
+
+				case 0x2E:
+					/* :CS */
+					prefixSegOverride = SegmentNumber.CS;
+					isOpcode = false;
+					break;
+
+				case 0x36:
+					/* :SS */
+					prefixSegOverride = SegmentNumber.SS;
+					isOpcode = false;
+					break;
+
+				case 0x3E:
+					/* :DS */
+					prefixSegOverride = SegmentNumber.DS;
+					isOpcode = false;
+					break;
+
+				case 0xF0:
+					/* LOCK */
+					//TODO: implement??
+					isOpcode = false;
+					break;
+
+				case 0xF2:
+					/* REPNE */
+					prefixHasRepeat = true;
+					prefixRepeatOnNotEqual = true;
+					isOpcode = false;
+					break;
+
+				case 0xF3:
+					/* REP/REPE */
+					prefixHasRepeat = true;
+					prefixRepeatOnNotEqual = false;
+					isOpcode = false;
+					break;
+			}
+
+			return isOpcode;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta
new file mode 100644
index 00000000..fa2df8ff
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: dff52160b1aa55c48a07722be9d654ff
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs
new file mode 100644
index 00000000..64de5811
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		enum RegisterNumber8 : byte
+		{
+			AL = 0b000,
+			CL = 0b001,
+			DL = 0b010,
+			BL = 0b011,
+			AH = 0b100,
+			CH = 0b101,
+			DH = 0b110,
+			BH = 0b111
+		}
+
+		enum RegisterNumber16 : byte
+		{
+			AX = 0b000,
+			CX = 0b001,
+			DX = 0b010,
+			BX = 0b011,
+			SP = 0b100,
+			BP = 0b101,
+			SI = 0b110,
+			DI = 0b111
+		}
+
+		private byte GetRegister8(RegisterNumber8 reg)
+		{
+			return reg switch
+			{
+				RegisterNumber8.AL => ax.Low,
+				RegisterNumber8.CL => cx.Low,
+				RegisterNumber8.DL => dx.Low,
+				RegisterNumber8.BL => bx.Low,
+				RegisterNumber8.AH => ax.High,
+				RegisterNumber8.CH => cx.High,
+				RegisterNumber8.DH => dx.High,
+				RegisterNumber8.BH => bx.High,
+				_ => throw new ArgumentException("Invalid register", nameof(reg)),
+			};
+		}
+
+		private ushort GetRegister16(RegisterNumber16 reg)
+		{
+			return reg switch
+			{
+				RegisterNumber16.AX => ax.Word,
+				RegisterNumber16.CX => cx.Word,
+				RegisterNumber16.DX => dx.Word,
+				RegisterNumber16.BX => bx.Word,
+				RegisterNumber16.SP => sp,
+				RegisterNumber16.BP => bp,
+				RegisterNumber16.SI => si,
+				RegisterNumber16.DI => di,
+				_ => throw new ArgumentException("Invalid register", nameof(reg)),
+			};
+		}
+
+		private void SetRegister8(RegisterNumber8 reg, byte value)
+		{
+			switch (reg)
+			{
+				case RegisterNumber8.AL: ax.Low = value; break;
+				case RegisterNumber8.CL: cx.Low = value; break;
+				case RegisterNumber8.DL: dx.Low = value; break;
+				case RegisterNumber8.BL: bx.Low = value; break;
+				case RegisterNumber8.AH: ax.High = value; break;
+				case RegisterNumber8.CH: cx.High = value; break;
+				case RegisterNumber8.DH: dx.High = value; break;
+				case RegisterNumber8.BH: bx.High = value; break;
+				default: throw new ArgumentException("Invalid register", nameof(reg));
+			}
+		}
+
+		private void SetRegister16(RegisterNumber16 reg, ushort value)
+		{
+			switch (reg)
+			{
+				case RegisterNumber16.AX: ax.Word = value; break;
+				case RegisterNumber16.CX: cx.Word = value; break;
+				case RegisterNumber16.DX: dx.Word = value; break;
+				case RegisterNumber16.BX: bx.Word = value; break;
+				case RegisterNumber16.SP: sp = value; break;
+				case RegisterNumber16.BP: bp = value; break;
+				case RegisterNumber16.SI: si = value; break;
+				case RegisterNumber16.DI: di = value; break;
+				default: throw new ArgumentException("Invalid register", nameof(reg));
+			}
+		}
+
+		[StructLayout(LayoutKind.Explicit)]
+		public struct Register16
+		{
+			[FieldOffset(0)]
+			public byte Low;
+			[FieldOffset(1)]
+			public byte High;
+
+			[FieldOffset(0)]
+			public ushort Word;
+
+			public static implicit operator Register16(ushort value) => new() { Word = value };
+
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta
new file mode 100644
index 00000000..95761e1d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a4d62a2a12b27744ea0c51ed3e7a2500
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs
new file mode 100644
index 00000000..d16710a4
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		enum SegmentNumber : byte
+		{
+			ES = 0b00,
+			CS = 0b01,
+			SS = 0b10,
+			DS = 0b11,
+			Unset = 0xFF
+		}
+
+		private ushort GetSegment(SegmentNumber seg)
+		{
+			return seg switch
+			{
+				SegmentNumber.ES => es,
+				SegmentNumber.CS => cs,
+				SegmentNumber.SS => ss,
+				SegmentNumber.DS => ds,
+				_ => throw new ArgumentException("Invalid segment", nameof(seg)),
+			};
+		}
+
+		private void SetSegment(SegmentNumber seg, ushort value)
+		{
+			switch (seg)
+			{
+				case SegmentNumber.ES: es = value; break;
+				case SegmentNumber.CS: cs = value; break;
+				case SegmentNumber.SS: ss = value; break;
+				case SegmentNumber.DS: ds = value; break;
+				default: throw new ArgumentException("Invalid segment", nameof(seg));
+			}
+		}
+
+		private ushort GetSegmentViaOverride(SegmentNumber seg)
+		{
+			return GetSegment(prefixSegOverride != SegmentNumber.Unset ? prefixSegOverride : seg);
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta
new file mode 100644
index 00000000..153ca8bc
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f05e782fc3972e146a5970e63968477a
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs
new file mode 100644
index 00000000..d6d6d6d9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs
@@ -0,0 +1,104 @@
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ
+	{
+		private static int GetIncrement(bool is16Bit, bool isDirectionFlagSet)
+		{
+			return isDirectionFlagSet ? (is16Bit ? -2 : -1) : (is16Bit ? 2 : 1);
+		}
+
+		private void InString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			if (!is16Bit)
+				WriteMemory8(es, di, machine.ReadPort(dx.Word));
+			else
+				WriteMemory16(es, di, ReadPort16(dx.Word));
+
+			di = (ushort)(di + increment);
+		}
+
+		private void OutString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			var temp = GetSegmentViaOverride(SegmentNumber.DS);
+
+			if (!is16Bit)
+				machine.WritePort(dx.Word, ReadMemory8(temp, si));
+			else
+				WritePort16(dx.Word, ReadMemory16(temp, si));
+
+			si = (ushort)(si + increment);
+		}
+
+		private void MoveString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			var temp = GetSegmentViaOverride(SegmentNumber.DS);
+
+			if (!is16Bit)
+				WriteMemory8(es, di, ReadMemory8(temp, si));
+			else
+				WriteMemory16(es, di, ReadMemory16(temp, si));
+
+			di = (ushort)(di + increment);
+			si = (ushort)(si + increment);
+		}
+
+		private void CompareString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			var temp = GetSegmentViaOverride(SegmentNumber.DS);
+
+			if (!is16Bit)
+				Sub8(false, ReadMemory8(temp, si), ReadMemory8(es, di));
+			else
+				Sub16(false, ReadMemory16(temp, si), ReadMemory16(es, di));
+
+			di = (ushort)(di + increment);
+			si = (ushort)(si + increment);
+		}
+
+		private void StoreString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			if (!is16Bit)
+				WriteMemory8(es, di, ax.Low);
+			else
+				WriteMemory16(es, di, ax.Word);
+
+			di = (ushort)(di + increment);
+		}
+
+		private void LoadString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			var temp = GetSegmentViaOverride(SegmentNumber.DS);
+
+			if (!is16Bit)
+				ax.Low = ReadMemory8(temp, si);
+			else
+				ax.Word = ReadMemory16(temp, si);
+
+			si = (ushort)(si + increment);
+		}
+
+		private void ScanString(bool is16Bit)
+		{
+			var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction));
+
+			if (!is16Bit)
+				Sub8(false, ax.Low, ReadMemory8(es, di));
+			else
+				Sub16(false, ax.Word, ReadMemory16(es, di));
+
+			di = (ushort)(di + increment);
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta
new file mode 100644
index 00000000..059b3c67
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 43c1a3a659adfb244be70cdc0ded4be7
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs
new file mode 100644
index 00000000..4a80ff25
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs
@@ -0,0 +1,139 @@
+using StoicGoose.Core.Interfaces;
+
+namespace StoicGoose.Core.CPU
+{
+	public sealed partial class V30MZ : IComponent
+	{
+		// TODO: attempt prefetch emulation (Meitantei Conan - Nishi no Meitantei Saidai no Kiki; cart changes banks on startup, can no longer execute jump, execs garbage)
+
+		/* Parent machine instance */
+		readonly IMachine machine = default;
+
+		/* General registers */
+		Register16 ax, bx, cx, dx;
+		ushort sp, bp, si, di;
+		/* Segment registers */
+		ushort cs, ds, ss, es;
+		/* Status and instruction registers */
+		ushort ip;
+		Flags flags;
+
+		bool halted;
+		int opCycles, intCycles;
+
+		/* Public properties for registers */
+		public Register16 AX { get => ax; set => ax = value; }
+		public Register16 BX { get => bx; set => bx = value; }
+		public Register16 CX { get => cx; set => cx = value; }
+		public Register16 DX { get => dx; set => dx = value; }
+		public ushort SP { get => sp; set => sp = value; }
+		public ushort BP { get => bp; set => bp = value; }
+		public ushort SI { get => si; set => si = value; }
+		public ushort DI { get => di; set => di = value; }
+		public ushort CS { get => cs; set => cs = value; }
+		public ushort DS { get => ds; set => ds = value; }
+		public ushort SS { get => ss; set => ss = value; }
+		public ushort ES { get => es; set => es = value; }
+		public ushort IP { get => ip; set => ip = value; }
+
+		public bool IsHalted { get => halted; set => halted = value; }
+
+		public V30MZ(IMachine machine)
+		{
+			this.machine = machine;
+
+			Reset();
+		}
+
+		public void Reset()
+		{
+			/* CPU reset */
+			flags = Flags.ReservedB1 | Flags.ReservedB12 | Flags.ReservedB13 | Flags.ReservedB14 | Flags.ReservedB15;
+			ip = 0x0000;
+			cs = 0xFFFF;
+			ds = 0x0000;
+			ss = 0x0000;
+			es = 0x0000;
+
+			/* Initialized by WS bootstrap */
+			ax.Word = 0x0000;
+			dx.Word = 0x0000;
+			bp = 0x0000;
+			ss = 0x0000;
+			sp = 0x2000;
+			ds = 0x0000;
+			es = 0x0000;
+
+			/* Misc variables */
+			halted = false;
+			opCycles = intCycles = 0;
+
+			ResetPrefixes();
+			modRm.Reset();
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public void Interrupt(int vector)
+		{
+			/* Resume execution */
+			halted = false;
+
+			/* Read interrupt handler's segment & offset */
+			var offset = ReadMemory16(0, (ushort)((vector * 4) + 0));
+			var segment = ReadMemory16(0, (ushort)((vector * 4) + 2));
+
+			/* Push state, clear flags, etc. */
+			Push((ushort)flags);
+			Push(cs);
+			Push(ip);
+
+			ClearFlags(Flags.InterruptEnable);
+			ClearFlags(Flags.Trap);
+
+			ResetPrefixes();
+			modRm.Reset();
+
+			intCycles = 32;
+
+			/* Continue with interrupt handler */
+			cs = segment;
+			ip = offset;
+		}
+
+		public int Step()
+		{
+			var cycles = 0;
+
+			if (halted)
+			{
+				/* CPU is halted */
+				cycles++;
+			}
+			else
+			{
+				/* Read any prefixes & opcode */
+				byte opcode;
+				while (!HandlePrefixes(opcode = ReadMemory8(cs, ip++))) { }
+
+				/* Execute instruction */
+				opCycles = instructions[opcode](this);
+
+				cycles += opCycles;
+				opCycles = 0;
+			}
+
+			cycles += intCycles;
+			intCycles = 0;
+
+			/* Reset state for next instruction */
+			ResetPrefixes();
+			modRm.Reset();
+
+			return cycles;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta
new file mode 100644
index 00000000..814b3b47
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 946e7f92ed1c35e45bd71bbcd108695c
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta
new file mode 100644
index 00000000..9d450740
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4878ed813b76a834abf448a6d1c96295
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs
new file mode 100644
index 00000000..4ab958fb
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs
@@ -0,0 +1,248 @@
+using System;
+
+using StoicGoose.Common.Utilities;
+using StoicGoose.Core.EEPROMs;
+using StoicGoose.Core.Interfaces;
+
+namespace StoicGoose.Core.Cartridges
+{
+	public class Cartridge : IComponent
+	{
+		byte[] rom, sram;
+		uint romMask, sramMask;
+
+		Metadata metadata;
+
+		/* REG_BANK_xxx */
+		byte romBank2, sramBank, romBank0, romBank1;
+
+		/* REG_EEP_xxx -> EEPROM class */
+		EEPROM eeprom = default;
+
+		/* REG_RTC_xxx -> RTC class */
+		RTC rtc = default;
+
+		public bool IsLoaded => rom?.Length > 0;
+		public int SizeInBytes => rom?.Length ?? 0;
+		public uint Crc32 { get; private set; } = default;
+
+		public Metadata Metadata => metadata;
+
+		public Cartridge()
+		{
+			rom = Array.Empty<byte>();
+			sram = Array.Empty<byte>();
+		}
+
+		public void Reset()
+		{
+			romBank2 = 0xFF;
+			sramBank = 0xFF;
+			romBank0 = 0xFF;
+			romBank1 = 0xFF;
+
+			eeprom?.Reset();
+			rtc?.Reset();
+
+			// HACK: set RTC to current date/time on boot for testing
+			rtc?.Program(DateTime.Now);
+		}
+
+		public void Shutdown()
+		{
+			eeprom?.Shutdown();
+			rtc?.Shutdown();
+		}
+
+		public void LoadRom(byte[] data)
+		{
+			rom = data;
+			romMask = (uint)(rom.Length - 1);
+
+			metadata = new Metadata(rom);
+
+			if (metadata.SaveSize != 0)
+			{
+				if (metadata.IsSramSave)
+				{
+					sram = new byte[metadata.SaveSize];
+					sramMask = (uint)(sram.Length - 1);
+				}
+				else if (metadata.IsEepromSave)
+				{
+					switch (metadata.SaveType)
+					{
+						// TODO: verify size/address bits
+						case Metadata.SaveTypes.Eeprom1Kbit: eeprom = new EEPROM(metadata.SaveSize, 6); break;
+						case Metadata.SaveTypes.Eeprom16Kbit: eeprom = new EEPROM(metadata.SaveSize, 10); break;
+						case Metadata.SaveTypes.Eeprom8Kbit: eeprom = new EEPROM(metadata.SaveSize, 9); break;
+					}
+				}
+			}
+
+			if (metadata.IsRtcPresent)
+			{
+				// NOTE: "RTC present" flag is not entirely consistent; ex. Digimon Tamers Battle Spirit has the flag, but does not have an RTC
+				rtc = new RTC();
+			}
+
+			Crc32 = Common.Utilities.Crc32.Calculate(rom);
+
+			Log.WriteEvent(LogSeverity.Information, this, "ROM loaded.");
+			Log.WriteLine($"~ {Ansi.Cyan}Cartridge metadata{Ansi.Reset} ~");
+			Log.WriteLine($" Publisher ID: {Metadata.PublisherCode}, {Metadata.PublisherName} [0x{Metadata.PublisherId:X2}]");
+			Log.WriteLine($" System type: {Metadata.SystemType}");
+			Log.WriteLine($" Game ID: 0x{Metadata.GameId:X2}");
+			Log.WriteLine($"  Calculated ID string: {Metadata.GameIdString}");
+			Log.WriteLine($" Game revision: 0x{Metadata.GameRevision:X2}");
+			Log.WriteLine($" ROM size: {Metadata.RomSize} [0x{(byte)Metadata.RomSize:X2}]");
+			Log.WriteLine($" Save type/size: {Metadata.SaveType}/{Metadata.SaveSize} [0x{(byte)Metadata.SaveType:X2}]");
+			Log.WriteLine($" Misc flags: 0x{Metadata.MiscFlags:X2}");
+			Log.WriteLine($"  Orientation: {Metadata.Orientation}");
+			Log.WriteLine($"  ROM bus width: {Metadata.RomBusWidth}");
+			Log.WriteLine($"  ROM access speed: {Metadata.RomAccessSpeed}");
+			Log.WriteLine($" RTC present: {Metadata.IsRtcPresent} [0x{Metadata.RtcPresentFlag:X2}]");
+			Log.WriteLine($" Checksum (from metadata): 0x{Metadata.Checksum:X4}");
+			Log.WriteLine($"  Checksum (calculated): 0x{Metadata.CalculatedChecksum:X4}");
+			Log.WriteLine($"  Checksum is {(metadata.IsChecksumValid ? $"{Ansi.Green}valid" : $"{Ansi.Red}invalid")}{Ansi.Reset}!");
+
+			if (metadata.PublisherId == 0x01 && metadata.GameId == 0x27)
+			{
+				// HACK: Meitantei Conan - Nishi no Meitantei Saidai no Kiki, prevent crash on startup (see TODO in V30MZ, prefetching)
+				rom[0xFFFE8] = 0xEA;
+				rom[0xFFFE9] = 0x00;
+				rom[0xFFFEA] = 0x00;
+				rom[0xFFFEB] = 0x00;
+				rom[0xFFFEC] = 0x20;
+				Log.WriteLine($"~ {Ansi.Red}Conan prefetch hack enabled{Ansi.Reset} ~");
+			}
+		}
+
+		public void LoadSram(byte[] data)
+		{
+			if (data.Length != sram.Length) throw new Exception("Sram size mismatch");
+			Buffer.BlockCopy(data, 0, sram, 0, data.Length);
+		}
+
+		public void LoadEeprom(byte[] data)
+		{
+			eeprom?.LoadContents(data);
+		}
+
+		public byte[] GetSram()
+		{
+			return sram.Clone() as byte[];
+		}
+
+		public byte[] GetEeprom()
+		{
+			return eeprom?.GetContents().Clone() as byte[];
+		}
+
+		public bool Step(int clockCyclesInStep)
+		{
+			return rtc != null && rtc.Step(clockCyclesInStep);
+		}
+
+		public byte ReadMemory(uint address)
+		{
+			return address switch
+			{
+				/* SRAM */
+				var n when n >= 0x010000 && n < 0x020000 && sram.Length != 0 => sram[((uint)(sramBank << 16) | (address & 0x0FFFF)) & sramMask],
+				/* ROM bank 0 */
+				var n when n >= 0x020000 && n < 0x030000 && rom.Length != 0 => rom[((uint)(romBank0 << 16) | (address & 0x0FFFF)) & romMask],
+				/* ROM bank 1 */
+				var n when n >= 0x030000 && n < 0x040000 && rom.Length != 0 => rom[((uint)(romBank1 << 16) | (address & 0x0FFFF)) & romMask],
+				/* ROM bank 2 */
+				var n when n >= 0x040000 && n < 0x100000 && rom.Length != 0 => rom[((uint)(romBank2 << 20) | (address & 0xFFFFF)) & romMask],
+				/* Unmapped */
+				_ => 0x90,
+			};
+		}
+
+		public void WriteMemory(uint address, byte value)
+		{
+			/* SRAM */
+			if (address >= 0x010000 && address < 0x020000 && sram.Length != 0)
+				sram[((uint)(sramBank << 16) | (address & 0x0FFFF)) & sramMask] = value;
+		}
+
+		public byte ReadPort(ushort port)
+		{
+			return port switch
+			{
+				/* REG_BANK_ROM2 */
+				0xC0 => romBank2,
+				/* REG_BANK_SRAM */
+				0xC1 => sramBank,
+				/* REG_BANK_ROM0 */
+				0xC2 => romBank0,
+				/* REG_BANK_ROM1 */
+				0xC3 => romBank1,
+				/* REG_EEP_DATA (low) */
+				0xC4 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90,
+				/* REG_EEP_DATA (high) */
+				0xC5 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90,
+				/* REG_EEP_ADDR (low) */
+				0xC6 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90,
+				/* REG_EEP_ADDR (high) */
+				0xC7 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90,
+				/* REG_EEP_STATUS (read) */
+				0xC8 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90,
+				/* REG_RTC_STATUS (read) */
+				0xCA => rtc != null ? rtc.ReadPort((byte)(port - 0xCA)) : (byte)0x90,
+				/* REG_RTC_DATA */
+				0xCB => rtc != null ? rtc.ReadPort((byte)(port - 0xCA)) : (byte)0x90,
+				/* Unmapped */
+				_ => 0x90,
+			};
+		}
+
+		public void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0xC0:
+					/* REG_BANK_ROM2 */
+					romBank2 = value;
+					break;
+
+				case 0xC1:
+					/* REG_BANK_SRAM */
+					sramBank = value;
+					break;
+
+				case 0xC2:
+					/* REG_BANK_ROM0 */
+					romBank0 = value;
+					break;
+
+				case 0xC3:
+					/* REG_BANK_ROM1 */
+					romBank1 = value;
+					break;
+
+				case 0xC4:
+				case 0xC5:
+				case 0xC6:
+				case 0xC7:
+				case 0xC8:
+					/* REG_EEP_DATA (low) */
+					/* REG_EEP_DATA (high) */
+					/* REG_EEP_ADDR (low) */
+					/* REG_EEP_ADDR (high) */
+					/* REG_EEP_CMD (write) */
+					eeprom?.WritePort((byte)(port - 0xC4), value);
+					break;
+
+				case 0xCA:
+				case 0xCB:
+					/* REG_RTC_CMD (write) */
+					/* REG_RTC_DATA */
+					rtc?.WritePort((byte)(port - 0xCA), value);
+					break;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta
new file mode 100644
index 00000000..fc5cb3d3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 4de2597a945e9a14082b644bcddf3e4e
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs
new file mode 100644
index 00000000..b373712c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs
@@ -0,0 +1,171 @@
+using System.Collections.Generic;
+
+namespace StoicGoose.Core.Cartridges
+{
+	public class Metadata
+	{
+		public enum SystemTypes : byte
+		{
+			WonderSwan = 0x00,
+			WonderSwanColor = 0x01
+		}
+
+		public enum RomSizes : byte
+		{
+			Rom1Mbit = 0x00,     // ???
+			Rom2Mbit = 0x01,     // ???
+			Rom4Mbit = 0x02,
+			Rom8Mbit = 0x03,
+			Rom16Mbit = 0x04,
+			Rom24Mbit = 0x05,
+			Rom32Mbit = 0x06,
+			Rom48Mbit = 0x07,
+			Rom64Mbit = 0x08,
+			Rom128Mbit = 0x09
+		}
+
+		public enum SaveTypes : byte
+		{
+			None = 0x00,
+			Sram64Kbit = 0x01,
+			Sram256Kbit = 0x02,
+			Sram1Mbit = 0x03,
+			Sram2Mbit = 0x04,
+			Sram4Mbit = 0x05,
+			Eeprom1Kbit = 0x10,
+			Eeprom16Kbit = 0x20,
+			Eeprom8Kbit = 0x50      //???
+		}
+
+		public enum Orientations : byte
+		{
+			Horizontal = 0 << 0,
+			Vertical = 1 << 0,
+		}
+
+		public enum RomBusWidths : byte
+		{
+			Width16Bit = 0 << 1,
+			Width8Bit = 1 << 1,
+		}
+
+		public enum RomAccessSpeeds : byte
+		{
+			Speed3Cycle = 0 << 2,
+			Speed1Cycle = 1 << 2
+		}
+
+		readonly Dictionary<byte, (string code, string name)> publishers = new()
+		{
+			{ 0x00, ("???", "Misc. (invalid)") },
+			{ 0x01, ("BAN", "Bandai") },
+			{ 0x02, ("TAT", "Taito") },
+			{ 0x03, ("TMY", "Tomy") },
+			{ 0x04, ("KEX", "Koei") },
+			{ 0x05, ("DTE", "Data East") },
+			{ 0x06, ("AAE", "Asmik Ace") },
+			{ 0x07, ("MDE", "Media Entertainment") },
+			{ 0x08, ("NHB", "Nichibutsu") },
+			{ 0x0A, ("CCJ", "Coconuts Japan") },
+			{ 0x0B, ("SUM", "Sammy") },
+			{ 0x0C, ("SUN", "Sunsoft") },
+			{ 0x0D, ("PAW", "Mebius (?)") },
+			{ 0x0E, ("BPR", "Banpresto") },
+			{ 0x10, ("JLC", "Jaleco") },
+			{ 0x11, ("MGA", "Imagineer") },
+			{ 0x12, ("KNM", "Konami") },
+			{ 0x16, ("KBS", "Kobunsha") },
+			{ 0x17, ("BTM", "Bottom Up") },
+			{ 0x18, ("KGT", "Kaga Tech") },
+			{ 0x19, ("SRV", "Sunrise") },
+			{ 0x1A, ("CFT", "Cyber Front") },
+			{ 0x1B, ("MGH", "Mega House") },
+			{ 0x1D, ("BEC", "Interbec") },
+			{ 0x1E, ("NAP", "Nihon Application") },
+			{ 0x1F, ("BVL", "Bandai Visual") },
+			{ 0x20, ("ATN", "Athena") },
+			{ 0x21, ("KDX", "KID") },
+			{ 0x22, ("HAL", "HAL Corporation") },
+			{ 0x23, ("YKE", "Yuki Enterprise") },
+			{ 0x24, ("OMM", "Omega Micott") },
+			{ 0x25, ("LAY", "Layup") },
+			{ 0x26, ("KDK", "Kadokawa Shoten") },
+			{ 0x27, ("SHL", "Shall Luck") },
+			{ 0x28, ("SQR", "Squaresoft") },
+			{ 0x2A, ("SCC", "NTT DoCoMo (?)") },    /* MobileWonderGate */
+			{ 0x2B, ("TMC", "Tom Create") },
+			{ 0x2D, ("NMC", "Namco") },
+			{ 0x2E, ("SES", "Movic (?)") },
+			{ 0x2F, ("HTR", "E3 Staff (?)") },
+			{ 0x31, ("VGD", "Vanguard") },
+			{ 0x32, ("MGT", "Megatron") },
+			{ 0x33, ("WIZ", "Wiz") },
+			{ 0x36, ("CAP", "Capcom") },
+		};
+
+		readonly Dictionary<SaveTypes, int> saveSizes = new()
+		{
+			{ SaveTypes.None, 0 },
+			{ SaveTypes.Sram64Kbit, 1024 * 8 },
+			{ SaveTypes.Sram256Kbit, 1024 * 32 },
+			{ SaveTypes.Sram1Mbit, 1024 * 128 },
+			{ SaveTypes.Sram2Mbit, 1024 * 256 },
+			{ SaveTypes.Sram4Mbit, 1024 * 512 },
+			{ SaveTypes.Eeprom1Kbit, 2 * 64 },
+			{ SaveTypes.Eeprom16Kbit, 2 * 1024 },
+			{ SaveTypes.Eeprom8Kbit, 2 * 512 },
+		};
+
+		public byte PublisherId { get; private set; }
+		public SystemTypes SystemType { get; private set; }
+		public byte GameId { get; private set; }
+		public byte GameRevision { get; private set; }
+		public RomSizes RomSize { get; private set; }
+		public SaveTypes SaveType { get; private set; }
+		public byte MiscFlags { get; private set; }
+		public byte RtcPresentFlag { get; private set; }
+		public ushort Checksum { get; private set; }
+
+		public string PublisherCode => publishers.ContainsKey(PublisherId) ? publishers[PublisherId].code : "???";
+		public string PublisherName => publishers.ContainsKey(PublisherId) ? publishers[PublisherId].name : "(Unknown)";
+
+		public string GameIdString => $"SWJ-{PublisherCode}{(SystemType == SystemTypes.WonderSwan ? "0" : "C")}{GameId:X2}";
+
+		public Orientations Orientation => (Orientations)(MiscFlags & (1 << 0));
+		public RomBusWidths RomBusWidth => (RomBusWidths)(MiscFlags & (1 << 1));
+		public RomAccessSpeeds RomAccessSpeed => (RomAccessSpeeds)(MiscFlags & (1 << 2));
+
+		public int SaveSize => saveSizes.ContainsKey(SaveType) ? saveSizes[SaveType] : 0;
+
+		public bool IsSramSave =>
+			SaveType == SaveTypes.Sram64Kbit || SaveType == SaveTypes.Sram256Kbit ||
+			SaveType == SaveTypes.Sram1Mbit || SaveType == SaveTypes.Sram2Mbit || SaveType == SaveTypes.Sram4Mbit;
+
+		public bool IsEepromSave =>
+			SaveType == SaveTypes.Eeprom1Kbit || SaveType == SaveTypes.Eeprom16Kbit || SaveType == SaveTypes.Eeprom8Kbit;
+
+		public bool IsRtcPresent => RtcPresentFlag != 0;
+
+		public ushort CalculatedChecksum { get; private set; }
+
+		public bool IsChecksumValid => Checksum == CalculatedChecksum;
+
+		public Metadata(byte[] data)
+		{
+			var offset = data.Length - 10;
+			PublisherId = data[offset + 0];
+			SystemType = (SystemTypes)data[offset + 1];
+			GameId = data[offset + 2];
+			GameRevision = data[offset + 3];
+			RomSize = (RomSizes)data[offset + 4];
+			SaveType = (SaveTypes)data[offset + 5];
+			MiscFlags = data[offset + 6];
+			RtcPresentFlag = data[offset + 7];
+			Checksum = (ushort)(data[offset + 9] << 8 | data[offset + 8]);
+
+			CalculatedChecksum = 0;
+			for (var i = 0; i < data.Length - 2; i++)
+				CalculatedChecksum += data[i + 0];
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta
new file mode 100644
index 00000000..718ec51f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 6ca048ba38a22c849a012278fc9515f3
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs
new file mode 100644
index 00000000..3683a9a5
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs
@@ -0,0 +1,349 @@
+using System;
+
+using StoicGoose.Common.Utilities;
+using StoicGoose.Core.Interfaces;
+using StoicGoose.Core.Machines;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Cartridges
+{
+	/* Seiko S-3511A real-time clock, through Bandai 2003 mapper
+	 * - https://forums.nesdev.org/viewtopic.php?t=21513
+	 * - https://datasheetspdf.com/pdf-file/1087347/Seiko/S-3511A/1
+	 */
+
+	// TODO: interrupts, save/load current state
+
+	public sealed class RTC : IPortAccessComponent
+	{
+		const int cyclesInSecond = (int)MachineCommon.CpuClock;
+
+		readonly byte[] numPayloadBytes = new byte[] { 0, 1, 7, 3, 2, 2, 2 };
+		readonly int[] numDaysPerMonth = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+		/* WS - Status & data registers */
+		byte wsData;
+		byte payloadIndex;
+
+		/* WS+RTC - Communication */
+		byte command;
+		bool isReadAccess;
+
+		/* RTC - Real-time data register */
+		byte year, month, day, dayOfWeek, hour, minute, second;
+		bool isPm, isTestModeActive;
+
+		/* RTC - Status register */
+		bool isPowered, is24HourMode;
+		bool intAE, intME, intFE;
+
+		/* RTC - Alarm time/frequency duty setting register */
+		ushort intRegister;
+
+		(bool pm, byte hour, byte minute) alarmTime => (IsBitSet((byte)(intRegister >> 0), 7), (byte)((intRegister >> 0) & 0b00111111), (byte)((intRegister >> 8) & 0b01111111));
+		int selectedInterruptFreq
+		{
+			get
+			{
+				var freq = 0;
+				for (var j = 0; j < 16; j++) if (((intRegister >> j) & 0b1) == 0b1) freq |= 32768 >> j;
+				return freq;
+			}
+		}
+
+		int cycleCount;
+
+		public RTC()
+		{
+			//
+		}
+
+		public void Reset()
+		{
+			wsData = 0;
+			payloadIndex = 0;
+
+			command = 0;
+			isReadAccess = false;
+
+			year = dayOfWeek = hour = minute = second = 0;
+			month = day = 1;
+			isPm = isTestModeActive = false;
+
+			is24HourMode = intAE = intME = false;
+			isPowered = intFE = true;
+
+			intRegister = 0x8000;
+
+			cycleCount = 0;
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public void Program(DateTime dateTime)
+		{
+			year = (byte)(dateTime.Year % 100);
+			month = (byte)(dateTime.Month % 13);
+			day = (byte)(dateTime.Day % 32);
+			dayOfWeek = (byte)((int)dateTime.DayOfWeek % 8);
+			hour = (byte)(dateTime.Hour % 25);
+			minute = (byte)(dateTime.Minute % 60);
+			second = (byte)(dateTime.Second % 60);
+		}
+
+		public bool Step(int clockCyclesInStep)
+		{
+			var interrupt = false;
+
+			for (var i = 0; i < clockCyclesInStep; i++)
+			{
+				if (intFE && !intME)
+				{
+					/* Selected frequency steady interrupt output */
+
+					// TODO probably not right
+					if (cycleCount >= selectedInterruptFreq)
+						interrupt = true;
+
+				}
+				else if (!intFE && intME)
+				{
+					/* Per-minute edge interrupt output */
+					// TODO
+				}
+				else if (intFE && intME)
+				{
+					/* Per-minute steady interrupt output */
+					// TODO
+				}
+				else if (!intFE && !intME && intAE)
+				{
+					/* Alarm interrupt output */
+					if (alarmTime.pm == isPm && Bcd.BcdToDecimal(alarmTime.hour) == hour && Bcd.BcdToDecimal(alarmTime.minute) == minute)
+						interrupt = true;
+				}
+
+				cycleCount++;
+				if (cycleCount >= cyclesInSecond)
+				{
+					UpdateClock();
+					cycleCount = 0;
+				}
+			}
+
+			return interrupt;
+		}
+
+		private void UpdateClock()
+		{
+			second++;
+			if (second < 60) return;
+
+			second = 0;
+			minute++;
+			if (minute < 60) return;
+
+			minute = 0;
+			hour++;
+			if (hour < 24) return;
+
+			hour = 0;
+			dayOfWeek++;
+			dayOfWeek %= 7;
+
+			day++;
+			var extraDay = (month == 2 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) ? 1 : 0;
+			if (day < numDaysPerMonth[month] + extraDay) return;
+
+			day = 0;
+			month++;
+			if (month < 12) return;
+
+			month = 0;
+			year++;
+		}
+
+		private void PerformAccess()
+		{
+			switch (command & 0b111)
+			{
+				case 0b000:
+					/* Reset */
+					wsData = 0;
+
+					year = 0;
+					month = 1;
+					day = 1;
+					dayOfWeek = 0;
+					hour = 0;
+					minute = 0;
+					second = 0;
+
+					isPowered = is24HourMode = false;
+					intAE = intME = intFE = false;
+
+					intRegister = 0x0000;
+					break;
+
+				case 0b001:
+					/* Status register access */
+					if (isReadAccess)
+					{
+						wsData = 0;
+						ChangeBit(ref wsData, 7, isPowered);
+						ChangeBit(ref wsData, 6, is24HourMode);
+						ChangeBit(ref wsData, 5, intAE);
+						ChangeBit(ref wsData, 3, intME);
+						ChangeBit(ref wsData, 1, intFE);
+					}
+					else
+					{
+						is24HourMode = IsBitSet(wsData, 6);
+						intAE = IsBitSet(wsData, 5);
+						intME = IsBitSet(wsData, 3);
+						intFE = IsBitSet(wsData, 1);
+					}
+					break;
+
+				case 0b010:
+					/* Real-time data access 1 */
+					if (isReadAccess)
+					{
+						wsData = 0;
+						switch (payloadIndex)
+						{
+							case 0: wsData = (byte)Bcd.DecimalToBcd(year); break;
+							case 1: wsData = (byte)Bcd.DecimalToBcd(month); break;
+							case 2: wsData = (byte)Bcd.DecimalToBcd(day); break;
+							case 3: wsData = (byte)Bcd.DecimalToBcd(dayOfWeek); break;
+							case 4: wsData = (byte)Bcd.DecimalToBcd(hour); ChangeBit(ref wsData, 7, isPm); break;
+							case 5: wsData = (byte)Bcd.DecimalToBcd(minute); break;
+							case 6: wsData = (byte)Bcd.DecimalToBcd(second); ChangeBit(ref wsData, 7, isTestModeActive); break;
+						}
+					}
+					else
+					{
+						switch (payloadIndex)
+						{
+							case 0: year = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 1: month = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 2: day = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 3: dayOfWeek = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 4: hour = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isPm = IsBitSet(wsData, 7); break;
+							case 5: minute = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 6: second = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isTestModeActive = IsBitSet(wsData, 7); break;
+						}
+					}
+					break;
+
+				case 0b011:
+					/* Real-time data access 2 */
+					if (isReadAccess)
+					{
+						wsData = 0;
+						switch (payloadIndex)
+						{
+							case 0: wsData = (byte)Bcd.DecimalToBcd(hour); ChangeBit(ref wsData, 7, isPm); break;
+							case 1: wsData = (byte)Bcd.DecimalToBcd(minute); break;
+							case 2: wsData = (byte)Bcd.DecimalToBcd(second); ChangeBit(ref wsData, 7, isTestModeActive); break;
+						}
+					}
+					else
+					{
+						switch (payloadIndex)
+						{
+							case 0: hour = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isPm = IsBitSet(wsData, 7); break;
+							case 1: minute = (byte)Bcd.BcdToDecimal(wsData); break;
+							case 2: second = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isTestModeActive = IsBitSet(wsData, 7); break;
+						}
+					}
+					break;
+
+				case 0b100:
+					/* Alarm time/frequency duty setting */
+					if (isReadAccess)
+					{
+						wsData = 0;
+						switch (payloadIndex)
+						{
+							case 0: wsData = (byte)((intRegister >> 0) & 0xFF); break;
+							case 1: wsData = (byte)((intRegister >> 8) & 0xFF); break;
+						}
+					}
+					else
+					{
+						switch (payloadIndex)
+						{
+							case 0: intRegister = (ushort)((intRegister & 0xFF00) | (wsData << 0)); break;
+							case 1: intRegister = (ushort)((intRegister & 0x00FF) | (wsData << 8)); break;
+						}
+					}
+					break;
+
+				case 0b101:
+					/* Unknown/invalid */
+					if (isReadAccess)
+					{
+						wsData = 0xFF;
+					}
+					break;
+
+				case 0b110:
+					/* Test mode start -- ignored */
+					break;
+
+				case 0b111:
+					/* Test mode end -- ignored */
+					break;
+
+				default:
+					break;
+			}
+		}
+
+		public byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0x90;
+
+			if (port == 0)
+			{
+				PerformAccess();
+
+				payloadIndex++;
+
+				ChangeBit(ref retVal, 7, true); // TODO: correct?
+				ChangeBit(ref retVal, 4, payloadIndex < numPayloadBytes[command & 0b111]);
+				ChangeBit(ref retVal, 0, true);
+				retVal |= (byte)((command & 0b1111) << 1);
+
+				if (payloadIndex >= numPayloadBytes[command & 0b111])
+					payloadIndex = 0;
+			}
+			else if (port == 1)
+			{
+				retVal = wsData;
+			}
+
+			return retVal;
+		}
+
+		public void WritePort(ushort port, byte value)
+		{
+			if (port == 0)
+			{
+				isReadAccess = IsBitSet(value, 0);
+				command = (byte)((value >> 1) & 0b111);
+
+				PerformAccess();
+			}
+			else if (port == 1)
+			{
+				wsData = value;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta
new file mode 100644
index 00000000..e6e61b38
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: acdef41e0d8804e45a3033ad3f95f77e
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta
new file mode 100644
index 00000000..223301e7
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e29bbdbdcb911604ea0efb453913bff8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs
new file mode 100644
index 00000000..33e2f3f8
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs
@@ -0,0 +1,168 @@
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.DMA
+{
+	public class SphinxGeneralDMAController : IPortAccessComponent
+	{
+		// TODO: verify behavior!
+
+		readonly IMachine machine = default;
+
+		/* REG_DMA_SRC(_HI) */
+		uint dmaSource;
+		/* REG_DMA_DST */
+		ushort dmaDestination;
+		/* REG_DMA_LEN */
+		ushort dmaLength;
+		/* REG_DMA_CTRL */
+		byte dmaControl;
+
+		public bool IsActive => IsBitSet(dmaControl, 7);
+
+		bool isDecrementMode => IsBitSet(dmaControl, 6);
+
+		public SphinxGeneralDMAController(IMachine machine)
+		{
+			this.machine = machine;
+		}
+
+		public void Reset()
+		{
+			//
+
+			ResetRegisters();
+		}
+
+		private void ResetRegisters()
+		{
+			dmaSource = dmaDestination = dmaLength = dmaControl = 0;
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public int Step()
+		{
+			if (dmaLength == 0 || ((dmaSource >> 16) & 0x0F) == 0x01)
+			{
+				/* Disable DMA if length is zero OR source is SRAM */
+				ChangeBit(ref dmaControl, 7, false);
+				return 5;
+			}
+			else
+			{
+				if (((dmaSource >> 16) & 0x0F) != 0x01)
+				{
+					/* Perform DMA if source is not SRAM */
+					machine.WriteMemory((uint)(dmaDestination + 0), machine.ReadMemory(dmaSource + 0));
+					machine.WriteMemory((uint)(dmaDestination + 1), machine.ReadMemory(dmaSource + 1));
+				}
+
+				dmaSource += (uint)(isDecrementMode ? -2 : 2);
+				dmaDestination += (ushort)(isDecrementMode ? -2 : 2);
+				dmaLength -= 2;
+
+				return 2;
+			}
+		}
+
+		public byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x40:
+					/* REG_DMA_SRC (low) */
+					retVal |= (byte)((dmaSource >> 0) & 0xFE);
+					break;
+				case 0x41:
+					/* REG_DMA_SRC (mid) */
+					retVal |= (byte)((dmaSource >> 8) & 0xFF);
+					break;
+				case 0x42:
+					/* REG_DMA_SRC_HI */
+					retVal |= (byte)((dmaSource >> 16) & 0x0F);
+					break;
+
+				case 0x44:
+					/* REG_DMA_DST (low) */
+					retVal |= (byte)((dmaDestination >> 0) & 0xFE);
+					break;
+				case 0x45:
+					/* REG_DMA_DST (high) */
+					retVal |= (byte)((dmaDestination >> 8) & 0xFF);
+					break;
+
+				case 0x46:
+					/* REG_DMA_LEN */
+					retVal |= (byte)((dmaLength >> 0) & 0xFE);
+					break;
+				case 0x47:
+					/* REG_DMA_LEN */
+					retVal |= (byte)((dmaLength >> 8) & 0xFF);
+					break;
+
+				case 0x48:
+					/* REG_DMA_CTRL */
+					retVal |= (byte)(dmaControl & 0b11000000);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x40:
+					/* REG_DMA_SRC (low) */
+					dmaSource &= 0xFFF00;
+					dmaSource |= (uint)((value << 0) & 0x000FE);
+					break;
+				case 0x41:
+					/* REG_DMA_SRC (high) */
+					dmaSource &= 0xF00FE;
+					dmaSource |= (uint)((value << 8) & 0x0FF00);
+					break;
+				case 0x42:
+					/* REG_DMA_SRC_HI */
+					dmaSource &= 0x0FFFE;
+					dmaSource |= (uint)((value << 16) & 0xF0000);
+					break;
+
+				case 0x44:
+					/* REG_DMA_DST (low) */
+					dmaDestination &= 0xFF00;
+					dmaDestination |= (ushort)((value << 0) & 0x00FE);
+					break;
+				case 0x45:
+					/* REG_DMA_DST (high) */
+					dmaDestination &= 0x00FE;
+					dmaDestination |= (ushort)((value << 8) & 0xFF00);
+					break;
+
+				case 0x46:
+					/* REG_DMA_LEN (low) */
+					dmaLength &= 0xFF00;
+					dmaLength |= (ushort)((value << 0) & 0x00FE);
+					break;
+				case 0x47:
+					/* REG_DMA_LEN (high) */
+					dmaLength &= 0x00FE;
+					dmaLength |= (ushort)((value << 8) & 0xFF00);
+					break;
+
+				case 0x48:
+					/* REG_DMA_CTRL */
+					dmaControl = (byte)(value & 0b11000000);
+					break;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta
new file mode 100644
index 00000000..12b199ae
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 8e43c53f0ef2ab24e9aec07a2ca82f6b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs
new file mode 100644
index 00000000..91942425
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs
@@ -0,0 +1,173 @@
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.DMA
+{
+	public class SphinxSoundDMAController : IPortAccessComponent
+	{
+		readonly static int[] cycleCounts = { 768, 512, 256, 128 };
+
+		readonly static ushort destinationPortChannel2Volume = 0x089;
+		readonly static ushort destinationPortHyperVoice = 0x095;
+
+		readonly IMachine machine = default;
+
+		/* REG_DMA_SRC(_HI) */
+		uint dmaSource;
+		/* REG_DMA_LEN(_HI) */
+		uint dmaLength;
+		/* REG_DMA_CTRL */
+		byte dmaControl;
+
+		public bool IsActive => IsBitSet(dmaControl, 7);
+
+		bool isDecrementMode => IsBitSet(dmaControl, 6);
+		bool isDestinationHyperVoice => IsBitSet(dmaControl, 4);
+		bool isLoopingMode => IsBitSet(dmaControl, 3);
+		int dmaRate => dmaControl & 0b11;
+
+		uint initialSource, initialLength;
+
+		int cycleCount;
+
+		public SphinxSoundDMAController(IMachine machine)
+		{
+			this.machine = machine;
+		}
+
+		public void Reset()
+		{
+			initialSource = initialLength = 0;
+
+			cycleCount = 0;
+
+			ResetRegisters();
+		}
+
+		private void ResetRegisters()
+		{
+			dmaSource = dmaLength = dmaControl = 0;
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public void Step(int clockCyclesInStep)
+		{
+			cycleCount += clockCyclesInStep;
+
+			if (cycleCount >= cycleCounts[dmaRate])
+			{
+				machine.WritePort(isDestinationHyperVoice ? destinationPortHyperVoice : destinationPortChannel2Volume, machine.ReadMemory(dmaSource));
+
+				dmaSource += (uint)(isDecrementMode ? -1 : 1);
+				dmaLength--;
+
+				if (dmaLength == 0)
+				{
+					if (isLoopingMode)
+					{
+						dmaSource = initialSource;
+						dmaLength = initialLength;
+					}
+					else
+						ChangeBit(ref dmaControl, 7, false);
+				}
+
+				cycleCount = 0;
+			}
+		}
+
+		public byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x4A:
+					/* REG_SDMA_SRC (low) */
+					retVal |= (byte)((dmaSource >> 0) & 0xFF);
+					break;
+				case 0x4B:
+					/* REG_SDMA_SRC (mid) */
+					retVal |= (byte)((dmaSource >> 8) & 0xFF);
+					break;
+				case 0x4C:
+					/* REG_SDMA_SRC_HI */
+					retVal |= (byte)((dmaSource >> 16) & 0x0F);
+					break;
+
+				case 0x4E:
+					/* REG_SDMA_LEN (low) */
+					retVal |= (byte)((dmaLength >> 0) & 0xFE);
+					break;
+				case 0x4F:
+					/* REG_SDMA_LEN (mid) */
+					retVal |= (byte)((dmaLength >> 8) & 0xFF);
+					break;
+				case 0x50:
+					/* REG_SDMA_LEN_HI */
+					retVal |= (byte)((dmaLength >> 16) & 0x0F);
+					break;
+
+				case 0x52:
+					/* REG_SDMA_CTRL */
+					retVal |= (byte)(dmaControl & 0b11011111);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x4A:
+					/* REG_SDMA_SRC (low) */
+					dmaSource &= 0xFFF00;
+					dmaSource |= (uint)((value << 0) & 0x000FF);
+					break;
+				case 0x4B:
+					/* REG_SDMA_SRC (mid) */
+					dmaSource &= 0xF00FF;
+					dmaSource |= (uint)((value << 8) & 0x0FF00);
+					break;
+				case 0x4C:
+					/* REG_SDMA_SRC_HI */
+					dmaSource &= 0x0FFFF;
+					dmaSource |= (uint)((value << 16) & 0xF0000);
+					break;
+
+				case 0x4E:
+					/* REG_SDMA_LEN (low) */
+					dmaLength &= 0xFFF00;
+					dmaLength |= (ushort)((value << 0) & 0x00FF);
+					break;
+				case 0x4F:
+					/* REG_SDMA_LEN (mid) */
+					dmaLength &= 0xF00FF;
+					dmaLength |= (ushort)((value << 8) & 0xFF00);
+					break;
+				case 0x50:
+					/* REG_SDMA_SRC_HI */
+					dmaLength &= 0x0FFFF;
+					dmaLength |= (uint)((value << 16) & 0xF0000);
+					break;
+
+				case 0x52:
+					/* REG_SDMA_CTRL */
+					if (!IsActive && IsBitSet(value, 7))
+					{
+						initialSource = dmaSource;
+						initialLength = dmaLength;
+					}
+					dmaControl = (byte)(value & 0b11011111);
+					break;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta
new file mode 100644
index 00000000..3c50aab5
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: ef4ffde1da744e54fb8facfbc5fac13f
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta
new file mode 100644
index 00000000..cc2f4bee
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3611bec488c079c419db211c75d1afd1
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs
new file mode 100644
index 00000000..13edb2b8
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs
@@ -0,0 +1,179 @@
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Display
+{
+	public sealed unsafe class AswanDisplayController : DisplayControllerCommon
+	{
+		public AswanDisplayController(IMachine machine) : base(machine) { }
+
+		protected override void RenderSleep(int y, int x)
+		{
+			DisplayUtilities.CopyPixel((255, 255, 255), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderBackColor(int y, int x)
+		{
+			DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[backColorIndex & 0b0111])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSCR1(int y, int x)
+		{
+			if (!scr1Enable) return;
+
+			var scrollX = (x + scr1ScrollX) & 0xFF;
+			var scrollY = (y + scr1ScrollY) & 0xFF;
+
+			var mapOffset = (uint)((scr1Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1));
+			var attribs = ReadMemory16(mapOffset);
+			var tileNum = (ushort)(attribs & 0x01FF);
+			var tilePal = (byte)((attribs >> 9) & 0b1111);
+
+			var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), false, false, false);
+
+			var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0;
+			if (!isOpaque) return;
+
+			DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSCR2(int y, int x)
+		{
+			if (!scr2Enable) return;
+
+			var scrollX = (x + scr2ScrollX) & 0xFF;
+			var scrollY = (y + scr2ScrollY) & 0xFF;
+
+			var mapOffset = (uint)((scr2Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1));
+			var attribs = ReadMemory16(mapOffset);
+			var tileNum = (ushort)(attribs & 0x01FF);
+			var tilePal = (byte)((attribs >> 9) & 0b1111);
+
+			var isVisible = !scr2WindowEnable || (scr2WindowEnable && ((!scr2WindowDisplayOutside && IsInsideSCR2Window(y, x)) || (scr2WindowDisplayOutside && IsOutsideSCR2Window(y, x))));
+			if (!isVisible) return;
+
+			var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), false, false, false);
+
+			var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0;
+			if (!isOpaque) return;
+
+			isUsedBySCR2[(y * HorizontalDisp) + x] = true;
+
+			DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSprites(int y, int x)
+		{
+			if (!sprEnable) return;
+
+			if (x == 0)
+			{
+				activeSpriteCountOnLine = 0;
+				for (var i = 0; i < spriteCountNextFrame; i++)
+				{
+					var spriteY = (spriteData[i] >> 16) & 0xFF;
+					if ((byte)(y - spriteY) <= 7 && activeSpriteCountOnLine < maxSpritesPerLine)
+						activeSpritesOnLine[activeSpriteCountOnLine++] = spriteData[i];
+				}
+			}
+
+			for (var i = 0; i < activeSpriteCountOnLine; i++)
+			{
+				var activeSprite = activeSpritesOnLine[i];
+
+				var spriteX = (activeSprite >> 24) & 0xFF;
+				if (x < 0 || x >= HorizontalDisp || (byte)(x - spriteX) > 7) continue;
+
+				var windowDisplayOutside = ((activeSprite >> 12) & 0b1) == 0b1;
+				if (!sprWindowEnable || (sprWindowEnable && (windowDisplayOutside != IsInsideSPRWindow(y, x))))
+				{
+					var tileNum = (ushort)(activeSprite & 0x01FF);
+					var tilePal = (byte)((activeSprite >> 9) & 0b111);
+					var priorityAboveSCR2 = ((activeSprite >> 13) & 0b1) == 0b1;
+					var spriteY = (activeSprite >> 16) & 0xFF;
+
+					var isVisible = !isUsedBySCR2[(y * HorizontalDisp) + x] || priorityAboveSCR2;
+					if (!isVisible) continue;
+
+					var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, (byte)((y - spriteY) ^ (((activeSprite >> 15) & 0b1) * 7)), (byte)((x - spriteX) ^ (((activeSprite >> 14) & 0b1) * 7)), false, false, false);
+
+					var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0;
+					if (!isOpaque) continue;
+
+					tilePal += 8;
+
+					DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+				}
+			}
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x01:
+					/* REG_BACK_COLOR */
+					retVal |= (byte)(backColorIndex & 0b111);
+					break;
+
+				case 0x04:
+					/* REG_SPR_BASE */
+					retVal |= (byte)(sprBase & 0b11111);
+					break;
+
+				case 0x07:
+					/* REG_MAP_BASE */
+					retVal |= (byte)((scr1Base & 0b111) << 0);
+					retVal |= (byte)((scr2Base & 0b111) << 4);
+					break;
+
+				case 0x14:
+					/* REG_LCD_CTRL */
+					ChangeBit(ref retVal, 0, lcdActive);
+					break;
+
+				default:
+					/* Fall through to common */
+					retVal = base.ReadPort(port);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x01:
+					/* REG_BACK_COLOR */
+					backColorIndex = (byte)(value & 0b111);
+					break;
+
+				case 0x04:
+					/* REG_SPR_BASE */
+					sprBase = (byte)(value & 0b11111);
+					break;
+
+				case 0x07:
+					/* REG_MAP_BASE */
+					scr1Base = (byte)((value >> 0) & 0b111);
+					scr2Base = (byte)((value >> 4) & 0b111);
+					break;
+
+				case 0x14:
+					/* REG_LCD_CTRL */
+					lcdActive = IsBitSet(value, 0);
+					break;
+
+				default:
+					/* Fall through to common */
+					base.WritePort(port, value);
+					break;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta
new file mode 100644
index 00000000..ce2209d9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 7245d0f687e243a4d9389a2c3c37d708
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs
new file mode 100644
index 00000000..11249218
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs
@@ -0,0 +1,773 @@
+using System;
+using System.Runtime.InteropServices;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+using StoicGoose.Core.Machines;
+using StoicGooseUnity;
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Display
+{
+    public unsafe abstract class DisplayControllerCommon : IPortAccessComponent
+    {
+        public const int HorizontalDisp = 224;
+        public const int HorizontalBlank = 32;
+        public const int HorizontalTotal = HorizontalDisp + HorizontalBlank;
+        public const double HorizontalClock = MachineCommon.CpuClock / HorizontalTotal;
+
+        public const int VerticalDisp = 144;
+        public const int VerticalBlank = 15;
+        public const int VerticalTotal = VerticalDisp + VerticalBlank;
+        public const double VerticalClock = 12000.0 / VerticalTotal;
+
+        public const int ScreenWidth = HorizontalDisp;
+        public const int ScreenHeight = VerticalDisp;
+
+        protected const int maxSpriteCount = 128;
+        protected const int maxSpritesPerLine = 32;
+
+        [Flags]
+        public enum DisplayInterrupts
+        {
+            None = 0,
+            LineCompare = 1 << 0,
+            VBlankTimer = 1 << 1,
+            VBlank = 1 << 2,
+            HBlankTimer = 1 << 3
+        }
+
+        protected readonly uint[] spriteData = new uint[maxSpriteCount];
+        protected readonly uint[] spriteDataNextFrame = new uint[maxSpriteCount];
+        protected readonly uint[] activeSpritesOnLine = new uint[maxSpritesPerLine];
+
+        protected readonly bool[] isUsedBySCR2 = new bool[HorizontalDisp * VerticalDisp];
+
+        protected int spriteCountNextFrame = 0, activeSpriteCountOnLine = 0;
+
+        protected int cycleCount = 0;
+        //protected readonly byte[] outputFramebuffer = new byte[ScreenWidth * ScreenHeight * 4];
+
+
+        #region //指针化 outputFramebuffer
+        protected byte[] outputFramebuffer_src;
+        protected GCHandle outputFramebuffer_handle;
+        protected IntPtr outputFramebuffer_IntPtr;
+        protected byte* outputFramebuffer;
+        protected int outputFramebufferLength;
+        protected bool outputFramebuffer_IsNull => outputFramebuffer == null;
+        protected byte[] outputFramebuffer_set
+        {
+            set
+            {
+                outputFramebuffer_handle.ReleaseGCHandle();
+                outputFramebuffer_src = value;
+                outputFramebufferLength = value.Length;
+                outputFramebuffer_src.GetObjectPtr(ref outputFramebuffer_handle, ref outputFramebuffer, out outputFramebuffer_IntPtr);
+            }
+        }
+        #endregion
+
+
+
+        //public Action<byte[]> SendFramebuffer { get; set; } = default;
+        public Action<IntPtr, long> SendFramebuffer { get; set; } = default;
+
+        protected readonly IMachine machine = default;
+
+        /* REG_DISP_CTRL */
+        protected bool scr1Enable, scr2Enable, sprEnable, sprWindowEnable, scr2WindowDisplayOutside, scr2WindowEnable;
+        /* REG_BACK_COLOR */
+        protected byte backColorIndex;
+        /* REG_LINE_xxx */
+        protected int lineCurrent, lineCompare;
+        /* REG_SPR_xxx */
+        protected int sprBase, sprFirst, sprCount;
+        /* REG_MAP_BASE */
+        protected int scr1Base, scr2Base;
+        /* REG_SCR2_WIN_xx */
+        protected int scr2WinX0, scr2WinY0, scr2WinX1, scr2WinY1;
+        /* REG_SPR_WIN_xx */
+        protected int sprWinX0, sprWinY0, sprWinX1, sprWinY1;
+        /* REG_SCR1_xx */
+        protected int scr1ScrollX, scr1ScrollY;
+        /* REG_SCR2_xx */
+        protected int scr2ScrollX, scr2ScrollY;
+        /* REG_LCD_xxx */
+        protected bool lcdActive;
+        protected bool iconSleep, iconVertical, iconHorizontal, iconAux1, iconAux2, iconAux3;
+        protected int vtotal, vsync;
+        /* REG_PALMONO_POOL_x */
+        protected readonly byte[] palMonoPools = default;
+        /* REG_PALMONO_x */
+        protected readonly byte[][] palMonoData = default;
+        /* REG_xTMR_xxx */
+        protected readonly DisplayTimer hBlankTimer = new(), vBlankTimer = new();
+
+        public DisplayControllerCommon(IMachine machine)
+        {
+            this.machine = machine;
+
+            //初始化指针
+            outputFramebuffer_set = new byte[ScreenWidth * ScreenHeight * 4];
+
+            palMonoPools = new byte[8];
+            palMonoData = new byte[16][];
+            for (var i = 0; i < palMonoData.GetLength(0); i++) palMonoData[i] = new byte[4];
+        }
+
+        public void Reset()
+        {
+            cycleCount = 0;
+
+            //Array.Fill<byte>(outputFramebuffer, 255);
+            for (var i = 0; i < outputFramebufferLength; i++)
+                outputFramebuffer[i] = 255;
+
+            Array.Fill(isUsedBySCR2, false);
+
+            Array.Fill<uint>(spriteData, 0);
+            Array.Fill<uint>(spriteDataNextFrame, 0);
+            Array.Fill<uint>(activeSpritesOnLine, 0);
+
+            spriteCountNextFrame = 0;
+            activeSpriteCountOnLine = 0;
+
+            ResetRegisters();
+        }
+
+        protected virtual void ResetRegisters()
+        {
+            scr1Enable = scr2Enable = sprEnable = sprWindowEnable = scr2WindowDisplayOutside = scr2WindowEnable = false;
+            backColorIndex = 0;
+            lineCurrent = lineCompare = 0;
+            sprBase = sprFirst = sprCount = 0;
+            scr1Base = scr2Base = 0;
+            scr2WinX0 = scr2WinY0 = scr2WinX1 = scr2WinY1 = 0;
+            sprWinX0 = sprWinY0 = sprWinX1 = sprWinY1 = 0;
+            scr1ScrollX = scr1ScrollY = 0;
+            scr2ScrollX = scr2ScrollY = 0;
+            lcdActive = true; /* NOTE: Final Lap 2000 depends on bootstrap doing this, otherwise LCD stays off? */
+            iconSleep = iconVertical = iconHorizontal = iconAux1 = iconAux2 = iconAux3 = false;
+            vtotal = VerticalTotal - 1;
+            vsync = VerticalTotal - 4; /* NOTE: Full usage/meaning unknown, so we're ignoring it for now */
+            Array.Fill<byte>(palMonoPools, 0);
+            for (var i = 0; i < palMonoData.GetLength(0); i++) Array.Fill<byte>(palMonoData[i], 0);
+            hBlankTimer.Reset();
+            vBlankTimer.Reset();
+        }
+
+        public void Shutdown()
+        {
+            /* Nothing to do... */
+        }
+
+        public DisplayInterrupts Step(int clockCyclesInStep)
+        {
+            var interrupt = DisplayInterrupts.None;
+
+            cycleCount += clockCyclesInStep;
+
+            if (cycleCount >= HorizontalTotal)
+            {
+                /* Sprite fetch */
+                if (lineCurrent == VerticalDisp - 2)
+                {
+                    spriteCountNextFrame = 0;
+                    for (var j = sprFirst; j < sprFirst + Math.Min(maxSpriteCount, sprCount); j++)
+                    {
+                        var k = (uint)((sprBase << 9) + (j << 2));
+                        spriteDataNextFrame[spriteCountNextFrame++] = (uint)(machine.ReadMemory(k + 3) << 24 | machine.ReadMemory(k + 2) << 16 | machine.ReadMemory(k + 1) << 8 | machine.ReadMemory(k + 0));
+                    }
+                }
+
+                /* Render pixels */
+                for (var x = 0; x < HorizontalDisp; x++)
+                    RenderPixel(lineCurrent, x);
+
+                /* Line compare interrupt */
+                if (lineCurrent == lineCompare)
+                    interrupt |= DisplayInterrupts.LineCompare;
+
+                /* H-timer interrupt */
+                if (hBlankTimer.Step())
+                    interrupt |= DisplayInterrupts.HBlankTimer;
+
+                /* V-blank interrupt */
+                if (lineCurrent == VerticalDisp)
+                {
+                    interrupt |= DisplayInterrupts.VBlank;
+
+                    /* V-timer interrupt */
+                    if (vBlankTimer.Step())
+                        interrupt |= DisplayInterrupts.VBlankTimer;
+
+                    /* Transfer framebuffer */
+                    //SendFramebuffer?.Invoke(outputFramebuffer.Clone() as byte[]);
+                    SendFramebuffer?.Invoke(outputFramebuffer_IntPtr, outputFramebufferLength);
+                }
+
+                /* Advance scanline */
+                lineCurrent++;
+
+                /* Is frame finished? */
+                if (lineCurrent > Math.Max(VerticalDisp, vtotal))
+                {
+                    /* Copy sprite data for next frame */
+                    for (int j = 0, k = spriteCountNextFrame - 1; k >= 0; j++, k--) spriteData[j] = spriteDataNextFrame[k];
+                    Array.Fill<uint>(spriteDataNextFrame, 0);
+
+                    /* Reset variables */
+                    lineCurrent = 0;
+                    Array.Fill(isUsedBySCR2, false);
+                }
+
+                /* End of scanline */
+                cycleCount = 0;
+            }
+
+            return interrupt;
+        }
+
+        protected void RenderPixel(int y, int x)
+        {
+            if (y < 0 || y >= VerticalDisp || x < 0 || x >= HorizontalDisp) return;
+
+            if (lcdActive)
+            {
+                RenderBackColor(y, x);
+                RenderSCR1(y, x);
+                RenderSCR2(y, x);
+                RenderSprites(y, x);
+            }
+            else
+            {
+                /* LCD sleeping */
+                RenderSleep(y, x);
+            }
+        }
+
+        protected abstract void RenderSleep(int y, int x);
+        protected abstract void RenderBackColor(int y, int x);
+        protected abstract void RenderSCR1(int y, int x);
+        protected abstract void RenderSCR2(int y, int x);
+        protected abstract void RenderSprites(int y, int x);
+
+        protected static void ValidateWindowCoordinates(ref int x0, ref int x1, ref int y0, ref int y1)
+        {
+            /* Thank you for this fix, for the encouragement and hints and advice, for just having been there... Thank you for everything, Near.
+			 * https://forum.fobby.net/index.php?t=msg&goto=6085 */
+
+            if (x0 > x1)
+                (x1, x0) = (x0, x1);
+
+            if (y0 > y1)
+                (y1, y0) = (y0, y1);
+        }
+
+        protected bool IsInsideSCR2Window(int y, int x)
+        {
+            var x0 = scr2WinX0;
+            var x1 = scr2WinX1;
+            var y0 = scr2WinY0;
+            var y1 = scr2WinY1;
+
+            ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1);
+
+            return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) &&
+                ((y >= y0 && y <= y1) || (y >= y1 && y <= y0));
+        }
+
+        protected bool IsOutsideSCR2Window(int y, int x)
+        {
+            var x0 = scr2WinX0;
+            var x1 = scr2WinX1;
+            var y0 = scr2WinY0;
+            var y1 = scr2WinY1;
+
+            ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1);
+
+            return x < x0 || x > x1 || y < y0 || y > y1;
+        }
+
+        protected bool IsInsideSPRWindow(int y, int x)
+        {
+            var x0 = sprWinX0;
+            var x1 = sprWinX1;
+            var y0 = sprWinY0;
+            var y1 = sprWinY1;
+
+            ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1);
+
+            return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) &&
+                ((y >= y0 && y <= y1) || (y >= y1 && y <= y0));
+        }
+
+        protected byte ReadMemory8(uint address) => machine.ReadMemory(address);
+        protected ushort ReadMemory16(uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
+        protected uint ReadMemory32(uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
+
+        public virtual byte ReadPort(ushort port)
+        {
+            var retVal = (byte)0;
+
+            switch (port)
+            {
+                case 0x00:
+                    /* REG_DISP_CTRL */
+                    ChangeBit(ref retVal, 0, scr1Enable);
+                    ChangeBit(ref retVal, 1, scr2Enable);
+                    ChangeBit(ref retVal, 2, sprEnable);
+                    ChangeBit(ref retVal, 3, sprWindowEnable);
+                    ChangeBit(ref retVal, 4, scr2WindowDisplayOutside);
+                    ChangeBit(ref retVal, 5, scr2WindowEnable);
+                    break;
+
+                case 0x02:
+                    /* REG_LINE_CUR */
+                    retVal |= (byte)(lineCurrent & 0xFF);
+                    break;
+
+                case 0x03:
+                    /* REG_LINE_CMP */
+                    retVal |= (byte)(lineCompare & 0xFF);
+                    break;
+
+                case 0x05:
+                    /* REG_SPR_FIRST */
+                    retVal |= (byte)(sprFirst & 0x7F);
+                    break;
+
+                case 0x06:
+                    /* REG_SPR_COUNT */
+                    retVal |= (byte)(sprCount & 0xFF);
+                    break;
+
+                case 0x08:
+                    /* REG_SCR2_WIN_X0 */
+                    retVal |= (byte)(scr2WinX0 & 0xFF);
+                    break;
+
+                case 0x09:
+                    /* REG_SCR2_WIN_Y0 */
+                    retVal |= (byte)(scr2WinY0 & 0xFF);
+                    break;
+
+                case 0x0A:
+                    /* REG_SCR2_WIN_X1 */
+                    retVal |= (byte)(scr2WinX1 & 0xFF);
+                    break;
+
+                case 0x0B:
+                    /* REG_SCR2_WIN_Y1 */
+                    retVal |= (byte)(scr2WinY1 & 0xFF);
+                    break;
+
+                case 0x0C:
+                    /* REG_SPR_WIN_X0 */
+                    retVal |= (byte)(sprWinX0 & 0xFF);
+                    break;
+
+                case 0x0D:
+                    /* REG_SPR_WIN_Y0 */
+                    retVal |= (byte)(sprWinY0 & 0xFF);
+                    break;
+
+                case 0x0E:
+                    /* REG_SPR_WIN_X1 */
+                    retVal |= (byte)(sprWinX1 & 0xFF);
+                    break;
+
+                case 0x0F:
+                    /* REG_SPR_WIN_Y1 */
+                    retVal |= (byte)(sprWinY1 & 0xFF);
+                    break;
+
+                case 0x10:
+                    /* REG_SCR1_X */
+                    retVal |= (byte)(scr1ScrollX & 0xFF);
+                    break;
+
+                case 0x11:
+                    /* REG_SCR1_Y */
+                    retVal |= (byte)(scr1ScrollY & 0xFF);
+                    break;
+
+                case 0x12:
+                    /* REG_SCR2_X */
+                    retVal |= (byte)(scr2ScrollX & 0xFF);
+                    break;
+
+                case 0x13:
+                    /* REG_SCR2_Y */
+                    retVal |= (byte)(scr2ScrollY & 0xFF);
+                    break;
+
+                case 0x15:
+                    /* REG_LCD_ICON */
+                    ChangeBit(ref retVal, 0, iconSleep);
+                    ChangeBit(ref retVal, 1, iconVertical);
+                    ChangeBit(ref retVal, 2, iconHorizontal);
+                    ChangeBit(ref retVal, 3, iconAux1);
+                    ChangeBit(ref retVal, 4, iconAux2);
+                    ChangeBit(ref retVal, 5, iconAux3);
+                    break;
+
+                case 0x16:
+                    /* REG_LCD_VTOTAL */
+                    retVal |= (byte)(vtotal & 0xFF);
+                    break;
+
+                case 0x17:
+                    /* REG_LCD_VSYNC */
+                    retVal |= (byte)(vsync & 0xFF);
+                    break;
+
+                case 0x1C:
+                case 0x1D:
+                case 0x1E:
+                case 0x1F:
+                    /* REG_PALMONO_POOL_x */
+                    retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 0] << 0);
+                    retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 1] << 4);
+                    break;
+
+                case ushort _ when port >= 0x20 && port <= 0x3F:
+                    /* REG_PALMONO_x */
+                    retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] << 0);
+                    retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] << 4);
+                    break;
+
+                case 0xA2:
+                    /* REG_TMR_CTRL */
+                    ChangeBit(ref retVal, 0, hBlankTimer.Enable);
+                    ChangeBit(ref retVal, 1, hBlankTimer.Repeating);
+                    ChangeBit(ref retVal, 2, vBlankTimer.Enable);
+                    ChangeBit(ref retVal, 3, vBlankTimer.Repeating);
+                    break;
+
+                case 0xA4:
+                case 0xA5:
+                    /* REG_HTMR_FREQ */
+                    retVal |= (byte)((hBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF);
+                    break;
+
+                case 0xA6:
+                case 0xA7:
+                    /* REG_VTMR_FREQ */
+                    retVal |= (byte)((vBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF);
+                    break;
+
+                case 0xA8:
+                case 0xA9:
+                    /* REG_HTMR_CTR */
+                    retVal |= (byte)((hBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF);
+                    break;
+
+                case 0xAA:
+                case 0xAB:
+                    /* REG_VTMR_CTR */
+                    retVal |= (byte)((vBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF);
+                    break;
+            }
+
+            return retVal;
+        }
+
+        public virtual void WritePort(ushort port, byte value)
+        {
+            switch (port)
+            {
+                case 0x00:
+                    /* REG_DISP_CTRL */
+                    scr1Enable = IsBitSet(value, 0);
+                    scr2Enable = IsBitSet(value, 1);
+                    sprEnable = IsBitSet(value, 2);
+                    sprWindowEnable = IsBitSet(value, 3);
+                    scr2WindowDisplayOutside = IsBitSet(value, 4);
+                    scr2WindowEnable = IsBitSet(value, 5);
+                    break;
+
+                case 0x03:
+                    /* REG_LINE_CMP */
+                    lineCompare = (byte)(value & 0xFF);
+                    break;
+
+                case 0x05:
+                    /* REG_SPR_FIRST */
+                    sprFirst = (byte)(value & 0x7F);
+                    break;
+
+                case 0x06:
+                    /* REG_SPR_COUNT */
+                    sprCount = (byte)(value & 0xFF);
+                    break;
+
+                case 0x08:
+                    /* REG_SCR2_WIN_X0 */
+                    scr2WinX0 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x09:
+                    /* REG_SCR2_WIN_Y0 */
+                    scr2WinY0 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0A:
+                    /* REG_SCR2_WIN_X1 */
+                    scr2WinX1 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0B:
+                    /* REG_SCR2_WIN_Y1 */
+                    scr2WinY1 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0C:
+                    /* REG_SPR_WIN_X0 */
+                    sprWinX0 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0D:
+                    /* REG_SPR_WIN_Y0 */
+                    sprWinY0 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0E:
+                    /* REG_SPR_WIN_X1 */
+                    sprWinX1 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x0F:
+                    /* REG_SPR_WIN_Y1 */
+                    sprWinY1 = (byte)(value & 0xFF);
+                    break;
+
+                case 0x10:
+                    /* REG_SCR1_X */
+                    scr1ScrollX = (byte)(value & 0xFF);
+                    break;
+
+                case 0x11:
+                    /* REG_SCR1_Y */
+                    scr1ScrollY = (byte)(value & 0xFF);
+                    break;
+
+                case 0x12:
+                    /* REG_SCR2_X */
+                    scr2ScrollX = (byte)(value & 0xFF);
+                    break;
+
+                case 0x13:
+                    /* REG_SCR2_Y */
+                    scr2ScrollY = (byte)(value & 0xFF);
+                    break;
+
+                case 0x15:
+                    /* REG_LCD_ICON */
+                    iconSleep = IsBitSet(value, 0);
+                    iconVertical = IsBitSet(value, 1);
+                    iconHorizontal = IsBitSet(value, 2);
+                    iconAux1 = IsBitSet(value, 3);
+                    iconAux2 = IsBitSet(value, 4);
+                    iconAux3 = IsBitSet(value, 5);
+                    break;
+
+                case 0x16:
+                    /* REG_LCD_VTOTAL */
+                    vtotal = (byte)(value & 0xFF);
+                    break;
+
+                case 0x17:
+                    /* REG_LCD_VSYNC */
+                    vsync = (byte)(value & 0xFF);
+                    break;
+
+                case 0x1C:
+                case 0x1D:
+                case 0x1E:
+                case 0x1F:
+                    /* REG_PALMONO_POOL_x */
+                    palMonoPools[((port & 0b11) << 1) | 0] = (byte)((value >> 0) & 0b1111);
+                    palMonoPools[((port & 0b11) << 1) | 1] = (byte)((value >> 4) & 0b1111);
+                    break;
+
+                case ushort _ when port >= 0x20 && port <= 0x3F:
+                    /* REG_PALMONO_x */
+                    palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] = (byte)((value >> 0) & 0b111);
+                    palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] = (byte)((value >> 4) & 0b111);
+                    break;
+
+                case 0xA2:
+                    /* REG_TMR_CTRL */
+                    hBlankTimer.Enable = IsBitSet(value, 0);
+                    hBlankTimer.Repeating = IsBitSet(value, 1);
+                    vBlankTimer.Enable = IsBitSet(value, 2);
+                    vBlankTimer.Repeating = IsBitSet(value, 3);
+                    break;
+
+                case 0xA4:
+                    /* REG_HTMR_FREQ (low) */
+                    hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0xFF00) | value);
+                    hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0xFF00) | value);
+                    break;
+
+                case 0xA5:
+                    /* REG_HTMR_FREQ (high) */
+                    hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0x00FF) | (value << 8));
+                    hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0x00FF) | (value << 8));
+                    break;
+
+                case 0xA6:
+                    /* REG_VTMR_FREQ (low) */
+                    vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0xFF00) | value);
+                    vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0xFF00) | value);
+                    break;
+
+                case 0xA7:
+                    /* REG_VTMR_FREQ (high) */
+                    vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0x00FF) | (value << 8));
+                    vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0x00FF) | (value << 8));
+                    break;
+            }
+        }
+
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SCR1 enable", 0)]
+        public bool Scr1Enable => scr1Enable;
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SCR2 enable", 1)]
+        public bool Scr2Enable => scr2Enable;
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SPR enable", 2)]
+        public bool SprEnable => sprEnable;
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SPR window enable", 3)]
+        public bool SprWindowEnable => sprWindowEnable;
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SCR2 window mode; display outside?", 4)]
+        public bool Scr2WindowDisplayOutside => scr2WindowDisplayOutside;
+        [Port("REG_DISP_CTRL", 0x000)]
+        [BitDescription("SCR2 window enable", 5)]
+        public bool Scr2WindowEnable => scr2WindowEnable;
+        [Port("REG_BACK_COLOR", 0x001)]
+        [BitDescription("Background color pool index", 0, 2)]
+        public virtual byte BackColorIndex => backColorIndex;
+        [Port("REG_LINE_CUR", 0x002)]
+        [BitDescription("Current line being drawn")]
+        public int LineCurrent => lineCurrent;
+        [Port("REG_LINE_CMP", 0x003)]
+        [BitDescription("Line compare interrupt line")]
+        public int LineCompare => lineCompare;
+        [Port("REG_SPR_BASE", 0x004)]
+        [BitDescription("Sprite table base address", 0, 4)]
+        [Format("X4", 9)]
+        public virtual int SprBase => sprBase;
+        [Port("REG_SPR_FIRST", 0x005)]
+        [BitDescription("First sprite to draw", 0, 6)]
+        public int SprFirst => sprFirst;
+        [Port("REG_SPR_COUNT", 0x006)]
+        [BitDescription("Number of sprites to draw")]
+        public int SprCount => sprCount;
+        [Port("REG_MAP_BASE", 0x007)]
+        [BitDescription("SCR1 base address", 0, 2)]
+        [Format("X4", 11)]
+        public virtual int Scr1Base => scr1Base;
+        [Port("REG_MAP_BASE", 0x007)]
+        [BitDescription("SCR2 base address", 4, 6)]
+        [Format("X4", 11)]
+        public virtual int Scr2Base => scr2Base;
+        [Port("REG_SCR2_WIN_X0", 0x008)]
+        [BitDescription("Top-left X of SCR2 window")]
+        public int Scr2WinX0 => scr2WinX0;
+        [Port("REG_SCR2_WIN_Y0", 0x009)]
+        [BitDescription("Top-left Y of SCR2 window")]
+        public int Scr2WinY0 => scr2WinY0;
+        [Port("REG_SCR2_WIN_X1", 0x00A)]
+        [BitDescription("Bottom-right X of SCR2 window")]
+        public int Scr2WinX1 => scr2WinX1;
+        [Port("REG_SCR2_WIN_Y1", 0x00B)]
+        [BitDescription("Bottom-right Y of SCR2 window")]
+        public int Scr2WinY1 => scr2WinY1;
+        [Port("REG_SPR_WIN_X0", 0x00C)]
+        [BitDescription("Top-left X of SPR window")]
+        public int SprWinX0 => sprWinX0;
+        [Port("REG_SPR_WIN_Y0", 0x00D)]
+        [BitDescription("Top-left Y of SPR window")]
+        public int SprWinY0 => sprWinY0;
+        [Port("REG_SPR_WIN_X1", 0x00E)]
+        [BitDescription("Bottom-right X of SPR window")]
+        public int SprWinX1 => sprWinX1;
+        [Port("REG_SPR_WIN_Y1", 0x00F)]
+        [BitDescription("Bottom-right Y of SPR window")]
+        public int SprWinY1 => sprWinY1;
+        [Port("REG_SCR1_X", 0x010)]
+        [BitDescription("SCR1 X scroll")]
+        public int Scr1ScrollX => scr1ScrollX;
+        [Port("REG_SCR1_Y", 0x011)]
+        [BitDescription("SCR1 Y scroll")]
+        public int Scr1ScrollY => scr1ScrollY;
+        [Port("REG_SCR2_X", 0x012)]
+        [BitDescription("SCR2 X scroll")]
+        public int Scr2ScrollX => scr2ScrollX;
+        [Port("REG_SCR2_Y", 0x013)]
+        [BitDescription("SCR2 Y scroll")]
+        public int Scr2ScrollY => scr2ScrollY;
+        [Port("REG_LCD_CTRL", 0x014)]
+        [BitDescription("LCD sleep mode; is LCD active?", 0)]
+        public bool LcdActive => lcdActive;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Sleep indicator", 0)]
+        public bool IconSleep => iconSleep;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Vertical orientation indicator", 1)]
+        public bool IconVertical => iconVertical;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Horizontal orientation indicator", 2)]
+        public bool IconHorizontal => iconHorizontal;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Auxiliary 1 (Small circle)", 3)]
+        public bool IconAux1 => iconAux1;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Auxiliary 2 (Medium circle)", 4)]
+        public bool IconAux2 => iconAux2;
+        [Port("REG_LCD_ICON", 0x015)]
+        [BitDescription("Auxiliary 3 (Big circle)", 5)]
+        public bool IconAux3 => iconAux3;
+        [Port("REG_LCD_VTOTAL", 0x016)]
+        [BitDescription("Display VTOTAL")]
+        public int VTotal => vtotal;
+        [Port("REG_LCD_VSYNC", 0x017)]
+        [BitDescription("VSYNC line position")]
+        public int VSync => vsync;
+        [Port("REG_TMR_CTRL", 0x0A2)]
+        [BitDescription("H-blank timer enable", 0)]
+        public bool HBlankTimerEnable => hBlankTimer.Enable;
+        [Port("REG_TMR_CTRL", 0x0A2)]
+        [BitDescription("H-blank timer mode; is repeating?", 1)]
+        public bool HBlankTimerRepeating => hBlankTimer.Repeating;
+        [Port("REG_TMR_CTRL", 0x0A2)]
+        [BitDescription("V-blank timer enable", 2)]
+        public bool VBlankTimerEnable => vBlankTimer.Enable;
+        [Port("REG_TMR_CTRL", 0x0A2)]
+        [BitDescription("V-blank timer mode; is repeating?", 3)]
+        public bool VBlankTimerRepeating => vBlankTimer.Repeating;
+        [Port("REG_HTMR_FREQ", 0x0A4, 0x0A5)]
+        [BitDescription("H-blank timer frequency")]
+        public ushort HBlankTimerFrequency => hBlankTimer.Frequency;
+        [Port("REG_VTMR_FREQ", 0x0A6, 0x0A7)]
+        [BitDescription("V-blank timer frequency")]
+        public ushort VBlankTimerFrequency => vBlankTimer.Frequency;
+        [Port("REG_HTMR_CTR", 0x0A8, 0x0A9)]
+        [BitDescription("H-blank timer counter")]
+        public ushort HBlankTimerCounter => hBlankTimer.Counter;
+        [Port("REG_VTMR_CTR", 0x0AA, 0x0AB)]
+        [BitDescription("V-blank timer counter")]
+        public ushort VBlankTimerCounter => vBlankTimer.Counter;
+
+        // TODO: reorganize palmono stuff & add attributes
+
+        public byte[] PalMonoPools => palMonoPools;
+        public byte[][] PalMonoData => palMonoData;
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta
new file mode 100644
index 00000000..0370aaca
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 1a27fcff4fc28e846845555e4cd903cd
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs
new file mode 100644
index 00000000..c94518ca
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs
@@ -0,0 +1,40 @@
+namespace StoicGoose.Core.Display
+{
+	public class DisplayTimer
+	{
+		public bool Enable { get; set; }
+		public bool Repeating { get; set; }
+		public ushort Frequency { get; set; }
+
+		public ushort Counter { get; set; }
+
+		public DisplayTimer()
+		{
+			Reset();
+		}
+
+		public void Reset()
+		{
+			Enable = Repeating = false;
+			Frequency = Counter = 0;
+		}
+
+		public void Reload()
+		{
+			Counter = Frequency;
+		}
+
+		public bool Step()
+		{
+			var counterNew = (ushort)(Counter - 1);
+
+			if (Enable && Counter != 0)
+			{
+				Counter = counterNew;
+				if (Repeating && Counter == 0)
+					Reload();
+			}
+			return counterNew == 0;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta
new file mode 100644
index 00000000..e23e0f0d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 25ad8c5efc6af8d45b2500b9c3411df0
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs
new file mode 100644
index 00000000..eccecc05
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs
@@ -0,0 +1,73 @@
+using System;
+using StoicGoose.Core.Interfaces;
+
+namespace StoicGoose.Core.Display
+{
+	public static class DisplayUtilities
+	{
+		// TODO: WSC high contrast mode
+
+		private static ushort ReadMemory16(IMachine machine, uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
+		private static uint ReadMemory32(IMachine machine, uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
+
+		public static byte ReadPixel(IMachine machine, ushort tile, int y, int x, bool isPacked, bool is4bpp, bool isColor)
+		{
+			/* http://perfectkiosk.net/stsws.html#color_mode */
+
+			/* WonderSwan OR Color/Crystal in 2bpp mode */
+			if (!isColor || (isColor && !is4bpp))
+			{
+				var data = ReadMemory16(machine, (uint)(0x2000 + (tile << 4) + ((y % 8) << 1)));
+				return (byte)((((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b11);
+			}
+
+			/* WonderSwan Color/Crystal in 4bpp mode */
+			else if (isColor && is4bpp)
+			{
+				/* 4bpp planar mode */
+				if (!isPacked)
+				{
+					var data = ReadMemory32(machine, (uint)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2)));
+					return (byte)((((data >> 31 - (x % 8)) & 0b1) << 3 | ((data >> 23 - (x % 8)) & 0b1) << 2 | ((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b1111);
+				}
+
+				/* 4bpp packed mode */
+				else if (isPacked)
+				{
+					var data = machine.ReadMemory((ushort)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2) + ((x % 8) >> 1)));
+					return (byte)((data >> 4 - (((x % 8) & 0b1) << 2)) & 0b1111);
+				}
+			}
+
+			throw new Exception("Invalid display controller configuration");
+		}
+
+		public static ushort ReadColor(IMachine machine, byte paletteIdx, byte colorIdx)
+		{
+			var address = (uint)(0x0FE00 + (paletteIdx << 5) + (colorIdx << 1));
+			return (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
+		}
+
+		private static byte DuplicateBits(int value) => (byte)((value & 0b1111) | (value & 0b1111) << 4);
+
+        public static (byte r, byte g, byte b) GeneratePixel(byte data) => (DuplicateBits(data), DuplicateBits(data), DuplicateBits(data));
+		public static (byte r, byte g, byte b) GeneratePixel(ushort data) => (DuplicateBits(data >> 8), DuplicateBits(data >> 4), DuplicateBits(data >> 0));
+
+		public static unsafe void CopyPixel((byte r, byte g, byte b) pixel, byte* data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4);
+        public static unsafe void CopyPixel((byte r, byte g, byte b) pixel, byte* data, long address)
+        {
+            data[address + 0] = pixel.r;
+            data[address + 1] = pixel.g;
+            data[address + 2] = pixel.b;
+            data[address + 3] = 255;
+        }
+        //public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4);
+        //public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, long address)
+        //{
+        //	data[address + 0] = pixel.r;
+        //	data[address + 1] = pixel.g;
+        //	data[address + 2] = pixel.b;
+        //	data[address + 3] = 255;
+        //}
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta
new file mode 100644
index 00000000..75587f15
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 3ef0eca0ad43a254f80fdccdc5891b74
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs
new file mode 100644
index 00000000..ac993b10
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs
@@ -0,0 +1,259 @@
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Display
+{
+	public sealed unsafe class SphinxDisplayController : DisplayControllerCommon
+	{
+		// TODO: reimplement high contrast mode; also, get a WSC, figure out how it's supposed to look?
+
+		/* REG_BACK_COLOR */
+		byte backColorPalette;
+		/* REG_LCD_CTRL */
+		bool lcdContrastHigh;
+		/* REG_DISP_MODE */
+		bool displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet;
+
+		public SphinxDisplayController(IMachine machine) : base(machine) { }
+
+		protected override void ResetRegisters()
+		{
+			base.ResetRegisters();
+
+			backColorPalette = 0;
+			lcdContrastHigh = false;
+			displayPackedFormatSet = display4bppFlagSet = displayColorFlagSet = false;
+		}
+
+		protected override void RenderSleep(int y, int x)
+		{
+			DisplayUtilities.CopyPixel((0, 0, 0), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderBackColor(int y, int x)
+		{
+			if (displayColorFlagSet)
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, backColorPalette, backColorIndex)), outputFramebuffer, x, y, HorizontalDisp);
+			else
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[backColorIndex & 0b0111])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSCR1(int y, int x)
+		{
+			if (!scr1Enable) return;
+
+			var scrollX = (x + scr1ScrollX) & 0xFF;
+			var scrollY = (y + scr1ScrollY) & 0xFF;
+
+			var mapOffset = (uint)((scr1Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1));
+			var attribs = ReadMemory16(mapOffset);
+			var tileNum = (ushort)((attribs & 0x01FF) | (displayColorFlagSet ? (((attribs >> 13) & 0b1) << 9) : 0));
+			var tilePal = (byte)((attribs >> 9) & 0b1111);
+
+			var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet);
+
+			var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0;
+			if (!isOpaque) return;
+
+			if (displayColorFlagSet)
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp);
+			else
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSCR2(int y, int x)
+		{
+			if (!scr2Enable) return;
+
+			var scrollX = (x + scr2ScrollX) & 0xFF;
+			var scrollY = (y + scr2ScrollY) & 0xFF;
+
+			var mapOffset = (uint)((scr2Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1));
+			var attribs = ReadMemory16(mapOffset);
+			var tileNum = (ushort)((attribs & 0x01FF) | (displayColorFlagSet ? (((attribs >> 13) & 0b1) << 9) : 0));
+			var tilePal = (byte)((attribs >> 9) & 0b1111);
+
+			var isVisible = !scr2WindowEnable || (scr2WindowEnable && ((!scr2WindowDisplayOutside && IsInsideSCR2Window(y, x)) || (scr2WindowDisplayOutside && IsOutsideSCR2Window(y, x))));
+			if (!isVisible) return;
+
+			var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet);
+
+			var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0;
+			if (!isOpaque) return;
+
+			isUsedBySCR2[(y * HorizontalDisp) + x] = true;
+
+			if (displayColorFlagSet)
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp);
+			else
+				DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+		}
+
+		protected override void RenderSprites(int y, int x)
+		{
+			if (!sprEnable) return;
+
+			if (x == 0)
+			{
+				activeSpriteCountOnLine = 0;
+				for (var i = 0; i < spriteCountNextFrame; i++)
+				{
+					var spriteY = (spriteData[i] >> 16) & 0xFF;
+					if ((byte)(y - spriteY) <= 7 && activeSpriteCountOnLine < maxSpritesPerLine)
+						activeSpritesOnLine[activeSpriteCountOnLine++] = spriteData[i];
+				}
+			}
+
+			for (var i = 0; i < activeSpriteCountOnLine; i++)
+			{
+				var activeSprite = activeSpritesOnLine[i];
+
+				var spriteX = (activeSprite >> 24) & 0xFF;
+				if (x < 0 || x >= HorizontalDisp || (byte)(x - spriteX) > 7) continue;
+
+				var windowDisplayOutside = ((activeSprite >> 12) & 0b1) == 0b1;
+				if (!sprWindowEnable || (sprWindowEnable && (windowDisplayOutside != IsInsideSPRWindow(y, x))))
+				{
+					var tileNum = (ushort)(activeSprite & 0x01FF);
+					var tilePal = (byte)((activeSprite >> 9) & 0b111);
+					var priorityAboveSCR2 = ((activeSprite >> 13) & 0b1) == 0b1;
+					var spriteY = (activeSprite >> 16) & 0xFF;
+
+					var isVisible = !isUsedBySCR2[(y * HorizontalDisp) + x] || priorityAboveSCR2;
+					if (!isVisible) continue;
+
+					var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, (byte)((y - spriteY) ^ (((activeSprite >> 15) & 0b1) * 7)), (byte)((x - spriteX) ^ (((activeSprite >> 14) & 0b1) * 7)), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet);
+
+					var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0;
+					if (!isOpaque) continue;
+
+					tilePal += 8;
+
+					if (displayColorFlagSet)
+						DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp);
+					else
+						DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp);
+				}
+			}
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x01:
+					/* REG_BACK_COLOR */
+					retVal |= (byte)((backColorIndex & 0b1111) << 0);
+					retVal |= (byte)((backColorPalette & 0b1111) << 4);
+					break;
+
+				case 0x04:
+					/* REG_SPR_BASE */
+					retVal |= (byte)(sprBase & (displayColorFlagSet ? 0b111111 : 0b011111));
+					break;
+
+				case 0x07:
+					/* REG_MAP_BASE */
+					retVal |= (byte)((scr1Base & (displayColorFlagSet ? 0b1111 : 0b0111)) << 0);
+					retVal |= (byte)((scr2Base & (displayColorFlagSet ? 0b1111 : 0b0111)) << 4);
+					break;
+
+				case 0x14:
+					/* REG_LCD_CTRL */
+					ChangeBit(ref retVal, 0, lcdActive);
+					ChangeBit(ref retVal, 1, lcdContrastHigh);
+					break;
+
+				case 0x60:
+					/* REG_DISP_MODE */
+					ChangeBit(ref retVal, 5, displayPackedFormatSet);
+					ChangeBit(ref retVal, 6, display4bppFlagSet);
+					ChangeBit(ref retVal, 7, displayColorFlagSet);
+					break;
+
+				default:
+					/* Fall through to common */
+					retVal = base.ReadPort(port);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x01:
+					/* REG_BACK_COLOR */
+					backColorIndex = (byte)((value >> 0) & 0b1111);
+					backColorPalette = (byte)((value >> 4) & 0b1111);
+					break;
+
+				case 0x04:
+					/* REG_SPR_BASE */
+					sprBase = (byte)(value & (displayColorFlagSet ? 0b111111 : 0b011111));
+					break;
+
+				case 0x07:
+					/* REG_MAP_BASE */
+					scr1Base = (byte)((value >> 0) & (displayColorFlagSet ? 0b1111 : 0b0111));
+					scr2Base = (byte)((value >> 4) & (displayColorFlagSet ? 0b1111 : 0b0111));
+					break;
+
+				case 0x14:
+					/* REG_LCD_CTRL */
+					lcdActive = IsBitSet(value, 0);
+					lcdContrastHigh = IsBitSet(value, 1);
+					break;
+
+				case 0x60:
+					/* REG_DISP_MODE */
+					displayPackedFormatSet = IsBitSet(value, 5);
+					display4bppFlagSet = IsBitSet(value, 6);
+					displayColorFlagSet = IsBitSet(value, 7);
+					break;
+
+				default:
+					/* Fall through to common */
+					base.WritePort(port, value);
+					break;
+			}
+		}
+
+		[Port("REG_BACK_COLOR", 0x001)]
+		[BitDescription("Background color index", 0, 3)]
+		public override byte BackColorIndex => backColorIndex;
+		[Port("REG_BACK_COLOR", 0x001)]
+		[BitDescription("Background color palette", 4, 7)]
+		public byte BackColorPalette => backColorPalette;
+		[Port("REG_SPR_BASE", 0x004)]
+		[BitDescription("Sprite table base address", 0, 5)]
+		[Format("X4", 9)]
+		public override int SprBase => sprBase;
+		[Port("REG_MAP_BASE", 0x007)]
+		[BitDescription("SCR1 base address", 0, 3)]
+		[Format("X4", 11)]
+		public override int Scr1Base => scr1Base;
+		[Port("REG_MAP_BASE", 0x007)]
+		[BitDescription("SCR2 base address", 4, 7)]
+		[Format("X4", 11)]
+		public override int Scr2Base => scr2Base;
+		[Port("REG_LCD_CTRL", 0x014)]
+		[BitDescription("LCD contrast setting; high contrast?", 1)]
+		public bool LcdContrastHigh => lcdContrastHigh;
+		[Port("REG_DISP_MODE", 0x060)]
+		[BitDescription("Tile format; is packed format?", 5)]
+		public bool DisplayPackedFormatSet => displayPackedFormatSet;
+		[Port("REG_DISP_MODE", 0x060)]
+		[BitDescription("Tile bits-per-pixel; is 4bpp?", 6)]
+		public bool Display4bppFlagSet => display4bppFlagSet;
+		[Port("REG_DISP_MODE", 0x060)]
+		[BitDescription("Display color mode; is color?", 7)]
+		public bool DisplayColorFlagSet => displayColorFlagSet;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta
new file mode 100644
index 00000000..ca142302
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: db70409b0ab432c438c40e9b0d82e082
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta
new file mode 100644
index 00000000..b2bf5e17
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: af8d3a9a00752da4496e02fe3b303d68
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs
new file mode 100644
index 00000000..4a695b2f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs
@@ -0,0 +1,204 @@
+using System;
+
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.EEPROMs
+{
+	public sealed class EEPROM : IPortAccessComponent
+	{
+		readonly byte[] contents = default;
+		readonly int numAddressBits = 0;
+
+		bool eraseWriteEnable = false;
+
+		byte dataLo, dataHi, addressLo, addressHi, statusCmd;
+
+		public EEPROM(int size, int addressBits)
+		{
+			contents = new byte[size];
+			numAddressBits = addressBits;
+		}
+
+		public void Reset()
+		{
+			dataLo = dataHi = 0;
+			addressLo = addressHi = 0;
+			statusCmd = 0;
+		}
+
+		public void Shutdown()
+		{
+			//
+		}
+
+		public void LoadContents(byte[] data)
+		{
+			if (data.Length != contents.Length)
+				throw new Exception("Data size mismatch error");
+
+			Buffer.BlockCopy(data, 0, contents, 0, data.Length);
+		}
+
+		public byte[] GetContents()
+		{
+			return contents;
+		}
+
+		public void Program(int address, byte value)
+		{
+			contents[address & (contents.Length - 1)] = value;
+		}
+
+		private void BeginAccess()
+		{
+			var addressHiLo = (addressHi << 8) | addressLo;
+
+			var address = (addressHiLo & ((1 << numAddressBits) - 1)) << 1;
+			var opcode = (addressHiLo >> (numAddressBits + 0)) & 0b11;
+			var extOpcode = (addressHiLo >> (numAddressBits - 2)) & 0b11; // if opcode == 0, then extended
+			var start = ((addressHiLo >> (numAddressBits + 2)) & 0b1) == 0b1;
+
+			// only one bit may be set
+			var requestBitsSet = 0;
+			for (var i = 4; i < 8; i++) requestBitsSet += (statusCmd >> i) & 0b1;
+			if (requestBitsSet != 1) return;
+
+			switch ((statusCmd >> 4) & 0b1111)
+			{
+				/* Read request? */
+				case 0b0001:
+					PerformAccess(start, opcode, extOpcode, address);
+					ChangeBit(ref statusCmd, 0, true);
+					ChangeBit(ref statusCmd, 4, false);
+					break;
+
+				/* Write request? */
+				case 0b0010:
+					PerformAccess(start, opcode, extOpcode, address);
+					ChangeBit(ref statusCmd, 1, true);
+					ChangeBit(ref statusCmd, 5, false);
+					break;
+
+				/* Erase or misc request? */
+				case 0b0100:
+					PerformAccess(start, opcode, extOpcode, address);
+					ChangeBit(ref statusCmd, 2, true);
+					ChangeBit(ref statusCmd, 6, false);
+					break;
+
+				/* Reset request? */
+				case 0b1000:
+					Reset();
+					ChangeBit(ref statusCmd, 3, true);
+					ChangeBit(ref statusCmd, 7, false);
+					break;
+			}
+		}
+
+		private void PerformAccess(bool start, int opcode, int extOpcode, int address)
+		{
+			if (!start) return;
+
+			switch (opcode)
+			{
+				/* EWEN/ERAL/WRAL/EWDS */
+				case 0b00:
+					{
+						switch (extOpcode)
+						{
+							/* EWDS */
+							case 0b00:
+								eraseWriteEnable = false;
+								break;
+
+							/* WRAL */
+							case 0b01:
+								if (eraseWriteEnable)
+								{
+									for (var i = 0; i < contents.Length; i += 2)
+									{
+										contents[i + 0] = dataLo;
+										contents[i + 1] = dataHi;
+									}
+								}
+								break;
+
+							/* ERAL */
+							case 0b10:
+								if (eraseWriteEnable)
+								{
+									for (var i = 0; i < contents.Length; i++)
+										contents[i] = 0xFF;
+								}
+								break;
+
+							/* EWEN */
+							case 0b11:
+								eraseWriteEnable = true;
+								break;
+						}
+					}
+					break;
+
+				/* WRITE */
+				case 0b01:
+					if (eraseWriteEnable)
+					{
+						contents[address + 0] = dataLo;
+						contents[address + 1] = dataHi;
+					}
+					break;
+
+				/* READ */
+				case 0b10:
+					dataLo = contents[address + 0];
+					dataHi = contents[address + 1];
+					break;
+
+				/* ERASE */
+				case 0b11:
+					if (eraseWriteEnable)
+					{
+						dataLo = contents[address + 0];
+						contents[address + 0] = 0xFF;
+						dataHi = contents[address + 1];
+						contents[address + 1] = 0xFF;
+					}
+					break;
+			}
+		}
+
+		public byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x00: retVal = dataLo; break;
+				case 0x01: retVal = dataHi; break;
+				case 0x02: retVal = addressLo; break;
+				case 0x03: retVal = addressHi; break;
+				case 0x04: retVal = (byte)(statusCmd & 0b0011); break;
+			}
+
+			return retVal;
+		}
+
+		public void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x00: dataLo = value; break;
+				case 0x01: dataHi = value; break;
+				case 0x02: addressLo = value; break;
+				case 0x03: addressHi = value; break;
+				case 0x04:
+					statusCmd = (byte)((statusCmd & 0b00001111) | (value & 0b11110000));
+					BeginAccess();
+					break;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta
new file mode 100644
index 00000000..c1f09626
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 3ce5cac210519e94a88dff895ab51d1e
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta
new file mode 100644
index 00000000..55b04239
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ca27119fa51e6604d92b9801e45d5b41
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs
new file mode 100644
index 00000000..530b502e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs
@@ -0,0 +1,8 @@
+namespace StoicGoose.Core.Interfaces
+{
+	public interface IComponent
+	{
+		void Reset();
+		void Shutdown();
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta
new file mode 100644
index 00000000..d5ac1760
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: fbe5f8c7b7960364a905f23a70f22e2b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs
new file mode 100644
index 00000000..b371c270
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+using StoicGoose.Core.Cartridges;
+using StoicGoose.Core.CPU;
+using StoicGoose.Core.Display;
+using StoicGoose.Core.EEPROMs;
+using StoicGoose.Core.Sound;
+
+namespace StoicGoose.Core.Interfaces
+{
+
+	public interface IMachine
+	{
+        //static IEnumerable<Type> GetMachineTypes() => Assembly.GetAssembly(typeof(IMachine)).GetTypes().Where(x => !x.IsInterface && !x.IsAbstract && x.IsAssignableTo(typeof(IMachine)));
+        static IEnumerable<Type> GetMachineTypes()
+        {
+            return Assembly.GetAssembly(typeof(IMachine))
+                           .GetTypes()
+                           .Where(x => !x.IsInterface &&
+                                       !x.IsAbstract &&
+                                       typeof(IMachine).IsAssignableFrom(x));
+        }
+
+        string Manufacturer { get; }
+		string Model { get; }
+
+		int ScreenWidth { get; }
+		int ScreenHeight { get; }
+		double RefreshRate { get; }
+		string GameControls { get; }
+		string HardwareControls { get; }
+		string VerticalControlRemap { get; }
+
+		string InternalEepromDefaultUsername { get; }
+		Dictionary<ushort, byte> InternalEepromDefaultData { get; }
+
+		Cartridge Cartridge { get; }
+		V30MZ Cpu { get; }
+		DisplayControllerCommon DisplayController { get; }
+		SoundControllerCommon SoundController { get; }
+		EEPROM InternalEeprom { get; }
+
+        //Func<(List<string> buttonsPressed, List<string> buttonsHeld)> ReceiveInput { get; set; }
+		
+        Func<long> ReceiveInput { get; set; }
+
+        Func<uint, byte, byte> ReadMemoryCallback { get; set; }
+		Action<uint, byte> WriteMemoryCallback { get; set; }
+		Func<ushort, byte, byte> ReadPortCallback { get; set; }
+		Action<ushort, byte> WritePortCallback { get; set; }
+		Func<bool> RunStepCallback { get; set; }
+
+		void Initialize();
+		void Reset();
+		void Shutdown();
+
+		void RunFrame();
+		void RunLine();
+		void RunStep();
+
+		void LoadBootstrap(byte[] data);
+		bool IsBootstrapLoaded { get; }
+		bool UseBootstrap { get; set; }
+		void LoadInternalEeprom(byte[] data);
+		void LoadRom(byte[] data);
+		void LoadSaveData(byte[] data);
+
+		byte[] GetInternalEeprom();
+		byte[] GetSaveData();
+
+		byte ReadMemory(uint address);
+		void WriteMemory(uint address, byte value);
+		byte ReadPort(ushort port);
+		void WritePort(ushort port, byte value);
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta
new file mode 100644
index 00000000..7ec97bae
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f0af901bd4adf4f449a3ec347bcd46ae
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs
new file mode 100644
index 00000000..1297847c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs
@@ -0,0 +1,8 @@
+namespace StoicGoose.Core.Interfaces
+{
+	interface IMemoryAccessComponent : IComponent
+	{
+		byte ReadMemory(uint address);
+		void WriteMemory(uint address, byte value);
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta
new file mode 100644
index 00000000..3f123089
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 7bbbf381ccd119f4291d1e8671a4e9b2
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs
new file mode 100644
index 00000000..5c9f035d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs
@@ -0,0 +1,8 @@
+namespace StoicGoose.Core.Interfaces
+{
+	interface IPortAccessComponent : IComponent
+	{
+		byte ReadPort(ushort port);
+		void WritePort(ushort port, byte value);
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta
new file mode 100644
index 00000000..59088af0
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d81205bc9412fb24e9905b414e4b6b30
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta
new file mode 100644
index 00000000..b17c2d48
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 35bba939b8459124c8b129925c4cc47d
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs
new file mode 100644
index 00000000..1991f346
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs
@@ -0,0 +1,360 @@
+using System;
+using System.Collections.Generic;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Common.Utilities;
+using StoicGoose.Core.Cartridges;
+using StoicGoose.Core.CPU;
+using StoicGoose.Core.Display;
+using StoicGoose.Core.EEPROMs;
+using StoicGoose.Core.Interfaces;
+using StoicGoose.Core.Serial;
+using StoicGoose.Core.Sound;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Machines
+{
+	public abstract class MachineCommon : IMachine, IMemoryAccessComponent, IPortAccessComponent
+	{
+		// http://daifukkat.su/docs/wsman/
+
+		public abstract string Manufacturer { get; }
+		public abstract string Model { get; }
+
+		public int ScreenWidth => DisplayControllerCommon.ScreenWidth;
+		public int ScreenHeight => DisplayControllerCommon.ScreenHeight;
+		public double RefreshRate => DisplayControllerCommon.VerticalClock;
+		public string GameControls => "Start, B, A, X1, X2, X3, X4, Y1, Y2, Y3, Y4";
+		public string HardwareControls => "Volume";
+		public string VerticalControlRemap => "X1=Y2, X2=Y3, X3=Y4, X4=Y1, Y1=X2, Y2=X3, Y3=X4, Y4=X1";
+
+		public abstract string InternalEepromDefaultUsername { get; }
+		public abstract Dictionary<ushort, byte> InternalEepromDefaultData { get; }
+
+		public const double MasterClock = 12288000.0; /* 12.288 MHz xtal */
+		public const double CpuClock = MasterClock / 4.0; /* /4 = 3.072 MHz */
+
+		public abstract int InternalRamSize { get; }
+		public uint InternalRamMask { get; protected set; } = 0;
+		public byte[] InternalRam { get; protected set; } = default;
+
+		public Cartridge Cartridge { get; protected set; } = new();
+		public V30MZ Cpu { get; protected set; } = default;
+		public DisplayControllerCommon DisplayController { get; protected set; } = default;
+		public SoundControllerCommon SoundController { get; protected set; } = default;
+		public EEPROM InternalEeprom { get; protected set; } = default;
+		public Bootstrap BootstrapRom { get; protected set; } = default;
+		public SerialPort Serial { get; protected set; } = default;
+
+		public abstract int InternalEepromSize { get; }
+		public abstract int InternalEepromAddressBits { get; }
+
+		public abstract int BootstrapRomAddress { get; }
+		public abstract int BootstrapRomSize { get; }
+
+        //public Func<(List<string> buttonsPressed, List<string> buttonsHeld)> ReceiveInput { get; set; } = default;
+        public Func<long> ReceiveInput { get; set; } = default;
+
+        public Func<uint, byte, byte> ReadMemoryCallback { get; set; } = default;
+		public Action<uint, byte> WriteMemoryCallback { get; set; } = default;
+		public Func<ushort, byte, byte> ReadPortCallback { get; set; } = default;
+		public Action<ushort, byte> WritePortCallback { get; set; } = default;
+		public Func<bool> RunStepCallback { get; set; } = default;
+
+		protected bool cancelFrameExecution = false;
+
+		public int CurrentClockCyclesInLine { get; protected set; } = 0;
+		public int CurrentClockCyclesInFrame { get; protected set; } = 0;
+
+		public int TotalClockCyclesInFrame { get; protected set; } = 0;
+
+		/* REG_HW_FLAGS */
+		protected bool cartEnable, isWSCOrGreater, is16BitExtBus, cartRom1CycleSpeed, builtInSelfTestOk;
+		/* REG_KEYPAD */
+		protected bool keypadYEnable, keypadXEnable, keypadButtonEnable;
+		/* REG_INT_xxx */
+		protected byte interruptBase, interruptEnable, interruptStatus;
+
+		public bool IsBootstrapLoaded { get; private set; } = false;
+		public bool UseBootstrap { get; set; } = false;
+
+		public virtual void Initialize()
+		{
+			if (InternalRamSize == -1) throw new Exception("Internal RAM size not set");
+
+			InternalRamMask = (uint)(InternalRamSize - 1);
+			InternalRam = new byte[InternalRamSize];
+
+			Cpu = new(this);
+			InternalEeprom = new(InternalEepromSize, InternalEepromAddressBits);
+			BootstrapRom = new(BootstrapRomSize);
+			Serial = new();
+
+			InitializeEepromToDefaults();
+
+			Log.WriteEvent(LogSeverity.Information, this, "Machine initialized.");
+		}
+
+		public virtual void Reset()
+		{
+			for (var i = 0; i < InternalRam.Length; i++) InternalRam[i] = 0;
+
+			Cartridge?.Reset();
+			Cpu?.Reset();
+			DisplayController?.Reset();
+			SoundController?.Reset();
+			InternalEeprom?.Reset();
+			Serial?.Reset();
+
+			CurrentClockCyclesInFrame = 0;
+			CurrentClockCyclesInLine = 0;
+			TotalClockCyclesInFrame = (int)Math.Round(CpuClock / DisplayControllerCommon.VerticalClock);
+
+			ResetRegisters();
+
+			Log.WriteEvent(LogSeverity.Information, this, "Machine reset.");
+		}
+
+		public virtual void ResetRegisters()
+		{
+			cartEnable = !IsBootstrapLoaded || !UseBootstrap;
+			is16BitExtBus = true;
+			cartRom1CycleSpeed = false;
+			builtInSelfTestOk = true;
+
+			keypadYEnable = keypadXEnable = keypadButtonEnable = false;
+
+			interruptBase = interruptEnable = interruptStatus = 0;
+		}
+
+		public virtual void Shutdown()
+		{
+			Cartridge?.Shutdown();
+			Cpu?.Shutdown();
+			DisplayController?.Shutdown();
+			SoundController?.Shutdown();
+			InternalEeprom?.Shutdown();
+			Serial?.Shutdown();
+
+			Log.WriteEvent(LogSeverity.Information, this, "Machine shutdown.");
+		}
+
+		protected virtual void InitializeEepromToDefaults()
+		{
+			var data = ConvertUsernameForEeprom(InternalEepromDefaultUsername);
+			for (var i = 0; i < data.Length; i++) InternalEeprom.Program(0x60 + i, data[i]); // Username (0x60-0x6F, max 16 characters)
+			foreach (var (address, value) in InternalEepromDefaultData) InternalEeprom.Program(address, value);
+		}
+
+		private static byte[] ConvertUsernameForEeprom(string name)
+		{
+			var data = new byte[16];
+			for (var i = 0; i < data.Length; i++)
+			{
+				var c = i < name.Length ? name[i] : ' ';
+				if (c == ' ') data[i] = (byte)(c - ' ' + 0x00);
+				else if (c >= '0' && c <= '9') data[i] = (byte)(c - '0' + 0x01);
+				else if (c >= 'A' && c <= 'Z') data[i] = (byte)(c - 'A' + 0x0B);
+				else if (c >= 'a' && c <= 'b') data[i] = (byte)(c - 'A' + 0x0B);
+				else if (c == '♥') data[i] = (byte)(c - '♥' + 0x25);
+				else if (c == '♪') data[i] = (byte)(c - '♪' + 0x26);
+				else if (c == '+') data[i] = (byte)(c - '+' + 0x27);
+				else if (c == '-') data[i] = (byte)(c - '-' + 0x28);
+				else if (c == '?') data[i] = (byte)(c - '?' + 0x29);
+				else if (c == '.') data[i] = (byte)(c - '.' + 0x2A);
+				else data[i] = 0x00;
+			}
+			return data;
+		}
+
+		public void RunFrame()
+		{
+			while (CurrentClockCyclesInFrame < TotalClockCyclesInFrame)
+			{
+				RunLine();
+
+				if (cancelFrameExecution) return;
+			}
+
+			CurrentClockCyclesInFrame -= TotalClockCyclesInFrame;
+
+			_ = ReceiveInput?.Invoke();
+		}
+
+		public void RunLine()
+		{
+			while (CurrentClockCyclesInLine < DisplayControllerCommon.HorizontalTotal)
+			{
+				RunStep();
+
+				if (cancelFrameExecution) return;
+			}
+
+			CurrentClockCyclesInFrame += CurrentClockCyclesInLine;
+			CurrentClockCyclesInLine = 0;
+		}
+
+		public abstract void RunStep();
+
+		protected void RaiseInterrupt(int number)
+		{
+			if (!IsBitSet(interruptEnable, number)) return;
+			ChangeBit(ref interruptStatus, number, true);
+		}
+
+		protected void LowerInterrupt(int number)
+		{
+			ChangeBit(ref interruptStatus, number, false);
+		}
+
+		protected void HandleInterrupts()
+		{
+			if (!Cpu.IsFlagSet(V30MZ.Flags.InterruptEnable)) return;
+
+			for (var i = 7; i >= 0; i--)
+			{
+				if (!IsBitSet(interruptStatus, i)) continue;
+
+				Cpu.IsHalted = false;
+				Cpu.Interrupt((interruptBase & 0b11111000) | i);
+				return;
+			}
+		}
+
+		public void LoadBootstrap(byte[] data)
+		{
+			BootstrapRom.LoadRom(data);
+
+			IsBootstrapLoaded = true;
+		}
+
+		public void LoadInternalEeprom(byte[] data)
+		{
+			InternalEeprom.LoadContents(data);
+		}
+
+		public void LoadRom(byte[] data)
+		{
+			Cartridge.LoadRom(data);
+		}
+
+		public void LoadSaveData(byte[] data)
+		{
+			if (Cartridge.Metadata.IsSramSave)
+				Cartridge.LoadSram(data);
+			else if (Cartridge.Metadata.IsEepromSave)
+				Cartridge.LoadEeprom(data);
+		}
+
+		public byte[] GetInternalEeprom()
+		{
+			return InternalEeprom.GetContents();
+		}
+
+		public byte[] GetSaveData()
+		{
+			if (Cartridge.Metadata != null)
+			{
+				if (Cartridge.Metadata.IsSramSave)
+					return Cartridge.GetSram();
+				else if (Cartridge.Metadata.IsEepromSave)
+					return Cartridge.GetEeprom();
+			}
+
+			return Array.Empty<byte>();
+		}
+
+		public byte ReadMemory(uint address)
+		{
+			byte retVal;
+
+			if (!cartEnable && BootstrapRom != null && address >= BootstrapRomAddress)
+			{
+				/* Bootstrap enabled */
+				retVal = BootstrapRom.ReadMemory(address);
+			}
+			else
+			{
+				address &= 0xFFFFF;
+
+				if ((address & 0xF0000) == 0x00000)
+				{
+					/* Internal RAM -- returns 0x90 if unmapped */
+					if (address < InternalRamSize)
+						retVal = InternalRam[address & InternalRamMask];
+					else
+						retVal = 0x90;
+				}
+				else
+				{
+					/* Cartridge */
+					retVal = Cartridge.ReadMemory(address);
+				}
+			}
+
+			if (ReadMemoryCallback != null)
+				retVal = ReadMemoryCallback.Invoke(address, retVal);
+
+			return retVal;
+		}
+
+		public void WriteMemory(uint address, byte value)
+		{
+			WriteMemoryCallback?.Invoke(address, value);
+
+			address &= 0xFFFFF;
+			if ((address & 0xF0000) == 0x00000)
+			{
+				/* Internal RAM -- no effect if unmapped */
+				if (address < InternalRamSize)
+					InternalRam[address & InternalRamMask] = value;
+			}
+			else if ((address & 0xF0000) == 0x10000)
+			{
+				/* Cartridge -- SRAM only, other writes not emitted */
+				Cartridge.WriteMemory(address, value);
+			}
+		}
+
+		public abstract byte ReadPort(ushort port);
+		public abstract void WritePort(ushort port, byte value);
+
+		[Port("REG_HW_FLAGS", 0x0A0)]
+		[BitDescription("BIOS lockout; is cartridge mapped?", 0)]
+		public bool CartEnable => cartEnable;
+		[Port("REG_HW_FLAGS", 0x0A0)]
+		[BitDescription("System type; is WSC or greater?", 1)]
+		public bool IsWSCOrGreater => isWSCOrGreater;
+		[Port("REG_HW_FLAGS", 0x0A0)]
+		[BitDescription("External bus width; is 16-bit bus?", 2)]
+		public bool Is16BitExtBus => is16BitExtBus;
+		[Port("REG_HW_FLAGS", 0x0A0)]
+		[BitDescription("Cartridge ROM speed; is 1-cycle?", 3)]
+		public bool CartRom1CycleSpeed => cartRom1CycleSpeed;
+		[Port("REG_HW_FLAGS", 0x0A0)]
+		[BitDescription("Built-in self test passed", 7)]
+		public bool BuiltInSelfTestOk => builtInSelfTestOk;
+
+		[Port("REG_KEYPAD", 0x0B5)]
+		[BitDescription("Y keys check enabled", 4)]
+		public bool KeypadYEnable => keypadYEnable;
+		[Port("REG_KEYPAD", 0x0B5)]
+		[BitDescription("X keys check enabled", 5)]
+		public bool KeypadXEnable => keypadXEnable;
+		[Port("REG_KEYPAD", 0x0B5)]
+		[BitDescription("Button check enabled", 6)]
+		public bool KeypadButtonEnable => keypadButtonEnable;
+
+		[Port("REG_INT_BASE", 0x0B0)]
+		public abstract byte InterruptBase { get; }
+		[Port("REG_INT_ENABLE", 0x0B2)]
+		[BitDescription("Interrupt enable bitmask", 4)]
+		[Format("X2")]
+		public byte InterruptEnable => interruptEnable;
+		[Port("REG_INT_STATUS", 0x0B4)]
+		[BitDescription("Interrupt status bitmask", 4)]
+		[Format("X2")]
+		public byte InterruptStatus => interruptStatus;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta
new file mode 100644
index 00000000..7195c435
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 961184224ac597c4281ef0e43aa48d68
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs
new file mode 100644
index 00000000..ebc82ddd
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs
@@ -0,0 +1,334 @@
+using System.Collections.Generic;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Display;
+using StoicGoose.Core.Serial;
+using StoicGoose.Core.Sound;
+using StoicGooseUnity;
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Machines
+{
+	public partial class WonderSwan : MachineCommon
+	{
+		public override string Manufacturer => "Bandai";
+		public override string Model => "WonderSwan";
+
+		public override string InternalEepromDefaultUsername => "WONDERSWAN";
+		public override Dictionary<ushort, byte> InternalEepromDefaultData => new()
+		{
+			{ 0x70, 0x19 }, // Year of birth [just for fun, here set to original WS release date; new systems probably had no date set?]
+			{ 0x71, 0x99 }, // ""
+			{ 0x72, 0x03 }, // Month of birth [again, WS release for fun]
+			{ 0x73, 0x04 }, // Day of birth [and again]
+			{ 0x74, 0x00 }, // Sex [set to ?]
+			{ 0x75, 0x00 }, // Blood type [set to ?]
+
+			{ 0x76, 0x00 }, // Last game played, publisher ID [set to presumably none]
+			{ 0x77, 0x00 }, // ""
+			{ 0x78, 0x00 }, // Last game played, game ID [set to presumably none]
+			{ 0x79, 0x00 }, // ""
+			{ 0x7A, 0x00 }, // Swan ID (see Mama Mitte) -- TODO: set to valid/random value?
+			{ 0x7B, 0x00 }, // ""
+			{ 0x7C, 0x00 }, // Number of different games played [set to presumably none]
+			{ 0x7D, 0x00 }, // Number of times settings were changed [set to presumably none]
+			{ 0x7E, 0x00 }, // Number of times powered on [set to presumably none]
+			{ 0x7F, 0x00 }  // ""
+		};
+
+		public override int InternalRamSize => 16 * 1024;
+
+		public override int InternalEepromSize => 64 * 2;
+		public override int InternalEepromAddressBits => 6;
+
+		public override int BootstrapRomAddress => 0xFF000;
+		public override int BootstrapRomSize => 0x1000;
+
+		public override void Initialize()
+		{
+			DisplayController = new AswanDisplayController(this);
+			SoundController = new AswanSoundController(this, 44100, 2);
+
+			base.Initialize();
+		}
+
+		public override void ResetRegisters()
+		{
+			isWSCOrGreater = false;
+
+			base.ResetRegisters();
+		}
+
+		public override void RunStep()
+		{
+			if (RunStepCallback == null || RunStepCallback.Invoke() == false)
+			{
+				HandleInterrupts();
+
+				var currentCpuClockCycles = Cpu.Step();
+
+				var displayInterrupt = DisplayController.Step(currentCpuClockCycles);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.LineCompare)) RaiseInterrupt(4);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlankTimer)) RaiseInterrupt(5);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlank)) RaiseInterrupt(6);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.HBlankTimer)) RaiseInterrupt(7);
+
+				SoundController.Step(currentCpuClockCycles);
+
+				if (Cartridge.Step(currentCpuClockCycles)) RaiseInterrupt(2);
+				else LowerInterrupt(2);
+
+				var serialInterrupt = Serial.Step();
+				if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialSend)) RaiseInterrupt(0);
+				if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialRecieve)) RaiseInterrupt(3);
+
+				CurrentClockCyclesInLine += currentCpuClockCycles;
+
+				cancelFrameExecution = false;
+			}
+			else
+				cancelFrameExecution = true;
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				/* Display controller, etc. (H/V timers, DISP_MODE) */
+				case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB):
+					retVal = DisplayController.ReadPort(port);
+					break;
+
+				/* Sound controller */
+				case var n when n >= 0x80 && n < 0xA0:
+					retVal = SoundController.ReadPort(port);
+					break;
+
+				/* Serial port */
+				case var n when n == 0xB1 || n == 0xB3:
+					retVal = Serial.ReadPort(port);
+					break;
+
+				/* System controller */
+				case 0xA0:
+					/* REG_HW_FLAGS */
+					ChangeBit(ref retVal, 0, cartEnable);
+					ChangeBit(ref retVal, 1, false);
+					ChangeBit(ref retVal, 2, is16BitExtBus);
+					ChangeBit(ref retVal, 3, cartRom1CycleSpeed);
+					ChangeBit(ref retVal, 7, builtInSelfTestOk);
+					break;
+
+				case 0xB0:
+					/* REG_INT_BASE */
+					retVal = interruptBase;
+					retVal |= 0b11;
+					break;
+
+				case 0xB2:
+					/* REG_INT_ENABLE */
+					retVal = interruptEnable;
+					break;
+
+				case 0xB4:
+					/* REG_INT_STATUS */
+					retVal = interruptStatus;
+					break;
+
+				case 0xB5:
+					/* REG_KEYPAD */
+					ChangeBit(ref retVal, 4, keypadYEnable);
+					ChangeBit(ref retVal, 5, keypadXEnable);
+					ChangeBit(ref retVal, 6, keypadButtonEnable);
+
+                    /* Get input from UI */
+                    var buttonsHeld = ReceiveInput?.Invoke();
+                    if (buttonsHeld != null)
+                    {
+                        if (buttonsHeld > 0)
+                            RaiseInterrupt(1);
+
+                        if (keypadYEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y1) > 0) ChangeBit(ref retVal, 0, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y2) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y3) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y4) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+
+                        if (keypadXEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X1) > 0) ChangeBit(ref retVal, 0, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X2) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X3) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X4) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+
+                        if (keypadButtonEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Start) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.A) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.B) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+                    }
+                    //var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld;
+                    //if (buttonsHeld != null)
+                    //{
+                    //	if (buttonsHeld.Count > 0)
+                    //		RaiseInterrupt(1);
+
+                    //	if (keypadYEnable)
+                    //	{
+
+
+                    //                       if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true);
+                    //		if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true);
+                    //	}
+
+                    //	if (keypadXEnable)
+                    //	{
+                    //		if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true);
+                    //		if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true);
+                    //	}
+
+                    //	if (keypadButtonEnable)
+                    //	{
+                    //		if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true);
+                    //	}
+                    //}
+                    break;
+
+				case 0xB6:
+					/* REG_INT_ACK */
+					retVal = 0x00;
+					break;
+
+				case 0xB7:
+					/* ??? */
+					retVal = 0x00;
+					break;
+
+				case 0xBA:
+				case 0xBB:
+				case 0xBC:
+				case 0xBD:
+				case 0xBE:
+					/* REG_IEEP_DATA (low) */
+					/* REG_IEEP_DATA (high) */
+					/* REG_IEEP_ADDR (low) */
+					/* REG_IEEP_ADDR (high) */
+					/* REG_IEEP_CMD (write) */
+					retVal = InternalEeprom.ReadPort((ushort)(port - 0xBA));
+					break;
+
+				/* Cartridge */
+				case var n when n >= 0xC0 && n < 0x100:
+					retVal = Cartridge.ReadPort(port);
+					break;
+
+				/* Unmapped */
+				default:
+					retVal = 0x90;
+					break;
+			}
+
+			if (ReadPortCallback != null)
+				retVal = ReadPortCallback.Invoke(port, retVal);
+
+			return retVal;
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			WritePortCallback?.Invoke(port, value);
+
+			switch (port)
+			{
+				/* Display controller, etc. (H/V timers, DISP_MODE) */
+				case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB):
+					DisplayController.WritePort(port, value);
+					break;
+
+				/* Sound controller */
+				case var n when n >= 0x80 && n < 0xA0:
+					SoundController.WritePort(port, value);
+					break;
+
+				/* Serial port */
+				case var n when n == 0xB1 || n == 0xB3:
+					Serial.WritePort(port, value);
+					break;
+
+				/* System controller */
+				case 0xA0:
+					/* REG_HW_FLAGS */
+					if (!cartEnable)
+						cartEnable = IsBitSet(value, 0);
+					is16BitExtBus = IsBitSet(value, 2);
+					cartRom1CycleSpeed = IsBitSet(value, 3);
+					break;
+
+				case 0xB0:
+					/* REG_INT_BASE */
+					interruptBase = (byte)(value & 0b11111000);
+					break;
+
+				case 0xB2:
+					/* REG_INT_ENABLE */
+					interruptEnable = value;
+					break;
+
+				case 0xB4:
+					/* REG_INT_STATUS -- read-only */
+					break;
+
+				case 0xB5:
+					/* REG_KEYPAD */
+					keypadYEnable = IsBitSet(value, 4);
+					keypadXEnable = IsBitSet(value, 5);
+					keypadButtonEnable = IsBitSet(value, 6);
+					break;
+
+				case 0xB6:
+					/* REG_INT_ACK */
+					interruptStatus &= (byte)~(value & (0b11110010 | ~interruptEnable));
+					break;
+
+				case 0xB7:
+					/* ??? */
+					break;
+
+				case 0xBA:
+				case 0xBB:
+				case 0xBC:
+				case 0xBD:
+				case 0xBE:
+					/* REG_IEEP_DATA (low) */
+					/* REG_IEEP_DATA (high) */
+					/* REG_IEEP_ADDR (low) */
+					/* REG_IEEP_ADDR (high) */
+					/* REG_IEEP_STATUS (read) */
+					InternalEeprom.WritePort((ushort)(port - 0xBA), value);
+					break;
+
+				/* Cartridge */
+				case var n when n >= 0xC0 && n < 0x100:
+					Cartridge.WritePort(port, value);
+					break;
+			}
+		}
+
+		[Port("REG_INT_BASE", 0x0B0)]
+		[BitDescription("Interrupt base address", 3, 7)]
+		[Format("X4", 0)]
+		public override byte InterruptBase => interruptBase;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta
new file mode 100644
index 00000000..c6d1d16b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f3e696cb652b87242b1d85bfbc978b7b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs
new file mode 100644
index 00000000..9e4dc8c9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs
@@ -0,0 +1,396 @@
+using System.Collections.Generic;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Display;
+using StoicGoose.Core.DMA;
+using StoicGoose.Core.Serial;
+using StoicGoose.Core.Sound;
+using StoicGooseUnity;
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Machines
+{
+	public partial class WonderSwanColor : MachineCommon
+	{
+		public override string Manufacturer => "Bandai";
+		public override string Model => "WonderSwan Color";
+
+		public override string InternalEepromDefaultUsername => "WONDERSWANCOLOR";
+		public override Dictionary<ushort, byte> InternalEepromDefaultData => new()
+		{
+			{ 0x70, 0x20 }, // Year of birth [set to WSC release date for fun]
+			{ 0x71, 0x00 }, // ""
+			{ 0x72, 0x12 }, // Month of birth [again]
+			{ 0x73, 0x09 }, // Day of birth [again]
+			{ 0x74, 0x00 }, // Sex [?]
+			{ 0x75, 0x00 }, // Blood type [?]
+
+			{ 0x76, 0x00 }, // Last game played, publisher ID [none]
+			{ 0x77, 0x00 }, // ""
+			{ 0x78, 0x00 }, // Last game played, game ID [none]
+			{ 0x79, 0x00 }, // ""
+			{ 0x7A, 0x00 }, // Swan ID (see Mama Mitte) -- TODO: set to valid/random value?
+			{ 0x7B, 0x00 }, // ""
+			{ 0x7C, 0x00 }, // Number of different games played [none]
+			{ 0x7D, 0x00 }, // Number of times settings were changed [none]
+			{ 0x7E, 0x00 }, // Number of times powered on [none]
+			{ 0x7F, 0x00 }  // ""
+		};
+
+		public override int InternalRamSize => 64 * 1024;
+
+		public override int InternalEepromSize => 1024 * 2;
+		public override int InternalEepromAddressBits => 10;
+
+		public override int BootstrapRomAddress => 0xFE000;
+		public override int BootstrapRomSize => 0x2000;
+
+		public SphinxGeneralDMAController DmaController { get; protected set; } = default;
+		public SphinxSoundDMAController SoundDmaController { get; protected set; } = default;
+
+		public override void Initialize()
+		{
+			DisplayController = new SphinxDisplayController(this);
+			SoundController = new SphinxSoundController(this, 44100, 2);
+			DmaController = new SphinxGeneralDMAController(this);
+			SoundDmaController = new SphinxSoundDMAController(this);
+
+			base.Initialize();
+		}
+
+		public override void Reset()
+		{
+			DmaController.Reset();
+
+			base.Reset();
+		}
+
+		public override void ResetRegisters()
+		{
+			isWSCOrGreater = true;
+
+			base.ResetRegisters();
+		}
+
+		public override void Shutdown()
+		{
+			DmaController.Shutdown();
+
+			base.Shutdown();
+		}
+
+		protected override void InitializeEepromToDefaults()
+		{
+			base.InitializeEepromToDefaults();
+
+			InternalEeprom.Program(0x83, (byte)(0b0 << 6 | SoundController.MaxMasterVolume & 0b11)); // Flags (low contrast, max volume)
+		}
+
+		public override void RunStep()
+		{
+			if (RunStepCallback == null || RunStepCallback.Invoke() == false)
+			{
+				HandleInterrupts();
+
+				var currentCpuClockCycles = DmaController.IsActive ? DmaController.Step() : Cpu.Step();
+
+				var displayInterrupt = DisplayController.Step(currentCpuClockCycles);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.LineCompare)) RaiseInterrupt(4);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlankTimer)) RaiseInterrupt(5);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlank)) RaiseInterrupt(6);
+				if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.HBlankTimer)) RaiseInterrupt(7);
+
+				if (SoundDmaController.IsActive)
+					SoundDmaController.Step(currentCpuClockCycles);
+
+				SoundController.Step(currentCpuClockCycles);
+
+				if (Cartridge.Step(currentCpuClockCycles)) RaiseInterrupt(2);
+				else LowerInterrupt(2);
+
+				var serialInterrupt = Serial.Step();
+				if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialSend)) RaiseInterrupt(0);
+				if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialRecieve)) RaiseInterrupt(3);
+
+				CurrentClockCyclesInLine += currentCpuClockCycles;
+
+				cancelFrameExecution = false;
+			}
+			else
+				cancelFrameExecution = true;
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				/* Display controller, etc. (H/V timers, DISP_MODE) */
+				case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB):
+					retVal = DisplayController.ReadPort(port);
+					break;
+
+				/* DMA controller */
+				case var n when n >= 0x40 && n < 0x4A:
+					retVal = DmaController.ReadPort(port);
+					break;
+
+				/* Sound DMA controller */
+				case var n when n >= 0x4A && n < 0x53:
+					retVal = SoundDmaController.ReadPort(port);
+					break;
+
+				/* Sound controller */
+				case var n when (n >= 0x80 && n < 0xA0) || (n >= 0x6A && n <= 0x6B):
+					retVal = SoundController.ReadPort(port);
+					break;
+
+				/* Serial port */
+				case var n when n == 0xB1 || n == 0xB3:
+					retVal = Serial.ReadPort(port);
+					break;
+
+				/* Misc system registers */
+				case 0x62:
+					/* REG_WSC_SYSTEM */
+					ChangeBit(ref retVal, 7, false); // not SwanCrystal
+					break;
+
+				/* System controller */
+				case 0xA0:
+					/* REG_HW_FLAGS */
+					ChangeBit(ref retVal, 0, cartEnable);
+					ChangeBit(ref retVal, 1, true);
+					ChangeBit(ref retVal, 2, is16BitExtBus);
+					ChangeBit(ref retVal, 3, cartRom1CycleSpeed);
+					ChangeBit(ref retVal, 7, builtInSelfTestOk);
+					break;
+
+				case 0xB0:
+					/* REG_INT_BASE */
+					retVal = interruptBase;
+					break;
+
+				case 0xB2:
+					/* REG_INT_ENABLE */
+					retVal = interruptEnable;
+					break;
+
+				case 0xB4:
+					/* REG_INT_STATUS */
+					retVal = interruptStatus;
+					break;
+
+				case 0xB5:
+					/* REG_KEYPAD */
+					ChangeBit(ref retVal, 4, keypadYEnable);
+					ChangeBit(ref retVal, 5, keypadXEnable);
+					ChangeBit(ref retVal, 6, keypadButtonEnable);
+
+					/* Get input from UI */
+					var buttonsHeld = ReceiveInput?.Invoke();
+                    if (buttonsHeld != null)
+                    {
+                        if (buttonsHeld > 0)
+                            RaiseInterrupt(1);
+
+                        if (keypadYEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y1) > 0) ChangeBit(ref retVal, 0, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y2) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y3) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Y4) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+
+                        if (keypadXEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X1) > 0) ChangeBit(ref retVal, 0, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X2) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X3) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.X4) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+
+                        if (keypadButtonEnable)
+                        {
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.Start) > 0) ChangeBit(ref retVal, 1, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.A) > 0) ChangeBit(ref retVal, 2, true);
+                            if ((buttonsHeld.Value & (ushort)StoicGooseKey.B) > 0) ChangeBit(ref retVal, 3, true);
+                        }
+                    }
+                    //var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld;
+                    //if (buttonsHeld != null)
+                    //{
+                    //	if (buttonsHeld.Count > 0)
+                    //		RaiseInterrupt(1);
+
+                    //	if (keypadYEnable)
+                    //	{
+                    //		if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true);
+                    //		if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true);
+                    //	}
+
+                    //	if (keypadXEnable)
+                    //	{
+                    //		if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true);
+                    //		if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true);
+                    //	}
+
+                    //	if (keypadButtonEnable)
+                    //	{
+                    //		if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true);
+                    //		if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true);
+                    //		if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true);
+                    //	}
+                    //}
+                    break;
+
+				case 0xB6:
+					/* REG_INT_ACK */
+					retVal = 0x00;
+					break;
+
+				case 0xB7:
+					/* ??? */
+					retVal = 0x00;
+					break;
+
+				case 0xBA:
+				case 0xBB:
+				case 0xBC:
+				case 0xBD:
+				case 0xBE:
+					/* REG_IEEP_DATA (low) */
+					/* REG_IEEP_DATA (high) */
+					/* REG_IEEP_ADDR (low) */
+					/* REG_IEEP_ADDR (high) */
+					/* REG_IEEP_CMD (write) */
+					retVal = InternalEeprom.ReadPort((ushort)(port - 0xBA));
+					break;
+
+				/* Cartridge */
+				case var n when n >= 0xC0 && n < 0x100:
+					retVal = Cartridge.ReadPort(port);
+					break;
+
+				/* Unmapped */
+				default:
+					retVal = 0x90;
+					break;
+			}
+
+			if (ReadPortCallback != null)
+				retVal = ReadPortCallback.Invoke(port, retVal);
+
+			return retVal;
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			WritePortCallback?.Invoke(port, value);
+
+			switch (port)
+			{
+				/* Display controller, etc. (H/V timers, DISP_MODE) */
+				case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB):
+					DisplayController.WritePort(port, value);
+					break;
+
+				/* DMA controller */
+				case var n when n >= 0x40 && n < 0x4A:
+					DmaController.WritePort(port, value);
+					break;
+
+				/* Sound DMA controller */
+				case var n when n >= 0x4A && n < 0x53:
+					SoundDmaController.WritePort(port, value);
+					break;
+
+				/* Sound controller */
+				case var n when (n >= 0x80 && n < 0xA0) || (n >= 0x6A && n <= 0x6B):
+					SoundController.WritePort(port, value);
+					break;
+
+				/* Serial port */
+				case var n when n == 0xB1 || n == 0xB3:
+					Serial.WritePort(port, value);
+					break;
+
+				/* Misc system registers */
+				case 0x62:
+					/* REG_WSC_SYSTEM */
+					if (IsBitSet(value, 0))
+					{
+						// TODO: power-off bit, stop emulation?
+					}
+					break;
+
+				/* System controller */
+				case 0xA0:
+					/* REG_HW_FLAGS */
+					if (!cartEnable)
+						cartEnable = IsBitSet(value, 0);
+					is16BitExtBus = IsBitSet(value, 2);
+					cartRom1CycleSpeed = IsBitSet(value, 3);
+					break;
+
+				case 0xB0:
+					/* REG_INT_BASE */
+					interruptBase = (byte)(value & 0b11111110);
+					break;
+
+				case 0xB2:
+					/* REG_INT_ENABLE */
+					interruptEnable = value;
+					break;
+
+				case 0xB4:
+					/* REG_INT_STATUS -- read-only */
+					break;
+
+				case 0xB5:
+					/* REG_KEYPAD */
+					keypadYEnable = IsBitSet(value, 4);
+					keypadXEnable = IsBitSet(value, 5);
+					keypadButtonEnable = IsBitSet(value, 6);
+					break;
+
+				case 0xB6:
+					/* REG_INT_ACK */
+					interruptStatus &= (byte)~(value & (0b11110010 | ~interruptEnable));
+					break;
+
+				case 0xB7:
+					/* ??? */
+					break;
+
+				case 0xBA:
+				case 0xBB:
+				case 0xBC:
+				case 0xBD:
+				case 0xBE:
+					/* REG_IEEP_DATA (low) */
+					/* REG_IEEP_DATA (high) */
+					/* REG_IEEP_ADDR (low) */
+					/* REG_IEEP_ADDR (high) */
+					/* REG_IEEP_STATUS (read) */
+					InternalEeprom.WritePort((ushort)(port - 0xBA), value);
+					break;
+
+				/* Cartridge */
+				case var n when n >= 0xC0 && n < 0x100:
+					Cartridge.WritePort(port, value);
+					break;
+			}
+		}
+
+		[Port("REG_INT_BASE", 0x0B0)]
+		[BitDescription("Interrupt base address", 1, 7)]
+		[Format("X4", 0)]
+		public override byte InterruptBase => interruptBase;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta
new file mode 100644
index 00000000..6c103aa3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 8054a1a1d865d2e4ea3fa676c4de78dd
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta
new file mode 100644
index 00000000..77e284ad
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2fcb17a464660ae4fbecae852698c8ab
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs
new file mode 100644
index 00000000..054093bf
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs
@@ -0,0 +1,130 @@
+using System;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Serial
+{
+	public class SerialPort : IPortAccessComponent
+	{
+		// https://github.com/ares-emulator/ares/tree/709afef820914e3399425bb77cbc1baf895028a1/ares/ws/serial
+
+		[Flags]
+		public enum SerialInterrupts
+		{
+			None = 0,
+			SerialSend = 1 << 0,
+			SerialRecieve = 1 << 1
+		}
+
+		int baudClock, txBitClock;
+
+		/* REG_SER_DATA */
+		protected byte serialData;
+		/* REG_SER_STATUS */
+		protected bool enable, baudRateSelect, txEmpty, rxOverrun, rxFull;
+
+		public void Reset()
+		{
+			serialData = 0;
+			enable = baudRateSelect = rxOverrun = rxFull = false;
+		}
+
+		public void Shutdown()
+		{
+			/* Nothing to do... */
+		}
+
+		public SerialInterrupts Step()
+		{
+			if (!enable) return SerialInterrupts.None;
+
+			if (!baudRateSelect && ++baudClock < 4) return SerialInterrupts.None;
+			baudClock = 0;
+
+			// STUB
+			if (!txEmpty)
+			{
+				if (++txBitClock == 9)
+				{
+					txBitClock = 0;
+					txEmpty = true;
+				}
+			}
+
+			var interrupt = SerialInterrupts.None;
+			if (txEmpty) interrupt |= SerialInterrupts.SerialSend;
+			if (rxFull) interrupt |= SerialInterrupts.SerialRecieve;
+			return interrupt;
+		}
+
+		public virtual byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0xB1:
+					/* REG_SER_DATA */
+					retVal = serialData;
+					rxFull = false;
+					break;
+
+				case 0xB3:
+					/* REG_SER_STATUS */
+					ChangeBit(ref retVal, 7, enable);
+					ChangeBit(ref retVal, 6, baudRateSelect);
+					ChangeBit(ref retVal, 2, txEmpty);
+					ChangeBit(ref retVal, 1, rxOverrun);
+					ChangeBit(ref retVal, 0, rxFull);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public virtual void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0xB1:
+					/* REG_SER_DATA */
+					if (txEmpty)
+					{
+						serialData = value;
+						txEmpty = false;
+					}
+					break;
+
+				case 0xB3:
+					/* REG_SER_STATUS */
+					enable = IsBitSet(value, 7);
+					baudRateSelect = IsBitSet(value, 6);
+					rxOverrun = !IsBitSet(value, 5);
+					break;
+			}
+		}
+
+		[Port("REG_SER_DATA", 0x0B1)]
+		[BitDescription("Serial data")]
+		[Format("X2")]
+		public byte SerialData => serialData;
+		[Port("REG_SER_STATUS", 0x0B3)]
+		[BitDescription("Serial enabled?", 7)]
+		public bool Enable => enable;
+		[Port("REG_SER_STATUS", 0x0B3)]
+		[BitDescription("Baud rate; is 38400 baud?", 6)]
+		public bool BaudRateSelect => baudRateSelect;
+		[Port("REG_SER_STATUS", 0x0B3)]
+		[BitDescription("TX empty?", 2)]
+		public bool TxEmpty => txEmpty;
+		[Port("REG_SER_STATUS", 0x0B3)]
+		[BitDescription("RX overrun?", 1)]
+		public bool RxOverrun => rxOverrun;
+		[Port("REG_SER_STATUS", 0x0B3)]
+		[BitDescription("RX full?", 0)]
+		public bool RxFull => rxFull;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta
new file mode 100644
index 00000000..a993eb35
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c946ee9cecab7f343b5e8896d2d98d7a
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta
new file mode 100644
index 00000000..e081fa81
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f7258409b0150f847b07fd6219501ad8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs
new file mode 100644
index 00000000..42cdf168
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs
@@ -0,0 +1,126 @@
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+
+namespace StoicGoose.Core.Sound
+{
+	public class AswanSoundController : SoundControllerCommon
+	{
+		public override byte MaxMasterVolume => 2;
+		public override int NumChannels => 4;
+
+		/* REG_SND_9697 */
+		protected ushort unknown9697;
+		/* REG_SND_9899 */
+		protected ushort unknown9899;
+
+		public AswanSoundController(IMachine machine, int rate, int outChannels) : base(machine, rate, outChannels) { }
+
+		public override void ResetRegisters()
+		{
+			base.ResetRegisters();
+
+			unknown9697 = 0;
+			unknown9899 = 0;
+		}
+
+		public override int[] GenerateSample()
+		{
+			channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputRight & 0x07FF) << 5 : 0));
+
+			var mixedLeft = 0;
+			if (channel1.IsEnabled) mixedLeft += channel1.OutputLeft;
+			if (channel2.IsEnabled) mixedLeft += channel2.OutputLeft;
+			if (channel3.IsEnabled) mixedLeft += channel3.OutputLeft;
+			if (channel4.IsEnabled) mixedLeft += channel4.OutputLeft;
+			mixedLeft = (mixedLeft & 0x07FF) << 5;
+
+			var mixedRight = 0;
+			if (channel1.IsEnabled) mixedRight += channel1.OutputRight;
+			if (channel2.IsEnabled) mixedRight += channel2.OutputRight;
+			if (channel3.IsEnabled) mixedRight += channel3.OutputRight;
+			if (channel4.IsEnabled) mixedRight += channel4.OutputRight;
+			mixedRight = (mixedRight & 0x07FF) << 5;
+
+			return new[] { mixedLeft, mixedRight };
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			return port switch
+			{
+				/* REG_SND_9697 (low) */
+				0x96 => (byte)((unknown9697 >> 0) & 0b11111111),
+				/* REG_SND_9697 (high) */
+				0x97 => (byte)((unknown9697 >> 8) & 0b00000011),
+				/* REG_SND_9899 (low) */
+				0x98 => (byte)((unknown9899 >> 0) & 0b11111111),
+				/* REG_SND_9899 (high) */
+				0x99 => (byte)((unknown9899 >> 8) & 0b00000011),
+				/* REG_SND_9A */
+				0x9A => 0b111,
+				/* REG_SND_9B */
+				0x9B => 0b11111110,
+				/* REG_SND_9C */
+				0x9C => 0b11111111,
+				/* REG_SND_9D */
+				0x9D => 0b11111111,
+				/* Fall through to common */
+				_ => base.ReadPort(port)
+			};
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x96:
+					/* REG_SND_9697 (low) */
+					unknown9697 = (ushort)((unknown9697 & 0x0300) | (value << 0));
+					break;
+
+				case 0x97:
+					/* REG_SND_9697 (high) */
+					unknown9697 = (ushort)((unknown9697 & 0x00FF) | (value << 8));
+					break;
+
+				case 0x98:
+					/* REG_SND_9899 (low) */
+					unknown9899 = (ushort)((unknown9899 & 0x0300) | (value << 0));
+					break;
+
+				case 0x99:
+					/* REG_SND_9899 (high) */
+					unknown9899 = (ushort)((unknown9899 & 0x00FF) | (value << 8));
+					break;
+
+				case 0x9A:
+				case 0x9B:
+				case 0x9C:
+				case 0x9D:
+					/* REG_SND_9x */
+					break;
+
+				default:
+					/* Fall through to common */
+					base.WritePort(port, value);
+					break;
+			}
+		}
+
+		[Port("REG_SND_9697", 0x096, 0x097)]
+		[BitDescription("Unknown data", 0, 9)]
+		[Format("X4")]
+		public ushort Unknown9697 => unknown9697;
+		[Port("REG_SND_9899", 0x098, 0x099)]
+		[BitDescription("Unknown data", 0, 9)]
+		[Format("X4")]
+		public ushort Unknown9899 => unknown9899;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta
new file mode 100644
index 00000000..60fbf46b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 28765af694138b54d82c34169449c831
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs
new file mode 100644
index 00000000..c6209252
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs
@@ -0,0 +1,55 @@
+namespace StoicGoose.Core.Sound
+{
+	/* Channel 1, no additional features */
+	public sealed class SoundChannel1
+	{
+		const int counterReload = 2048;
+
+		ushort counter;
+		byte pointer;
+
+		public byte OutputLeft { get; set; }
+		public byte OutputRight { get; set; }
+
+		readonly WaveTableReadDelegate waveTableReadDelegate;
+
+		/* REG_SND_CH1_PITCH */
+		public ushort Pitch { get; set; }
+		/* REG_SND_CH1_VOL */
+		public byte VolumeLeft { get; set; }
+		public byte VolumeRight { get; set; }
+		/* REG_SND_CTRL */
+		public bool IsEnabled { get; set; }
+
+		public SoundChannel1(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
+
+		public void Reset()
+		{
+			counter = counterReload;
+			pointer = 0;
+			OutputLeft = OutputRight = 0;
+
+			Pitch = 0;
+			VolumeLeft = VolumeRight = 0;
+			IsEnabled = false;
+		}
+
+		public void Step()
+		{
+			counter--;
+			if (counter == Pitch)
+			{
+				var data = waveTableReadDelegate((ushort)(pointer >> 1));
+				if ((pointer & 0b1) == 0b1) data >>= 4;
+				data &= 0x0F;
+
+				OutputLeft = (byte)(data * VolumeLeft);
+				OutputRight = (byte)(data * VolumeRight);
+
+				pointer++;
+				pointer &= 0b11111;
+				counter = counterReload;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta
new file mode 100644
index 00000000..accfd797
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 72cd30fc769465c4e8a91b33b4baf47d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs
new file mode 100644
index 00000000..b2d9f97c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs
@@ -0,0 +1,75 @@
+namespace StoicGoose.Core.Sound
+{
+	/* Channel 2, supports PCM voice */
+	public sealed class SoundChannel2
+	{
+		const int counterReload = 2048;
+
+		ushort counter;
+		byte pointer;
+
+		public byte OutputLeft { get; set; }
+		public byte OutputRight { get; set; }
+
+		readonly WaveTableReadDelegate waveTableReadDelegate;
+
+		/* REG_SND_CH2_PITCH */
+		public ushort Pitch { get; set; }
+		/* REG_SND_CH2_VOL */
+		public byte VolumeLeft { get; set; }
+		public byte VolumeRight { get; set; }
+		/* REG_SND_CTRL */
+		public bool IsEnabled { get; set; }
+		public bool IsVoiceEnabled { get; set; }
+
+		/* REG_SND_VOICE_CTRL */
+		public bool PcmRightFull { get; set; }
+		public bool PcmRightHalf { get; set; }
+		public bool PcmLeftFull { get; set; }
+		public bool PcmLeftHalf { get; set; }
+
+		public SoundChannel2(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
+
+		public void Reset()
+		{
+			counter = counterReload;
+			pointer = 0;
+			OutputLeft = OutputRight = 0;
+
+			Pitch = 0;
+			VolumeLeft = VolumeRight = 0;
+			IsEnabled = false;
+
+			IsVoiceEnabled = false;
+
+			PcmRightFull = PcmRightHalf = PcmLeftFull = PcmLeftHalf = false;
+		}
+
+		public void Step()
+		{
+			if (IsVoiceEnabled)
+			{
+				var pcm = (ushort)(VolumeLeft << 4 | VolumeRight);
+				OutputLeft = (byte)(PcmLeftFull ? pcm : (PcmLeftHalf ? pcm >> 1 : 0));
+				OutputRight = (byte)(PcmRightFull ? pcm : (PcmRightHalf ? pcm >> 1 : 0));
+			}
+			else
+			{
+				counter--;
+				if (counter == Pitch)
+				{
+					var data = waveTableReadDelegate((ushort)(pointer >> 1));
+					if ((pointer & 0b1) == 0b1) data >>= 4;
+					data &= 0x0F;
+
+					OutputLeft = (byte)(data * VolumeLeft);
+					OutputRight = (byte)(data * VolumeRight);
+
+					pointer++;
+					pointer &= 0b11111;
+					counter = counterReload;
+				}
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta
new file mode 100644
index 00000000..82a1d818
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 4082002c536d05c4f97e428bfdfbb686
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs
new file mode 100644
index 00000000..5c6b88aa
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs
@@ -0,0 +1,88 @@
+namespace StoicGoose.Core.Sound
+{
+	/* Channel 3, has optional sweep */
+	public sealed class SoundChannel3
+	{
+		const int counterReload = 2048;
+		const int sweepReload = 32 * 256;
+
+		ushort counter;
+		byte pointer;
+
+		public byte OutputLeft { get; set; }
+		public byte OutputRight { get; set; }
+
+		int sweepCounter;
+		int sweepCycles;
+
+		readonly WaveTableReadDelegate waveTableReadDelegate;
+
+		/* REG_SND_CH3_PITCH */
+		public ushort Pitch { get; set; }
+		/* REG_SND_CH3_VOL */
+		public byte VolumeLeft { get; set; }
+		public byte VolumeRight { get; set; }
+		/* REG_SND_CTRL */
+		public bool IsEnabled { get; set; }
+		public bool IsSweepEnabled { get; set; }
+
+		/* REG_SND_SWEEP_VALUE */
+		public sbyte SweepValue { get; set; }
+		/* REG_SND_SWEEP_TIME */
+		public byte SweepTime { get; set; }
+
+		public SoundChannel3(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
+
+		public void Reset()
+		{
+			counter = counterReload;
+			pointer = 0;
+			OutputLeft = OutputRight = 0;
+
+			Pitch = 0;
+			VolumeLeft = VolumeRight = 0;
+			IsEnabled = false;
+
+			IsSweepEnabled = false;
+
+			sweepCounter = 0;
+			sweepCycles = sweepReload;
+
+			SweepValue = 0;
+			SweepTime = 0;
+		}
+
+		public void Step()
+		{
+			if (IsSweepEnabled)
+			{
+				sweepCycles--;
+				if (sweepCycles == 0)
+				{
+					sweepCounter--;
+					if (sweepCounter <= 0)
+					{
+						sweepCounter = SweepTime;
+						Pitch = (ushort)(Pitch + SweepValue);
+					}
+				}
+				sweepCycles = sweepReload;
+			}
+
+			counter--;
+			if (counter == Pitch)
+			{
+				var data = waveTableReadDelegate((ushort)(pointer >> 1));
+				if ((pointer & 0b1) == 0b1) data >>= 4;
+				data &= 0x0F;
+
+				OutputLeft = (byte)(data * VolumeLeft);
+				OutputRight = (byte)(data * VolumeRight);
+
+				pointer++;
+				pointer &= 0b11111;
+				counter = counterReload;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta
new file mode 100644
index 00000000..4ba8af64
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 2885470480fbb3846b82cc3aec9dc315
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs
new file mode 100644
index 00000000..755ebbd2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs
@@ -0,0 +1,88 @@
+namespace StoicGoose.Core.Sound
+{
+	/* Channel 4, supports noise */
+	public sealed class SoundChannel4
+	{
+		const int counterReload = 2048;
+
+		readonly static byte[] noiseLfsrTaps = { 14, 10, 13, 4, 8, 6, 9, 11 };
+
+		ushort counter;
+		byte pointer;
+
+		public byte OutputLeft { get; set; }
+		public byte OutputRight { get; set; }
+
+		readonly WaveTableReadDelegate waveTableReadDelegate;
+
+		/* REG_SND_CH4_PITCH */
+		public ushort Pitch { get; set; }
+		/* REG_SND_CH4_VOL */
+		public byte VolumeLeft { get; set; }
+		public byte VolumeRight { get; set; }
+		/* REG_SND_CTRL */
+		public bool IsEnabled { get; set; }
+		public bool IsNoiseEnabled { get; set; }
+
+		/* REG_SND_NOISE */
+		public byte NoiseMode { get; set; }
+		public bool NoiseReset { get; set; }
+		public bool NoiseEnable { get; set; }
+		/* REG_SND_RANDOM */
+		public ushort NoiseLfsr { get; set; }
+
+		public SoundChannel4(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
+
+		public void Reset()
+		{
+			counter = counterReload;
+			pointer = 0;
+			OutputLeft = OutputRight = 0;
+
+			Pitch = 0;
+			VolumeLeft = VolumeRight = 0;
+			IsEnabled = false;
+
+			IsNoiseEnabled = false;
+
+			NoiseMode = 0;
+			NoiseReset = NoiseEnable = false;
+			NoiseLfsr = 0;
+		}
+
+		public void Step()
+		{
+			counter--;
+			if (counter == Pitch)
+			{
+				if (NoiseEnable)
+				{
+					var tap = noiseLfsrTaps[NoiseMode];
+					var noise = (1 ^ (NoiseLfsr >> 7) ^ (NoiseLfsr >> tap)) & 0b1;
+					NoiseLfsr = (ushort)(((NoiseLfsr << 1) | noise) & 0x7FFF);
+				}
+
+				var data = IsNoiseEnabled ? ((NoiseLfsr & 0b1) * 0x0F) : waveTableReadDelegate((ushort)(pointer >> 1));
+				if (!IsNoiseEnabled)
+				{
+					if ((pointer & 0b1) == 0b1) data >>= 4;
+					data &= 0x0F;
+				}
+
+				OutputLeft = (byte)(data * VolumeLeft);
+				OutputRight = (byte)(data * VolumeRight);
+
+				if (NoiseReset)
+				{
+					NoiseLfsr = 0;
+					OutputLeft = OutputRight = 0;
+					NoiseReset = false;
+				}
+
+				pointer++;
+				pointer &= 0b11111;
+				counter = counterReload;
+			}
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta
new file mode 100644
index 00000000..fb9f58cc
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b6fec75dc93d8b646a1294310530ae97
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs
new file mode 100644
index 00000000..b27cae5b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs
@@ -0,0 +1,55 @@
+namespace StoicGoose.Core.Sound
+{
+	/* HyperVoice channel */
+	public sealed class SoundChannelHyperVoice
+	{
+		public byte OutputLeft { get; set; }
+		public byte OutputRight { get; set; }
+
+		/* REG_HYPER_CTRL */
+		public bool IsEnabled { get; set; }
+		public int ScalingMode { get; set; }
+		public int Volume { get; set; }
+		public byte CtrlUnknown { get; set; }
+
+		/* REG_HYPER_CHAN_CTRL */
+		public bool RightEnable { get; set; }
+		public bool LeftEnable { get; set; }
+		public byte ChanCtrlUnknown { get; set; }
+
+		/* REG_SND_HYPERVOICE */
+		public byte Data { get; set; }
+
+		public SoundChannelHyperVoice() { }
+
+		public void Reset()
+		{
+			OutputLeft = OutputRight = 0;
+
+			IsEnabled = false;
+			ScalingMode = Volume = 0;
+			CtrlUnknown = 0;
+
+			RightEnable = LeftEnable = false;
+			ChanCtrlUnknown = 0;
+
+			Data = 0;
+		}
+
+		public void Step()
+		{
+			var output = (byte)0;
+
+			switch (ScalingMode)
+			{
+				case 0: output = (byte)(Data << 3 - Volume); break;
+				case 1: output = (byte)((Data << 3 - Volume) | (-0x100 << 3 - Volume)); break;
+				case 2: output = (byte)(Data << 3 - Volume); break;    // ???
+				case 3: output = (byte)(Data << 3); break;
+			}
+
+			OutputLeft = LeftEnable ? output : (byte)0;
+			OutputRight = RightEnable ? output : (byte)0;
+		}
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta
new file mode 100644
index 00000000..b93bb622
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b15fb27a01956c340b331a6969e590f9
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs
new file mode 100644
index 00000000..70c30572
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs
@@ -0,0 +1,487 @@
+using System;
+using System.Collections.Generic;
+
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+using StoicGoose.Core.Machines;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Sound
+{
+	public delegate byte WaveTableReadDelegate(ushort address);
+
+	public abstract partial class SoundControllerCommon : IPortAccessComponent
+	{
+		/* http://daifukkat.su/docs/wsman/#hw_sound */
+
+		public abstract byte MaxMasterVolume { get; }
+		public abstract int NumChannels { get; }
+
+		readonly int sampleRate, numOutputChannels;
+
+		protected readonly SoundChannel1 channel1 = default;
+		protected readonly SoundChannel2 channel2 = default;
+		protected readonly SoundChannel3 channel3 = default;
+		protected readonly SoundChannel4 channel4 = default;
+
+		protected readonly List<short>[] channelSampleBuffers = default;
+		protected readonly List<short> mixedSampleBuffer = new();
+
+		public short[][] LastEnqueuedChannelSamples { get; private set; } = default;
+		public short[] LastEnqueuedMixedSamples { get; private set; } = Array.Empty<short>();
+
+		public Action<short[]> SendSamples { get; set; } = default;
+
+		readonly double clockRate, refreshRate;
+		readonly int samplesPerFrame, cyclesPerFrame, cyclesPerSample;
+		int cycleCount;
+
+		protected readonly IMachine machine = default;
+
+		/* REG_SND_WAVE_BASE */
+		protected byte waveTableBase;
+		/* REG_SND_OUTPUT */
+		protected bool speakerEnable, headphoneEnable, headphonesConnected;
+		protected byte speakerVolumeShift;
+		/* REG_SND_VOLUME */
+		protected byte masterVolume;
+
+		public SoundControllerCommon(IMachine machine, int rate, int outChannels)
+		{
+			this.machine = machine;
+
+			sampleRate = rate;
+			numOutputChannels = outChannels;
+
+			channel1 = new SoundChannel1((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (0 << 4) + a)));
+			channel2 = new SoundChannel2((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (1 << 4) + a)));
+			channel3 = new SoundChannel3((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (2 << 4) + a)));
+			channel4 = new SoundChannel4((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (3 << 4) + a)));
+
+			channelSampleBuffers = new List<short>[NumChannels];
+			for (var i = 0; i < channelSampleBuffers.Length; i++) channelSampleBuffers[i] = new();
+
+			LastEnqueuedChannelSamples = new short[NumChannels][];
+
+			clockRate = MachineCommon.CpuClock;
+			refreshRate = Display.DisplayControllerCommon.VerticalClock;
+
+			samplesPerFrame = (int)(sampleRate / refreshRate);
+			cyclesPerFrame = (int)(clockRate / refreshRate);
+			cyclesPerSample = cyclesPerFrame / samplesPerFrame;
+		}
+
+		public virtual void Reset()
+		{
+			cycleCount = 0;
+
+			channel1.Reset();
+			channel2.Reset();
+			channel3.Reset();
+			channel4.Reset();
+
+			FlushSamples();
+
+			ResetRegisters();
+		}
+
+		public virtual void ResetRegisters()
+		{
+			waveTableBase = 0;
+			speakerEnable = headphoneEnable = false;
+			headphonesConnected = true; /* NOTE: always set for stereo sound */
+			speakerVolumeShift = 0;
+			masterVolume = MaxMasterVolume;
+		}
+
+		public void Shutdown()
+		{
+			/* Nothing to do */
+		}
+
+		public void ChangeMasterVolume()
+		{
+			var newMasterVolume = MasterVolume - 1;
+			if (newMasterVolume < 0) newMasterVolume = MaxMasterVolume;
+			else if (newMasterVolume > MaxMasterVolume) newMasterVolume = 0;
+
+			masterVolume = (byte)newMasterVolume;
+		}
+
+		public void Step(int clockCyclesInStep)
+		{
+			cycleCount += clockCyclesInStep;
+
+			for (int i = 0; i < clockCyclesInStep; i++)
+				StepChannels();
+
+			if (cycleCount >= cyclesPerSample)
+			{
+				ProcessSample(GenerateSample());
+				cycleCount -= cyclesPerSample;
+			}
+
+			if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels))
+			{
+				var sampleArray = mixedSampleBuffer.ToArray();
+
+				LastEnqueuedMixedSamples = sampleArray;
+				for (var i = 0; i < NumChannels; i++) LastEnqueuedChannelSamples[i] = channelSampleBuffers[i].ToArray();
+
+				SendSamples?.Invoke(sampleArray.Clone() as short[]);
+
+				FlushSamples();
+			}
+		}
+
+		public virtual void StepChannels()
+		{
+			channel1.Step();
+			channel2.Step();
+			channel3.Step();
+			channel4.Step();
+		}
+
+		public abstract int[] GenerateSample();
+
+		public virtual void ProcessSample(int[] lrSamples)
+		{
+			if (headphonesConnected && !headphoneEnable && !speakerEnable)
+				/* Headphones connected but neither headphones nor speaker enabled? Don't output sound */
+				lrSamples[0] = lrSamples[1] = 0;
+			else if (!headphonesConnected)
+				/* Otherwise, no headphones connected? Mix down to mono, perform volume shift */
+				lrSamples[0] = lrSamples[1] = ((lrSamples[0] + lrSamples[1]) / 2) >> speakerVolumeShift;
+
+			mixedSampleBuffer.Add((short)(lrSamples[0] * (masterVolume / (double)MaxMasterVolume))); /* Left */
+			mixedSampleBuffer.Add((short)(lrSamples[1] * (masterVolume / (double)MaxMasterVolume))); /* Right */
+		}
+
+		public void FlushSamples()
+		{
+			foreach (var buffer in channelSampleBuffers)
+				buffer.Clear();
+
+			mixedSampleBuffer.Clear();
+		}
+
+		public virtual byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x80:
+				case 0x81:
+					/* REG_SND_CH1_PITCH */
+					retVal |= (byte)(channel1.Pitch >> ((port & 0b1) * 8));
+					break;
+				case 0x82:
+				case 0x83:
+					/* REG_SND_CH2_PITCH */
+					retVal |= (byte)(channel2.Pitch >> ((port & 0b1) * 8));
+					break;
+				case 0x84:
+				case 0x85:
+					/* REG_SND_CH3_PITCH */
+					retVal |= (byte)(channel3.Pitch >> ((port & 0b1) * 8));
+					break;
+				case 0x86:
+				case 0x87:
+					/* REG_SND_CH4_PITCH */
+					retVal |= (byte)(channel4.Pitch >> ((port & 0b1) * 8));
+					break;
+
+				case 0x88:
+					/* REG_SND_CH1_VOL */
+					retVal |= (byte)(channel1.VolumeLeft << 4 | channel1.VolumeRight);
+					break;
+				case 0x89:
+					/* REG_SND_CH2_VOL */
+					retVal |= (byte)(channel2.VolumeLeft << 4 | channel2.VolumeRight);
+					break;
+				case 0x8A:
+					/* REG_SND_CH3_VOL */
+					retVal |= (byte)(channel3.VolumeLeft << 4 | channel3.VolumeRight);
+					break;
+				case 0x8B:
+					/* REG_SND_CH4_VOL */
+					retVal |= (byte)(channel4.VolumeLeft << 4 | channel4.VolumeRight);
+					break;
+
+				case 0x8C:
+					/* REG_SND_SWEEP_VALUE */
+					retVal |= (byte)channel3.SweepValue;
+					break;
+
+				case 0x8D:
+					/* REG_SND_SWEEP_TIME */
+					retVal |= (byte)(channel3.SweepTime & 0b11111);
+					break;
+
+				case 0x8E:
+					/* REG_SND_NOISE */
+					retVal |= (byte)(channel4.NoiseMode & 0b111);
+					/* Noise reset (bit 3) always reads 0 */
+					ChangeBit(ref retVal, 4, channel4.NoiseEnable);
+					break;
+
+				case 0x8F:
+					/* REG_SND_WAVE_BASE */
+					retVal |= waveTableBase;
+					break;
+
+				case 0x90:
+					/* REG_SND_CTRL */
+					ChangeBit(ref retVal, 0, channel1.IsEnabled);
+					ChangeBit(ref retVal, 1, channel2.IsEnabled);
+					ChangeBit(ref retVal, 2, channel3.IsEnabled);
+					ChangeBit(ref retVal, 3, channel4.IsEnabled);
+					ChangeBit(ref retVal, 5, channel2.IsVoiceEnabled);
+					ChangeBit(ref retVal, 6, channel3.IsSweepEnabled);
+					ChangeBit(ref retVal, 7, channel4.IsNoiseEnabled);
+					break;
+
+				case 0x91:
+					/* REG_SND_OUTPUT */
+					ChangeBit(ref retVal, 0, speakerEnable);
+					ChangeBit(ref retVal, 3, headphoneEnable);
+					ChangeBit(ref retVal, 7, headphonesConnected);
+					retVal |= (byte)((speakerVolumeShift & 0b11) << 1);
+					break;
+
+				case 0x92:
+				case 0x93:
+					/* REG_SND_RANDOM */
+					retVal |= (byte)((channel4.NoiseLfsr >> ((port & 0b1) * 8)) & 0xFF);
+					break;
+
+				case 0x94:
+					/* REG_SND_VOICE_CTRL */
+					ChangeBit(ref retVal, 0, channel2.PcmRightFull);
+					ChangeBit(ref retVal, 1, channel2.PcmRightHalf);
+					ChangeBit(ref retVal, 2, channel2.PcmLeftFull);
+					ChangeBit(ref retVal, 3, channel2.PcmLeftHalf);
+					break;
+
+				case 0x9E:
+					/* REG_SND_VOLUME */
+					retVal |= (byte)(masterVolume & 0b11);
+					break;
+
+				default:
+					throw new NotImplementedException($"Unimplemented sound register read {port:X2}");
+			}
+
+			return retVal;
+		}
+
+		public virtual void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x80:
+				case 0x81:
+					/* REG_SND_CH1_PITCH */
+					channel1.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF);
+					channel1.Pitch |= (ushort)(value << ((port & 0b1) * 8));
+					break;
+				case 0x82:
+				case 0x83:
+					/* REG_SND_CH2_PITCH */
+					channel2.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF);
+					channel2.Pitch |= (ushort)(value << ((port & 0b1) * 8));
+					break;
+				case 0x84:
+				case 0x85:
+					/* REG_SND_CH3_PITCH */
+					channel3.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF);
+					channel3.Pitch |= (ushort)(value << ((port & 0b1) * 8));
+					break;
+				case 0x86:
+				case 0x87:
+					/* REG_SND_CH4_PITCH */
+					channel4.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF);
+					channel4.Pitch |= (ushort)(value << ((port & 0b1) * 8));
+					break;
+
+				case 0x88:
+					/* REG_SND_CH1_VOL */
+					channel1.VolumeLeft = (byte)((value >> 4) & 0b1111);
+					channel1.VolumeRight = (byte)((value >> 0) & 0b1111);
+					break;
+				case 0x89:
+					/* REG_SND_CH2_VOL */
+					channel2.VolumeLeft = (byte)((value >> 4) & 0b1111);
+					channel2.VolumeRight = (byte)((value >> 0) & 0b1111);
+					break;
+				case 0x8A:
+					/* REG_SND_CH3_VOL */
+					channel3.VolumeLeft = (byte)((value >> 4) & 0b1111);
+					channel3.VolumeRight = (byte)((value >> 0) & 0b1111);
+					break;
+				case 0x8B:
+					/* REG_SND_CH4_VOL */
+					channel4.VolumeLeft = (byte)((value >> 4) & 0b1111);
+					channel4.VolumeRight = (byte)((value >> 0) & 0b1111);
+					break;
+
+				case 0x8C:
+					/* REG_SND_SWEEP_VALUE */
+					channel3.SweepValue = (sbyte)value;
+					break;
+
+				case 0x8D:
+					/* REG_SND_SWEEP_TIME */
+					channel3.SweepTime = (byte)(value & 0b11111);
+					break;
+
+				case 0x8E:
+					/* REG_SND_NOISE */
+					channel4.NoiseMode = (byte)(value & 0b111);
+					channel4.NoiseReset = IsBitSet(value, 3);
+					channel4.NoiseEnable = IsBitSet(value, 4);
+					break;
+
+				case 0x8F:
+					/* REG_SND_WAVE_BASE */
+					waveTableBase = value;
+					break;
+
+				case 0x90:
+					/* REG_SND_CTRL */
+					channel1.IsEnabled = IsBitSet(value, 0);
+					channel2.IsEnabled = IsBitSet(value, 1);
+					channel3.IsEnabled = IsBitSet(value, 2);
+					channel4.IsEnabled = IsBitSet(value, 3);
+					channel2.IsVoiceEnabled = IsBitSet(value, 5);
+					channel3.IsSweepEnabled = IsBitSet(value, 6);
+					channel4.IsNoiseEnabled = IsBitSet(value, 7);
+					break;
+
+				case 0x91:
+					/* REG_SND_OUTPUT */
+					speakerEnable = IsBitSet(value, 0);
+					speakerVolumeShift = (byte)((value >> 1) & 0b11);
+					headphoneEnable = IsBitSet(value, 3);
+					/* Headphones connected (bit 7) is read-only */
+					break;
+
+				case 0x92:
+				case 0x93:
+					/* REG_SND_RANDOM */
+					break;
+
+				case 0x94:
+					/* REG_SND_VOICE_CTRL */
+					channel2.PcmRightFull = IsBitSet(value, 0);
+					channel2.PcmRightHalf = IsBitSet(value, 1);
+					channel2.PcmLeftFull = IsBitSet(value, 2);
+					channel2.PcmLeftHalf = IsBitSet(value, 3);
+					break;
+
+				case 0x9E:
+					/* REG_SND_VOLUME */
+					masterVolume = (byte)(value & 0b11);
+					break;
+
+				default:
+					throw new NotImplementedException($"Unimplemented sound register write {port:X2}");
+			}
+		}
+
+		[Port("REG_SND_CH1_PITCH", 0x080, 0x081)]
+		[BitDescription("Channel 1 pitch (frequency reload)", 0, 10)]
+		public ushort Channel1Pitch => channel1.Pitch;
+		[Port("REG_SND_CH2_PITCH", 0x082, 0x083)]
+		[BitDescription("Channel 2 pitch (frequency reload)", 0, 10)]
+		public ushort Channel2Pitch => channel2.Pitch;
+		[Port("REG_SND_CH3_PITCH", 0x084, 0x085)]
+		[BitDescription("Channel 3 pitch (frequency reload)", 0, 10)]
+		public ushort Channel3Pitch => channel3.Pitch;
+		[Port("REG_SND_CH4_PITCH", 0x086, 0x087)]
+		[BitDescription("Channel 4 pitch (frequency reload)", 0, 10)]
+		public ushort Channel4Pitch => channel4.Pitch;
+		[Port("REG_SND_CH1_VOL", 0x088)]
+		[BitDescription("Channel 1 volume right", 0, 3)]
+		public byte Channel1VolumeRight => channel1.VolumeRight;
+		[Port("REG_SND_CH1_VOL", 0x088)]
+		[BitDescription("Channel 1 volume left", 4, 7)]
+		public byte Channel1VolumeLeft => channel1.VolumeLeft;
+		[Port("REG_SND_CH2_VOL", 0x089)]
+		[BitDescription("Channel 2 volume right", 0, 3)]
+		public byte Channel2VolumeRight => channel2.VolumeRight;
+		[Port("REG_SND_CH2_VOL", 0x089)]
+		[BitDescription("Channel 2 volume left", 4, 7)]
+		public byte Channel2VolumeLeft => channel2.VolumeLeft;
+		[Port("REG_SND_CH3_VOL", 0x08A)]
+		[BitDescription("Channel 3 volume right", 0, 3)]
+		public byte Channel3VolumeRight => channel3.VolumeRight;
+		[Port("REG_SND_CH3_VOL", 0x08A)]
+		[BitDescription("Channel 3 volume left", 4, 7)]
+		public byte Channel3VolumeLeft => channel3.VolumeLeft;
+		[Port("REG_SND_CH4_VOL", 0x08B)]
+		[BitDescription("Channel 4 volume right", 0, 3)]
+		public byte Channel4VolumeRight => channel4.VolumeRight;
+		[Port("REG_SND_CH4_VOL", 0x08B)]
+		[BitDescription("Channel 4 volume left", 4, 7)]
+		public byte Channel4VolumeLeft => channel4.VolumeLeft;
+		[Port("REG_SND_SWEEP_VALUE", 0x08C)]
+		[BitDescription("Channel 3 sweep value")]
+		public sbyte Channel3SweepValue => channel3.SweepValue;
+		[Port("REG_SND_SWEEP_TIME", 0x08D)]
+		[BitDescription("Channel 3 sweep time", 0, 4)]
+		public byte Channel3SweepTime => channel3.SweepTime;
+		[Port("REG_SND_NOISE", 0x08E)]
+		[BitDescription("Channel 4 noise mode", 0, 2)]
+		public byte Channel4NoiseMode => channel4.NoiseMode;
+		[Port("REG_SND_NOISE", 0x08E)]
+		[BitDescription("Is channel 4 noise enabled?", 4)]
+		public bool Channel4NoiseEnable => channel4.NoiseEnable;
+		[Port("REG_SND_WAVE_BASE", 0x08F)]
+		[BitDescription("Wavetable base address")]
+		[Format("X4", 6)]
+		public byte WaveTableBase => waveTableBase;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 1 enabled?", 0)]
+		public bool Channel1IsEnabled => channel1.IsEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 2 enabled?", 1)]
+		public bool Channel2IsEnabled => channel2.IsEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 3 enabled?", 2)]
+		public bool Channel3IsEnabled => channel3.IsEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 4 enabled?", 3)]
+		public bool Channel4IsEnabled => channel4.IsEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 2 in voice mode?", 5)]
+		public bool Channel2IsVoiceEnabled => channel2.IsVoiceEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 3 in sweep mode?", 6)]
+		public bool Channel3IsSweepEnabled => channel3.IsSweepEnabled;
+		[Port("REG_SND_CTRL", 0x090)]
+		[BitDescription("Is channel 4 in noise mode?", 7)]
+		public bool Channel4IsNoiseEnabled => channel4.IsNoiseEnabled;
+		[Port("REG_SND_OUTPUT", 0x091)]
+		[BitDescription("Is speaker enabled?", 0)]
+		public bool SpeakerEnable => speakerEnable;
+		[Port("REG_SND_OUTPUT", 0x091)]
+		[BitDescription("Speaker PWM volume bitshift", 1, 2)]
+		public byte SpeakerVolumeShift => speakerVolumeShift;
+		[Port("REG_SND_OUTPUT", 0x091)]
+		[BitDescription("Are headphones enabled?", 3)]
+		public bool HeadphoneEnable => headphoneEnable;
+		[Port("REG_SND_OUTPUT", 0x091)]
+		[BitDescription("Are headphones connected?", 7)]
+		public bool HeadphonesConnected => headphonesConnected;
+		[Port("REG_SND_RANDOM", 0x092, 0x093)]
+		[BitDescription("Current noise LFSR value", 0, 14)]
+		[Format("X4")]
+		public ushort Channel4NoiseLfsr => channel4.NoiseLfsr;
+		[Port("REG_SND_VOLUME", 0x09E)]
+		[BitDescription("Master volume level", 0, 1)]
+		public byte MasterVolume => masterVolume;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta
new file mode 100644
index 00000000..935f95ac
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 58b2556218f34ae4eaca2861c63517cd
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs
new file mode 100644
index 00000000..4922a423
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs
@@ -0,0 +1,182 @@
+using StoicGoose.Common.Attributes;
+using StoicGoose.Core.Interfaces;
+
+using static StoicGoose.Common.Utilities.BitHandling;
+
+namespace StoicGoose.Core.Sound
+{
+	public class SphinxSoundController : SoundControllerCommon
+	{
+		public override byte MaxMasterVolume => 3;
+		public override int NumChannels => 5;
+
+		readonly SoundChannelHyperVoice channelHyperVoice = default;
+
+		public SphinxSoundController(IMachine machine, int rate, int outChannels) : base(machine, rate, outChannels)
+		{
+			channelHyperVoice = new();
+		}
+
+		public override void Reset()
+		{
+			base.Reset();
+
+			channelHyperVoice.Reset();
+		}
+
+		public override void StepChannels()
+		{
+			base.StepChannels();
+
+			channelHyperVoice.Step();
+		}
+
+		public override int[] GenerateSample()
+		{
+			channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputRight & 0x07FF) << 5 : 0));
+			channelSampleBuffers[4].Add((short)(channelHyperVoice.IsEnabled ? (channelHyperVoice.OutputLeft & 0x07FF) << 5 : 0));
+			channelSampleBuffers[4].Add((short)(channelHyperVoice.IsEnabled ? (channelHyperVoice.OutputRight & 0x07FF) << 5 : 0));
+
+			var mixedLeft = 0;
+			if (channel1.IsEnabled) mixedLeft += channel1.OutputLeft;
+			if (channel2.IsEnabled) mixedLeft += channel2.OutputLeft;
+			if (channel3.IsEnabled) mixedLeft += channel3.OutputLeft;
+			if (channel4.IsEnabled) mixedLeft += channel4.OutputLeft;
+			if (channelHyperVoice.IsEnabled && headphonesConnected) mixedLeft += channelHyperVoice.OutputLeft;
+			mixedLeft = (mixedLeft & 0x07FF) << 5;
+
+			var mixedRight = 0;
+			if (channel1.IsEnabled) mixedRight += channel1.OutputRight;
+			if (channel2.IsEnabled) mixedRight += channel2.OutputRight;
+			if (channel3.IsEnabled) mixedRight += channel3.OutputRight;
+			if (channel4.IsEnabled) mixedRight += channel4.OutputRight;
+			if (channelHyperVoice.IsEnabled && headphonesConnected) mixedRight += channelHyperVoice.OutputRight;
+			mixedRight = (mixedRight & 0x07FF) << 5;
+
+			return new[] { mixedLeft, mixedRight };
+		}
+
+		public override byte ReadPort(ushort port)
+		{
+			var retVal = (byte)0;
+
+			switch (port)
+			{
+				case 0x6A:
+					/* REG_HYPER_CTRL */
+					ChangeBit(ref retVal, 7, channelHyperVoice.IsEnabled);
+					retVal |= (byte)((channelHyperVoice.CtrlUnknown << 4) & 0b111);
+					retVal |= (byte)((channelHyperVoice.ScalingMode << 2) & 0b11);
+					retVal |= (byte)((channelHyperVoice.Volume << 0) & 0b11);
+					break;
+
+				case 0x6B:
+					/* REG_HYPER_CHAN_CTRL */
+					ChangeBit(ref retVal, 6, channelHyperVoice.RightEnable);
+					ChangeBit(ref retVal, 5, channelHyperVoice.LeftEnable);
+					retVal |= (byte)((channelHyperVoice.ChanCtrlUnknown << 0) & 0b1111);
+					break;
+
+				case 0x95:
+					/* REG_SND_HYPERVOICE */
+					retVal |= channelHyperVoice.Data;
+					break;
+
+				case 0x96:
+				case 0x97:
+				case 0x98:
+				case 0x99:
+				case 0x9A:
+				case 0x9B:
+				case 0x9C:
+				case 0x9D:
+					/* REG_SND_9x */
+					retVal = 0;
+					break;
+
+				default:
+					/* Fall through to common */
+					retVal |= base.ReadPort(port);
+					break;
+			}
+
+			return retVal;
+		}
+
+		public override void WritePort(ushort port, byte value)
+		{
+			switch (port)
+			{
+				case 0x6A:
+					/* REG_HYPER_CTRL */
+					channelHyperVoice.IsEnabled = IsBitSet(value, 7);
+					channelHyperVoice.CtrlUnknown = (byte)((value >> 4) & 0b111);
+					channelHyperVoice.ScalingMode = (byte)((value >> 2) & 0b11);
+					channelHyperVoice.Volume = (byte)((value >> 0) & 0b11);
+					break;
+
+				case 0x6B:
+					/* REG_HYPER_CHAN_CTRL */
+					channelHyperVoice.RightEnable = IsBitSet(value, 6);
+					channelHyperVoice.LeftEnable = IsBitSet(value, 5);
+					channelHyperVoice.ChanCtrlUnknown = (byte)((value >> 0) & 0b1111);
+					break;
+
+				case 0x95:
+					/* REG_SND_HYPERVOICE */
+					channelHyperVoice.Data = value;
+					break;
+
+				case 0x96:
+				case 0x97:
+				case 0x98:
+				case 0x99:
+				case 0x9A:
+				case 0x9B:
+				case 0x9C:
+				case 0x9D:
+					/* REG_SND_9x */
+					break;
+
+				default:
+					/* Fall through to common */
+					base.WritePort(port, value);
+					break;
+			}
+		}
+
+		[Port("REG_HYPER_CTRL", 0x06A)]
+		[BitDescription("Is HyperVoice enabled?", 7)]
+		public bool ChannelHyperVoiceIsEnable => channelHyperVoice.IsEnabled;
+		[Port("REG_HYPER_CTRL", 0x06A)]
+		[BitDescription("HyperVoice control unknown", 4, 6)]
+		public byte ChannelHyperVoiceCtrlUnknown => channelHyperVoice.CtrlUnknown;
+		[Port("REG_HYPER_CTRL", 0x06A)]
+		[BitDescription("HyperVoice scaling mode", 2, 3)]
+		public int ChannelHyperVoiceScalingMode => channelHyperVoice.ScalingMode;
+		[Port("REG_HYPER_CTRL", 0x06A)]
+		[BitDescription("HyperVoice volume", 0, 1)]
+		public int ChannelHyperVoiceVolume => channelHyperVoice.Volume;
+
+		[Port("REG_HYPER_CHAN_CTRL", 0x06B)]
+		[BitDescription("Is HyperVoice right channel enabled?", 6)]
+		public bool ChannelHyperVoiceChanRightEnable => channelHyperVoice.RightEnable;
+		[Port("REG_HYPER_CHAN_CTRL", 0x06B)]
+		[BitDescription("Is HyperVoice left channel enabled?", 5)]
+		public bool ChannelHyperVoiceChanLeftEnable => channelHyperVoice.LeftEnable;
+		[Port("REG_HYPER_CHAN_CTRL", 0x06B)]
+		[BitDescription("HyperVoice channel control unknown", 0, 3)]
+		public byte ChannelHyperVoiceChanCtrlUnknown => channelHyperVoice.ChanCtrlUnknown;
+
+		[Port("REG_SND_HYPERVOICE", 0x095)]
+		[BitDescription("HyperVoice channel working sample")]
+		public byte ChannelHyperVoiceData => channelHyperVoice.Data;
+	}
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta
new file mode 100644
index 00000000..0d383538
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f1a789d9d88897f498d2634d568514c3
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs
new file mode 100644
index 00000000..a52006e1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace StoicGooseUnity
+{
+    [Flags]
+    public enum StoicGooseKey : ushort
+    {
+        X1 = 1,
+        X2 = 2,
+        X3 = 4,
+        X4 = 8,
+        Y1 = 16,
+        Y2 = 32,
+        Y3 = 64,
+        Y4 = 128,
+        Start = 256,
+        A = 512,
+        B = 1024
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta
new file mode 100644
index 00000000..ab8e45bc
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseKey.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5e6310aac38e03548983e7e42f83018b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef
new file mode 100644
index 00000000..fd78c039
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef
@@ -0,0 +1,14 @@
+{
+    "name": "StoicGooseUnity",
+    "rootNamespace": "",
+    "references": [],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": true,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta
new file mode 100644
index 00000000..57f393e7
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Plugins/StoicGooseUnity/StoicGooseUnity.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 28e943ec033eb584b994cc1198ac76be
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity.meta
new file mode 100644
index 00000000..750c3c6a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e38b0e24f0e41b54fb38be7507821d5c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab
new file mode 100644
index 00000000..3276f677
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab
@@ -0,0 +1,365 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &70883439141109485
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1697793132499616605}
+  - component: {fileID: 8208523459577044397}
+  - component: {fileID: 1761025800639127157}
+  - component: {fileID: 175477975286986780}
+  - component: {fileID: 8490678488192273632}
+  - component: {fileID: 6011412303868462633}
+  m_Layer: 0
+  m_Name: StoicGooseUnity
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1697793132499616605
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  serializedVersion: 2
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4829774629647575852}
+  m_Father: {fileID: 0}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &8208523459577044397
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: b7e1a8282bc4d764c81f63e62fd7aec8, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!114 &1761025800639127157
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e8778828cf820b640b9d26ae977cdaba, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  mWidth: 0
+  mHeight: 0
+  mDataLenght: 0
+  m_rawBufferWarper: {fileID: 0}
+  m_drawCanvas: {fileID: 1415903496979242101}
+  m_drawCanvasrect: {fileID: 4829774629647575852}
+--- !u!114 &175477975286986780
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 925771571ae9709429297d42587ce36d, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_as: {fileID: 6011412303868462633}
+--- !u!114 &8490678488192273632
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 54c184e653057e64da4b9be96f4d876d, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!82 &6011412303868462633
+AudioSource:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 70883439141109485}
+  m_Enabled: 1
+  serializedVersion: 4
+  OutputAudioMixerGroup: {fileID: 0}
+  m_audioClip: {fileID: 0}
+  m_Resource: {fileID: 0}
+  m_PlayOnAwake: 0
+  m_Volume: 1
+  m_Pitch: 1
+  Loop: 1
+  Mute: 0
+  Spatialize: 0
+  SpatializePostEffects: 0
+  Priority: 128
+  DopplerLevel: 1
+  MinDistance: 1
+  MaxDistance: 500
+  Pan2D: 0
+  rolloffMode: 0
+  BypassEffects: 0
+  BypassListenerEffects: 0
+  BypassReverbZones: 0
+  rolloffCustomCurve:
+    serializedVersion: 2
+    m_Curve:
+    - serializedVersion: 3
+      time: 0
+      value: 1
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    - serializedVersion: 3
+      time: 1
+      value: 0
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    m_PreInfinity: 2
+    m_PostInfinity: 2
+    m_RotationOrder: 4
+  panLevelCustomCurve:
+    serializedVersion: 2
+    m_Curve:
+    - serializedVersion: 3
+      time: 0
+      value: 0
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    m_PreInfinity: 2
+    m_PostInfinity: 2
+    m_RotationOrder: 4
+  spreadCustomCurve:
+    serializedVersion: 2
+    m_Curve:
+    - serializedVersion: 3
+      time: 0
+      value: 0
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    m_PreInfinity: 2
+    m_PostInfinity: 2
+    m_RotationOrder: 4
+  reverbZoneMixCustomCurve:
+    serializedVersion: 2
+    m_Curve:
+    - serializedVersion: 3
+      time: 0
+      value: 1
+      inSlope: 0
+      outSlope: 0
+      tangentMode: 0
+      weightedMode: 0
+      inWeight: 0.33333334
+      outWeight: 0.33333334
+    m_PreInfinity: 2
+    m_PostInfinity: 2
+    m_RotationOrder: 4
+--- !u!1 &2203418964758308711
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 153069469667130431}
+  - component: {fileID: 1996193783355217829}
+  - component: {fileID: 1415903496979242101}
+  m_Layer: 5
+  m_Name: GameRawImage
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &153069469667130431
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2203418964758308711}
+  m_LocalRotation: {x: 1, y: 0, z: 0, w: 0}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 4829774629647575852}
+  m_LocalEulerAnglesHint: {x: 180, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1996193783355217829
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2203418964758308711}
+  m_CullTransparentMesh: 1
+--- !u!114 &1415903496979242101
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2203418964758308711}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Texture: {fileID: 0}
+  m_UVRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+--- !u!1 &5558964681998005947
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4829774629647575852}
+  - component: {fileID: 6904606342347745421}
+  - component: {fileID: 2921482546112766419}
+  - component: {fileID: 7864505849399022799}
+  m_Layer: 5
+  m_Name: Canvas
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &4829774629647575852
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5558964681998005947}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0, y: 0, z: 0}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 153069469667130431}
+  m_Father: {fileID: 1697793132499616605}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0}
+--- !u!223 &6904606342347745421
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5558964681998005947}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_VertexColorAlwaysGammaSpace: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_UpdateRectTransformForStandalone: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!114 &2921482546112766419
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5558964681998005947}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+  m_PresetInfoIsWorld: 0
+--- !u!114 &7864505849399022799
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5558964681998005947}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab.meta
new file mode 100644
index 00000000..2216e9ab
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/StoicGooseUnity.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 19a6fb74a404996459f79316dcef0f41
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu.meta
new file mode 100644
index 00000000..d0afd9e6
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c002056b1a3ebd541ba56af40fe41ac2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat.meta
new file mode 100644
index 00000000..93c82f9e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: baecae65d43245441a7e7e2b16e96ae9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes
new file mode 100644
index 00000000..c8c5af5f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes	
@@ -0,0 +1,479 @@
+<?xml version="1.0"?>
+<datafile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://datomatic.no-intro.org/stuff https://datomatic.no-intro.org/stuff/schema_nointro_datfile_v3.xsd">
+	<header>
+		<id>51</id>
+		<name>Bandai - WonderSwan Color</name>
+		<description>Bandai - WonderSwan Color</description>
+		<version>20230827-003018</version>
+		<author>C. V. Reynolds, Gefflon, Hiccup, omonim2007, PPLToast, rarenight, relax, sCZther, SonGoku, xuom2</author>
+		<homepage>No-Intro</homepage>
+		<url>https://www.no-intro.org</url>
+		<clrmamepro forcenodump="required"/>
+	</header>
+	<game name="[BIOS] SwanCrystal Boot ROM (Japan) (En)" id="0121" cloneofid="0096">
+		<description>[BIOS] SwanCrystal Boot ROM (Japan) (En)</description>
+		<rom name="[BIOS] SwanCrystal Boot ROM (Japan) (En).wsc" size="8192" crc="0b382c81" md5="d3eff34719a363e586e12b700501ed91" sha1="8270c4a72624692842a3cb9f195058f2ffba48c5" sha256="82e96addf5ab1ce09a84b6eedaa904e4ca432756851f7e0cc0649006c183834d"/>
+	</game>
+	<game name="[BIOS] WonderSwan Color Boot ROM (Japan) (En)" id="0096">
+		<description>[BIOS] WonderSwan Color Boot ROM (Japan) (En)</description>
+		<rom name="[BIOS] WonderSwan Color Boot ROM (Japan) (En).wsc" size="8192" crc="cb06d9c3" md5="880893bd5a7d53fff826bd76a83d566e" sha1="c5ad0b8af45d762662a69f50b64161b9c8919efb" sha256="f5a5c044d84ce1681f94e9ef74287cb989784497be5bd5108df17908dfa55db2"/>
+	</game>
+	<game name="Alchemist Marie &amp; Elie - Futari no Atelier (Japan)" id="0001">
+		<description>Alchemist Marie &amp; Elie - Futari no Atelier (Japan)</description>
+		<rom name="Alchemist Marie &amp; Elie - Futari no Atelier (Japan).wsc" size="4194304" crc="b18cdc0d" md5="cb58db877b8adfce59f2e34cc4224d8b" sha1="99d9d7f951ae589059f34e76aea7489ae4cd79f1"/>
+	</game>
+	<game name="Another Heaven - Memory of those Days (Japan)" id="0002">
+		<description>Another Heaven - Memory of those Days (Japan)</description>
+		<rom name="Another Heaven - Memory of those Days (Japan).wsc" size="4194304" crc="d7a0ab74" md5="30e5f0895254ea2952f4a6a707ace47c" sha1="caf4a8de853ded732b2a72619acf2784eeceafc7" status="verified"/>
+	</game>
+	<game name="Arc the Lad - Kishin Fukkatsu (Japan)" id="0003">
+		<description>Arc the Lad - Kishin Fukkatsu (Japan)</description>
+		<rom name="Arc the Lad - Kishin Fukkatsu (Japan).wsc" size="8388608" crc="e2317345" md5="7a1023850bddb3b9547a9be8075da01d" sha1="68981c05d8118d4189100eed462ee6639328dc59" status="verified"/>
+	</game>
+	<game name="Battle Spirit - Digimon Frontier (Japan) (Rev 1)" id="0004">
+		<description>Battle Spirit - Digimon Frontier (Japan) (Rev 1)</description>
+		<rom name="Battle Spirit - Digimon Frontier (Japan) (Rev 1).wsc" size="4194304" crc="8ba49dab" md5="5fd4676d03e21bf3eee5c9c0236c992c" sha1="fffb1aea34e0a96113cd10ba9de515000d27bfe6" status="verified"/>
+	</game>
+	<game name="Blue Wing Blitz (Japan)" id="0005">
+		<description>Blue Wing Blitz (Japan)</description>
+		<rom name="Blue Wing Blitz (Japan).wsc" size="2097152" crc="99027238" md5="1ea61538422bc2d6349c321fa15b334f" sha1="02103fc5fc97c3a38834ced32a3cfe6523832535"/>
+	</game>
+	<game name="Cardinal Sins - Recycle Edition (World) (v1.02) (WonderWitch Conversion)" id="0123">
+		<description>Cardinal Sins - Recycle Edition (World) (v1.02) (WonderWitch Conversion)</description>
+		<rom name="Cardinal Sins - Recycle Edition (World) (v1.02) (WonderWitch Conversion).wsc" size="524288" crc="7ee85eb9" md5="485072a6e4fbd66f7162ebbc899541c5" sha1="1c8af39ee8c499947e8cc14f42b274594e2da141" sha256="b3cd54eb15d212887ed41c2b574927a0379faae5d3fb3c461b025f0b51608cb5" mia="yes"/>
+	</game>
+	<game name="Dark Eyes - Battle Gate (Japan)" id="0006">
+		<description>Dark Eyes - Battle Gate (Japan)</description>
+		<rom name="Dark Eyes - Battle Gate (Japan).wsc" size="4194304" crc="12ae932c" md5="d3d18ea7800d93cb3a22e275bae9f836" sha1="c2188171dc0f78fb6a13bbb55b4e85bdf7b82fd5"/>
+	</game>
+	<game name="Dicing Knight. (Japan)" id="0007">
+		<description>Dicing Knight. (Japan)</description>
+		<rom name="Dicing Knight. (Japan).wsc" size="2097152" crc="1887389c" md5="098b747bf9d88f651735b45197e393e1" sha1="1e4d8e8b3d16083968055cc76b604da91fa0a132" status="verified"/>
+	</game>
+	<game name="Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Hong Kong) (En)" id="0008">
+		<description>Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Hong Kong) (En)</description>
+		<rom name="Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Hong Kong) (En).wsc" size="4194304" crc="77689273" md5="47b23a84817217cc5b9bbd85fe634174" sha1="7a6411cf8a4d91e8a4e0532779f11bdd25b92363"/>
+	</game>
+	<game name="Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Korea) (En)" id="0111" cloneofid="0008">
+		<description>Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Korea) (En)</description>
+		<rom name="Digimon - Anode Tamer &amp; Cathode Tamer - Veedramon Version (Korea) (En).wsc" size="4194304" crc="7b2a02e3" md5="31b9dc2a403ddacacf1a7cd0c15c5227" sha1="c43ce28fa21b0a6725a6f0e5b2b68bcae6c508f2"/>
+	</game>
+	<game name="Digimon Adventure 02 - D1 Tamers (Japan)" id="0009" cloneofid="0097">
+		<description>Digimon Adventure 02 - D1 Tamers (Japan)</description>
+		<rom name="Digimon Adventure 02 - D1 Tamers (Japan).wsc" size="4194304" crc="4d28637e" md5="833bd00f18fac9b03392a1d2cec17a54" sha1="18d3dfe25d82964ab7bb61af363d368fd12f4d4b" status="verified"/>
+	</game>
+	<game name="Digimon Adventure 02 - D1 Tamers (Japan) (Rev 1)" id="0097">
+		<description>Digimon Adventure 02 - D1 Tamers (Japan) (Rev 1)</description>
+		<rom name="Digimon Adventure 02 - D1 Tamers (Japan) (Rev 1).wsc" size="4194304" crc="62f4e4b4" md5="bb1067e3df3b632b32cd38543da8bd81" sha1="6fbb07bfefac7832436ec56e4d95678428b0f7ba" status="verified"/>
+	</game>
+	<game name="Digimon Tamers - Battle Spirit (Japan, Korea) (En,Ja)" id="0010">
+		<description>Digimon Tamers - Battle Spirit (Japan, Korea) (En,Ja)</description>
+		<rom name="Digimon Tamers - Battle Spirit (Japan, Korea) (En,Ja).wsc" size="4194304" crc="c927bfcb" md5="71146ab7c32bd1524c27da0faefcf46a" sha1="757e92177385a14d979227edee1cb544b4c56bd6" status="verified"/>
+	</game>
+	<game name="Digimon Tamers - Battle Spirit Ver. 1.5 (Japan)" id="0011">
+		<description>Digimon Tamers - Battle Spirit Ver. 1.5 (Japan)</description>
+		<rom name="Digimon Tamers - Battle Spirit Ver. 1.5 (Japan).wsc" size="8388608" crc="6caad4a2" md5="7e1be9ec064d8e1e92f26668c8a74326" sha1="3f39ff494a3d8dd9d55a2e7cf86b47f1c8e8a156" status="verified"/>
+	</game>
+	<game name="Digimon Tamers - Brave Tamer (Japan) (Rev 1)" id="0012">
+		<description>Digimon Tamers - Brave Tamer (Japan) (Rev 1)</description>
+		<rom name="Digimon Tamers - Brave Tamer (Japan) (Rev 1).wsc" size="4194304" crc="f1f4d41f" md5="5883b9d0f63fe8daa9c1a2259c154466" sha1="31a718cfbcff2dab56ab9606a0b5b2dfccecbbcb" status="verified"/>
+	</game>
+	<game name="Digimon Tamers - Digimon Medley (Japan)" id="0013" cloneofid="0102">
+		<description>Digimon Tamers - Digimon Medley (Japan)</description>
+		<rom name="Digimon Tamers - Digimon Medley (Japan).wsc" size="4194304" crc="fa92418d" md5="aaa71e8698a1e765d655eb24fcac19e3" sha1="8638737e5a35c6be05a888dc81e504e0d80fd756" status="verified"/>
+	</game>
+	<game name="Digimon Tamers - Digimon Medley (Japan) (Rev 1)" id="0102">
+		<description>Digimon Tamers - Digimon Medley (Japan) (Rev 1)</description>
+		<rom name="Digimon Tamers - Digimon Medley (Japan) (Rev 1).wsc" size="4194304" crc="84a46949" md5="367e9ef3630061fdf91a2110911611a7" sha1="6c5a2dc7e231ebd278fe22bb7f01b1a7cc3785d6" status="verified"/>
+	</game>
+	<game name="Digital Monster - D-Project (Japan)" id="0014" cloneofid="0105">
+		<description>Digital Monster - D-Project (Japan)</description>
+		<rom name="Digital Monster - D-Project (Japan).wsc" size="4194304" crc="faaefbcb" md5="88eee9ec8e4f093a55125f42cd868647" sha1="3e8fffe1f607ea5f855397d9d877cecb285507f7"/>
+	</game>
+	<game name="Digital Monster - D-Project (Japan) (Rev 1)" id="0098" cloneofid="0105">
+		<description>Digital Monster - D-Project (Japan) (Rev 1)</description>
+		<rom name="Digital Monster - D-Project (Japan) (Rev 1).wsc" size="4194304" crc="bd83b82d" md5="473af43db90ac49686c91672fc0bb095" sha1="7dab09df13e65aa778e3bc9100efffb10b93b8a9"/>
+	</game>
+	<game name="Digital Monster - D-Project (Japan) (Rev 2)" id="0105">
+		<description>Digital Monster - D-Project (Japan) (Rev 2)</description>
+		<rom name="Digital Monster - D-Project (Japan) (Rev 2).wsc" size="4194304" crc="0e40829c" md5="173e9d76206a88bf05696027b4d55850" sha1="016de32719e920fd9996c52d7eb81f2a60a24d7a" sha256="b8a4a641a896e205467b6c209aa5af604472e1779d1aed9888e3ecad84dbce33" status="verified"/>
+	</game>
+	<game name="Digital Monster Card Game - Ver. WonderSwan Color (Japan)" id="0015" cloneofid="0103">
+		<description>Digital Monster Card Game - Ver. WonderSwan Color (Japan)</description>
+		<rom name="Digital Monster Card Game - Ver. WonderSwan Color (Japan).wsc" size="4194304" crc="603cb5e6" md5="52b643d1564b4e093e786e670aa30582" sha1="ba16a0770f7a71dd49e2879799fd04a4f04f7e60" status="verified"/>
+	</game>
+	<game name="Digital Monster Card Game - Ver. WonderSwan Color (Japan) (Rev 2)" id="0103">
+		<description>Digital Monster Card Game - Ver. WonderSwan Color (Japan) (Rev 2)</description>
+		<rom name="Digital Monster Card Game - Ver. WonderSwan Color (Japan) (Rev 2).wsc" size="4194304" crc="1e760c41" md5="c17c4de6648c776b246ae83991ac3978" sha1="e31bfa54cbf539a9d28090b372d8e669a93c3e28" status="verified"/>
+	</game>
+	<game name="Dokodemo Hamster 3 - Odekake Saffron (Japan) (Rev 2)" id="0016">
+		<description>Dokodemo Hamster 3 - Odekake Saffron (Japan) (Rev 2)</description>
+		<rom name="Dokodemo Hamster 3 - Odekake Saffron (Japan) (Rev 2).wsc" size="2097152" crc="93e19f13" md5="9ca8890339c62cc782b1a61c81e055ef" sha1="66b4bd15ef67dc324736a1cc78d6aca335f03389"/>
+	</game>
+	<game name="Dragon Ball (Japan)" id="0017">
+		<description>Dragon Ball (Japan)</description>
+		<rom name="Dragon Ball (Japan).wsc" size="2097152" crc="067238d1" md5="7209acaa3415a4f179ac17fd574453a6" sha1="5384f9974c66e5e26129a4709976de0bb1ae1f17"/>
+	</game>
+	<game name="Final Fantasy (Japan)" id="0018">
+		<description>Final Fantasy (Japan)</description>
+		<rom name="Final Fantasy (Japan).wsc" size="4194304" crc="b7243e88" md5="e36650ac50df69d1832a0d496c165db2" sha1="26628eb76c16880b6faf2e706778d91a60144078" status="verified"/>
+	</game>
+	<game name="Final Fantasy II (Japan)" id="0019">
+		<description>Final Fantasy II (Japan)</description>
+		<rom name="Final Fantasy II (Japan).wsc" size="4194304" crc="f09e752f" md5="e03e666452651e82eb5734a9d684802a" sha1="959321e3b971516e38a4cbf95b0fc3efc0b0a825" sha256="73e6265656ad16118c7d0896eeba516c5e499ac0f214508fb0f232a8b459be2d" status="verified"/>
+	</game>
+	<game name="Final Fantasy IV (Japan)" id="0020">
+		<description>Final Fantasy IV (Japan)</description>
+		<rom name="Final Fantasy IV (Japan).wsc" size="4194304" crc="f699d6d1" md5="47d83279cbdbd91c51cb7b0063d5d3e5" sha1="6d707e88c85d1b5ef708631e709668006a9ee244"/>
+	</game>
+	<game name="Final Lap Special - GT &amp; Formula Machine (Japan)" id="0021">
+		<description>Final Lap Special - GT &amp; Formula Machine (Japan)</description>
+		<rom name="Final Lap Special - GT &amp; Formula Machine (Japan).wsc" size="4194304" crc="b07e6a56" md5="0870f205e8a0148cc75d642f00558057" sha1="4c3f092b095bdb0afdaf8d32d4c54b4d6c209c96"/>
+	</game>
+	<game name="Flash Koibito-kun (Japan)" id="0022">
+		<description>Flash Koibito-kun (Japan)</description>
+		<rom name="Flash Koibito-kun (Japan).wsc" size="2097152" crc="69d8d433" md5="ca1526278a8cf00816b1a88a51916b00" sha1="a3d6717efdb8f243fe86b4c3d869a9734a2e02d3"/>
+	</game>
+	<game name="Flash Masta Firmware (USA) (2016-08-29) (Unl)" id="0116">
+		<description>Flash Masta Firmware (USA) (2016-08-29) (Unl)</description>
+		<rom name="Flash Masta Firmware (USA) (2016-08-29) (Unl).wsc" size="131072" crc="c071d240" md5="53a132ba86468f4b94ba5677ba8e6005" sha1="2fce8b8e08e3f90999589b2d226fc7038b17ef22"/>
+	</game>
+	<game name="Flash Masta Firmware (USA) (2016-05-13) (Unl)" id="0117" cloneofid="0116">
+		<description>Flash Masta Firmware (USA) (2016-05-13) (Unl)</description>
+		<rom name="Flash Masta Firmware (USA) (2016-05-13) (Unl).wsc" size="524288" crc="aabce377" md5="13bf6cd03774fb7ddb70d62813aa89b9" sha1="9869c7c97e229e103203360454495a4dbcdc3614"/>
+	</game>
+	<game name="From TV Animation One Piece - Chopper no Daibouken (Japan)" id="0023">
+		<description>From TV Animation One Piece - Chopper no Daibouken (Japan)</description>
+		<rom name="From TV Animation One Piece - Chopper no Daibouken (Japan).wsc" size="4194304" crc="8e120b5a" md5="f19436970509e5e97b5fd96752aadb8a" sha1="221f48e97ec2c6d0046213956e1f36e923c0dec2"/>
+	</game>
+	<game name="From TV Animation One Piece - Grand Battle Swan Colosseum (Japan)" id="0024">
+		<description>From TV Animation One Piece - Grand Battle Swan Colosseum (Japan)</description>
+		<rom name="From TV Animation One Piece - Grand Battle Swan Colosseum (Japan).wsc" size="8388608" crc="f8a1dd2b" md5="7fa6a3034b8c03fca0b756fb5526ce62" sha1="01e765bf356cdcb413bfd27c6321f7449465766a" sha256="f6d9727a3183bd8b9a9a4765f8437c07c232935219cf4907b993d4b23b4cffb7" status="verified"/>
+	</game>
+	<game name="From TV Animation One Piece - Grand Battle Swan Colosseum (Japan) (Sample)" id="0100" cloneofid="0024">
+		<description>From TV Animation One Piece - Grand Battle Swan Colosseum (Japan) (Sample)</description>
+		<rom name="From TV Animation One Piece - Grand Battle Swan Colosseum (Japan) (Sample).wsc" size="8388608" crc="23853305" md5="3163aefecbb4daa562dcfa286e4084e1" sha1="60aad42f70367fad2e1ce4a84214e467c53f873c" sha256="cdc5d215df65383c8e84abb8da72682ae81ed96d2281489764d584072d342181" status="verified"/>
+	</game>
+	<game name="From TV Animation One Piece - Niji no Shima Densetsu (Japan)" id="0025">
+		<description>From TV Animation One Piece - Niji no Shima Densetsu (Japan)</description>
+		<rom name="From TV Animation One Piece - Niji no Shima Densetsu (Japan).wsc" size="4194304" crc="427056c4" md5="547501367ccf6262a70d0030e68cc75e" sha1="2410690ad46667c52b63402df9e95fc8a75cee62" status="verified"/>
+	</game>
+	<game name="From TV Animation One Piece - Treasure Wars (Japan)" id="0026" cloneofid="0099">
+		<description>From TV Animation One Piece - Treasure Wars (Japan)</description>
+		<rom name="From TV Animation One Piece - Treasure Wars (Japan).wsc" size="4194304" crc="205503c3" md5="9a860c9eea23a35bb5b17a1ae640e269" sha1="dd1e6e5467b72fcb5848f07a9747aa66bb207d45" status="verified"/>
+	</game>
+	<game name="From TV Animation One Piece - Treasure Wars (Japan) (Rev 1)" id="0099">
+		<description>From TV Animation One Piece - Treasure Wars (Japan) (Rev 1)</description>
+		<rom name="From TV Animation One Piece - Treasure Wars (Japan) (Rev 1).wsc" size="4194304" crc="3df3e34c" md5="166946565e646215816123677c7c2108" sha1="55088795164170c24b243a1b572506f123064c0f"/>
+	</game>
+	<game name="From TV Animation One Piece - Treasure Wars 2 - Buggy Land e Youkoso (Japan)" id="0027">
+		<description>From TV Animation One Piece - Treasure Wars 2 - Buggy Land e Youkoso (Japan)</description>
+		<rom name="From TV Animation One Piece - Treasure Wars 2 - Buggy Land e Youkoso (Japan).wsc" size="8388608" crc="0d1048f0" md5="852740c38184f0dbb27ee2bdf670869a" sha1="b7775e8f60fd62dc07f2865f8fad29a11e12dbb5"/>
+	</game>
+	<game name="Front Mission (Japan)" id="0028">
+		<description>Front Mission (Japan)</description>
+		<rom name="Front Mission (Japan).wsc" size="8388608" crc="2f9e2560" md5="9bfcf86bf65c9fdae4a0f88fadafd0d8" sha1="3c752694ab651f9a00ccd39c334a2e3ff78f5cb2"/>
+	</game>
+	<game name="Gekitou! Crash Gear Turbo - Gear Champion League (Japan)" id="0029">
+		<description>Gekitou! Crash Gear Turbo - Gear Champion League (Japan)</description>
+		<rom name="Gekitou! Crash Gear Turbo - Gear Champion League (Japan).wsc" size="4194304" crc="8a8b827c" md5="497bc31e5e84ade37a809aeb90208943" sha1="1bc1e831b9e2aefc59f2cac5f19f7d22be574fc1" status="verified"/>
+	</game>
+	<game name="Gensou Maden Saiyuuki Retribution - Hi no Ataru Basho de (Japan) (Rev 2)" id="0030">
+		<description>Gensou Maden Saiyuuki Retribution - Hi no Ataru Basho de (Japan) (Rev 2)</description>
+		<rom name="Gensou Maden Saiyuuki Retribution - Hi no Ataru Basho de (Japan) (Rev 2).wsc" size="2097152" crc="446e2581" md5="cdbcacff7dd0348beffb1e228592e2e1" sha1="adbe6e38a0bc6a2d19da64a444071977b771f14f" status="verified"/>
+	</game>
+	<game name="Golden Axe (Japan)" id="0031">
+		<description>Golden Axe (Japan)</description>
+		<rom name="Golden Axe (Japan).wsc" size="4194304" crc="bc944a98" md5="55c9cc830000f0aaf721eac69d1703cc" sha1="87661841ca63e99b04c0f6dc4ba3454c897e0c6d"/>
+	</game>
+	<game name="Gransta Chronicle (Japan)" id="0032">
+		<description>Gransta Chronicle (Japan)</description>
+		<rom name="Gransta Chronicle (Japan).wsc" size="8388608" crc="af24f95c" md5="f6a4c3b2b58b14dbb96c622757b89150" sha1="3a4c5d1c08b74cf05b4cb64cbfd7c3dd8b1c3789" status="verified"/>
+	</game>
+	<game name="Guilty Gear Petit (Japan)" id="0033">
+		<description>Guilty Gear Petit (Japan)</description>
+		<rom name="Guilty Gear Petit (Japan).wsc" size="2097152" crc="9750bc2a" md5="be0f50bc4470711a31be0bd33c775ad2" sha1="6d8f8fd330f32374b55cf6b998196a7db2131073"/>
+	</game>
+	<game name="Guilty Gear Petit 2 (Japan)" id="0034">
+		<description>Guilty Gear Petit 2 (Japan)</description>
+		<rom name="Guilty Gear Petit 2 (Japan).wsc" size="4194304" crc="d7a12bd5" md5="1eb91e6b46ab5624c7b707ea7b7abe9d" sha1="f7aeab6724154f7ef6a389f9f18b7100045e1064"/>
+	</game>
+	<game name="GunPey EX (Japan)" id="0035">
+		<description>GunPey EX (Japan)</description>
+		<rom name="GunPey EX (Japan).wsc" size="1048576" crc="0c9cb12c" md5="b7f9c3d80b83178ba192297ea755d066" sha1="1eb729aa9ab0a7df6f8a3470a6fede59d7622d4a"/>
+	</game>
+	<game name="Hanjuku Hero - Ah, Sekai yo Hanjuku Nare...!! (Japan) (Rev 1)" id="0036">
+		<description>Hanjuku Hero - Ah, Sekai yo Hanjuku Nare...!! (Japan) (Rev 1)</description>
+		<rom name="Hanjuku Hero - Ah, Sekai yo Hanjuku Nare...!! (Japan) (Rev 1).wsc" size="4194304" crc="31e09bed" md5="6c1b75de270e7e96df161833a5522b7d" sha1="2e3f221d6965f53b29586d2019ee81dec6d1ac30"/>
+	</game>
+	<game name="Hataraku Chocobo (Japan)" id="0037">
+		<description>Hataraku Chocobo (Japan)</description>
+		<rom name="Hataraku Chocobo (Japan).wsc" size="1048576" crc="7a29e9a6" md5="ebab0f1f4148d54437834971d9756431" sha1="9bd63ed48926b27be70333fbe07da2ceed56328a" status="verified"/>
+	</game>
+	<game name="Hunter X Hunter - Greed Island (Japan)" id="0038" cloneofid="0108">
+		<description>Hunter X Hunter - Greed Island (Japan)</description>
+		<rom name="Hunter X Hunter - Greed Island (Japan).wsc" size="8388608" crc="a487b7a8" md5="c8c0387c6a1f9e55a111da9fde7b854a" sha1="f66335b5af87e7cb72ae311eb9b339534722f738"/>
+	</game>
+	<game name="Hunter X Hunter - Greed Island (Japan) (Rev 1)" id="0108">
+		<description>Hunter X Hunter - Greed Island (Japan) (Rev 1)</description>
+		<rom name="Hunter X Hunter - Greed Island (Japan) (Rev 1).wsc" size="8388608" crc="130af567" md5="e54a236ff923346e1b6eaed84bc8033c" sha1="e26410d4eee4cc8cec5e2e369604aedf26d69d0c" status="verified"/>
+	</game>
+	<game name="Hunter X Hunter - Michibikareshi Mono (Japan)" id="0039">
+		<description>Hunter X Hunter - Michibikareshi Mono (Japan)</description>
+		<rom name="Hunter X Hunter - Michibikareshi Mono (Japan).wsc" size="4194304" crc="9402bca9" md5="d3e0f6a6731565c1bd57757a0e4bad3c" sha1="bc591fc24d3f8e94b70503fd8b6a35fa58151139"/>
+	</game>
+	<game name="Hunter X Hunter - Sorezore no Ketsui (Japan)" id="0040">
+		<description>Hunter X Hunter - Sorezore no Ketsui (Japan)</description>
+		<rom name="Hunter X Hunter - Sorezore no Ketsui (Japan).wsc" size="4194304" crc="d0b20c5a" md5="12a59977999dcf7baebd79c81ab8f5a7" sha1="2da2a9bcff4813abcb5b2c88095258d89a575378" status="verified"/>
+	</game>
+	<game name="Inuyasha - Fuuun Emaki (Japan)" id="0041">
+		<description>Inuyasha - Fuuun Emaki (Japan)</description>
+		<rom name="Inuyasha - Fuuun Emaki (Japan).wsc" size="4194304" crc="3ff5791f" md5="71578fb7c59a3a3923d03d1d48b5ffd3" sha1="99d5bdde193685a1d09ea73bb79a54b4da82625d" status="verified"/>
+	</game>
+	<game name="Inuyasha - Kagome no Sengoku Nikki (Japan)" id="0042">
+		<description>Inuyasha - Kagome no Sengoku Nikki (Japan)</description>
+		<rom name="Inuyasha - Kagome no Sengoku Nikki (Japan).wsc" size="2097152" crc="0c23d551" md5="f1e53c706af452671467b8f4595258d4" sha1="b4fbea1a2c50d8566685f72820b360af4b54f82f" status="verified"/>
+	</game>
+	<game name="Inuyasha - Kagome no Yume Nikki (Japan)" id="0043">
+		<description>Inuyasha - Kagome no Yume Nikki (Japan)</description>
+		<rom name="Inuyasha - Kagome no Yume Nikki (Japan).wsc" size="4194304" crc="44453234" md5="209a77802e1c1a5d73c0dfc9dc726f7d" sha1="f7c8f8b6b6d036df8fc4bde72fcfac2846dffe35" status="verified"/>
+	</game>
+	<game name="Judgement Silversword - Rebirth Edition (Japan) (Rev 4321)" id="0044" cloneofid="0045">
+		<description>Judgement Silversword - Rebirth Edition (Japan) (Rev 4321)</description>
+		<rom name="Judgement Silversword - Rebirth Edition (Japan) (Rev 4321).wsc" size="2097152" crc="aa13e9de" md5="282ff1481a55f7483d8defa4c9c1d81b" sha1="1dc66ac8ac21eb651723428657c9b18cb80d9ee0"/>
+	</game>
+	<game name="Judgement Silversword - Rebirth Edition (Japan) (Rev 5C21)" id="0045">
+		<description>Judgement Silversword - Rebirth Edition (Japan) (Rev 5C21)</description>
+		<rom name="Judgement Silversword - Rebirth Edition (Japan) (Rev 5C21).wsc" size="2097152" crc="85c4c9a1" md5="b017d367af1ba43171beba3e184d9ee9" sha1="58c691cb31f96eea5689693fd23768d02e8b133f" status="verified"/>
+	</game>
+	<game name="Kidou Senshi Gundam - Giren no Yabou - Tokubetsu Hen - Aoki Hoshi no Hasha (Japan)" id="0046">
+		<description>Kidou Senshi Gundam - Giren no Yabou - Tokubetsu Hen - Aoki Hoshi no Hasha (Japan)</description>
+		<rom name="Kidou Senshi Gundam - Giren no Yabou - Tokubetsu Hen - Aoki Hoshi no Hasha (Japan).wsc" size="4194304" crc="d4061551" md5="399e48a3347c378554de65848f1f496c" sha1="20b671bc14a8ab6373deecc641479d09658ac21f" status="verified"/>
+	</game>
+	<game name="Kidou Senshi Gundam Seed (Japan)" id="0047">
+		<description>Kidou Senshi Gundam Seed (Japan)</description>
+		<rom name="Kidou Senshi Gundam Seed (Japan).wsc" size="4194304" crc="bce15137" md5="8e7aabf85435384bd5e80a1eb6e6409a" sha1="e933ff8eace56a462019ae4654b0bab1b21b1d6c" status="verified"/>
+	</game>
+	<game name="Kidou Senshi Gundam Vol. 1 - Side 7 (Japan)" id="0048">
+		<description>Kidou Senshi Gundam Vol. 1 - Side 7 (Japan)</description>
+		<rom name="Kidou Senshi Gundam Vol. 1 - Side 7 (Japan).wsc" size="4194304" crc="08c0247b" md5="3f81d86b97a81ed8fb2fd90a20b94c7a" sha1="29e72e7f96f145a0ff56e447f577310df2ec463b" status="verified"/>
+	</game>
+	<game name="Kidou Senshi Gundam Vol. 2 - Jaburo (Japan)" id="0049">
+		<description>Kidou Senshi Gundam Vol. 2 - Jaburo (Japan)</description>
+		<rom name="Kidou Senshi Gundam Vol. 2 - Jaburo (Japan).wsc" size="8388608" crc="39a1391a" md5="95b2632395ce85fc5f0cdb762e665136" sha1="df1a794f7e3992b1e1e9de14141b607746202202" status="verified"/>
+	</game>
+	<game name="Kidou Senshi Gundam Vol. 3 - A Baoa Qu (Japan)" id="0050">
+		<description>Kidou Senshi Gundam Vol. 3 - A Baoa Qu (Japan)</description>
+		<rom name="Kidou Senshi Gundam Vol. 3 - A Baoa Qu (Japan).wsc" size="8388608" crc="a9f5bf54" md5="fc3bf32e77a2b1f6b749242e89f35e9a" sha1="35443e2ef8a20a0ad82da1274b2768c16239dd46" status="verified"/>
+	</game>
+	<game name="Kinnikuman II-Sei - Choujin Seisenshi (Japan)" id="0051">
+		<description>Kinnikuman II-Sei - Choujin Seisenshi (Japan)</description>
+		<rom name="Kinnikuman II-Sei - Choujin Seisenshi (Japan).wsc" size="4194304" crc="6142fd9d" md5="c69232823a6a14ad7bf6dd539c435ba3" sha1="efcf8f92357ffc6f6ec0e4aa960cd97a5070836e"/>
+	</game>
+	<game name="Kinnikuman II-Sei - Dream Tag Match (Japan)" id="0052">
+		<description>Kinnikuman II-Sei - Dream Tag Match (Japan)</description>
+		<rom name="Kinnikuman II-Sei - Dream Tag Match (Japan).wsc" size="2097152" crc="462f9275" md5="3d41e27fb5cc7eee9187ef275acb86b9" sha1="81dd3124cce8a1aafd423bfe0814187fb7c646cb" sha256="83c5f23f014d7b94f23169940c589b5a9749f4a4d3168114e615522c4446721e" status="verified"/>
+	</game>
+	<game name="Kurupara! (Japan) (Rev 1)" id="0053">
+		<description>Kurupara! (Japan) (Rev 1)</description>
+		<rom name="Kurupara! (Japan) (Rev 1).wsc" size="2097152" crc="274719f5" md5="9450a7cf7d4adea3aa9a97529bcd5b4b" sha1="9942d1b7d1c00126b9891e560e6a3e264f8fdc2e"/>
+	</game>
+	<game name="Last Alive (Japan)" id="0054">
+		<description>Last Alive (Japan)</description>
+		<rom name="Last Alive (Japan).wsc" size="4194304" crc="da4479bf" md5="5ee55daa90d63f97a01a569ef5023431" sha1="b019f41207e396d9fe3509dccdbe1cc6e7ac46bb"/>
+	</game>
+	<game name="Makai Toushi Sa-Ga (Japan)" id="0055">
+		<description>Makai Toushi Sa-Ga (Japan)</description>
+		<rom name="Makai Toushi Sa-Ga (Japan).wsc" size="4194304" crc="1b6f5f30" md5="957137e7d5249c02fecff063e0c86e87" sha1="6b7a9b810c932974cbda4de7178cf0ea5a90e628"/>
+	</game>
+	<game name="mama Mitte (Japan) (Program)" id="0110" cloneofid="0118">
+		<description>mama Mitte (Japan) (Program)</description>
+		<rom name="mama Mitte (Japan) (Program).wsc" size="1048576" crc="f366172e" md5="992fe1e67e917977fcb13afa54d9ff9b" sha1="196190b24297008ab4e48b418ff29b2f8d4bc610"/>
+	</game>
+	<game name="mama Mitte (Japan) (Rev D) (Program)" id="0118">
+		<description>mama Mitte (Japan) (Rev D) (Program)</description>
+		<rom name="mama Mitte (Japan) (Rev D) (Program).wsc" size="1048576" crc="867a8a3f" md5="c56c0d1c5f1d5f032d93554eb31d134a" sha1="b901a571d9e6c988245594588d875d696bc76594" sha256="462ee43b22bd922835894197718aca83b6963e681410312306da79108dbc10e5"/>
+	</game>
+	<game name="Meitantei Conan - Yuugure no Oujo (Japan)" id="0056">
+		<description>Meitantei Conan - Yuugure no Oujo (Japan)</description>
+		<rom name="Meitantei Conan - Yuugure no Oujo (Japan).wsc" size="4194304" crc="9f6e3f8d" md5="6ec4fe6789acab4347355fcb53f10146" sha1="36d8bc2ce7920d940943358d48f056f81055ab34" status="verified"/>
+	</game>
+	<game name="Memories Off - Festa (Japan)" id="0057">
+		<description>Memories Off - Festa (Japan)</description>
+		<rom name="Memories Off - Festa (Japan).wsc" size="2097152" crc="8e123373" md5="a23a6c63016540a3e6e1ed6f7eb5e5cc" sha1="f47b4ab9197999bbec351750601baa20fbbd7177"/>
+	</game>
+	<game name="Mikeneko Holmes - Ghost Panic (Japan)" id="0058">
+		<description>Mikeneko Holmes - Ghost Panic (Japan)</description>
+		<rom name="Mikeneko Holmes - Ghost Panic (Japan).wsc" size="4194304" crc="d75effc2" md5="861083eb47c62024cf3c99141c83a857" sha1="2358701531e8a38419859cd70bf2fbbd967b6745"/>
+	</game>
+	<game name="Mr. Driller (Japan)" id="0059">
+		<description>Mr. Driller (Japan)</description>
+		<rom name="Mr. Driller (Japan).wsc" size="2097152" crc="5555d95c" md5="9d600bfe28196609fbe4fb5b89486cbc" sha1="209232f1e91c05140529d466c0ef6b7ad3386de1"/>
+	</game>
+	<game name="Namco Super Wars (Japan)" id="0060">
+		<description>Namco Super Wars (Japan)</description>
+		<rom name="Namco Super Wars (Japan).wsc" size="2097152" crc="8ce4652f" md5="4180034fe25dbc97ddd0d7e3adf83e3b" sha1="c48569fd0a46ab7b7ceafeb5698be90420cd4fbe" status="verified"/>
+	</game>
+	<game name="Naruto - Konoha Ninpouchou (Japan)" id="0061">
+		<description>Naruto - Konoha Ninpouchou (Japan)</description>
+		<rom name="Naruto - Konoha Ninpouchou (Japan).wsc" size="4194304" crc="71556e6a" md5="5f742027ef79b71b0007ff5654e9565f" sha1="dbaa50fd56e69e72fdfe49362ef5fe4437d66667" status="verified"/>
+	</game>
+	<game name="NAVI GET 400 Million (Japan) (Version 1.0) (Program)" id="0119" cloneofid="0112">
+		<description>NAVI GET 400 Million (Japan) (Version 1.0) (Program)</description>
+		<rom name="NAVI GET 400 Million (Japan) (Version 1.0) (Program).wsc" size="1048576" crc="f79be3b5" md5="4278fd901c463102b2b683cffe40b1f6" sha1="b01a9572351ac8f36a578ea5486b1ae71c5d21a7"/>
+	</game>
+	<game name="NAVI GET 400 Million (Japan) (Version 3.0) (Program)" id="0112">
+		<description>NAVI GET 400 Million (Japan) (Version 3.0) (Program)</description>
+		<rom name="NAVI GET 400 Million (Japan) (Version 3.0) (Program).wsc" size="1048576" crc="4c6cbdb2" md5="9dce5e7af6841901b902f701ab6f861a" sha1="4253d5151a925c7ad766f3dd19497150d578940b"/>
+	</game>
+	<game name="NAVI GET 400 Million (Japan) (Version 2.1) (Program)" id="0113" cloneofid="0112">
+		<description>NAVI GET 400 Million (Japan) (Version 2.1) (Program)</description>
+		<rom name="NAVI GET 400 Million (Japan) (Version 2.1) (Program).wsc" size="1048576" crc="0a072698" md5="71bda13f8ab40f74c67b358528f08742" sha1="bc571f5cace41b17ddb5646d67329021be472aee"/>
+	</game>
+	<game name="NAVI GET 400 Million (Japan) (Version 9) (Program)" id="0120" cloneofid="0112">
+		<description>NAVI GET 400 Million (Japan) (Version 9) (Program)</description>
+		<rom name="NAVI GET 400 Million (Japan) (Version 9) (Program).wsc" size="1048576" crc="83512340" md5="269f61e701aec1720ecc205437f6912d" sha1="863260de4e0626ee7f4055ee7d9ce95824d635f2"/>
+	</game>
+	<game name="Pocket no Naka no Doraemon (Japan)" id="0062">
+		<description>Pocket no Naka no Doraemon (Japan)</description>
+		<rom name="Pocket no Naka no Doraemon (Japan).wsc" size="4194304" crc="2b61bb2b" md5="77e8335f51cd8f5baa2117bbf2b25307" sha1="57338999b949589c36ce116a30f433e9618685e4"/>
+	</game>
+	<game name="Raku Jongg (Japan)" id="0063">
+		<description>Raku Jongg (Japan)</description>
+		<rom name="Raku Jongg (Japan).wsc" size="1048576" crc="fe4ff701" md5="a461ad467a1bf5ba55fa1874017f621b" sha1="977d5830e45c78b9020e9d06a63a9ad6bc623745" status="verified"/>
+	</game>
+	<game name="Rhyme Rider Kerorican (Japan)" id="0064">
+		<description>Rhyme Rider Kerorican (Japan)</description>
+		<rom name="Rhyme Rider Kerorican (Japan).wsc" size="4194304" crc="60706555" md5="04237a449794b5a7a8e4a3572707befc" sha1="5973306a864c3804ee10b209e45067807d39a4de"/>
+	</game>
+	<game name="Riviera - Yakusoku no Chi Riviera (Japan)" id="0065">
+		<description>Riviera - Yakusoku no Chi Riviera (Japan)</description>
+		<rom name="Riviera - Yakusoku no Chi Riviera (Japan).wsc" size="8388608" crc="2460b45a" md5="3e62a6b6af656fcac225cd02446acb9d" sha1="a8f8d3efc9b2d5741081e05f517d746ee5437f87"/>
+	</game>
+	<game name="Rockman EXE - N1 Battle (Japan) (Rev 1)" id="0066">
+		<description>Rockman EXE - N1 Battle (Japan) (Rev 1)</description>
+		<rom name="Rockman EXE - N1 Battle (Japan) (Rev 1).wsc" size="4194304" crc="1f10ca75" md5="d902afdadf17b452621c50a1ffda2fa9" sha1="9b4786adca7b83fe66a9d4b9fd4ffaf32abe7656"/>
+	</game>
+	<game name="Rockman EXE WS (Japan)" id="0067">
+		<description>Rockman EXE WS (Japan)</description>
+		<rom name="Rockman EXE WS (Japan).wsc" size="4194304" crc="658c4b98" md5="a66390da2c2defcf092eb107edaf4fa0" sha1="b4a3ff3b72639f27d1a6f449b0335074aeb9e603"/>
+	</game>
+	<game name="Romancing Sa-Ga (Japan)" id="0068">
+		<description>Romancing Sa-Ga (Japan)</description>
+		<rom name="Romancing Sa-Ga (Japan).wsc" size="4194304" crc="9c98d97d" md5="a4862ef07e13231ae429a98ef667a74a" sha1="06fcc9aad3ae478db6eed27621af4f56a6488a67" status="verified"/>
+	</game>
+	<game name="RUN=DIM - Return to Earth (Japan)" id="0069">
+		<description>RUN=DIM - Return to Earth (Japan)</description>
+		<rom name="RUN=DIM - Return to Earth (Japan).wsc" size="2097152" crc="15c4552e" md5="5898c0dfee65ff9b47ce6ec1be2014d5" sha1="3a41a3b8fc126da07e2a82c21056a45c15efbc98" status="verified"/>
+	</game>
+	<game name="Saint Seiya - Ougon Densetsu Hen - Perfect Edition (Japan)" id="0070">
+		<description>Saint Seiya - Ougon Densetsu Hen - Perfect Edition (Japan)</description>
+		<rom name="Saint Seiya - Ougon Densetsu Hen - Perfect Edition (Japan).wsc" size="2097152" crc="6e8a792d" md5="fd7f1859cb0ee0b63ccb7f36e9a3351d" sha1="8542649963efe0976015759382c180b7c056be9a"/>
+	</game>
+	<game name="SD Gundam - Operation U.C. (Japan)" id="0071">
+		<description>SD Gundam - Operation U.C. (Japan)</description>
+		<rom name="SD Gundam - Operation U.C. (Japan).wsc" size="2097152" crc="f0acda5c" md5="12c3cca0ef52343509dda1c1fb4c1b65" sha1="152c4d63b1b17f2c717a43efc75d718b614f9ddc" status="verified"/>
+	</game>
+	<game name="SD Gundam Eiyuu Den - Kishi Densetsu (Japan)" id="0072">
+		<description>SD Gundam Eiyuu Den - Kishi Densetsu (Japan)</description>
+		<rom name="SD Gundam Eiyuu Den - Kishi Densetsu (Japan).wsc" size="4194304" crc="c60e5162" md5="3944c5d21434e5836f414b319af96331" sha1="ebd4b37ade6df717f7b637747a4d3c45a6cca037"/>
+	</game>
+	<game name="SD Gundam Eiyuu Den - Musha Densetsu (Japan)" id="0073">
+		<description>SD Gundam Eiyuu Den - Musha Densetsu (Japan)</description>
+		<rom name="SD Gundam Eiyuu Den - Musha Densetsu (Japan).wsc" size="4194304" crc="18ecffb8" md5="18267bcb9d31ffb6711f5464f6ab8077" sha1="d8097e25431f0ad5183b2479ee0837599677a300"/>
+	</game>
+	<game name="SD Gundam G Generation - Gather Beat 2 (Japan)" id="0074">
+		<description>SD Gundam G Generation - Gather Beat 2 (Japan)</description>
+		<rom name="SD Gundam G Generation - Gather Beat 2 (Japan).wsc" size="8388608" crc="4d21a347" md5="6c1949e0201437ed16d9182956b67b0e" sha1="016ff46509cbfe57a7440a1755d3a41ef49c048f"/>
+	</game>
+	<game name="SD Gundam G Generation - Mono-Eye Gundams (Japan)" id="0075" cloneofid="0107">
+		<category>Games</category>
+		<description>SD Gundam G Generation - Mono-Eye Gundams (Japan)</description>
+		<rom name="SD Gundam G Generation - Mono-Eye Gundams (Japan).wsc" size="8388608" crc="6aca1f04" md5="c492c6406967e5533022e490b7584da9" sha1="91e087056207fce21e782e25e383c203bc046897"/>
+	</game>
+	<game name="SD Gundam G Generation - Mono-Eye Gundams (Japan) (Rev 2)" id="0107">
+		<category>Games</category>
+		<description>SD Gundam G Generation - Mono-Eye Gundams (Japan) (Rev 2)</description>
+		<rom name="SD Gundam G Generation - Mono-Eye Gundams (Japan) (Rev 2).wsc" size="8388608" crc="a3ecc9ac" md5="c1cb619ec3a596366a324da1f8957985" sha1="1f7c28d9d575b260d973f8526ecadda834032149" sha256="e0ec49d6586787bf11c985787a921b69956770657e71461ffab00f217642dd98"/>
+	</game>
+	<game name="Senkaiden Ni - TV Animation Senkaiden Houshin Engi Yori (Japan)" id="0076">
+		<description>Senkaiden Ni - TV Animation Senkaiden Houshin Engi Yori (Japan)</description>
+		<rom name="Senkaiden Ni - TV Animation Senkaiden Houshin Engi Yori (Japan).wsc" size="4194304" crc="9f35d00f" md5="29badb7011c6d4d7b2047249f24fafb9" sha1="df9e831842072d9af613effbee7162229849de58"/>
+	</game>
+	<game name="Shaman King - Asu e no Ishi (Japan)" id="0077" cloneofid="0078">
+		<description>Shaman King - Asu e no Ishi (Japan)</description>
+		<rom name="Shaman King - Asu e no Ishi (Japan).wsc" size="4194304" crc="6c029674" md5="ed02c631f0915b7ce37c9267e13a2271" sha1="1e735d1e83a7bfa06c5c717c7e8a386d55a8e3f0"/>
+	</game>
+	<game name="Shaman King - Asu e no Ishi (Japan) (Rev 1)" id="0078">
+		<description>Shaman King - Asu e no Ishi (Japan) (Rev 1)</description>
+		<rom name="Shaman King - Asu e no Ishi (Japan) (Rev 1).wsc" size="4194304" crc="34908cb4" md5="0383d7778eac82483efb4e9d276581c6" sha1="473195666a633573c777d3be98d7e8f46569c84b"/>
+	</game>
+	<game name="Sorobang (Japan) (Rev 1)" id="0079">
+		<description>Sorobang (Japan) (Rev 1)</description>
+		<rom name="Sorobang (Japan) (Rev 1).wsc" size="1048576" crc="0e467d97" md5="8756f7653d5d7dd201c1048078ff1cd0" sha1="983582fe8d18839df30b6d29fb75780a9e32f4ec"/>
+	</game>
+	<game name="Star Hearts - Hoshi to Daichi no Shisha (Japan)" id="0081">
+		<description>Star Hearts - Hoshi to Daichi no Shisha (Japan)</description>
+		<rom name="Star Hearts - Hoshi to Daichi no Shisha (Japan).wsc" size="4194304" crc="138d1018" md5="41a4a0ab39c036fb4ad741f19027e443" sha1="2b2c2a0566646156bcdde2a00b728c5b8218aa23"/>
+	</game>
+	<game name="Star Hearts - Hoshi to Daichi no Shisha - Taikenban (Japan) (Not For Sale)" id="0080" cloneofid="0081">
+		<description>Star Hearts - Hoshi to Daichi no Shisha - Taikenban (Japan) (Not For Sale)</description>
+		<rom name="Star Hearts - Hoshi to Daichi no Shisha - Taikenban (Japan) (Not For Sale).wsc" size="4194304" crc="9874e9a2" md5="624cc1e06ade72315784b82f30f7f83f" sha1="44940ae0140df1bd91d742a166c459df1b6c2339"/>
+	</game>
+	<game name="Super Robot Taisen Compact 3 (Japan) (Rev 5)" id="0082" cloneofid="0083">
+		<description>Super Robot Taisen Compact 3 (Japan) (Rev 5)</description>
+		<rom name="Super Robot Taisen Compact 3 (Japan) (Rev 5).wsc" size="8388608" crc="6918c824" md5="38be1f76e69fe58f9268c032c7f22fbb" sha1="b579f204be604ebef4e8238e5883152b70399c4d"/>
+	</game>
+	<game name="Super Robot Taisen Compact 3 (Japan) (Rev 6)" id="0083">
+		<description>Super Robot Taisen Compact 3 (Japan) (Rev 6)</description>
+		<rom name="Super Robot Taisen Compact 3 (Japan) (Rev 6).wsc" size="8388608" crc="188ca644" md5="d43e85a61b91423de8a91f78e62936fe" sha1="dd6fe0f278cdec2670d3be8552dbb0cf6a3a2841"/>
+	</game>
+	<game name="Super Robot Taisen Compact for WonderSwan Color (Japan)" id="0084">
+		<description>Super Robot Taisen Compact for WonderSwan Color (Japan)</description>
+		<rom name="Super Robot Taisen Compact for WonderSwan Color (Japan).wsc" size="4194304" crc="16e0d929" md5="59c20a67961e60791360d8d29d937ef0" sha1="bf212cecbbc51ee32ee2655a072f55e7bf70b9ec" status="verified"/>
+	</game>
+	<game name="Terrors 2 (Japan)" id="0085">
+		<description>Terrors 2 (Japan)</description>
+		<rom name="Terrors 2 (Japan).wsc" size="4194304" crc="9bd8f08c" md5="a8f950c87c0237ead29b23c04368de44" sha1="9532113e14b03c95f034c015168e21273d42eff1" status="verified"/>
+	</game>
+	<game name="Tetris (Japan)" id="0086">
+		<description>Tetris (Japan)</description>
+		<rom name="Tetris (Japan).wsc" size="1048576" crc="7b0caea9" md5="b7e66090d059f77636161fa4e21f3e89" sha1="1a86403d7896d60fcb7a4c09367f5a976c7ea5a5" status="verified"/>
+	</game>
+	<game name="Tonpuusou (Japan)" id="0087">
+		<description>Tonpuusou (Japan)</description>
+		<rom name="Tonpuusou (Japan).wsc" size="1048576" crc="47659b2c" md5="ccab821fe0db8dc9c468d2d3479b530a" sha1="fb53c28bd48174d3829467f1ab81d3f87f9a7f5b"/>
+	</game>
+	<game name="Uchuu Senkan Yamato (Japan)" id="0088">
+		<description>Uchuu Senkan Yamato (Japan)</description>
+		<rom name="Uchuu Senkan Yamato (Japan).wsc" size="4194304" crc="5793bdda" md5="9f612c697b72b2d5e87776edd95de077" sha1="dd1878279a6667fb66dd1ac44a2cdb9a5acbe415"/>
+	</game>
+	<game name="Ultraman - Hikari no Kuni no Shisha (Japan)" id="0089">
+		<description>Ultraman - Hikari no Kuni no Shisha (Japan)</description>
+		<rom name="Ultraman - Hikari no Kuni no Shisha (Japan).wsc" size="2097152" crc="de2208ab" md5="50afa9b3099b822b0f01e32fbecff9bf" sha1="bd107befe5ce6c5508d2da8be351b9984166ae1d"/>
+	</game>
+	<game name="Wild Card (Japan)" id="0090">
+		<description>Wild Card (Japan)</description>
+		<rom name="Wild Card (Japan).wsc" size="2097152" crc="d9401f0a" md5="3da84c8d458cb9ef07b923dadb209990" sha1="ea878a485a20abd5251065fd66e82d9d8b8a669d" status="verified"/>
+	</game>
+	<game name="With You - Mitsumete Itai (Japan)" id="0091">
+		<description>With You - Mitsumete Itai (Japan)</description>
+		<rom name="With You - Mitsumete Itai (Japan).wsc" size="4194304" crc="e14e9d36" md5="b810c7e4d13452444633b6a6a123664b" sha1="6a4f4a03c367ccf00aa7462191c929a2736eb44b"/>
+	</game>
+	<game name="Wizardry Scenario 1 - Proving Grounds of the Mad Overlord (Japan)" id="0092">
+		<description>Wizardry Scenario 1 - Proving Grounds of the Mad Overlord (Japan)</description>
+		<rom name="Wizardry Scenario 1 - Proving Grounds of the Mad Overlord (Japan).wsc" size="2097152" crc="15e55706" md5="f0ba64cd7b88eab7add0f7af02080072" sha1="c1ad383d337dba8a63295cfb8c7ca8470c893c67"/>
+	</game>
+	<game name="Wonder Classic (Japan)" id="0093">
+		<description>Wonder Classic (Japan)</description>
+		<rom name="Wonder Classic (Japan).wsc" size="4194304" crc="12f10b27" md5="50a6fd0e2a65487b5ea2672d2b93a862" sha1="55b54944efd6e277fa7140925ed2457a8cfb40b8"/>
+	</game>
+	<game name="X - Card of Fate (Japan)" id="0094">
+		<description>X - Card of Fate (Japan)</description>
+		<rom name="X - Card of Fate (Japan).wsc" size="4194304" crc="66b617d5" md5="26c76cfcb14c5c8799dbe4367184d4a5" sha1="c1ab4e24f261615ca59f937b866fcf7047b67796"/>
+	</game>
+	<game name="XI Little (Japan)" id="0095">
+		<description>XI Little (Japan)</description>
+		<rom name="XI Little (Japan).wsc" size="2097152" crc="25e2ba75" md5="3c5e5826998dcf3ee18b9396c860df6f" sha1="97c29917a78918a6905fd61a1466971cfd2a33c6"/>
+	</game>
+</datafile>
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta
new file mode 100644
index 00000000..048f4791
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan Color.dat.bytes.meta	
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: af2f9150b8258834096b238494c8da95
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes
new file mode 100644
index 00000000..1fe7764d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes	
@@ -0,0 +1,561 @@
+<?xml version="1.0"?>
+<datafile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://datomatic.no-intro.org/stuff https://datomatic.no-intro.org/stuff/schema_nointro_datfile_v3.xsd">
+	<header>
+		<id>50</id>
+		<name>Bandai - WonderSwan</name>
+		<description>Bandai - WonderSwan</description>
+		<version>20230717-110112</version>
+		<author>C. V. Reynolds, Gefflon, gigadeath, Hiccup, kazumi213, MeguCocoa, omonim2007, PPLToast, RetroUprising, sCZther, SonGoku, xuom2</author>
+		<homepage>No-Intro</homepage>
+		<url>https://www.no-intro.org</url>
+		<clrmamepro forcenodump="required"/>
+	</header>
+	<game name="[BIOS] WonderSwan Boot ROM (Japan) (En)" id="0118">
+		<description>[BIOS] WonderSwan Boot ROM (Japan) (En)</description>
+		<rom name="[BIOS] WonderSwan Boot ROM (Japan) (En).ws" size="4096" crc="7f35f890" md5="54b915694731cc22e07d3fb8a00ee2db" sha1="4015bcacea76bb0b5bbdb13c5358f7e1abb986a1" sha256="bf4480dbea1c47c8b54ce7be9382bc1006148f431fbe4277e136351fa74f635e"/>
+	</game>
+	<game name="Anchorz Field (Japan)" id="0001">
+		<description>Anchorz Field (Japan)</description>
+		<rom name="Anchorz Field (Japan).ws" size="1048576" crc="425eb893" md5="7528a5de5924896d152920b1eaf8fd5d" sha1="06447c248afce04c4f4a1c3b5f7a4ab6f383c94b"/>
+	</game>
+	<game name="Armored Unit (Japan)" id="0002">
+		<description>Armored Unit (Japan)</description>
+		<rom name="Armored Unit (Japan).ws" size="1048576" crc="04366d92" md5="9587c46e7a2d4d8c2e5ddc971b7325fd" sha1="1578669c1fcf59ab5f5e603c6a65121d7ae209b1"/>
+	</game>
+	<game name="Bakusou Dekotora Densetsu for WonderSwan (Japan)" id="0003">
+		<description>Bakusou Dekotora Densetsu for WonderSwan (Japan)</description>
+		<rom name="Bakusou Dekotora Densetsu for WonderSwan (Japan).ws" size="2097152" crc="392dd813" md5="c53a5d8c189a23b16c444c4e8ef581af" sha1="821bb81917445b63ac663c706ab4ce27de28543f"/>
+	</game>
+	<game name="BANDAI Default Splash Screen (Japan) (Program)" id="0140">
+		<description>BANDAI Default Splash Screen (Japan) (Program)</description>
+		<rom name="BANDAI Default Splash Screen (Japan) (Program).ws" size="16777216" crc="9da44185" md5="133aada0250cf13a3e34966cc0c0ba7c" sha1="930277816a22eeeb68646a135192c6104abbc948" sha256="a218fc09e9c6d62b2661039f47a6c115b81480c8fe3bccb9063abc21cbb42344"/>
+	</game>
+	<game name="beatmania for WonderSwan (Japan)" id="0004">
+		<description>beatmania for WonderSwan (Japan)</description>
+		<rom name="beatmania for WonderSwan (Japan).ws" size="16777216" crc="324622c9" md5="b814e71eb1d079466a9535566d605280" sha1="544e76133fa53fc0ae5e00e3465b9cf634f14fd0" status="verified"/>
+	</game>
+	<game name="Buffers Evolution (Japan)" id="0005">
+		<description>Buffers Evolution (Japan)</description>
+		<rom name="Buffers Evolution (Japan).ws" size="4194304" crc="b25a0635" md5="9b15b2236cae605f7bc3bea3859fdd36" sha1="35eea568f756bacf533bb9aaad7e3239ba00e411"/>
+	</game>
+	<game name="Cardcaptor Sakura - Sakura to Fushigi na Clow Card (Japan)" id="0006">
+		<description>Cardcaptor Sakura - Sakura to Fushigi na Clow Card (Japan)</description>
+		<rom name="Cardcaptor Sakura - Sakura to Fushigi na Clow Card (Japan).ws" size="2097152" crc="7f3a14c0" md5="bb9f130931b2b7d1f646f44d1667ad63" sha1="39e9a897b681b2c326b052827d7c534f22290286" status="verified"/>
+	</game>
+	<game name="Chaos Gear - Michibikareshi Mono (Japan)" id="0007">
+		<description>Chaos Gear - Michibikareshi Mono (Japan)</description>
+		<rom name="Chaos Gear - Michibikareshi Mono (Japan).ws" size="2097152" crc="27b3cc18" md5="f647a51827915109d1bc6a05c076eda4" sha1="e212bba4fac51bbfcf440966da0e67b1686dcfc5"/>
+	</game>
+	<game name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 2)" id="0008" cloneofid="0119">
+		<description>Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 2)</description>
+		<rom name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 2).ws" size="2097152" crc="ccaa4853" md5="edbc77ab0d585447d927318a6eb66c9b" sha1="3b62fd2841602f1077270848ab7a3aad58712ee9"/>
+	</game>
+	<game name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 1)" id="0114" cloneofid="0119">
+		<description>Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 1).ws" size="2097152" crc="a607a350" md5="6d7d60c65e5a5cc92f83a62c434577b5" sha1="a8c4f423429a8683cfebd05370ea122613349033" status="verified"/>
+	</game>
+	<game name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 3)" id="0119">
+		<description>Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 3)</description>
+		<rom name="Chocobo no Fushigi na Dungeon for WonderSwan (Japan) (Rev 3).ws" size="2097152" crc="aa53971d" md5="03b416e7326a34c9546e8336f7d50bf2" sha1="f7a65e95a8e97f35ec2419897ad96af1e1d49676"/>
+	</game>
+	<game name="Chou Aniki - Otoko no Tamafuda (Japan) (Rev 4)" id="0009">
+		<description>Chou Aniki - Otoko no Tamafuda (Japan) (Rev 4)</description>
+		<rom name="Chou Aniki - Otoko no Tamafuda (Japan) (Rev 4).ws" size="1048576" crc="7fff2520" md5="24fd819c4f4866d7c5c340d0273acbf9" sha1="eb538b82c5516fae8ce38778e41fb118aa5c830f"/>
+	</game>
+	<game name="Chou Denki Card Battle - Youfu Makai (Japan) (Rev 3)" id="0010">
+		<description>Chou Denki Card Battle - Youfu Makai (Japan) (Rev 3)</description>
+		<rom name="Chou Denki Card Battle - Youfu Makai (Japan) (Rev 3).ws" size="2097152" crc="56e2c069" md5="5432d188664bc4e5dae0fc859580cda1" sha1="c4436a59fd830ba6af2d63462f71e1ab1cfa3212"/>
+	</game>
+	<game name="Clock Tower for WonderSwan (Japan) (Rev 1)" id="0011">
+		<description>Clock Tower for WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Clock Tower for WonderSwan (Japan) (Rev 1).ws" size="4194304" crc="4e8909d1" md5="8f0ba3401662a40e8da5ebcfe7b85e81" sha1="db9b3308336b59aeff7bd173d687953a37739381"/>
+	</game>
+	<game name="Crazy Climber (Japan)" id="0012">
+		<description>Crazy Climber (Japan)</description>
+		<rom name="Crazy Climber (Japan).ws" size="1048576" crc="0cb57376" md5="0ed3a08a3a9858f65d1487889645dc55" sha1="a88882426bf435416616191902a26b2b066f2491"/>
+	</game>
+	<game name="D's Garage 21 Koubo Game - Tane o Maku Tori (Japan)" id="0013">
+		<description>D's Garage 21 Koubo Game - Tane o Maku Tori (Japan)</description>
+		<rom name="D's Garage 21 Koubo Game - Tane o Maku Tori (Japan).ws" size="1048576" crc="b1caec06" md5="e39e90944a683b9d4a996a53804826f0" sha1="83e190af2e25fbb3e93b1d5835c52fe6f1d279ce" sha256="3d791b4e9b05eb600ba89be687bc49dee171af645c3a046b5f8f695198005daf" status="verified"/>
+	</game>
+	<game name="Densha de Go! (Japan) (Rev 1)" id="0014">
+		<description>Densha de Go! (Japan) (Rev 1)</description>
+		<rom name="Densha de Go! (Japan) (Rev 1).ws" size="4194304" crc="b62e5dd0" md5="7b2180e38b4720ce711768a73c33c9df" sha1="d3da0ae529c6f78162682141154a95879f288ca7" sha256="4f68c09f93cce8ef4aa600394f22f8a14825e0fdbad4f4a13d799fdd08a6067b" status="verified"/>
+	</game>
+	<game name="Densha de Go! 2 (Japan)" id="0015">
+		<description>Densha de Go! 2 (Japan)</description>
+		<rom name="Densha de Go! 2 (Japan).ws" size="4194304" crc="af9d8f42" md5="eec79ad5bb634a90b9d020415046e921" sha1="c07f776ac4374b648d1a49efd9d6fcd0db2ac1fa"/>
+	</game>
+	<game name="Digimon - Ver. WonderSwan (Hong Kong) (En)" id="0016" cloneofid="0020">
+		<description>Digimon - Ver. WonderSwan (Hong Kong) (En)</description>
+		<rom name="Digimon - Ver. WonderSwan (Hong Kong) (En).ws" size="2097152" crc="94ea6ffc" md5="d5f7fbf06c57aa50f08c14e64d2e02a2" sha1="5cc59ec1687fe83ec5fb048d3dfc37849747df34"/>
+	</game>
+	<game name="Digimon Adventure - Anode Tamer (Japan) (Rev 1)" id="0017">
+		<description>Digimon Adventure - Anode Tamer (Japan) (Rev 1)</description>
+		<rom name="Digimon Adventure - Anode Tamer (Japan) (Rev 1).ws" size="2097152" crc="6e9dd148" md5="ba249ee5c5ccb1512e0fb6af200a361a" sha1="9db54826c2887dea07aac774bd15e092596e37af"/>
+	</game>
+	<game name="Digimon Adventure - Anode Tamer (Japan)" id="0115" cloneofid="0017">
+		<description>Digimon Adventure - Anode Tamer (Japan)</description>
+		<rom name="Digimon Adventure - Anode Tamer (Japan).ws" size="2097152" crc="fc6946f0" md5="db33df2754fb51ce740006cf9176049f" sha1="c49bd00c95bca49a183d59f85e81815efb1a2fb9" status="verified"/>
+	</game>
+	<game name="Digimon Adventure - Cathode Tamer (Japan)" id="0018">
+		<description>Digimon Adventure - Cathode Tamer (Japan)</description>
+		<rom name="Digimon Adventure - Cathode Tamer (Japan).ws" size="2097152" crc="42ad238b" md5="10f50d5b44a7b8b1f308c1bea8263823" sha1="0b54cc1d350ab92c42ce8214784389b994562bf6" status="verified"/>
+	</game>
+	<game name="Digimon Adventure 02 - Tag Tamers (Japan) (Rev 1)" id="0019">
+		<description>Digimon Adventure 02 - Tag Tamers (Japan) (Rev 1)</description>
+		<rom name="Digimon Adventure 02 - Tag Tamers (Japan) (Rev 1).ws" size="2097152" crc="6ededaf8" md5="2cb264ba76b88452d7576992f2b90dbf" sha1="44a5502b70ea75926b87377e3f634c8093bc574a" status="verified"/>
+	</game>
+	<game name="Digimon Adventure 02 - Tag Tamers (Japan)" id="0123" cloneofid="0019">
+		<description>Digimon Adventure 02 - Tag Tamers (Japan)</description>
+		<rom name="Digimon Adventure 02 - Tag Tamers (Japan).ws" size="2097152" crc="56ce1bc5" md5="0ae28388d68fb56bee38cc96faf37f90" sha1="521754084afc6321ae329421b9d2ab0f0cac8c70" status="verified"/>
+	</game>
+	<game name="Digital Monster - Ver. WonderSwan (Japan) (Rev 1)" id="0020">
+		<description>Digital Monster - Ver. WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Digital Monster - Ver. WonderSwan (Japan) (Rev 1).ws" size="2097152" crc="ab59de2e" md5="deb2c37baea996386b2af10bdd0ca3b1" sha1="ecea24db6e65254ab4d6e312de0eb951c7df716f" status="verified"/>
+	</game>
+	<game name="Digital Partner (Japan)" id="0021">
+		<description>Digital Partner (Japan)</description>
+		<rom name="Digital Partner (Japan).ws" size="2097152" crc="b5e675ae" md5="768b8f5722f0b07be4e8ac356e90acf2" sha1="c622f6742ca3f0129fc12dce0a1c17d292388ffb" sha256="c98c05e7ed2005b162051a242ed91b68a47b576a44da329492718e168a18ee58" status="verified"/>
+	</game>
+	<game name="Dokodemo Hamster (Japan)" id="0022">
+		<description>Dokodemo Hamster (Japan)</description>
+		<rom name="Dokodemo Hamster (Japan).ws" size="1048576" crc="89e7d950" md5="da17db6b7f491510e4b284996ff0eebf" sha1="3d5a1ed77e721908eb1145aaedef17c0ee6355ae"/>
+	</game>
+	<game name="Engacho! for WonderSwan (Japan)" id="0023">
+		<description>Engacho! for WonderSwan (Japan)</description>
+		<rom name="Engacho! for WonderSwan (Japan).ws" size="1048576" crc="4e467626" md5="3584e4a63a6ae9fa546722a349f88573" sha1="f79451034b6d844f0e10c825306bbc26f26a5466"/>
+	</game>
+	<game name="Fever - Sankyo Koushiki Pachinko Simulation for WonderSwan (Japan)" id="0024">
+		<description>Fever - Sankyo Koushiki Pachinko Simulation for WonderSwan (Japan)</description>
+		<rom name="Fever - Sankyo Koushiki Pachinko Simulation for WonderSwan (Japan).ws" size="2097152" crc="8922dd0b" md5="ae2e0e9da1f25119cb4ad24a821446ba" sha1="f26b0215c49e04cb8ef6f031b627dff6a49d2015"/>
+	</game>
+	<game name="Final Lap 2000 (Japan)" id="0025">
+		<description>Final Lap 2000 (Japan)</description>
+		<rom name="Final Lap 2000 (Japan).ws" size="1048576" crc="ce2f1a1d" md5="a466797b353d610f43a0f030cec721c1" sha1="cfcb14be6d2f1dbffdfcefb8c8d83b4f39bc102b"/>
+	</game>
+	<game name="Fire Pro Wrestling for WonderSwan (Japan) (Rev 5)" id="0026">
+		<description>Fire Pro Wrestling for WonderSwan (Japan) (Rev 5)</description>
+		<rom name="Fire Pro Wrestling for WonderSwan (Japan) (Rev 5).ws" size="4194304" crc="f246a68e" md5="dd9be38cd66ffd3b526d3388c6b99b8e" sha1="fbb745b016cc710ff6f82ec3091a181415d8de61"/>
+	</game>
+	<game name="Fishing Freaks - Bass Rise for WonderSwan (Japan)" id="0027">
+		<description>Fishing Freaks - Bass Rise for WonderSwan (Japan)</description>
+		<rom name="Fishing Freaks - Bass Rise for WonderSwan (Japan).ws" size="1048576" crc="a1fb16fc" md5="eb3f161ea3db4ebd759c9b1346032d4f" sha1="f8f077da30f227f3793e97c7f1d656559f08b9d4"/>
+	</game>
+	<game name="From TV Animation One Piece - Mezase Kaizoku Ou! (Japan)" id="0028">
+		<description>From TV Animation One Piece - Mezase Kaizoku Ou! (Japan)</description>
+		<rom name="From TV Animation One Piece - Mezase Kaizoku Ou! (Japan).ws" size="1048576" crc="f2e362b8" md5="fe30867e698c071f6be94cce24b095ee" sha1="99c831c27c478064e3d3fa8f9f089cc28f0e946f" status="verified"/>
+	</game>
+	<game name="Ganso Jajamaru-kun (Japan)" id="0029">
+		<description>Ganso Jajamaru-kun (Japan)</description>
+		<rom name="Ganso Jajamaru-kun (Japan).ws" size="524288" crc="a193458c" md5="6f09fc64352ba0051e724c4ae58402f4" sha1="cbf6455e89b20a000b6121e5c485be1a20d1f726"/>
+	</game>
+	<game name="Glocal Hexcite (Japan)" id="0030">
+		<description>Glocal Hexcite (Japan)</description>
+		<rom name="Glocal Hexcite (Japan).ws" size="1048576" crc="4aed3911" md5="21744e51668ab1fca63e5b2a204c194d" sha1="837528b9d95e309f7b1e8c4ffd46ca3e2b68a5a3"/>
+	</game>
+	<game name="Gomoku Narabe &amp; Reversi - Touryuumon (Japan)" id="0031">
+		<description>Gomoku Narabe &amp; Reversi - Touryuumon (Japan)</description>
+		<rom name="Gomoku Narabe &amp; Reversi - Touryuumon (Japan).ws" size="1048576" crc="a9f11523" md5="3ab76903152993aeee1118818bfad8f7" sha1="0931ddec058eefb32a68a1752716ed2ba68b78bf"/>
+	</game>
+	<game name="Goraku Ou Tango! (Japan) (Rev 2)" id="0032">
+		<description>Goraku Ou Tango! (Japan) (Rev 2)</description>
+		<rom name="Goraku Ou Tango! (Japan) (Rev 2).ws" size="1048576" crc="00137e86" md5="1adacf9cb5aa3eb5839a9e2c94933348" sha1="af3fe9da3f5ee0f5a7b06b0440223db88fcb3bf2" status="verified"/>
+	</game>
+	<game name="GunPey (Japan)" id="0033">
+		<description>GunPey (Japan)</description>
+		<rom name="GunPey (Japan).ws" size="1048576" crc="a1656bbb" md5="816c81b156146be62a45edd7d7d49fc6" sha1="ee4b777f029bac9561e60c19407d08360e733822" status="verified"/>
+	</game>
+	<game name="Hanafuda Shiyouyo (Japan)" id="0034">
+		<description>Hanafuda Shiyouyo (Japan)</description>
+		<rom name="Hanafuda Shiyouyo (Japan).ws" size="1048576" crc="4b22270d" md5="2e26e037cb01f70a6454a61c2955e8b1" sha1="1eda3327eb9b5a5844a95ac789f71b669f4cb6a7"/>
+	</game>
+	<game name="Harobots (Japan)" id="0035" cloneofid="0122">
+		<description>Harobots (Japan)</description>
+		<rom name="Harobots (Japan).ws" size="2097152" crc="aa525c04" md5="0eb951b486fe25f37371835be81eed75" sha1="1f42c5694a798de8ff3c68f63dfc7395be1669a5"/>
+	</game>
+	<game name="Harobots (Japan) (Rev 1)" id="0122">
+		<description>Harobots (Japan) (Rev 1)</description>
+		<rom name="Harobots (Japan) (Rev 1).ws" size="2097152" crc="f75ce82c" md5="b9020cfae65fe791bd52723cbff31707" sha1="ecbaf210f92c75a55df9dff4777ea364596ae0c9"/>
+	</game>
+	<game name="Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 2)" id="0036">
+		<description>Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 2)</description>
+		<rom name="Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 2).ws" size="4194304" crc="70aa800e" md5="fd2165de8c6bb617166f6bb34447e70d" sha1="57b4278fc5812f52413ca65f45225922d4f2ec3d"/>
+	</game>
+	<game name="Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 1)" id="0121" cloneofid="0036">
+		<description>Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 1)</description>
+		<rom name="Hunter X Hunter - Ishi o Tsugu Mono (Japan) (Rev 1).ws" size="4194304" crc="bd6fc68a" md5="cc9d1519e1aba4a0f48f2052af031671" sha1="43d985b31848e1ae58d07231da80ee7aa8d3f686" status="verified"/>
+	</game>
+	<game name="Kakutou Ryouri Densetsu Bistro Recipe - Wonder Battle Hen (Japan)" id="0038">
+		<description>Kakutou Ryouri Densetsu Bistro Recipe - Wonder Battle Hen (Japan)</description>
+		<rom name="Kakutou Ryouri Densetsu Bistro Recipe - Wonder Battle Hen (Japan).ws" size="1048576" crc="4d103236" md5="8be5abfaef7ad77d14f92f10b2460098" sha1="b40fbc7b72921c9ac31330831c0f77e4133ec7d6"/>
+	</game>
+	<game name="Kaze no Klonoa - Moonlight Museum (Japan)" id="0039">
+		<description>Kaze no Klonoa - Moonlight Museum (Japan)</description>
+		<rom name="Kaze no Klonoa - Moonlight Museum (Japan).ws" size="1048576" crc="80c6ef12" md5="5e907dd88b3cfb2855a18fb1bf689860" sha1="207a3ceb9a09eabca6e455deeb7035e7e04c9795" status="verified"/>
+	</game>
+	<game name="Keiba Yosou Shien Soft - Yosou Shinkaron (Japan)" id="0040">
+		<description>Keiba Yosou Shien Soft - Yosou Shinkaron (Japan)</description>
+		<rom name="Keiba Yosou Shien Soft - Yosou Shinkaron (Japan).ws" size="1048576" crc="517f962e" md5="840be356bd48676bd4e39f1e3d54c3b3" sha1="12d26522665cb8ecb3178bc242d984deae438e5c"/>
+	</game>
+	<game name="Kiss Yori... - Seaside Serenade (Japan) (Rev 2)" id="0041">
+		<description>Kiss Yori... - Seaside Serenade (Japan) (Rev 2)</description>
+		<rom name="Kiss Yori... - Seaside Serenade (Japan) (Rev 2).ws" size="2097152" crc="3b4c60c6" md5="611d42816a979ece34dd8221d3023c9c" sha1="9ef89b6fe68c5a06d34344e8c783ec24114ad959"/>
+	</game>
+	<game name="Kosodate Quiz - Dokodemo My Angel (Japan)" id="0042">
+		<description>Kosodate Quiz - Dokodemo My Angel (Japan)</description>
+		<rom name="Kosodate Quiz - Dokodemo My Angel (Japan).ws" size="2097152" crc="4c48624c" md5="a5e1cf7e43e991592890d916369bcf88" sha1="52b154a3e36d01357649a9f7f614139ce6cc46b8" status="verified"/>
+	</game>
+	<game name="Kyousouba Ikusei Simulation - Keiba (Japan) (Rev 1)" id="0043">
+		<description>Kyousouba Ikusei Simulation - Keiba (Japan) (Rev 1)</description>
+		<rom name="Kyousouba Ikusei Simulation - Keiba (Japan) (Rev 1).ws" size="1048576" crc="ecfbcb1d" md5="442e0025aeda0ad8df502696aa97c499" sha1="a309a430fbbed6c42f41d8ccaf4aba82e96d6a7b"/>
+	</game>
+	<game name="Langrisser Millennium WS - The Last Century (Japan) (Rev 1)" id="0044">
+		<description>Langrisser Millennium WS - The Last Century (Japan) (Rev 1)</description>
+		<rom name="Langrisser Millennium WS - The Last Century (Japan) (Rev 1).ws" size="1048576" crc="9e0854e2" md5="0e4369d3f611377433272b3563325ca2" sha1="9fdf3f5821f2a4488139525fe49e87b23de4571f"/>
+	</game>
+	<game name="Last Stand (Japan)" id="0045">
+		<description>Last Stand (Japan)</description>
+		<rom name="Last Stand (Japan).ws" size="2097152" crc="cccaf8a1" md5="cf7ee109aa551fdebaadd5bfbe344fd7" sha1="d524da01f2bfad92c2fa080950229955a3030ef2"/>
+	</game>
+	<game name="Lode Runner for WonderSwan (Japan)" id="0046">
+		<description>Lode Runner for WonderSwan (Japan)</description>
+		<rom name="Lode Runner for WonderSwan (Japan).ws" size="1048576" crc="21279e82" md5="c7445937d6fbc462256bd2ebcdbf3c25" sha1="847f51592f181aa68061900700149b86cdba651b"/>
+	</game>
+	<game name="Macross - True Love Song (Japan)" id="0047">
+		<description>Macross - True Love Song (Japan)</description>
+		<rom name="Macross - True Love Song (Japan).ws" size="4194304" crc="62d419cd" md5="694042e6f8eaa2423693c0a9bba8aef0" sha1="211e051db3fd4d7ae1ea143e043f87cfbcec5f1c"/>
+	</game>
+	<game name="Magical Drop for WonderSwan (Japan)" id="0048">
+		<description>Magical Drop for WonderSwan (Japan)</description>
+		<rom name="Magical Drop for WonderSwan (Japan).ws" size="1048576" crc="637ada93" md5="f98cbebf4a06794aa74636e7a6285ace" sha1="a25944969068ee495254f94c2c48dfffcb66ce8d"/>
+	</game>
+	<game name="Mahjong Touryuumon (Japan) (Rev 3)" id="0049">
+		<description>Mahjong Touryuumon (Japan) (Rev 3)</description>
+		<rom name="Mahjong Touryuumon (Japan) (Rev 3).ws" size="1048576" crc="e7e7fd4c" md5="7edd59281ec08fdb2daaf45e58085e7e" sha1="281079b22cb213ee4dda5c304b5b5be028130929" status="verified"/>
+	</game>
+	<game name="Mahjong Touryuumon (Japan) (Rev 1)" id="0116" cloneofid="0049">
+		<description>Mahjong Touryuumon (Japan) (Rev 1)</description>
+		<rom name="Mahjong Touryuumon (Japan) (Rev 1).ws" size="1048576" crc="c2ed122e" md5="60ad41d50a0b9dd55b0161b1853b824c" sha1="748ca335d39515a6650352449972684be749052a" status="verified"/>
+	</game>
+	<game name="Makaimura for WonderSwan (Japan)" id="0050">
+		<description>Makaimura for WonderSwan (Japan)</description>
+		<rom name="Makaimura for WonderSwan (Japan).ws" size="2097152" crc="00b31fbb" md5="f06beaff2703728baa8dddc0ddeb7094" sha1="5eaeab859e5f647fac354dad285a311387ea126b" status="verified"/>
+	</game>
+	<game name="Medarot Perfect Edition - Kabuto Version (Japan)" id="0051">
+		<description>Medarot Perfect Edition - Kabuto Version (Japan)</description>
+		<rom name="Medarot Perfect Edition - Kabuto Version (Japan).ws" size="1048576" crc="12fb8b28" md5="893ac7863337a65c919780b41bc52406" sha1="509e5748e5efdfb56093c78ae886153dd1838215"/>
+	</game>
+	<game name="Medarot Perfect Edition - Kuwagata Version (Japan)" id="0052">
+		<description>Medarot Perfect Edition - Kuwagata Version (Japan)</description>
+		<rom name="Medarot Perfect Edition - Kuwagata Version (Japan).ws" size="1048576" crc="2b40745d" md5="d8a29d331e9ba86609c75a4aedf9c269" sha1="315061e4739e947175d6ad7f006498cd61a33f8c"/>
+	</game>
+	<game name="Meitantei Conan - Majutsushi no Chousenjou! (Japan)" id="0053">
+		<description>Meitantei Conan - Majutsushi no Chousenjou! (Japan)</description>
+		<rom name="Meitantei Conan - Majutsushi no Chousenjou! (Japan).ws" size="1048576" crc="92fbf7fb" md5="98e88544d8b7df359e37bf2c17dd0641" sha1="8f3f97be31f3bd0e6922ab7795aa6f04bc5cfe2a" status="verified"/>
+	</game>
+	<game name="Meitantei Conan - Nishi no Meitantei Saidai no Kiki! (Japan)" id="0054">
+		<description>Meitantei Conan - Nishi no Meitantei Saidai no Kiki! (Japan)</description>
+		<rom name="Meitantei Conan - Nishi no Meitantei Saidai no Kiki! (Japan).ws" size="2097152" crc="e226863b" md5="1990a2c04395b08df6181f6c8be2a953" sha1="e5684789e81f9d739010db575022a12a448b5509"/>
+	</game>
+	<game name="Metakomi Theraphy - Nee Kiite! (Japan)" id="0055">
+		<description>Metakomi Theraphy - Nee Kiite! (Japan)</description>
+		<rom name="Metakomi Theraphy - Nee Kiite! (Japan).ws" size="2097152" crc="a3ead689" md5="a9c86af9db3743595186274b65c93f90" sha1="dc94e17a942acfdc1eb0c38d91bf72460a4bb8f9"/>
+	</game>
+	<game name="Mingle Magnet (Japan) (En,Ja) (Rev 1)" id="0056">
+		<description>Mingle Magnet (Japan) (En,Ja) (Rev 1)</description>
+		<rom name="Mingle Magnet (Japan) (En,Ja) (Rev 1).ws" size="524288" crc="9baac7bb" md5="555bee0c37a0726d8e8646a290de137f" sha1="c7230ef709f6ceaef9a220541c8cdc05c0cd549f"/>
+	</game>
+	<game name="Mobile Suit Gundam MSVS (Japan)" id="0057">
+		<description>Mobile Suit Gundam MSVS (Japan)</description>
+		<rom name="Mobile Suit Gundam MSVS (Japan).ws" size="2097152" crc="53b9fef8" md5="3ad90f3b8fdb3f2f5a7769e42ebc0792" sha1="2688ca67ac31ce3d5c3523b0e11cad55e70fa257" sha256="d82239a439c51ced0fa7243e21d8f834f70340d072ef55a3ebc73f3d38f560c0" status="verified"/>
+	</game>
+	<game name="MobileWonderGate (Japan) (Rev 1)" id="0058">
+		<description>MobileWonderGate (Japan) (Rev 1)</description>
+		<rom name="MobileWonderGate (Japan) (Rev 1).ws" size="2097152" crc="80de367d" md5="b1b20bb24be3767ab5bfcfca54b51c54" sha1="92d4a6ff6f2b1152d8935025f38f910155e5d709" status="verified"/>
+	</game>
+	<game name="Moero!! Pro Yakyuu Rookies (Japan)" id="0059">
+		<description>Moero!! Pro Yakyuu Rookies (Japan)</description>
+		<rom name="Moero!! Pro Yakyuu Rookies (Japan).ws" size="1048576" crc="eb995e86" md5="ff73a924c6e7d5190be8a9c749b4c9fd" sha1="e88e659cc04fc08a04b8c881f62fe086c5cdab06"/>
+	</game>
+	<game name="Morita Shougi for WonderSwan (Japan)" id="0060">
+		<description>Morita Shougi for WonderSwan (Japan)</description>
+		<rom name="Morita Shougi for WonderSwan (Japan).ws" size="1048576" crc="d675c265" md5="9472518275eaf9f3dedca8b59e2fa97f" sha1="3ce41c90cfc1d53a89ade2c88e0b16cdc92c0268"/>
+	</game>
+	<game name="Nazo Ou Pocket (Japan)" id="0061">
+		<description>Nazo Ou Pocket (Japan)</description>
+		<rom name="Nazo Ou Pocket (Japan).ws" size="1048576" crc="4ed8820c" md5="5e06ad2f0c65d68a124542ddfffdff37" sha1="b358c65bae818c4b3de6bf668d16c311534036c2"/>
+	</game>
+	<game name="Neon Genesis Evangelion - Shito Ikusei (Japan)" id="0062">
+		<description>Neon Genesis Evangelion - Shito Ikusei (Japan)</description>
+		<rom name="Neon Genesis Evangelion - Shito Ikusei (Japan).ws" size="2097152" crc="bf8d9212" md5="0215c4b8a395f6fcf8f5b07605eae08b" sha1="ae31488cee1c91f383efbe3083b4abec092dda36" status="verified"/>
+	</game>
+	<game name="Nice On (Japan) (Rev 1)" id="0063">
+		<description>Nice On (Japan) (Rev 1)</description>
+		<rom name="Nice On (Japan) (Rev 1).ws" size="1048576" crc="b5dbcf12" md5="4b33b1f24f05300c1504f1d9b92d4361" sha1="6a479ee45e69cd3d6cc6cdda5a60eff3077953b0" status="verified"/>
+	</game>
+	<game name="Nihon Pro Mahjong Renmei Kounin - Tetsuman (Japan) (Rev 2)" id="0064">
+		<description>Nihon Pro Mahjong Renmei Kounin - Tetsuman (Japan) (Rev 2)</description>
+		<rom name="Nihon Pro Mahjong Renmei Kounin - Tetsuman (Japan) (Rev 2).ws" size="1048576" crc="44b3e67c" md5="4aa43895710a9fa5a96b9cd1da46348f" sha1="4eefc5a51008c2ab33e8d04064ec9bdcbc03d036" status="verified"/>
+	</game>
+	<game name="Nobunaga no Yabou for WonderSwan (Japan)" id="0065">
+		<description>Nobunaga no Yabou for WonderSwan (Japan)</description>
+		<rom name="Nobunaga no Yabou for WonderSwan (Japan).ws" size="1048576" crc="04531734" md5="d8bb5304f1a68a07e0aca535555171d5" sha1="785ebb7528f5268e1a1fc10dffbe95ccf6d39560"/>
+	</game>
+	<game name="Ou-chan no Oekaki Logic (Japan)" id="0066">
+		<description>Ou-chan no Oekaki Logic (Japan)</description>
+		<rom name="Ou-chan no Oekaki Logic (Japan).ws" size="524288" crc="631bd97a" md5="5e92e316ce0998edbec00b31a6f2e112" sha1="0f73d3112b1184f74e728cf1252ffbee6a146fa6"/>
+	</game>
+	<game name="Pocket Fighter (Japan)" id="0067">
+		<description>Pocket Fighter (Japan)</description>
+		<rom name="Pocket Fighter (Japan).ws" size="2097152" crc="35361250" md5="e79dddc7db77ad96c52b0b7690f8c1b1" sha1="fb8d0f4e58a4192989ec71eb6e392d182aaa3eec"/>
+	</game>
+	<game name="Pro Mahjong Kiwame for WonderSwan (Japan) (Rev 1)" id="0068">
+		<description>Pro Mahjong Kiwame for WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Pro Mahjong Kiwame for WonderSwan (Japan) (Rev 1).ws" size="1048576" crc="90f7e6d6" md5="a2e4f77f749fb0a95db697903d42e718" sha1="32013a7a745a3aa2fd63cc9427c5e1f2635655ed"/>
+	</game>
+	<game name="Puyo Puyo Tsuu (Japan)" id="0069">
+		<description>Puyo Puyo Tsuu (Japan)</description>
+		<rom name="Puyo Puyo Tsuu (Japan).ws" size="1048576" crc="5a41a7ba" md5="e5394d336231c99e9c93f1f41e80a401" sha1="d72c1221c2ce3e281a0ee288a3d079aa8e1b714b" status="verified"/>
+	</game>
+	<game name="Puzzle Bobble (Japan)" id="0070">
+		<description>Puzzle Bobble (Japan)</description>
+		<rom name="Puzzle Bobble (Japan).ws" size="1048576" crc="f504cd84" md5="cf5e9f022baadd1ed9b0a9e88b503e95" sha1="fdb8e9f37a4b097350b7c5b1b8ee381ca51dc0b6"/>
+	</game>
+	<game name="Rainbow Islands - Putty's Party (Japan)" id="0071">
+		<description>Rainbow Islands - Putty's Party (Japan)</description>
+		<rom name="Rainbow Islands - Putty's Party (Japan).ws" size="2097152" crc="8f8608ad" md5="854bd4105d726bf7e76fef8393d6ead0" sha1="759deb79a3fc3befed705d7264e4b88adbadacc7"/>
+	</game>
+	<game name="Ring Infinity (Japan)" id="0072">
+		<description>Ring Infinity (Japan)</description>
+		<rom name="Ring Infinity (Japan).ws" size="4194304" crc="14adbd4b" md5="ffee38c08b4e76cf68420f2e22973284" sha1="9896d93c97381dc06b6f044de6c9bd112ca0c94b" status="verified"/>
+	</game>
+	<game name="Robot Works (Japan)" id="0074">
+		<description>Robot Works (Japan)</description>
+		<rom name="Robot Works (Japan).ws" size="1048576" crc="6adf0e32" md5="6ca5dff7d8a86279591fbb14324e7c3d" sha1="4d4d4a3fde6b1dbbc8f008fbd035fb59624dfba7"/>
+	</game>
+	<game name="Robot Works (Hong Kong) (En,Ja) (Rev 1)" id="0073" cloneofid="0074">
+		<description>Robot Works (Hong Kong) (En,Ja) (Rev 1)</description>
+		<rom name="Robot Works (Hong Kong) (En,Ja) (Rev 1).ws" size="1048576" crc="be6be690" md5="dbaff79d3a241fba6af06cf5b7c935b8" sha1="2117ed92e8cb4ae61868535f1d4d16851b480890"/>
+	</game>
+	<game name="Rockman &amp; Forte - Mirai Kara no Chousensha (Japan)" id="0075">
+		<description>Rockman &amp; Forte - Mirai Kara no Chousensha (Japan)</description>
+		<rom name="Rockman &amp; Forte - Mirai Kara no Chousensha (Japan).ws" size="2097152" crc="cd206a9e" md5="523004d48e9d606e1557c2c57af6790b" sha1="9f8829aa8ea523e8370cbb2acd2acce056bb7958"/>
+	</game>
+	<game name="Sangokushi for WonderSwan (Japan)" id="0076">
+		<description>Sangokushi for WonderSwan (Japan)</description>
+		<rom name="Sangokushi for WonderSwan (Japan).ws" size="524288" crc="e385ee88" md5="9434714e17547ebf3a67baf63c8a6d04" sha1="d064b94f31b15564c9a3dbd3a68690244ea043ac"/>
+	</game>
+	<game name="Sangokushi II for WonderSwan (Japan)" id="0077">
+		<description>Sangokushi II for WonderSwan (Japan)</description>
+		<rom name="Sangokushi II for WonderSwan (Japan).ws" size="1048576" crc="440b2630" md5="263e4218454f7350839ec257441bed85" sha1="3e7492478059d142a6a41b40219eba0c688a8e3f"/>
+	</game>
+	<game name="SD Gundam - Emotional Jam (Japan) (Rev 3)" id="0078">
+		<description>SD Gundam - Emotional Jam (Japan) (Rev 3)</description>
+		<rom name="SD Gundam - Emotional Jam (Japan) (Rev 3).ws" size="2097152" crc="ae83f873" md5="6620592b79b06d1857b449508fe1d557" sha1="ae54a1f8916a2d37a1e0c82c5a9b5d8fe0eeae51" status="verified"/>
+	</game>
+	<game name="SD Gundam - Emotional Jam (Japan) (Rev 2)" id="0129" cloneofid="0078">
+		<description>SD Gundam - Emotional Jam (Japan) (Rev 2)</description>
+		<rom name="SD Gundam - Emotional Jam (Japan) (Rev 2).ws" size="2097152" crc="adfc3048" md5="c38ac44ef65779506dabd0f6db59748c" sha1="b3b4cf8e996c2a1fb149074725dc4b07922b3133"/>
+	</game>
+	<game name="SD Gundam G Generation - Gather Beat (Japan)" id="0079">
+		<description>SD Gundam G Generation - Gather Beat (Japan)</description>
+		<rom name="SD Gundam G Generation - Gather Beat (Japan).ws" size="4194304" crc="e4eb3ab1" md5="39a4626ba187933297b3155180147778" sha1="5e5db8b066e1b41c5c12a2d4ffa97b73ed6c3f03" status="verified"/>
+	</game>
+	<game name="SD Gundam Gashapon Senki - Episode 1 (Japan)" id="0080">
+		<description>SD Gundam Gashapon Senki - Episode 1 (Japan)</description>
+		<rom name="SD Gundam Gashapon Senki - Episode 1 (Japan).ws" size="1048576" crc="21eb4c59" md5="aff7a473a087e38a1a1a7d5f71ffc426" sha1="e6899de5b53f73c8978e3330dca0f2daaf95f140" status="verified"/>
+	</game>
+	<game name="SD Gundam Gashapon Senki - Episode 1 (Japan) (Alt)" id="0125" cloneofid="0080">
+		<description>SD Gundam Gashapon Senki - Episode 1 (Japan) (Alt)</description>
+		<rom name="SD Gundam Gashapon Senki - Episode 1 (Japan) (Alt).ws" size="2097152" crc="2ec1e9c8" md5="c30a3facebc27ac58c359dedca66cce1" sha1="80eff574c75c2168fd0991c0efd16f9a9cadc24c"/>
+	</game>
+	<game name="Senkaiden - TV Animation Senkaiden Houshin Engi Yori (Japan)" id="0081">
+		<description>Senkaiden - TV Animation Senkaiden Houshin Engi Yori (Japan)</description>
+		<rom name="Senkaiden - TV Animation Senkaiden Houshin Engi Yori (Japan).ws" size="2097152" crc="07a3dd46" md5="0230c5ed802e72a9c6bb690e262a302b" sha1="fc8b0b9b7efeac54812e7ae54153b7ae0cb9c12f" status="verified"/>
+	</game>
+	<game name="Sennou Millennium (Japan)" id="0082">
+		<description>Sennou Millennium (Japan)</description>
+		<rom name="Sennou Millennium (Japan).ws" size="1048576" crc="301436ac" md5="e12db3065b59e51bae7bf86053dd5782" sha1="708288e70b3186f6c0ef07acaef1b50fe6b7ab22"/>
+	</game>
+	<game name="Shanghai Pocket (Japan)" id="0083">
+		<description>Shanghai Pocket (Japan)</description>
+		<rom name="Shanghai Pocket (Japan).ws" size="524288" crc="1c489351" md5="37772a59d2fc13b07ba6260b3c4299da" sha1="d64b9b2d567d1cea5960f64e5bdf83d4514446da" status="verified"/>
+	</game>
+	<game name="Shin Nihon Pro Wrestling - Toukon Retsuden (Japan) (Rev 1)" id="0084">
+		<description>Shin Nihon Pro Wrestling - Toukon Retsuden (Japan) (Rev 1)</description>
+		<rom name="Shin Nihon Pro Wrestling - Toukon Retsuden (Japan) (Rev 1).ws" size="1048576" crc="5b76f901" md5="91896b3ee0975f58a8cf322a59da85f2" sha1="7324c5939b8b64858c96bd9726f5b5c483a11e22"/>
+	</game>
+	<game name="Shougi Touryuumon (Japan)" id="0085">
+		<description>Shougi Touryuumon (Japan)</description>
+		<rom name="Shougi Touryuumon (Japan).ws" size="1048576" crc="3ad194eb" md5="f95259c0c48527db0f8a63cb3e9b0527" sha1="0bc88b0affa97225e22c531306e9930ddb8f8905"/>
+	</game>
+	<game name="Side Pocket for WonderSwan (Japan)" id="0086">
+		<description>Side Pocket for WonderSwan (Japan)</description>
+		<rom name="Side Pocket for WonderSwan (Japan).ws" size="1048576" crc="8655269e" md5="496100bcd73fbfa39e473c6ddee190b2" sha1="4a756dab81e0101475dc2e5494270f3df7dac1e6"/>
+	</game>
+	<game name="Slither Link (Japan)" id="0087">
+		<description>Slither Link (Japan)</description>
+		<rom name="Slither Link (Japan).ws" size="1048576" crc="352a570d" md5="d422d16a28390d395f4c0878c555e52c" sha1="9a087b0e6031e7e5e6d133ac82fecb8faa30816a"/>
+	</game>
+	<game name="Soccer Yarou! - Challenge the World (Japan)" id="0088">
+		<description>Soccer Yarou! - Challenge the World (Japan)</description>
+		<rom name="Soccer Yarou! - Challenge the World (Japan).ws" size="1048576" crc="1263da65" md5="5d0ef57b85182dcbe630edda46064cfb" sha1="435f207cce79ad6ac5b564e8a37e0d4395bd3739"/>
+	</game>
+	<game name="Sotsugyou for WonderSwan (Japan) (Rev 1)" id="0089">
+		<description>Sotsugyou for WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Sotsugyou for WonderSwan (Japan) (Rev 1).ws" size="2097152" crc="f016dfe1" md5="2030ae7ddc9f47307165859d75026f13" sha1="e461762566d529d1b103f119da50353902d180d7"/>
+	</game>
+	<game name="Space Invaders (Japan)" id="0090">
+		<description>Space Invaders (Japan)</description>
+		<rom name="Space Invaders (Japan).ws" size="1048576" crc="8d83014f" md5="5558b39b21cc90b0b2f0a4358c043eec" sha1="54dd6e3fe81a8a384a0ffdd7a39211a5de9174c7"/>
+	</game>
+	<game name="Super Robot Taisen Compact (Japan) (Rev 2)" id="0091">
+		<description>Super Robot Taisen Compact (Japan) (Rev 2)</description>
+		<rom name="Super Robot Taisen Compact (Japan) (Rev 2).ws" size="2097152" crc="7021d54f" md5="bd6d4cb18dbd098a797d6c09fad23ccd" sha1="e93d58ab5819992e54223f5d1c4d5aeb6983d6a3" status="verified"/>
+	</game>
+	<game name="Super Robot Taisen Compact (Japan)" id="0117" cloneofid="0091">
+		<description>Super Robot Taisen Compact (Japan)</description>
+		<rom name="Super Robot Taisen Compact (Japan).ws" size="2097152" crc="8a8c5aa8" md5="4f678ef6dd98bd4c0ebad56271528857" sha1="a957111681951eb6a971a6b4f75bca7f89b29628" status="verified"/>
+	</game>
+	<game name="Super Robot Taisen Compact (Japan) (Rev 1)" id="0124" cloneofid="0091">
+		<description>Super Robot Taisen Compact (Japan) (Rev 1)</description>
+		<rom name="Super Robot Taisen Compact (Japan) (Rev 1).ws" size="2097152" crc="7572e478" md5="5c4c57fbc68c5248cace4cb325236a83" sha1="c4a21084bff1f2a63784fe7d11e046f305ad310a" status="verified"/>
+	</game>
+	<game name="Super Robot Taisen Compact 2 - Dai-1-bu - Chijou Gekidou Hen (Japan)" id="0092">
+		<description>Super Robot Taisen Compact 2 - Dai-1-bu - Chijou Gekidou Hen (Japan)</description>
+		<rom name="Super Robot Taisen Compact 2 - Dai-1-bu - Chijou Gekidou Hen (Japan).ws" size="4194304" crc="782877bc" md5="af355adec937a9db1d447980bf85aa2e" sha1="e6911e5bb0a742ba299e05b20ee81f2faa4854a5" status="verified"/>
+	</game>
+	<game name="Super Robot Taisen Compact 2 - Dai-2-bu - Uchuu Gekishin Hen (Japan) (Rev 4)" id="0093">
+		<description>Super Robot Taisen Compact 2 - Dai-2-bu - Uchuu Gekishin Hen (Japan) (Rev 4)</description>
+		<rom name="Super Robot Taisen Compact 2 - Dai-2-bu - Uchuu Gekishin Hen (Japan) (Rev 4).ws" size="4194304" crc="ecbb46de" md5="bb1cf0d7237d7ae2c8aac562fc62906d" sha1="6014ac0b8978e710f26c9cc41180cdf788584743" status="verified"/>
+	</game>
+	<game name="Super Robot Taisen Compact 2 - Dai-3-bu - Ginga Kessen Hen (Japan) (Rev 2)" id="0094">
+		<description>Super Robot Taisen Compact 2 - Dai-3-bu - Ginga Kessen Hen (Japan) (Rev 2)</description>
+		<rom name="Super Robot Taisen Compact 2 - Dai-3-bu - Ginga Kessen Hen (Japan) (Rev 2).ws" size="4194304" crc="0b0f8981" md5="44f63dcb11c916df900a128a6f2e3839" sha1="d24d8cea57c5c487e877eaa523eefb0dd184556d"/>
+	</game>
+	<game name="Taikyoku Igo - Heisei Kiin (Japan)" id="0113">
+		<description>Taikyoku Igo - Heisei Kiin (Japan)</description>
+		<rom name="Taikyoku Igo - Heisei Kiin (Japan).ws" size="524288" crc="5023db90" md5="9fae96e8955c6a5684b04bfe53f93a5d" sha1="636395a62d16f31cac845fef1927dda3890d3f0c" sha256="cbb805f2ef607af3c2fb49509929d2b8df4ee0c8ded8b6b57b551f56eb6810cf"/>
+	</game>
+	<game name="Tanjou Debut for WonderSwan (Japan) (Rev 1)" id="0096">
+		<description>Tanjou Debut for WonderSwan (Japan) (Rev 1)</description>
+		<rom name="Tanjou Debut for WonderSwan (Japan) (Rev 1).ws" size="2097152" crc="8b74f59a" md5="c80ab865bc9a93e946354f41815e93c4" sha1="2f35d250b8ddeb98ca3a2704a4ad85713f4c71b0"/>
+	</game>
+	<game name="Tare Panda no GunPey (Japan)" id="0097">
+		<description>Tare Panda no GunPey (Japan)</description>
+		<rom name="Tare Panda no GunPey (Japan).ws" size="1048576" crc="a5643aa3" md5="c21571f057d05bb01db2ece8517b121d" sha1="9622c65c939f05a9dfae288919ec5bd15c348f14"/>
+	</game>
+	<game name="Tekken Card Challenge (Japan)" id="0098">
+		<description>Tekken Card Challenge (Japan)</description>
+		<rom name="Tekken Card Challenge (Japan).ws" size="1048576" crc="e7c608e5" md5="1e8bca5c31f62a9dd1121884351a2885" sha1="96a9ce5e56dc0c9648027ad4454e6f35e88d9a07" status="verified"/>
+	</game>
+	<game name="Tenori-on (Japan) (En)" id="0132">
+		<description>Tenori-on (Japan) (En)</description>
+		<rom name="Tenori-on (Japan) (En).ws" size="524288" crc="6fe79bb1" md5="8b5c2993d6eccf6a03f377f9c99d5a92" sha1="c0104db6e176cfa64a95e4c9bc9382beae4d70d1" sha256="8d11c841805a241a14af9c5d135840eb3e8106a32a7ee134e986b65af2cd8cc5"/>
+	</game>
+	<game name="Terrors (Japan)" id="0099">
+		<description>Terrors (Japan)</description>
+		<rom name="Terrors (Japan).ws" size="4194304" crc="ef5b6b82" md5="b03441b7b71af24450da7f06b4aac718" sha1="7148d750f12b5da9a0efd99f5a5a7ccadecbdf60"/>
+	</game>
+	<game name="Tetsujin 28 Gou (Japan)" id="0100">
+		<description>Tetsujin 28 Gou (Japan)</description>
+		<rom name="Tetsujin 28 Gou (Japan).ws" size="4194304" crc="6f304dca" md5="8b8ea655dbea4a3152b300126556404c" sha1="65c4c6aaa36328bba5d56419af59af5d3420ed78"/>
+	</game>
+	<game name="Time Bokan Series - Bokan Densetsu - Buta mo Odaterya Doronboo (Japan)" id="0101">
+		<description>Time Bokan Series - Bokan Densetsu - Buta mo Odaterya Doronboo (Japan)</description>
+		<rom name="Time Bokan Series - Bokan Densetsu - Buta mo Odaterya Doronboo (Japan).ws" size="1048576" crc="7da6acb9" md5="9a41ed23b82a090ec4508d3725e19f9b" sha1="ad77d2e8429d5ed926d514d926050086f4edbeee"/>
+	</game>
+	<game name="Tokyo Majin Gakuen - Fuju Houroku (Japan)" id="0102">
+		<description>Tokyo Majin Gakuen - Fuju Houroku (Japan)</description>
+		<rom name="Tokyo Majin Gakuen - Fuju Houroku (Japan).ws" size="8388608" crc="91117d1b" md5="a002e1af08611506555e9a2fe559eddc" sha1="866c67737a4fbb5f09a0b13bbdb89397bcab1f55" status="verified"/>
+	</game>
+	<game name="Trump Collection - Bottom-Up Teki Trump Seikatsu (Japan) (Rev 1)" id="0103">
+		<description>Trump Collection - Bottom-Up Teki Trump Seikatsu (Japan) (Rev 1)</description>
+		<rom name="Trump Collection - Bottom-Up Teki Trump Seikatsu (Japan) (Rev 1).ws" size="1048576" crc="c283ec5f" md5="c1c2fc60d813556480226d45d62121a1" sha1="9313e6d7090e91cca0304dc450b2f2f87329ae7a"/>
+	</game>
+	<game name="Trump Collection 2 - Bottom-Up Teki Sekaiisshuu no Tabi (Japan) (Rev 1)" id="0104">
+		<description>Trump Collection 2 - Bottom-Up Teki Sekaiisshuu no Tabi (Japan) (Rev 1)</description>
+		<rom name="Trump Collection 2 - Bottom-Up Teki Sekaiisshuu no Tabi (Japan) (Rev 1).ws" size="1048576" crc="64aaf392" md5="523da6fd9e07e6e1d1bee62be04d7b1e" sha1="b25ff8fc79168e439ba913a2cea6195094be9ac2"/>
+	</game>
+	<game name="Turntablist - DJ Battle (Japan)" id="0105">
+		<description>Turntablist - DJ Battle (Japan)</description>
+		<rom name="Turntablist - DJ Battle (Japan).ws" size="4194304" crc="0d5171f0" md5="144b29a9997c016fb4b2bb05e3965cfe" sha1="858f1f57b5522a1701cc8a0abae43cec948e26a6"/>
+	</game>
+	<game name="Umizuri ni Ikou! (Japan)" id="0106">
+		<description>Umizuri ni Ikou! (Japan)</description>
+		<rom name="Umizuri ni Ikou! (Japan).ws" size="524288" crc="86b56511" md5="bce82b55b44a7d9b8eeb06cdcc884968" sha1="4f739292d11a45490851eaf40c0a7081824ad75a"/>
+	</game>
+	<game name="Uzumaki - Denshi Kaiki Hen (Japan) (Rev 4)" id="0107">
+		<description>Uzumaki - Denshi Kaiki Hen (Japan) (Rev 4)</description>
+		<rom name="Uzumaki - Denshi Kaiki Hen (Japan) (Rev 4).ws" size="2097152" crc="812020ef" md5="eacb689de3482cf6e6da8befc7da65b2" sha1="4c8166e0632bdb8c098d586a7b1522ed7b63b5f7"/>
+	</game>
+	<game name="Uzumaki - Noroi Simulation (Japan)" id="0037">
+		<description>Uzumaki - Noroi Simulation (Japan)</description>
+		<rom name="Uzumaki - Noroi Simulation (Japan).ws" size="2097152" crc="ca3f0b00" md5="c329cc51abf1f9f85c33ca28d5a26f0c" sha1="38f708a4c0c4fcec0cf4d6ce051d1ff76466d617"/>
+	</game>
+	<game name="Vaitz Blade (Japan) (Rev 1)" id="0108">
+		<description>Vaitz Blade (Japan) (Rev 1)</description>
+		<rom name="Vaitz Blade (Japan) (Rev 1).ws" size="4194304" crc="8fc9e145" md5="49a2932821583fa7d3ed07312b47ab32" sha1="cfb877f0988920c8fe4da5cdd7583197799df621" status="verified"/>
+	</game>
+	<game name="Wasabi Produce - Street Dancer (Japan)" id="0109">
+		<description>Wasabi Produce - Street Dancer (Japan)</description>
+		<rom name="Wasabi Produce - Street Dancer (Japan).ws" size="4194304" crc="1860b655" md5="da0eb7a02b6a5250047eef22deba5c39" sha1="672cfc0e4547b2721d11b67476391b6e6cca81ae"/>
+	</game>
+	<game name="Wonder Stadium (Japan)" id="0111">
+		<description>Wonder Stadium (Japan)</description>
+		<rom name="Wonder Stadium (Japan).ws" size="1048576" crc="23bc0309" md5="56c33436c90f652e02092d064287b5ce" sha1="cb9454a8277bb2a7d5a6e3b4ddc84194fcbb1231" status="verified"/>
+	</game>
+	<game name="Wonder Stadium '99 (Japan)" id="0110">
+		<description>Wonder Stadium '99 (Japan)</description>
+		<rom name="Wonder Stadium '99 (Japan).ws" size="1048576" crc="e252919d" md5="cbd1f30650653d8ac845915bc2aea608" sha1="bb138765346d9f4d77615444d090b1328a59818a" status="verified"/>
+	</game>
+	<game name="WonderSwan Handy Sonar (Japan) (Rev 1)" id="0112" cloneofid="0126">
+		<description>WonderSwan Handy Sonar (Japan) (Rev 1)</description>
+		<rom name="WonderSwan Handy Sonar (Japan) (Rev 1).ws" size="1048576" crc="2ab9852d" md5="5db558122eabe25b930d57c8e5fb05d8" sha1="70d65a936ee1dfc2b89c543312c205285d955efb"/>
+	</game>
+	<game name="WonderSwan Handy Sonar (Japan) (Rev 2)" id="0126">
+		<description>WonderSwan Handy Sonar (Japan) (Rev 2)</description>
+		<rom name="WonderSwan Handy Sonar (Japan) (Rev 2).ws" size="1048576" crc="d4188811" md5="74562136e58960870694c8b6bc913cd2" sha1="a1691ef96097c409b56c77f1d4c731fbfb3f386b" status="verified"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.0.0) (Program)" id="0128" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.0.0) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.0.0) (Program).ws" size="524288" crc="dc60f640" md5="c0fe5cdc311f91aeaa350cda5a8cb31c" sha1="e8b8562d0d63eff76581782647d455cb94b58c77" status="verified"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.2.0) (Program)" id="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.2.0) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.2.0) (Program).ws" size="524288" crc="8e5e9633" md5="5670b16583073b43dc1b486ebee87660" sha1="d9dd280972ec45e56de98f3d425533dd49713caf" status="verified"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.5) (Program)" id="0131" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.5) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.5) (Program).ws" size="524288" crc="45ba7287" md5="dcc8ea5ccb5815f41692467775789770" sha1="905cca29fd6188b2c6237b1fb71e89d7b6a1f842" status="verified"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.0.2) (Program)" id="0133" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.0.2) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.0.2) (Program).ws" size="524288" crc="71aa2e39" md5="375e9ad8ee04587ba92c3adeecd429b5" sha1="f20af32f9e6a2d7deff2d474d20a9da8d2462e07"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.0.3) (Program)" id="0134" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.0.3) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.0.3) (Program).ws" size="524288" crc="f71ef60c" md5="8c4a28687ca4d042bea7df0aa20ad894" sha1="c98fecb3da5cd9712026eea7ca8943fd77356058"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.1) (Program)" id="0135" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.1) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.1) (Program).ws" size="524288" crc="f8bdf7ab" md5="e1afd5588561655121d97d94c20db1f9" sha1="0a09eca4a8a1bce2bad344216589ee833f0b8383"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.2) (Program)" id="0136" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.2) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.2) (Program).ws" size="524288" crc="05c0166e" md5="13566913cd2c8d529869ea03342f5249" sha1="159648c577811986397dbae86002793d18e9147b"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.3) (Program)" id="0137" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.3) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.3) (Program).ws" size="524288" crc="9303fa7e" md5="f7bc604aba650f56c06174bc0f31fbbc" sha1="4ed5d9ef000d33b785bbd659aaec376157faa646"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.4) (Program)" id="0138" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.4) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.4) (Program).ws" size="524288" crc="e8d001b8" md5="75a68a0739c137a4ced5bded8214c733" sha1="9e42a85003c66b286f8335c3372f05df86e1607b"/>
+	</game>
+	<game name="WonderWitch (Japan) (FreyaOS 1.1.6b1) (Program)" id="0139" cloneofid="0130">
+		<description>WonderWitch (Japan) (FreyaOS 1.1.6b1) (Program)</description>
+		<rom name="WonderWitch (Japan) (FreyaOS 1.1.6b1) (Program).ws" size="524288" crc="6480bf70" md5="08ec42043bf68583b830d4e9c2fd3e48" sha1="7913dcda7ec702e152a48e2df0cd721035138c54"/>
+	</game>
+</datafile>
diff --git a/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta
new file mode 100644
index 00000000..b4f07022
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/StoicGooseUnity/emu/Dat/Bandai - WonderSwan.dat.bytes.meta	
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8c7855ba6b3026744bae333b09af339f
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/LaunchUI.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/LaunchUI.prefab
index b254ba90..d0e9b39f 100644
--- a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/LaunchUI.prefab
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/LaunchUI.prefab
@@ -203,6 +203,20 @@ MonoBehaviour:
       Description: "ColecoVision \u662F Coleco \u516C\u53F8\u4E8E1982\u5E748\u6708\u63A8\u51FA\u7684\u7B2C\u4E8C\u4E16\u4EE3\u5BB6\u7528\u6E38\u620F\u673A\uFF0C\u4EE5\u201C\u5C06\u8857\u673A\u4F53\u9A8C\u5E26\u5165\u5BB6\u5EAD\u201D\u4E3A\u76EE\u6807\uFF0C\u5BF9\u65E9\u671F\u6E38\u620F\u673A\u5E02\u573A\u53CA\u4EFB\u5929\u5802FC\u7684\u8BBE\u8BA1\u4EA7\u751F\u4E86\u6DF1\u8FDC\u5F71\u54CD"
       OverrideTemplate: {fileID: 1952221633680236903, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       SubMenus: []
+    - Icon: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+      Name: "Wonder Swan / \u795E\u5947\u5929\u9E45"
+      SubTitle: 
+      Description: "WonderSwan\uFF08\u65E5\u8BED\uFF1A\u30EF\u30F3\u30C0\u30FC\u30B9\u30EF\u30F3\uFF0C\u7B80\u79F0\u4E3AWS\uFF09\u662F\u65E5\u672C\u73A9\u5177\u5236\u9020\u5546\u4E07\u4EE3\uFF08\u540E\u4E0E\u5357\u68A6\u5BAB\u5408\u5E76\u4E3A\u4E07\u4EE3\u5357\u68A6\u5BAB\uFF09\u63A8\u51FA\u768416\u4F4D\u638C\u4E0A\u6E38\u620F\u673A\u3001\u7B2C\u4E94\u4E16\u4EE3\u6E38\u620F\u673A\uFF0C\u7531Game
+        Boy\u8BBE\u8BA1\u8005\u6A2A\u4E95\u519B\u5E73\u6210\u7ACB\u7684\u7684\u516C\u53F8Koto
+        Laboratory\u548C\u4E07\u4EE3\u5171\u540C\u8BBE\u8BA1"
+      OverrideTemplate: {fileID: 1952221633680236903, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      SubMenus: []
+    - Icon: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+      Name: "Wonder Swan Color / \u795E\u5947\u5929\u9E45 Color"
+      SubTitle: 
+      Description: "WSC\u4E3ABANDAI\uFF08\u4E07\u4EE3\uFF09\u516C\u53F8\u63A8\u51FA\u7684\u638C\u673A\u4E2D\u6587\u540D\u4E3A\u201C\u795E\u5947\u5929\u9E45\u201D\u540E\u9762\u7684\u5B57\u6BCDC\u662FCOLOER\u5373\u5F69\u8272\u7684\u610F\u601D\u3002\u6B64\u673A\u7684\u8BBE\u8BA1\u8005\u662FGB\u7684\u751F\u7236\u6A2A\u4E95\u519B\u5E73\u5148\u751F\u3002\u4E3B\u673A\u4E3A16\u4F4D\u4E3B\u673A\uFF0C\u53EF\u652F\u6301\u6A2A\u5411\u548C\u675F\u5411\u4E24\u79CD\u6E38\u620F\u65B9\u5F0F\u3002"
+      OverrideTemplate: {fileID: 1952221633680236903, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      SubMenus: []
   - Icon: {fileID: 21300000, guid: ecce24ec6d4b5b546af85d64ba55a3a2, type: 3}
     Name: "\u8054\u673A"
     SubTitle: 
@@ -495,9 +509,9 @@ RectTransform:
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_ConstrainProportionsScale: 0
   m_Children:
-  - {fileID: 1717590458912744764}
-  - {fileID: 6421621517224560934}
-  - {fileID: 246052657658441022}
+  - {fileID: 4059251362547879848}
+  - {fileID: 905490728719920459}
+  - {fileID: 5045491097022569823}
   m_Father: {fileID: 6855144573435021451}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0, y: 0}
@@ -594,727 +608,13 @@ CanvasGroup:
   m_Interactable: 1
   m_BlocksRaycasts: 1
   m_IgnoreParentGroups: 0
---- !u!1001 &514448941129496145
+--- !u!1001 &195434918666700151
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -1299
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_Text
-      value: Master System / Master III
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_Text
-      value: SAGE Master System / Master III
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-      propertyPath: m_Name
-      value: Master System / Master III
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
---- !u!224 &5657488097292995197 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
-  m_PrefabInstance: {fileID: 514448941129496145}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &895452707268062177
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7102897325704768026}
-    m_Modifications:
-    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Text
-      value: Settings
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 200
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 203
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -664
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -985
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Name
-      value: Settings
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: c300d49e84cf0fb4186c750320e50146, type: 3}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.x
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.y
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.z
-      value: 0.85
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects:
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 5564311985537057645}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 4831117889634108019}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 3415513729133228886}
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
---- !u!224 &1717590458912744764 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 895452707268062177}
-  m_PrefabAsset: {fileID: 0}
---- !u!224 &2353956740009227929 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 895452707268062177}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &975676169669992135
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -1923
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_Text
-      value: SC-3000
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_Text
-      value: "SEGA Computer 3000\u200B"
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-      propertyPath: m_Name
-      value: SC-3000
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
---- !u!224 &4911900709131215595 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
-  m_PrefabInstance: {fileID: 975676169669992135}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &1122233520035511537
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -1611
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_Text
-      value: GAME BOY Color
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_Text
-      value: Nintendo GAME BOY Color
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-      propertyPath: m_Name
-      value: GAME BOY Color
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
---- !u!224 &5058147756976079069 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
-  m_PrefabInstance: {fileID: 1122233520035511537}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &1788339739036902371
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7102897325704768026}
-    m_Modifications:
-    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Text
-      value: "\u8054\u673A"
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 200
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 203
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -664
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -985
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Name
-      value: "\u8054\u673A"
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: ecce24ec6d4b5b546af85d64ba55a3a2, type: 3}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.x
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.y
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.z
-      value: 0.85
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects:
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 5612497320695847736}
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
---- !u!224 &246052657658441022 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 1788339739036902371}
-  m_PrefabAsset: {fileID: 0}
---- !u!224 &3753420248460525211 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 1788339739036902371}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &2394091768133954744
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -2079
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_Text
-      value: SG-1000
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_Text
-      value: SEGA Game 1000
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-      propertyPath: m_Name
-      value: SG-1000
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
---- !u!224 &7537154555208831124 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
-  m_PrefabInstance: {fileID: 2394091768133954744}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &3809207121127636363
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 2353956740009227929}
+    m_TransformParent: {fileID: 1092597733360213005}
     m_Modifications:
     - target: {fileID: 734025543935719296, guid: 98ac562d730eabc42b9a3b12c715d114, type: 3}
       propertyPath: m_IsActive
@@ -1429,569 +729,128 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: 98ac562d730eabc42b9a3b12c715d114, type: 3}
---- !u!224 &3415513729133228886 stripped
+--- !u!224 &1805100227214035882 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 98ac562d730eabc42b9a3b12c715d114, type: 3}
-  m_PrefabInstance: {fileID: 3809207121127636363}
+  m_PrefabInstance: {fileID: 195434918666700151}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &4802381660348418043
+--- !u!1001 &1427742513238972974
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7102897325704768026}
+    m_TransformParent: {fileID: 4317834147708567278}
     m_Modifications:
-    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Text
-      value: Game
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_Pivot.x
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_Pivot.y
       value: 0.5
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchorMax.x
       value: 0.5
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchorMax.y
       value: 0.5
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchorMin.x
       value: 0.5
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchorMin.y
       value: 0.5
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 200
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 203
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: -0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -664
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -985
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Name
-      value: Game
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: 1b52cdd34b39a8c4fa0dad6f2007e2f3, type: 3}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.x
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.y
-      value: 0.85
-      objectReference: {fileID: 0}
-    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      propertyPath: m_LocalScale.z
-      value: 0.85
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects:
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 5525319357449371675}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 8485779968100355135}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 7745862243931306566}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 4921720938111346992}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 8559666481227234823}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 8412498494860582544}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 3837640573846009971}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 5657488097292995197}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 1341087999754857221}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 5058147756976079069}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 2589537515658179182}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 4911900709131215595}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 7537154555208831124}
-    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-      insertIndex: -1
-      addedObject: {fileID: 2653551480213789642}
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
---- !u!224 &6421621517224560934 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 4802381660348418043}
-  m_PrefabAsset: {fileID: 0}
---- !u!224 &7954160675638876803 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
-  m_PrefabInstance: {fileID: 4802381660348418043}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &6221945542930306533
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 3753420248460525211}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Text
-      value: "\u623F\u95F4\u5217\u8868"
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_SizeDelta.x
       value: 144
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_SizeDelta.y
       value: 104
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalPosition.x
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalPosition.y
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalPosition.z
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalRotation.w
       value: 1
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalRotation.x
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalRotation.y
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalRotation.z
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchoredPosition.x
       value: -72
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_AnchoredPosition.y
-      value: -207
+      value: -2235
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalEulerAnglesHint.x
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalEulerAnglesHint.y
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_LocalEulerAnglesHint.z
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: e1f1b901785009046a04b7f05cbfc2c6, type: 3}
-    - target: {fileID: 3189920797946144379, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Name
-      value: "\u623F\u95F4\u5217\u8868"
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+    - target: {fileID: 6906796367924543454, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
       propertyPath: m_Text
-      value: "\u5728\u7EBF\u623F\u95F4\u5217\u8868"
+      value: ColecoVision
       objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Alpha
-      value: 0
+    - target: {fileID: 9003373412835913538, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
+      propertyPath: m_Text
+      value: "ColecoVision \u662F Coleco \u516C\u53F8\u4E8E1982\u5E748\u6708\u63A8\u51FA\u7684\u7B2C\u4E8C\u4E16\u4EE3\u5BB6\u7528\u6E38\u620F\u673A\uFF0C\u4EE5\u201C\u5C06\u8857\u673A\u4F53\u9A8C\u5E26\u5165\u5BB6\u5EAD\u201D\u4E3A\u76EE\u6807\uFF0C\u5BF9\u65E9\u671F\u6E38\u620F\u673A\u5E02\u573A\u53CA\u4EFB\u5929\u5802FC\u7684\u8BBE\u8BA1\u4EA7\u751F\u4E86\u6DF1\u8FDC\u5F71\u54CD"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
+      propertyPath: m_Name
+      value: ColecoVision
       objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: e1f1b901785009046a04b7f05cbfc2c6, type: 3}
     m_RemovedComponents: []
     m_RemovedGameObjects: []
     m_AddedGameObjects: []
     m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
---- !u!224 &5612497320695847736 stripped
+  m_SourcePrefab: {fileID: 100100000, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
+--- !u!224 &6516853407300068866 stripped
 RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
-  m_PrefabInstance: {fileID: 6221945542930306533}
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
+  m_PrefabInstance: {fileID: 1427742513238972974}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &6233890455380381104
+--- !u!1001 &1434864455140837103
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 2353956740009227929}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Text
-      value: "\u80CC\u666F"
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -207
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: 0bdbd1b2830ae724dbd62e306f54d60a, type: 3}
-    - target: {fileID: 3189920797946144379, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Name
-      value: "\u80CC\u666F"
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Text
-      value: 
-      objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: 0bdbd1b2830ae724dbd62e306f54d60a, type: 3}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
---- !u!224 &5564311985537057645 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
-  m_PrefabInstance: {fileID: 6233890455380381104}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &6275399652512353990
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Text
-      value: "\u6536\u85CF"
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -207
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 7637870703528583553, guid: a8e14774cb9b81d4799116466bc09437, type: 3}
-    - target: {fileID: 3189920797946144379, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Name
-      value: "\u6536\u85CF"
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Text
-      value: "\u5C55\u793A\u6240\u6709\u5E73\u53F0\u6536\u85CF\u7684rom"
-      objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 7637870703528583553, guid: a8e14774cb9b81d4799116466bc09437, type: 3}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
---- !u!224 &5525319357449371675 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
-  m_PrefabInstance: {fileID: 6275399652512353990}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &6390825634325253294
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 2353956740009227929}
+    m_TransformParent: {fileID: 1092597733360213005}
     m_Modifications:
     - target: {fileID: 734025543935719296, guid: 3ecc1c637c161184099b69c3d7a0f354, type: 3}
       propertyPath: m_IsActive
@@ -2106,254 +965,197 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: 3ecc1c637c161184099b69c3d7a0f354, type: 3}
---- !u!224 &4831117889634108019 stripped
+--- !u!224 &599818281276590130 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 3ecc1c637c161184099b69c3d7a0f354, type: 3}
-  m_PrefabInstance: {fileID: 6390825634325253294}
+  m_PrefabInstance: {fileID: 1434864455140837103}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &6574234606974949161
+--- !u!1001 &1669605207363117974
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
+    m_TransformParent: {fileID: 7102897325704768026}
     m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -1455
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_Text
-      value: GAME BOY
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_Text
-      value: Nintendo GAME BOY
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-      propertyPath: m_Name
-      value: GAME BOY
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 16523b967a6221241ab1109d556992f4, type: 3}
---- !u!224 &1341087999754857221 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
-  m_PrefabInstance: {fileID: 6574234606974949161}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &6914755027508488173
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Text
-      value: CPS2
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -675
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
-    - target: {fileID: 3189920797946144379, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Name
-      value: CPS2
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-      propertyPath: m_Text
-      value: "Capcom Arcade \u2161"
-      objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
       propertyPath: m_Alpha
       value: 0
       objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Text
+      value: Game
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 200
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 203
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -664
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -245
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Name
+      value: Game
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
       propertyPath: m_Sprite
       value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+      objectReference: {fileID: 21300000, guid: 1b52cdd34b39a8c4fa0dad6f2007e2f3, type: 3}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 0.85
+      objectReference: {fileID: 0}
     m_RemovedComponents: []
     m_RemovedGameObjects: []
-    m_AddedGameObjects: []
+    m_AddedGameObjects:
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 4916857729186405442}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 9100259551027709282}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 5915103534449548264}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 2468814289847610196}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 9161925335042560357}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 488536325200041129}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 1735927827576127070}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 7627876286178725017}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 3198253282780471134}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 7565994594409076016}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 5814797579013412827}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 3086809728505469733}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 8545248743875837910}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 6516853407300068866}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 7601123610744924862}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 7577688307410105946}
     m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
---- !u!224 &4921720938111346992 stripped
+  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+--- !u!224 &905490728719920459 stripped
 RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
-  m_PrefabInstance: {fileID: 6914755027508488173}
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 1669605207363117974}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &7660408852212698690
+--- !u!224 &4317834147708567278 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 1669605207363117974}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1806665220749945847
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
+    m_TransformParent: {fileID: 4317834147708567278}
     m_Modifications:
     - target: {fileID: 5305486536744057900, guid: 9d1d397edc91f544b917d31d56f7074b, type: 3}
       propertyPath: m_Pivot.x
@@ -2452,380 +1254,18 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: 9d1d397edc91f544b917d31d56f7074b, type: 3}
---- !u!224 &2589537515658179182 stripped
+--- !u!224 &5814797579013412827 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 9d1d397edc91f544b917d31d56f7074b, type: 3}
-  m_PrefabInstance: {fileID: 7660408852212698690}
+  m_PrefabInstance: {fileID: 1806665220749945847}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &7886182564343984346
+--- !u!1001 &2124840448071277172
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Text
-      value: NeoGeo
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -831
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
-    - target: {fileID: 3189920797946144379, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Name
-      value: NeoGeo
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Text
-      value: SNK NeoGeo
-      objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
---- !u!224 &8559666481227234823 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
-  m_PrefabInstance: {fileID: 7886182564343984346}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &7886806690583406566
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -2235
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6906796367924543454, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_Text
-      value: ColecoVision
-      objectReference: {fileID: 0}
-    - target: {fileID: 9003373412835913538, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_Text
-      value: "ColecoVision \u662F Coleco \u516C\u53F8\u4E8E1982\u5E748\u6708\u63A8\u51FA\u7684\u7B2C\u4E8C\u4E16\u4EE3\u5BB6\u7528\u6E38\u620F\u673A\uFF0C\u4EE5\u201C\u5C06\u8857\u673A\u4F53\u9A8C\u5E26\u5165\u5BB6\u5EAD\u201D\u4E3A\u76EE\u6807\uFF0C\u5BF9\u65E9\u671F\u6E38\u620F\u673A\u5E02\u573A\u53CA\u4EFB\u5929\u5802FC\u7684\u8BBE\u8BA1\u4EA7\u751F\u4E86\u6DF1\u8FDC\u5F71\u54CD"
-      objectReference: {fileID: 0}
-    - target: {fileID: 9106117812833555594, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-      propertyPath: m_Name
-      value: ColecoVision
-      objectReference: {fileID: 0}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
---- !u!224 &2653551480213789642 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 146c51253379ea34cb1e979eb56072b1, type: 3}
-  m_PrefabInstance: {fileID: 7886806690583406566}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &7960352008143667938
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
-    m_Modifications:
-    - target: {fileID: 734025543935719296, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_IsActive
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 991446423622995247, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Text
-      value: NES
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Pivot.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Pivot.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchorMax.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchorMax.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchorMin.x
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchorMin.y
-      value: 0.5
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_SizeDelta.x
-      value: 144
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_SizeDelta.y
-      value: 104
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalPosition.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalPosition.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalPosition.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalRotation.w
-      value: 1
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalRotation.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalRotation.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalRotation.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchoredPosition.x
-      value: -72
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_AnchoredPosition.y
-      value: -363
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.x
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.y
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_LocalEulerAnglesHint.z
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 2619187604372594158, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
-    - target: {fileID: 3189920797946144379, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Name
-      value: NES
-      objectReference: {fileID: 0}
-    - target: {fileID: 3380485461544738227, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Text
-      value: Nintendo Entertainment System / Family Computer
-      objectReference: {fileID: 0}
-    - target: {fileID: 5331629140490413834, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Alpha
-      value: 0
-      objectReference: {fileID: 0}
-    - target: {fileID: 6771349210554360888, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-      propertyPath: m_Sprite
-      value: 
-      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
-    m_RemovedComponents: []
-    m_RemovedGameObjects: []
-    m_AddedGameObjects: []
-    m_AddedComponents: []
-  m_SourcePrefab: {fileID: 100100000, guid: b170104e466853c49b29f9b5b103364e, type: 3}
---- !u!224 &8485779968100355135 stripped
-RectTransform:
-  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
-  m_PrefabInstance: {fileID: 7960352008143667938}
-  m_PrefabAsset: {fileID: 0}
---- !u!1001 &7999625342290202701
-PrefabInstance:
-  m_ObjectHideFlags: 0
-  serializedVersion: 2
-  m_Modification:
-    serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
+    m_TransformParent: {fileID: 4317834147708567278}
     m_Modifications:
     - target: {fileID: 734025543935719296, guid: c4467b8175b4db64093d603a93775dff, type: 3}
       propertyPath: m_IsActive
@@ -2940,18 +1380,1088 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: c4467b8175b4db64093d603a93775dff, type: 3}
---- !u!224 &8412498494860582544 stripped
+--- !u!224 &488536325200041129 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: c4467b8175b4db64093d603a93775dff, type: 3}
-  m_PrefabInstance: {fileID: 7999625342290202701}
+  m_PrefabInstance: {fileID: 2124840448071277172}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &8126049235216200859
+--- !u!1001 &2279606829499168741
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
+    m_TransformParent: {fileID: 1092597733360213005}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Text
+      value: "\u80CC\u666F"
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -207
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: 0bdbd1b2830ae724dbd62e306f54d60a, type: 3}
+    - target: {fileID: 3189920797946144379, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Name
+      value: "\u80CC\u666F"
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Text
+      value: 
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: 0bdbd1b2830ae724dbd62e306f54d60a, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+--- !u!224 &295434682472724792 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: dd267389f23898f45b22dbc9670a17c7, type: 3}
+  m_PrefabInstance: {fileID: 2279606829499168741}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2340595223093063861
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -1299
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_Text
+      value: Master System / Master III
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_Text
+      value: SAGE Master System / Master III
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+      propertyPath: m_Name
+      value: Master System / Master III
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+--- !u!224 &7627876286178725017 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 29303a37c43a05e48baf7b3fe43bfd09, type: 3}
+  m_PrefabInstance: {fileID: 2340595223093063861}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2344551020705630838
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -2547
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_Text
+      value: "Wonder Swan Color / \u795E\u5947\u5929\u9E45 Color"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_Text
+      value: "WSC\u4E3ABANDAI\uFF08\u4E07\u4EE3\uFF09\u516C\u53F8\u63A8\u51FA\u7684\u638C\u673A\u4E2D\u6587\u540D\u4E3A\u201C\u795E\u5947\u5929\u9E45\u201D\u540E\u9762\u7684\u5B57\u6BCDC\u662FCOLOER\u5373\u5F69\u8272\u7684\u610F\u601D\u3002\u6B64\u673A\u7684\u8BBE\u8BA1\u8005\u662FGB\u7684\u751F\u7236\u6A2A\u4E95\u519B\u5E73\u5148\u751F\u3002\u4E3B\u673A\u4E3A16\u4F4D\u4E3B\u673A\uFF0C\u53EF\u652F\u6301\u6A2A\u5411\u548C\u675F\u5411\u4E24\u79CD\u6E38\u620F\u65B9\u5F0F\u3002"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+      propertyPath: m_Name
+      value: "Wonder Swan Color / \u795E\u5947\u5929\u9E45 Color"
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+--- !u!224 &7577688307410105946 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 017a4e122916b0c489123671b06d9ea7, type: 3}
+  m_PrefabInstance: {fileID: 2344551020705630838}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2367840363771991698
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -2391
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_Text
+      value: "Wonder Swan / \u795E\u5947\u5929\u9E45"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_Text
+      value: "WonderSwan\uFF08\u65E5\u8BED\uFF1A\u30EF\u30F3\u30C0\u30FC\u30B9\u30EF\u30F3\uFF0C\u7B80\u79F0\u4E3AWS\uFF09\u662F\u65E5\u672C\u73A9\u5177\u5236\u9020\u5546\u4E07\u4EE3\uFF08\u540E\u4E0E\u5357\u68A6\u5BAB\u5408\u5E76\u4E3A\u4E07\u4EE3\u5357\u68A6\u5BAB\uFF09\u63A8\u51FA\u768416\u4F4D\u638C\u4E0A\u6E38\u620F\u673A\u3001\u7B2C\u4E94\u4E16\u4EE3\u6E38\u620F\u673A\uFF0C\u7531Game
+        Boy\u8BBE\u8BA1\u8005\u6A2A\u4E95\u519B\u5E73\u6210\u7ACB\u7684\u7684\u516C\u53F8Koto
+        Laboratory\u548C\u4E07\u4EE3\u5171\u540C\u8BBE\u8BA1"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+      propertyPath: m_Name
+      value: "Wonder Swan / \u795E\u5947\u5929\u9E45"
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+--- !u!224 &7601123610744924862 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 6b9cf0040ec05e742aa8ca739b5f6adf, type: 3}
+  m_PrefabInstance: {fileID: 2367840363771991698}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2404658431831599388
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -1611
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_Text
+      value: GAME BOY Color
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_Text
+      value: Nintendo GAME BOY Color
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+      propertyPath: m_Name
+      value: GAME BOY Color
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+--- !u!224 &7565994594409076016 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: c73ba8d34c204a5408505f72df70da0b, type: 3}
+  m_PrefabInstance: {fileID: 2404658431831599388}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &2589017321316548981
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 7102897325704768026}
+    m_Modifications:
+    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Text
+      value: Settings
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 200
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 203
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -664
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -245
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Name
+      value: Settings
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: c300d49e84cf0fb4186c750320e50146, type: 3}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 0.85
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects:
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 295434682472724792}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 599818281276590130}
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 1805100227214035882}
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+--- !u!224 &1092597733360213005 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 2589017321316548981}
+  m_PrefabAsset: {fileID: 0}
+--- !u!224 &4059251362547879848 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 2589017321316548981}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &3311887530792451334
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 8176807569060777722}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Text
+      value: "\u623F\u95F4\u5217\u8868"
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -207
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: e1f1b901785009046a04b7f05cbfc2c6, type: 3}
+    - target: {fileID: 3189920797946144379, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Name
+      value: "\u623F\u95F4\u5217\u8868"
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Text
+      value: "\u5728\u7EBF\u623F\u95F4\u5217\u8868"
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: e1f1b901785009046a04b7f05cbfc2c6, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+--- !u!224 &3912891659551650779 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 71eabba88b30a4945b153dbaa6237441, type: 3}
+  m_PrefabInstance: {fileID: 3311887530792451334}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &4177563188377789833
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Text
+      value: CPS2
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -675
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    - target: {fileID: 3189920797946144379, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Name
+      value: CPS2
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Text
+      value: "Capcom Arcade \u2161"
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+--- !u!224 &2468814289847610196 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: cf3c029a754c0dc40b15ce6b1962e31f, type: 3}
+  m_PrefabInstance: {fileID: 4177563188377789833}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &4554842985378694138
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -2079
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_Text
+      value: SG-1000
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_Text
+      value: SEGA Game 1000
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+      propertyPath: m_Name
+      value: SG-1000
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+--- !u!224 &8545248743875837910 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: a2a595dedf34bfe4f970da5fcaaa0283, type: 3}
+  m_PrefabInstance: {fileID: 4554842985378694138}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &5309173593580639541
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
     m_Modifications:
     - target: {fileID: 734025543935719296, guid: ae0d9b04c112f5b4c98feb0af7ed5676, type: 3}
       propertyPath: m_IsActive
@@ -3066,18 +2576,18 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: ae0d9b04c112f5b4c98feb0af7ed5676, type: 3}
---- !u!224 &7745862243931306566 stripped
+--- !u!224 &5915103534449548264 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ae0d9b04c112f5b4c98feb0af7ed5676, type: 3}
-  m_PrefabInstance: {fileID: 8126049235216200859}
+  m_PrefabInstance: {fileID: 5309173593580639541}
   m_PrefabAsset: {fileID: 0}
---- !u!1001 &8998990446227653727
+--- !u!1001 &5888349638185763442
 PrefabInstance:
   m_ObjectHideFlags: 0
   serializedVersion: 2
   m_Modification:
     serializedVersion: 3
-    m_TransformParent: {fileID: 7954160675638876803}
+    m_TransformParent: {fileID: 4317834147708567278}
     m_Modifications:
     - target: {fileID: 5305486536744057900, guid: a5295d41d2c9aae41bfdf2c9c712074e, type: 3}
       propertyPath: m_Pivot.x
@@ -3176,8 +2686,740 @@ PrefabInstance:
     m_AddedGameObjects: []
     m_AddedComponents: []
   m_SourcePrefab: {fileID: 100100000, guid: a5295d41d2c9aae41bfdf2c9c712074e, type: 3}
---- !u!224 &3837640573846009971 stripped
+--- !u!224 &1735927827576127070 stripped
 RectTransform:
   m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: a5295d41d2c9aae41bfdf2c9c712074e, type: 3}
-  m_PrefabInstance: {fileID: 8998990446227653727}
+  m_PrefabInstance: {fileID: 5888349638185763442}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &6754974452157174658
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 7102897325704768026}
+    m_Modifications:
+    - target: {fileID: 632697230221148209, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Text
+      value: "\u8054\u673A"
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 200
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 203
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: -0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -664
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -245
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 3189920797946144379, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Name
+      value: "\u8054\u673A"
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: ecce24ec6d4b5b546af85d64ba55a3a2, type: 3}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 0.85
+      objectReference: {fileID: 0}
+    - target: {fileID: 8754483333502849411, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 0.85
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects:
+    - targetCorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+      insertIndex: -1
+      addedObject: {fileID: 3912891659551650779}
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+--- !u!224 &5045491097022569823 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 6754974452157174658}
+  m_PrefabAsset: {fileID: 0}
+--- !u!224 &8176807569060777722 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 3226730524206505336, guid: ece591129eb9bcc48bd83ec153c98018, type: 3}
+  m_PrefabInstance: {fileID: 6754974452157174658}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &6883578444828758687
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Text
+      value: "\u6536\u85CF"
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -207
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 7637870703528583553, guid: a8e14774cb9b81d4799116466bc09437, type: 3}
+    - target: {fileID: 3189920797946144379, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Name
+      value: "\u6536\u85CF"
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Text
+      value: "\u5C55\u793A\u6240\u6709\u5E73\u53F0\u6536\u85CF\u7684rom"
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 7637870703528583553, guid: a8e14774cb9b81d4799116466bc09437, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+--- !u!224 &4916857729186405442 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 2ab970ec87696e44a99fdd18821215fc, type: 3}
+  m_PrefabInstance: {fileID: 6883578444828758687}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &7167007059898459913
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -1923
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_Text
+      value: SC-3000
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_Text
+      value: "SEGA Computer 3000\u200B"
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+      propertyPath: m_Name
+      value: SC-3000
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+--- !u!224 &3086809728505469733 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 8fae89702697f0147bad6c542d95ae58, type: 3}
+  m_PrefabInstance: {fileID: 7167007059898459913}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &7250479423501819832
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Text
+      value: NeoGeo
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -831
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    - target: {fileID: 3189920797946144379, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Name
+      value: NeoGeo
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Text
+      value: SNK NeoGeo
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+--- !u!224 &9161925335042560357 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: 7478117b6f7d6cb4cb8c0f5d56205ea1, type: 3}
+  m_PrefabInstance: {fileID: 7250479423501819832}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &7332605178436412274
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -1455
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6906796367924543454, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_Text
+      value: GAME BOY
+      objectReference: {fileID: 0}
+    - target: {fileID: 9003373412835913538, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_Text
+      value: Nintendo GAME BOY
+      objectReference: {fileID: 0}
+    - target: {fileID: 9106117812833555594, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+      propertyPath: m_Name
+      value: GAME BOY
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+--- !u!224 &3198253282780471134 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 5305486536744057900, guid: 16523b967a6221241ab1109d556992f4, type: 3}
+  m_PrefabInstance: {fileID: 7332605178436412274}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &7345880936025361343
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    serializedVersion: 3
+    m_TransformParent: {fileID: 4317834147708567278}
+    m_Modifications:
+    - target: {fileID: 734025543935719296, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_IsActive
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 991446423622995247, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Text
+      value: NES
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Pivot.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Pivot.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchorMax.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchorMax.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchorMin.x
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchorMin.y
+      value: 0.5
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_SizeDelta.x
+      value: 144
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_SizeDelta.y
+      value: 104
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchoredPosition.x
+      value: -72
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_AnchoredPosition.y
+      value: -363
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2619187604372594158, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    - target: {fileID: 3189920797946144379, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Name
+      value: NES
+      objectReference: {fileID: 0}
+    - target: {fileID: 3380485461544738227, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Text
+      value: Nintendo Entertainment System / Family Computer
+      objectReference: {fileID: 0}
+    - target: {fileID: 5331629140490413834, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Alpha
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6771349210554360888, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+      propertyPath: m_Sprite
+      value: 
+      objectReference: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+    m_RemovedComponents: []
+    m_RemovedGameObjects: []
+    m_AddedGameObjects: []
+    m_AddedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+--- !u!224 &9100259551027709282 stripped
+RectTransform:
+  m_CorrespondingSourceObject: {fileID: 1998281097548910301, guid: b170104e466853c49b29f9b5b103364e, type: 3}
+  m_PrefabInstance: {fileID: 7345880936025361343}
   m_PrefabAsset: {fileID: 0}
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab
new file mode 100644
index 00000000..651daa50
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab
@@ -0,0 +1,1129 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &547097114322157613
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2959939562593878400}
+  - component: {fileID: 437203712799690500}
+  - component: {fileID: 4882225280214010061}
+  m_Layer: 5
+  m_Name: RomGroup
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2959939562593878400
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 5615390190915218624}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 1}
+--- !u!114 &437203712799690500
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fdacbe30e88f6a844a435595a4affdbb, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 0
+  m_StartCorner: 0
+  m_StartAxis: 0
+  m_CellSize: {x: 500, y: 200}
+  m_Spacing: {x: 0, y: 20}
+  m_Constraint: 1
+  m_ConstraintCount: 1
+  ItemTemplate: {fileID: 1998281097548910301, guid: e6df0d7c236795247971f0d1e691b068, type: 3}
+  ViewRect: {fileID: 5615390190915218624}
+  PauseUpdateView: 0
+--- !u!114 &4882225280214010061
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalFit: 0
+  m_VerticalFit: 2
+--- !u!1 &1731000361478154045
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 471896259363812078}
+  - component: {fileID: 4047536162787520316}
+  - component: {fileID: 6906796367924543454}
+  - component: {fileID: 7379165731187569985}
+  m_Layer: 5
+  m_Name: Name
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &471896259363812078
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 33}
+  m_Pivot: {x: 0, y: 1}
+--- !u!222 &4047536162787520316
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_CullTransparentMesh: 1
+--- !u!114 &6906796367924543454
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 33a3bdf8f6bd1ec4eba7c4bc58183212, type: 3}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 300
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: NAME
+--- !u!114 &7379165731187569985
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 0, g: 0, b: 0, a: 0.3137255}
+  m_EffectDistance: {x: 3, y: -3}
+  m_UseGraphicAlpha: 1
+--- !u!1 &2384302913435809247
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3127083372996404082}
+  - component: {fileID: 6945246414914211772}
+  - component: {fileID: 6172144285760254677}
+  m_Layer: 5
+  m_Name: Root
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &3127083372996404082
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 460203047818732930}
+  - {fileID: 3161584559533241995}
+  m_Father: {fileID: 5305486536744057900}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0.5}
+  m_AnchorMax: {x: 0, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 130}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &6945246414914211772
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 0
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 1
+  m_ChildControlHeight: 1
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!114 &6172144285760254677
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalFit: 2
+  m_VerticalFit: 0
+--- !u!1 &3538343756569101823
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5169807349761294599}
+  - component: {fileID: 7825479500896033466}
+  - component: {fileID: 7987100532788937847}
+  - component: {fileID: 4168298989964156774}
+  m_Layer: 5
+  m_Name: Image
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5169807349761294599
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 4}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7825479500896033466
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_CullTransparentMesh: 1
+--- !u!114 &7987100532788937847
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &4168298989964156774
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: -1
+  m_PreferredHeight: -1
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &5385582025794088653
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 460203047818732930}
+  - component: {fileID: 3728605797866308165}
+  - component: {fileID: 1144802487456110281}
+  - component: {fileID: 7017134925330126122}
+  m_Layer: 5
+  m_Name: Icon
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &460203047818732930
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4631375053668232476}
+  - {fileID: 6233968584065934053}
+  m_Father: {fileID: 3127083372996404082}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 1, y: 0.5}
+--- !u!222 &3728605797866308165
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_CullTransparentMesh: 1
+--- !u!114 &1144802487456110281
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &7017134925330126122
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 144
+  m_PreferredHeight: 104
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &5418383961348466497
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8062875795445748770}
+  - component: {fileID: 2662717078255122285}
+  - component: {fileID: 3625047787372487136}
+  m_Layer: 5
+  m_Name: SelectArrow
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8062875795445748770
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6233968584065934053}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0.5}
+  m_AnchorMax: {x: 0, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 63, y: 70}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!222 &2662717078255122285
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_CullTransparentMesh: 1
+--- !u!114 &3625047787372487136
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 0
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: -1023481969782777897, guid: d518d00d4940e854bbe45d9ef891401a, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &5941102631143440070
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2512431393477943384}
+  - component: {fileID: 8619900709659458996}
+  - component: {fileID: 9003373412835913538}
+  - component: {fileID: 598358273028336866}
+  m_Layer: 5
+  m_Name: Descript
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2512431393477943384
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 33}
+  m_Pivot: {x: 0, y: 1}
+--- !u!222 &8619900709659458996
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_CullTransparentMesh: 1
+--- !u!114 &9003373412835913538
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 33a3bdf8f6bd1ec4eba7c4bc58183212, type: 3}
+    m_FontSize: 20
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 300
+    m_Alignment: 0
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: SNK NeoGeo
+--- !u!114 &598358273028336866
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 0, g: 0, b: 0, a: 0.3137255}
+  m_EffectDistance: {x: 3, y: -3}
+  m_UseGraphicAlpha: 1
+--- !u!1 &6355781530872251761
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4631375053668232476}
+  - component: {fileID: 178555959028296911}
+  - component: {fileID: 8521572219737141023}
+  - component: {fileID: 5380294627991656309}
+  - component: {fileID: 7817320956777133495}
+  - component: {fileID: 5660897083404887179}
+  m_Layer: 5
+  m_Name: shadowIcon
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &4631375053668232476
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 460203047818732930}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &178555959028296911
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_CullTransparentMesh: 1
+--- !u!114 &8521572219737141023
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &5380294627991656309
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: f8b2ed11d675446c5a49da1ea296d490, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Version: 300
+  m_EffectMaterial: {fileID: 21305736874167728, guid: aee96bc531e6eba468ec405e536f515f, type: 2}
+  m_EffectFactor: 0
+  m_ColorFactor: 0
+  m_BlurFactor: 0
+  m_EffectMode: 0
+  m_ColorMode: 1
+  m_BlurMode: 3
+  m_AdvancedBlur: 1
+  m_ShadowBlur: 1
+  m_ShadowStyle: 0
+  m_ShadowColor: {r: 0, g: 0, b: 0, a: 1}
+  m_EffectDistance: {x: 1, y: -1}
+  m_UseGraphicAlpha: 1
+  m_EffectColor: {r: 1, g: 1, b: 1, a: 1}
+  m_AdditionalShadows: []
+--- !u!114 &7817320956777133495
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0848bff101191904ead4bb831f7084db, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BlurFactor: 1
+  m_Style: 3
+  m_AdditionalShadows: []
+  m_EffectColor: {r: 1, g: 1, b: 1, a: 0}
+  m_EffectDistance: {x: 8, y: 8}
+  m_UseGraphicAlpha: 0
+--- !u!95 &5660897083404887179
+Animator:
+  serializedVersion: 7
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_Avatar: {fileID: 0}
+  m_Controller: {fileID: 9100000, guid: 0b3ccf7414d2ead43be0cd33b6e1b53c, type: 2}
+  m_CullingMode: 0
+  m_UpdateMode: 0
+  m_ApplyRootMotion: 0
+  m_LinearVelocityBlending: 0
+  m_StabilizeFeet: 0
+  m_AnimatePhysics: 0
+  m_WarningMessage: 
+  m_HasTransformHierarchy: 1
+  m_AllowConstantClipSamplingOptimization: 1
+  m_KeepAnimatorStateOnDisable: 0
+  m_WriteDefaultValuesOnDisable: 0
+--- !u!1 &7067879617774535778
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5615390190915218624}
+  - component: {fileID: 889923332512703221}
+  - component: {fileID: 1675349766756430658}
+  m_Layer: 5
+  m_Name: viewport
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5615390190915218624
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2959939562593878400}
+  m_Father: {fileID: 6233968584065934053}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &889923332512703221
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_CullTransparentMesh: 1
+--- !u!114 &1675349766756430658
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 0}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &7311425894574767944
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3161584559533241995}
+  - component: {fileID: 9167458784761723490}
+  - component: {fileID: 2010379511303345659}
+  - component: {fileID: 1744265074350971135}
+  m_Layer: 5
+  m_Name: InfoNode
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &3161584559533241995
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 471896259363812078}
+  - {fileID: 5169807349761294599}
+  - {fileID: 2512431393477943384}
+  m_Father: {fileID: 3127083372996404082}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &9167458784761723490
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 20
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 10
+  m_ChildForceExpandWidth: 1
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 1
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!225 &2010379511303345659
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_Alpha: 0
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!114 &1744265074350971135
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 600
+  m_PreferredHeight: -1
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &7421823347209277103
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6233968584065934053}
+  - component: {fileID: 9045566912386895324}
+  - component: {fileID: 1354521528220721166}
+  - component: {fileID: 8704788976101297821}
+  m_Layer: 5
+  m_Name: RomGroupScroll
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6233968584065934053
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 5615390190915218624}
+  - {fileID: 8062875795445748770}
+  m_Father: {fileID: 460203047818732930}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 1, y: 0.5}
+  m_AnchorMax: {x: 1, y: 0.5}
+  m_AnchoredPosition: {x: 0.000015258789, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &9045566912386895324
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Content: {fileID: 2959939562593878400}
+  m_Horizontal: 0
+  m_Vertical: 1
+  m_MovementType: 0
+  m_Elasticity: 0.1
+  m_Inertia: 1
+  m_DecelerationRate: 0.135
+  m_ScrollSensitivity: 1
+  m_Viewport: {fileID: 5615390190915218624}
+  m_HorizontalScrollbar: {fileID: 0}
+  m_VerticalScrollbar: {fileID: 0}
+  m_HorizontalScrollbarVisibility: 0
+  m_VerticalScrollbarVisibility: 0
+  m_HorizontalScrollbarSpacing: 0
+  m_VerticalScrollbarSpacing: 0
+  m_OnValueChanged:
+    m_PersistentCalls:
+      m_Calls: []
+--- !u!114 &1354521528220721166
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1d1e3e91ac34bc8468f357ee247ffb6a, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_menuItemRoot: {fileID: 0}
+  SubMenuItemTemplate: {fileID: 0}
+  alphaGroup: {fileID: 0}
+  m_selectItemPosition: {x: 50, y: -51}
+  step: 50
+  splitStep: 200
+  m_selectArrow: {fileID: 8062875795445748770}
+  ArrowOffset: 60
+  WidthFix: 280
+  itemGroup: {fileID: 437203712799690500}
+  srollRect: {fileID: 9045566912386895324}
+--- !u!225 &8704788976101297821
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_Alpha: 1
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!1 &9106117812833555594
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5305486536744057900}
+  - component: {fileID: 1952221633680236903}
+  - component: {fileID: 2091811895805808559}
+  m_Layer: 5
+  m_Name: Game_Wonder_Swan_Color_Template
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5305486536744057900
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 3127083372996404082}
+  m_Father: {fileID: 0}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: -72, y: -831}
+  m_SizeDelta: {x: 144, y: 104}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &1952221633680236903
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e2f2e38adaa854144b67512333b1b363, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Icon: {fileID: 1144802487456110281}
+  Txt: {fileID: 6906796367924543454}
+  SubTitle: {fileID: 0}
+  spline: {fileID: 0}
+  Descript: {fileID: 9003373412835913538}
+  Root: {fileID: 3127083372996404082}
+  ShadowIcon: {fileID: 8521572219737141023}
+  InfoNode: {fileID: 2010379511303345659}
+  SubMenuItemGroup: {fileID: 1354521528220721166}
+  SelectScale: 1
+  UnSelectScale: 1
+  RomGroupRoot: {fileID: 8704788976101297821}
+  StarRom: 0
+  Platform: 41
+  SearchKey: 
+--- !u!114 &2091811895805808559
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 200
+  m_PreferredHeight: 230
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab.meta b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab.meta
new file mode 100644
index 00000000..7665d43a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Color_Template.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 017a4e122916b0c489123671b06d9ea7
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab
new file mode 100644
index 00000000..bd60a298
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab
@@ -0,0 +1,1129 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &547097114322157613
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2959939562593878400}
+  - component: {fileID: 437203712799690500}
+  - component: {fileID: 4882225280214010061}
+  m_Layer: 5
+  m_Name: RomGroup
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2959939562593878400
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 5615390190915218624}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 1}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 1}
+--- !u!114 &437203712799690500
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fdacbe30e88f6a844a435595a4affdbb, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 0
+  m_StartCorner: 0
+  m_StartAxis: 0
+  m_CellSize: {x: 500, y: 200}
+  m_Spacing: {x: 0, y: 20}
+  m_Constraint: 1
+  m_ConstraintCount: 1
+  ItemTemplate: {fileID: 1998281097548910301, guid: e6df0d7c236795247971f0d1e691b068, type: 3}
+  ViewRect: {fileID: 5615390190915218624}
+  PauseUpdateView: 0
+--- !u!114 &4882225280214010061
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 547097114322157613}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalFit: 0
+  m_VerticalFit: 2
+--- !u!1 &1731000361478154045
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 471896259363812078}
+  - component: {fileID: 4047536162787520316}
+  - component: {fileID: 6906796367924543454}
+  - component: {fileID: 7379165731187569985}
+  m_Layer: 5
+  m_Name: Name
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &471896259363812078
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 33}
+  m_Pivot: {x: 0, y: 1}
+--- !u!222 &4047536162787520316
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_CullTransparentMesh: 1
+--- !u!114 &6906796367924543454
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 33a3bdf8f6bd1ec4eba7c4bc58183212, type: 3}
+    m_FontSize: 30
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 300
+    m_Alignment: 3
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 1
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: NAME
+--- !u!114 &7379165731187569985
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1731000361478154045}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 0, g: 0, b: 0, a: 0.3137255}
+  m_EffectDistance: {x: 3, y: -3}
+  m_UseGraphicAlpha: 1
+--- !u!1 &2384302913435809247
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3127083372996404082}
+  - component: {fileID: 6945246414914211772}
+  - component: {fileID: 6172144285760254677}
+  m_Layer: 5
+  m_Name: Root
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &3127083372996404082
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 460203047818732930}
+  - {fileID: 3161584559533241995}
+  m_Father: {fileID: 5305486536744057900}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0.5}
+  m_AnchorMax: {x: 0, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 130}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &6945246414914211772
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 0
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 0
+  m_ChildForceExpandWidth: 0
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 1
+  m_ChildControlHeight: 1
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!114 &6172144285760254677
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2384302913435809247}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalFit: 2
+  m_VerticalFit: 0
+--- !u!1 &3538343756569101823
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5169807349761294599}
+  - component: {fileID: 7825479500896033466}
+  - component: {fileID: 7987100532788937847}
+  - component: {fileID: 4168298989964156774}
+  m_Layer: 5
+  m_Name: Image
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5169807349761294599
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 4}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7825479500896033466
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_CullTransparentMesh: 1
+--- !u!114 &7987100532788937847
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &4168298989964156774
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3538343756569101823}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: -1
+  m_PreferredHeight: -1
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &5385582025794088653
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 460203047818732930}
+  - component: {fileID: 3728605797866308165}
+  - component: {fileID: 1144802487456110281}
+  - component: {fileID: 7017134925330126122}
+  m_Layer: 5
+  m_Name: Icon
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &460203047818732930
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4631375053668232476}
+  - {fileID: 6233968584065934053}
+  m_Father: {fileID: 3127083372996404082}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 1, y: 0.5}
+--- !u!222 &3728605797866308165
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_CullTransparentMesh: 1
+--- !u!114 &1144802487456110281
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &7017134925330126122
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5385582025794088653}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 144
+  m_PreferredHeight: 104
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &5418383961348466497
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 8062875795445748770}
+  - component: {fileID: 2662717078255122285}
+  - component: {fileID: 3625047787372487136}
+  m_Layer: 5
+  m_Name: SelectArrow
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &8062875795445748770
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 6233968584065934053}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0.5}
+  m_AnchorMax: {x: 0, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 63, y: 70}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!222 &2662717078255122285
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_CullTransparentMesh: 1
+--- !u!114 &3625047787372487136
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5418383961348466497}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 0
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: -1023481969782777897, guid: d518d00d4940e854bbe45d9ef891401a, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &5941102631143440070
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2512431393477943384}
+  - component: {fileID: 8619900709659458996}
+  - component: {fileID: 9003373412835913538}
+  - component: {fileID: 598358273028336866}
+  m_Layer: 5
+  m_Name: Descript
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &2512431393477943384
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 3161584559533241995}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 33}
+  m_Pivot: {x: 0, y: 1}
+--- !u!222 &8619900709659458996
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_CullTransparentMesh: 1
+--- !u!114 &9003373412835913538
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_FontData:
+    m_Font: {fileID: 12800000, guid: 33a3bdf8f6bd1ec4eba7c4bc58183212, type: 3}
+    m_FontSize: 20
+    m_FontStyle: 0
+    m_BestFit: 0
+    m_MinSize: 2
+    m_MaxSize: 300
+    m_Alignment: 0
+    m_AlignByGeometry: 0
+    m_RichText: 1
+    m_HorizontalOverflow: 0
+    m_VerticalOverflow: 1
+    m_LineSpacing: 1
+  m_Text: SNK NeoGeo
+--- !u!114 &598358273028336866
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5941102631143440070}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: cfabb0440166ab443bba8876756fdfa9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EffectColor: {r: 0, g: 0, b: 0, a: 0.3137255}
+  m_EffectDistance: {x: 3, y: -3}
+  m_UseGraphicAlpha: 1
+--- !u!1 &6355781530872251761
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4631375053668232476}
+  - component: {fileID: 178555959028296911}
+  - component: {fileID: 8521572219737141023}
+  - component: {fileID: 5380294627991656309}
+  - component: {fileID: 7817320956777133495}
+  - component: {fileID: 5660897083404887179}
+  m_Layer: 5
+  m_Name: shadowIcon
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 0
+--- !u!224 &4631375053668232476
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 460203047818732930}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &178555959028296911
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_CullTransparentMesh: 1
+--- !u!114 &8521572219737141023
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 21300000, guid: b12ca21105df97a469be3cf97a4f5fc1, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!114 &5380294627991656309
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: f8b2ed11d675446c5a49da1ea296d490, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Version: 300
+  m_EffectMaterial: {fileID: 21305736874167728, guid: aee96bc531e6eba468ec405e536f515f, type: 2}
+  m_EffectFactor: 0
+  m_ColorFactor: 0
+  m_BlurFactor: 0
+  m_EffectMode: 0
+  m_ColorMode: 1
+  m_BlurMode: 3
+  m_AdvancedBlur: 1
+  m_ShadowBlur: 1
+  m_ShadowStyle: 0
+  m_ShadowColor: {r: 0, g: 0, b: 0, a: 1}
+  m_EffectDistance: {x: 1, y: -1}
+  m_UseGraphicAlpha: 1
+  m_EffectColor: {r: 1, g: 1, b: 1, a: 1}
+  m_AdditionalShadows: []
+--- !u!114 &7817320956777133495
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0848bff101191904ead4bb831f7084db, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_BlurFactor: 1
+  m_Style: 3
+  m_AdditionalShadows: []
+  m_EffectColor: {r: 1, g: 1, b: 1, a: 0}
+  m_EffectDistance: {x: 8, y: 8}
+  m_UseGraphicAlpha: 0
+--- !u!95 &5660897083404887179
+Animator:
+  serializedVersion: 7
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6355781530872251761}
+  m_Enabled: 1
+  m_Avatar: {fileID: 0}
+  m_Controller: {fileID: 9100000, guid: 0b3ccf7414d2ead43be0cd33b6e1b53c, type: 2}
+  m_CullingMode: 0
+  m_UpdateMode: 0
+  m_ApplyRootMotion: 0
+  m_LinearVelocityBlending: 0
+  m_StabilizeFeet: 0
+  m_AnimatePhysics: 0
+  m_WarningMessage: 
+  m_HasTransformHierarchy: 1
+  m_AllowConstantClipSamplingOptimization: 1
+  m_KeepAnimatorStateOnDisable: 0
+  m_WriteDefaultValuesOnDisable: 0
+--- !u!1 &7067879617774535778
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5615390190915218624}
+  - component: {fileID: 889923332512703221}
+  - component: {fileID: 1675349766756430658}
+  m_Layer: 5
+  m_Name: viewport
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5615390190915218624
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2959939562593878400}
+  m_Father: {fileID: 6233968584065934053}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &889923332512703221
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_CullTransparentMesh: 1
+--- !u!114 &1675349766756430658
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7067879617774535778}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 0}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+--- !u!1 &7311425894574767944
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3161584559533241995}
+  - component: {fileID: 9167458784761723490}
+  - component: {fileID: 2010379511303345659}
+  - component: {fileID: 1744265074350971135}
+  m_Layer: 5
+  m_Name: InfoNode
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &3161584559533241995
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 471896259363812078}
+  - {fileID: 5169807349761294599}
+  - {fileID: 2512431393477943384}
+  m_Father: {fileID: 3127083372996404082}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &9167458784761723490
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Padding:
+    m_Left: 20
+    m_Right: 0
+    m_Top: 0
+    m_Bottom: 0
+  m_ChildAlignment: 3
+  m_Spacing: 10
+  m_ChildForceExpandWidth: 1
+  m_ChildForceExpandHeight: 0
+  m_ChildControlWidth: 1
+  m_ChildControlHeight: 0
+  m_ChildScaleWidth: 0
+  m_ChildScaleHeight: 0
+  m_ReverseArrangement: 0
+--- !u!225 &2010379511303345659
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_Alpha: 0
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!114 &1744265074350971135
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7311425894574767944}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 600
+  m_PreferredHeight: -1
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!1 &7421823347209277103
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6233968584065934053}
+  - component: {fileID: 9045566912386895324}
+  - component: {fileID: 1354521528220721166}
+  - component: {fileID: 8704788976101297821}
+  m_Layer: 5
+  m_Name: RomGroupScroll
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6233968584065934053
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 5615390190915218624}
+  - {fileID: 8062875795445748770}
+  m_Father: {fileID: 460203047818732930}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 1, y: 0.5}
+  m_AnchorMax: {x: 1, y: 0.5}
+  m_AnchoredPosition: {x: 0.000015258789, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &9045566912386895324
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Content: {fileID: 2959939562593878400}
+  m_Horizontal: 0
+  m_Vertical: 1
+  m_MovementType: 0
+  m_Elasticity: 0.1
+  m_Inertia: 1
+  m_DecelerationRate: 0.135
+  m_ScrollSensitivity: 1
+  m_Viewport: {fileID: 5615390190915218624}
+  m_HorizontalScrollbar: {fileID: 0}
+  m_VerticalScrollbar: {fileID: 0}
+  m_HorizontalScrollbarVisibility: 0
+  m_VerticalScrollbarVisibility: 0
+  m_HorizontalScrollbarSpacing: 0
+  m_VerticalScrollbarSpacing: 0
+  m_OnValueChanged:
+    m_PersistentCalls:
+      m_Calls: []
+--- !u!114 &1354521528220721166
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1d1e3e91ac34bc8468f357ee247ffb6a, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_menuItemRoot: {fileID: 0}
+  SubMenuItemTemplate: {fileID: 0}
+  alphaGroup: {fileID: 0}
+  m_selectItemPosition: {x: 50, y: -51}
+  step: 50
+  splitStep: 200
+  m_selectArrow: {fileID: 8062875795445748770}
+  ArrowOffset: 60
+  WidthFix: 280
+  itemGroup: {fileID: 437203712799690500}
+  srollRect: {fileID: 9045566912386895324}
+--- !u!225 &8704788976101297821
+CanvasGroup:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7421823347209277103}
+  m_Enabled: 1
+  m_Alpha: 1
+  m_Interactable: 1
+  m_BlocksRaycasts: 1
+  m_IgnoreParentGroups: 0
+--- !u!1 &9106117812833555594
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5305486536744057900}
+  - component: {fileID: 1952221633680236903}
+  - component: {fileID: 2091811895805808559}
+  m_Layer: 5
+  m_Name: Game_Wonder_Swan_Template
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &5305486536744057900
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 3127083372996404082}
+  m_Father: {fileID: 0}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: -72, y: -831}
+  m_SizeDelta: {x: 144, y: 104}
+  m_Pivot: {x: 0, y: 0.5}
+--- !u!114 &1952221633680236903
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e2f2e38adaa854144b67512333b1b363, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Icon: {fileID: 1144802487456110281}
+  Txt: {fileID: 6906796367924543454}
+  SubTitle: {fileID: 0}
+  spline: {fileID: 0}
+  Descript: {fileID: 9003373412835913538}
+  Root: {fileID: 3127083372996404082}
+  ShadowIcon: {fileID: 8521572219737141023}
+  InfoNode: {fileID: 2010379511303345659}
+  SubMenuItemGroup: {fileID: 1354521528220721166}
+  SelectScale: 1
+  UnSelectScale: 1
+  RomGroupRoot: {fileID: 8704788976101297821}
+  StarRom: 0
+  Platform: 40
+  SearchKey: 
+--- !u!114 &2091811895805808559
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9106117812833555594}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: 200
+  m_PreferredHeight: 230
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab.meta b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab.meta
new file mode 100644
index 00000000..c6887046
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/SubMenuItemTemplates/Game_Wonder_Swan_Template.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 6b9cf0040ec05e742aa8ca739b5f6adf
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
index b7f7eaf3..24d5e068 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
@@ -6,7 +6,8 @@
         "VirtualNes.Core",
         "UIEffect2018",
         "Mame.Core",
-        "Essgee.Unity"
+        "Essgee.Unity",
+        "StoicGooseUnity"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs
index 57ad9e97..aeca7de5 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgee.cs
@@ -38,7 +38,7 @@ public class UEssgee : MonoBehaviour, IEmuCore
     UEGSoundPlayer soundHandler;
     GameMetadataHandler gameMetadataHandler;
     GameMetadata lastGameMetadata;
-    EmulatorHandler emulatorHandler;
+    Essgee.Emulation.EmulatorHandler emulatorHandler;
     UEGResources uegResources;
     UEGLog uegLog;
     UEGSaveByteConvert uegSaveByteConvert;
@@ -297,7 +297,7 @@ public class UEssgee : MonoBehaviour, IEmuCore
         //    EmuStandInfo.Configuration.SerializeToFile(EmuStandInfo.programConfigPath);
         //}
 
-        EmuStandInfo.Configuration = new Configuration();
+        EmuStandInfo.Configuration = new Essgee.Configuration();
 
         List<Type> machineType = new List<Type>();
         machineType.Add(typeof(GameBoy));
@@ -505,7 +505,7 @@ public class UEssgee : MonoBehaviour, IEmuCore
         if (emulatorHandler != null)
             ShutdownEmulation();
 
-        emulatorHandler = new EmulatorHandler(machineType, ExceptionHandler, uegSaveByteConvert);
+        emulatorHandler = new Essgee.Emulation.EmulatorHandler(machineType, ExceptionHandler, uegSaveByteConvert);
         emulatorHandler.Initialize();
 
         emulatorHandler.SendLogMessage += EmulatorHandler_SendLogMessage;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator.meta
new file mode 100644
index 00000000..8d46363a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 218c1e917c9305445b77d6ee8c43c78f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common.meta
new file mode 100644
index 00000000..a3932718
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 27413e559e2279046810313f807b4880
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs
new file mode 100644
index 00000000..45b2bfb1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs
@@ -0,0 +1,89 @@
+using StoicGoose.Common.Utilities;
+using System.Collections.Generic;
+
+
+public sealed class Configuration : ConfigurationBase<Configuration>
+{
+    //[DisplayName("General")]
+    //[Description("General settings.")]
+    public GeneralConfiguration General { get; set; } = new GeneralConfiguration();
+    //[DisplayName("Video")]
+    //[Description("Settings related to video output.")]
+    public VideoConfiguration Video { get; set; } = new VideoConfiguration();
+    //[DisplayName("Sound")]
+    //[Description("Settings related to sound output.")]
+    public SoundConfiguration Sound { get; set; } = new SoundConfiguration();
+    //[DisplayName("Input")]
+    //[Description("Settings related to emulation input.")]
+    public InputConfiguration Input { get; set; } = new InputConfiguration();
+}
+
+public sealed class GeneralConfiguration : ConfigurationBase<GeneralConfiguration>
+{
+    //[DisplayName("Prefer Original WS")]
+    //[Description("Prefer emulation of the original non-Color system.")]
+    public bool PreferOriginalWS { get; set; } = false;
+    //[DisplayName("Use Bootstrap ROM")]
+    //[Description("Toggle using WonderSwan bootstrap ROM images.")]
+    public bool UseBootstrap { get; set; } = false;
+    //[DisplayName("WS Bootstrap ROM Path")]
+    //[Description("Path to the WonderSwan bootstrap ROM image to use.")]
+    public string BootstrapFile { get; set; } = string.Empty;
+    //[DisplayName("WSC Bootstrap ROM Path")]
+    //[Description("Path to the WonderSwan Color bootstrap ROM image to use.")]
+    public string BootstrapFileWSC { get; set; } = string.Empty;
+    //[DisplayName("Limit FPS")]
+    //[Description("Toggle limiting the framerate to the system's native ~75.47 Hz.")]
+    public bool LimitFps { get; set; } = true;
+    //[DisplayName("Enable Cheats")]
+    //[Description("Toggle using the cheat system.")]
+    public bool EnableCheats { get; set; } = true;
+    //[DisplayName("Recent Files")]
+    //[Description("List of recently loaded files.")]
+    //public List<string> RecentFiles { get; set; } = new List<string>(15);
+}
+
+public sealed class VideoConfiguration : ConfigurationBase<VideoConfiguration>
+{
+    //[DisplayName("Screen Size")]
+    //[Description("Size of the emulated screen, in times original display resolution.")]
+    public int ScreenSize { get; set; } = 3;
+    //[DisplayName("Shader")]
+    //[Description("Currently selected shader.")]
+    public string Shader { get; set; } = string.Empty;
+    //[DisplayName("Brightness")]
+    //[Description("Adjust the brightness of the emulated screen, in percent.")]
+    //[Range(-100, 100)]
+    public int Brightness { get; set; } = 0;
+    //[DisplayName("Contrast")]
+    //[Description("Adjust the contrast of the emulated screen, in percent.")]
+    //[Range(0, 200)]
+    public int Contrast { get; set; } = 100;
+    //[DisplayName("Saturation")]
+    //[Description("Adjust the saturation of the emulated screen, in percent.")]
+    //[Range(0, 200)]
+    public int Saturation { get; set; } = 100;
+}
+
+public sealed class SoundConfiguration : ConfigurationBase<SoundConfiguration>
+{
+    //[DisplayName("Mute")]
+    //[Description("Toggles muting all sound output.")]
+    public bool Mute { get; set; } = false;
+    //[DisplayName("Low-Pass Filter")]
+    //[Description("Toggles low-pass filter for all sound output.")]
+    public bool LowPassFilter { get; set; } = true;
+}
+
+public sealed class InputConfiguration : ConfigurationBase<InputConfiguration>
+{
+    //[DisplayName("Automatic Remapping")]
+    //[Description("Automatically remap X-/Y-pads with game orientation.")]
+    public bool AutoRemap { get; set; } = true;
+    //[DisplayName("Game Controls")]
+    //[Description("Controls related to game input, i.e. X-/Y-pads, etc.")]
+    public Dictionary<string, List<string>> GameControls { get; set; } = new Dictionary<string, List<string>>();
+    //[DisplayName("System Controls")]
+    //[Description("Controls related to hardware functions, i.e. volume button.")]
+    public Dictionary<string, List<string>> SystemControls { get; set; } = new Dictionary<string, List<string>>();
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs.meta
new file mode 100644
index 00000000..e43254f8
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/Configuration.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: ee0a5e22651983e479915e5429079d99
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs
new file mode 100644
index 00000000..e493c9ba
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Reflection;
+
+
+public static class GlobalVariables
+{
+    public static readonly bool IsAuthorsMachine = System.Environment.MachineName == "KAMIKO";
+#if DEBUG
+    public static readonly bool IsDebugBuild = true;
+#else
+		public static readonly bool IsDebugBuild = false;
+#endif
+    public static readonly bool EnableLocalDebugIO = IsAuthorsMachine;
+
+    public static readonly bool EnableSuperVerbosity = false;
+    public static readonly bool EnableOpenGLDebug = false;
+
+    public static readonly bool EnableSkipBootstrapIfFound = false;
+
+    public static string[] Dump()
+    {
+        var vars = new List<string>();
+        foreach (var fieldInfo in typeof(GlobalVariables).GetFields(BindingFlags.Static | BindingFlags.Public))
+            vars.Add($"{fieldInfo.Name} == {fieldInfo.GetValue(null)}");
+        return vars.ToArray();
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs.meta
new file mode 100644
index 00000000..b35cc907
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Common/GlobalVariables.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 043ec2227e850204faefe0ce10f2ae04
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle.meta
new file mode 100644
index 00000000..e67f73d3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cb360a28c0621034ea0d310e18e5a747
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs
new file mode 100644
index 00000000..01953a32
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xml.Serialization;
+using StoicGoose.Common.Utilities;
+
+public sealed class DatabaseHandler
+{
+    readonly Dictionary<string, DatFile> datFiles = new();
+    const string ResourceRoot = "StoicGooseUnity/emu/";
+
+    public DatabaseHandler()
+    {
+        {
+            string wsc = "Bandai - WonderSwan Color.dat";
+            GetDatBytes(wsc, out byte[] loadedData);
+            using (MemoryStream stream = new MemoryStream(loadedData))
+            {
+                var root = new XmlRootAttribute("datafile") { IsNullable = true };
+                var serializer = new XmlSerializer(typeof(DatFile), root);
+                var reader = XmlReader.Create(stream, new() { DtdProcessing = DtdProcessing.Ignore });
+                datFiles.Add(Path.GetFileName(wsc), (DatFile)serializer.Deserialize(reader));
+            }
+        }
+
+        {
+            string ws = "Bandai - WonderSwan.dat";
+            GetDatBytes(ws, out byte[] loadedData);
+            using (MemoryStream stream = new MemoryStream(loadedData))
+            {
+                var root = new XmlRootAttribute("datafile") { IsNullable = true };
+                var serializer = new XmlSerializer(typeof(DatFile), root);
+                var reader = XmlReader.Create(stream, new() { DtdProcessing = DtdProcessing.Ignore });
+                datFiles.Add(Path.GetFileName(ws), (DatFile)serializer.Deserialize(reader));
+            }
+        }
+
+        Log.WriteEvent(LogSeverity.Information, this, $"Loaded {datFiles.Count} .dat file(s) with {datFiles.Sum(x => x.Value.Game.Length)} known game(s).");
+        foreach (var datFile in datFiles.Select(x => x.Value))
+            Log.WriteLine($" '{datFile.Header.Name} ({datFile.Header.Version})' from {datFile.Header.Homepage}");
+    }
+
+    bool GetDatBytes(string DatName, out byte[] loadedData)
+    {
+        try
+        {
+            loadedData = UnityEngine.Resources.Load<UnityEngine.TextAsset>(ResourceRoot + "Dat/" + DatName).bytes;
+            return true;
+        }
+        catch
+        {
+            loadedData = null;
+            return false;
+        }
+    }
+
+    private DatGame GetGame(uint romCrc32, int romSize)
+    {
+        return datFiles.Select(x => x.Value.Game).Select(x => x.FirstOrDefault(x => x.Rom.Any(y => y.Crc.ToLowerInvariant() == $"{romCrc32:x8}" && y.Size.ToLowerInvariant() == $"{romSize:D}"))).FirstOrDefault(x => x != null);
+    }
+
+    public string GetGameTitle(uint romCrc32, int romSize)
+    {
+        return GetGame(romCrc32, romSize)?.Name.Replace("&", "&&") ?? "unrecognized game";
+    }
+
+    public class DatHeader
+    {
+        [XmlElement("name")]
+        public string Name { get; set; }
+        [XmlElement("description")]
+        public string Description { get; set; }
+        [XmlElement("category")]
+        public string Category { get; set; }
+        [XmlElement("version")]
+        public string Version { get; set; }
+        [XmlElement("date")]
+        public string Date { get; set; }
+        [XmlElement("author")]
+        public string Author { get; set; }
+        [XmlElement("email")]
+        public string Email { get; set; }
+        [XmlElement("homepage")]
+        public string Homepage { get; set; }
+        [XmlElement("url")]
+        public string Url { get; set; }
+        [XmlElement("comment")]
+        public string Comment { get; set; }
+    }
+
+    public class DatRelease
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+        [XmlAttribute("region")]
+        public string Region { get; set; }
+        [XmlAttribute("language")]
+        public string Language { get; set; }
+        [XmlAttribute("date")]
+        public string Date { get; set; }
+        [XmlAttribute("default")]
+        public string Default { get; set; }
+    }
+
+    public class DatBiosSet
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+        [XmlAttribute("description")]
+        public string Description { get; set; }
+        [XmlAttribute("default")]
+        public string Default { get; set; }
+    }
+
+    public class DatRom
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+        [XmlAttribute("size")]
+        public string Size { get; set; }
+        [XmlAttribute("crc")]
+        public string Crc { get; set; }
+        [XmlAttribute("sha1")]
+        public string Sha1 { get; set; }
+        [XmlAttribute("md5")]
+        public string Md5 { get; set; }
+        [XmlAttribute("merge")]
+        public string Merge { get; set; }
+        [XmlAttribute("status")]
+        public string Status { get; set; }
+        [XmlAttribute("date")]
+        public string Date { get; set; }
+    }
+
+    public class DatDisk
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+        [XmlAttribute("sha1")]
+        public string Sha1 { get; set; }
+        [XmlAttribute("md5")]
+        public string Md5 { get; set; }
+        [XmlAttribute("merge")]
+        public string Merge { get; set; }
+        [XmlAttribute("status")]
+        public string Status { get; set; }
+    }
+
+    public class DatSample
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+    }
+
+    public class DatArchive
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+    }
+
+    public class DatGame
+    {
+        [XmlAttribute("name")]
+        public string Name { get; set; }
+        [XmlAttribute("sourcefile")]
+        public string SourceFile { get; set; }
+        [XmlAttribute("isbios")]
+        public string IsBios { get; set; }
+        [XmlAttribute("cloneof")]
+        public string CloneOf { get; set; }
+        [XmlAttribute("romof")]
+        public string RomOf { get; set; }
+        [XmlAttribute("sampleof")]
+        public string SampleOf { get; set; }
+        [XmlAttribute("board")]
+        public string Board { get; set; }
+        [XmlAttribute("rebuildto")]
+        public string RebuildTo { get; set; }
+
+        [XmlElement("year")]
+        public string Year { get; set; }
+        [XmlElement("manufacturer")]
+        public string Manufacturer { get; set; }
+
+        [XmlElement("release")]
+        public DatRelease[] Release { get; set; }
+
+        [XmlElement("biosset")]
+        public DatBiosSet[] BiosSet { get; set; }
+
+        [XmlElement("rom")]
+        public DatRom[] Rom { get; set; }
+
+        [XmlElement("disk")]
+        public DatDisk[] Disk { get; set; }
+
+        [XmlElement("sample")]
+        public DatSample[] Sample { get; set; }
+
+        [XmlElement("archive")]
+        public DatArchive[] Archive { get; set; }
+    }
+
+    [Serializable()]
+    public class DatFile
+    {
+        [XmlElement("header")]
+        public DatHeader Header { get; set; }
+
+        [XmlElement("game")]
+        public DatGame[] Game { get; set; }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs.meta
new file mode 100644
index 00000000..8dcc4098
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/DatabaseHandler.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 28105de94482c1643b7398d0bbb32af2
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs
new file mode 100644
index 00000000..cb268120
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs
@@ -0,0 +1,133 @@
+using StoicGoose.Core.Interfaces;
+using StoicGooseUnity;
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+public class EmulatorHandler
+{
+    readonly static string threadName = $"Unity_Emulation";
+
+    //Thread thread = default;
+    volatile bool threadRunning = false, threadPaused = false;
+
+    volatile bool isResetRequested = false;
+    volatile bool isPauseRequested = false, newPauseState = false;
+    volatile bool isFpsLimiterChangeRequested = false, limitFps = true, newLimitFps = false;
+
+    public bool IsRunning => threadRunning;
+    public bool IsPaused => threadPaused;
+
+    public IMachine Machine { get; } = default;
+    public int AxiEmuRunFrame { get; private set; }
+
+    public EmulatorHandler(Type machineType)
+    {
+        StoicGooseUnityAxiMem.Init();
+        Machine = Activator.CreateInstance(machineType) as IMachine;
+        Machine.Initialize();
+    }
+
+    public void Startup()
+    {
+        Machine.Reset();
+
+        threadRunning = true;
+        threadPaused = false;
+
+        //thread = new Thread(ThreadMainLoop) { Name = threadName, Priority = ThreadPriority.AboveNormal, IsBackground = false };
+        //thread.Start();
+        AxiEmuRunFrame = 0;
+    }
+
+    public void Reset()
+    {
+        isResetRequested = true;
+    }
+
+    public void Pause()
+    {
+        isPauseRequested = true;
+        newPauseState = true;
+    }
+
+    public void Unpause()
+    {
+        isPauseRequested = true;
+        newPauseState = false;
+    }
+
+    public void Shutdown()
+    {
+        threadRunning = false;
+        threadPaused = false;
+        //thread?.Join();
+        Machine.Shutdown();
+        StoicGooseUnityAxiMem.FreeAllGCHandle();
+    }
+
+    public void SetFpsLimiter(bool value)
+    {
+        isFpsLimiterChangeRequested = true;
+        newLimitFps = value;
+    }
+
+    private void ThreadMainLoop()
+    {
+        var stopWatch = Stopwatch.StartNew();
+        var interval = 1000.0 / Machine.RefreshRate;
+        var lastTime = 0.0;
+
+        while (true)
+        {
+            if (!threadRunning) break;
+
+            if (isResetRequested)
+            {
+                Machine.Reset();
+                stopWatch.Restart();
+                lastTime = 0.0;
+
+                isResetRequested = false;
+            }
+
+            if (isPauseRequested)
+            {
+                threadPaused = newPauseState;
+                isPauseRequested = false;
+            }
+
+            if (isFpsLimiterChangeRequested)
+            {
+                limitFps = newLimitFps;
+                isFpsLimiterChangeRequested = false;
+            }
+
+            if (!threadPaused)
+            {
+                if (limitFps)
+                {
+                    while ((stopWatch.Elapsed.TotalMilliseconds - lastTime) < interval)
+                        Thread.Sleep(0);
+
+                    lastTime += interval;
+                }
+                else
+                    lastTime = stopWatch.Elapsed.TotalMilliseconds;
+
+                Machine.RunFrame();
+            }
+            else
+                lastTime = stopWatch.Elapsed.TotalMilliseconds;
+        }
+    }
+
+    public void Frame_Update()
+    {
+        if (!threadRunning || !threadPaused)
+            return;
+
+        Machine.RunFrame();
+        AxiEmuRunFrame++;
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs.meta
new file mode 100644
index 00000000..4aa9582a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/Handle/EmulatorHandler.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: da891d0a5babf7649992f83861f6f33d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface.meta
new file mode 100644
index 00000000..e736b368
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8193f4d4ec66bb441b59f6549e95e013
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs
new file mode 100644
index 00000000..716f8f5d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs
@@ -0,0 +1,52 @@
+using StoicGooseUnity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+public class SGKeyboard : MonoBehaviour
+{
+    Dictionary<KeyCode, StoicGooseKey> dictKey2SGKey = new Dictionary<KeyCode, StoicGooseKey>();
+    KeyCode[] checkKeys;
+    long currInput;
+    private void Awake()
+    {
+        SetVerticalOrientation(false);
+    }
+
+
+    internal void PollInput(ref long buttonsHeld)
+    {
+        buttonsHeld = currInput;
+    }
+
+    internal void SetVerticalOrientation(bool isVerticalOrientation)
+    {
+        dictKey2SGKey[KeyCode.Return] = StoicGooseKey.Start;
+        dictKey2SGKey[KeyCode.W] = StoicGooseKey.X1;
+        dictKey2SGKey[KeyCode.S] = StoicGooseKey.X2;
+        dictKey2SGKey[KeyCode.A] = StoicGooseKey.X3;
+        dictKey2SGKey[KeyCode.D] = StoicGooseKey.X4;
+        dictKey2SGKey[KeyCode.G] = StoicGooseKey.Y1;
+        dictKey2SGKey[KeyCode.V] = StoicGooseKey.Y2;
+        dictKey2SGKey[KeyCode.C] = StoicGooseKey.Y3;
+        dictKey2SGKey[KeyCode.B] = StoicGooseKey.Y4;
+        dictKey2SGKey[KeyCode.Return] = StoicGooseKey.Start;
+        dictKey2SGKey[KeyCode.J] = StoicGooseKey.B;
+        dictKey2SGKey[KeyCode.K] = StoicGooseKey.A;
+        checkKeys = dictKey2SGKey.Keys.ToArray();
+    }
+
+    public void Update_InputData()
+    {
+        currInput = 0;
+        for (int i = 0; i < checkKeys.Length; i++)
+        {
+            KeyCode key = checkKeys[i];
+            if (Input.GetKey(key))
+            {
+                currInput |= (long)dictKey2SGKey[key];
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs.meta
new file mode 100644
index 00000000..6d44ae03
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGKeyboard.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 54c184e653057e64da4b9be96f4d876d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs
new file mode 100644
index 00000000..19fcea2e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs
@@ -0,0 +1,36 @@
+using StoicGoose.Common.Utilities;
+using System;
+
+public class SGLogger : IStoicGooseLogger
+{
+    public void Debug(string message)
+    {
+        UnityEngine.Debug.Log(message);
+    }
+
+    public void Err(string message)
+    {
+        UnityEngine.Debug.LogError(message);
+    }
+
+    public void Log(StoicGoose.Common.Utilities.LogType logtype, string message)
+    {
+        switch (logtype)
+        {
+            case LogType.Debug:
+                Debug(message);
+                break;
+            case LogType.Warning:
+                Warning(message);
+                break;
+            case LogType.Error:
+                Err(message);
+                break;
+        }
+    }
+
+    public void Warning(string message)
+    {
+        UnityEngine.Debug.LogWarning(message);
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs.meta
new file mode 100644
index 00000000..9ac0db44
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGLogger.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e9f99144ff5ead44297997370fab702c
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs
new file mode 100644
index 00000000..11279d35
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class SGSoundPlayer : MonoBehaviour//, ISoundPlayer
+{
+    [SerializeField]
+    private AudioSource m_as;
+    private RingBuffer<float> _buffer = new RingBuffer<float>(44100 * 2);
+    private TimeSpan lastElapsed;
+    public double audioFPS { get; private set; }
+
+    void Awake()
+    {
+        // ��ȡ��ǰ��Ƶ����
+        AudioConfiguration config = AudioSettings.GetConfiguration();
+
+        // ����Ŀ����Ƶ����
+        config.sampleRate = 44100;       // ������Ϊ 44100Hz
+        config.numRealVoices = 32;      // ���������ƵԴ��������ѡ��
+        config.numVirtualVoices = 512;   // ����������ƵԴ��������ѡ��
+        config.dspBufferSize = 1024;     // ���� DSP ��������С����ѡ��
+        config.speakerMode = AudioSpeakerMode.Stereo; // ������������2 ������
+
+        // Ӧ���µ���Ƶ����
+        if (AudioSettings.Reset(config))
+        {
+            Debug.Log("Audio settings updated successfully.");
+            Debug.Log("Sample Rate: " + config.sampleRate + "Hz");
+            Debug.Log("Speaker Mode: " + config.speakerMode);
+        }
+        else
+        {
+            Debug.LogError("Failed to update audio settings.");
+        }
+
+    }
+
+    private Queue<float> sampleQueue = new Queue<float>();
+
+
+    // Unity ��Ƶ�̻߳ص�
+    void OnAudioFilterRead(float[] data, int channels)
+    {
+        for (int i = 0; i < data.Length; i++)
+        {
+            if (_buffer.TryRead(out float rawData))
+                data[i] = rawData;
+            else
+                data[i] = 0; // ������ʱ����
+        }
+    }
+
+
+    public void Initialize()
+    {
+        if (!m_as.isPlaying)
+        {
+            m_as.Play();
+        }
+    }
+
+    public void StopPlay()
+    {
+        if (m_as.isPlaying)
+        {
+            m_as.Stop();
+        }
+    }
+
+    //public void SubmitSamples(short[] buffer, short[][] ChannelSamples, int samples_a)
+    //{
+    //    var current = UStoicGoose.sw.Elapsed;
+    //    var delta = current - lastElapsed;
+    //    lastElapsed = current;
+    //    audioFPS = 1d / delta.TotalSeconds;
+
+    //    for (int i = 0; i < samples_a; i += 1)
+    //    {
+    //        _buffer.Write(buffer[i] / 32767.0f);
+
+    //    }
+    //}
+    public void BufferWirte(int Off, byte[] Data)
+    {
+    }
+
+    public void GetCurrentPosition(out int play_position, out int write_position)
+    {
+        play_position = 0;
+        write_position = 0;
+    }
+
+    public void SetVolume(int Vol)
+    {
+        //TODO ����
+        if (m_as)
+            return;
+        m_as.volume = Vol;
+    }
+
+
+    internal void EnqueueSamples(short[] buffer)
+    {
+        var current = UStoicGoose.sw.Elapsed;
+        var delta = current - lastElapsed;
+        lastElapsed = current;
+        audioFPS = 1d / delta.TotalSeconds;
+
+        for (int i = 0; i < buffer.Length; i += 1)
+        {
+            _buffer.Write(buffer[i] / 32767.0f);
+        }
+    }
+
+    internal void Unpause()
+    {
+        throw new NotImplementedException();
+    }
+
+    internal void Pause()
+    {
+        throw new NotImplementedException();
+    }
+
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs.meta
new file mode 100644
index 00000000..f4fa8e10
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGSoundPlayer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 925771571ae9709429297d42587ce36d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs
new file mode 100644
index 00000000..0c663ea9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs
@@ -0,0 +1,113 @@
+using System;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class SGVideoPlayer : MonoBehaviour
+{
+
+    [SerializeField]
+    private int mWidth;
+    [SerializeField]
+    private int mHeight;
+    [SerializeField]
+    private int mDataLenght;
+    [SerializeField]
+    private Texture2D m_rawBufferWarper;
+    [SerializeField]
+    private RawImage m_drawCanvas;
+    [SerializeField]
+    private RectTransform m_drawCanvasrect;
+    //byte[] mFrameData;
+    IntPtr mFrameDataPtr;
+    public Texture2D rawBufferWarper => m_rawBufferWarper;
+    public RawImage DrawCanvas => m_drawCanvas;
+    private TimeSpan lastElapsed;
+    public double videoFPS { get; private set; }
+    public ulong mFrame { get; private set; }
+    bool bInit = false;
+    bool bHadData = false;
+
+    private void Awake()
+    {
+        bHadData = false;
+        mFrame = 0;
+        m_drawCanvas = GameObject.Find("GameRawImage").GetComponent<RawImage>();
+        m_drawCanvasrect = m_drawCanvas.GetComponent<RectTransform>();
+    }
+
+    public void Initialize()
+    {
+        m_drawCanvas.color = Color.white;
+
+        if (m_rawBufferWarper == null)
+        {
+            mDataLenght = mWidth * mHeight * 4;
+            //mFrameData = new byte[mDataLenght];
+
+            //// �̶����飬��ֹ�����������ƶ���  
+            //var bitmapcolorRect_handle = GCHandle.Alloc(mFrameData, GCHandleType.Pinned);
+            //// ��ȡ�����ָ��  
+            //mFrameDataPtr = bitmapcolorRect_handle.AddrOfPinnedObject();
+
+
+            //MAME������BGRA32���úú�
+            m_rawBufferWarper = new Texture2D(mWidth, mHeight, TextureFormat.BGRA32, false);
+            //m_rawBufferWarper = new Texture2D(mWidth, mHeight, TextureFormat.ARGB32, false);
+            m_rawBufferWarper.filterMode = FilterMode.Point;
+        }
+
+        //mFrameDataPtr = framePtr;
+        m_drawCanvas.texture = m_rawBufferWarper;
+        bInit = true;
+
+        float targetWidth = ((float)mWidth / mHeight) * m_drawCanvasrect.rect.height;
+        m_drawCanvasrect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, targetWidth);
+    }
+
+    public void StopVideo()
+    {
+        bInit = false;
+        m_drawCanvas.color = new Color(0, 0, 0, 0);
+    }
+
+    void Update()
+    {
+        if (!bHadData
+            ||
+            !UStoicGoose.instance.emulatorHandler.IsRunning)
+            return;
+
+        if (!bInit)
+        {
+            Initialize();
+            return;
+        }
+        m_rawBufferWarper.LoadRawTextureData(mFrameDataPtr, mDataLenght);
+        m_rawBufferWarper.Apply();
+    }
+
+
+    public byte[] GetScreenImg()
+    {
+        return (m_drawCanvas.texture as Texture2D).EncodeToJPG();
+    }
+
+    public bool IsVerticalOrientation { get; internal set; }
+
+    internal void UpdateScreen(IntPtr ptr, long frame_number)
+    {
+        var current = UStoicGoose.sw.Elapsed;
+        var delta = current - lastElapsed;
+        lastElapsed = current;
+        videoFPS = 1d / delta.TotalSeconds;
+        mFrameDataPtr = ptr;
+        if (!bHadData)
+            bHadData = true;
+    }
+
+    internal void SetSize(int screenWidth, int screenHeight)
+    {
+        mWidth = screenWidth;
+        mHeight = screenHeight;
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs.meta
new file mode 100644
index 00000000..519fd5e1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/StoicGooseInterface/SGVideoPlayer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e8778828cf820b640b9d26ae977cdaba
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs
new file mode 100644
index 00000000..f749ac88
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs
@@ -0,0 +1,717 @@
+using AxibugEmuOnline.Client;
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugProtobuf;
+using StoicGoose.Common.Utilities;
+using StoicGoose.Core.Machines;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.UI;
+using CartridgeMetadata = StoicGoose.Core.Cartridges.Metadata;
+
+public class UStoicGoose : MonoBehaviour, IEmuCore
+{
+    public static UStoicGoose instance;
+    public static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
+
+    /* Constants */
+    readonly static int maxScreenSizeFactor = 5;
+    readonly static int maxRecentFiles = 15;
+    readonly static int statusIconSize = 12;
+
+    readonly static List<(string description, string extension, Func<string, Stream> streamReadFunc)> supportedFileInformation = new()
+        {
+            ("WonderSwan ROMs", ".ws", GetStreamFromFile),
+            ("WonderSwan Color ROMs", ".wsc", GetStreamFromFile),
+            ("Zip Archives", ".zip", GetStreamFromFirstZippedFile)
+        };
+
+    /* Various handlers */
+    DatabaseHandler databaseHandler = default;
+    SGVideoPlayer graphicsHandler = default;
+    SGSoundPlayer soundHandler = default;
+    SGKeyboard inputHandler = default;
+    SGLogger loggerHandler = default;
+    public EmulatorHandler emulatorHandler = default;
+    private RomPlatformType mPlatform = RomPlatformType.WonderSwan;
+
+    /* Misc. windows */
+    //SoundRecorderForm soundRecorderForm = default;
+    //CheatsForm cheatsForm = default;
+
+    /* Misc. runtime variables */
+    Type machineType = default;
+    bool isVerticalOrientation = false;
+    string internalEepromPath = string.Empty;
+
+    public string CurrRomName { get; private set; }
+
+    #region 实现IEmuCore
+    public RomPlatformType Platform => mPlatform;
+
+    public uint Frame => (uint)emulatorHandler.AxiEmuRunFrame;
+
+    public Texture OutputPixel => graphicsHandler.rawBufferWarper;
+
+    public RawImage DrawCanvas => graphicsHandler.DrawCanvas;
+    public object GetState()
+    {
+        throw new NotImplementedException();
+    }
+
+    public byte[] GetStateBytes()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void LoadState(object state)
+    {
+        throw new NotImplementedException();
+    }
+
+    public void LoadStateFromBytes(byte[] data)
+    {
+        throw new NotImplementedException();
+    }
+
+    public void Pause()
+    {
+        PauseEmulation();
+    }
+
+    public void Resume()
+    {
+        UnpauseEmulation();
+    }
+
+    public MsgBool StartGame(RomFile romFile)
+    {
+        mPlatform = romFile.Platform;
+
+        Init();
+
+
+        //保存当前正在进行的游戏存档
+        if (emulatorHandler != null && !emulatorHandler.IsRunning)
+        {
+            SaveAllData();
+        }
+
+        if (LoadAndRunCartridge(romFile.LocalFilePath))
+            return true;
+        else
+            return "Rom加载失败";
+    }
+
+    public void Dispose()
+    {
+        //保存当前正在进行的游戏存档
+        if (emulatorHandler != null && !emulatorHandler.IsRunning)
+        {
+            SaveAllData();
+        }
+        EmuClose();
+    }
+
+    public void DoReset()
+    {
+        ResetEmulation();
+    }
+
+    public IControllerSetuper GetControllerSetuper()
+    {
+        throw new NotImplementedException();
+    }
+
+    public bool PushEmulatorFrame()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void AfterPushFrame()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void GetAudioParams(out int frequency, out int channels)
+    {
+        throw new NotImplementedException();
+    }
+    #endregion
+
+    //Cheat[] cheats = default;
+
+    #region Unity 生命周期
+
+    void Awake()
+    {
+        //关闭垂直同步
+        QualitySettings.vSyncCount = 0;
+        //设为60帧
+        Application.targetFrameRate = 60;
+
+        instance = this;
+        loggerHandler = new SGLogger();
+        graphicsHandler = this.gameObject.GetComponent<SGVideoPlayer>();
+        soundHandler = this.gameObject.GetComponent<SGSoundPlayer>();
+        inputHandler = this.gameObject.GetComponent<SGKeyboard>();
+        Log.Initialize(loggerHandler);
+        Program.InitPath(Application.persistentDataPath);
+        //Init();
+        //LoadAndRunCartridge("G:/BaiduNetdiskDownload/Rockman & Forte - Mirai Kara no Chousen Sha (J) [M][!].ws");
+    }
+    private void Update()
+    {
+        if (!emulatorHandler.IsRunning)
+            return;
+
+        inputHandler.Update_InputData();
+
+        emulatorHandler.Frame_Update();
+    }
+    void OnDestroy()
+    {
+        EmuClose();
+    }
+    #endregion
+    private void Init()
+    {
+        Log.WriteEvent(LogSeverity.Information, this, "Initializing emulator and UI...");
+
+        machineType = Program.Configuration.General.PreferOriginalWS ? typeof(WonderSwan) : typeof(WonderSwanColor);
+
+        InitializeEmulatorHandler();
+        VerifyConfiguration();
+        InitializeOtherHandlers();
+        //InitializeWindows();
+
+        //SizeAndPositionWindow();
+        SetWindowTitleAndStatus();
+        Log.WriteEvent(LogSeverity.Information, this, "Initialization done!");
+    }
+
+
+    private void EmuClose()
+    {
+        SaveAllData();
+        emulatorHandler.Shutdown();
+
+        Program.SaveConfiguration();
+    }
+
+
+    private void InitializeEmulatorHandler()
+    {
+        emulatorHandler = new EmulatorHandler(machineType);
+        emulatorHandler.SetFpsLimiter(Program.Configuration.General.LimitFps);
+    }
+
+    private void VerifyConfiguration()
+    {
+        foreach (var button in emulatorHandler.Machine.GameControls.Replace(" ", "").Split(','))
+        {
+            if (!Program.Configuration.Input.GameControls.ContainsKey(button))
+                Program.Configuration.Input.GameControls[button] = new();
+        }
+
+        foreach (var button in emulatorHandler.Machine.HardwareControls.Replace(" ", "").Split(','))
+        {
+            if (!Program.Configuration.Input.SystemControls.ContainsKey(button))
+                Program.Configuration.Input.SystemControls[button] = new();
+        }
+
+        if (Program.Configuration.Video.ScreenSize < 2 || Program.Configuration.Video.ScreenSize > maxScreenSizeFactor)
+            Program.Configuration.Video.ResetToDefault(nameof(Program.Configuration.Video.ScreenSize));
+
+        //if (string.IsNullOrEmpty(Program.Configuration.Video.Shader) || (graphicsHandler != null && !graphicsHandler.AvailableShaders.Contains(Program.Configuration.Video.Shader)))
+        //    Program.Configuration.Video.Shader = GraphicsHandler.DefaultShaderName;
+    }
+
+    private void InitializeOtherHandlers()
+    {
+        databaseHandler = new DatabaseHandler();
+
+        //statusIconsLocation = machineType == typeof(WonderSwan) ? new(0, DisplayControllerCommon.ScreenHeight) : new(DisplayControllerCommon.ScreenWidth, 0);
+
+        //TODO graphicsHandler基本参数,可能需要补上
+        //graphicsHandler = new GraphicsHandler(machineType, new(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight), statusIconsLocation, statusIconSize, machineType != typeof(WonderSwan), Program.Configuration.Video.Shader)
+        //{
+        //    IsVerticalOrientation = isVerticalOrientation
+        //};
+
+        //TODO 声音基本参数,可能需要补上
+        //soundHandler = new SoundHandler(44100, 2);
+        //soundHandler.SetVolume(1.0f);
+        //soundHandler.SetMute(Program.Configuration.Sound.Mute);
+        //soundHandler.SetLowPassFilter(Program.Configuration.Sound.LowPassFilter);
+
+        //TODO Input基本参数,可能需要补上
+        //inputHandler = new InputHandler(renderControl);
+        //inputHandler.SetKeyMapping(Program.Configuration.Input.GameControls, Program.Configuration.Input.SystemControls);
+        //inputHandler.SetVerticalOrientation(isVerticalOrientation);
+        //inputHandler.SetEnableRemapping(Program.Configuration.Input.AutoRemap);
+        //inputHandler.SetVerticalRemapping(emulatorHandler.Machine.VerticalControlRemap
+        //    .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
+        //    .Select(x => x.Split('=', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
+        //    .ToDictionary(x => x[0], x => x[1]));
+
+
+        emulatorHandler.Machine.DisplayController.SendFramebuffer = graphicsHandler.UpdateScreen;
+        emulatorHandler.Machine.SoundController.SendSamples = (s) =>
+        {
+            soundHandler.EnqueueSamples(s);
+            //soundRecorderForm.EnqueueSamples(s);
+        };
+
+        emulatorHandler.Machine.ReceiveInput += () =>
+        {
+            //var buttonsPressed = new List<string>();
+            //var buttonsHeld = new List<string>();
+
+            //inputHandler.PollInput(ref buttonsPressed, ref buttonsHeld);
+            long buttonsHeld = 0;
+            inputHandler.PollInput(ref buttonsHeld);
+            return buttonsHeld;
+            //if (buttonsPressed.Contains("Volume"))
+            //    emulatorHandler.Machine.SoundController.ChangeMasterVolume();
+
+            //return (buttonsPressed, buttonsHeld);
+        };
+
+        //renderControl.Resize += (s, e) => { if (s is Control control) graphicsHandler.Resize(control.ClientRectangle); };
+        //renderControl.Paint += (s, e) =>
+        //{
+        //    graphicsHandler.SetClearColor(Color.Black);
+
+        //    graphicsHandler.ClearFrame();
+
+        //    if (emulatorHandler.Machine is MachineCommon machine)
+        //    {
+        //        var activeIcons = new List<string>() { "Power" };
+
+        //        if (machine.BuiltInSelfTestOk) activeIcons.Add("Initialized");
+
+        //        if (machine.DisplayController.IconSleep) activeIcons.Add("Sleep");
+        //        if (machine.DisplayController.IconVertical) activeIcons.Add("Vertical");
+        //        if (machine.DisplayController.IconHorizontal) activeIcons.Add("Horizontal");
+        //        if (machine.DisplayController.IconAux1) activeIcons.Add("Aux1");
+        //        if (machine.DisplayController.IconAux2) activeIcons.Add("Aux2");
+        //        if (machine.DisplayController.IconAux3) activeIcons.Add("Aux3");
+
+        //        if (machine.SoundController.HeadphonesConnected) activeIcons.Add("Headphones");
+        //        if (machine.SoundController.MasterVolume == 0) activeIcons.Add("Volume0");
+        //        if (machine.SoundController.MasterVolume == 1) activeIcons.Add("Volume1");
+        //        if (machine.SoundController.MasterVolume == 2) activeIcons.Add("Volume2");
+        //        if (machine.SoundController.MasterVolume == 3 && machine is WonderSwanColor) activeIcons.Add("Volume3");
+
+        //        graphicsHandler.UpdateStatusIcons(activeIcons);
+        //    }
+        //    graphicsHandler.DrawFrame();
+        //};
+
+        internalEepromPath = Path.Combine(Program.InternalDataPath, $"{machineType.Name}.eep");
+    }
+
+    //private void InitializeWindows()
+    //{
+    //    soundRecorderForm = new(soundHandler.SampleRate, soundHandler.NumChannels);
+    //    cheatsForm = new()
+    //    {
+    //        Callback = (c) =>
+    //        {
+    //            if (emulatorHandler.IsRunning)
+    //                cheats = (Cheat[])c.Clone();
+    //        }
+    //    };
+    //}
+
+    private void SizeAndPositionWindow()
+    {
+        graphicsHandler.SetSize(emulatorHandler.Machine.ScreenWidth, emulatorHandler.Machine.ScreenHeight);
+        //if (WindowState == For emulatorHandler.Machine.ScreenHeight;mWindowState.Maximized)
+        //    WindowState = FormWindowState.Normal;
+
+        //MinimumSize = SizeFromClientSize(CalculateRequiredClientSize(2));
+        //Size = SizeFromClientSize(CalculateRequiredClientSize(Program.Configuration.Video.ScreenSize));
+        //var screen = Screen.FromControl(this);
+        //var workingArea = screen.WorkingArea;
+        //Location = new Point()
+        //{
+        //    X = Math.Max(workingArea.X, workingArea.X + (workingArea.Width - Width) / 2),
+        //    Y = Math.Max(workingArea.Y, workingArea.Y + (workingArea.Height - Height) / 2)
+        //};
+    }
+
+
+    //TODO 设置屏幕宽高 看是否需要
+    //private Size CalculateRequiredClientSize(int screenSize)
+    //{
+    //    if (emulatorHandler == null || graphicsHandler == null)
+    //        return ClientSize;
+
+    //    var statusIconsOnRight = statusIconsLocation.X > statusIconsLocation.Y;
+
+    //    int screenWidth, screenHeight;
+
+    //    if (!isVerticalOrientation)
+    //    {
+    //        screenWidth = emulatorHandler.Machine.ScreenWidth;
+    //        screenHeight = emulatorHandler.Machine.ScreenHeight;
+    //        if (statusIconsOnRight) screenWidth += statusIconSize;
+    //        if (!statusIconsOnRight) screenHeight += statusIconSize;
+    //    }
+    //    else
+    //    {
+    //        screenWidth = emulatorHandler.Machine.ScreenHeight;
+    //        screenHeight = emulatorHandler.Machine.ScreenWidth;
+    //        if (!statusIconsOnRight) screenWidth += statusIconSize;
+    //        if (statusIconsOnRight) screenHeight += statusIconSize;
+    //    }
+
+    //    return new(screenWidth * screenSize, (screenHeight * screenSize) + menuStrip.Height + statusStrip.Height);
+    //}
+
+    private void SetWindowTitleAndStatus()
+    {
+        //TODO 修改为状态字符串,显示在某个地方
+
+        //var titleStringBuilder = new StringBuilder();
+
+        //titleStringBuilder.Append($"{Application.ProductName} {Program.GetVersionString(false)}");
+
+        //if (emulatorHandler.Machine.Cartridge.IsLoaded)
+        //{
+        //    titleStringBuilder.Append($" - [{Path.GetFileName(Program.Configuration.General.RecentFiles.First())}]");
+
+        //    var statusStringBuilder = new StringBuilder();
+        //    statusStringBuilder.Append($"Emulating {emulatorHandler.Machine.Manufacturer} {emulatorHandler.Machine.Model}, ");
+        //    statusStringBuilder.Append($"playing {databaseHandler.GetGameTitle(emulatorHandler.Machine.Cartridge.Crc32, emulatorHandler.Machine.Cartridge.SizeInBytes)} ({emulatorHandler.Machine.Cartridge.Metadata.GameIdString})");
+
+        //    tsslStatus.Text = statusStringBuilder.ToString();
+        //    tsslEmulationStatus.Text = emulatorHandler.IsRunning ? (emulatorHandler.IsPaused ? "Paused" : "Running") : "Stopped";
+        //}
+        //else
+        //{
+        //    tsslStatus.Text = "Ready";
+        //    tsslEmulationStatus.Text = "Stopped";
+        //}
+
+        //Text = titleStringBuilder.ToString();
+    }
+
+    private void LoadBootstrap(string filename)
+    {
+        if (GlobalVariables.EnableSkipBootstrapIfFound) return;
+
+        if (!emulatorHandler.IsRunning)
+        {
+            if (File.Exists(filename))
+            {
+                using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+                var data = new byte[stream.Length];
+                stream.Read(data, 0, data.Length);
+                emulatorHandler.Machine.LoadBootstrap(data);
+            }
+            emulatorHandler.Machine.UseBootstrap = Program.Configuration.General.UseBootstrap;
+        }
+    }
+
+    private void LoadInternalEeprom()
+    {
+        if (!emulatorHandler.IsRunning && File.Exists(internalEepromPath))
+        {
+            using var stream = new FileStream(internalEepromPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+            var data = new byte[stream.Length];
+            stream.Read(data, 0, data.Length);
+            emulatorHandler.Machine.LoadInternalEeprom(data);
+        }
+    }
+
+    private static Stream GetStreamFromFile(string filename)
+    {
+        return new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+    }
+
+    private static Stream GetStreamFromFirstZippedFile(string filename)
+    {
+        return new ZipArchive(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)).Entries.FirstOrDefault()?.Open();
+    }
+
+    private bool LoadAndRunCartridge(string filename)
+    {
+        try
+        {
+            if (emulatorHandler.IsRunning)
+            {
+                SaveAllData();
+                emulatorHandler.Shutdown();
+            }
+
+            using var inputStream = supportedFileInformation.FirstOrDefault(x => x.extension == Path.GetExtension(filename)).streamReadFunc(filename) ?? GetStreamFromFile(filename);
+            using var stream = new MemoryStream();
+            inputStream.CopyTo(stream);
+            stream.Position = 0;
+
+            var data = new byte[stream.Length];
+            stream.Read(data, 0, data.Length);
+            emulatorHandler.Machine.LoadRom(data);
+
+            graphicsHandler.IsVerticalOrientation = isVerticalOrientation = emulatorHandler.Machine.Cartridge.Metadata.Orientation == CartridgeMetadata.Orientations.Vertical;
+            inputHandler.SetVerticalOrientation(isVerticalOrientation);
+
+            CurrRomName = Path.GetFileName(filename);
+
+            LoadRam();
+
+            LoadBootstrap(emulatorHandler.Machine is WonderSwan ? Program.Configuration.General.BootstrapFile : Program.Configuration.General.BootstrapFileWSC);
+            LoadInternalEeprom();
+
+            //初始化音频
+            soundHandler.Initialize();
+
+            emulatorHandler.Startup();
+
+            SizeAndPositionWindow();
+            SetWindowTitleAndStatus();
+
+            Program.SaveConfiguration();
+            return true;
+        }
+        catch (Exception ex) when (!AppEnvironment.DebugMode)
+        {
+            App.log.Error("ex=>"+ex.ToString());
+            return false;
+        }
+    }
+
+    private void LoadRam()
+    {
+        //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav");
+        var path = Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav");
+        if (!File.Exists(path)) return;
+
+        using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+        var data = new byte[stream.Length];
+        stream.Read(data, 0, data.Length);
+        if (data.Length != 0)
+            emulatorHandler.Machine.LoadSaveData(data);
+    }
+
+    private void SaveAllData()
+    {
+        SaveInternalEeprom();
+        SaveRam();
+    }
+
+    private void SaveInternalEeprom()
+    {
+        var data = emulatorHandler.Machine.GetInternalEeprom();
+        if (data.Length == 0) return;
+
+        using var stream = new FileStream(internalEepromPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
+        stream.Write(data, 0, data.Length);
+    }
+
+    private void SaveRam()
+    {
+        var data = emulatorHandler.Machine.GetSaveData();
+        if (data.Length == 0) return;
+
+        //var path = Path.Combine(Program.SaveDataPath, $"{Path.GetFileNameWithoutExtension(Program.Configuration.General.RecentFiles.First())}.sav");
+        var path = Path.Combine(Program.SaveDataPath, $"{CurrRomName}.sav");
+
+        using var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
+        stream.Write(data, 0, data.Length);
+    }
+
+
+    private void PauseEmulation()
+    {
+        if (!emulatorHandler.IsRunning) return;
+
+        emulatorHandler.Pause();
+        soundHandler.Pause();
+
+        SetWindowTitleAndStatus();
+    }
+
+    private void UnpauseEmulation()
+    {
+        if (!emulatorHandler.IsRunning) return;
+
+        emulatorHandler.Unpause();
+        soundHandler.Unpause();
+
+        SetWindowTitleAndStatus();
+    }
+
+    private void ResetEmulation()
+    {
+        SaveAllData();
+        emulatorHandler.Reset();
+
+        Program.SaveConfiguration();
+    }
+
+}
+
+static class Program
+{
+    static string jsonConfigFileName;//= "Config.json";
+    static string logFileName;//= "Log.txt";
+    static string internalDataDirectoryName;//= "Internal";
+    static string saveDataDirectoryName;//= "Saves";
+    static string cheatDataDirectoryName;//= "Cheats";
+    static string debuggingDataDirectoryName;//= "Debugging";
+    static string assetsDirectoryName;//= "Assets";
+    static string shaderDirectoryName;//= "Shaders";
+    static string noIntroDatDirectoryName;//= "No-Intro";
+    static string mutexName;//= $"Unity_{GetVersionDetails()}";
+    static string programDataDirectory;//= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Application.ProductName);
+    static string programConfigPath;//= Path.Combine(programDataDirectory, jsonConfigFileName);
+
+    public static Configuration Configuration;// { get; private set; } = LoadConfiguration(programConfigPath);
+
+    public static string DataPath;//{ get; } = string.Empty;
+    public static string InternalDataPath;//{ get; } = string.Empty;
+    public static string SaveDataPath;//{ get; } = string.Empty;
+    public static string CheatsDataPath;//{ get; } = string.Empty;
+    public static string DebuggingDataPath;//{ get; } = string.Empty;
+
+    static string programApplicationDirectory;// = AppDomain.CurrentDomain.BaseDirectory;
+    static string programAssetsDirectory;// = Path.Combine(programApplicationDirectory, assetsDirectoryName);
+
+    //public static string ShaderPath { get; } = string.Empty;
+    public static string NoIntroDatPath;// { get; } = string.Empty;
+
+    //static MainForm mainForm = default;
+
+    public static void InitPath(string CustonDataDir)
+    {
+        try
+        {
+            jsonConfigFileName = "Config.json";
+            logFileName = "Log.txt";
+            internalDataDirectoryName = "Internal";
+            saveDataDirectoryName = "Saves";
+            cheatDataDirectoryName = "Cheats";
+            debuggingDataDirectoryName = "Debugging";
+            assetsDirectoryName = "Assets";
+            shaderDirectoryName = "Shaders";
+            noIntroDatDirectoryName = "No-Intro";
+            mutexName = $"Unity_{GetVersionDetails()}";
+            programDataDirectory = Path.Combine(CustonDataDir, "AxibugEmu");
+            programConfigPath = Path.Combine(programDataDirectory, jsonConfigFileName);
+            Configuration = LoadConfiguration(programConfigPath);
+            Log.WriteLine(Path.Combine(programDataDirectory, logFileName));
+            programApplicationDirectory = AppDomain.CurrentDomain.BaseDirectory;
+            programAssetsDirectory = Path.Combine(programApplicationDirectory, assetsDirectoryName);
+            Directory.CreateDirectory(DataPath = programDataDirectory);
+            Directory.CreateDirectory(InternalDataPath = Path.Combine(programDataDirectory, internalDataDirectoryName));
+            Directory.CreateDirectory(SaveDataPath = Path.Combine(programDataDirectory, saveDataDirectoryName));
+            Directory.CreateDirectory(CheatsDataPath = Path.Combine(programDataDirectory, cheatDataDirectoryName));
+            Directory.CreateDirectory(DebuggingDataPath = Path.Combine(programDataDirectory, debuggingDataDirectoryName));
+
+            //if (!Directory.Exists(ShaderPath = Path.Combine(programAssetsDirectory, shaderDirectoryName)))
+            //    throw new DirectoryNotFoundException("Shader directory missing");
+
+            if (!Directory.Exists(NoIntroDatPath = Path.Combine(programAssetsDirectory, noIntroDatDirectoryName)))
+                throw new DirectoryNotFoundException("No-Intro .dat directory missing");
+        }
+        catch (DirectoryNotFoundException e)
+        {
+        }
+    }
+
+    //[STAThread]
+    //static void Main()
+    //{
+    //    using var mutex = new Mutex(true, mutexName, out bool newInstance);
+    //    if (!newInstance)
+    //    {
+    //        MessageBox.Show($"Another instance of {Application.ProductName} is already running.\n\nThis instance will now shut down.",
+    //            $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+    //        Environment.Exit(-1);
+    //    }
+
+    //    Application.SetHighDpiMode(HighDpiMode.SystemAware);
+    //    Application.EnableVisualStyles();
+    //    Application.SetCompatibleTextRenderingDefault(false);
+
+    //    if (!Debugger.IsAttached)
+    //    {
+    //        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
+    //        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
+    //        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
+    //    }
+
+    //    Application.Run(mainForm = new MainForm());
+    //}
+
+    //static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
+    //{
+    //    if (e.Exception is GLFWException glEx)
+    //    {
+    //        var renderControl = mainForm.Controls["renderControl"] as OpenGL.RenderControl;
+    //        MessageBox.Show($"{glEx.Message.EnsureEndsWithPeriod()}\n\n{Application.ProductName} requires GPU and drivers supporting OpenGL {renderControl.APIVersion.Major}.{renderControl.APIVersion.Minor}.", $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+    //    }
+    //    else
+    //    {
+    //        MessageBox.Show(e.Exception.Message.EnsureEndsWithPeriod(), $"{Application.ProductName} Startup Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+    //    }
+
+    //    Environment.Exit(-1);
+    //}
+
+    //static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+    //{
+    //    MessageBox.Show((e.ExceptionObject as Exception).Message, $"{Application.ProductName} Startup Error");
+    //    Environment.Exit(-1);
+    //}
+
+    private static Configuration LoadConfiguration(string filename)
+    {
+        Directory.CreateDirectory(Path.GetDirectoryName(filename));
+
+        Configuration configuration;
+        //if (!File.Exists(filename) || (configuration = filename.DeserializeFromFile<Configuration>()) == null)
+        //{
+        //    configuration = new Configuration();
+        //    configuration.SerializeToFile(filename);
+        //}
+
+        configuration = new Configuration();
+
+        return configuration;
+    }
+
+    public static void ReplaceConfiguration(Configuration newConfig)
+    {
+        ConfigurationBase.CopyConfiguration(newConfig, Configuration);
+        SaveConfiguration();
+    }
+
+    public static void SaveConfiguration()
+    {
+        //Configuration?.SerializeToFile(programConfigPath);
+    }
+
+    private static string GetVersionDetails()
+    {
+        //return $"{ThisAssembly.Git.Branch}-{ThisAssembly.Git.Commit}{(ThisAssembly.Git.IsDirty ? "-dirty" : string.Empty)}{(GlobalVariables.IsDebugBuild ? "+debug" : string.Empty)}";
+        return $"{(GlobalVariables.IsDebugBuild ? "+debug" : string.Empty)}";
+    }
+
+    //public static string GetVersionString(bool detailed)
+    //{
+    //    var version = new Version(Application.ProductVersion);
+    //    var stringBuilder = new StringBuilder();
+    //    stringBuilder.Append($"v{version.Major:D3}{(version.Minor != 0 ? $".{version.Minor}" : string.Empty)}");
+    //    if (detailed) stringBuilder.Append($" ({GetVersionDetails()})");
+    //    return stringBuilder.ToString();
+    //}
+}
+
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs.meta
new file mode 100644
index 00000000..4d5d9493
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/StoicGooseEmulator/UStoicGoose.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b7e1a8282bc4d764c81f63e62fd7aec8
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
index 88b5fa24..f92e144d 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
@@ -70,7 +70,11 @@ namespace AxibugEmuOnline.Client.Manager
                 case RomPlatformType.Sc3000:
                 case RomPlatformType.Sg1000:
                     m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("EssgeeUnity/EssgeeUnity")).GetComponent<IEmuCore>();
-                    break;
+                    break;
+                case RomPlatformType.WonderSwan:
+                case RomPlatformType.WonderSwanColor:
+                    m_emuCore = GameObject.Instantiate(Resources.Load<GameObject>("StoicGooseUnity/StoicGooseUnity")).GetComponent<IEmuCore>();
+                    break;
             }
 
             var result = m_emuCore.StartGame(romFile);
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Protobuf/ProtobufAxibugEmuOnline.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Protobuf/ProtobufAxibugEmuOnline.cs
index 7db4888f..755f46d8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Protobuf/ProtobufAxibugEmuOnline.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Protobuf/ProtobufAxibugEmuOnline.cs
@@ -157,17 +157,18 @@ namespace AxibugProtobuf {
             "bBAFEhQKEFN3aXRjaFByb0NvbnRyb2wQBhIQCgxTd2l0Y2hKb3lDb24QBxIS",
             "Cg5YQk9YMzYwQ29udHJvbBAIEhIKDlhCT1hPTkVDb250cm9sEAkSEQoNUFNW",
             "aXRhQ29udHJvbBAKEhIKDldpaVVQYWRDb250cm9sEAsSFAoQV2lpUmVtb3Rl",
-            "Q29udHJvbBAMEhYKEk5pbnRlbmRvM0RTQ29udHJvbBANKtsBCg9Sb21QbGF0",
+            "Q29udHJvbBAMEhYKEk5pbnRlbmRvM0RTQ29udHJvbBANKoMCCg9Sb21QbGF0",
             "Zm9ybVR5cGUSCwoHSW52YWxpZBAAEgcKA05lcxABEhEKDU1hc3Rlcl9TeXN0",
             "ZW0QAhINCglHYW1lX0dlYXIQAxIMCghHYW1lX0JveRAEEhIKDkdhbWVfQm95",
             "X0NvbG9yEAUSEQoNQ29sZWNvX1Zpc2lvbhAGEgsKB1NDXzMwMDAQBxILCgdT",
             "R18xMDAwEAgSCgoGTkVPR0VPEBQSBwoDSUdTEBUSCAoEQ1BTMRAWEggKBENQ",
-            "UzIQFxIOCgpBcmNhZGVfT0xEEB4SCAoDQWxsEOcHKnAKDVJvb21HYW1lU3Rh",
-            "dGUSEgoOTm9uZV9HYW1lU3RhdGUQABIMCghPbmx5SG9zdBABEhEKDVdhaXRS",
-            "YXdVcGRhdGUQAhINCglXYWl0UmVhZHkQAxIJCgVQYXVzZRAEEhAKDEluT25s",
-            "aW5lR2FtZRAFKk4KEUxvZ2luUmVzdWx0U3RhdHVzEiEKHUxvZ2luUmVzdWx0",
-            "U3RhdHVzX0Jhc2VEZWZhdWx0EAASBgoCT0sQARIOCgpBY2NvdW50RXJyEAJC",
-            "AkgBYgZwcm90bzM="));
+            "UzIQFxIOCgpBcmNhZGVfT0xEEB4SDwoLV29uZGVyX1N3YW4QKBIVChFXb25k",
+            "ZXJfU3dhbl9Db2xvchApEggKA0FsbBDnBypwCg1Sb29tR2FtZVN0YXRlEhIK",
+            "Dk5vbmVfR2FtZVN0YXRlEAASDAoIT25seUhvc3QQARIRCg1XYWl0UmF3VXBk",
+            "YXRlEAISDQoJV2FpdFJlYWR5EAMSCQoFUGF1c2UQBBIQCgxJbk9ubGluZUdh",
+            "bWUQBSpOChFMb2dpblJlc3VsdFN0YXR1cxIhCh1Mb2dpblJlc3VsdFN0YXR1",
+            "c19CYXNlRGVmYXVsdBAAEgYKAk9LEAESDgoKQWNjb3VudEVychACQgJIAWIG",
+            "cHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::AxibugProtobuf.CommandID), typeof(global::AxibugProtobuf.ErrorCode), typeof(global::AxibugProtobuf.LoginType), typeof(global::AxibugProtobuf.DeviceType), typeof(global::AxibugProtobuf.GamePadType), typeof(global::AxibugProtobuf.RomPlatformType), typeof(global::AxibugProtobuf.RoomGameState), typeof(global::AxibugProtobuf.LoginResultStatus), }, null, new pbr::GeneratedClrTypeInfo[] {
@@ -480,6 +481,8 @@ namespace AxibugProtobuf {
     [pbr::OriginalName("CPS1")] Cps1 = 22,
     [pbr::OriginalName("CPS2")] Cps2 = 23,
     [pbr::OriginalName("Arcade_OLD")] ArcadeOld = 30,
+    [pbr::OriginalName("Wonder_Swan")] WonderSwan = 40,
+    [pbr::OriginalName("Wonder_Swan_Color")] WonderSwanColor = 41,
     [pbr::OriginalName("All")] All = 999,
   }