Ghostrunner2.asl 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. state("Ghostrunner2-Win64-Shipping")
  2. {
  3. //Address found by Kuno for the beta, still works here (unused)
  4. string100 CurAudioPlaying : "fmod.dll",0x001B0C10, 0x1A0, 0x1D0, 0x28, 0x60, 0x70, 0x2E0, 0x0;
  5. }
  6. startup
  7. {
  8. // Generic map list Kuno uses
  9. vars.doneMaps = new List<string>();
  10. vars.DoLoad = false;
  11. vars.EndSplit = false;
  12. vars.scanCooldown = new Stopwatch();
  13. //There is a few instances where the game loads worlds out of order so we're adding a counter to fix it
  14. vars.Counter = 0;
  15. // Taken from Dude Simulator 3 (Meta worked on it)
  16. if (timer.CurrentTimingMethod == TimingMethod.RealTime)
  17. {
  18. var timingMessage = MessageBox.Show (
  19. "This game uses Time without Loads (Game Time) as the main timing method.\n"+
  20. "LiveSplit is currently set to show Real Time (RTA).\n"+
  21. "Would you like to set the timing method to Game Time?",
  22. "LiveSplit | Ghostrunner 2",
  23. MessageBoxButtons.YesNo,MessageBoxIcon.Question
  24. );
  25. if (timingMessage == DialogResult.Yes)
  26. {
  27. timer.CurrentTimingMethod = TimingMethod.GameTime;
  28. }
  29. }
  30. //This text comp. has been floating around for years (4+) I'm unsure who originally wrote it
  31. vars.SetTextComponent = (Action<string, string>)((id, text) =>
  32. {
  33. var textSettings = timer.Layout.Components.Where(x => x.GetType().Name == "TextComponent").Select(x => x.GetType().GetProperty("Settings").GetValue(x, null));
  34. var textSetting = textSettings.FirstOrDefault(x => (x.GetType().GetProperty("Text1").GetValue(x, null) as string) == id);
  35. if (textSetting == null)
  36. {
  37. var textComponentAssembly = Assembly.LoadFrom("Components\\LiveSplit.Text.dll");
  38. var textComponent = Activator.CreateInstance(textComponentAssembly.GetType("LiveSplit.UI.Components.TextComponent"), timer);
  39. timer.Layout.LayoutComponents.Add(new LiveSplit.UI.Components.LayoutComponent("LiveSplit.Text.dll", textComponent as LiveSplit.UI.Components.IComponent));
  40. textSetting = textComponent.GetType().GetProperty("Settings", BindingFlags.Instance | BindingFlags.Public).GetValue(textComponent, null);
  41. textSetting.GetType().GetProperty("Text1").SetValue(textSetting, id);
  42. }
  43. if (textSetting != null)
  44. textSetting.GetType().GetProperty("Text2").SetValue(textSetting, text);
  45. });
  46. settings.Add("GR2", true, "Ghostrunner 2 Auto Splitting");
  47. // Mission Autosplitting Parent
  48. settings.Add("Mission Splits", true, "Mission Autosplits (Checkpoint subsplits are experimental)", "GR2");
  49. // Mission Splits
  50. settings.Add("00_01_world", true, "Uninvited Guests", "Mission Splits");
  51. settings.Add("00_02_world", true, "Will Bushido Allow It?", "Mission Splits");
  52. settings.Add("01_01_World", true, "Setting The Stage", "Mission Splits");
  53. settings.Add("01_02_World", true, "The Hacker's Den", "Mission Splits");
  54. settings.Add("01_03_World", true, "Behind The Curtain", "Mission Splits");
  55. settings.Add("01_04_world", true, "You Shouldn't Have Peeked", "Mission Splits");
  56. settings.Add("02_01_WORLD", true, "A Price To Be Paid", "Mission Splits");
  57. settings.Add("VSL_01_World", true, "Licking The Wounds", "Mission Splits");
  58. settings.Add("VSL_02_World", true, "I Won't Be Back Today", "Mission Splits");
  59. settings.Add("02_04_WORLD", true, "Winds Of The Desolate", "Mission Splits");
  60. settings.Add("02_05_World", true, "Pillars Of Creation", "Mission Splits");
  61. settings.Add("02_06_world", true, "Something Lurks In The Sand", "Mission Splits");
  62. settings.Add("02_07_world", true, "Minigames", "Mission Splits");
  63. settings.Add("2", true, "Can Anyone Hear Me?", "Mission Splits");
  64. settings.Add("03_02_world", true, "Danse Macabre", "Mission Splits");
  65. settings.Add("03_03_World", true, "Elevator Maintenance", "Mission Splits");
  66. settings.Add("03_04_World", true, "Too Close To The Sun", "Mission Splits");
  67. settings.Add("03_05_World", true, "The Monolith of Inhumanity", "Mission Splits");
  68. // Hub Autosplitting
  69. settings.Add("Hub Splits", true, "Toggle Hub levels in autosplitter", "GR2");
  70. var tB = (Func<string, string, string, Tuple<string, string, string>>) ((elmt1, elmt2, elmt3) => { return Tuple.Create(elmt1, elmt2, elmt3); });
  71. var sB = new List<Tuple<string, string, string>>
  72. {
  73. //Uninvited Guests
  74. tB("00_01_world","00_01_worldBP_CheckpointTrigger37","Arena I"),
  75. tB("00_01_world","00_01_worldBP_CheckpointTrigger22","Arena II"),
  76. tB("00_01_world","00_01_worldBP_CheckpointTrigger31","Trains I"),
  77. tB("00_01_world","00_01_worldBP_CheckpointTrigger16","Arena III"),
  78. tB("00_01_world","00_01_worldBP_CheckpointTrigger33","Platforming I"),
  79. tB("00_01_world","00_01_worldBP_CheckpointTrigger21","Arena IV"),
  80. tB("00_01_world","00_01_worldBP_CheckpointTrigger24","Trains II"),
  81. tB("00_01_world","00_01_worldBP_CheckpointTrigger27","Platforming II"),
  82. //Will Bushido Allow It?
  83. tB("00_02_world","00_02_worldBP_CheckpointTrigger2","Ahriman Phase I"),
  84. tB("00_02_world","00_02_worldBP_CheckpointTrigger3","Ahriman Platforming"),
  85. //Setting The Stage
  86. tB("01_01_World","01_01_WorldBP_CheckpointTrigger2","Water Basin Skip / Near start of 1st room with big statue dude"),
  87. tB("01_01_World","01_01_WorldBP_CheckpointTrigger24","Required OOB Load Trigger / After Grind Rail Cross Section"),
  88. tB("01_01_World","01_01_WorldBP_CheckpointTrigger38","Required OOB Load Trigger / Before Final Arena"),
  89. tB("01_01_World","01_01_WorldBP_CheckpointTrigger_Cybervoid","Final Arena Complete"),
  90. //The Hackers Den
  91. tB("01_02_World","01_02_WorldBP_CheckpointTrigger24","Right Side"),
  92. tB("01_02_World","01_02_WorldBP_CheckpointTrigger5","Time Cybervoid I"),
  93. tB("01_02_World","01_02_WorldBP_CheckpointTriggerAfterTimeCV","Time Cybervoid II"),
  94. tB("01_02_World","01_02_WorldBP_CheckpointTrigger23","Middle"),
  95. tB("01_02_World","01_02_WorldBP_CheckpointTrigger15","Gravity Cybervoid I"),
  96. tB("01_02_World","01_02_WorldBP_CheckpointTriggerAfterGravityCV","Gravity Cybervoid II"),
  97. tB("01_02_World","01_02_WorldBP_CheckpointTrigger20","Left Side"),
  98. tB("01_02_World","01_02_WorldBP_CheckpointTrigger19","Shuriken Cybervoid I"),
  99. tB("01_02_World","01_02_WorldBP_CheckpointTriggerAfterShurikenCV","Shuriken Cybervoid II"),
  100. //Behind The Curtain
  101. tB("01_03_World","01_03_WorldBP_CheckpointTrigger43","Cybervoid"),
  102. tB("01_03_World","01_03_WorldBP_CheckpointTrigger10","Checkpoint before Arena I / After Panda Skip"),
  103. tB("01_03_World","01_03_WorldBP_CheckpointTrigger31","Arena I"),
  104. tB("01_03_World","01_03_WorldBP_CheckpointTrigger36","Arena II [Restricted]"),
  105. tB("01_03_World","01_03_WorldBP_CheckpointTrigger7","Arena III / Arena III Skip"),
  106. tB("01_03_World","01_03_WorldBP_CheckpointTrigger17","Arena IV"),
  107. //You Shouldn't Have Peeked
  108. tB("01_04_world","01_04_worldBP_CheckpointTrigger","Avatar Tutorial"),
  109. tB("01_04_world","01_04_worldBP_CheckpointTrigger6","Mini Avatar's Defeated"),
  110. tB("01_04_world","01_04_worldBP_CheckpointTrigger2","Rahu I [Restricted Route]"),
  111. tB("01_04_world","01_04_worldBP_CheckpointTrigger3","Rahu II [Restricted Route]"),
  112. tB("01_04_world","01_04_worldBP_CheckpointTrigger4","Rahu III / Rahu Phase Skip"),
  113. tB("01_04_world","01_04_worldBP_CheckpointTrigger5","Rahu IV (Rail Grinding)"),
  114. tB("01_04_world","01_04_worldBP_CheckpointTrigger7","Rahu V [Restricted Route]"),
  115. tB("01_04_world","01_04_worldBP_CheckpointTrigger8","Rahu VI [Restricted Route - May trigger if too close to portal!!"),
  116. //A Price To Be Paid
  117. tB("02_01_WORLD","02_01_WORLDBP_CheckpointTrigger12","Laser Guy Intro Arena [Restricted Route]"),
  118. tB("02_01_WORLD","02_01_WORLDBP_CheckpointTrigger7","Grapple Walls [Restricted Route]"),
  119. tB("02_01_WORLD","02_01_WORLDBP_CheckpointTrigger21","Hostiles Bossfight Halfway Complete [Restricted Route]"), //?????
  120. //Licking The Wounds
  121. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger31","Arena I"),
  122. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger8","Right Side Skip"),
  123. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger10","Arena II"),
  124. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger13","Vents"),
  125. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger17","Various Mini Fights (CP just before Arena III)"),
  126. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger18","Arena III [Restricted Route]"),
  127. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger21","Crane Room / Arena III Skip"),
  128. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger24","Shuriken Tempest Puzzle Skip"), //!!!old2==BP_CheckpointTrigger2"),
  129. tB("VSL_01_World","VSL_01_WorldBP_CheckpointTrigger27","Triple Enemy Rail"), //!!!old2==BP_CheckpointTrigger28"),
  130. //I Won't Be Back Today
  131. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger2","Power Core Tutorial"),
  132. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger4","Power Core II"),
  133. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger25","Power Core III"),
  134. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger7","Wallriding I"),
  135. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger9","Tunnels I"),
  136. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger11","Power Core IV"),
  137. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger13","Wallriding II"),
  138. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger14","Tunnels II"),
  139. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger18","Crawlers I"),
  140. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger21","Crawlers II"),
  141. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger22","Bollards I"),
  142. tB("VSL_02_World","VSL_02_WorldBP_CheckpointTrigger24","Bollards II"),
  143. //Winds of The Desolate
  144. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger33","Bike (Lasers)"),
  145. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger50","Gate I"),
  146. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger41","Gate II"),
  147. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger16","Gate III"),
  148. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger39","Gate IV"),
  149. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger40","Gate V [Restricted Route]"),
  150. tB("02_04_WORLD","02_04_WORLDBP_CheckpointTrigger15","Entering Cybervoid"),
  151. //Pillars of Creation
  152. tB("02_05_World","02_05_WorldBP_CheckpointTrigger8","Arena I"),
  153. tB("02_05_World","02_05_WorldBP_CheckpointTrigger76","Bike Section I[Restricted Route]"),
  154. tB("02_05_World","02_05_WorldBP_CheckpointCV1","LeftPillar[Restricted Route]"),
  155. tB("02_05_World","02_05_WorldBP_CheckpointTriggerLeftTower","Left Pillar Cybervoid [Restricted Route]"),
  156. tB("02_05_World","02_05_WorldBP_CheckpointCV2","RightPillar[Restricted Route]"),
  157. tB("02_05_World","02_05_WorldBP_CheckpointTriggerRightTower","Right Pillar Cybervoid [Restricted Route]"),
  158. tB("02_05_World","02_05_WorldBP_CheckpointCV3","MiddlePillar[Restricted Route]"),
  159. tB("02_05_World","02_05_WorldBP_CheckpointTriggerMiddleTower","Middle Pillar Cybervoid [Restricted Route]"),
  160. //Something Lurking In The Sand
  161. tB("02_06_world","02_06_worldBP_CheckpointTrigger13","Bike Section I [Restricted Route]"),
  162. tB("02_06_world","02_06_worldBP_CheckpointTrigger16","Bike Section II / Worm Skip"),
  163. tB("02_06_world","02_06_worldCheckpoint6","Bike Section III"),
  164. tB("02_06_world","02_06_worldBP_CheckpointTrigger20","Bike Section IV (Bridge I)"),
  165. tB("02_06_world","02_06_worldCheckpoint10","Bike Section IV (Bridge II)"),
  166. tB("02_06_world","02_06_worldBP_Checkpoint_Inside1","Bike Section V (Barrage)"),
  167. tB("02_06_world","02_06_worldBP_Checkpoint_Inside4","Naga Phase I"),
  168. tB("02_06_world","02_06_worldBP_Checkpoint_Inside7","Naga Phase II"),
  169. tB("02_06_world","02_06_worldBP_Checkpoint_Inside9","Naga Phase III"),
  170. tB("02_06_world","02_06_worldBP_Checkpoint_Inside11","Naga Phase IV"),
  171. //Mindgames
  172. tB("02_07_world","02_07_worldCheckpoint_start_loop2","Loop I"),
  173. tB("02_07_world","02_07_worldCheckpoint_start_loop3","Loop II"),
  174. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable12","Loop III"),
  175. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable6","Colour Puzzle I"),
  176. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable5","Fight & Cutscene I"),
  177. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable15","Platforming I"),
  178. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable20","Colour Puzzle II"),
  179. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable10","Fight & Cutscene II"),
  180. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable24","Platforming II"),
  181. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable27","Colour Puzzle III"),
  182. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable13","Fight & Cutscene III"),
  183. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable30","Platforming III"),
  184. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable32","Colour Puzzle IV"),
  185. tB("02_07_world","02_07_worldBP_CheckpointTriggerMovable14","Fight & Cutscene IV"),
  186. //Can Anyone Hear Me?
  187. tB("2","03_01_worldBP_CheckpointTrigger19","Bike Section I (On-Ramp - must be on bike during trigger)"),
  188. tB("2","03_01_worldBP_CheckpointTrigger8","Bike Section II (Wrecks I)"),
  189. tB("2","03_01_worldBP_CheckpointTrigger18","Bike Section III (Wallride I)"),
  190. tB("2","03_01_worldBP_CheckpointTrigger9","Bike Section IV (Wrecks II)"),
  191. tB("2","03_01_worldBP_CheckpointTrigger11","Bike Section V (Biker Maniacs I)"),
  192. tB("2","03_01_worldBP_CheckpointTrigger12","Bike Section VI (Wallride II)"),
  193. tB("2","03_01_worldBP_CheckpointTrigger13","Bike Section VII (Wrecks III)"),
  194. tB("2","03_01_worldBP_CheckpointTrigger14","Bike Section VIII (Biker Maniacs 2)"),
  195. tB("2","03_01_worldBP_CheckpointTrigger3","Bike Section IX (Downhill)"),
  196. tB("2","03_01_worldBP_CheckpointTrigger4","Bike Section X (Inside Dharma)"),
  197. tB("2","03_01_worldBP_CheckpointTrigger16","Arena Fight / Challenge Warp"),
  198. //Danse Macabre
  199. //No Checkpoint Splits, this shits weird af and just randomizes checkpoint IDs
  200. //Elevator Maintenance
  201. tB("03_03_World","03_03_WorldBP_CheckpointTrigger7","Required Load Trigger I (Arena I Skip / After Arena I)"),
  202. tB("03_03_World","03_03_WorldBP_CheckpointTrigger16","Required Load Trigger II (Crane Skip / After Crane)"),
  203. tB("03_03_World","03_03_WorldBP_CheckpointTrigger20","Required Load Trigger III (Tube Skip Part I / Underneath Biter)"),
  204. tB("03_03_World","03_03_WorldBP_CheckpointTrigger36","Required Load Trigger IV (Tube Skip Part II / Inside Red Octagon)"),
  205. tB("03_03_World","03_03_WorldBP_CheckpointTrigger18","Required Load Trigger V (Exterior Skip / Reached Outside)"),
  206. //Too Close To The Sun
  207. tB("03_04_World","03_04_WorldBP_CheckpointTrigger14","Flying I (Glider Intro)"),
  208. tB("03_04_World","03_04_WorldBP_CheckpointTrigger18","Flying II (Sideways Triangle Arch)"),
  209. tB("03_04_World","03_04_WorldBP_CheckpointTrigger10","Flying III (Rail Grinding + Fans I)"),
  210. tB("03_04_World","03_04_WorldBP_CheckpointTrigger27","Arena I"),
  211. tB("03_04_World","03_04_WorldBP_CheckpointTrigger16","Flying IV (Big Tube I)[Restricted Route]"),
  212. tB("03_04_World","03_04_WorldBP_CheckpointTrigger25","Arena II[Restricted Route]"),
  213. tB("03_04_World","03_04_WorldBP_CheckpointTrigger23","Flying V (Big OOB / Start of Biter's Hallway)"),
  214. tB("03_04_World","03_04_WorldBP_CheckpointTrigger","Flying VI (Shuriken Gaps)"),
  215. tB("03_04_World","03_04_WorldBP_CheckpointTrigger24","Arena III"),
  216. tB("03_04_World","03_04_WorldBP_CheckpointTrigger34","Flying VII (Glider Grapples)"),
  217. tB("03_04_World","03_04_WorldBP_CheckpointTrigger38","Arena IV [Restricted Route]"),
  218. //The Monolith of Inhumanity
  219. tB("03_05_World","03_05_WorldBP_CheckpointTrigger5","Mitra Phase I"),
  220. tB("03_05_World","03_05_WorldBP_CheckpointTriggerPlaterReactor","Mitra Phase II"),
  221. tB("03_05_World","03_05_WorldBP_CheckpointTriggerVR1Start","Mitra Phase III"),
  222. //tB("03_05_World","03_05_WorldBP_CheckpointTriggerPlaterReactor","Mitra Phase IV"), literally the only time this method breaks bruh lol
  223. tB("03_05_World","03_05_WorldBP_CheckpointTriggerVR2Start","Mitra Phase IV & V"),
  224. };
  225. foreach (var s in sB) settings.Add(s.Item2, false, s.Item3, s.Item1);
  226. // Code assistance by Ero, written by Kuno / Meta
  227. vars.ILStartCamTargets = new Dictionary<string, Tuple<string, string>>
  228. {
  229. { "00_02_world", Tuple.Create("ExpiredSpawnable", "BP_PlayerCharacter_C") },
  230. { "01_01_World", Tuple.Create("BP_PlayerCharacter_C", "-") },
  231. { "01_02_World", Tuple.Create("BP_PlayerCharacter_C", "-") },
  232. { "01_03_World", Tuple.Create("BP_PlayerCharacter_C", "-") },
  233. { "01_04_world", Tuple.Create("BP_PlayerCharacter_C", "-") },
  234. { "02_01_WORLD", Tuple.Create("CineCameraActor", "CS_09_Connor_s_Death") },
  235. { "VSL_01_World", Tuple.Create("CS1_Opening01", "BP_PlayerCharacter_C") },
  236. { "VSL_02_World", Tuple.Create("BP_PlayerCharacter_C", "BP_MotorcycleVehicle") },
  237. { "02_04_WORLD", Tuple.Create("BP_PlayerCharacter_C", "BP_MotorcycleVehicle") },
  238. { "02_05_World", Tuple.Create("BP_PlayerCharacter_C", "BP_MotorcycleVehicle") },
  239. { "02_06_world", Tuple.Create("BP_PlayerCharacter_C", "BP_MotorcycleVehicle") },
  240. { "02_07_world", Tuple.Create("01_Opening_02_07", "BP_PlayerCharacter_C") },
  241. { "03_01_world", Tuple.Create("CS2_CineCameraActor1", "BP_MotorcycleVehicle") },
  242. { "03_02_world", Tuple.Create("BP_CinematicCamera", "BP_PlayerCharacter_C") },
  243. { "03_03_World", Tuple.Create("BP_PlayerCharacter_C", "-") },
  244. //{ "03_03_World", Tuple.Create("BP_CinematicCamera", "BP_PlayerCharacter_C") },
  245. { "03_04_World", Tuple.Create("BP_PlayerCharacter_C", "-") },
  246. { "03_05_World", Tuple.Create("CS4_Mitra_Intro", "BP_PlayerCharacter_C") },
  247. // ...
  248. };
  249. // Code written by Kuno / Meta
  250. settings.Add("ILMode", true, "IL MODE: Enables unique autostarts for IL runs");
  251. // Code written by Micrologist
  252. //Parent setting
  253. settings.Add("Variable Information", true, "Variable Information");
  254. //Child settings that will sit beneath Parent setting
  255. settings.Add("Camera", false, "Current Camera Target", "Variable Information");
  256. settings.Add("Map", false, "Current Map", "Variable Information");
  257. // Code written by Kuno / Meta
  258. settings.Add("Checkpoint", true, "Current Checkpoint", "Variable Information");
  259. settings.Add("Speed", true, "Current Speed", "Variable Information");
  260. }
  261. init
  262. {
  263. //Code original written by Micrologist
  264. var scn = new SignatureScanner(game, game.MainModule.BaseAddress, game.MainModule.ModuleMemorySize);
  265. var syncLoadTrg = new SigScanTarget(5, "89 43 60 8B 05 ?? ?? ?? ??") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  266. var syncLoadCounterPtr = scn.Scan(syncLoadTrg);
  267. var uWorldTrg = new SigScanTarget(8, "0F 2E ?? 74 ?? 48 8B 1D ?? ?? ?? ?? 48 85 DB 74") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  268. var uWorld = scn.Scan(uWorldTrg);
  269. var gameEngineTrg = new SigScanTarget(3, "48 39 35 ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  270. var gameEngine = scn.Scan(gameEngineTrg);
  271. var fNamePoolTrg = new SigScanTarget(13, "89 5C 24 ?? 89 44 24 ?? 74 ?? 48 8D 15") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  272. var fNamePool = scn.Scan(fNamePoolTrg);
  273. // Code written by Kuno / Meta
  274. var PlayerControllerTrg = new SigScanTarget(3, "48 89 3D ?? ?? ?? ?? C7 05 ?? ?? ?? ?? 00 00 B4 42 89 05") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  275. var PlayerController = scn.Scan(PlayerControllerTrg);
  276. var EndLeveltrg = new SigScanTarget(3, "4c 8b 05 ?? ?? ?? ?? 33 ff 4c 8b c9"){ OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  277. var EndLevel = scn.Scan(EndLeveltrg);
  278. print(uWorld.ToString("X"));
  279. // Code original written by Diggity (converted into a sgiscan by Kuno/Meta)
  280. var GNamePoolTrg = new SigScanTarget(3, "48 89 05 ?? ?? ?? ?? 48 83 c4 ?? c3") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) };
  281. var GNamePool = scn.Scan(GNamePoolTrg);
  282. // Throwing in case any base pointers can't be found (yet, hopefully)
  283. if(syncLoadCounterPtr == IntPtr.Zero || uWorld == IntPtr.Zero || gameEngine == IntPtr.Zero || fNamePool == IntPtr.Zero || GNamePool == IntPtr.Zero || PlayerController == IntPtr.Zero || EndLevel == IntPtr.Zero)
  284. {
  285. throw new Exception("One or more base pointers not found - retrying");
  286. }
  287. vars.Watchers = new MemoryWatcherList
  288. {
  289. //Code original written by Micrologist (changed from ulong to long to work with diggity's FnameReader)
  290. new MemoryWatcher<int>(new DeepPointer(syncLoadCounterPtr)) { Name = "syncLoadCount" },
  291. new MemoryWatcher<long>(new DeepPointer(uWorld, 0x18)) { Name = "worldFName"},
  292. new MemoryWatcher<long>(new DeepPointer(gameEngine, 0xD28, 0x38, 0x0, 0x30, 0x2B8, 0xE90, 0x18)) { Name = "camViewTargetFName"},
  293. // Code original written by Diggity (converted from a stated address into memorywatcher by Kuno/Meta)
  294. new MemoryWatcher<long>(new DeepPointer(GNamePool)) {Name = "GNamePool"},
  295. new MemoryWatcher<long>(new DeepPointer(uWorld, 0x180, 0xF0)) {Name = "giss"},
  296. new MemoryWatcher<int>(new DeepPointer(uWorld, 0x180, 0xF8)) {Name = "gissCount"},
  297. // Code written by Kuno / Meta
  298. //End of level scene
  299. new MemoryWatcher<int>(new DeepPointer(EndLevel, 0x80)) {Name = "EndLevel"},
  300. //Current velocity shown on the motorcycle in KMH
  301. new MemoryWatcher<float>(new DeepPointer(EndLevel + 0x1000, 0x20, 0x294)) {Name = "MotorcycleVelocity"},
  302. //Typically only works on the last two end movies and the intro one (excludes the credits one)
  303. new MemoryWatcher<long>(new DeepPointer(uWorld, 0x138, 0x20, 0xE8, 0x248, 0x0 + 0x3bc)) { Name = "curMovieName"},
  304. //Current player x and y velocity not on the motorcycle, in UE4 units
  305. new MemoryWatcher<float>(new DeepPointer(PlayerController, 0x30, 0x250, 0x290, 0x140)) {Name = "xVel"},
  306. new MemoryWatcher<float>(new DeepPointer(PlayerController, 0x30, 0x250, 0x290, 0x144)) {Name = "yVel"},
  307. };
  308. //Generic line of text updating the watchers list and creating current.camtarget and world (to not have it print null errors later on)
  309. vars.Watchers.UpdateAll(game);
  310. current.camTarget = "";
  311. current.world = "";
  312. current.Movie = "";
  313. // Code original written by Diggity (until bottom unstated message)
  314. var giss = vars.Watchers["giss"].Current;
  315. var gissCount = vars.Watchers["gissCount"].Current;
  316. var gNamePool = vars.Watchers["GNamePool"].Current;
  317. if (giss == null || giss == 0)
  318. {
  319. throw new Exception("--Couldn't find a pointer I want! Game is still starting or an update broke things!");
  320. }
  321. var cachedFNames = new Dictionary<long, string>();
  322. vars.ReadFName = (Func<long, string>)(fname =>
  323. {
  324. string name;
  325. if (cachedFNames.TryGetValue(fname, out name))
  326. return name;
  327. int name_offset = (int) fname & 0xFFFF;
  328. int chunk_offset = (int) (fname >> 0x10) & 0xFFFF;
  329. var base_ptr = new DeepPointer((IntPtr) gNamePool + chunk_offset * 0x8, name_offset * 0x2);
  330. byte[] name_metadata = base_ptr.DerefBytes(game, 2);
  331. // First 10 bits are the size, but we read the bytes out of order
  332. // e.g. 3C05 in memory is 0011 1100 0000 0101, but really the bytes we want are the last 8 and the first two, in that order.
  333. int size = name_metadata[1] << 2 | (name_metadata[0] & 0xC0) >> 6;
  334. // read the next (size) bytes after the name_metadata
  335. IntPtr name_addr;
  336. base_ptr.DerefOffsets(game, out name_addr);
  337. // 2 bytes here for the name_metadata
  338. name = game.ReadString(name_addr + 0x2, size);
  339. cachedFNames[fname] = name;
  340. return name;
  341. });
  342. vars.ReadFNameOfObject = (Func<IntPtr, string>)(obj => vars.ReadFName(game.ReadValue<long>(obj + 0x18)));
  343. vars.Checkpoint = null;
  344. vars.RefreshSubsystemCache = (Action<dynamic>)((curr) =>
  345. {
  346. print("Reloading subsystem cache...");
  347. // iterate over game instances and check for the checkpoint trigger
  348. for (int i = 0; i < gissCount; i++)
  349. {
  350. var ssPtr = game.ReadValue<IntPtr>((IntPtr) (giss + i * 0x18 + 0x8));
  351. var name = vars.ReadFNameOfObject(ssPtr);
  352. //print(name + " at " + ssPtr.ToString("X"));
  353. if (name == "CheckpointSubsystem") {
  354. vars.Checkpoint = new MemoryWatcher<long>(new DeepPointer(ssPtr + 0x50, 0x18));
  355. }
  356. }
  357. });
  358. vars.RefreshSubsystemCache(current);
  359. //End of code written by Diggity
  360. }
  361. update
  362. {
  363. //Generic line of text updating the watchers list
  364. vars.Watchers.UpdateAll(game);
  365. // Code original written by Diggity (interpreted to watchers by kuno/meta)
  366. vars.Checkpoint.Update(game);
  367. current.giss = vars.Watchers["giss"].Current;
  368. current.gissCount = vars.Watchers["gissCount"].Current;
  369. current.checkpoint = old.checkpoint = vars.ReadFName(vars.Checkpoint.Current);
  370. if (old.gissCount == 0 && current.gissCount != 0)
  371. {
  372. vars.RefreshSubsystemCache(current);
  373. }
  374. //Code assitance by DMGvol, written by Kuno / Meta
  375. float xVel = (float)vars.Watchers["xVel"].Current;
  376. float yVel = (float)vars.Watchers["yVel"].Current;
  377. double hVel = Math.Floor(Math.Sqrt((xVel * xVel) + (yVel * yVel)) + 0.5f);
  378. current.CurrentSpeed = (float)hVel;
  379. current.MotorcycleSpeed = vars.Watchers["MotorcycleVelocity"].Current;
  380. // Code original written by Micrologist (until unstated)
  381. // The game is considered to be loading if any scenes are loading synchronously
  382. current.loading = vars.Watchers["syncLoadCount"].Current > 0;
  383. // Get the current world name as string, only if *UWorld isnt null
  384. var worldFName = vars.Watchers["worldFName"].Current;
  385. current.world = worldFName != 0x0 ? vars.ReadFName(worldFName) : old.world;
  386. // Get the Name of the current target for the CameraManager
  387. current.camTarget = vars.ReadFName(vars.Watchers["camViewTargetFName"].Current);
  388. // End of code original written by Micrologist
  389. //Code written by Kuno / Meta
  390. current.EndLoading = vars.Watchers["EndLevel"].Current;
  391. current.WorldNewCheckpoint = (current.world + current.checkpoint).Replace(" ", "");
  392. // The movie address doesn't initialize until the movie actually starts playing, so doing this so it doesn't constantly throw an error message saying it's a nullptr
  393. try
  394. {
  395. current.Movie = vars.ReadFName(vars.Watchers["curMovieName"].Current);
  396. }
  397. catch
  398. {
  399. }
  400. if (vars.scanCooldown.Elapsed.TotalMilliseconds > 499)
  401. {
  402. vars.scanCooldown.Stop();
  403. }
  404. print(vars.scanCooldown.Elapsed.TotalMilliseconds.ToString());
  405. if (current.world == "03_01_world" && old.world != "03_01_world")
  406. {
  407. vars.Counter++;
  408. }
  409. //Code written by Kuno / Meta
  410. //There is a weird space between when the end level screen appears vs when loading starts, so we're checking if we're on an endloading screen then setting doload to true
  411. if (vars.DoLoad == false && current.EndLoading == 1)
  412. {
  413. print("DOLOAD");
  414. vars.DoLoad = true;
  415. }
  416. // After the above if is ran and do load is enabled, we check if we're currently loading (which doesn't equal 0 when loading) and disable it as the syncloadcount should be actively removing them anyway
  417. if (vars.DoLoad == true && vars.Watchers["syncLoadCount"].Current != 0)
  418. {
  419. vars.DoLoad = false;
  420. }
  421. //All of these settings are added to have the user be able to see the current camera, map, checkpoint names are and the current player speed
  422. if(settings["Camera"])
  423. {
  424. vars.SetTextComponent("Camera Target:",current.camTarget.ToString());
  425. if (old.camTarget != current.camTarget) print("Camera Target:" + current.camTarget.ToString());
  426. }
  427. if(settings["Map"])
  428. {
  429. vars.SetTextComponent("Map:",current.world.ToString());
  430. if (old.world != current.world) print("Map:" + current.world.ToString());
  431. }
  432. if(settings["Checkpoint"])
  433. {
  434. vars.SetTextComponent("Checkpoint:",current.checkpoint.ToString());
  435. if (old.world != current.world) print("Checkpoint:" + current.checkpoint.ToString());
  436. }
  437. //The way the game handles player velocity is changed when on the motorcycle so we're just checking to see if we're moving on the bike and the camera target is the motorcycle
  438. if (settings["Speed"])
  439. {
  440. if (current.MotorcycleSpeed != 0 && current.camTarget == "BP_MotorcycleVehicle")
  441. {
  442. // Different rounding as the bike likes to gitter
  443. vars.SetTextComponent("Speed:",current.MotorcycleSpeed.ToString("0000"));
  444. }
  445. else
  446. {
  447. vars.SetTextComponent("Speed:",current.CurrentSpeed.ToString("0000.00"));
  448. }
  449. }
  450. print(current.checkpoint);
  451. }
  452. isLoading
  453. {
  454. //Generic loading information
  455. return current.loading || vars.DoLoad;
  456. }
  457. start
  458. {
  459. // written by Kuno / Meta, Used for generic starting for full game runs
  460. if (current.world == "00_01_world" && old.camTarget == "CS1_CineCameraActor" && current.camTarget == "CS1_01_Opening")
  461. {
  462. print("Normal Start");
  463. vars.doneMaps.Add(current.world);
  464. return true;
  465. }
  466. // Code assistance by Ero, written by Kuno / Meta. In a try statement due to the vars.ILStartCamTargets throwing some errors if the current world doesn't equal one in the index
  467. if (settings["ILMode"])
  468. {
  469. try
  470. {
  471. var targets = vars.ILStartCamTargets[current.world];
  472. //Check one is checking if we're inbetween two camera regions, check two is for certain levels without cutscenes. Can anyone hear me is the only one with an issue being able to work with both so we just excluded it from the second check
  473. if (old.camTarget == targets.Item1 && current.camTarget == targets.Item2 || old.camTarget == targets.Item1 && old.loading != current.loading && current.world != "03_01_world")
  474. {
  475. current.checkpoint = "";
  476. return true;
  477. }
  478. }
  479. catch
  480. {
  481. }
  482. }
  483. }
  484. onStart
  485. {
  486. vars.scanCooldown.Start();
  487. timer.IsGameTimePaused = true;
  488. current.checkpoint = "";
  489. vars.doneMaps.Add(current.world);
  490. vars.Checkpoint.Reset();
  491. }
  492. split
  493. {
  494. if ((vars.scanCooldown.Elapsed.TotalMilliseconds >= 500))
  495. {
  496. //Split if the current world is enabled, and not inside of our donemaps list
  497. if (settings[current.world] && (!vars.doneMaps.Contains(current.world)) && (!current.loading))
  498. {
  499. vars.doneMaps.Add(current.world);
  500. print("Split on:" + current.world);
  501. return true;
  502. }
  503. //Split if the current world we're in and the checkpoint we just reached is in settings, and not in our donemaps (also used for done checkpoints)
  504. if (settings[current.WorldNewCheckpoint] && (!vars.doneMaps.Contains(current.WorldNewCheckpoint)))
  505. {
  506. vars.doneMaps.Add(current.WorldNewCheckpoint);
  507. print("Split on new checkpoint:" + current.WorldNewCheckpoint);
  508. return true;
  509. }
  510. if (settings[vars.Counter.ToString()] && !vars.doneMaps.Contains(vars.Counter.ToString()))
  511. {
  512. vars.doneMaps.Add(vars.Counter.ToString());
  513. print("Split on new counter:" + vars.Counter.ToString());
  514. return true;
  515. }
  516. //There is a hub section we return to a few times throughout the game, this is a generic check nothing major
  517. if (settings["Hub Splits"] && (current.world == "HUB_Blockout" && old.world != "HUB_Blockout"))
  518. {
  519. print("Split on Hub");
  520. return true;
  521. }
  522. //End time for full game runs is on the ending movie, DMGvol helped us find the current.Movie playing and we're just checking if we reached it. Alongside, if we already endsplitted just in case so it doesn't split a billion times if the runner wasn't on their end split (for whatever reason)
  523. if (current.Movie == "UI.Video.Outro" && vars.EndSplit == false)
  524. {
  525. vars.EndSplit = true;
  526. print("end split");
  527. return true;
  528. }
  529. }
  530. }
  531. onReset
  532. {
  533. //Clearing out donemaps, and setting endsplit back to false
  534. vars.doneMaps.Clear();
  535. vars.EndSplit = false;
  536. vars.scanCooldown.Reset();
  537. current.Movie = "";
  538. vars.Counter = 0;
  539. current.checkpoint = "";
  540. vars.Checkpoint.Reset();
  541. }
  542. exit
  543. {
  544. //Just in case the game crashes we'll have the time paused until the user loads into the mainmenu
  545. timer.IsGameTimePaused = true;
  546. vars.Checkpoint.Reset();
  547. }