state("Watch_Dogs") { // unknown/default version } state("Watch_Dogs" , "v1.04.497") { int XP: "Disrupt_b64.dll", 0x396E038, 0x768, 0x0, 0x60, 0x8, 0xB8, 0x20; int act1mainmissions: "Disrupt_b64.dll", 0x3950830, 0xA8, 0x18, 0xC8, 0x18, 0x180, 0x98, 0xC24; int act2mainmissions: "Disrupt_b64.dll", 0x3950830, 0x10, 0x48, 0x38, 0x98, 0x2C4; int act3mainmissions: "Disrupt_b64.dll", 0x3950830, 0x18, 0x10, 0x50, 0x30, 0x68, 0x654; int act4mainmissions: "Disrupt_b64.dll", 0x3950830, 0x58, 0x78, 0x98, 0x954; int lineid: "Disrupt_b64.dll", 0x3940438, 0x20; int ending: "Disrupt_b64.dll", 0x393EB78; int loading: "Disrupt_b64.dll", 0x39562CC; int lineIdIdx0: "Disrupt_b64.dll", 0x3940438, 0x8, 0x30; int lineIdIdx1: "Disrupt_b64.dll", 0x3940438, 0x8, 0x70; } state("Watch_Dogs" , "v1.06.329 Steam Latest") { int XP: "Disrupt_b64.dll", 0x3BDB920, 0x90, 0x18, 0xAA8; int act1mainmissions: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x78, 0x98, 0xEC4; int act2mainmissions: "Disrupt_b64.dll", 0x3B70098, 0x40, 0x48, 0x168, 0x3B4; int act3mainmissions: "Disrupt_b64.dll", 0x3B70098, 0x40, 0x48, 0x1A0, 0x7D4; int act4mainmissions: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0xB64; int badbloodact1: "Disrupt_b64.dll", 0x3B78918, 0x110, 0x1F8, 0x98, 0x2F4; int badbloodact2: "Disrupt_b64.dll", 0x3B78918, 0xE0, 0x1E8, 0x98, 0x54; int badbloodact3: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0x1D4; int lineid: "Disrupt_b64.dll", 0x3B5CAB8, 0x20; int ending: "Disrupt_b64.dll", 0x3B5B078; int loading: "Disrupt_b64.dll", 0x3B7BAFC; int lineIdIdx0: "Disrupt_b64.dll", 0x3B5CAB8, 0x8, 0x30; int lineIdIdx1: "Disrupt_b64.dll", 0x3B5CAB8, 0x8, 0x70; int hotspots: "Disrupt_b64.dll", 0x3BE3738, 0x18, 0x180, 0x98, 0x84; int ctosbreach: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0xC54; int ctostower: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x78, 0x98, 0x324; int privacyinvasion: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0xE64; int songsneak: "Disrupt_b64.dll", 0x3BE3738, 0x18, 0x180, 0x98, 0xBC4; int weapontrade: "Disrupt_b64.dll", 0x3B78918, 0x110, 0x1F8, 0x98, 0x1A4; int missingpersons: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0xE34; int qrcodes: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x78, 0x98, 0x9E4; int burnerphones: "Disrupt_b64.dll", 0x3B70098, 0x40, 0x48, 0x98, 0xAA4; int humantraffic: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x78, 0x98, 0xFB4; int drinkinggame: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x78, 0x98, 0xEF4; int shellgame: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0x5F4; int fixer: "Disrupt_b64.dll", 0x3B70098, 0x10, 0x48, 0x98, 0xF24; int audiologs: "Disrupt_b64.dll", 0x03B70098, 0x48, 0x10, 0x108, 0x38, 0x10, 0x80; } state("Watch_Dogs" , "v1.06.329 Uplay Latest") { int XP: "Disrupt_b64.dll", 0x3B59050, 0x40, 0x98, 0x248, 0xA8; int act1mainmissions: "Disrupt_b64.dll", 0x3B91918, 0xE0, 0x1E8, 0x98, 0xEC4; int act2mainmissions: "Disrupt_b64.dll", 0x3B91918, 0x110, 0x1F8, 0x168, 0x3B4; int act3mainmissions: "Disrupt_b64.dll", 0x3B91918, 0xE0, 0xC8, 0x18, 0x180, 0x98, 0x7D4; int act4mainmissions: "Disrupt_b64.dll", 0x3B91918, 0xE0, 0x1E8, 0x98, 0xB64; int badbloodact1: "Disrupt_b64.dll", 0x3B91918, 0x110, 0x1F8, 0x98, 0x2F4; int badbloodact2: "Disrupt_b64.dll", 0x3B91918, 0xE0, 0x1E8, 0x98, 0x54; int badbloodact3: "Disrupt_b64.dll", 0x3B91918, 0x10, 0x48, 0x98, 0x1D4; int lineid: "Disrupt_b64.dll", 0x3B784F8, 0x20; int ending: "Disrupt_b64.dll", 0x3B76B28; int loading: "Disrupt_b64.dll", 0x3B94ACC; int lineIdIdx0: "Disrupt_b64.dll", 0x3B784F8, 0x8, 0x30; int lineIdIdx1: "Disrupt_b64.dll", 0x3B784F8, 0x8, 0x70; int hotspots: "Disrupt_b64.dll", 0x3B91918, 0x110, 0x1F8, 0x98, 0x84; } startup{ vars.stopwatch = new Stopwatch(); vars.line0Stopwatch = new Stopwatch(); vars.line1Stopwatch = new Stopwatch(); settings.Add ("CTOS Control Centers", false, "CTOS Control Centers"); settings.SetToolTip("CTOS Control Centers", "Splits after completing a ctOS control center."); settings.CurrentDefaultParent = "CTOS Control Centers"; settings.Add("Brandon Docks", false, "Brandon Docks"); settings.Add("The Wards", false, "The Wards"); settings.Add("Mad Mile", false, "Mad Mile"); settings.Add("Pawnee", false, "Pawnee"); settings.CurrentDefaultParent = null; settings.Add("Hacking Contract", false, "Hacking Contract"); settings.SetToolTip("Hacking Contract", "Splits after completing the hacking invasion mission in Act 1 with 2XTheTap and accessing the online contracts app"); settings.Add("Remember", false, "Remember"); settings.SetToolTip("Remember", "Splits after the cemetery cutscene in Act 1"); settings.Add("Any% Ending", true, "Any% Ending"); settings.SetToolTip("Any% Ending", "Splits when Aiden shoots Damien at the end of the game"); settings.Add("Log Dialog", false, "Log Dialog"); settings.SetToolTip("Log Dialog", "Log line IDs and their duration in milliseconds as they occurred in the run to LineLog.txt next to your LiveSplit.exe"); settings.Add ("100%", false, "100%"); settings.CurrentDefaultParent = "100%"; settings.Add("Hotspots", false, "Hotspots"); settings.SetToolTip("Hotspots", "Splits for each hotspot obtained"); settings.Add("ctOS Breaches", false, "ctOS Breaches"); settings.SetToolTip("ctOS Breaches", "Splits for each ctOS breach done"); settings.Add("ctOS Towers", false, "ctOS Towers"); settings.SetToolTip("ctOS Towers", "Splits for each ctOS Tower done"); settings.Add("Privacy Invasions", false, "Privacy Invasions"); settings.SetToolTip("Privacy Invasions", "Splits for each privacy invasion done"); settings.Add("SongSneak", false, "SongSneak"); settings.SetToolTip("SongSneak", "Splits for each SongSneak done"); settings.Add("Weapons Trade", false, "Weapons Trade"); settings.SetToolTip("Weapons Trade", "Splits for each weapons trade done"); settings.Add("Missing Persons", false, "Missing Persons"); settings.SetToolTip("Missing Persons", "Splits for each missing persons done"); settings.Add("QR Codes", false, "QR Codes"); settings.SetToolTip("QR Codes", "Splits for each QR code done"); settings.Add("Burner Phones", false, "Burner Phones"); settings.SetToolTip("Burner Phones", "Splits for each burner phone done"); settings.Add("Human Traffic", false, "Human Traffic"); settings.SetToolTip("Human Traffic", "Splits for each human trafficking location done"); settings.Add("Drinking Game", false, "Drinking Game"); settings.SetToolTip("Drinking Game", "Splits for each drinking game done"); settings.Add("Shell Game", false, "Shell Game"); settings.SetToolTip("Shell Game", "Splits for each shell game done"); settings.Add("Fixer Contracts", false, "Fixer Contracts"); settings.SetToolTip("Fixer Contracts", "Splits after the 40th fixer contract is completed"); settings.Add("Audio Logs", false, "Audio Logs"); settings.SetToolTip("Audio Logs", "Splits for each audio log completed"); Action logDebug = (text) => { print("[Watch_Dogs Autosplitter | DEBUG] "+ text); }; vars.logDebug = logDebug; Func calcModuleHash = (module) => { vars.logDebug("Calcuating hash of " + module.FileName); byte[] exeHashBytes = new byte[0]; using (System.Security.Cryptography.MD5 sha = System.Security.Cryptography.MD5.Create()) { using (FileStream s = File.Open(module.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { exeHashBytes = sha.ComputeHash(s); } } string hash = exeHashBytes.Select(x => x.ToString("X2")).Aggregate((a, b) => a + b); vars.logDebug("Hash: " + hash); return hash; }; vars.calcModuleHash = calcModuleHash; vars.lastSplitTime = null; Func isNotDoubleSplit = () => { bool isDoubleSplit = false; if (vars.lastSplitTime != null) { System.TimeSpan ts = System.DateTime.Now - vars.lastSplitTime; if (ts.TotalSeconds < 15) { isDoubleSplit = true; vars.logDebug("Double split detected!"); } } vars.lastSplitTime = System.DateTime.Now; return !isDoubleSplit; }; vars.isNotDoubleSplit = isNotDoubleSplit; Action logLine = (text) => { vars.logDebug("Writing line: " + text); if (vars.lineLogFile == null) { vars.lineLogFile = File.Open("LineLog.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite); } byte[] line = new UTF8Encoding(true).GetBytes(text + "\r\n"); vars.lineLogFile.Write(line, 0, line.Length); vars.lineLogFile.Flush(true); }; vars.lineLogFile = null; vars.logLine = logLine; Action detectLineChange = (oldLineId, newLineId, stopwatch) => { // if (oldLineId != newLineId) { // vars.logDebug("oldLineId:" + oldLineId + " newLineId:" + newLineId); // } if (oldLineId <= 0 && newLineId > 0) { // no dialog -> dialog stopwatch.Restart(); } else if (oldLineId > 0 && newLineId == -1) { // dialog -> no dialog vars.logLine(oldLineId + "\t" + stopwatch.ElapsedMilliseconds); } else if (oldLineId != newLineId && oldLineId > 0 && newLineId > 0) { // Dialog -> different dialog vars.logLine(oldLineId + "\t" + stopwatch.ElapsedMilliseconds); stopwatch.Restart(); } }; vars.detectLineChange = detectLineChange; } shutdown { if (vars.lineLogFile != null) { vars.lineLogFile.Dispose(); vars.lineLogFile = null; } } init{ // vars.logDebug("modules: " + String.Join(", ", modules.Select(m=> m.ModuleName + " : " + m.BaseAddress.ToString() + " : " + m.EntryPointAddress.ToString()))); ProcessModuleWow64Safe module = modules.Single(x => String.Equals(x.ModuleName, "Disrupt_b64.dll", StringComparison.OrdinalIgnoreCase)); string hash = vars.calcModuleHash(module); switch (hash) { case "C3B1AD89FCCC74FE9C5BC5050A233308": version = "v1.04.497"; break; case "1837A42D913BB7DAF94FEF3163BA615A": version = "v1.06.329 Steam Latest"; break; case "77D09E2A3DAAABBFEE4F3466F52A5794": version = "v1.06.329 Uplay Latest"; break; default: throw new NotImplementedException("Unrecognized hash: " + hash); break; } } isLoading { if (version != "") return current.loading > 0; } update{ if (vars.stopwatch.ElapsedMilliseconds > 10000) { vars.stopwatch.Reset(); } if (settings["Log Dialog"]) { vars.detectLineChange(old.lineIdIdx0, current.lineIdIdx0, vars.line0Stopwatch); vars.detectLineChange(old.lineIdIdx1, current.lineIdIdx1, vars.line1Stopwatch); } } start{ if (vars.stopwatch.ElapsedMilliseconds > 2000) { vars.stopwatch.Reset(); } if (current.lineid == 46209) { vars.stopwatch.Start(); if(vars.stopwatch.ElapsedMilliseconds > 300) { //Aiden Story Start if(settings["Log Dialog"]) { vars.logLine("### Starting new run ###"); } return true; } } if (current.lineid == 10004649) { //Bad Blood Start if(settings["Log Dialog"]) { vars.logLine("### Starting new run ###"); } return true; } } split{ if(current.act1mainmissions == old.act1mainmissions + 1) //Aiden Story return vars.isNotDoubleSplit(); if(current.act2mainmissions == old.act2mainmissions + 1) //Aiden Story return vars.isNotDoubleSplit(); if(current.act3mainmissions == old.act3mainmissions + 1) //Aiden Story return vars.isNotDoubleSplit(); if(current.act4mainmissions == old.act4mainmissions + 1) //Aiden Story return vars.isNotDoubleSplit(); if(settings["Any% Ending"]) { if(current.lineid == 194143 && old.ending == 0 && current.ending == 1) //Aiden Story Ending return vars.isNotDoubleSplit(); } if(settings["Hacking Contract"] && current.lineid == 217543) { vars.stopwatch.Start(); if(vars.stopwatch.ElapsedMilliseconds > 6033) //Act 1 Fake Online Hacking Mission return vars.isNotDoubleSplit(); } if(settings["Remember"] && current.lineid == 204646) //Act 1 Graveyard Visit { vars.stopwatch.Start(); if(vars.stopwatch.ElapsedMilliseconds > 7300) return vars.isNotDoubleSplit(); } if(settings["Brandon Docks"] && current.lineid == 208307) //Brandon Docks ctOS Control Center return vars.isNotDoubleSplit(); if(settings["The Wards"] && (current.act2mainmissions == 5) && current.XP == old.XP+500) //The Wards ctOS Control Center return vars.isNotDoubleSplit(); if(settings["Mad Mile"] && current.lineid == 209437) //Mad Mile ctOS Control Center return vars.isNotDoubleSplit(); if(settings["Pawnee"] && current.lineid == 219093) //Pawnee ctOS Control Center return vars.isNotDoubleSplit(); if(current.badbloodact1 == old.badbloodact1 + 1) //BB Act 1 Main Missions return vars.isNotDoubleSplit(); if(current.badbloodact2 == old.badbloodact2 + 1) //BB Act 2 Main Missions return vars.isNotDoubleSplit(); if(current.badbloodact3 == old.badbloodact3 + 1) //BB Act 3 Main Missions return vars.isNotDoubleSplit(); if(settings["Hotspots"] && current.hotspots == old.hotspots + 1 ) //City Hotspots return true; if(settings["ctOS Breaches"] && current.ctosbreach == old.ctosbreach + 1) //ctOS Breaches return true; if(settings["ctOS Towers"] && current.ctostower == old.ctostower + 1) //ctOS Towers return true; if(settings["Privacy Invasions"] && current.privacyinvasion == old.privacyinvasion + 1) //Privacy Invasions return true; if(settings["Weapons Trade"] && current.weapontrade == old.weapontrade + 1) //Weapons Trade return true; if(settings["Missing Persons"] && current.missingpersons == old.missingpersons + 1) //Missing Persons return true; if(settings["QR Codes"] && current.qrcodes == old.qrcodes + 1) //QR Codes return true; if(settings["Burner Phones"] && current.burnerphones == old.burnerphones + 1) //Burner Phones return true; if(settings["Human Traffic"] && current.humantraffic == old.humantraffic + 1) //Human Traffic return true; if(settings["Drinking Game"] && current.drinkinggame == old.drinkinggame + 1) //Drinking Game return true; if(settings["SongSneak"] && current.songsneak == old.songsneak + 1) //Song Sneaks return true; if(settings["Shell Game"]) //Shell Game { if(current.shellgame == old.shellgame + 1 || current.shellgame == old.shellgame + 2 || current.shellgame == old.shellgame + 3) return true; } if(settings["Fixer Contracts"] && current.fixer == old.fixer + 1 && current.fixer == 40) //Fixer Contracts Complete return true; if(settings["Audio Logs"] && current.audiologs == old.audiologs + 1) //Audio Logs return true; } reset{ if(current.lineid == 46208) return true; }