// Towerbolt Autosplitter // Author: hyperbola0 // version 1.3 // CHANGELOG: // // version 1.3 // - Added a setting to split when entering any level from main menu. // - This will store the current file time in a variable and use it to read accurate split times. // // version 1.2 // - Supports Towerbolt 1.00.01 and Towerbolt 1.00.02 // - Implemented in-game time for Towerbolt 1.00.02 // - Fixed the method of game version checking to hash the data.win file instead of the exe // // version 1.1 // - Implemented game version checking to support multiple versions // // version 1.0 // - Auto-starts when game transitions from room 5 (main menu) to room 6 (F1) // - Auto-resets when game transitions from any room to 5 (main menu) // - Auto-splits on game end (leaving F160) // - Option to auto-split on each block (floors 19, 54, 73, 107, 124, 155) // - Option to auto-split on each floor state("Towerbolt", "1.00.01") { uint sceneIdx : "Towerbolt.exe", 0x006A9A34; } state("Towerbolt", "1.00.02") { uint sceneIdx : "Towerbolt.exe", 0x006A9A34; double gameTime : "Towerbolt.exe", 0x004993A0, 0x60, 0x10, 0xa30, 0x0; } startup { refreshRate = 60; settings.Add("SplitLayers", true, "Split on floor blocks"); settings.Add("SplitFloors", true, "Split on each floor", "SplitLayers"); settings.Add("StartAnywhere", false, "Start when entering any level from main menu\n(Allows for chapter runs)"); } init { string MD5Hash; string dataPath = Path.GetDirectoryName(modules.First().FileName) + @"\data.win"; print("data.win at " + dataPath); using (var md5 = System.Security.Cryptography.MD5.Create()) using (var s = File.Open(dataPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) MD5Hash = md5.ComputeHash(s).Select(x => x.ToString("X2")).Aggregate((a, b) => a + b); switch(MD5Hash) { case "EF1D2194C462E67844FE9BE9B59C378B": print("Detected Towerbolt 1.00.01"); version = "1.00.01"; vars.allowGameTime = false; break; case "7DE8229F647FDF833018037EA0C9BF74": print("Detected Towerbolt 1.00.02"); version = "1.00.02"; vars.allowGameTime = true; break; default: print("Found unknown hash \"" + MD5Hash + "\""); version = "1.00.02"; vars.allowGameTime = true; break; } vars.blocks = new List{24, 59, 78, 112, 129, 160}; vars.startTime = new TimeSpan(0); } start { if (old.sceneIdx == current.sceneIdx) { return false; } if (old.sceneIdx == 5) { if (settings["StartAnywhere"] && current.sceneIdx >= 6 && current.sceneIdx <= 165) { vars.startTime = TimeSpan.FromSeconds(current.gameTime); return true; } return current.sceneIdx == 6; } return false; } split { if (current.sceneIdx == old.sceneIdx) { return false; } if (old.sceneIdx == 165) { print("Splitting on completion"); return true; } if (settings["SplitLayers"] && vars.blocks.Contains(old.sceneIdx)) { print("Splitting on layer " + old.sceneIdx + " => " + current.sceneIdx); return true; } else if (old.sceneIdx == 79 && current.sceneIdx == 178) { print("Skipping the first 79 load"); return false; } else if (settings["SplitFloors"] && old.sceneIdx >= 6 && old.sceneIdx <= 165) { print("Splitting on non-layer floor " + old.sceneIdx + " => " + current.sceneIdx); return true; } else { print("Not splitting"); return false; } } reset { return current.sceneIdx == 5 && old.sceneIdx != 5; } isLoading { return vars.allowGameTime; } gameTime { if (vars.allowGameTime) { TimeSpan time = TimeSpan.FromSeconds(current.gameTime) - vars.startTime; return time; } }