about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Taiji.asl122
1 files changed, 98 insertions, 24 deletions
diff --git a/Taiji.asl b/Taiji.asl index 080dbd9..dffc3c4 100644 --- a/Taiji.asl +++ b/Taiji.asl
@@ -1,9 +1,11 @@
1state("Taiji") 1// Autosplitter script for Taiji, by hatkirby.
2{ 2//
3 // v9.10.2022, v9.12.2022.6 3// Requires v9.17.2022 or later.
4 int solveCount: "GameAssembly.dll", 0x0168ED88, 0x80, 0x100, 0xD94; 4//
5 byte10 worldsCompleted: "GameAssembly.dll", 0x015C8010, 0x48, 0x40, 0x80, 0x290, 0xB8, 0x10, 0x20; 5// Massive thanks to the game developer, mvandevander, for working with me to
6} 6// make this possible.
7
8state("Taiji") {}
7 9
8startup 10startup
9{ 11{
@@ -13,34 +15,106 @@ startup
13 15
14 settings.Add("solveCount", true, "Split on solve count increasing"); 16 settings.Add("solveCount", true, "Split on solve count increasing");
15 settings.Add("world", false, "Split on completing a world"); 17 settings.Add("world", false, "Split on completing a world");
18 settings.Add("tutorial", false, "Split on Tutorial completion");
19 settings.Add("black", true, "Split on Black ending");
20 settings.Add("white", false, "Split on White ending");
16 21
17 vars.log("Autosplitter loaded"); 22 vars.log("Autosplitter loaded");
18} 23}
19 24
20onStart 25init
26{
27 // magic byte array format:
28 // [0-7]: 7b 08 ec f9 87 1d b7 d6 (random bytes used for sigscanning)
29 // [8]: New file flag. Gets set to 1 when "start a new game" is selected.
30 // Gets reset to 0 when the pause menu is opened.
31 // [9-17]: A copy of the world completion flags.
32 // [18]: Solve count / 256.
33 // [19]: Solve count % 256.
34 // [20]: Tutorial completion flag.
35 // [21]: Black ending flag. Gets set to 1 when the square that starts the
36 // interactive ending is clicked.
37 // [22]: White ending flag. Gets set to 1 when the square that enables the
38 // prison is clicked.
39 // [23]: Loading flag. Set to 1 during loads, 0 otherwise.
40 IntPtr ptr = IntPtr.Zero;
41 foreach (var page in game.MemoryPages(true).Reverse()) {
42 var scanner = new SignatureScanner(game, page.BaseAddress, (int)page.RegionSize);
43 ptr = scanner.Scan(new SigScanTarget(0, "7b 08 ec f9 87 1d b7 d6"));
44 if (ptr != IntPtr.Zero) {
45 break;
46 }
47 }
48 if (ptr == IntPtr.Zero) {
49 throw new Exception("Could not find magic autosplitter array!");
50 }
51 vars.newFileFlag = new MemoryWatcher<byte>(ptr + 8);
52 vars.worldCompletion = new List<MemoryWatcher<byte>>();
53 for (int i = 0; i < 9; i++) {
54 vars.worldCompletion.Add(new MemoryWatcher<byte>(ptr + 9 + i));
55 }
56 vars.solveCountHigh = new MemoryWatcher<byte>(ptr + 18);
57 vars.solveCountLow = new MemoryWatcher<byte>(ptr + 19);
58 vars.tutorialCompletion = new MemoryWatcher<byte>(ptr + 20);
59 vars.blackEnding = new MemoryWatcher<byte>(ptr + 21);
60 vars.whiteEnding = new MemoryWatcher<byte>(ptr + 22);
61 vars.loadingFlag = new MemoryWatcher<byte>(ptr + 23);
62
63 vars.log(String.Format("Magic autosplitter array: {0}", ptr.ToString("X")));
64}
65
66update
67{
68 vars.newFileFlag.Update(game);
69 vars.tutorialCompletion.Update(game);
70 vars.blackEnding.Update(game);
71 vars.whiteEnding.Update(game);
72 vars.loadingFlag.Update(game);
73
74 vars.solveCountHigh.Update(game);
75 vars.solveCountLow.Update(game);
76 current.solveCount = vars.solveCountHigh.Current * 256 + vars.solveCountLow.Current;
77
78 int curWorlds = 0;
79 for (int i = 0; i < 9; i++) {
80 vars.worldCompletion[i].Update(game);
81 if (vars.worldCompletion[i].Current == 1) {
82 curWorlds++;
83 }
84 }
85 current.numWorlds = curWorlds;
86}
87
88start
21{ 89{
22 vars.maxSolve = 0; 90 return vars.newFileFlag.Old == 0 && vars.newFileFlag.Current == 1;
23 vars.numWorlds = 0;
24} 91}
25 92
26split 93split
27{ 94{
28 if (settings["solveCount"] && current.solveCount > vars.maxSolve) { 95 if (settings["solveCount"] && current.solveCount > old.solveCount) {
29 vars.log(String.Format("Solve count increased from {0} to {1}", vars.maxSolve, current.solveCount)); 96 vars.log(String.Format("Solve count increased from {0} to {1}", old.solveCount, current.solveCount));
30 vars.maxSolve = current.solveCount;
31 return true; 97 return true;
32 } 98 }
33 if (settings["world"]) { 99 if (settings["world"] && current.numWorlds > old.numWorlds) {
34 int curWorlds = 0; 100 vars.log(String.Format("World count increased from {0} to {1}", old.numWorlds, current.numWorlds));
35 foreach (byte b in current.worldsCompleted) { 101 return true;
36 if (b == 1) { 102 }
37 curWorlds += 1; 103 if (settings["tutorial"] && vars.tutorialCompletion.Old == 0 && vars.tutorialCompletion.Current == 1) {
38 } 104 vars.log("Split on tutorial completion");
39 } 105 return true;
40 if (curWorlds > vars.numWorlds) {
41 vars.log(String.Format("World count increased from {0} to {1}", vars.numWorlds, curWorlds));
42 vars.numWorlds = curWorlds;
43 return true;
44 }
45 } 106 }
107 if (settings["black"] && vars.blackEnding.Old == 0 && vars.blackEnding.Current == 1) {
108 vars.log("Split on Black ending");
109 return true;
110 }
111 if (settings["white"] && vars.whiteEnding.Old == 0 && vars.whiteEnding.Current == 1) {
112 vars.log("Split on White ending");
113 return true;
114 }
115}
116
117isLoading
118{
119 return vars.loadingFlag.Current == 1;
46} 120}