-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGameMaker.UndertaleWildfire.asl
168 lines (142 loc) · 6.32 KB
/
GameMaker.UndertaleWildfire.asl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Undertale Wildfire Autosplitter by NERS
state("Undertale Wildfire", "Combat Demo v1.10")
{
double menuSelection : 0xE28C90, 0x98, 0x48, 0x10, 0x30, 0x0; // obj_menu.selection
string16 menuState : 0xE383A0, 0x18, 0x88, 0x8, 0x0, 0x0, 0x0; // obj_menu.fsm state (SnowState)
float playerX : 0xC18F60, 0x0, 0x4B0, 0x18, 0x58, 0x10, 0xF4; // obj_player.x
}
startup
{
refreshRate = 30;
settings.Add("Combat_Demo", true, "Combat Demo");
settings.CurrentDefaultParent = "Combat_Demo";
settings.Add("C_Nochallenge", false, "No challenge");
settings.Add("C_Trinketless", false, "Trinketless");
settings.Add("C_StressHurts", false, "Stress Hurts");
settings.Add("C_Patience", false, "Patience");
settings.Add("C_OneHitWonder", true, "One Hit Wonder");
settings.CurrentDefaultParent = null;
}
init
{
var module = modules.First();
// Thanks to Jujstme and Ero for this (finding room names)
var scanner = new SignatureScanner(game, module.BaseAddress, module.ModuleMemorySize);
Func<int, string, IntPtr> scan = (o, sig) =>
{
IntPtr ptr = scanner.Scan(new SigScanTarget(o, sig) { OnFound = (p, s, addr) => addr + p.ReadValue<int>(addr) + 0x4 });
if(ptr == IntPtr.Zero) throw new NullReferenceException("[Undertale Wildfire] Signature scanning failed");
print("[Undertale Wildfire] Signature found at " + ptr.ToString("X"));
return ptr;
};
IntPtr ptrRoomArray = scan(5, "74 0C 48 8B 05 ?? ?? ?? ?? 48 8B 04 D0");
vars.ptrRoomID = scan(6, "48 ?? ?? ?? 3B 35 ?? ?? ?? ?? 41 ?? ?? ?? 49 ?? ?? E8 ?? ?? ?? ?? FF");
vars.getRoomName = (Func<string>)(() =>
{
IntPtr arrayMain = game.ReadPointer(ptrRoomArray);
if(arrayMain == IntPtr.Zero) return string.Empty;
IntPtr arrayItem = game.ReadPointer(arrayMain + game.ReadValue<int>((IntPtr)vars.ptrRoomID) * 8);
if(arrayItem == IntPtr.Zero) return string.Empty;
return game.ReadString(arrayItem, 64);
});
string hash;
using(var md5 = System.Security.Cryptography.MD5.Create())
using(var fs = File.OpenRead(new FileInfo(module.FileName).DirectoryName + @"\data.win"))
hash = string.Concat(md5.ComputeHash(fs).Select(b => b.ToString("X2")));
switch(hash)
{
case "A2339F04EA118F0A43FB70FD9357CBBD":
version = "Combat Demo v1.10";
break;
default:
version = "Unknown";
MessageBox.Show
(
"This version of Undertale Wildfire is not supported by the autosplitter.\nIf you are playing an older version, update your game.\nIf not, please wait until the autosplitter receives an update.\n\n" +
"Supported version: Combat Demo v1.10.",
"LiveSplit | Undertale Wildfire", MessageBoxButtons.OK, MessageBoxIcon.Warning
);
break;
}
print("[Undertale Wildfire] Version: " + version + " (" + hash + ")");
vars.currentChallenge = 0;
vars.splits = new Dictionary<string, object[]>()
{
// Object variables in order: done, old room, new room, special condition
{"C_Nochallenge", new object[] {false, null, "rm_trail_anser_quigley", 1}},
{"C_Trinketless", new object[] {false, null, "rm_trail_anser_quigley", 2}},
{"C_StressHurts", new object[] {false, null, "rm_trail_anser_quigley", 3}},
{"C_Patience", new object[] {false, null, "rm_trail_anser_quigley", 4}},
{"C_OneHitWonder", new object[] {false, null, "rm_trail_anser_quigley", 5}}
};
}
start
{
if(version.StartsWith("Combat Demo"))
return (current.roomName == "rm_menu" && old.menuState == "challenges" && current.menuState == "fade_challenges" && old.menuSelection <= 1);
// Checking for selections 0 and 1 because you can do Down+Z on the same frame while on Back and it counts as starting No challenge while selection is still 0
}
reset
{
if(version.StartsWith("Combat Demo"))
return (current.roomName == "rm_menu" && old.menuState == "challenges" && current.menuState == "fade_challenges" && old.menuSelection <= 1);
}
onReset
{
if(game != null)
{
foreach(string split in vars.splits.Keys)
vars.splits[split][0] = false;
print("[Undertale Wildfire] All splits have been reset to initial state");
}
}
update
{
if(version == "Unknown")
return false;
current.room = game.ReadValue<int>((IntPtr)vars.ptrRoomID);
current.roomName = vars.getRoomName();
if(version.StartsWith("Combat Demo"))
{
if(current.roomName == "rm_menu" && old.menuState == "challenges" && current.menuState == "fade_challenges")
vars.currentChallenge = (old.menuSelection == 0 ? 1 : old.menuSelection);
// There is a global.challenge variable but it's 0 for both No challenge and Trinketless so it's not really reliable
// Checking for selection 0 for the same reason mentioned in start{}
}
if(old.room != current.room)
print("[Undertale Wildfire] Room: " + old.room + " (" + old.roomName + ")" + " -> " + current.room + " (" + current.roomName + ")");
}
split
{
int done = 0,
oldRoom = 1,
newRoom = 2,
condition = 3;
foreach(string splitKey in vars.splits.Keys)
{
if((!settings[splitKey] || vars.splits[splitKey][done]) ||
(vars.splits[splitKey][oldRoom] != null && old.roomName != vars.splits[splitKey][oldRoom]) ||
(vars.splits[splitKey][newRoom] != null && current.roomName != vars.splits[splitKey][newRoom])) continue;
bool pass = false;
int specialCondition = vars.splits[splitKey][condition];
switch(specialCondition)
{
case 0:
pass = true;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
pass = (current.playerX >= 969 && vars.currentChallenge == specialCondition);
break;
}
if(pass)
{
vars.splits[splitKey][done] = true;
print("[Undertale Wildfire] Split triggered (" + splitKey + ")");
return true;
}
}
}