state("PokeyPoke", "Not supported") { int gemCount : 0x0; int rubyCount : 0x0; int emeraldCount : 0x0; int blackGemCount : 0x0; int room : 0x0; int playerSprite : 0x0; float playerImageIndex : 0x0; int lanceCount : 0x0; } state("PokeyPoke", "Demo") { int gemCount : 0xb680e8, 0x0, 0x2f0, 0x18, 0x60; int rubyCount : 0xb680e8, 0x0, 0x390, 0x18, 0x60; int emeraldCount : 0xb680e8, 0x0, 0x330, 0x18, 0x60; int blackGemCount : 0xb680e8, 0x0, 0x300, 0x18, 0x60; int room : 0xd8ab34; int playerSprite : 0xb680e8, 0x0, 0x520, 0x18, 0x50, 0x10, 0xc4; float playerImageIndex : 0xb680e8, 0x0, 0x520, 0x18, 0x50, 0x10, 0xd4; int lanceCount : 0xb680e8, 0x0, 0x400, 0x18, 0x60; } init { int moduleSize = modules.First().ModuleMemorySize; vars.Debug("Module size: " + moduleSize); if (moduleSize == 14852096) { version = "Demo"; vars.eatSandSprite = 320; vars.jumpSprite = 294; vars.runSprite = 302; vars.gemList = new DeepPointer("PokeyPoke.exe", 0xb680e8, 0x0, 0x2f0, 0x18, 0x50); vars.rubyList = new DeepPointer("PokeyPoke.exe", 0xb680e8, 0x0, 0x390, 0x18, 0x50); vars.emeraldList = new DeepPointer("PokeyPoke.exe", 0xb680e8, 0x0, 0x330, 0x18, 0x50); vars.blackGemList = new DeepPointer("PokeyPoke.exe", 0xb680e8, 0x0, 0x300, 0x18, 0x50); Predicate<long> IsCollected = (gem) => { return new DeepPointer((IntPtr)(gem + 0x10), 0x48, 0x10, 0x480, 0x0).Deref<double>(game) == 1; }; vars.IsCollected = IsCollected; Func<long, int> InstanceId = (instance) => { return new DeepPointer((IntPtr)(instance + 0x10), 0xbc).Deref<int>(game); }; vars.InstanceId = InstanceId; } else { version = "Not supported"; vars.Debug("Unknown version!"); vars.eatSandSprite = -1; vars.jumpSprite = -1; vars.runSprite = -1; vars.gemList = new DeepPointer("PokeyPoke.exe", 0x0); vars.rubyList = new DeepPointer("PokeyPoke.exe", 0x0); vars.emeraldList = new DeepPointer("PokeyPoke.exe", 0x0); vars.blackGemList = new DeepPointer("PokeyPoke.exe", 0x0); Predicate<long> IsCollected = (gem) => { return false; }; vars.IsCollected = IsCollected; Func<long, int> InstanceId = (instance) => { return 0; }; vars.InstanceId = InstanceId; return; } vars.Debug("Version detected: " + version); } startup { settings.Add("StartAuto", true, "Start timer when moving after restarting the game"); settings.Add("SplitLance", false, "Split when collecting the spear"); settings.Add("SplitGem", true, "Split when collecting a blue gem"); settings.Add("SplitEmerald", true, "Split when collecting an emerald"); settings.Add("SplitRuby", true, "Split when collecting a ruby"); settings.Add("SplitBlackGem", true, "Split when collecting a black gem"); settings.Add("SplitArea", false, "Split when entering another area"); vars.CollectedLance = false; // The tuples store the old and current value of whether a gem is collected vars.rubies = new Dictionary<int, Tuple<bool, bool>>(); vars.gems = new Dictionary<int, Tuple<bool, bool>>(); vars.emeralds = new Dictionary<int, Tuple<bool, bool>>(); vars.blackGems = new Dictionary<int, Tuple<bool, bool>>(); Action<Dictionary<int, Tuple<bool, bool>>, DeepPointer, Process> CheckGems = (gems, gemList, _game) => { var gem = gemList.Deref<int>(_game); var existingIds = new List<int>(); while (gem != 0) { var id = vars.InstanceId(gem); existingIds.Add(id); bool currValue = gems.ContainsKey(id) && gems[id].Item2; gems[id] = new Tuple<bool, bool>(currValue, vars.IsCollected(gem)); gem = new DeepPointer((IntPtr)gem).Deref<int>(_game); } var nonExistingIds = gems.Keys.Except(existingIds).ToList(); foreach (var id in nonExistingIds) { gems.Remove(id); } }; vars.CheckGems = CheckGems; Action<string> Debug = (text) => { print("[PokeyPoke Autosplitter] " + text); }; vars.Debug = Debug; vars.Debug("Initialized!"); } start { if( settings["StartAuto"] && ( ( current.playerSprite == vars.eatSandSprite && old.playerImageIndex == 0 && current.playerImageIndex > 0 ) || (current.playerSprite == vars.jumpSprite) || (current.playerSprite == vars.runSprite) ) ) { vars.Debug("Starting run"); return true; } return false; } update { if (vars.CollectedLance && timer.CurrentPhase == TimerPhase.NotRunning) { vars.CollectedLance = false; } if (vars.rubyList != null) vars.CheckGems(vars.rubies, vars.rubyList, game); if (vars.gemList != null) vars.CheckGems(vars.gems, vars.gemList, game); if (vars.emeraldList != null) vars.CheckGems(vars.emeralds, vars.emeraldList, game); if (vars.blackGemList != null) vars.CheckGems(vars.blackGems, vars.blackGemList, game); return true; } split { if (settings["SplitArea"] && old.room != current.room) { vars.Debug("Entered new area"); return true; } if (settings["SplitLance"] && old.lanceCount == 0 && current.lanceCount == 1 && !vars.CollectedLance) { vars.Debug("Collected lance"); vars.CollectedLance = true; return true; } if (settings["SplitRuby"]) { foreach (var ruby in vars.rubies.Values) { if (!ruby.Item1 && ruby.Item2) { vars.Debug("Collected ruby"); return true; } } } if (settings["SplitGem"]) { foreach (var gem in vars.gems.Values) { if (!gem.Item1 && gem.Item2) { vars.Debug("Collected gem"); return true; } } } if (settings["SplitEmerald"]) { foreach (var emerald in vars.emeralds.Values) { if (!emerald.Item1 && emerald.Item2) { vars.Debug("Collected emerald"); return true; } } } if (settings["SplitBlackGem"]) { foreach (var blackGem in vars.blackGems.Values) { if (!blackGem.Item1 && blackGem.Item2) { vars.Debug("Collected black gem"); return true; } } } return false; }