Found an incredibly powerful Melee tool, "Melee Subaction Unpacker", in C++:
a CLI tool to try to unpack melee's subaction scripting language.
Here's Peach dash attack:
Here's the definition (in the melee subaction language) exported from Melee Subaction Unpacker:
name: PlyPeach5K_Share_ACTION_AttackDash_figatree
stroff: 794
animoff: 62ca0
unknown 0x8: 3000
eventsoff: 4a8c
positionalFlags: 88
charID: 900
unknown0x14: 0
34 (0x8b80):
offset: 0x4a8c
first value:08
08 wait_for(6)
44 sfx(<0b00 00 00 00 00 00 00 40 00 00 c0 00>)
2c hitbox(0 128 0 1000 0 200 0 10257 8704 76 192
8960 0 0 64 192)
2c hitbox(0 0 128 1200 0 2000 2000 46225 8704 76
192 6400 0 0 64 192)
28 graphic_common(1021 0 0 0 0 0 0)
ac gen_article(<0b00 80 00 00>)
04 wait_until(3)
2c hitbox(0 128 0 700 0 200 0 10257 8704 76 192
2560 0 0 0 192)
2c hitbox(0 0 128 900 0 2100 1800 46225 8704 76
192 2560 0 0 0 192)
04 wait_until(12)
40 end_all_collisions(<0b00 00 00 00>)
08 wait_for(36)
5c iasa(<0b00 00 00 00>)
00 exit(<0b00 00 00 00>)
It also gives properties from the attribute table:
❯ ./mreader ~/repos/jam1garner/gc-gcm/melee/PlPe.dat | grep 'shield_break_initial_velocity'
shield_break_initial_velocity = 2.5
❯ ./mreader ~/repos/jam1garner/gc-gcm/melee/PlPr.dat | grep 'shield_break_initial_velocity'
shield_break_initial_velocity = 10
So that means:
- When someone hits Peach's shield until it breaks, Peach gets sent up with 2.5 initial velocity
- When someone hits Puff's shield until it breaks, Puff gets sent up with 10 initial velocity
If you're familiar with the game, you might know that Puff shield break sends her straight up and usually kills her immediately.
So, I wanted to see where shield_break_initial_velocity
is coming from in PlPr.dat
and PlPe.dat
!
In the C++ code, it comes from a struct definition, ftdata_attribute_table
. There's some comments about the offsets:
// 0x90
float shield_size;
float shield_break_initial_velocity;
uint32_t rapid_jab_window;
float unknown0x9C;
// 0xA0
So that's between relative offset 0x90
and 0xA0
, what's that length? that's 0x10
, enough space for 16 bytes. The first 2 floats (shield_size
, shield_break_initial_velocity
) take up 8 bytes, and the last two (rapid_jab_window
, unknown0x9C
) take up 8 bytes.
I had a lot of trouble finding the attribute table, which should be around 0x3888
:
[attribute_table]: 0x3888
[attribute_table]
walk_initial_velocity = 0.2
walk_acceleration = 0.1
walk_maximum_velocity = 0.85
walk_animation_speed = 0.187
But then I used an IEEE 754 floating point converter!
- offset - 0 1 2 3 0123 comment
0x00003888 fe00 0000 ....
0x0000388c 0000 0000 ....
0x00003890 1800 0000 ....
0x00003894 3e4c cccd >L.. ; walk_initial_velocity = 0.2
0x00003898 3dcc cccd =... ; walk_acceleration = 0.1
0x0000389c 3f59 999a ?Y.. ; walk_maximum_velocity = 0.85
0x000038a0 3e3f 7cee >?|. ; walk_animation_speed = 0.187
This means:
- there's a
0xC
"header" at the start of the attribute table:fe00 0000 0000 0000 1800 0000
- attributes start at
0x3888
+0xC
shield_break_initial_velocity
has a relative offset of0x94
(0x90 + 4
, from the comment), absolute offset of0x3888 + 0xC + 0x94
If I know that Peach's shield_break_initial_velocity
should be 2.5, I expect to see 40 20 00 00
at that address.
❯ r2 -s '0x3888 + 0xC + 0x94' -n ~/repos/jam1garner/gc-gcm/melee/PlPe.dat <<< 'px 4'
-- Well, it looks like it's working.
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x00003928 4020 0000 @ ..
Very satisfying to understand!