/*
* PogoChamp has intentional support for Autosplitters built into the game. The data is exposed
* through the static class "AutosplitData", which has the following fields:
///
/// True if the game is in a load screen.
///
public static bool isLoading = false;
///
/// The current state of the game in human readable format.
///
/// Possible values are:
/// "Playing", "Crashed", "Replay", "Victory", "Exiting Level", "Level Select",
/// "Cinematic", "Main Menu", "Loading", or null.
///
private static string gameState = null;
///
/// True if the player is in a level, false otherwise.
///
public static bool isInLevel = false;
///
/// The index of the level the player is in. -1 if not in a level.
///
public static int levelIndex = -1;
///
/// The in-game time for the current attempt on this level.
///
public static float attemptTime = 0f;
///
/// The total playtime of this save file that you are playing on. This is the same time that is shown
/// in the save file selection menu.
///
public static float totalPlaytime = 0f;
///
/// The number of stars that you have unlocked.
///
public static int starCount = 0;
///
/// The number of rainbow gems that you have unlocked. This will be 0 unless rainbow gems are
/// visible (either by enabling them in the in-game speedrun settings, or by collecting all stars).
///
public static int rainbowGemCount = 0;
///
/// The total number of jumps that you have done on this save file.
///
public static int jumpCount = 0;
*
* If you have an idea for a new speedrun category that can't be autosplit with these values,
* join the PogoChamp Discord and let the game's developer (me!) know. Discord link: https://discord.gg/GRxYEWr
*/
state("PogoChamp") {}
startup
{
vars.Log = (Action)(output => print("[] " + output));
vars.Unity = Assembly.Load(File.ReadAllBytes(@"Components\UnityASL.bin")).CreateInstance("UnityASL.Unity");
/*
* Gate star reqs (skipping the 1 star gate) as of 2022_04_11:
* 7, 15, 25, 36, 46, 56, 65, 77, 88, 100, 110, 120, 130, 150, 168, 180, 191
*/
vars.gateBreakpoints = new int[] { 7, 15, 25, 36, 46, 56, 65, 77, 88, 100, 110, 120, 130, 150, 168, 180, 191, 200, 210 };
settings.Add("pick_one", true, "Pick ONE of the following:");
settings.Add("gates", true, "Split on gates (20 splits)", "pick_one");
settings.SetToolTip("gates", "Split whenever you get enough stars to open the next gate. Skips the first 1-star gate.");
// foreach (int breakpoint in vars.gateBreakpoints)
// {
// settings.Add("gate_" + breakpoint.ToString(), true, breakpoint.ToString() + " Star Gate", "gates");
// }
settings.Add("levels", false, "Split every 10 levels (10 splits)", "pick_one");
settings.SetToolTip("levels", "Split every 10 levels completed. Final split has 11 levels.");
// for (int levelNumber = 10; levelNumber < 99; levelNumber += 10)
// {
// settings.Add("level_" + levelNumber.ToString(), true, "Level " + levelNumber.ToString(), "levels");
// }
settings.Add("stars", false, "Split every 50 stars (6 splits).", "pick_one");
settings.SetToolTip("stars", "Split every 50 stars. Final split has 53 stars.");
// for (int starCounts = 0; starCounts < 350; starCounts += 50)
// {
// settings.Add("stars_" + starCounts.ToString(), true, "Level " + starCounts.ToString(), "stars");
// }
settings.Add("rainbowGems", false, "Split every 10 Rainbow Gems.", "pick_one");
settings.SetToolTip("rainbowGems", "Split every 10 Rainbow Gems. Final split has 11 gems.");
// for (int starCounts = 0; starCounts < 350; starCounts += 50)
// {
// settings.Add("stars_" + starCounts.ToString(), true, "Level " + starCounts.ToString(), "stars");
// }
settings.Add("demo", false, "DEMO: Split every 15 stars. (7 Splits).", "pick_one");
settings.SetToolTip("demo", "Split every 15 stars. The demo has a total of 105 stars.");
vars.nextSplitLevelIndex = 9;
vars.justUnlockedGate = false;
}
init
{
vars.Unity.TryOnLoad = (Func)(helper =>
{
var myClass = helper.GetClass("Assembly-CSharp", "AutosplitData");
vars.Unity.Make(myClass.Static, myClass["isLoading"]).Name = "isLoading";
vars.Unity.MakeString(myClass.Static, myClass["gameState"]).Name = "gameState";
vars.Unity.Make(myClass.Static, myClass["isInLevel"]).Name = "isInLevel";
vars.Unity.Make(myClass.Static, myClass["levelIndex"]).Name = "levelIndex";
vars.Unity.Make(myClass.Static, myClass["attemptTime"]).Name = "attemptTime";
vars.Unity.Make(myClass.Static, myClass["totalPlaytime"]).Name = "totalPlaytime";
vars.Unity.Make(myClass.Static, myClass["starCount"]).Name = "starCount";
vars.Unity.Make(myClass.Static, myClass["rainbowGemCount"]).Name = "rainbowGemCount";
vars.Unity.Make(myClass.Static, myClass["jumpCount"]).Name = "jumpCount";
return true;
});
vars.Unity.Load(game);
}
update
{
if (!vars.Unity.Loaded) return false;
vars.Unity.Update();
}
start
{
/* Leaving the main menu means starting the game, if you start the game with an in-game
* speedrun time of 0, you're clearly playing a reset file.
*/
if (vars.Unity["gameState"].Current != "Main Menu" && vars.Unity["totalPlaytime"].Current == 0)
{
vars.nextSplitLevelIndex = 9; // Reset the next split level index.
vars.justUnlockedGate = false;
return true;
}
}
split
{
if (settings["gates"])
{
// Split each time a gate is opened. This checks that your last star gain was enough to unlock a gate,
// and then waits for you to get back to the Level Select after the gate open animation.
var starCount = vars.Unity["starCount"];
if (starCount.Changed) {
// Only check if the star count has changed.
foreach (int breakpoint in vars.gateBreakpoints) {
if (starCount.Current < breakpoint) {
// Early exit if you don't have enough stars.
break;
}
if (starCount.Old < breakpoint && breakpoint <= starCount.Current) {
// If you didn't have enough stars before, but you do have enough stars now, you've opened the gate.
vars.justUnlockedGate = true;
break;
}
}
}
if (vars.justUnlockedGate && vars.Unity["gameState"].Current == "Level Select" && vars.Unity["gameState"].Old == "Cinematic")
{
vars.justUnlockedGate = false;
return true;
}
// If you finished the final level, that's the final split
if (vars.Unity["gameState"].Changed && (vars.Unity["gameState"].Current == "Victory" || vars.Unity["gameState"].Current == "Cinematic") && vars.Unity["levelIndex"].Current == 100) // level 101's index is 100.
{
return true;
}
}
else if (settings["levels"])
{
if (!vars.Unity["starCount"].Changed) {
return false;
}
if (vars.Unity["levelIndex"].Current == vars.nextSplitLevelIndex)
{
vars.nextSplitLevelIndex += 10;
if (vars.nextSplitLevelIndex == 99) {
vars.nextSplitLevelIndex = -1;
}
return true;
}
// If you finished the final level, that's the final split
if (vars.Unity["gameState"].Changed && (vars.Unity["gameState"].Current == "Victory" || vars.Unity["gameState"].Current == "Cinematic") && vars.Unity["levelIndex"].Current == 100) // level 101's index is 100.
{
return true;
}
}
else if (settings["stars"])
{
var starCount = vars.Unity["starCount"];
if (starCount.Changed)
{
// This only goes up to 250 because the last split requires 303 stars instead of 300.
for (int splitPoint = 50; splitPoint < 251; splitPoint += 50)
{
if (starCount.Current < splitPoint) {
// Early exit if you don't have enough stars.
return false;
}
if (starCount.Old < splitPoint && splitPoint <= starCount.Current)
{
return true;
}
}
if (starCount.Current == 303)
{
return true;
}
}
}
else if (settings["rainbowGems"])
{
var gemCount = vars.Unity["rainbowGems"];
if (gemCount.Changed)
{
// This only goes up to 99 because the last split requires 101 stars instead of 100.
for (int splitPoint = 10; splitPoint < 99; splitPoint += 10)
{
if (gemCount.Current < splitPoint) {
// Early exit if you don't have enough stars.
return false;
}
if (gemCount.Old < splitPoint && splitPoint <= gemCount.Current)
{
return true;
}
}
if (gemCount.Current == 101)
{
return true;
}
}
}
else if (settings["demo"])
{
var starCount = vars.Unity["starCount"];
if (starCount.Changed)
{
// This only goes up to 250 because the last split requires 303 stars instead of 300.
for (int splitPoint = 15; splitPoint < 106; splitPoint += 15)
{
if (starCount.Current < splitPoint) {
// Early exit if you don't have enough stars.
return false;
}
if (starCount.Old < splitPoint && splitPoint <= starCount.Current)
{
return true;
}
}
if (starCount.Current == 105)
{
return true;
}
}
}
}
isLoading
{
return vars.Unity["isLoading"].Current;
}
reset
{
/* If you're in the main menu with a playtime of 0, you probably just reset your save file,
* and you definitely aren't in a current run, so reset the timer.
*/
return vars.Unity["gameState"].Current == "Main Menu" && vars.Unity["totalPlaytime"].Current == 0;
}
exit
{
vars.Unity.Reset();
}
shutdown
{
vars.Unity.Reset();
}