Last active
October 29, 2018 01:00
-
-
Save argusdusty/7fea0526d09c74184f71c4d6c0911480 to your computer and use it in GitHub Desktop.
Broforce Auto Splitter for Livesplit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
state("Broforce_beta", "") | |
{ | |
// The level of the current campaign | |
// If you need to scan for this: offset always ends with 0x18 | |
byte level : "Broforce_beta.exe", 0x1020554, 0x64, 0xA4, 0x9C, 0xC8, 0x18, 0x18; | |
// The timer behind the 3...2...1...Go! countdown. See start for more details | |
float start_timer : "Broforce_beta.exe", 0xFE4CB0, 0x40, 0xA8; | |
// Indicates whether or not we're in the main menu. 1 when we are, 0 when we aren't | |
byte menu : "Broforce_beta.exe", 0xFE5210, 0x38; | |
float final_death_countdown : "mono.dll", 0x1F62F0, 0x50, 0x40C, 0x78, 0x8, 0x10, 0x1C4; // If you need to scan for this: offset always ends with 0x1C4 | |
//int final_boss_health : "mono.dll", 0x1F62F0, 0x50, 0x40C, 0x78, 0x8, 0x10, 0x1E8; // If you need to scan for this: offset always ends with 0x1E8, value starts at 1043 | |
// Counts down from 2.0 while level is running, reset to 2.0 upon completion of level/loading of new level | |
// Obtained from GameModeController object, always ends with offset 0x28 | |
// Nice and short pointer path, hopefully means it works for everyone | |
float level_start_counter : "mono.dll", 0x1F62F0, 0x50, 0x528, 0x0, 0x28; | |
} | |
startup | |
{ | |
settings.Add("campaign%", false, "Campaign Any% NG+"); | |
settings.Add("all", false, "Split on all levels, rather than just on campaigns", "campaign%"); | |
settings.Add("3first", false, "Do campaign 3 before campaign 2", "campaign%"); | |
settings.Add("5first", false, "Do campaign 5 before campaign 4", "campaign%"); | |
settings.Add("8first", false, "Do campaign 8 before campaign 7", "campaign%"); | |
settings.Add("10first", false, "Do campaign 10 before campaign 9", "campaign%"); | |
settings.Add("13first", false, "Do campaign 13 before campaign 12", "campaign%"); | |
// Number of levels in each campaign of campaign mode | |
vars.campaigns = new byte[15] {4, 4, 4, 3, 3, 4, 3, 4, 4, 4, 6, 5, 5, 5, 14}; | |
vars.initial_load = false; | |
} | |
isLoading | |
{ | |
if (current.level_start_counter == 2) { | |
return true; | |
} | |
if (vars.initial_load) { | |
if (current.level == 0 && old.level_start_counter == 2 && current.level_start_counter != 2) { | |
vars.initial_load = false; | |
} else { | |
return true; | |
} | |
} | |
return false; | |
} | |
init | |
{ | |
vars.campaign = 0; | |
// Order to campaign levels | |
vars.campaignOrder = new byte[15] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; | |
// Swap the campaign order per settings | |
// Really, most of this is useless, since only 7 and 8 have differing numbers of levels | |
byte temp; | |
if (settings["3first"]) { | |
temp = vars.campaignOrder[2]; | |
vars.campaignOrder[2] = vars.campaignOrder[1]; | |
vars.campaignOrder[1] = temp; | |
} | |
if (settings["5first"]) { | |
temp = vars.campaignOrder[4]; | |
vars.campaignOrder[4] = vars.campaignOrder[3]; | |
vars.campaignOrder[3] = temp; | |
} | |
if (settings["8first"]) { | |
temp = vars.campaignOrder[7]; | |
vars.campaignOrder[7] = vars.campaignOrder[6]; | |
vars.campaignOrder[6] = temp; | |
} | |
if (settings["10first"]) { | |
temp = vars.campaignOrder[9]; | |
vars.campaignOrder[9] = vars.campaignOrder[8]; | |
vars.campaignOrder[8] = temp; | |
} | |
if (settings["13first"]) { | |
temp = vars.campaignOrder[12]; | |
vars.campaignOrder[12] = vars.campaignOrder[11]; | |
vars.campaignOrder[11] = temp; | |
} | |
} | |
start | |
{ | |
// There are multiple start timers roughly in multiples of 400 (0, 400, ..., 1600) | |
// They are imprecise. Off by at most a few dozen from "correct" values | |
// Picked the 1200 timer, which hits 0 right as "Go" starts | |
// Putting the threshold under that for more accurate starts | |
// Extra validation is there so it doesn't randomly trigger (the timers are weird) | |
// Still a little finicky, try not to go too fast when starting | |
if (current.level == 0 && | |
(current.start_timer < old.start_timer) && | |
(current.start_timer < -300) && | |
(current.start_timer > -400) && | |
(old.start_timer - current.start_timer < 10*400/refreshRate)) { | |
vars.campaign = 0; | |
if (!settings["campaign%"]) { | |
vars.initial_load = true; // First level fix for Arcade | |
} | |
return true; | |
} | |
} | |
reset | |
{ | |
if (current.menu == 1 && old.menu == 0) { | |
return true; | |
} | |
} | |
split | |
{ | |
// Detect the level change | |
if (current.level == old.level+1) { | |
if (settings["campaign%"]) { | |
if (settings["all"]) { | |
return true; | |
} else if (!settings["all"]) { | |
if (current.level == vars.campaigns[vars.campaignOrder[vars.campaign]]) { | |
vars.campaign++; | |
return true; | |
} | |
} | |
} else { | |
return true; | |
} | |
} | |
// Detect the ending | |
bool is_final_level = false; | |
if (settings["campaign%"]) { | |
// Final level of final campaign | |
if (vars.campaign == 14 && current.level == vars.campaigns[vars.campaignOrder[vars.campaign]]-1) { | |
is_final_level = true; | |
} | |
} else if (current.level == 63) { | |
is_final_level = true; | |
} | |
if (is_final_level && current.final_death_countdown < 3 && current.final_death_countdown >= 1) { | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment