The action hitbox, like all abstract mechanical concepts, is a name given to us by MathOnNapkins in his US disassembly. This hitbox describes the current size and location of Link's sword and hammer attacks. Its routine begins at $06F5E6
, and is surprisingly simple.
Hitboxes are very simple shapes. In fact, they're rectangles defined by 4 parameters:
x
- The x-position of the top-left corner of the rectangley
- The y-position of the top-left corner of the rectanglew
- The length in pixels that the rectangle extends towards the right; i.e. its widthh
- The length in pixels that the rectangle extends downwards; i.e. its heightFor the action hitbox specifically, x
and y
will be relative offsets, rather than absolute. That is, all values of x
and y
will need to be added to Link's x- and y-coordinates to get the actual position of the hitbox.
Hitboxes are simple shapes because this cuts down on calculation time. Even modern 3D games still use basic shapes (spheres or rectangular prisms), because they are much more efficient. These games tend to use a whole lot of them to approximate more complex shapes, but the calculations are so fast and easy that this turns out to be better than a single complicated calculation.
Within the action hitbox routine, there are several branches to determine which hitbox is used, checked in the following order:
Direction | Parameters | |||
---|---|---|---|---|
x | y | w | h | |
Up | 0 | −8 | 16 | 16 |
Down | 0 | 16 | 16 | 16 |
Left | −8 | 8 | 16 | 16 |
Right | 8 | 8 | 16 | 16 |
The dashing hitbox is used whenever the dashing flag at $0372
is nonzero. The direction Link is facing is used to index tables just before the routine to determine the relative offsets of the top-left corner. Regardless of Link's direction, the dash hitbox always extends 16 pixels right and 16 pixels down.
The spin hitbox is next, because it's dead simple, and because the next two sets need to be discussed together. This hitbox is used when bit7 of $3C
, an address for sword control, is set.
Link's direction is completely irrelevant for the spin hitbox. This hitbox will always be 14 pixels up, 10 pixels left, and extend 44 pixels right and 45 pixels down.
$3C | Box? |
---|---|
$00 | false |
$01 | false |
$02 | false |
$03 | true |
$04 | true |
$05 | true |
$06 | true |
$07 | false |
$08 | false |
$09 | true |
$0A | true |
$0B | false |
$0C | false |
$80+ | spin |
The hammer and net hitboxes point to the same branch, which is taken when the hammer is flagged (bit 1 or unused bit 3 of $0301
) or the net is flagged (bit 4 of $037A
). This routine shares code with slashing and poking, but there's a key difference. Believe it or not, the direction Link is facing is not taken into account.
The sword control address $3C
handles spin attacks, but it also handles whether or not a hitbox should even be calculated for other sword attacks. In this case, when the value is non-negative, it indexes a table (shown to the right), for this decision. For the hammer and net, the value here is irrelevant.
The parameters of the hitbox are indexed from various tables using the X
register. For the hammer and net, this index is always 0, but for sword attacks, it is a function of Link's direction and the current animation step of the attack, which is held in $3C
. Once this index is calculated, both branches merge, and the rest of the routine is the same.
If direction is irrelevant for the hammer and net, how are their hitboxes actually different?
This is where two more variables come into play. They're pretty much an additional offset to x
and y
, so we'll call them Ox
and Oy
.
These offsets are constantly being recalculated, and they depend mostly on Link's current action and the direction he's facing. So I kinda lied. Direction does matter for the hammer and net, but it's done indepedently in an entirely separate part of the code. Furthermore, this means direction matters twice for slash and poke attacks.
As for why the sword can extend the hammer hitbox, that's just because a hitbox calculation is requested after the sword has placed its values, but before the offsets are reset again.
With just that much information, the calculations are super simple:
xhitbox = xLink + xi + Ox
yhitbox = yLink + yi + Oy
whitbox = wi
hhitbox = hi
Where vi
just indicates the variable came from our tables indexed by our direction and how far we are into the slash animation.
Hammer/Net | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
I | x | y | w | h | ||||||||||||||||||
$00 | 0 | 0 | 15 | 15 | ||||||||||||||||||
Sword slash | ||||||||||||||||||||||
Up | Down | Left | Right | |||||||||||||||||||
I | x | y | w | h | I | x | y | w | h | I | x | y | w | h | I | x | y | w | h | |||
$01 | 2 | 2 | 4 | 4 | $11 | 2 | 2 | 4 | 4 | $21 | 0 | 0 | 8 | 8 | $31 | 0 | 0 | 8 | 8 | |||
$02 | 0 | 0 | 8 | 8 | $12 | 4 | 0 | 16 | 8 | $22 | 0 | 0 | 8 | 8 | $32 | 0 | 0 | 8 | 8 | |||
$03 | 0 | 2 | 8 | 2 | $13 | 4 | 2 | 12 | 4 | $23 | 0 | 0 | 8 | 8 | $33 | 0 | 0 | 8 | 8 | |||
$04 | −8 | 4 | 8 | 12 | $14 | 0 | −4 | 8 | 12 | $24 | 2 | −2 | 10 | 8 | $34 | −4 | −2 | 10 | 8 | |||
$05 | 0 | 4 | 8 | 8 | $15 | 0 | −3 | 8 | 12 | $25 | 2 | 0 | 14 | 8 | $35 | −4 | 0 | 14 | 8 | |||
$06 | 2 | 4 | 12 | 12 | $16 | −4 | −8 | 12 | 12 | $26 | 4 | −4 | 15 | 12 | $36 | −10 | −4 | 15 | 12 | |||
$07 | 0 | 7 | 8 | 8 | $17 | −4 | 0 | 11 | 4 | $27 | 4 | 1 | 4 | 4 | $37 | 0 | 1 | 4 | 4 | |||
$08 | 2 | 2 | 4 | 4 | $18 | −6 | 0 | 12 | 8 | $28 | 2 | 2 | 4 | 4 | $38 | 2 | 2 | 4 | 4 | |||
$09 | 2 | 2 | 4 | 4 | $19 | 2 | 2 | 4 | 4 | $29 | 2 | 2 | 4 | 4 | $39 | 2 | 2 | 4 | 4 | |||
$0A | 1 | 1 | 6 | 6 | $1A | 1 | 1 | 6 | 6 | $2A | 2 | 1 | 6 | 6 | $3A | 0 | 1 | 6 | 6 | |||
$0B | 1 | 1 | 6 | 6 | $1B | 1 | 1 | 6 | 4 | $2B | 2 | 1 | 6 | 6 | $3B | 0 | 1 | 6 | 6 | |||
$0C | 0 | 0 | 0 | 0 | $1C | 0 | 0 | 0 | 0 | $2C | 0 | 0 | 0 | 0 | $3C | 0 | 0 | 0 | 0 | |||
$0D | 0 | 0 | 0 | 0 | $1D | 0 | 0 | 0 | 0 | $2D | 0 | 0 | 0 | 0 | $3D | 0 | 0 | 0 | 0 | |||
$0E | 0 | 0 | 0 | 0 | $1E | 0 | 0 | 0 | 0 | $2E | 0 | 0 | 0 | 0 | $3E | 0 | 0 | 0 | 0 | |||
$0F | 0 | 0 | 0 | 0 | $1F | 0 | 0 | 0 | 0 | $2F | 0 | 0 | 0 | 0 | $3F | 0 | 0 | 0 | 0 | |||
$10 | 0 | 0 | 0 | 0 | $20 | 0 | 0 | 0 | 0 | $30 | 0 | 0 | 0 | 0 | $40 | 0 | 0 | 0 | 0 |
Interestingly, I didn't make any mention of how exactly a hitbox is cancelled. That's because, they kind of aren't. In the case where everything else fails the scratch space values are mostly left alone. The only one that isn't is the high byte of the x-coordinate, which will take on the value 0x80
. This means the existing values will be used for the size and vertical position of the hitbox, but the horizontal position will be anywhere from −32513 to −32768 pixels away.
What about the offsets for the hammer? Most of the time, these extra offsets are 0x80
. They are only set to proper values for a single frame. But, nothing actually prevents the hitbox from being created. Instead, it will just use that default value. Unfortunately, everything that requests an action hitbox also checks Oy
beforehand, skipping the request and subsequent hitbox code if the value is exactly 0x80
.
And as one last thing: ya know that thing where you hit King Helma and then he clinks you and you see the clink at the bottom. What's that about?
At first, I thought it had to do with those offsets, since there's a routine for placing that tink spark, and they're used in the calculation.
It turns out to be even dumber.
When you hit King Helma with the hammer while outmaneuvering him, the game calls a subroutine to calculate the velocity of Link's recoil. In doing so, some leftovers are put into scratch space. And for some got dang reason, right after doing that, those same leftovers are used for the coordinates of the tink.
I think what they were going for is using the leftovers of the action hitbox routine for these coordinates, but, yeah…