Skip to content

Hookbill the Koopa

Raiden edited this page Jul 13, 2017 · 2 revisions

Hookbill is the most technically complex boss in the game. He has a whopping 56 AI states, a skeleton for his body parts, one of which is drawn on a background layer, his body parts each have separate rotational values per animation frame, his graphics are mostly Super FX, and much of his processing is on the Super FX as well, despite even his 65816 code being over a quarter of a bank long. He touches on many, many aspects of the game's coding, lookup tables, etc.

AI

  crawl sequence:
  00: restart crawl sequence - check if run needed (if yoshi is close)
  01: crawling a little bit on all fours

  jumping on head sequence:
  02: spit egg (head goes down a bit)
  03: head nudge back up
  04: head go back to normal, stay frozen a bit, go back to 01

  jumping on shell sequence:
  05: spit egg (head goes down a bit)
  06: head nudge back up
  07: head go back to normal, stay frozen a bit, go back to 01

  run sequence:
  08: bob head slightly up (from the crawl)
  09: stare forward not moving for a few
  0A: stand up
  0B: walk forward until yoshi close
  0C: hunch forward
  0D: (hit with egg while in the midst of standing up, closes eyes for a bit and skips to 0A afterward)
  0E: run forward until yoshi close
  0F: dives at yoshi
  10: landing on ground, bobbing a bit
  11: more landing/bobbing
  12: more landing/bobbing
  13: more landing/bobbing
  14: blinking after landing
  15: gets up back to a crawl

  turn around on all fours sequence:
  16: body into shell
  17: jump up and turn around

  turn around while standing sequence:
  18: jump up and retract body into shell
  19: rotate slightly
  1A: rotate again, turning fully around
  1B: fall back down and body comes back out, switch to 09

  getting egged sequence:
  1C: first two egg hits (init & jump to 1D immediately)
  1D: angle backward, cry & wobble arms, ready for the next hit
  1E: if not egged again, retract back to standing, switch to 09
  1F: third egg hit (init & jump to 20 immediately)
  20: hop up in the air from the third egg hit
  21: fall back down while leaning backward
  22: lean back to center
  23: wobbling on back helpless
  24: frozen on back

  hopping in shell sequence:
  25: wobbling back and forth after getting hit
  26: one hop toward yoshi, turning around 180 degrees
  27: two hops toward yoshi in the same fashion
  28: pound onto ground, wait a bit, body come out of shell

  ground pounded sequence:
  29: initial hit, squishes & turns yellow
  2A: flashes yellow then stretches back to normal

  beginning cinematic sequence:
  2B: small hookbill walking over
  2C: waits on kamek routine to finish (via a flag)
  2D: init/prep for growing
  2E: init/prep for growing
  2F: small hookbill crouching down ready to grow
  30: turns into real hookbill shell
  31: shell growing (and bobbing back and forth)
  32: body comes out of shell, fight begin prep

  death sequence:
  33: initially dead, turn yellow
  34: flashes yellow and squishes down a bit
  35: squishes down and down into a pancake
  36: shell break, small koopa goes up then down middle
  37: dead, final state, do boss key bullshit etc.

Blastoff Bug

Upon Yoshi's final hit onto Hookbill, there is code that governs exactly how much to move Yoshi's Y coordinate by. The basic formula comes down to this:

 $700058 - $700056 - $700122 + 3

The main two SRAM addresses here ($0058 and $0056) get computed/stored in Hookbill's Super FX code:

 CODE_08A636:         iwt   r0,#1C18     ;
 CODE_08A639:         add   r10          ;
 CODE_08A63A:         to r7              ;
 CODE_08A63B:         ldw   (r0)         ;
 CODE_08A63C:         lms   r0,(004E)    ;
 CODE_08A63F:         to r8              ;
 CODE_08A640:         add   r7           ;
 CODE_08A641:         sms   (0058),r8    ;
 CODE_08A644:         lms   r7,(0122)    ;
 CODE_08A647:         lms   r0,(0002)    ;
 CODE_08A64A:         sms   (0056),r0    ;

This code is necessary to be run each frame on Hookbill's final hit for proper placement of Yoshi. Blastoff occurs when this code is not run, and this happens because of a check:

 CODE_08A61C:         iwt   r0,#1C16     ;
 CODE_08A61F:         add   r10          ;
 CODE_08A620:         to r7              ;
 CODE_08A621:         ldw   (r0)         ;
 CODE_08A622:         lms   r0,(004C)    ;
 CODE_08A625:         to r8              ;
 CODE_08A626:         add   r7           ;
 CODE_08A627:         lms   r7,(0120)    ;
 CODE_08A62A:         lms   r0,(0000)    ;
 CODE_08A62D:         add   r7           ;
 CODE_08A62E:         to r4              ;
 CODE_08A62F:         add   r0           ;
 CODE_08A630:         add   r8           ;
 CODE_08A631:         cmp   r4           ;
 CODE_08A633:         bcs CODE_08A65B    ;

That last bcs can branch PAST the above code, therefore NOT running it and NOT properly placing Yoshi's Y coordinate. Because of this, and because address $700058 is written to elsewhere for completely different purposes, most if not all of the time you will get something like these values (taken from an actual trace):

 $700058: $0001
 $700056: $000F

Because $700058 was not properly computed (because the code was was branched past), it gets this "garbage" value of $0001 which it never would normally get. Because of this, our formula to move Yoshi goes like this:

 $0001 - $000F - $000C + 3

This comes out to $FFE9, or -23! Now we are moving 23 pixels BACKWARDS, or in this case up, each frame. Which of course causes Yoshi to blast off to the moon.

So what causes this branch to go past the necessary code? That code simply checks to make sure Yoshi's X coordinate is within range of his shell. In brief, if Yoshi's X moves off the shell, he blasts off. Normally, this wouldn't happen, but it can if you ground pound him early because that would bypass AI states which zero out his X velocity (the process of him landing after falling, etc.), therefore he can retain his X velocity and keep moving left or right, while Yoshi stays stationary. This causes Yoshi to be outside the X bounds of his shell, which causes the check to branch past the necessary code.

Clone this wiki locally