I mostly just looked at this one function, so there's a lot I still don't know. Nonetheless, this single function does write to a huge portion of the ANM VM data structure, and almost no field on it is written by more than one command, meaning that a good 75% or so of the structure can be immediately associated with particular commands just by looking at this function.
I still haven't looked at 000 commands, 300-302 (textures).
This may contain many blatant factual errors. I was taking notes at 3AM and this shit is hard, yo.
All data is from TH16.
So this is obviously just an alias for rotateTime(t, mode, 0, 0, theta), right?
...wrong. It writes to a completely separate set of data, time, and mode variables. It enables the same flag as rotateTime and doesn't appear to enable any others, which suggests to me that both rotations are applied together. (i.e. it appears you can probably use both rotateTime and rotateTime2d and have the effects stack).
If I had to guess without any further information, this is probably to allow things to be rotated onscreen after an arbitrary 3d rotation has already been applied.
This implicitly sets the move mode to 8.
The three input positions are saved to zAnmVM.pos_bezier_1, zAnmVM.pos_bezier_2, and zAnmVM.pos_final. (the last of which is the same variable used by 407 moveTime). Calling 407 moveTime clears pos_bezier_1 and pos_bezier_2.
There is no additional data exclusive to moveBezier beyond those two 3-vectors, and it sets no flags.
I still haven't fully figured out the set of fields that this accesses.
The implementation of this begins similarly to moveTime, clearing bezier_point_1 and bezier_point_2. However, it has fewer arguments, and appears to write to a completely separate set of data, time, and mode fields.
434 is some kind of scale-related thing. 435 appears to be its time counterpart.
Each one writes its own set of variables that aren't used by any other opcode. Both enable the same bitflag that is enabled by all of the scale commands.
415, 416, 425, and 426 are all explained on the chinese wiki but the translated descriptions are confusing to me so I haven't named them. 415 is rotation-related, 416 is scale-related. 425 and 426 are... I dunno, uv-related?
All six write to their own disjoint sets of data, time, and mode variables.
427 and 428 appear to be ___Time versions of 425 and 426.
Strangely, the first four commands all share a bit flag (using any of those commands enables the bit). The remaining two do not automatically enable this bit for some reason, even though most other ___Time commands usually do.
A tentative set of names I might give these:
403 alpha1(a)
404 rgb1(r, g, b)
405 alpha2(a)
406 rgb2(r, g, b)
408 rgb2Time(t, mode, r, g, b)
409 alpha2Time(t, mode a)
413 rgb1Time(t, mode, r, g, b)
414 alpha1Time(t, mode, a)
423 colorTimeEnabled(twoBit)
The numeral 1 refers to the "main" color, and the numeral 2 refers to the secondary color used by gradients.
(Initially I thought 408 and 409 were the time functions for the first color, but this assignment makes more sense)
Calling either 413 rgb1Time or 414 alpha1Time has the side-effect of causing a 2-bit bitfield to be set to 0b01. This appears to be related to a statement on the chinese wiki which suggests that 414 alpha1Time prevents the second gradient color from changing. Unknown423 can be used to set this 2-bit bitfield manually. Presumably, calling Unknown423(0b11) AFTER calling 413 and 414 will allow both gradient colors to change with time.
(Edit: Dammit, no, things still don't make sense! Most time functions do at some point read the data for their non-time counterpart, and 408 and 409 read the data for color 1, while 413 and 414 read the data for color 2. I'm so confused!)
I have no idea what the wiki is saying about this or how it's supposed to differ from alpha1Time and alpha2Time, but it modifies the same fields as alpha2Time.
This actually sets a two bit field instead of a 1-bit field. We know that the lowest bit is a visibility flag. What is the other bit?
The description on the wiki makes absolutely no sense.
Judging from the implementation, this is the ___Time version of 429 windowBlinds.
This takes some vec3 field—let's call it AnmVM.backup_pos—and copies it into AnmVM.pos. It then sets AnmVM.backup_pos to zero.
backup_pos also appears to be used for some purpose in the code that runs for all opcodes after exiting the switch statement, but I don't know anything more than that.
Unknown418 calls a pretty important-looking function that uses many, many of the fields stored on the VM like position, texture size, scale, as well as many of the unknown quantities and bitflags. (this function is definitely on my todo list of useful things to look at!)
The function takes an output pointer to a float[3][4], and it writes what appears to be (based on values seen in memory) four vertices of a quadrilateral in 3d space. After calling that function, Unknown418 copies the xy parts of these vertices into a float[2][4] array stored on the VM. (after dividing the components by 640 and 480)
...sadly, this instruction does not appear to be used in TH16.
Unknown419 seems to be a continuous form of Unknown418. Basically, Unknown419 sets a bitflag that causes ins_3 to do something similar to Unknown418 on every frame. This instruction also does not seem to be used in TH16!
There is one remaining callsite for the important-looking function. This callsite IS used many times per frame... however, I tried hacking it to always write the quadrilateral [(100, 200), (100, 100), (200, 200), (200, 100)], and nothing out of the ordinary happened. Terribly disappointing!
When the layer number falls within particular ranges, some bit flags may be changed. In particular, it always simulates a call to setVisible, with different arguments based on the layer number. It sometimes also simulates a call to Unknown313(0b001). See the bitflags listing at the end for more details.
Using any of these creates a child VM.
There is a single bitflag that is always copied from the parent to child. (see bitflags section at end). The rest are copied from a VM stored in the AnmLoaded type. (Curiously, at first glance, the code for these instructions also appears to be explicitly enabling one particular flag; but that happens before everything gets copied, so it is overwritten)
Aside from the layer, the one bitflag, and a pointer to a "root" VM, nothing else is copied from parent to child.
The specific instruction you use decides where the object is placed:
- 500 inserts at the back of the
worldlist. This is a list of ANMs that exist in the game world. When you pause the game, these ANMs stop running. They are only allowed to use layers 0 to 35 (if you try to use others, the game will change the layer on you). - 501 inserts at the front of the
worldlist. This probably lets you achieve a different z-ordering. - 502 inserts at the back of the
uilist. This is a list of ANMs that exist outside of the game world. These ANMs alre always running. They are only allowed to use layers 36 to 42 (if you try to use others, the game will change the layer on you). - 503 inserts at the front of the
uilist.
Unless stated otherwise, all other child creation opcodes insert the child in the same place as 500 does.
This is identical to 500, but then reads two more float args and stores them in the "alternate position" variable for bitflag 530:10 (described later).
Unlike 500-503, this enable the aforementioned flag after copying everything, so it actually gets enabled this time.
This one copies far more state from the parent, including rotation, position, and the alternate position. It still only copies one bitflag.
506 simply combines the effects of 504 and 505.
When a child VM calls this, it will receive the current values of all script variables that are stored per-VM. There's 16 of them in total. I believe they are specifically the following: (this likely contains errors)
10000, 10001, 10002, 1000310004f, 10005f, 10006f, 10007f10008f, 1000910010f, 10011f, 10012f. These are "random" but there's also some data associated with them (presumably scale factors?) which can be modified by scripts by attempting to store these variables. (well, at least, the first two can be modified.10012fhas data, but for some reason you can't modify it!)10033f, 10034f, 10035f
This one also creates an object. This time, the argument is the index of some special, "global" hardcoded ANM instruction, and looks it up in some static table. A function pointer from this table is immediately called after the child is created, and then a bunch of data from the table is copied over.
This table is used for other purposes besides 508 (in fact I'm not sure if opcode 508 is ever even used!). It is used by Aya's and Cirno's bombs (both use entry 0x3), and ECL 334 calls this with the user-supplied arg. The table has four entries total in TH16.
This instruction sets a bitflag. Calling Unknown507(1) on a child VM appears to decouple it from its parent's scale and rotation, so that scaling the parent does not scale the child.
Or at least, this is what it looks like from the small amount of code that I've witnessed using this bitflag so far.
This one subtracts an amount from the current time, simulating a wait.
Useful for waiting a random amount of time, though ironically it's often used with fixed values.
When instruction 3 is encountered, it begins by scanning ahead and doing the following:
- If an instruction with opcode
-1is encountered, it resumes normal execution at the instruction after the-1. - If it encounters
label(0), then one of two things occurs:- If it previously encountered a
label(-1), it will immediately resume normal execution at the instruction after thelabel(-1). - If it did not previously encounter a
label(-1), it will enter an important-looking part of the code that appears to perform time evolution.
- If it previously encountered a
I have tentatively named 3 run, though I know someone else has named it stop! Whatever it is, its (large) implementation will contain crucial details to understanding what many of the bitfields and variables actually do.
The following commands have been verified to have no immediate effect inside anm_parser besides setting bitfields.
Unknown305(bool)Unknown306(bool)Unknown307(bool)Unknown311(bool)Unknown312(twoBit, twoBit)Unknown313(threeBit)(as mentioned,setLayermay also change these bits)Unknown314(bool)Unknown315(bool)Unknown316()(enables a bit)Unknown317()(disables that bit)Unknown419(bool)Unknown431(bool)Unknown432(bool)Unknown423(twoBit)(described above)Unknown507(bool)(described above)
There is space for 64 bitflags stored on the VM, contained in positions 0x530-0x538 in TH16. The game almost always uses 32-bit dword operations to manipulate these, so I group them into two blocks of 32, which I will call 530 and 534.
Here is a mapping of bitflags to the commands that modify them. This may contain errors. In the following, 530:2 names the 1 << 2 bit, and 530:(4-6) names a semi-inclusive range of bits.
If you see (unknown) it means I did not spot any usage of it in this function. It may be unused, it may be used by other functions, or it might even be used by this function (and I missed it).
530:0:- Set by 310
- Enabled by 300
texSelect
530:1: Enabled by 316, disabled by 317530:2: Enabled by 401rotate, 410rotateTime, 414rotateTime2d530:3: Enabled by 402scale, 412scaleTime, 434, 435530:4: Enabled by 429windowBlinds, 430530:(5-9): Set by 303blendMode530:9: (unknown)530:10: "Alternate start pos flag"- Switches between two possible vec3s for the starting position (the value corresponding to 400
move). Any command that attempts to read or write this vector will look at this flag to decide which vec3 to access.
- Switches between two possible vec3s for the starting position (the value corresponding to 400
530:11: Set by 308mirrorX530:12: Set by 309mirrorY530:13:- Set by 305
- Usage at
0x40b200.
530:14: (unknown)530:15: Set by 306530:16: (unknown)- Usage at
0x467489. When disabled, this code computesmatrix_410based onmatrix_3d0and some scale members. When enabled, this code does not overwritematrix_410, and additionally uses position members somehow. - Usage at
0x466f1b.
- Usage at
530:(17-19):- Set to
0b01by 413rgb1Timeand 414alpha1Time - Can be manually set to any value using 423
- Usage at 0x467952
- Set to
530:(19-21): (unknown)530:(21-25): Set by 412anchor530:(25-30):- Set by 302
renderMode - Virtually every 600-series opcode also changes this (in addition to their other effects)
- Set by 302
530:(30-32): Set by 312 (second arg)- Usage at
0x4651f1. It is compared to a field on the giant ANM struct. If it does not match,sub_465a80is called, and then the aforementioned field is set to the value stored in the bitflags.
- Usage at
534:(0-2): Set by 312 (first arg)534:(2-5):- Set by 437
rotationSystem - Usage at
0x46757f
- Set by 437
534:(5-7): (unknown)- At
0x46e783, these anms will only be rendered if these flags are0b00. - Usage at
0x4684ce - Usage at
0x46e3b9 - Set to
0b10at0x46e6df - Set to
0b01at0x46f1ea,0x46f2c2and more.
- At
534:7:- Set by 424
autoRotate - Usage at
0x41d414. - Usage at
0x445972.
- Set by 424
534:8: Set by 431534:9: Set by 432534:10:- Set by 307
- Instructions 500-503 and 505 appear to forcibly enable this flag on the child at first glance; but then it gets copied over from the vm on the
AnmLoaded. - 504, 506, and 508 do forcibly enable this flag on the child.
- Enabled at
0x405fc. (oops, I think I a digit) - Enabled at
0x41901c.
534:11: Set by 311534:12: (unknown)- Usage at
0x46da53. Changes some arguments to a text-drawing function. - Enabled at
0x429df2. - Enabled at
0x42a570.
- Usage at
534:13:- Set by 419
- Each frame, when
ins_3sees this flag set, it does things that appear to be very similar to instruction 418.
534:(14-16): (unknown)- Cleared at
0x46f9e0 - Cleared at
0x419071 - Set to
0b10at0x45f072and0x45f19e. - Set to
0b01at0x45f2a3. - Compared to
0b10at0x45f289. - Compared to
0b01at0x45fa91.
- Cleared at
534:16:- Set by 507
- When this flag is 0, some functions contain additional code that take into account the parent (or root?) VM's scale and rotation.
534:17: (unknown)534:(18-20):- Set by 438
setVisible. - 304
setLayer(layer)also affects this:- if
3 <= layer <= 19, it callssetVisible(0b01) - if
20 <= layer <= 23, it callssetVisible(0b10) - otherwise, it calls
setVisible(0b00)
- if
- Set to
0b00at0x4071da - Usage at
0x406bb1 - Usage at
0x467f20(comparison to0b00)
- Set by 438
534:(20-23):- Set by 313.
- 304
setLayer(layer)also affects this:- if
20 <= layer <= 31, or if36 <= layer <= 42, it callsUnknown313(0b001). - otherwise, these flags are not modified.
- if
- Set to
0b001at0x406deb. - Usage at
0x4687aa. Causes some things to optionally be scaled to the window resolution or half of that. - Usage at
0x406a88. Similar effect.
534:23: Set by 314534:24: Enabled by 415, 416, 425, 426534:25:- Set by 315
- This flag is copied from parent to child by instructions 500-506.
534:26:- Enabled at
0x46f84b. - Enabled at
0x46fc9f. - Cleared at
0x46f9c2. - Usage at
0x46f1d9. - Usage at
0x46f22e.
- Enabled at
534:(27-32): (unknown)