-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
366 additions
and
3 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +0,0 @@ | ||
/Phasmophobia | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<Splits> | ||
<Split ID="scene_shop" Name="Shop (Enter Scene)" ToolTip="Splits when current scene is 'Shop'" Type="SCENE_ENTER"/> | ||
<Split ID="scene_map_world_1" Name="Inkwell Isle 1 (Enter Scene)" ToolTip="Splits when first entering Inkwell Isle I" Type="SCENE_ENTER"/> | ||
<Split ID="scene_map_world_2" Name="Inkwell Isle 2 (Enter Scene)" ToolTip="Splits when first entering Inkwell Isle II" Type="SCENE_ENTER"/> | ||
<Split ID="scene_map_world_3" Name="Inkwell Isle 3 (Enter Scene)" ToolTip="Splits when first entering Inkwell Isle III" Type="SCENE_ENTER"/> | ||
<Split ID="scene_map_world_4" Name="Inkwell Hell (Enter Scene)" ToolTip="Splits when first entering Inkwell Hell" Type="SCENE_ENTER"/> | ||
<Split ID="scene_map_world_DLC" Name="Inkwell Isle DLC (Enter Scene)" ToolTip="Splits when first entering Inkwell Isle DLC" Type="SCENE_ENTER"/> | ||
|
||
<Split ID="scene_level_tutorial" Name="Tutorial (Level)" ToolTip="Splits when leaving the Tutorial level" Type="SCENE_LEAVE"/> | ||
<!-- Sort of guessing the chalice tutorial level name, long story short our current mod has some issues regarding that tutorial level and it doesn't display properly --> | ||
<Split ID="scene_level_chalice_tutorial" Name="Chalice Tutorial (Level)" ToolTip="Splits when leaving the Chalice Tutorial level" Type="SCENE_LEAVE"/> | ||
|
||
<Split ID="scene_level_veggies" Name="The Root Pack (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_slime" Name="Goopy Le Grande (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flower" Name="Cagney Carnation (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_frogs" Name="Ribby And Croaks (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flying_blimp" Name="Hilda Berg (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_level_baroness" Name="Baroness Von Bon Bon (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flying_genie" Name="Djimmi The Great (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_clown" Name="Beppi The Clown (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flying_bird" Name="Wally Warbles (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_dragon" Name="Grim Matchstick (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_level_bee" Name="Rumor Honeybottoms (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_pirate" Name="Captin Brineybeard (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_mouse" Name="Werner Werman (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_robot" Name="Dr. Kahl's Robot (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_sally_stage_play" Name="Sally Stageplay (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flying_mermaid" Name="Cala Maria (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_train" Name="Phantom Express (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_level_old_man" Name="Glumstone The Giant (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_snow_cult" Name="Mortimer Freeze (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_airplane" Name="The Howling Aces (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_flying_cowboy" Name="Esther Winchester (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_rum_runners" Name="Moonshine Mob (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_saltbaker" Name="Chef Saltbaker (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_graveyard" Name="Demon and Angel (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_cutscene_kingdice" Name="King Dice (Contract Cutscene)" ToolTip="Splits when you get the cutscene trying to enter the King Dice fight without all contracts" Type="SCENE_ENTER"/> | ||
<Split ID="scene_level_dice_palace_main" Name="King Dice (Boss)" ToolTip="Splits when you beat King Dice" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_devil" Name="Devil (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_cutscene_credits" Name="End Game (Credits)" ToolTip="Splits when entering the credits" Type="SCENE_ENTER"/> | ||
|
||
<Split ID="scene_level_platforming_1_1F" Name="Forest Follies (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_platforming_1_2F" Name="Treetop Trouble (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_platforming_2_1F" Name="Funfair Fever (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_platforming_2_2F" Name="Funhouse Frazzle (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_platforming_3_1F" Name="Perilous Piers (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_platforming_3_2F" Name="Rugged Ridge (Run 'n Gun)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="scene_level_mausoleum_0" Name="Mausoleum I (Super)" ToolTip="Splits when level is finished" Type="ENDING"/> | ||
<Split ID="scene_level_mausoleum_1" Name="Mausoleum II (Super)" ToolTip="Splits when level is finished" Type="ENDING"/> | ||
<Split ID="scene_level_mausoleum_2" Name="Mausoleum III (Super)" ToolTip="Splits when level is finished" Type="ENDING"/> | ||
|
||
<Split ID="scene_level_chess_pawn" Name="Chess Pawns (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_chess_knight" Name="Chess Knight (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_chess_bishop" Name="Chess Bishop (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_chess_rook" Name="Chess Rook (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
<Split ID="scene_level_chess_queen" Name="Chess Queen (Boss)" ToolTip="Splits when level is finished" Type="LEVEL_COMPLETE"/> | ||
|
||
<Split ID="ilEnter" Name="Enter Level (IL)" ToolTip="Splits when entering any level" Type="CUSTOM"/> | ||
<Split ID="ilEnd" Name="End Level (IL)" ToolTip="Splits when ending any level" Type="CUSTOM"/> | ||
</Splits> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
state("Cuphead") {} | ||
|
||
startup | ||
{ | ||
vars.Log = (Action<object>)(output => print("[Cuphead] " + output)); | ||
|
||
var bytes = File.ReadAllBytes(@"Components\LiveSplit.ASLHelper.bin"); | ||
var type = Assembly.Load(bytes).GetType("ASLHelper.Unity"); | ||
vars.Helper = Activator.CreateInstance(type, timer, this); | ||
|
||
vars.Splits = new Dictionary<string, string>(); | ||
|
||
settings.Add("splits", false, "Splits:"); | ||
|
||
var xml = System.Xml.Linq.XDocument.Load(@"Components\Cuphead.Splits.xml"); | ||
foreach (var split in xml.Element("Splits").Elements("Split")) | ||
{ | ||
string id = split.Attribute("ID").Value, name = split.Attribute("Name").Value; | ||
string tt = split.Attribute("ToolTip").Value, splitType = split.Attribute("Type").Value; | ||
|
||
settings.Add(id, false, name, "splits"); | ||
settings.SetToolTip(id, tt); | ||
|
||
vars.Splits[id] = splitType; | ||
} | ||
|
||
vars.CompletedSplits = new List<string>(); | ||
} | ||
|
||
onStart | ||
{ | ||
timer.IsGameTimePaused = true; | ||
vars.CompletedSplits.Clear(); | ||
} | ||
|
||
onSplit | ||
{ | ||
// Set final split's time to accurate in-game time when player is doing IL attempts. | ||
// This (like `reset`) assumes the runner only has 1 split. | ||
// DevilSquirrel's code. /shrug | ||
if (timer.CurrentPhase != TimerPhase.Ended || timer.Run.Count != 1) | ||
return; | ||
|
||
var time = timer.Run[0].SplitTime; | ||
timer.Run[0].SplitTime = new Time(time.RealTime, TimeSpan.FromSeconds(current.Time)); | ||
} | ||
|
||
onReset | ||
{} | ||
|
||
init | ||
{ | ||
int PTR_SIZE = game.Is64Bit() ? 0x8 : 0x4; | ||
|
||
current.SaveSlot = IntPtr.Zero; | ||
|
||
vars.Helper.TryOnLoad = (Func<dynamic, bool>)(mono => | ||
{ | ||
#region PlayerData | ||
var pd = mono.GetClass("PlayerData"); | ||
|
||
vars.Helper["inGame"] = pd.Make<bool>("inGame"); | ||
vars.Helper["saveSlotIndex"] = pd.Make<int>("_CurrentSaveFileIndex"); | ||
vars.Helper["saveFiles"] = pd.MakeArray<IntPtr>("_saveFiles"); | ||
|
||
vars.GetCurrentSave = (Func<IntPtr>)(() => | ||
{ | ||
var slot = vars.Helper["saveSlotIndex"].Current; | ||
return vars.Helper["saveFiles"].Current[slot]; | ||
}); | ||
|
||
// Level Completion | ||
var pldm = mono.GetClass("PlayerLevelDataManager"); | ||
var pldo = mono.GetClass("PlayerLevelDataObject"); | ||
|
||
vars.GetAllLevelsData = (Func<List<dynamic>>)(() => | ||
{ | ||
var levels = vars.Helper.ReadList<IntPtr>(current.SaveSlot + pd["levelDataManager"], pldm["levelObjects"]); | ||
var ret = new List<dynamic>(); | ||
|
||
foreach (var level in levels) | ||
{ | ||
var id = vars.Helper.Read<int>(level + pldo["levelID"]); | ||
var completed = vars.Helper.Read<bool>(level + pldo["completed"]); | ||
var grade = vars.Helper.Read<int>(level + pldo["grade"]); | ||
var difficulty = vars.Helper.Read<int>(level + pldo["difficultyBeaten"]); | ||
|
||
ret.Add(new | ||
{ | ||
ID = id, | ||
Completed = completed, | ||
Grade = grade, | ||
Difficulty = difficulty | ||
}); | ||
} | ||
|
||
return ret; | ||
}); | ||
|
||
vars.IsLevelCompleted = (Func<int, int, int, bool>)((levelId, targetDifficulty, targetGrade) => | ||
{ | ||
foreach (var level in vars.GetAllLevelsData()) | ||
{ | ||
if (level.ID == levelId) | ||
return level.Completed && level.Grade >= targetGrade && level.Difficulty >= targetDifficulty; | ||
} | ||
|
||
return false; | ||
}); | ||
#endregion // PlayerData | ||
|
||
#region Level | ||
var lvl = mono.GetClass("Level"); | ||
|
||
vars.Helper["lvl"] = lvl.Make<int>("PreviousLevel"); | ||
vars.Helper["lvlTime"] = lvl.Make<float>("Current", "LevelTime"); | ||
vars.Helper["lvlDifficulty"] = lvl.Make<int>("Current", "mode"); | ||
vars.Helper["lvlEnding"] = lvl.Make<bool>("Current", "Ending"); | ||
vars.Helper["lvlWon"] = lvl.Make<bool>("Won"); | ||
#endregion // Level | ||
|
||
#region SceneLoader | ||
var sl = mono.GetClass("SceneLoader"); | ||
|
||
vars.Helper["sceneName"] = sl.MakeString("SceneName"); | ||
vars.Helper["doneLoading"] = sl.Make<bool>("_instance", "doneLoadingSceneAsync"); | ||
#endregion // SceneLoader | ||
|
||
var x = mono.GetClass("PlayerStatsManager"); | ||
|
||
return true; | ||
}); | ||
|
||
vars.Helper.Load(); | ||
} | ||
|
||
update | ||
{ | ||
if (!vars.Helper.Update()) | ||
return false; | ||
|
||
current.SaveSlot = vars.GetCurrentSave(); | ||
|
||
current.InGame = vars.Helper["inGame"].Current; | ||
|
||
current.Level = vars.Helper["lvl"].Current; | ||
current.Time = vars.Helper["lvlTime"].Current; | ||
current.Difficulty = vars.Helper["lvlDifficulty"].Current; | ||
current.IsEnding = vars.Helper["lvlEnding"].Current; | ||
current.HasWon = vars.Helper["lvlWon"].Current; | ||
|
||
current.Loading = !vars.Helper["doneLoading"].Current; | ||
current.Scene = vars.Helper["sceneName"].Current; | ||
|
||
// vars.Log("InGame: " + current.InGame); | ||
// vars.Log("Level: " + current.Level); | ||
// vars.Log("Time: " + current.Time); | ||
// vars.Log("Difficulty: " + current.Difficulty); | ||
// vars.Log("IsEnding: " + current.IsEnding); | ||
// vars.Log("HasWon: " + current.HasWon); | ||
// vars.Log("Loading: " + current.Loading); | ||
// vars.Log("Scene: " + current.Scene); | ||
// vars.Log("---------------------------------"); | ||
} | ||
|
||
start | ||
{ | ||
return current.Scene == "scene_cutscene_intro" && current.InGame && current.Loading; | ||
} | ||
|
||
split | ||
{ | ||
foreach (var split in vars.Splits) | ||
{ | ||
string id = split.Key, type = split.Value; | ||
|
||
if (!settings[id] || vars.CompletedSplits.Contains(id)) | ||
continue; | ||
|
||
switch (type) | ||
{ | ||
case "SCENE_ENTER": | ||
{ | ||
if (old.Scene != id && current.Scene == id) | ||
{ | ||
vars.Log("SCENE_ENTER | " + id); | ||
|
||
vars.CompletedSplits.Add(id); | ||
return true; | ||
} | ||
|
||
continue; | ||
} | ||
|
||
case "SCENE_LEAVE": | ||
{ | ||
if (old.Scene == id && current.Scene != id) | ||
{ | ||
vars.Log("SCENE_LEAVE | " + id); | ||
|
||
vars.CompletedSplits.Add(id); | ||
return true; | ||
} | ||
|
||
continue; | ||
} | ||
|
||
case "LEVEL_COMPLETE": | ||
{ | ||
if (current.Scene == id && vars.IsLevelCompleted(current.Level, -1, -1)) | ||
{ | ||
vars.Log("LEVEL_COMPLETE | " + id); | ||
|
||
vars.CompletedSplits.Add(id); | ||
return true; | ||
} | ||
|
||
continue; | ||
} | ||
|
||
case "ENDING": | ||
{ | ||
var scene = id.Substring(0, id.Length - 2); | ||
var diff = int.Parse(id[id.Length - 1].ToString()); | ||
if (!old.IsEnding && current.IsEnding && current.Scene == scene && current.Difficulty == diff) | ||
{ | ||
vars.Log("ENDING | " + id); | ||
|
||
vars.CompletedSplits.Add(id); | ||
return true; | ||
} | ||
|
||
continue; | ||
} | ||
} | ||
|
||
// case "CUSTOM" | ||
switch (id) | ||
{ | ||
case "ilEnter": | ||
{ | ||
if (old.Time == 0f && current.Time > 0f) | ||
return true; | ||
|
||
continue; | ||
} | ||
|
||
case "ilEnd": | ||
{ | ||
if (current.Time > 0f && current.IsEnding) | ||
return true; | ||
|
||
continue; | ||
} | ||
} | ||
} | ||
} | ||
|
||
reset | ||
{ | ||
// Reset only when the runner is doing IL attempts. | ||
// Kind of a big assumption, don't you think? Runners can do full game runs with only 1 split, too. | ||
// DevilSquirrel's code. /shrug | ||
return timer.Run.Count == 1 && current.Loading && current.Time == 0f; | ||
} | ||
|
||
gameTime | ||
{} | ||
|
||
isLoading | ||
{ | ||
return current.Loading; | ||
} | ||
|
||
exit | ||
{ | ||
vars.Helper.Dispose(); | ||
} | ||
|
||
shutdown | ||
{ | ||
vars.Helper.Dispose(); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Auto Splitter for ***Cuphead*** | ||
## Disclaimer | ||
This is a temporary attempt at fixing [DevilSquirrel's component](https://github.com/ShootMe/LiveSplit.Cuphead) for the new DLC. | ||
|
||
## Features | ||
Starts the timer when choosing any save file. | ||
Splits are available in the settings. | ||
Resets the timer when the runner only has one split. | ||
Removes loading times. | ||
|
||
## Resources | ||
*Leaderboards: [speedrun.com/cuphead](https://speedrun.com/cuphead)* | ||
*Discord: [discord.gg/2BcMwEd](https://discord.gg/2BcMwEd)* | ||
*Website: [cupheadgame.com](https://cupheadgame.com)* | ||
*Game: [s.team/a/268910](https://s.team/a/268910) ($19.99)* |
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