don't click here

Basic Questions & Answers thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

  1. Screenshot (8).png
  2. Wafer


    Find me on Twitter instead Member
    I know this isn't a technical question, but I thought I'd put it here because it kinda follows on from my posts above.

    Whilst trying to solve the cutscene issue, I ended up doing a lot of investigation using r57shell's Gens mod, I even found the place where Sonic was being told to look up before I decided there would probably be a faster solution.

    My question then, is: Would it help us as a community to have a guide on using a debugger, with an example being "let's track down and replace Sonic's behaviour in a cutscene"? I've got some time on my hands for the next few months(!) so I'd be happy to produce a thorough guide based on the tools and methods I use and the resources available, and if it was on the wiki other people could adapt the guide to support other debuggers.
    Last edited: Feb 9, 2020
  3. E-122-Psi


    Cutscenes do tend to be a recurrent issue when reprogramming movesets, so that could be helpful I suppose.
  4. Dulappy


    koronesuki Member
    Hey, so I have a bit of a technical question, how easy would it be to expand Sonic’s mappings in Sonic 1 beyond $FF (practically $FC)? Would there have to be big engine changes, or will some small changes do the trick?
  5. Inferno


    Sonic 1 Definitive
    The basics are that you'd have to expand mapping_frame (or $1A) from a byte to a word (For $FFFF frames) by finding a conflict-free spot, then you'd have to change every single mention of that SST in the game code to be a word, and that'd make every object capable of using $FFFF frames. However, you'd also have to modify BuildSprites: to properly use the word. In addition, you'd also have to move the animation flags to another value.

    Or you could just take the S3 route and load different mappings and DPLCs once Sonic reaches a certain animation, therefore kind of expanding the number of frames Sonic has.
  6. Fred


    Taking a break Oldbie
    Sonic 3 Unlocked
    This is completely misleading; S3 is still very much bound to the $FC frame limit. The DPLC hack is only there so Sonic and Tails can use more than one "page" of art -- Sonic has a lot of unique art due to Super Sonic, whereas Tails is mostly streamed from the S3 cart except for some extra anims added in S&K, which are on a separate "page" on the S&K cart.
    • Informative Informative x 1
    • List
  7. Inferno


    Sonic 1 Definitive
    Sorry for that, then. I could of worded it better. Thanks for correcting me.

    I guess what I was getting at was more "you can also just use checks to swap out the mappings and DPLCs loaded once you reach a certain threshold".
  8. Fred


    Taking a break Oldbie
    Sonic 3 Unlocked
    Yes this a good point, although watch out if doing this with Sonic, as the game already changes his mappings pointer on the fly when he turns/loses Super.
  9. So, I managed to implement some animated tiles for one of my zones (read: by copying the MTZ routine and cutting out unneeded bits, as all I wanted was the rotating mesh), and... I don't quite know how, but it somehow messed up the Options menu's own animated tile routine. Note that no zones are affected by this.
    The only way I think this could have happened myself is because of where I placed said animated tiles.
    Note that I am using MainMemory's Sonic 2 Sound Driver Plus Disassembly - although this shouldn't really have much effect on what is going on, it might still be part of it.

    The relevant definitions for s2.constants.asm are below:
    Code (Text):
    1. ; STZ
    2. ArtTile_ArtUnc_STZCylinder                = $00CD
    3. ArtTile_ArtUnc_STZFrontClouds            = $00DD
    4. ArtTile_ArtUnc_STZBackClouds            = $00E5
    And the code it matches with from s2.asm (note that it matches with MTZ's code) is below:
    Code (Text):
    1. ;This section of code is placed between HPZ and OOZ's animation scripts.
    3. Animated_STZ:    zoneanimstart
    4.     ; Spinning metal cylinder
    5.     zoneanimdecl 0, ArtUnc_STZCylinder, ArtTile_ArtUnc_STZCylinder, 8,$10
    6.     dc.b   0
    7.     dc.b $10
    8.     dc.b $20
    9.     dc.b $30
    10.     dc.b $40
    11.     dc.b $50
    12.     dc.b $60
    13.     dc.b $70
    15.     zoneanimend
    17. ;This section is between HPZ's and OOZ Animated Pattern Mappings.
    18. APM_STZ:    begin_animpat
    19.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$E,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$E,0,0,3,0)
    20.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$F,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$F,0,0,3,0)
    22.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$C,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$C,0,0,3,0)
    23.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$D,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$D,0,0,3,0)
    25.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$A,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$A,0,0,3,0)
    26.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$B,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$B,0,0,3,0)
    28.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$8,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$8,0,0,3,0)
    29.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$9,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$9,0,0,3,0)
    31.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$6,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$6,0,0,3,0)
    32.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$7,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$7,0,0,3,0)
    34.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$4,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$4,0,0,3,0)
    35.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$5,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$5,0,0,3,0)
    37.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$2,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$2,0,0,3,0)
    38.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$3,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$3,0,0,3,0)
    40.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$0,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$0,0,0,3,0)
    41.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$1,0,0,3,0),make_block_tile(ArtTile_ArtUnc_STZCylinder+$1,0,0,3,0)
    43.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$E,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$E,0,0,3,1)
    44.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$F,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$F,0,0,3,1)
    46.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$C,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$C,0,0,3,1)
    47.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$D,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$D,0,0,3,1)
    49.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$A,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$A,0,0,3,1)
    50.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$B,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$B,0,0,3,1)
    52.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$8,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$8,0,0,3,1)
    53.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$9,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$9,0,0,3,1)
    55.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$6,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$6,0,0,3,1)
    56.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$7,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$7,0,0,3,1)
    58.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$4,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$4,0,0,3,1)
    59.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$5,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$5,0,0,3,1)
    61.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$2,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$2,0,0,3,1)
    62.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$3,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$3,0,0,3,1)
    64.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$0,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$0,0,0,3,1)
    65.     dc.w make_block_tile(ArtTile_ArtUnc_STZCylinder+$1,0,0,3,1),make_block_tile(ArtTile_ArtUnc_STZCylinder+$1,0,0,3,1)
    66. APM_STZ_End:

    EDIT: Noticed that Sonic's 3D rotation sprites bugged out as well... Man, Sonic 2 can be sensitive. Seems unrelated to the above, though - as nulling out the animation scripts fixes the options menu...
    Last edited: Feb 14, 2020
  10. MainMemory


    Kate the Wolf Tech Member
    It sounds like your art is crossing a 128kb boundary in the ROM, which messes up the DMA transfers. This explains both of your broken art problems. There's a post about it here.
  11. E-122-Psi


    I've been trying to get this object connected to Sonic to load upside down in Sonic 2, but it doesn't seem to be working. Here's the coding:

    Translated in Sonic 1 in works just fine, but for whatever reason it won't flip vertically in Sonic 2. #2,status(a0) is vertical flip, right?

    Also is there any direct way to edit the ending sprites in Sonic 2? They don't seem to translate right in SonMapEd.
    Last edited: Feb 23, 2020
  12. WhoWhatWhenWhale


    Try checking if something is resetting the object's status later in the frame. It might be that its getting set upside down and then IMMEDIATELY turning right-side up.

    Also, does anyone know how exactly Sonic_Floor.asm and Sonic_Dontrunonwalls interact with each-other? I'm trying to make it so that sonic can attach to any surface no matter the angle, but I'm having some trouble deciphering these parts. commenting out sonic_dontrunonwalls gets me part-way there, but also causes some wacky collision behaviour with ceilings and such. I'm using the sonic 1 github disassembly btw.
  13. E-122-Psi


    I've been checking for status resets I may have missed but nothing yet (though knowing me it will likely turn out to be something obvious and stupid).

    I have come to another problem though, I've used the DPLC tutorial on the wiki so I can edit the special stage sprites, however I still have problems making them appear properly. It seems it won't recognise when I add any new sprite pieces. Is there something restricting this I've overlooked?


    Also I'm using an asymmetrical character, while I think I've found the animation data to make new frames (though obviously can't yet due to the above problem), I don't know what is causing the four frame run cycle to flip on it's second turn. Any idea what part I'm supposed to target here?

    EDIT: Actually scratch that. I think I've found the problem, the new pieces aren't given the right priority so load behind the special stage tiles (as you can see the new hud has the same problem). That can be fixed, though I still need to figure out how to get rid of the flip command for the normal run animation.
    Last edited: Mar 7, 2020
  14. WhoWhatWhenWhale


    Alright so it actually turns out that the github disassembly of sonic 1's label names suck. Sonic_Dontrunonwalls doesnt actually prevent sonic from running on walls and ACTUALLY just checks sonic's distance from the ceiling. it takes his x_pos, y_pos and angle, and then returns the y distance from the ceiling in register d1 and the sonic-angle of the ceiling (NOT the tile angle) in register d3. It works basically the opposite way of Sonic_Hitfloor. Shoutouts to the Shadow05 disassembly for its label names not sucking major dong.

    Anyway, new question, does anyone know how to get the collision type of a block that sonic is close to? (I.E. whether it is top-collision, left/right/bottom-collision, all-collision, or no collision.) There's a really weird bug where sonic is only able to properly run along walls if they have all collision. If they have left/right/bottom collision, he gets put 9 pixels inside of the wall and sorta spazzes out before falling down.
  15. MarkeyJester


    Nothing's Impossible Resident Jester
    The call to "FindFloor"/"FindWall" (not sure what it would be called in the GIT version), requires the following parameters:
    • d2 = Y position to search.
    • d3 = X position to search.
    • d5 = Collision status to check (Should be D for top solid check, E for left/right/bottom check. This means both top and left/right/bottom checking cannot be done within one call, and may be related to the issue you describe).
    • d6 = Flip/Mirror compensation (if you are checking for collision up-side down (flipped) then +$1000, if you are checking for collision facing the other way (mirrored) then +$800, these are the block flip/mirror bits B and C which will be reversed by d6 via an XOR).
    • a3 = Y shift for "FindFloor", X shift for "FindWall" (+$10 to check next block down/right, -$10 to check next block up/left).
    The subroutines which check for floor/wall/ceiling collision will setup these registers before calling. Usually they will take Sonic's X and Y position, and add/subtract his width/height from them to get the corners of the hitbox, they usually check the corners of the side meant to be collided. For example, touching the floor it'll get the position of the bottom left and bottom right, and perform two calls, one from each corner.

    The call to "FindFloor" will call further subroutines which take the X and Y position, and calculate the exact block ID by referencing through the layout and through the chunks. The address of the block ID in the chunk itself is stored inside a1. The subroutine will then load the word from a1 to d4. It'll check the block's collision status using d5's bit setting, if the block does not have the status set which you requested, it'll then add a3's shift to either d2 or d3 (depending on "FindFloor"/"FindWall") temporarily (it'll revert afterwards) and will check the next block's status. If the block ID is 000, then it'll ignore the block the same as if the collision status did not match your request.

    If any of the blocks collision status match your request, it will then reference the collision array, and perform the necessary flip/mirror on the collision based on the block's flip/mirror status, and your compensation flip/mirror status you set in d6, and will then work out and return the distance away from the "surface" of the collision inside d1. This can be positive or negative, negative represents you are in-side the collision block, thus the distance from the surface is negative (this is regardless of whether or not you are checking the floor or ceiling, negative is always inside the block).

    Upon return, d1 will contain the distance from the surface, and d4/(a1) will contain the last block ID that was checked. You may check bits D and E for top or left/right/bottom collision.
  16. Vanishing Vision

    Vanishing Vision

    Apologies if this comes across as uninformed, I have zero knowledge of hacking/programming but have been wondering about this for some time now.

    What would be necessary to change the values of the end of act time bonuses in the Genesis games? As in, say, change the 10k for under a minute into 40k? I've been trying to think of ways classic Sonic could work better as a score-focused game, and I've decided that the time bonus values are the key problem. Are there any editors or tools that might help change these numbers? Alternately, what would be necessary to modify the time limit itself, like reduce it down to five or three minutes instead of ten?
  17. Wafer


    Find me on Twitter instead Member
    @Vanishing Vision If you knew where you were looking, the only thing you'd need is a hex editor, but it seems unlikely that you know where you're looking (I wouldn't).

    If you check out the disassemblies in the Sonic Retro Github, I suspect what you need is in the largest .asm file in the root directory. It's a text file, but quite large, so open it in a decent text editor (eg Notepad++) and search for something like "time bonus" or some variation on that. You'll probably find the score values somewhere near whatever hits you get. I'd guess that the score is handled as a multiple of 10, so the values you'd be looking for would be eg. 1000 instead of 10000 for under a minute, so bear that in mind. If you're really unlucky, it's stored as a hex (hexadecimal) value, so you might want to use some website or the Windows calculator to convert to/from hex to know what you're looking for and what to change it to. Once you've made your changes and saved, run build.bat to produce a .bin file that you can run in an emulator.

    I'm not at a computer right now so I can't point you in a more specific direction, just a kinda top-down description of where I'd start with something like this. Let us know if you have problems finding the values to change, and I'll have a look for the specific locations.
    Last edited: Mar 29, 2020
  18. MarkeyJester


    Nothing's Impossible Resident Jester
    I'll leave the source explanation to Wafer for when he gains access to his computer.

    For the ROM itself, when opening with a hexadecimal editor, you can go to offset 00ECF0 on a REV00 ROM:
    Code (Text):
    1. 1388 1388 03E8 01F4 0190 0190 012C 012C
    2. 00C8 00C8 00C8 00C8 0064 0064 0064 0064
    3. 0032 0032 0032 0032 0000
    Each word (two bytes) represents together the score you'll obtain for every 15 in-game seconds. The first word is 0 - 14 seconds, the next word is 15 - 29 seconds, the next is 30 - 44 seconds, etc, etc, up to 5 minutes, 5 minutes and beyond will always yield the last word as the score (which is 0000).

    These values are in hexadecimal obviously, in decimal the scores will look like this:
    Code (Text):
    1. 5000 5000 1000  500  400  400  300  300
    2.  200  200  200  200  100  100  100  100
    3.   50   50   50   50    0
    The score itself is actually a division of 10 less than what you see on the screen, the extra 0 on the end is for visual purposes only. So if you want the score for 30 - 44 seconds to be 40k, you will need to change the 1000 to a 4000 (in hex, the 03E8 to a 0FA0):
    Code (Text):
    1. 1388 1388 0FA0 01F4 0190 0190 012C 012C
    2. 00C8 00C8 00C8 00C8 0064 0064 0064 0064
    3. 0032 0032 0032 0032 0000
    However, you did say "under a minute" so I assume you don't know that the scores are in increments of 15 seconds, it was probably the fact that 0 - 14 and 15 - 29 have the same score value, in any case, you may want to reassess the entire score board...
  19. Wafer


    Find me on Twitter instead Member
    Aaand here is the source explanation.

    (This was for the most part a lot easier than I expected *tips hat to all the brave hackers who labelled all this stuff*)

    You'll need the disassemblies to get started, so go to and go to s1disasm, s2disasm and skdisasm. In each one, click "Clone or Download" and then "Download as ZIP". I'd guess you know how to open a .zip file.

    Sonic 1

    First I searched in sonic.asm. No real joy finding the table, but I was half-expecting this to be the trickiest because of the way the disassembly makes more use of separate files.

    Notepad++ has a handy feature that I overuse called "Folder as Workspace", you can enable it under the "View" menu. Drag the folder from the Github repo into the new space that opened up on the left, then right-click on the folder and select "Find in Files" to search for a string in every file.

    tldr: The file to look in is _incObj/0D Signpost.asm and the label you need is called TimeBonuses. Each score is two bytes, so the maximum value you can enter is 65535, but I have no idea whether the engine itself will support that much. Once you've made your changes, build your ROM with build.bat. *hacker voice* you're in.

    Sonic 2

    This is more my thing: ONE HUGE HONKING .ASM containing 90% of the game code. So we open s2.asm and do a ctrl-f for "timebonus" and sure enough, there's a label again called TimeBonuses. Have at it. Build the ROM the same way as with Sonic 1.

    Sonic 3/3&K/S&K

    Because of historical reasons (I guess), the Sonic 3/3&K/S&K disassembly is called skdisasm. Things get a bit weird here, because the disassembly can produce three different ROMs (one for each separate game, and one for S3&K).

    But actually, it doesn't change what we do that much. As with the Sonic 1 disassembly, we load the folder as a workspace, and do "Find in Files". This time we're looking TimeBonus (singular), because consistency is overrated.

    But wait, there's... TWO labels with that name? Yep, that's right, there are two files containing the same label, one used for building S3&K and one for building vanilla S3.

    (What about S&K? I'm guessing it's folded into the S3&K code)

    And that's not all that's weird, because some of these numbers have letters! Yep, we're looking at hex numbers here, that's why there are also dollar signs.

    But it's no real biggie, because if we fire up the Windows 10 calculator, hit the burger button and select "Programmer", then click "HEX", we can enter those numbers, and then click "DEC" to convert them to friendly base-10. (Don't have the Windows 10? I believe this function has been in Windows for some time, BUT you can just Google for "convert hex" and use the first result to do this bit).

    Now you know what each of those wacky numbers are, you know which ones to change. I bet you're thinking you'll have to convert them back to hex, but actually if you just remove the $ from the beginning of the number you want to change, you can enter regular decimal numbers. To introduce some consistency into this madness, you may as well make both TimeBonus labels the same, so once you've edited one copy it over the other.

    Lastly, building from skdisasm is also weird, because we need to tell it which specific ROM to build. So, instead go into the Build Scripts folder and run the appropriate buildX.bat (or heck, just run all three buildX.bats, this isn't the 90s so you shouldn't need to request time on a Cray for this).

    Hope that helps!
  20. E-122-Psi


    Okay, I've been trying to get an object attached to Sonic to load from an animation routine like so:

    Code (Text):
    1. Cheese_HomeIn:
    2.         bsr.w    HomingCheese
    3.         addq.b    #2,$26(a0)    ; Increment wobble
    4.         move.w    $10(a0),d0    ; Move X velocity into d0
    5.         tst.b    $2A(a0)    ; Is Cheese going after something?
    6.         bne.s    @Test_Direction    ; If not, branch
    7.         move.w    8(a2),d0    ; Move Cream's X position into d0
    8.         sub.w    8(a0),d0    ; Subtract Cheese's X position from d0
    10. @Test_Direction:
    11.         tst.w    d0    ; Check if d0 is 0
    12.         beq.s    @Animate    ; If so, branch
    13.         bpl.s    @Face_Right    ; If positive (Going to the right), branch
    14.         bset    #0,1(a0)    ; Flip Cheese to the left
    15.         bra.s    @Animate    ; Branch
    16. ; ---------------------------------------------------------------------------
    17. @Face_Right:
    18.         bclr    #0,1(a0)    ; Flip Cheese to the right
    20. @Animate:
    21.         lea    ($FFFFD000).w,a2
    22.         cmpi.b  #$1A,$1C(a2)    ; is Cream hurt?
    23.         beq.s     @Animate_Frame_Hurt            ; if not, branch
    24.         move.b    #0,$1C(a0)
    25.         jmp    @Display
    26. @Animate_Frame_Hurt:
    27.         move.b    #1,$1C(a0)
    29. @Display:
    30.         lea    (Ani_obj10).l,a1
    31.         jsr    AnimateSprite
    32.         jmp    (DisplaySprite).l    ; Display
    33. ; ---------------------------------------------------------------------------
    35. Obj10_LeaveScreen:
    36.         bsr.w    Cheese_ClearTarget    ; Clear target
    37.         move.w    8(a0),d2    ; Save X position into d2
    38.         move.w    $C(a0),d3    ; Save Y position into d3
    39.         subi.w    #$C0,d2    ; Go 192 pixels left
    40.         subi.w    #$C0,d3    ; Go 192 pixels up
    41.         tst.b    1(a0)    ; Test if off screen
    42.         bmi.w    Cheese_HomeIn    ; If not, branch ;edit
    43.         move.b    #6,$24(a0)    ; Go to Obj10_Idling

    The issue here is that turned right, it works just fine, but turned left, the objects jitters both directions rapidly, like something is telling it to look both ways. I get something is conflicting the code here, but I can't figure what and how to bypass it, let alone why it only happens when I assign an animation routine (a timer automating the frames for example doesn't have this problem).

    While we're at it, does anyone know if the Final Zone boss uses a specific flag to recognise being hit compared to the other bosses?
    Last edited: Mar 31, 2020