// Code by SBDWolf and Kannadan // // Some code taken from the Super Metroid autosplitter: https://github.com/UNHchabo/AutoSplitters/blob/master/SuperMetroid/LiveSplit.SuperMetroid.asl state("bsnes"){} state("snes9x"){} state("snes9x-x64"){} state("retroarch"){} state("higan"){} startup { vars.scarX = 1209; vars.scarY = 70; Action<string> DebugOutput = (text) => { print("[The Lion King SNES Autosplitter] "+text); }; vars.DebugOutput = DebugOutput; } init { IntPtr memoryOffset = IntPtr.Zero; if (memory.ProcessName.ToLower().Contains("snes9x")) { var versionsLegacy = new Dictionary<int, long>{ { 10330112, 0x789414 }, // snes9x 1.52-rr { 7729152, 0x890EE4 }, // snes9x 1.54-rr { 5914624, 0x6EFBA4 }, // snes9x 1.53 { 6909952, 0x140405EC8 }, // snes9x 1.53 (x64) { 6447104, 0x7410D4 }, // snes9x 1.54/1.54.1 { 7946240, 0x1404DAF18 }, // snes9x 1.54/1.54.1 (x64) { 6602752, 0x762874 }, // snes9x 1.55 { 8355840, 0x1405BFDB8 }, // snes9x 1.55 (x64) { 6856704, 0x78528C }, // snes9x 1.56/1.56.2 { 9003008, 0x1405D8C68 }, // snes9x 1.56 (x64) { 6848512, 0x7811B4 }, // snes9x 1.56.1 { 8945664, 0x1405C80A8 }, // snes9x 1.56.1 (x64) { 9015296, 0x1405D9298 }, // snes9x 1.56.2 (x64) { 6991872, 0x7A6EE4 }, // snes9x 1.57 { 9048064, 0x1405ACC58 }, // snes9x 1.57 (x64) { 7000064, 0x7A7EE4 }, // snes9x 1.58 { 9060352, 0x1405AE848 }, // snes9x 1.58 (x64) { 8953856, 0x975A54 }, // snes9x 1.59.2 { 12537856, 0x1408D86F8 },// snes9x 1.59.2 (x64) { 9646080, 0x97EE04 }, // Snes9x-rr 1.60 { 13565952, 0x140925118 },// Snes9x-rr 1.60 (x64) { 9027584, 0x94DB54 }, // snes9x 1.60 { 12836864, 0x1408D8BE8 } // snes9x 1.60 (x64) }; long pointerAddr; if (versionsLegacy.TryGetValue(modules.First().ModuleMemorySize, out pointerAddr)) { memoryOffset = memory.ReadPointer((IntPtr)pointerAddr); } else { // Module-relative addresses var versions = new Dictionary<int, int>{ { 10399744, 0x587494 }, // snes9x 1.62.3 { 15474688, 0xA32314 }, // snes9x 1.62.3 (x64) }; int wramAddr; if (versions.TryGetValue(modules.First().ModuleMemorySize, out wramAddr)) { memoryOffset = modules.First().BaseAddress + wramAddr; } } } else if (memory.ProcessName.ToLower().Contains("bsnes") || memory.ProcessName.ToLower().Contains("higan")) { var versions = new Dictionary<int, int>{ { 23781376, 0x7B0CC8 }, // higan v110 { 52477952, 0x716D7C }, // bsnes v115 { 52719616, 0x73AD7C }, // bsnes v115 2023 Nightly }; int wramAddr; if (versions.TryGetValue(modules.First().ModuleMemorySize, out wramAddr)) { memoryOffset = modules.First().BaseAddress + wramAddr; } }else if (memory.ProcessName.ToLower().Contains("retroarch")) { var bsnesModule = modules.FirstOrDefault(m => m.ModuleName.ToLower() == "bsnes_libretro.dll"); if (bsnesModule != null) { var versions = new Dictionary<int, int>{ { 53301248, 0x8179DC }, // bsnes v115 }; int wramOffset; if (versions.TryGetValue(bsnesModule.ModuleMemorySize, out wramOffset)) { memoryOffset = bsnesModule.BaseAddress + wramOffset; } } } if (memoryOffset == IntPtr.Zero) { vars.DebugOutput("Unsupported emulator version"); vars.watchers = new MemoryWatcherList{}; // Throwing prevents initialization from completing. LiveSplit will // retry it until it eventually works. (Which lets you load a core in // RA for example.) throw new InvalidOperationException("Unsupported emulator version"); } vars.DebugOutput("Found WRAM address: 0x" + memoryOffset.ToString("X8")); vars.watchers = new MemoryWatcherList { new MemoryWatcher<byte>(memoryOffset + 0x1FF9E) { Name = "level" }, new MemoryWatcher<ushort>(memoryOffset + 0xB248) { Name = "menu" }, new MemoryWatcher<ushort>(memoryOffset + 0xA65) { Name = "finisher" }, new MemoryWatcher<ushort>(memoryOffset + 0xF946) { Name = "x" }, new MemoryWatcher<ushort>(memoryOffset + 0x4C) { Name = "yCamera" }, new MemoryWatcher<byte>(memoryOffset + 0x5C) { Name = "joypad1" }, new MemoryWatcher<byte>(memoryOffset + 0x5D) { Name = "joypad2" }, new MemoryWatcher<byte>(memoryOffset + 0x1F) { Name = "options" }, }; } update { vars.watchers.UpdateAll(game); } start { if(vars.watchers["options"].Current == 0){ vars.canStart = false; } else { if(vars.watchers["joypad2"].Current == 0){ vars.canStart = true; } } if(vars.canStart && vars.watchers["level"].Current == 0 && (vars.watchers["joypad1"].Current >= 64 || vars.watchers["joypad2"].Current == 16 || vars.watchers["joypad2"].Current > 32 ) && vars.watchers["menu"].Current == 24064 ){ return true; } } split { if(vars.watchers["level"].Current > vars.watchers["level"].Old){ return true; } if(vars.watchers["level"].Current == 9 && vars.watchers["yCamera"].Current < vars.scarY && vars.watchers["x"].Current >= vars.scarX && vars.watchers["finisher"].Current == 0xFFFF){ return true; } } reset { if (vars.watchers["level"].Old != 14 && vars.watchers["level"].Current == 14){ return true; } }