-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEventScripts.txt
More file actions
202 lines (168 loc) · 7.18 KB
/
EventScripts.txt
File metadata and controls
202 lines (168 loc) · 7.18 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
Addresses are MFOMTU
At 081014BC is a big pointer array to data which *I think* are event script data
(I already was wrong once (see ActorSchedules.txt) so I don't be surprised if I am a second time)
The format for those data chunks is literally RIFF (!) (https://en.wikipedia.org/wiki/Resource_Interchange_File_Format)
RIFF "SCR "
subchunk "CODE" (probably contains script bytecode)
+00 | word | size of following chunk (seems redundant but sure)
+04 | .... | actual data
subchunk "JUMP" (not always present, unknown purpose (jump tables? command 24 reads those))
+00 | word | ?
+04 | .... | ?
subchunk "STR " (definitely contains strings/text data)
+00 | word | number of entries in the following table
+04 | word[] | string offset table. Each string is located at data + value in this table.
+XX | byte[] | actual string data
a struct layout (0803F0D8 populates it from script data):
+000 | word | non-zero if properly initialized?
+004 | word | address of script code data. Construction will fail if this is non-zero
+008 | word | current offset within script data?
+00C | word | size of script code data?
+010 | word | number of entries in the string (offset) table
+014 | word | address of the string offset table
+018 | word | address of string data
+01C | word | first word of "JUMP" section, if any
+020 | word | address of "JUMP" section +04
+024 | word[100] | ascending stack?
+1B4 | word | index of first free stack slot?
+1B8 | word[100] | memory?
+348 | word | ?
+34C | word | vtable
vtable layout:
+08 | <destructor>
+0C |
+10 | int usercommand(int id);
some subclass struct:
+000 | see above
+350 | word | pointer to GameData (see GameData.txt)
+354 | word | pointer to some object
+04 | word | pointer to some object
+A8 | word | pointer to GameObject (see Entities.txt)
+9C | word | ? (set by 080122B0, which also sets +E4) (text box related?)
+AC | word | auto_ptr to TextBoxHandle
+B0 | word | pointer to TextBoxCharExpander (whatever that is, december2018!me)
+B4 | word | auto_ptr to some object
+04 | word | vtable
+B8 | word | auto_ptr to some object
+04 | word | vtable
+BC | MusicPlayer
+D0 | begin ptr of a MusicPlayer range
+D4 | end ptr of a MusicPlayer range
+E0 | short | ? (set by 08012D38/scr func 37, which also sets +9C to 15)
+E4 | word | pointer to an Entity/Actor
+E8 | byte |
0803F2CC does core script interpretation
0803FAC8 handles "function calls" (instruction 21)
Each instruction starts with a byte:
+00bit | 7bit | instruction id
+07bit | 1bit | for instructions with immediate operands, if set, the value of the operand will intead be imm + [+348] (instead of just imm)
INSTRUCTIONS:
00: nop (nop)
01: equ ([-2] = [-1])
02: addequ ([-2] += [-1])
03: subequ ([-2] -= [-1])
04: mulequ ([-2] *= [-1])
05: divequ ([-2] /= [-1])
06: modequ ([-2] %= [-1])
07: add ([-2] + [-1])
08: sub ([-2] - [-1])
09: mul ([-2] * [-1])
0A: div ([-2] / [-1])
0B: mod ([-2] % [-1])
0C: and ([-2] && [-1])
0D: or ([-2] || [-1])
0E: inc ([-1]+1)
0F: dec ([-1]-1)
10: neg (-[-1])
11: not (![-1])
12: cmp ([-2] <=> [-1]) (result is -1, 0 or +1)
13: pushm imm (push mem[imm])
14: popm imm (pop mem[imm])
15: dup (push [-1])
16: pop (naked pop/discard)
17: push imm
18: b imm (goto offset imm)
19: blt imm
1A: ble imm
1B: beq imm
1C: bne imm
1D: bge imm
1E: bgt imm
1F: bi
20: end
21: call imm
22: push16 imm
23: push8 imm
24: select imm
instruction 01 (equ):
so +24 is some kind of stack, and +1B4 is like sp
what this does is read the second topmost value from the stack, and interprets it as an offset in the +1B8 array, which is probably something more like random access memory
it then stores the topmost value from the stack to both the offset in the +1B8 array *and* the second topmost stack slot
and also reduces the stack pointer by 1
So something like this:
IN: STACK = { ..., OFF, VAL }; MEMORY = { ... }
OUT: STACK = { ..., VAL }; MEMORY = { ..., [OFF] = VAL, ... }
This is amazing
instruction 24 (select):
this instruction is the sole reason for the JUMP chunk in the riff to exist.
So this is how we know how it is agenced:
first word of JUMP is... the total data size? Maybe?
First part of the JUMP data is an array of offsets to the actual jump data for each select instruction (indexed by select imm)
Jump data for select instruction:
+00 | word | case count
+04 | word | default jump offset within code (ignored if negative)
+08 | an array of [+00] objects (size: 8), *sorted by match value* (it is going to be bsearched through, so it better be sorted)
+00 | word | match value
+04 | word | jump offset within code
ins 02: (addequ)
IN: STACK = { ..., OFF, OP2 }; MEMORY = { ..., [OFF] = OP1, ... }
OUT: STACK = { ..., OP1 + OP2 }; MEMORY = { ..., [OFF] = OP1 + OP2, ... }
ins 03: (subequ)
IN: STACK = { ..., OFF, OP2 }; MEMORY = { ..., [OFF] = OP1, ... }
OUT: STACK = { ..., OP1 - OP2 }; MEMORY = { ..., [OFF] = OP1 - OP2, ... }
ins 04: (mulequ) (mem_op *= stack_op)
ins 05: (divequ) (mem_op /= stack_op)
ins 06: (modequ) (mem_op %= stack_op)
ins 07: (add)
IN: STACK = { ..., OP1, OP2 }
OUT: STACK = { ..., OP1 + OP2 }
ins 08: (sub)
IN: STACK = { ..., OP1, OP2 }
OUT: STACK = { ..., OP1 - OP2 }
ins 09: (mul)
ins 0A: (div)
ins 0B: (mod)
ins 0C: (and)
IN: STACK = { ..., OP1, OP2 }
OUT: STACK = { ..., OP1 && OP2 }
ins 0D: (or)
ins 0E: (inc)
ins 0F: (dec)
ins 10: (neg)
ins 11: (not)
(... (both tools/py/scr-tool.py and mary have full lists))
Scripts seem to use push8 for values up to 127 (as opposed to 255). Maybe a mistake in the original script processor?
bi is never used in any of the 1407 vanilla scripts (thank god)
subequ, divequ, modequ and dec are never used, but I feel like I know how they would have been used
addequ is only used by 1051
inc, popm and dup are all only used by 5, 166, 1046, 1052, 1121, 1226, 1244, 1345
5:
pushm 2; // stack: ([2])
inc; // stack: ([2]+1)
dup; // stack: ([2]+1), ([2]+1)
popm 2; // stack: ([2]+1); s.e.: [2] = [2]+1
this is push ++[2];
1046:
pushm 4; // stack: ([4])
dup; // stack: ([4]), ([4])
inc; // stack: ([4]), ([4]+1)
popm 4; // stack: ([4]); s.e.: [4] = [4]+1
this is push [4]++;
funcs:
note on arguments:
all of them are 32bit integers, but some have different meanings than others.
var is whatever, unk is idk, string is an index in the string offset table/a string id, addr is a variable slot id
see tools/functions.mary for script function documentation
scripts:
01 is when you get prengant?
04 is when you get horse?