// Finding Frankie Autosplliter // Developed by Lox and Nikoheart state("FF_Train_test-Win64-Shipping") { bool bossflipped : "FF_Train_test-Win64-Shipping.exe", 0x07FE2548, 0x110, 0x68, 0xA0, 0x840, 0x90, 0x2F4; bool bossabletopull : "FF_Train_test-Win64-Shipping.exe", 0x07FE2548, 0x110, 0x68, 0xA0, 0x840, 0x90, 0x328; } startup { Assembly.Load(File.ReadAllBytes("Components/asl-help")).CreateInstance("Basic"); vars.Helper.GameName = "Finding Frankie"; vars.Helper.AlertLoadless(); dynamic[,] _settings = { { "Inbounds", false, "Speedrun Category - Inbounds", null}, { "frankie_pipe", true, "Falling Down Frankie Pipe", "Inbounds" }, { "has_deputy_duck", true, "Deputy Duck Pickup", "Inbounds" }, { "henry_hotline_chase_end", true, "Henry Hotline Chase End", "Inbounds" }, { "water_section_warp", true, "Water Section Warp", "Inbounds" }, { "lever_trampoline", true, "Hitting Level in Trampoline Park", "Inbounds" }, { "key_trampoline", true, "Collecting Key in Trampoline Park", "Inbounds" }, { "end_bossfight_inb", true, "End Hexa Havoc Bossfight", "Inbounds" }, { "OutOfBounds", false, "Speedrun Category - Out of Bounds", null }, { "elevator_pressed", true, "Elevator Button Pressed", "OutOfBounds" }, { "end_bossfight_oob", true, "End Hexa Havoc Bossfight", "OutOfBounds" }, { "AutoReset", true, "Auto-Reset when returning to Main Menu", null }, }; vars.Helper.Settings.Create(_settings); vars.CompletedSplits = new HashSet<string>(); var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); vars.Watcher = new FileSystemWatcher() { Path = localAppData + @"\FF_Train_test\Saved\SaveGames", Filter = "Key*.sav", EnableRaisingEvents = true }; vars.Watcher.Changed += new FileSystemEventHandler((sender, e) => vars.CerealBoxKey = true); vars.CerealBoxKey = false; } init { IntPtr gWorld = vars.Helper.ScanRel(3, "48 8B 1D ???????? 48 85 DB 74 ?? 41 B0 01"); IntPtr gEngine = vars.Helper.ScanRel(3, "48 8B 0D ???????? 66 0F 5A C9 E8"); IntPtr fNames = vars.Helper.ScanRel(7, "8B D9 74 ?? 48 8D 15 ???????? EB"); if (gWorld == IntPtr.Zero || gEngine == IntPtr.Zero || fNames == IntPtr.Zero) { const string Msg = "Not all required addresses could be found by scanning."; throw new Exception(Msg); } vars.Helper["GWorldName"] = vars.Helper.Make<ulong>(gWorld, 0x18); vars.Helper["MovementMode"] = vars.Helper.Make<byte>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x2E0, 0x320, 0x201); vars.Helper["TransitionType"] = vars.Helper.Make<byte>(gEngine, 0xBBB); vars.Helper["Incutscene"] = vars.Helper.Make<bool>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x2E0, 0xA28); vars.Helper["has_deputy_duck"] = vars.Helper.Make<bool>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x338, 0x791); vars.Helper["Curbreaker"] = vars.Helper.Make<int>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x2E0, 0xA0C); vars.Helper["Curbreaker"].FailAction = MemoryWatcher.ReadFailAction.SetZeroOrNull; vars.Helper["TrampolineLever"] = vars.Helper.Make<bool>(gWorld, 0x30, 0x158, 0x60, 0x160, 0x60, 0x2EC); vars.Helper["TrampolineWonga"] = vars.Helper.Make<bool>(gWorld, 0x30, 0x158, 0x60, 0x160, 0x60, 0x378); vars.Helper["ElevatorButtonPress"] = vars.Helper.Make<bool>(gWorld, 0x30, 0x158, 0x60, 0x880, 0x60, 0x470); vars.Helper["POVX"] = vars.Helper.Make<double>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x348, 0x330); vars.Helper["POVY"] = vars.Helper.Make<double>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x348, 0x338); vars.Helper["POVZ"] = vars.Helper.Make<double>(gWorld, 0x1D8, 0x38, 0x0, 0x30, 0x348, 0x340); vars.FNameToString = (Func<ulong, string>)(fName => { var nameIdx = (fName & 0x000000000000FFFF) >> 0x00; var chunkIdx = (fName & 0x00000000FFFF0000) >> 0x10; var number = (fName & 0xFFFFFFFF00000000) >> 0x20; // IntPtr chunk = vars.Helper.Read<IntPtr>(fNames + 0x10 + (int)chunkIdx * 0x8); IntPtr chunk = vars.Helper.Read<IntPtr>(fNames + 0x10 + (int)chunkIdx * 0x8); IntPtr entry = chunk + (int)nameIdx * sizeof(short); int length = vars.Helper.Read<short>(entry) >> 6; string name = vars.Helper.ReadString(length, ReadStringType.UTF8, entry + sizeof(short)); return number == 0 ? name : name + "_" + number; }); current.World = ""; vars.StartFlag = false; vars.FallingDownFrankiePipe = false; vars.IncutsceneAfterCurbreaker8 = false; vars.BossFlippedLever = false; vars.BossReadyToPull = false; vars.TrampolineWon = false; } onStart { vars.FallingDownFrankiePipe = false; vars.IncutsceneAfterCurbreaker8 = false; vars.BossFlippedLever = false; vars.BossReadyToPull = false; vars.TrampolineWon = false; vars.CerealBoxKey = false; vars.CompletedSplits.Clear(); timer.IsGameTimePaused = true; } start { if (old.World == "FinalMenu" && current.World == "test1" || old.World == "game_intro" && current.World == "test1") { vars.StartFlag = true; } return vars.StartFlag == true && (old.MovementMode == 0 || old.MovementMode == 3) && current.MovementMode == 1; } update { vars.Helper.Update(); vars.Helper.MapPointers(); var world = vars.FNameToString(current.GWorldName); if (!string.IsNullOrEmpty(world) && world != "None") current.World = world; if (current.POVY < -5300 && current.POVZ < -2400 && !vars.CompletedSplits.Contains("frankie_pipe")) vars.FallingDownFrankiePipe = true; if (vars.CompletedSplits.Contains("henry_hotline_chase_end") && old.Incutscene == true && current.Incutscene == false) vars.IncutsceneAfterCurbreaker8 = true; if ((settings["Inbounds"] || settings["OutOfBounds"]) && old.bossabletopull == false && current.bossabletopull == true) { vars.BossReadyToPull = true; } if (old.TrampolineLever == false && current.TrampolineLever == true) vars.CerealBoxKey = false; if (settings["key_trampoline"] && old.TrampolineWonga == false && current.TrampolineWonga == true) vars.TrampolineWon = true; } split { if (settings["Inbounds"] && settings["frankie_pipe"] && !vars.CompletedSplits.Contains("frankie_pipe") && vars.FallingDownFrankiePipe == true && old.TransitionType == 1 && current.TransitionType == 0) { vars.CompletedSplits.Add("frankie_pipe"); return true; } if (settings["Inbounds"] && settings["has_deputy_duck"] && !vars.CompletedSplits.Contains("has_deputy_duck") && old.has_deputy_duck != current.has_deputy_duck && current.has_deputy_duck == true) { vars.CompletedSplits.Add("has_deputy_duck"); return true; } if (settings["Inbounds"] && settings["henry_hotline_chase_end"] && !vars.CompletedSplits.Contains("henry_hotline_chase_end") && old.Curbreaker == 8 && current.Curbreaker == 0) { vars.CompletedSplits.Add("henry_hotline_chase_end"); return true; } if (settings["Inbounds"] && settings["water_section_warp"] && !vars.CompletedSplits.Contains("water_section_warp") && vars.CompletedSplits.Contains("henry_hotline_chase_end") && vars.IncutsceneAfterCurbreaker8 == true && old.Incutscene == false && current.Incutscene == true) { vars.CompletedSplits.Add("water_section_warp"); return true; } if (settings["Inbounds"] && settings["lever_trampoline"] && !vars.CompletedSplits.Contains("lever_trampoline") && old.TrampolineLever == false && current.TrampolineLever == true) { vars.CompletedSplits.Add("lever_trampoline"); return true; } if (settings["Inbounds"] && settings["key_trampoline"] && !vars.CompletedSplits.Contains("key_trampoline") && vars.TrampolineWon == true && vars.CerealBoxKey == true) { vars.CompletedSplits.Add("key_trampoline"); return true; } if (settings["OutOfBounds"] && settings["elevator_pressed"] && old.ElevatorButtonPress == false && current.ElevatorButtonPress == true) { vars.CompletedSplits.Add("elevator_pressed"); return true; } // End Splits for Inbounds & OutOfBounds if (settings["Inbounds"] && settings["end_bossfight_inb"] && !vars.CompletedSplits.Contains("end_bossfight") && vars.BossReadyToPull == true && old.bossflipped == false && current.bossflipped == true) { vars.CompletedSplits.Add("end_bossfight"); return true; } if (settings["OutOfBounds"] && settings["end_bossfight_oob"] && !vars.CompletedSplits.Contains("end_bossfight") && vars.BossReadyToPull == true && old.bossflipped == false && current.bossflipped == true) { vars.CompletedSplits.Add("end_bossfight"); return true; } } isLoading { if (current.World == "FinalMenu") { return true; } else if (!current.Incutscene) return current.MovementMode == 0 || current.TransitionType == 1; } reset { return settings["AutoReset"] && old.World == "test1" && current.World == "FinalMenu"; }