state("MassEffect2") {} state("ME2Game") {} init { // Exclude script from running if you open the Legendary edition of the game, which shares the same .exe name if (game.Is64Bit()) throw new Exception("Not OG Mass Effect!"); // Define pointer paths int[] boolsOffsets = new int[4] {0xE7F010, 0x11C, 0x4D0, 0x3C}; // Pointer path to the game's booleans int[] xyzOffsets = new int[3] {0xE8312C, 0x0, 0x4C}; // Pointer path to character position // Define vars.watchers vars.watchers = new MemoryWatcherList(); // isLoading variable (picked from the previous version of this autosplitter by PayDay) vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + 0xE6B644)) { Name = "isLoading" }); // Main story progression vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x14A)) { Name = "plotPrologue" }); // Used for prologue mission vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x43)) { Name = "plotCR0" }); // CR0, CR1, CR2 and CR3 are the CRitical missions that drive the story forward (Freedom's progress, Horizon, Collector Ship and Normany crew abduction) vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x27)) { Name = "plotCR123" }); // CR0, CR1, CR2 and CR3 are the CRitical missions that drive the story forward (Freedom's progress, Horizon, Collector Ship and Normany crew abduction) vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xB3)) { Name = "plotIFF" }); // Corresponds to Legion acquisition, but that is one and the same with the reaper IFF mission vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x12E)) { Name = "crewAbduct" }); // Used in place of CR3 for "reasons" vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xFE)) { Name = "suicideOculus" }); // Suicide mission: destroying the oculus vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x16F)) { Name = "suicideValve" }); // Suicide mission: making it through the ventilation system vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x170)) { Name = "suicideBubble" }); // Suicide mission: making it through the biotic bubble part vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x1BC)) { Name = "suicideReaper" }); // Used for signalling the end of the game // Dossiers vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x278)) { Name = "crewAcq1" }); // For Mordin, Jack, Garrus, Tali vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x4D)) { Name = "crewAcq2" }); // For Grunt vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x279)) { Name = "crewAcq3" }); // For Thane vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x47)) { Name = "crewAcq4" }); // For Samara vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x32)) { Name = "crewAcq5" }); // For Zaeed vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xB9)) { Name = "crewAcq6" }); // For Kasumi // Loyalty missions vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xBB)) { Name = "loyaltyMissions1" }); // Loyalty mission status for Miranda, Jacob, Jack, Legion, Kasumi, Garrus, Thane and Tali vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xBC)) { Name = "loyaltyMissions2" }); // Loyalty mission status for Mordin, Grunt, Samara/Morinth and Zaeed // N7 Missions vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x1A8)) { Name = "WMF" }); // N7: Wrecked Merchant Freighter vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x225)) { Name = "ARS" }); // N7: Abandoned Research Station vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x18C)) { Name = "ADS" }); // N7: Archeological Dig Site vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x156)) { Name = "MSVE" }); // N7: MSV Estevanico vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x28A)) { Name = "ESD" }); // N7: Eclipse Smuggling Depot (and N7: Endangered Research Station) vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x288)) { Name = "LO" }); // N7: Lost Operative // X, Y and Z positions vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + xyzOffsets[0], xyzOffsets[1], xyzOffsets[2], 0x110)) { Name = "XPOS" }); vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + xyzOffsets[0], xyzOffsets[1], xyzOffsets[2], 0x114)) { Name = "YPOS" }); vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + xyzOffsets[0], xyzOffsets[1], xyzOffsets[2], 0x118)) { Name = "ZPOS" }); // Address checks put in place for avoiding unwanted splitting vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x158)) { Name = "splitchecks01" }); vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0xE8)) { Name = "splitchecks02" }); vars.watchers.Add(new MemoryWatcher(new DeepPointer(modules.First().BaseAddress + boolsOffsets[0], boolsOffsets[1], boolsOffsets[2], boolsOffsets[3], 0x39)) { Name = "splitchecks03" }); // Custom functions used for autosplitting vars.bitCheck = new Func((string plotEvent, int b) => ((byte)(vars.watchers[plotEvent].Current) & (1 << b)) != 0); } startup { // Autosplitting settings settings.Add("escapeLazarus", true, "Prologue: Awakening"); settings.Add("freedomProgress", true, "Freedom's Progress"); settings.Add("recruitMordin", true, "Dossier: The Professor"); settings.Add("recruitGarrus", true, "Dossier: Archangel"); settings.Add("recruitJack", true, "Dossier: The Convict"); settings.Add("acquireGrunt", true, "Dossier: The Warlord"); settings.Add("horizonCompleted", true, "Horizon"); settings.Add("N7_WMF", true, "N7: Wrecked Merchant Freighter"); // Eagle Nebula --> Amun --> Neith settings.Add("N7_ARS", true, "N7: Abandoned Research Station"); // Jarrahe Station settings.Add("N7_ADS", true, "N7: Archeological Dig Site"); // Rosetta --> Enoch (Prothean artifact) settings.Add("N7_MSVE", true, "N7: MSV Estevanico"); // Hourglass --> Ploitari --> Zanethu settings.Add("N7_ESD", true, "N7: Eclipse Smuggling Depot"); // Hourglass --> Faryar --> Daratar settings.Add("collectorShip", true, "Collector ship"); settings.Add("reaperIFF", true, "Reaper IFF"); settings.Add("N7_ERS", true, "N7: Endangered Research Station"); // Caleston Rift --> Solveig --> Sinmara settings.Add("N7_LO", true, "N7: Lost Operative"); // Omega Nebula --> Fathar --> Lorek settings.Add("crewAbuct", true, "Normandy crew abduction"); settings.Add("ME2SuocideMission", true, "Suicide Mission"); settings.Add("ME2Oculus", true, "Oculus", "ME2SuocideMission"); settings.Add("ME2Valve", true, "Valve", "ME2SuocideMission"); settings.Add("ME2Bubble", true, "Bubble", "ME2SuocideMission"); settings.Add("ME2ending", true, "Human Reaper", "ME2SuocideMission"); settings.Add("DLCcharactersRectuitment", false, "DLC Characters rectuitment"); settings.Add("recruitKasumi", true, "Dossier: The Master Thief", "DLCcharactersRectuitment"); settings.Add("recruitZaeed", true, "Dossier: The Veteran", "DLCcharactersRectuitment"); settings.Add("ME2OptionalDossiers", true, "Optional Dossiers"); settings.Add("recruitThane", true, "Dossier: The Assassin", "ME2OptionalDossiers"); settings.Add("recruitSamara", true, "Dossier: The Justicar", "ME2OptionalDossiers"); settings.Add("recruitTali", true, "Dossier: Tali", "ME2OptionalDossiers"); settings.Add("ME2LoyaltyMissions", true, "Loyalty Missions"); settings.Add("loyaltyMiranda", true, "Miranda", "ME2LoyaltyMissions"); settings.Add("loyaltyJacob", true, "Jacob", "ME2LoyaltyMissions"); settings.Add("loyaltyJack", true, "Jack", "ME2LoyaltyMissions"); settings.Add("loyaltyLegion", true, "Legion", "ME2LoyaltyMissions"); settings.Add("loyaltyKasumi", true, "Kasumi", "ME2LoyaltyMissions"); settings.Add("loyaltyGarrus", true, "Garrus", "ME2LoyaltyMissions"); settings.Add("loyaltyThane", true, "Thane", "ME2LoyaltyMissions"); settings.Add("loyaltyTali", true, "Tali", "ME2LoyaltyMissions"); settings.Add("loyaltyMordin", true, "Mordin", "ME2LoyaltyMissions"); settings.Add("loyaltyGrunt", true, "Grunt", "ME2LoyaltyMissions"); settings.Add("loyaltySamara", true, "Samara", "ME2LoyaltyMissions"); settings.Add("loyaltyZaeed", true, "Zaeed", "ME2LoyaltyMissions"); } update { vars.watchers.UpdateAll(game); // Main story progression missions current.lazarusCompleted = vars.bitCheck("plotPrologue", 5) && !vars.bitCheck("plotCR0", 1); current.FreedomProgressCompleted = vars.bitCheck("plotCR0", 1); current.horizonCompleted = vars.bitCheck("plotCR123", 0); current.collectorShipCompleted = vars.bitCheck("plotCR123", 1); current.reaperIFFcompleted = vars.bitCheck("plotIFF", 3); current.crewAbductMissionComplete = vars.bitCheck("crewAbduct", 1); // Suicide mission current.suicideOculusDestroyed = vars.bitCheck("suicideOculus", 4); current.suicideValveCompleted = vars.bitCheck("suicideValve", 5); current.suicideBubbleCompleted = vars.bitCheck("suicideBubble", 0); current.suicideMissonCompleted = vars.bitCheck("suicideReaper", 3) || vars.bitCheck("suicideReaper", 5) || vars.bitCheck("suicideReaper", 6); // Recruitment missions Phase 1 current.MordinRecruited = vars.bitCheck("crewAcq1", 6); current.GarrusRecruited = vars.bitCheck("crewAcq1", 5); current.JackRecruited = vars.bitCheck("crewAcq1", 3); current.GruntTankRecovered = vars.bitCheck("crewAcq2", 2); // Recruitment missions Phase 2 current.TaliRecruited = vars.bitCheck("crewAcq1", 7); current.ThaneRecruited = vars.bitCheck("crewAcq3", 1); current.SamaraRecruited = vars.bitCheck("crewAcq4", 4); // N7 missions current.N7WMF_completed = vars.bitCheck("WMF", 0); current.N7ARS_completed = vars.bitCheck("ARS", 6); current.N7ADS_completed = vars.bitCheck("ADS", 0); current.N7MSVE_completed = vars.bitCheck("MSVE", 2); current.N7ESD_completed = vars.bitCheck("ESD", 2); current.N7ERS_completed = vars.bitCheck("ESD", 3); current.N7LO_completed = vars.bitCheck("LO", 7); // DLC recruitments current.ZaeedRecruited = vars.bitCheck("crewAcq5", 4); current.KasumiRecruited = vars.bitCheck("crewAcq6", 4); // Loyalty missions current.MirandaLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 0); current.JacobLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 1); current.JackLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 2); current.LegionLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 3); current.KasumiLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 4); current.GarrusLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 5); current.ThaneLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 6); current.TaliLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions1", 7); current.MordinLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions2", 0); current.GruntLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions2", 1); current.SamaraLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions2", 2); current.ZaeedLoyaltyMissionCompleted = vars.bitCheck("loyaltyMissions2", 3); // Split Checks // This is used for a consistency check to prevent unwanted splits (which WILL happen // if you load a savefile of if you return from the game to the main menu). // Essentially, the game checks whather the first 3 booleans of the game are set to true // The booleans are: // 1. Journal updates with the mission "Rescue Joker" // 2. Reached upper deck in the Normandy SR1 in the prologue // 3. Rescued Joker // 4. Normandy SR1 destroyed // All 4 booleans are necessarily set to true in the prologue because they are an essential part of the game progression, // so if even one of those 3 is not checked, it means the game is doing funny stuff in memory and LiveSplit should not split. current.allowsplitting = vars.bitCheck("splitchecks02", 2) && vars.bitCheck("splitchecks01", 7) && vars.bitCheck("splitchecks02", 3) && vars.bitCheck("splitchecks03", 7); } start { // Start the timer as soon as you move from the default starting position in Lazarus Lab return (vars.watchers["XPOS"].Old == 1136428027 && vars.watchers["YPOS"].Old == 3338886377 && (vars.watchers["XPOS"].Changed || vars.watchers["YPOS"].Changed) && current.allowsplitting); } isLoading { return vars.watchers["isLoading"].Current; } split { return current.allowsplitting && old.allowsplitting && ( // Main story progression (settings["escapeLazarus"] && current.lazarusCompleted && !old.lazarusCompleted && !current.FreedomProgressCompleted) || (settings["freedomProgress"] && current.FreedomProgressCompleted && !old.FreedomProgressCompleted) || (settings["horizonCompleted"] && current.horizonCompleted && !old.horizonCompleted) || (settings["collectorShip"] && current.collectorShipCompleted && !old.collectorShipCompleted) || (settings["reaperIFF"] && current.reaperIFFcompleted && !old.reaperIFFcompleted) || (settings["crewAbuct"] && current.crewAbductMissionComplete && !old.crewAbductMissionComplete) || // Suicide Mission (settings["ME2Oculus"] && current.suicideOculusDestroyed && !old.suicideOculusDestroyed) || (settings["ME2Valve"] && current.suicideValveCompleted && !old.suicideValveCompleted) || (settings["ME2Bubble"] && current.suicideBubbleCompleted && !old.suicideBubbleCompleted) || (settings["ME2ending"] && current.suicideMissonCompleted && !old.suicideMissonCompleted) || // N7 missions (settings["N7_WMF"] && current.N7WMF_completed && !old.N7WMF_completed) || (settings["N7_ARS"] && current.N7ARS_completed && !old.N7ARS_completed) || (settings["N7_ADS"] && current.N7ADS_completed && !old.N7ADS_completed) || (settings["N7_MSVE"] && current.N7MSVE_completed && !old.N7MSVE_completed) || (settings["N7_ESD"] && current.N7ESD_completed && !old.N7ESD_completed) || (settings["N7_ERS"] && current.N7ERS_completed && !old.N7ERS_completed) || (settings["N7_LO"] && current.N7LO_completed && !old.N7LO_completed) || // Dossiers (used to split for Phase 1 of the game and for DLC characters) (settings["recruitMordin"] && current.MordinRecruited && !old.MordinRecruited) || (settings["recruitGarrus"] && current.GarrusRecruited && !old.GarrusRecruited) || (settings["acquireGrunt"] && current.GruntTankRecovered && !old.GruntTankRecovered) || (settings["recruitJack"] && current.JackRecruited && !old.JackRecruited) || (settings["recruitZaeed"] && current.ZaeedRecruited && !old.ZaeedRecruited) || (settings["recruitKasumi"] && current.KasumiRecruited && !old.KasumiRecruited) || // Phase 2 Dossiers (settings["recruitTali"] && current.TaliRecruited && !old.TaliRecruited) || (settings["recruitSamara"] && current.SamaraRecruited && !old.SamaraRecruited) || (settings["recruitThane"] && current.ThaneRecruited && !old.ThaneRecruited) || // Loyalty missions (settings["loyaltyMiranda"] && current.MirandaLoyaltyMissionCompleted && !old.MirandaLoyaltyMissionCompleted) || (settings["loyaltyJacob"] && current.JacobLoyaltyMissionCompleted && !old.JacobLoyaltyMissionCompleted) || (settings["loyaltyJack"] && current.JackLoyaltyMissionCompleted && !old.JackLoyaltyMissionCompleted) || (settings["loyaltyLegion"] && current.LegionLoyaltyMissionCompleted && !old.LegionLoyaltyMissionCompleted) || (settings["loyaltyKasumi"] && current.KasumiLoyaltyMissionCompleted && !old.KasumiLoyaltyMissionCompleted) || (settings["loyaltyGarrus"] && current.GarrusLoyaltyMissionCompleted && !old.GarrusLoyaltyMissionCompleted) || (settings["loyaltyThane"] && current.ThaneLoyaltyMissionCompleted && !old.ThaneLoyaltyMissionCompleted) || (settings["loyaltyTali"] && current.TaliLoyaltyMissionCompleted && !old.TaliLoyaltyMissionCompleted) || (settings["loyaltyMordin"] && current.MordinLoyaltyMissionCompleted && !old.MordinLoyaltyMissionCompleted) || (settings["loyaltyGrunt"] && current.GruntLoyaltyMissionCompleted && !old.GruntLoyaltyMissionCompleted) || (settings["loyaltySamara"] && current.SamaraLoyaltyMissionCompleted && !old.SamaraLoyaltyMissionCompleted) || (settings["loyaltyZaeed"] && current.ZaeedLoyaltyMissionCompleted && !old.ZaeedLoyaltyMissionCompleted) ); }