diff options
-rw-r--r-- | Lingo.asl | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/Lingo.asl b/Lingo.asl new file mode 100644 index 0000000..f53eee9 --- /dev/null +++ b/Lingo.asl | |||
@@ -0,0 +1,102 @@ | |||
1 | // Autosplitter script for Lingo, by hatkirby. | ||
2 | // | ||
3 | // Requires a version released January 10th, 2023 or later. | ||
4 | // | ||
5 | // Massive thanks to the game developer, Brenton, for working with me to | ||
6 | // make this possible. | ||
7 | |||
8 | state("Lingo") {} | ||
9 | |||
10 | startup | ||
11 | { | ||
12 | vars.log = (Action<string>)((string logLine) => { | ||
13 | print("[Lingo ASL] " + logLine); | ||
14 | }); | ||
15 | |||
16 | settings.Add("end", false, "Split on The End"); | ||
17 | settings.Add("unchallenged", false, "Split on The Unchallenged"); | ||
18 | settings.Add("master", false, "Split on The Master"); | ||
19 | settings.Add("pilgrimage", false, "Split on Pilgrimage"); | ||
20 | settings.Add("showLastPanel",false, "Override first text component with the name of the most recently solved panel"); | ||
21 | |||
22 | vars.log("Autosplitter loaded"); | ||
23 | } | ||
24 | |||
25 | init | ||
26 | { | ||
27 | // magic byte array format: | ||
28 | // [0-7]: 5b a6 7d fe b8 69 f1 80 (random bytes used for sigscanning) | ||
29 | // [8]: First input | ||
30 | // [9-40]: Name of last solved panel | ||
31 | IntPtr ptr = IntPtr.Zero; | ||
32 | foreach (var page in game.MemoryPages(true).Reverse()) { | ||
33 | var scanner = new SignatureScanner(game, page.BaseAddress, (int)page.RegionSize); | ||
34 | ptr = scanner.Scan(new SigScanTarget(0, "5b a6 7d fe b8 69 f1 80")); | ||
35 | if (ptr != IntPtr.Zero) { | ||
36 | break; | ||
37 | } | ||
38 | } | ||
39 | if (ptr == IntPtr.Zero) { | ||
40 | throw new Exception("Could not find magic autosplitter array!"); | ||
41 | } | ||
42 | vars.firstInput = new MemoryWatcher<byte>(ptr + 8); | ||
43 | vars.lastPanel = new StringWatcher(ptr + 9, 32); | ||
44 | |||
45 | vars.log(String.Format("Magic autosplitter array: {0}", ptr.ToString("X"))); | ||
46 | |||
47 | vars.updateText = false; | ||
48 | if (settings["showLastPanel"]) { | ||
49 | foreach (LiveSplit.UI.Components.IComponent component in timer.Layout.Components) { | ||
50 | if (component.GetType().Name == "TextComponent") { | ||
51 | vars.tc = component; | ||
52 | vars.tcs = vars.tc.Settings; | ||
53 | vars.updateText = true; | ||
54 | vars.log("Found text component at " + component); | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | update | ||
62 | { | ||
63 | vars.firstInput.Update(game); | ||
64 | vars.lastPanel.Update(game); | ||
65 | |||
66 | if (settings["showLastPanel"] && vars.updateText && vars.lastPanel.Old != vars.lastPanel.Current) { | ||
67 | vars.tcs.Text2 = vars.lastPanel.Current; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | start | ||
72 | { | ||
73 | return vars.firstInput.Old == 0 && vars.firstInput.Current == 255; | ||
74 | } | ||
75 | |||
76 | onStart | ||
77 | { | ||
78 | if (settings["showLastPanel"] && vars.updateText) { | ||
79 | vars.tcs.Text1 = "Last Panel:"; | ||
80 | vars.tcs.Text2 = ""; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | split | ||
85 | { | ||
86 | if (settings["end"] && vars.lastPanel.Old != "Panel_end_end" && vars.lastPanel.Current == "Panel_end_end") { | ||
87 | vars.log("Split on The End"); | ||
88 | return true; | ||
89 | } | ||
90 | if (settings["unchallenged"] && vars.lastPanel.Old == "Panel_challenged_unchallenged" && vars.lastPanel.Current == "Panel_challenged_unchallenged") { | ||
91 | vars.log("Split on The Unchallenged"); | ||
92 | return true; | ||
93 | } | ||
94 | if (settings["master"] && vars.lastPanel.Old == "Panel_master_master" && vars.lastPanel.Current == "Panel_master_master") { | ||
95 | vars.log("Split on The Master"); | ||
96 | return true; | ||
97 | } | ||
98 | if (settings["pilgrimage"] && vars.lastPanel.Old == "Panel_pilgrim" && vars.lastPanel.Current == "Panel_pilgrim") { | ||
99 | vars.log("Split on Pilgrimage"); | ||
100 | return true; | ||
101 | } | ||
102 | } | ||