I’ve updated my
old post in this thread about subaction event functions with new information concerning the color events I formerly called “unkFX” events.
For the most part, I've studied these from data that resides in PlCo.dat. I believe that is where many "body auras" are defined using this event system:
Code:
80014258 $!_SAevent_Parse_Color
# generic color events: list @803BA248
80013bb0 $!_SAeventColor_00-[28]-Terminate_color_update
80013bb8 $!_SAeventColor_01-[2C]-Sync_Timer_INT
80013be4 $!_SAeventColor_02-[30]-Disable_Light_and_Overlay
80013c18 $!_SAeventColor_03-[34]-Set_New_Light
80013d68 $!_SAeventColor_04-[38]-Set_Light_Color
80013e3c $!_SAeventColor_05-[3C]-Set_Light_Blend_Rate
80013f78 $!_SAeventColor_06-[40]-Set_Light_Position
80013ff0 $!_SAeventColor_07-[44]-Disable_Light
80014014 $!_SAeventColor_08-[48]-Set_New_Overlay
800140f8 $!_SAeventColor_09-[4C]-Set_Overlay_Blend_Rate
80014234 $!_SAeventColor_0A-[50]-Disable_Overlay
---
800bff34 $!_SAevent_Parse_ColorPlayer
# extra events for fighters: list @803C6AD0
800bfe74 $!_SAeventColorPlayer_00-[54]-Spawn_GFX
800bfeb4 $!_SAeventColorPlayer_04-[58]-Spawn_SFX
800bfef4 $!_SAeventColorPlayer_08-[5C]-unkFlag
Caller:
800c0408 Ab_Knockback+HitEffects_Unknown4
---
800bff70 $!_SAevent_Parse_ColorPlayerSkip
# extra events for skipping fighter events: list @803C6ADC
800BFE94 $!_SAeventColorPlayerSkip_00-[54]-5word
800BFED4 $!_SAeventColorPlayerSkip_00-[58]-3word
800BFF14 $!_SAeventColorPlayerSkip_00-[5C]-1word
---
80021c18 $!_SAevent_Parse_ColorScreenFlash
# This is literally just a blr.
# There is no extra index of opcodes for screen flashes,
# so this blr instruction is passed in place of a new parse function.
Caller:
80021c80
---
801c9664 $!_SAevent_Parse_ColorWorld
# extra events for world color events: @r13 - 0x7134 (804D456C)
# events are determined by variables, and may change depending on stage
Caller:
801c9698
---
80279b30 $!_SAevent_Parse_ColorItem
# extra events for item color events: @r13 - 0x64D8 (804D51C8)
# events are determined by variables, and may change depending on item
Caller:
80279be0
Here are some more details:
[28] - 1word -
Terminate Color Update
@80013bb0
no syntax
# use this to end a color event, like you were using "00 00 00 00"
# -- using this in place of null will prevent the color register from further updating its object
[2C] - 1word -
Synchronous Timer (int-based)
@80013bb8
0:
03FFFFFF = add to timer
# use this to set the color register timer, in place of [04] or [08] events
[30] - 1word -
Disable Light/Overlay Colors
@80013be4
no syntax
# use this to disable the effects of an existing aura color/light
[34] - 2word -
Set Light Position and Color
@80013c18
0:
02000000 = set flag (20)
0:
00FFF000 = set light X (SINT)
0:
00000FFF = set light Y (SINT)
1:
FFFFFFFF = RGBA
# use this to set a new light, with both position and color info
# -- sets blend rates to 0
[38] - 2word -
Set Light Color
@80013d68
1:
FFFFFFFF = RGBA
# use this to just set the light's color to a new color
# -- sets blend rates to 0
[3C] - 2word -
Set Light Blend Rate
@80013e3c
0:
03FFFFFF = blend rate
1:
FFFFFFFF = target RGBA
# use this to adjust light to a new color by blending it over time
# -- blend rates will persist beyond specified number of frames, and can overflow to create a blink effect
[40] - 1word -
Set Light Position
@80013f78
0:
01FFE000 = Light X
0:
00001FFF = Light Y
# use this to adjust light XY position, relative to GObj
[44] - 1word -
Disable Light
@80013ff0
no syntax
# disable just the light effect
[48] - 2word -
Set Overlay Color
@80014014
1:
FFFFFFFF = RGBA
# use this to set overlay to a new color
# -- sets blend rates to 0
[4C] - 2word -
Set Overlay Blend Rate
@800140f8
0:
03FFFFFF = blend rate
1:
FFFFFFFF = RGBA
# use this to adjust overlay to a new color by blending it over time
# -- blend rates can create aforementioned blink effect
[50] - 1word -
Disable Overlay
@80014234
no syntax
# disable just the overlay effect
---
Unlike other event parsers; the color event parser can read in a
tertiary opcode list as an argument from its caller. This allows it to append the default opcodes based on what type of object is being colored.
For players, this list is constant, and can be used to create GFX and SFX within the aura loops used for things like body auras:
[54] - 5word -
Spawn Player GFX
@800bfe74
# syntax is exactly the same as player event [28]
[58] - 3word -
Spawn Player SFX
@800bfeb4
# syntax is exactly the same as player event [44]
[5C] - 1word -
unk flag
@800bfef4
# syntax is exactly the same as player event [E4]
This particular detail about the color event system creates some pretty interesting implications about how
event systems can be run simultaneously in parallel.
For other GObjs -- like those used by items and stages -- these extra opcodes appear to be variables. Screen flashes do not have any extra opcodes, and use a blr instruction in place of a tertiary opcode function. To see how the color event parser handles these, use breakpoints on the described functions during the following in-game scenarios to create examples:
Items - launch from a barrel cannon
Stages - lighting transition in underground maze, in adventure mode -- when fighting Link.
---
From this new information, it would seem that moveset scripts, projectile scripts, player aura lights/colors, item aura lights/colors, screen flashes, and some world lighting transitions are all handled (in part) by a common event system.
An event operation in this system is simply a function designed to read a chunk of data that contains arguments; and then do something with those arguments. Each function is indexed as a callback on a pointer table contained in the data section of Start.dol, and a unique parser function is given one of these pointer lists in order to create a
system of opcodes. The lists can be concatenated, and all of the various event systems share a common set of control events in addition to any operations that might be defined for specific purposes.
Each chunk of data to be parsed by one of these systems includes a 6-bit opcode that tells its parser
what kind of operation it is. The parser uses this opcode to identify a callback function from its assembled opcode list, and sends the data chunk to its corresponding function using an event pointer. When the operation is done, the parser moves onto the next chunk of data until it either terminates or hits a delay instruction.
The subaction event data that can be seen in Crazy Hand is
merely one example how this system can be utilized.
---
For each of these common event systems, a small control structure is used to keep parser variables persistent between frames:
Code:
Event controller:
0x00 Event Timer (float)
0x04 Event Frame Counter (float)
0x08 Pointer to Next Event Op
0x0C Memory Count
0x10 Control Memory 0
0x14 Control Memory 1
0x18 Control Memory 2
0x1C Control Memory 3
0x20 Control Memory 4
The event timer and frame counter variables are used to store timer information. The pointer stores the current place being parsed in-between frames. The memory count keeps track of how many pieces of control memory are currently stacked. The control memory stores return pointers, and loop counters.
Player GObjs (aka “player entities”) have data tables that contain these control structures as a part of their format -- allowing each player GObj to read moveset data. This structure starts at
offset 0x3E4 of the player data table.
A little known fact however is that players actually have
4 of these structures. The other 3 are used by the color event system -- and have been extended to create a new structure format that I think is called a "color register" -- or a "color ratio register". They are each a whopping 0x80 bytes in length, compared to the original 0x24 of the generic control structure:
Code:
Color register:
0x00 W Event Timer (int)
0x04 ? (unused?)
0x08 P Pointer to Next Event Op
0x0C W Memory Count
0x10 W Control Memory 0
0x14 W Control Memory 1
0x18 W Control Memory 2
0x1C W Control Memory 3
0x20 W Control Memory 4
0x24 ? ?
0x28 ? ?
0x2C W RGBA
0x30 F R
0x34 F G
0x38 F B
0x3C F A
0x40 F add R
0x44 F add G
0x48 F add B
0x4C F add A
0x50 W light RGBA
0x54 F light R
0x58 F light G
0x5C F light B
0x60 F light A
0x64 F light add R
0x68 F light add G
0x6C F light add B
0x70 F light add A
0x74 F light X position
0x78 F light Y position
0x7C B flags
# (80) = color overlay display toggle
# (40) = light display toggle
For as long as I’ve been hacking Melee, the community seems to have known about most of these color variables as utilities for creating
Flash <color> on <action> style codes. I don’t however think that anyone has documented the fact that these variables are actually part of an extended control structure for parsing event data. What the SSBM Data sheet calls the “blend pointer” is actually an event pointer, like the one used for moveset data.
Each color register can be accessed from the following player data offsets:
Code:
0x408 = Inflicted color register
0x488 = Self color register
0x508 = Auxiliary color register?
The “add” variables in each of these structures will add their float value to the corresponding channel each frame. These are used to create the blended transitions over time that can be created with the default color events. Channel overflows (> 255.0) go back to zero, which allows them to be used for “blinking” animations as well. Negative blend values will subtract instead of add. Setting them to 0 will keep a channel from changing over time within the scope of a single action.
Creative use of these variables with Achilles' custom player data subaction event could result in some very interesting effects. On that note, custom color events might allow for an exploit that lets us run separate, specialized player data events (even custom ones) in parallel by further extending the player-color events to create additional doppelgangers. In fact, it seems like it would be a fairly simple matter to invent entirely new event systems from scratch, using the game's methods as a template. I think these revelations will have
interesting implications for the future of custom event syntaxes.
Itaru
UnclePunch
SinsOfApathy
DRGN
Achilles1515