I'm trying to edit this enemy: https://www.smwcentral.net/?p=section&a=details&id=20385 to have 3 HP instead of 1 and turn it into a full boss so that the level ends after it's being defeated. I'm thinking of making it behave like this boss does when it's hit: https://www.smwcentral.net/?p=section&a=details&id=32045. How would I change the ASM code of the Elite Ninji to make it work like that?
Turning a Regular Enemy into a Boss
A good place to start is by opening up the sprite's CFG/JSON file with PIXI's included CFG editor and enabling the setting listed under $190F for "Takes 5 fireballs to kill". When set, the game will automatically count the number of fireballs the sprite has been hit by in $1528, and will kill the sprite when that reaches 5. You can then either add some custom handling to handle the boss's death when that hits 3, or you can just reuse the original Chuck death by initializing the counter to 2 in the sprite's INIT code:
Code
print "MAIN ",pc PHB PHK PLB JSR Elitemain PLB RTL ; add this RTL in so that the MAIN doesn't flow into the INIT print "INIT ",pc LDA #$02 ; initialize damage counter STA !1528,x RTL
Now, this doesn't handle an invulnerability period between hitting the boss, so the player could potentially just spam fireballs to kill the boss almost instantly. If you want to add an invuln period, you'll need some sort of detection method for when the boss is actually hit. An easy way of doing this is to maintain a copy of the boss's HP in another miscellaneous RAM address (such as $151C), and then you'll know the boss just got hit if the current HP no longer matches the copy. Like this:
Code
LDA !1528,x CMP !151C,x BEQ .notHit STA !1528,x ; code that you want to run when the boss was hit .notHit:
(if using the INIT code from before, be sure to add an update there to $151C as well, or else the sprite will register a "hit" immediately upon spawning)
For then preventing the sprite from being hit for a bit, you can manage the sprite's invulnerability to fireballs via bit 1 of $167A. Just use one of the miscellaneous sprite timers (e.g. $1558) to manage that, which gives you this:
Code
LDA !1528,x CMP !151C,x BEQ .notHit STA !1528,x LDA #$30 ; how many frames the sprite should be invulnerable for (can make this a define) STA !1558,x LDA !167A,x ; make invulnerable to fireballs ORA #%00000010 STA !167A,x .notHit: LDA !1558,x DEC BNE .notBecomingVulnerable LDA !167A,x ; make vulnerable to fireballs AND #%11111101 STA !167A,x .notBecomingVulnerable:
You can then make the boss flash by modifying its graphics routine to return early based on the $1558 timer. An easy way to do flashing is like this:
Code
GFX: LDA !1558,x AND #$02 ; rate the sprite should flash at (power of 2) BEQ .draw RTS .draw:
Professional frame-by-frame time wizard. YouTube - Bluesky - SMW Glitch List - SMW Randomizer
Thanks for the help, but I'm confused on where to put the second and third blocks of code, I have no experience with ASM.
just replaces the
GFX:
label already in the sprite.is a little more open on where you put it, as long as it's part of the sprite's MAIN routine. A good option is right before the
%SubOffScreen()
line in the sprite. Also, note that I modified it a bit to fix an issue for this particular sprite, so use the above version instead of the one from the previous post.Also, testing it, it looks like the original SFX for the chuck getting hit by the fireball is a bit of a dull thud. If you want to add a different sound effect, add these two lines right after the
STA !1558,x
line in the above code:Code
LDA #$xx STA $1DF9|!addr
The address on the second line should be either $1DF9, $1DFA, or $1DFC, and the xx on the first line should be the sound effect ID you want to play. You can find a list of SMW's sound effects here. For instance, to use the standard "hurt" sound effect most of SMW's bosses use, use ID
#$28
with $1DFC
.Professional frame-by-frame time wizard. YouTube - Bluesky - SMW Glitch List - SMW Randomizer