News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

[SM]Metroid Hatchling PLM

Started by BananaSplit, August 12, 2016, 07:07:28 PM

Previous topic - Next topic

BananaSplit

I'm not asking for anyone to make that for me (although if you want to, be my guest :p), but I'd just like to know how feasible this idea of mine would be.

Basically, I want to create a PLM having the appearance of the hatchling in its glass container, just like the one you see in the Game Over screen. Picking it up would then activate the self destruct sequence.

Thankfully, the self destruct timer part is already covered thanks to the asm file made by FullOfFail, Jathys, Mon732, Scyzer, and PJBoy, which I tinkered a tiny bit to also switch on event 0E (Exploding Zebes). The PLM part is a bit more worrying since I'm basically still a noob at writing asm for SM (got the bases covered, but that's all). How difficult do you think that would be ?

Crashtour99

It really shouldn't be too terribly difficult.  The hard part is going to be animating it.

A typical item PLM has only 2 frames of animation, which isn't going to work for the hatchling container (unless you rewrite part of the PLM routine that loads the gfx into VRAM).
For PLMs like map/energy/missile/save stations, they have more complex animations.  Their gfx however are part of the CRE gfx, like those for block breaking animations, doors opening, etc.  It would be tricky to fit the gfx for the hatchling into the CRE gfx sheet.
There is I believe one method that might work best for a PLM.  Phantoon creates a special locked door PLM in his room, which the gfx for are in his gfx sheet (along with the rest of him).  It should be possible to put the hatchling gfx into the tile sheet and have the PLM use those for its animation.  Off the top of my head though I can't remember exactly how it works for identifying the gfx tile in the tile table.  It would make sense to use the page flags in a normal tilemap, but PLMs don't exactly use the normal tilemaps.

Your other option, which honestly might be easier for something so animated, would be to use an enemy as a faux-PLM.  It'd be probably one of the most simple enemies to create, since it wouldn't move, it'd just sit there and animate until it was touched and then run some code.  Enemies and PLMs are relatively similar in design, so if you can understand how to make a PLM then it shouldn't be too hard to make an extremely simple custom enemy.

BananaSplit

#2
Making a faux-PLM definitely sounds like a better idea ! Thanks.

Well, now to study the asm to make a PLM/Enemy... Any suggestion on where to start ? I've been checking out some disassemblies from Kejardon, but that's gonna take a while to make some sense out of em.

EDIT : Managed to clone enemy EA7F and made it activate the self-destruct sequence on touch although it messes up the music for some reason. Baby steps !

Smiley

#3
I decided to partially create the enemy for you. You should be able to finish it.

org $A0F8C0 ;Enemy F8C0 header
DW $0400,$F700,$0008,$0000 ;tile data size, palette pointer, HP, damage from contact
DW $0008,$0010 ;Width/Height (/2)
DB $B3,$02 ;bank, 'hurt' AI length when hit
DW $0000,$0000 ;sound when hit, special boss fight value
DW InitAI,$0000,$0000 ;pointer to init AI, how many "parts", unknown
DW MainAI ;Main AI
DW $800F,$804C ;Grapple AI, extra AI (Shot2?)
DW $8041,$0000 ;frozen AI, x-ray AI
DW $0000,$0000,$0000 ;death animation, unknown,unknown
DW $0000,$0000,$0000,$0000 ;PB reaction, 3 unknowns
DW TouchAI,$804C ;touch AI, shot AI
DW $0000 ;unknown
DL $B88000 ;pointer to tiles
DB $05 ;layer
DW $0000 ;item drops
DW $0000,$0000 ;vulnerable pointer, pointer to enemy name in bank $B4

org $B3E000 ;Point this to free space in bank $B3

InitAI: ;All this does is set the graphic
LDX $0E54 ;Enemy index

LDA #MetroidAnim : STA $0F92,x ;\
LDA #$0001 : STA $0F94,x ;/Sets graphic AI

RTL


MainAI: ;This doesn't actually need to do anything
RTL


TouchAI: ;Code run when the enemy touches Samus. This is where you set the escape etc.
RTL



MetroidAnim: ;How long a tilemap is displayed and the pointer to tilemap
DW $0004, MetroidFrame1
DW LoopAnimation, MetroidAnim ;Instruction that tells the animation to jump somewhere else. In this case it's used to loop the animation


LoopAnimation: ;Can't touch this
LDA $0000,y : TAY : RTL

;Tilemaps below. Refer to Scyzer's document http://old.metroidconstruction.com/docs/SadFishEnemyTilemapsRundown.rtf

MetroidFrame1:
DW $0001
DB $00,$00,$00,$00,$00


E: Didn't see you almost managed to get it done yourself. Well, this is still a valid base for custom enemies if someone wants to try!

As for the music messing up, I assume you get a terrible sound glitch, like it plays the same 0.1 seconds over and over for a while? If that's what's happening, you need to mute the music before loading the next song. (LDA #$0000 : JSL $808FC1 will mute it.)

BananaSplit

Thank you, that will certainly help me a lot. Currently trying to make sense of GFX part, but it seems like I have to hunt for the hatchling graphics now.

For the music glitch, the original code does stop the music before starting the self destruct theme. Actually, there's no problem when executing it with a Setup ASM pointer or with an Air Fool block for example. But triggering the code from touching an enemy glitches up the music. It plays the first notes like 2 times and then it goes silent.


Smiley

Quote from: BananaSplit on August 13, 2016, 01:40:08 PM
It plays the first notes like 2 times and then it goes silent.

Sounds like the code gets triggered multiple times. Does the touch AI delete the enemy from the room, set it untouchable or do anything else to prevent the code from being run multiple times?

BananaSplit

I was thinking that was the reason, but I don't know yet what code to use to "kill" the enemy, as dumb as it sounds.

Smiley

LDA $0F86,x
ORA #$0200
STA $0F86,x

That sets a bit which will delete the enemy. Should do the trick.

BananaSplit

#8
Added your code with a LDX $0E54 just before it and it worked a like a charm. The enemy now dies and the music isn't screwed up anymore. That's one more problem solved. Thanks !

Now, back to finding those GFX...

Edit : Another question, is it possible to use a different palette for different parts of the animation ? I mean, there's the option to specify a palette in 5th byte of a tilemap, and it does seem to change the palette, but I'm really not understanding how it works. I just want to have the hatchling "flash" every so often like he does on the title screen when it cries.

Quote58

Quote from: BananaSplit on August 13, 2016, 02:39:03 PM
Edit : Another question, is it possible to use a different palette for different parts of the animation ? I mean, there's the option to specify a palette in 5th byte of a tilemap, and it does seem to change the palette, but I'm really not understanding how it works. I just want to have the hatchling "flash" every so often like he does on the title screen when it cries.

Depending on stuff, it's possible to do it that way but there's a much better way instead.
So you know that running ai that doesn't do anything for this enemy because all your enemy does is animate some tiles? Well all you have to do is add a routine into the running ai which cycles through a palette glow every X frames to make a nice looking flash. There's a couple ways to do it, either with a hard coded set of palette lines or with systematically adjusting the colour values. The former will produce better looking colours (unless you want to code certain algorithms into the routine...), but requires that you write up the palettes into the asm file. The latter is harder if you don't know what you're doing or easier if you do. If you don't, I suggest taking a look at black falcon's Flex Glow asm file.

Side note, I had literally been writing a response to your initial question and left the tab open but forgot to finish it. I was going to give you some sample enemy code but smiley did you one better! If you have any enemy related questions feel free to shoot me a PM.

BananaSplit

#10
That does sound like an good idea, I'll check out that Flex Glow file although it looks quite complicated, thanks !

EDIT; after fiddling around, I managed to make it work using the first option ! Now to synchronize the palette changes with the animation...

I have one last question. The icing on the cake would be to have the sounds the hatchling makes aswell. I'm even more clueless to how to do that though. Any lead for me ?

Crashtour99

http://jathys.zophar.net/supermetroid/kejardon/RandomRoutines.txt
About halfway down this page you'll see some information on sound libraries. 

Library 2
90A3 ($0654 = 0F)
90AD ($0654 = 09)
90B7 ($0654 = 03)
90C1 ($0654 = 01)
90CB ($0654 = 06)
   2C = Either a Draygon scream or a Metroid/Mother Brain scream
   50 = Metroid screech (only works with Tourian/Maridia BGMs)
   52 = Alternate metroid screech?
   58 = Another metroid screamm
   5A = Metroid feeding noise?
   72 = Shitroid feeling sorry noise
   78 = Shitroid feeding off of Samus in Tourian and Maridia BGM/Shitroid feeding off of Mother Brain during with battle's BGM.
   7D = Sad Metroid :(

To play a sound, you just load an index into A (like LDA #$007D for the sad metroid sound), and then JSL to one of those sound routines in $90 (such as JSL $9090A3).  Every time the JSL runs it will load one sound into the queue, which will usually start playing on the next frame.  I only say usually because it is possible for the queue to get loaded up, and if it gets overloaded then the sound won't play, but that's a pretty rare occurrence (and should really only happen if you have the JSL run several times in a row, kinda like with the sound glitch for switching music that you found out about earlier).  Each of those JSLs have a different number of sound indexes they can store into the sound fx queue, so if one isn't working (like 90C1 which can only queue one sound at a time) then just try a different one.  Each library has it's own JSLs and sound indexes that you cannot mix between, so library 2 sounds will only play using library 2 JSLs.

The main thing to remember with sounds, is that they can depend heavily on which song is loaded.  You can see from the edited list above that some of the metroid sounds only seem to work with Tourian or Maridia background music or boss music.  You may have to experiment a little to see which ones work and which ones don't and with what music.

BananaSplit

#12
Thank you so much ! The faux-PLM is pretty much complete now, I wish I could find the actual hatchling noises and the code isn't pretty to see, but eh, it looks the same as the hatchling and it works.

I'm thinking of improving it by adding a message box when you pick it up aswell. I saw a whole bunch of ASM files touching on that subject, so I may find out how to do that.

EDIT : Nevermind for the hatchling noise, I actually found them by searching around in library 3. They correspond to numbers 23, 24, 26 and 27 if anyone wonders.

EDIT2: Managed to add a textbox thanks to Kej and JAM's Message Box V4. Here's a video of the final result :

https://youtu.be/UvtDag-sKdY

Thank you all again for your help !

Scyzer

You could have messaged me lol. I made a metroid hatchling enemy for my HISHE hack.
It is possible to make with a PLM, but an enemy would have far more variables for animations, etc, and palette changes, so you made a good choice.

[spoiler=If you want to have a look at my code for a hatchling, here:]

Org $A0FF80
   DW $0400,#MetroidPalette,$7FFF,$0000,$0000,$0000
   DB $A3,$00,$00,$00,$00,$00
   DW #MetroidInit,$0001,$0000,#MetroidRun,$800A,$804C,$8041,$0000,$0000
   DW $0000,$0000,$0000,$0000,$0000,$0000,#MetroidTouch,#MetroidShot,$0000
   DL $B0EE00
   DB $00
   DW $0000,$E000,$0000
   
Org $A3F311
   MetroidPalette:
      DW $FFFF,$3260,$31C0,$3120
      DW $28BE,$2096,$188C,$63FE
      DW $5358,$4292,$7E20,$6560
      DW $34E0,$2480,$1000,$0000
   MetroidGlowPalette:
      DW $1364,$12C4,$1224
   MetroidTileMap:
      DW MetroidSpeed, MetroidMapA
      DW MetroidSpeed, MetroidMapB
      DW MetroidSpeed, MetroidMapA
      DW MetroidSpeed, MetroidMapC
      DW $80ED, MetroidTileMap
      MetroidMapA: DW $0002
         DB $F8,$81,$F0,$00,$31
         DB $F8,$81,$00,$02,$31
      MetroidMapB: DW $0002
         DB $F8,$81,$F0,$04,$31
         DB $F8,$81,$00,$06,$31
      MetroidMapC: DW $0002
         DB $F8,$81,$F0,$08,$31
         DB $F8,$81,$00,$0A,$31
      MetroidSpeed: PHY : LDX $0E54
         LDA $0FA8,X : STA $0F94,X
         PLY : DEY : DEY : PLA : PEA $C297 : RTL

   MetroidInit: LDX $0E54
      LDA #$0002 : JSL $8081DC : BCC +
         STZ $0F78,X : RTL
   +   LDA #$000C : STA $0FA8,X
      LDA #$0020 : STA $0FAA,X
      LDA #MetroidTileMap : STA $0F92,X
      RTL
   MetroidRun: LDX $0E54
      DEC $0FAA,X : BPL ++
         LDA $05E5 : AND #$007F : CLC :  ADC #$0070 : STA $0FAA,X
         LDA #$0001 : STA $0F94,X
         LDA #$0006 : STA $0FA8,X
         LDA $0F97,X : AND #$000E : ASL #4 : TAX : LDY #$0000
         -   LDA MetroidGlowPalette,Y : STA $7EC102,X
            INX #2 : INY #2 : CPY #$0005 : BMI -
         LDA $05E5 : AND #$0002 : TAX : LDA MetroidSoundTable,X : JSL $8090CB
         LDX $0E54
         LDA #$0030 : STA $0FAC,X
   ++   LDA $0FAC,X : BEQ ++ : DEC $0FAC,X : BNE ++
         LDA #$0001 : STA $0F94,X
         LDA #$000C : STA $0FA8,X
         LDA $0F97,X : AND #$000E : ASL #4 : TAX : LDY #$0000
         -   LDA MetroidPalette,Y : STA $7EC100,X
            INX #2 : INY #2 : CPY #$0020 : BMI -
   ++   RTL
   MetroidSoundTable:
      DW $0052,$0058
   MetroidTouch:
      LDA #$0002 : JSL $808FC1
      LDA #$0003 : JSL $858080
      LDA #$0007 : JSL $808FC1
      LDA #$0002 : JSL $8081A6
      LDX $0E54 : STZ $0F78,X
   MetroidShot:
      RTL

[/spoiler]

BananaSplit

#14
Oh, so I'm not the first one with that idea...

Oh well, I'm happy I managed to do this by myself, thanks for the code, it could help me.

PS : That HISHE hack is hilarious.