state("bgb") {} state("bgb64") {} state("gambatte") {} state("gambatte_qt") {} state("gambatte_qt_nonpsr") {} state("gambatte_speedrun") {} state("emuhawk") {} startup { //-------------------------------------------------------------// settings.Add("entrances", true, "Dungeon Entrance Splits"); settings.Add("essences", true, "Dungeon End Splits (Essences)"); settings.Add("boss", true, "Boss Splits"); settings.Add("items", true, "Item Splits"); settings.Add("keyItems", true, "Key Items Splits"); settings.Add("misc", true, "Miscellaneous Splits"); settings.CurrentDefaultParent = "entrances"; settings.Add("d1Enter", true, "Spirit's Grave (D1)"); settings.Add("d2Enter", true, "Wing Dungeon (D2)"); settings.Add("d3Enter", true, "Moonlit Grotto (D3)"); settings.Add("d4Enter", true, "Skull Dungeon (D4)"); settings.Add("d5Enter", true, "Crown Dungeon (D5)"); settings.Add("d6Enter", true, "Mermaid's Cave (D6)"); settings.CurrentDefaultParent = "essences"; settings.Add("d1Ess", true, "Eternal Spirit (D1)"); settings.Add("d2Ess", true, "Ancient Wood (D2)"); settings.Add("d3Ess", true, "Echoing Howl (D3)"); settings.Add("d6Ess", true, "Bereft Peak (D6)"); settings.CurrentDefaultParent = "boss"; settings.Add("greatMoblin", true, "Great Moblin"); settings.Add("nayru", true, "Save Nayru"); settings.Add("veranEnter", false, "Enter Veran Fight"); settings.Add("veran", true, "Defeat Veran"); settings.CurrentDefaultParent = "items"; settings.Add("l1Sword", true, "Sword (L1)"); settings.Add("seedSatchel", false, "Seed Satchel"); settings.Add("feather", true, "Feather"); settings.Add("seedShooter", true, "Seed Shooter"); settings.Add("switchHook", true, "Switch Hook"); settings.Add("cane", true, "Cane of Somaria"); settings.Add("fluteR", false, "Flute (Ricky)"); settings.Add("fluteD", true, "Flute (Dimitri)"); settings.Add("fluteM", false, "Flute (Moosh)"); settings.Add("harp1", true, "Harp of Ages"); settings.Add("harp2", true, "Tune of Currents"); settings.CurrentDefaultParent = "keyItems"; settings.Add("rope", false, "Rope"); settings.Add("chart", false, "Chart"); settings.Add("tuniNut", false, "Tuni Nut"); settings.Add("lavaJuice", true, "Lava Juice"); settings.Add("mermaidSuit", false, "Mermaid Suit"); settings.Add("d6BossKey", true, "D6 Boss Key"); settings.CurrentDefaultParent = "misc"; settings.Add("d2Skip", false, "D2 Skip"); settings.Add("shipwreck", true, "Crescent Island (shipwreck)"); //-------------------------------------------------------------// refreshRate = 0.5; vars.timer_OnStart = (EventHandler)((s, e) => { vars.splits = vars.GetSplitList(); }); timer.OnStart += vars.timer_OnStart; vars.TryFindOffsets = (Func)((proc, memorySize, baseAddress) => { long wramOffset = 0; string state = proc.ProcessName.ToLower(); if (state.Contains("gambatte")) { IntPtr scanOffset = vars.SigScan(proc, 0, "20 ?? ?? ?? 20 ?? ?? ?? 20 ?? ?? ?? 20 ?? ?? ?? 05 00 00"); wramOffset = (long)scanOffset - 0x10; } else if (state == "emuhawk") { IntPtr scanOffset = vars.SigScan(proc, 0, "05 00 00 00 ?? 00 00 00 00 ?? ?? 00 ?? 40 ?? 00 00 ?? ?? 00 00 00 00 00 ?? 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 ?? 00 00 00 00 00 ?? 00 ?? 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F8 00 00 00"); wramOffset = (long)scanOffset - 0x40; } else if (state == "bgb") { IntPtr scanOffset = vars.SigScan(proc, 12, "6D 61 69 6E 6C 6F 6F 70 83 C4 F4 A1 ?? ?? ?? ??"); wramOffset = new DeepPointer(scanOffset, 0, 0, 0x34).Deref(proc) + 0x108; } else if (state == "bgb64") { IntPtr scanOffset = vars.SigScan(proc, 20, "48 83 EC 28 48 8B 05 ?? ?? ?? ?? 48 83 38 00 74 1A 48 8B 05 ?? ?? ?? ?? 48 8B 00 80 B8 ?? ?? ?? ?? 00 74 07"); IntPtr baseOffset = scanOffset + proc.ReadValue(scanOffset) + 4; wramOffset = new DeepPointer(baseOffset, 0, 0x44).Deref(proc) + 0x190; } if (wramOffset > 0) { vars.watchers = vars.GetWatcherList((int)(wramOffset - baseAddress)); print("[Autosplitter] WRAM Pointer: " + wramOffset.ToString("X8")); return true; } return false; }); vars.SigScan = (Func)((proc, offset, signature) => { var target = new SigScanTarget(offset, signature); IntPtr result = IntPtr.Zero; foreach (var page in proc.MemoryPages(true)) { var scanner = new SignatureScanner(proc, page.BaseAddress, (int)page.RegionSize); if ((result = scanner.Scan(target)) != IntPtr.Zero) { break; } } return result; }); vars.GetWatcherList = (Func)((wramOffset) => { return new MemoryWatcherList { new MemoryWatcher(new DeepPointer(wramOffset, 0x924)) { Name = "d1Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x946)) { Name = "d2Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x966)) { Name = "d3Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x991)) { Name = "d4Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x9BB)) { Name = "d5Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xA44)) { Name = "d6Enter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x9D4)) { Name = "veranEnter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x911)) { Name = "d1Ess" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x938)) { Name = "d2Ess" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x949)) { Name = "d3Ess" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xA37)) { Name = "d6Ess" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x10B3)) { Name = "nayruHP" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x10A9)) { Name = "veranHP" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x1084)) { Name = "bossPhase" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x6B2)) { Name = "sword" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x738)) { Name = "seedSatchel" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x928)) { Name = "feather" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x958)) { Name = "seedShooter" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x987)) { Name = "switchHook" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x9A5)) { Name = "cane" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x6B5)) { Name = "flute" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x8AE)) { Name = "harp1" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x88F)) { Name = "harp2" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x6A4)) { Name = "raft" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x6C2)) { Name = "tuniNut" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x8E7)) { Name = "lavaJuice" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xA13)) { Name = "mermaidSuit" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xA1C)) { Name = "d6BossKey" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x82E)) { Name = "d2Skip" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x8AA)) { Name = "shipwreck" }, new MemoryWatcher(new DeepPointer(wramOffset, 0x709)) { Name = "greatMoblin" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xB00)) { Name = "fileSelect1" }, new MemoryWatcher(new DeepPointer(wramOffset, 0xBB3)) { Name = "fileSelect2" }, //new MemoryWatcher(new DeepPointer(wramOffset, 0x1EFF)) { Name = "resetCheck" }, }; }); vars.GetSplitList = (Func>>)(() => { return new Dictionary> { { "d1Enter", new Dictionary { { "d1Enter", 0x10 } } }, { "d2Enter", new Dictionary { { "d2Enter", 0x10 } } }, { "d3Enter", new Dictionary { { "d3Enter", 0x10 } } }, { "d4Enter", new Dictionary { { "d4Enter", 0x10 } } }, { "d5Enter", new Dictionary { { "d5Enter", 0x10 } } }, { "d6Enter", new Dictionary { { "d6Enter", 0x10 } } }, { "veranEnter", new Dictionary { { "veranEnter", 0x10 } } }, { "d1Ess", new Dictionary { { "d1Ess", 0x30 } } }, { "d2Ess", new Dictionary { { "d2Ess", 0x30 } } }, { "d3Ess", new Dictionary { { "d3Ess", 0x30 } } }, { "d6Ess", new Dictionary { { "d6Ess", 0x30 } } }, { "nayru", new Dictionary { { "nayruHP", 0x01 }, { "bossPhase", 0x12 } } }, { "veran", new Dictionary { { "veranHP", 0x01 }, { "veranEnter", 0x10 } } }, { "l1Sword", new Dictionary { { "sword", 0x01 } } }, { "seedSatchel", new Dictionary { { "seedSatchel", 0xB0 } } }, { "feather", new Dictionary { { "feather", 0x30 } } }, { "seedShooter", new Dictionary { { "seedShooter", 0x30 } } }, { "switchHook", new Dictionary { { "switchHook", 0x34 } } }, { "cane", new Dictionary { { "cane", 0x30 } } }, { "fluteR", new Dictionary { { "flute", 0x01 } } }, { "fluteD", new Dictionary { { "flute", 0x02 } } }, { "fluteM", new Dictionary { { "flute", 0x03 } } }, { "harp1", new Dictionary { { "harp1", 0x30 } } }, { "harp2", new Dictionary { { "harp2", 0x30 } } }, { "rope", new Dictionary { { "raft", 0x04 } } }, { "chart", new Dictionary { { "raft", 0x10 } } }, { "tuniNut", new Dictionary { { "tuniNut", 0x02 } } }, { "lavaJuice", new Dictionary { { "lavaJuice", 0x30 } } }, { "mermaidSuit", new Dictionary { { "mermaidSuit", 0x30 } } }, { "d6BossKey", new Dictionary { { "d6BossKey", 0x30 } } }, { "d2Skip", new Dictionary { { "d2Skip", 0x10 } } }, { "shipwreck", new Dictionary { { "shipwreck", 0x10 } } }, { "greatMoblin", new Dictionary { { "greatMoblin", 0x11 } } }, }; }); } init { vars.watchers = new MemoryWatcherList(); vars.splits = new List>>>(); if (!vars.TryFindOffsets(game, modules.First().ModuleMemorySize, (long)modules.First().BaseAddress)) { throw new Exception("[Autosplitter] Emulated memory not yet initialized."); } else { refreshRate = 200/3.0; } } update { vars.watchers.UpdateAll(game); } start { return vars.watchers["fileSelect1"].Current == 0x23 && vars.watchers["fileSelect2"].Current == 0x0301; } reset { //return vars.watchers["resetCheck"].Current > 0; } split { //prevent splitting on the file select screen var fs = vars.watchers["fileSelect1"].Current; if (fs == 0x17 || fs == 0x23) { return false; } foreach (var _split in vars.splits) { if (settings[_split.Key]) { var count = 0; foreach (var _condition in _split.Value) { if (vars.watchers[_condition.Key].Current == _condition.Value) { count++; } } if (count == _split.Value.Count) { print("[Autosplitter] Split: " + _split.Key); vars.splits.Remove(_split.Key); return true; } } } } exit { refreshRate = 0.5; } shutdown { timer.OnStart -= vars.timer_OnStart; }