// People who collectively worked on this: // DrTChops // Glurmo // TheFuncannon // loitho // sychotixx // Instagibz // blairmadison11 // heny // Meta // SabulineHorizon // probably more //===NOTES AND CHANGELOG===// //Known Bugs: Auto-reset sometimes causes the timer start to fail in the intro for a classic start //SabulineHorizon @08\27\24: Widened the search region for start player position to make start more reliable //Meta & SabulineHorizon @08\15\24: Updated loading address, updated code logic, fixed some bugs, removed legacy code //SabulineHorizon @07\18\24: Updated the splitter for 1,0,0,1 version (in progress, there are probably some bugs) //SabulineHorizon @08\12\21: Added Auto-Reset, added split for Spider Mastermind Skip, fixed timer start delays, fixed optional intro split bug, fixed random intro timer starts, fixed UN start split //Meta @03\08\21: Added popup that detects real time & asks if you want game time comparison. Added livesplit cycle fix that otherwise starts timer @ 0.00 - 0.06 //heny @21\08\20: Added setting to optionally split at the end of the intro section //heny @21\08\20: Updated the splitter for the latest 6,1,1,321 version to support OpenGL + added setting to optionally split between Lazarus Labs 1 & 2 //Glurmo @23\01\19: Removed steam api ("tier0_s64.dll") dependency to prevent steam client updates breaking autosplitter + Add NG+ support //Glurmo @21\01\19: Fixed map name pointer for steam update (4.89.17.15) + added skipping of rune loadscreens for 100% //Instagibz @04\04\18: Updated the splitter for latest 6,1,1,321 version, VULKAN only //Loitho @13\10\17: Fixed mapname variable. Invalid pointer caused by a steam update of the tier0_s64.dll | Works for Steam >= 4.17.60.88 //Loitho @09\09\17: Fixed the splitter for auto split on last boss hit 6,1,1,818 - Vulkan only //blairmadison11 @02\09\17: Partially updated the splitter for the latest 6,1,1,818, VULKAN only //Instagibz & blairmadison11 @22\07\17: Updated the splitter for the latest 6,1,1,513 version, VULKAN only for now. Note: Versioning changed back from 6,1,1,1219 to 6,1,1,513 //Instagibz @29\01\17: Updated the splitter for latest steam-api change //Instagibz @20\12\16: Updated the splitter for latest 6,1,1,1219 version, VULKAN only for now //Instagibz @08\12\16: Updated the splitter for latest 6,1,1,1201 version, VULKAN only for now //Instagibz @14\11\16: Updated the splitter for latest 6,1,1,1109 version //Instagibz @19\10\16: Updated the splitter for latest 6,1,1,1012 version //Instagibz @30\09\16: Added auto-end to 6,1,1,706 also changed auto-start, was broken for me a few times //TheFuncannon @30\09\16: Updated the OGL version 6,1,1,706 to auto-start //Instagibz @30\09\16: Updated the vulkan and OGL version 6,1,1,920 to auto-start, auto-split and auto-end the run. Requires 13 splits //===NOTES AND CHANGELOG===// // 2024-04-11 Patch (Vulkan) state("DOOMx64vk", "1, 0, 0, 1") { float bossHealth: 0x2F60468, 0x30, 0x4E8, 0x2F0, 0x1B4; float playerX: 0x5BB6058; float playerY: 0x5BB605C; float playerZ: 0x5BB6060; // bool start: 0x597FCD0; //Removed because replacement wasn't found. Intro cutscene start now relies on player position bool finalHit: 0x35EB8EC; bool notLoading: 0x360FF58; //0 is loading, 1 is not loading bool menuOpen: 0x360F644; byte menuSelection: 0x5BE3778, 0x218, 0x2C8, 0x1B8, 0x1A4; //0-Resume, 1-Settings , 2-Load Checckpoint , 3-Restart Mission , 4-Exit to Main Menu , 5-Exit to Desktop byte deathReset: 0x5FA9ACA; //44 when death menu appears, and 36 when resetting byte difficulty: 0x5D4C9A0; //0-I'm Too Young To Die, 1-Hurt Me Plenty, 2-Ultra-Violence, 3-Nightmare 4 = Ultra-Nightmare int finalCutscene: 0x7068D98; string60 mapFile: 0x66E13B5; } startup { vars.TimerStart = (EventHandler) ((s, e) => timer.IsGameTimePaused = true); timer.OnStart += vars.TimerStart; //^ Ensures the timer starts at 0.00, thanks Gelly for this if (timer.CurrentTimingMethod == TimingMethod.RealTime) // Pops up if real time comparison is detected, asking if you want to switch to Game Time. Thanks Micrologist for this. { var timingMessage = MessageBox.Show ( "This game uses Time without Loads (Game Time) as the main timing method.\n"+ "LiveSplit is currently set to show Real Time (RTA).\n"+ "Would you like to set the timing method to Game Time?", "LiveSplit | DOOM 2016", MessageBoxButtons.YesNo,MessageBoxIcon.Question ); if (timingMessage == DialogResult.Yes) { timer.CurrentTimingMethod = TimingMethod.GameTime; } } settings.Add("optionalSplits", true, "Optional Splits (Game Version 6, 1, 1, 321 and 1, 0, 0, 1)"); settings.Add("splitForIntro", true, "Intro", "optionalSplits"); settings.Add("splitForLazarusLabs1", true, "Lazarus Labs 1", "optionalSplits"); settings.Add("noCheckpointResets", false, "No checkpoint reset"); settings.Add("spamFinalSplit", false, "Spam split on final cutscene"); settings.SetToolTip("optionalSplits", "Optionally split for special situations/in special locations (currently only working on game version 6, 1, 1, 321)"); settings.SetToolTip("splitForIntro", "Split when smashing the elevator button panel in the intro section"); settings.SetToolTip("splitForLazarusLabs1", "Split at the end of the first part of Lazarus Labs"); settings.SetToolTip("noCheckpointResets", "Do not reset the timer when reloading checkpoint at the start of Intro"); settings.SetToolTip("spamFinalSplit", "Repeatedly trigger final split when the final cutscene starts"); vars.visitedMapFiles = new List<string>(); vars.introMapFile = "game/sp/intro/intro"; // UAC vars.mapFileSplits = new List<string>() { "game/sp/resource_ops/resource_ops", // Resource Operations "game/sp/resource_ops_foundry/resource_ops_foundry", // Foundry "game/sp/surface1/surface1", // Argent Facility "game/sp/argent_tower/argent_tower", // Argent Energy Tower "game/sp/blood_keep/blood_keep", // Kadingir Sanctum "game/sp/surface2/surface2", // Argent Facility (Destroyed) "game/sp/bfg_division/bfg_division", // Advanced Research Complex "game/sp/lazarus/lazarus", // Lazarus Labs (1) "game/sp/blood_keep_b/blood_keep_b", // Titan's Realm "game/sp/blood_keep_c/blood_keep_c", // The Necropolis "game/sp/polar_core/polar_core", // VEGA Central Processing "game/sp/titan/titan", // Argent D'Nur }; } init { vars.hasSplitForIntro = false; vars.resetType = 0; vars.pauseStart = false; vars.endCutsceneCanTrigger = false; var firstModule = modules.First(); version = firstModule.FileVersionInfo.FileVersion; print(version); } update { if (vars.pauseStart){ vars.pauseStart = current.menuOpen; } } exit { timer.IsGameTimePaused = true; } start { vars.hasSplitForIntro = false; vars.visitedMapFiles = new List<string>(); vars.pauseStart = false; vars.resetType = 0; vars.endCutsceneCanTrigger = false; if (settings["splitForLazarusLabs1"]) { vars.mapFileSplits.Add("game/sp/lazarus_2/lazarus_2"); } else { vars.mapFileSplits.Remove("game/sp/lazarus_2/lazarus_2"); } //If we're starting UN instead of another difficulty if (!old.notLoading && current.notLoading && (current.difficulty == 4)){ Thread.Sleep(3560); return ( (Math.Abs(current.playerX - (-10200.00)) < 1) && (Math.Abs(current.playerY - (-2624.00)) < 1) && (Math.Abs(current.playerZ - (9540.00)) < 6) ); } if ( //reload checkpoint or failed restart mission current.mapFile == vars.introMapFile && ((!old.notLoading && current.notLoading && (Math.Abs(current.playerX - (-18101.34)) < 2) && (Math.Abs(current.playerY - (-2782.34)) < 2) && (Math.Abs(current.playerZ - (3076.90)) < 2)) || //new game or restart mission (current.notLoading && // !old.start && // current.start && (Math.Abs(current.playerX - (-18029.99)) < 2) && (Math.Abs(current.playerY - (-2736.30)) < 2) && (Math.Abs(current.playerZ - (3073.49)) < 2) ) ) ){ vars.pauseStart = true; //pause timer on start if menu is open during loading (usually caused by alt+tabbing during load) return true; } } reset { if (current.difficulty == 4){ //UN difficulty return ( old.deathReset == 36 && current.deathReset == 44 && current.mapFile == "game/sp/intro/intro" ); } else { //Other difficulty if (current.menuSelection == 2){ vars.resetType = 2;} else if (current.menuSelection == 3){ vars.resetType = 3;} return ( current.mapFile == vars.introMapFile && !current.notLoading && ( ( old.notLoading && current.menuSelection == 3 ) || ( // current.menuSelection == 2 && !settings["noCheckpointResets"] && (Math.Abs(current.playerX - (-18101.34)) < 2) && (Math.Abs(current.playerY - (-2782.34)) < 2) && (Math.Abs(current.playerZ - (3076.90)) < 2) ) ) ); } } split { bool finalSplit = !current.finalHit && current.bossHealth == 1; bool levelSplit = !String.IsNullOrEmpty(current.mapFile) && !String.IsNullOrEmpty(old.mapFile) && old.mapFile != current.mapFile && !current.notLoading && !old.mapFile.Contains("challenges/") && vars.mapFileSplits.Contains(current.mapFile); if (finalSplit) { return true; } else if (levelSplit && !vars.visitedMapFiles.Contains(current.mapFile)) { // Track to prevent splitting twice in 100% vars.visitedMapFiles.Add(current.mapFile); return true; } else if (current.mapFile == "game/sp/intro/intro") { if (!vars.hasSplitForIntro && settings["splitForIntro"]) { // Optional intro split when smashing the panel bool inUAC = current.mapFile.Equals("game/sp/intro/intro"); bool correctIntroSplitXPos = Math.Abs(current.playerX - (-10152.54)) < 0.1; bool correctIntroSplitYPos = Math.Abs(current.playerY - (-2685.575)) < 0.1; bool correctIntroSplitZPos = Math.Abs(current.playerZ - 3148.311) < 0.1; bool correctIntroSplitPos = correctIntroSplitXPos && correctIntroSplitYPos && correctIntroSplitZPos; if (inUAC && correctIntroSplitPos) { vars.hasSplitForIntro = true; return true; } } } else if (current.mapFile == "game/sp/titan/titan") { //Spider Mastermind Skip if ( (current.playerX > -80) && (current.playerX < 215) && (current.playerY > -80) && (current.playerY < 215) && (current.playerZ > -10080) && (current.playerZ < -9800) && (current.finalCutscene == 5) && (old.finalCutscene != 5) ){ vars.endCutsceneCanTrigger = true; } //Trigger final split if (vars.endCutsceneCanTrigger) { if(!settings["spamFinalSplit"]) vars.endCutsceneCanTrigger = false; return true; } } else if (!current.notLoading && vars.endCutsceneCanTrigger) {vars.endCutsceneCanTrigger = false;} return false; } isLoading { return (!current.notLoading | vars.pauseStart); } shutdown{ timer.OnStart -= vars.TimerStart; }