state("Hellraiser-Win64-Shipping") {} startup { Assembly.Load(File.ReadAllBytes("Components/uhara10")).CreateInstance("Main"); vars.Uhara.AlertLoadless(); vars.Uhara.EnableDebug(); #region setting creation dynamic[,] _settings = { { "Splits", true, "Splits", null }, { "MapEntry", true, "Split on entry into new map", "Splits" }, { "Checkpoint Splits", false, "Checkpoint Splits", "Splits" }, { "MAP_EP_0_Prologue_2", true, "Prologue: Movement Tutorial", "Checkpoint Splits" }, { "MAP_EP_0_Prologue_3", true, "Prologue: Bedroom", "Checkpoint Splits" }, { "MAP_EP_1_1", true, "EP1: All Tied Up", "Checkpoint Splits" }, { "MAP_EP_1_2", true, "EP1: Fragment & Diamond Puzzle", "Checkpoint Splits" }, { "MAP_EP_1_3", true, "EP1: Grates Murder", "Checkpoint Splits" }, { "MAP_EP_1_4", true, "EP1: Tongue Key", "Checkpoint Splits" }, { "MAP_EP_1_6", true, "EP1: Bruno", "Checkpoint Splits" }, { "MAP_EP_1_9", true, "EP1: Chatterer Chase", "Checkpoint Splits" }, { "MAP_EP_1_10", true, "EP1: Melee Tutorial", "Checkpoint Splits" }, { "MAP_EP_1_12", true, "EP1: Pistol (Deathrun 1)", "Checkpoint Splits" }, { "MAP_EP_1_13", true, "EP1: Deathrun 2", "Checkpoint Splits" }, { "MAP_EP_1_14", true, "EP1: Leviathan Puzzle", "Checkpoint Splits" }, { "MAP_EP_1_16", true, "EP1: VIP Area Entrance", "Checkpoint Splits" }, { "MAP_EP_1_17", true, "EP1: Altar Room Charlotte Chase Start", "Checkpoint Splits" }, { "MAP_EP_1_18", true, "EP1: Tunnels Start", "Checkpoint Splits" }, { "MAP_EP_1_19", true, "EP1: Tunnels After Hallway", "Checkpoint Splits" }, { "MAP_EP_1_20", true, "EP1: Tunnels Zora Shop", "Checkpoint Splits" }, { "MAP_EP_1_21", true, "EP1: Tunnels After Dark Room", "Checkpoint Splits" }, { "MAP_EP_1_22", true, "EP1: Tunnels After Telekinesis Tutorial", "Checkpoint Splits" }, { "MAP_EP_1_23", true, "EP1: Tunnels Before Martyr", "Checkpoint Splits" }, { "MAP_EP_1_24", true, "EP1: Tunnels After Martyr Armored Encounter", "Checkpoint Splits" }, { "MAP_EP_1_25", true, "EP1: Charlotte Woods Chase", "Checkpoint Splits" }, { "MAP_EP_2_1", true, "EP2: Start", "Checkpoint Splits" }, { "MAP_EP_2_2", true, "EP2: Gravediggers House", "Checkpoint Splits" }, { "MAP_EP_2_3", true, "EP2: Graveyard After Shed", "Checkpoint Splits" }, { "MAP_EP_2_4", true, "EP2: Graveyard Exit", "Checkpoint Splits" }, { "MAP_EP_2_5", true, "EP2: After Graveyard Gate", "Checkpoint Splits" }, { "MAP_EP_2_6", true, "EP2: Following Pinhead Start", "Checkpoint Splits" }, { "MAP_EP_2_7", true, "EP2: Labyrinth After Dark Room", "Checkpoint Splits" }, { "MAP_EP_2_8", true, "EP2: Sunny Shadow", "Checkpoint Splits" }, { "MAP_EP_2_9", true, "EP2: After Sunny Shadow", "Checkpoint Splits" }, { "MAP_EP_2_10", true, "EP2: Before Labyrinth Reward", "Checkpoint Splits" }, { "MAP_EP_2_11", true, "EP2: After Hexagonal Room", "Checkpoint Splits" }, { "MAP_EP_2_12", true, "EP2: Hexagonal Room", "Checkpoint Splits" }, { "MAP_EP_2_13", true, "EP2: After Double Spinning Trap Room", "Checkpoint Splits" }, { "MAP_EP_2_14", true, "EP2: Rotating Cylinder Trap Room", "Checkpoint Splits" }, { "MAP_EP_2_15", true, "EP2: Following Pinhead End", "Checkpoint Splits" }, { "MAP_EP_2_16", true, "EP2: Collapsing Ceiling Tower End", "Checkpoint Splits" }, { "MAP_EP_2_17", true, "EP2: Before Jail Section", "Checkpoint Splits" }, { "MAP_EP_2_18", true, "EP2: Chatterer Chase 01 Start", "Checkpoint Splits" }, { "MAP_EP_2_20", true, "EP2: Chatterer Chase 01 End", "Checkpoint Splits" }, { "MAP_EP_2_21", true, "EP2: Chatterer Chase 02 Start", "Checkpoint Splits" }, { "MAP_EP_2_22", true, "EP2: Field Of Souls Entrance", "Checkpoint Splits" }, { "MAP_EP_2_23", true, "EP2: Field Of Souls Puzzle", "Checkpoint Splits" }, { "MAP_EP_2_24", true, "EP2: Attic", "Checkpoint Splits" }, { "MAP_EP_3_1", true, "EP3: Attic", "Checkpoint Splits" }, { "MAP_EP_3_2", true, "EP3: Hub", "Checkpoint Splits" }, { "MAP_EP_3_3", true, "EP3: Stairs", "Checkpoint Splits" }, { "MAP_EP_3_4", true, "EP3: Bruno Encounter", "Checkpoint Splits" }, { "MAP_EP_3_5", true, "EP3: Bruno Elevator", "Checkpoint Splits" }, { "MAP_EP_3_6", true, "EP3: Bruno Encounter Finished", "Checkpoint Splits" }, { "MAP_EP_3_7", true, "EP3: Before Alarm", "Checkpoint Splits" }, { "MAP_EP_3_8", true, "EP3: Ritual Room Start", "Checkpoint Splits" }, { "MAP_EP_3_9", true, "EP3: Secret Room", "Checkpoint Splits" }, { "MAP_EP_3_10", true, "EP3: After Turning Off Alarm", "Checkpoint Splits" }, { "MAP_EP_3_11", true, "EP3: After Last Encounter", "Checkpoint Splits" }, { "MAP_EP_3_12", true, "EP3: Cabin 01", "Checkpoint Splits" }, { "MAP_EP_3_13", true, "EP3: Cabin 02", "Checkpoint Splits" }, { "MAP_EP_3_14", true, "EP3: Cabin Encounter", "Checkpoint Splits" }, { "MAP_EP_3_15", true, "EP3: After Cabin Encounter", "Checkpoint Splits" }, { "MAP_EP_3_16", true, "EP3: After Cabin Level Pickup", "Checkpoint Splits" }, { "MAP_EP_3_17", true, "EP3: Cabin Bridge", "Checkpoint Splits" }, { "MAP_EP_3_18", true, "EP3: Park 01", "Checkpoint Splits" }, { "MAP_EP_3_19", true, "EP3: Park 02", "Checkpoint Splits" }, { "MAP_EP_3_20", true, "EP3: Park 03", "Checkpoint Splits" }, { "MAP_EP_3_21", true, "EP3: Park 04", "Checkpoint Splits" }, { "MAP_EP_3_22", true, "EP3: Park Well", "Checkpoint Splits" }, { "MAP_EP_3_23", true, "EP3: After Well Puzzle", "Checkpoint Splits" }, { "MAP_EP_3_24", true, "EP3: Underground Well", "Checkpoint Splits" }, { "MAP_EP_3_25", true, "EP3: Charlotte Path", "Checkpoint Splits" }, { "MAP_EP_3_26", true, "EP3: Start", "Checkpoint Splits" }, { "MAP_EP_3_27", true, "EP3: Charlotte Arena After Police", "Checkpoint Splits" }, { "MAP_EP_3_28", true, "EP3: After Combat", "Checkpoint Splits" }, { "MAP_EP_3_29", true, "EP3: Lab Ch 01", "Checkpoint Splits" }, { "MAP_EP_3_30", true, "EP3: Lab Ch 02", "Checkpoint Splits" }, { "MAP_EP_3_31", true, "EP3: Lab Ch 03", "Checkpoint Splits" }, { "MAP_EP_3_32", true, "EP3: Lab Ch 04", "Checkpoint Splits" }, { "MAP_EP_3_33", true, "EP3: Lab Ch 05", "Checkpoint Splits" }, { "MAP_EP_3_34", true, "EP3: Fire Section", "Checkpoint Splits" }, { "MAP_EP_3_35", true, "EP3: Loop 01", "Checkpoint Splits" }, { "MAP_EP_3_36", true, "EP3: Loop 02", "Checkpoint Splits" }, { "MAP_EP_3_37", true, "EP3: Loop 03", "Checkpoint Splits" }, { "MAP_EP_3_38", true, "EP3: Attic Entrance", "Checkpoint Splits" }, { "MAP_EP_4_1", true, "EP4: Hub Area Start", "Checkpoint Splits" }, { "MAP_EP_4_2", true, "EP4: Voyeur Ticket Room", "Checkpoint Splits" }, { "MAP_EP_4_3", true, "EP4: Voyeur Hallways Entrance", "Checkpoint Splits" }, { "MAP_EP_4_4", true, "EP4: Embracer Ladder", "Checkpoint Splits" }, { "MAP_EP_4_5", true, "EP4: Embracer Dead End", "Checkpoint Splits" }, { "MAP_EP_4_6", true, "EP4: After Embracer Mini Boss", "Checkpoint Splits" }, { "MAP_EP_4_7", true, "EP4: Sex Dungeon Ladder", "Checkpoint Splits" }, { "MAP_EP_4_8", true, "EP4: SoM Stealth Section", "Checkpoint Splits" }, { "MAP_EP_4_9", true, "EP4: Labyrinth After SoM Stealth Start", "Checkpoint Splits" }, { "MAP_EP_4_10", true, "EP4: Blade Trap Intro", "Checkpoint Splits" }, { "MAP_EP_4_11", true, "EP4: Blade Traps Big 4 Bladed Trap", "Checkpoint Splits" }, { "MAP_EP_4_12", true, "EP4: Double Walled Blade Traps", "Checkpoint Splits" }, { "MAP_EP_4_13", true, "EP4: Blade Trap And Ability", "Checkpoint Splits" }, { "MAP_EP_4_14", true, "EP4: Blade Trap And Ability End", "Checkpoint Splits" }, { "MAP_EP_4_15", true, "EP4: Rotating Rooms", "Checkpoint Splits" }, { "MAP_EP_4_16", true, "EP4: Rotating Rooms End", "Checkpoint Splits" }, { "MAP_EP_4_17", true, "EP4: After Syringe Moment", "Checkpoint Splits" }, { "MAP_EP_4_18", true, "EP4: Portals Room", "Checkpoint Splits" }, { "MAP_EP_4_19", true, "EP4: Portals Room End", "Checkpoint Splits" }, { "MAP_EP_4_20", true, "EP4: After Toilet Room", "Checkpoint Splits" }, { "MAP_EP_4_21", true, "EP4: After Chatterer Chase", "Checkpoint Splits" }, { "MAP_EP_4_22", true, "EP4: Chatterer Chase Start 02", "Checkpoint Splits" }, { "MAP_EP_4_23", true, "EP4: Hellchains Room", "Checkpoint Splits" }, { "MAP_EP_4_24", true, "EP4: After Hellchains Room", "Checkpoint Splits" }, { "MAP_EP_4_25", true, "EP4: Sex Rooms Entrance", "Checkpoint Splits" }, { "MAP_EP_4_26", true, "EP4: Long Hallway", "Checkpoint Splits" }, { "MAP_EP_4_27", true, "EP4: Sex Rooms Great Hall", "Checkpoint Splits" }, { "MAP_EP_4_28", true, "EP4: Sex Rooms After Great Hall Embracer", "Checkpoint Splits" }, { "MAP_EP_4_29", true, "EP4: Club Entrance", "Checkpoint Splits" }, { "MAP_EP_4_30", true, "EP4: SoM Fight Start", "Checkpoint Splits" }, { "MAP_EP_4_31", true, "EP4: Labyrinth After Boss Fight", "Checkpoint Splits" }, { "MAP_EP_4_32", true, "EP4: Attic Level End", "Checkpoint Splits" }, { "MAP_EP_5_1", true, "EP5: Attic Start", "Checkpoint Splits" }, { "MAP_EP_5_2", true, "EP5: Suffering Reward", "Checkpoint Splits" }, { "MAP_EP_5_3", true, "EP5: Outside Elevator Room", "Checkpoint Splits" }, { "MAP_EP_5_4", true, "EP5: Before Cenobite Door", "Checkpoint Splits" }, { "MAP_EP_5_5", true, "EP5: After Cenobite Door", "Checkpoint Splits" }, { "MAP_EP_5_6", true, "EP5: After Fallen Dialogue", "Checkpoint Splits" }, { "MAP_EP_5_7", true, "EP5: After Sculptures Room Dark Encounter", "Checkpoint Splits" }, { "MAP_EP_5_8", true, "EP5: Before Bruno Boss Fight", "Checkpoint Splits" }, { "MAP_EP_5_9", true, "EP5: After Bruno Banish", "Checkpoint Splits" }, { "MAP_EP_5_10", true, "EP5: TV Room", "Checkpoint Splits" }, { "MAP_EP_5_11", true, "EP5: Elevator Key Room", "Checkpoint Splits" }, { "MAP_EP_5_12", true, "EP5: Brunos Office Elevator", "Checkpoint Splits" }, { "MAP_EP_5_13", true, "EP5: After Stairs To Horror Hallways", "Checkpoint Splits" }, { "MAP_EP_5_14", true, "EP5: Before Water Collector Encounter", "Checkpoint Splits" }, { "MAP_EP_5_15", true, "EP5: Water Collector After Embracer Boss", "Checkpoint Splits" }, { "MAP_EP_5_16", true, "EP5: Distillery Entrance", "Checkpoint Splits" }, { "MAP_EP_5_17", true, "EP5: Distillery Exit", "Checkpoint Splits" }, { "MAP_EP_5_18", true, "EP5: Flooded Room Entrance", "Checkpoint Splits" }, { "MAP_EP_5_19", true, "EP5: After Flooded Room Bridge", "Checkpoint Splits" }, { "MAP_EP_5_20", true, "EP5: Catacombs Golden Skull", "Checkpoint Splits" }, { "MAP_EP_5_21", true, "EP5: Catacombs After Embracer Fight", "Checkpoint Splits" }, { "MAP_EP_5_22", true, "EP5: Catacombs Exit", "Checkpoint Splits" }, { "MAP_EP_5_23", true, "EP5: Church Entrance", "Checkpoint Splits" }, { "MAP_EP_5_24", true, "EP5: After Marlowe Boss Fight", "Checkpoint Splits" }, { "MAP_EP_5_25", true, "EP5: Attic After Boss Fight", "Checkpoint Splits" }, { "MAP_Epilogue_1", true, "Epilogue: Labyrinth Start", "Checkpoint Splits" }, { "MAP_Epilogue_2", true, "Epilogue: Bridge Start", "Checkpoint Splits" }, { "MAP_Epilogue_3", true, "Epilogue: Bridge Fall", "Checkpoint Splits" }, { "MAP_Epilogue_4", true, "Epilogue: Attic After Labyrinth", "Checkpoint Splits" }, { "Movies/Epilogue_Ending01.bk2", true, "Epilogue: Ending 1", "Splits" }, { "Movies/Epilogue_Ending02.bk2", true, "Epilogue: Ending 2", "Splits" }, { "Debug", false, "Debug", null }, { "World", false, "World", "Debug" }, { "CheckpointID", false, "CheckpointID", "Debug" }, { "isLoading", false, "isLoading", "Debug" }, { "BlockUI", false, "BlockUI", "Debug" }, { "EngineLoading", false, "EngineLoading", "Debug" }, { "SyncLoading", false, "SyncLoading", "Debug" }, { "Cutscene", false, "Cutscene", "Debug" }, { "Cinematic", false, "Cinematic", "Debug" }, }; vars.Uhara.Settings.Create(_settings); #endregion #region TextComponent vars.lcCache = new Dictionary(); vars.SetText = (Action)((text1, text2) => { const string FileName = "LiveSplit.Text.dll"; LiveSplit.UI.Components.ILayoutComponent lc; if (!vars.lcCache.TryGetValue(text1, out lc)) { lc = timer.Layout.LayoutComponents.Reverse().Cast() .FirstOrDefault(llc => llc.Path.EndsWith(FileName) && llc.Component.Settings.Text1 == text1) ?? LiveSplit.UI.Components.ComponentManager.LoadLayoutComponent(FileName, timer); vars.lcCache.Add(text1, lc); } if (!timer.Layout.LayoutComponents.Contains(lc)) timer.Layout.LayoutComponents.Add(lc); dynamic tc = lc.Component; tc.Settings.Text1 = text1; tc.Settings.Text2 = text2.ToString(); }); vars.RemoveText = (Action)(text1 => { LiveSplit.UI.Components.ILayoutComponent lc; if (vars.lcCache.TryGetValue(text1, out lc)) { timer.Layout.LayoutComponents.Remove(lc); vars.lcCache.Remove(text1); } }); #endregion vars.CompletedSplits = new HashSet(); } init { vars.Events = vars.Uhara.CreateTool("UnrealEngine", "Events"); vars.Utils = vars.Uhara.CreateTool("UnrealEngine", "Utils"); vars.Resolver.Watch("GSync", vars.Utils.GSync); //World vars.Resolver.Watch("GWorldPtr", vars.Utils.GWorld); vars.Resolver.Watch("GWorldFName", vars.Utils.GWorld, 0x18); // GameEngine.GameInstance(1248) -> CoreGameInstance.bBlockUIInputWhileLoading(300) vars.Resolver.Watch("BlockUI", vars.Utils.GEngine, 0x1248, 0x300); vars.Resolver.Watch("CheckpointID", vars.Events.InstancePtr("CheckpointSubsystem", "CheckpointSubsystem"), 0x38, 0x4E8); vars.Resolver["CheckpointID"].FailAction = MemoryWatcher.ReadFailAction.SetZeroOrNull; // UsingBinkMedia(448) is 1 while a cutscene plays. BinkMediaPlayer(430) -> URL(A8) is the movie name. IntPtr cinematic = vars.Events.InstancePtr("W_CinematicScreen_C", "W_CinematicScreen_C"); vars.Resolver.Watch("UsingBinkMedia", cinematic, 0x448); vars.Resolver["UsingBinkMedia"].FailAction = MemoryWatcher.ReadFailAction.SetZeroOrNull; vars.Resolver.WatchString("CinematicUrl", cinematic, 0x430, 0xA8, 0x0); #region Text Component vars.SetTextIfEnabled = (Action)((text1, text2) => { if (settings[text1]) vars.SetText(text1, text2); else vars.RemoveText(text1); }); #endregion current.World = ""; current.IsLoading = false; } update { vars.Uhara.Update(); var world = vars.Utils.FNameToString((uint)(current.GWorldFName & 0xFFFFFFFF)); uint number = (uint)(current.GWorldFName >> 32); if (!string.IsNullOrEmpty(world) && world != "None") current.World = number == 0 ? world : world + "_" + (number - 1); //loading setup if (current.BlockUI != 0 || current.GWorldPtr == 0UL) current.IsLoading = true; else if (old.GSync > 0 && current.GSync == 0) current.IsLoading = false; #region Debug Prints if (settings["Debug"]) { if (old.World != current.World) { vars.SetTextIfEnabled("World", current.World); print("World? " + current.World); } if (old.CheckpointID != current.CheckpointID) { vars.SetTextIfEnabled("CheckpointID", current.CheckpointID); print("CheckpointID? " + current.CheckpointID); } if (old.BlockUI != current.BlockUI) { vars.SetTextIfEnabled("BlockUI", current.BlockUI != 0); print("BlockUI? " + (current.BlockUI != 0).ToString()); } if ((old.GWorldPtr == 0UL) != (current.GWorldPtr == 0UL)) { vars.SetTextIfEnabled("EngineLoading", current.GWorldPtr == 0UL); print("EngineLoading? " + (current.GWorldPtr == 0UL).ToString()); } if ((old.GSync > 0) != (current.GSync > 0)) { vars.SetTextIfEnabled("SyncLoading", current.GSync > 0); print("SyncLoading? " + (current.GSync > 0).ToString()); } if (old.UsingBinkMedia != current.UsingBinkMedia) { vars.SetTextIfEnabled("Cutscene", current.UsingBinkMedia != 0); print("Cutscene? " + (current.UsingBinkMedia != 0).ToString()); } if (old.CinematicUrl != current.CinematicUrl) { vars.SetTextIfEnabled("Cinematic", current.CinematicUrl ?? ""); print("Cinematic? " + current.CinematicUrl); } if (old.IsLoading != current.IsLoading) { vars.SetTextIfEnabled("isLoading", current.IsLoading); print("isLoading? " + current.IsLoading.ToString()); } } #endregion } onStart { timer.IsGameTimePaused = true; timer.SetGameTime(TimeSpan.Zero); vars.CompletedSplits.Clear(); vars.CompletedSplits.Add(current.World); // the map the run starts in is not a new map } start { return old.World == "MAP_MainMenu" && current.World != "MAP_MainMenu"; } isLoading { return current.IsLoading || current.UsingBinkMedia != 0; } split { string key = null; // first entry into each map if (old.World != current.World && old.World != "" && old.World != "MAP_MainMenu" && current.World != "MAP_MainMenu") key = current.World; else if (current.CheckpointID > 0 && current.CheckpointID != old.CheckpointID && !current.IsLoading) key = current.World + "_" + current.CheckpointID; else if (old.CinematicUrl != current.CinematicUrl && (current.CinematicUrl == "Movies/Epilogue_Ending01.bk2" || current.CinematicUrl == "Movies/Epilogue_Ending02.bk2")) key = current.CinematicUrl; if (key == null) return false; print("Split? " + key); return vars.CompletedSplits.Add(key) && settings[key == current.World ? "MapEntry" : key]; } reset { return old.World != "MAP_MainMenu" && current.World == "MAP_MainMenu"; } exit { timer.IsGameTimePaused = true; } onReset { vars.CompletedSplits.Clear(); }