Difference between revisions of "Fix Blue Knuckles"
From Sonic Retro
(Added fixes for End of Level Signpost graphics, Slot Bonus Stage, and Super/Hyper palette. These fixes make Blue Knuckles a 99% bug-free character, the last thing to add is a better explanation on how to fix him on the save screen too.) |
(Improved asm tutorial, comments and indentation. Used mnemonic BHS and BLO instead of BCC and BCS (source: MarkeyJester’s Motorola 68000 Beginner’s Tutorial). General cleanup) |
||
Line 18: | Line 18: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #3,(Player_mode).w | |
− | + | bne.s [label] | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 28: | Line 28: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #3,(Player_mode).w | |
− | + | beq.s [label] | |
</syntaxhighlight> | </syntaxhighlight> | ||
− | If player_mode is #3 (Red Knuckles), the game will jump to a label for special processing for Knuckles events | + | If player_mode is #3 (Red Knuckles), the game will jump to a label for special processing for Knuckles events. If player_mode is NOT #3 (Red Knuckles), then the game will execute code for Sonic &/or Tails. Since Blue Knuckles (ID #4) is NOT ID #3, the game will execute Sonic &/or Tails code for Blue Knuckles, which is not what we want. We want Blue Knuckles to execute code for Red Knuckles. This guide will also fix statements of this format. |
Line 76: | Line 76: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
addq.w #1,d1 | addq.w #1,d1 | ||
− | cmpi.w #4,d1 | + | cmpi.w #4,d1 ; Blue Knuckles Fix: Now character #4 is the highest selectable |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 96: | Line 96: | ||
Change this: | Change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | addq.w #3,d0 | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 102: | Line 102: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | addq.w #4,d0 ; Blue Knuckles Fix: No Save Slot - Now character #4 is the highest selectable | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 129: | Line 129: | ||
Change this: | Change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #3,d0 | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 135: | Line 135: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #4,d0 ; Blue Knuckles Fix: Save Slot Update Character - Now character #4 is the highest selectable | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 155: | Line 155: | ||
Change this: | Change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | moveq #3,d0 | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 161: | Line 161: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | moveq #4,d0 ; Blue Knuckles Fix: Save Slot Update Character - Reset character to #4 if below #0 (negative) | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 171: | Line 171: | ||
Next, we will fix the character select for the Level Select screen. This character selection is done by pressing C on the level select screen. Pressing C will increment the player_mode. As before, we will change the max character from #3 (Red Knuckles) to #4 (Blue Knuckles). | Next, we will fix the character select for the Level Select screen. This character selection is done by pressing C on the level select screen. Pressing C will increment the player_mode. As before, we will change the max character from #3 (Red Knuckles) to #4 (Blue Knuckles). | ||
− | There is only on step to fix it here. Goto loc_7F46 . | + | There is only on step to fix it here. Goto loc_7F46. |
It should look like this: | It should look like this: | ||
Line 187: | Line 187: | ||
Change this: | Change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #4,(Player_option).w | |
+ | bcs.s locret_7F60 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 193: | Line 194: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | cmpi.w #5,(Player_option).w ; Blue Knuckles Fix: 04 is the highest selectable player_option | |
+ | blo.s locret_7F60 ; Used mnemonic "blo" instead of "bcs" - if player_option is lower than 5 don't reset to 0 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | ''Note: you can make Blue Knuckles available only in the Level Select Screen.'' | ||
==Fixing bugs== | ==Fixing bugs== | ||
− | Now that Blue Knuckles is | + | Now that Blue Knuckles is available for selection by normal means, we still have to fix all of his level events and other bugs. To do so, we will have to fix the player_mode comparison statements that were shown before. Search for every instance of “cmpi.w #3, (player_mode).w”: |
+ | <ul> | ||
+ | <li>If the statement afterwards is “beq.s [label]”, change it to “bhs.s [label]”. (Branch if Higher or Same, the assembler will convert it to “bcc.s” when assembling) | ||
+ | <li>If the statement afterwards is “bne.s [label]”, change it to “blo.s [label]”. (Branch if LOwer than, the assembler will convert it to “bcs.s” when assembling) | ||
+ | </ul> | ||
− | |||
− | |||
If you did all of the replacements correctly, all of the level events and most other things for Blue Knuckles will work. But wait! In replacing ALL of those conditional statements, you inadvertently made player #4 (Blue Knuckles) red and fixed the bugs that made him blue! The following steps will restore the bugs that made player #4 blue. | If you did all of the replacements correctly, all of the level events and most other things for Blue Knuckles will work. But wait! In replacing ALL of those conditional statements, you inadvertently made player #4 (Blue Knuckles) red and fixed the bugs that made him blue! The following steps will restore the bugs that made player #4 blue. | ||
− | Goto the following labels and revert what you changed back to the original code | + | Goto the following labels and revert what you changed back to the original code (i.e. change “bhs.s [label]” to “beq.s [label]” and “blo.s [label]” to “bne.s [label]”), |
− | i.e. change | ||
− | |||
− | |||
The labels, and what reverting the code back does: | The labels, and what reverting the code back does: | ||
<ul> | <ul> | ||
− | <li>loc_61BE | + | <li>loc_61BE - Makes player #4 blue above water. |
− | <li>loc_7A18 | + | <li>loc_7A18 - Makes player #4 blue underwater. |
− | <li>loc_8284 | + | <li>loc_8284 - Makes player #4 blue in Special Stages. |
− | <li>loc_55C84 - | + | <li>loc_55C84 - Makes player #4 blue when entering the pyramid after SOZ miniboss. |
</ul> | </ul> | ||
− | If you did that step and all of the other steps right, you should now be able to select Blue Knuckles from the Save and Level Select Screens. Most of the bugs involving Blue Knuckles should be fixed now too. | + | |
+ | If you did that step and all of the other steps right, you should now be able to select Blue Knuckles from the Save and Level Select Screens. ''Most'' of the bugs involving Blue Knuckles should be fixed now too. | ||
===Additional step 1: Fix End of Level Signpost=== | ===Additional step 1: Fix End of Level Signpost=== | ||
− | Now, as soon as we can, we have to fix the end of level signpost graphic for Blue Knuckles. This is as easy as weird. | + | Now, as soon as we can, we have to fix the end of level signpost graphic for Blue Knuckles. This is as easy as "weird". |
Go to ''FrameArray_EndSign'', change this: | Go to ''FrameArray_EndSign'', change this: | ||
Line 234: | Line 237: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | FrameArray_EndSign: dc.b 0, 0, 1, 2, 2, 2, 2, 2 | + | FrameArray_EndSign: dc.b 0, 0, 1, 2, 2, 2, 2, 2 ; Character shown per ID: 00 - Sonic, 01 - Sonic, 02 - Tails, 03 - Knuckles, 04to07 - Blue Knuckles (Knuckles with blue palette) |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 246: | Line 249: | ||
This happens because he uses the "Red" Knuckles' palette transition when reverting back to "normal form". | This happens because he uses the "Red" Knuckles' palette transition when reverting back to "normal form". | ||
− | Go to SuperHyper_PalCycle_Revert / loc_37EE: | + | Go to ''SuperHyper_PalCycle_Revert / loc_37EE'': |
It should look like this: | It should look like this: | ||
Line 253: | Line 256: | ||
SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards | SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards | ||
cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific | cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific | ||
− | bhs.s SuperHyper_PalCycle_RevertNotSonic | + | bhs.s SuperHyper_PalCycle_RevertNotSonic |
− | |||
; run frame timer | ; run frame timer | ||
− | subq.b #1,(Palette_timer).w | + | subq.b #1,(Palette_timer).w |
− | + | ... | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 278: | Line 269: | ||
SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards | SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards | ||
cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific | cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific | ||
− | bhs.s SuperHyper_PalCycle_RevertNotSonic | + | bhs.s SuperHyper_PalCycle_RevertNotSonic (loc_3820 in older disassemblies) |
− | |||
; run frame timer | ; run frame timer | ||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 291: | Line 278: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
; loc_37EE: | ; loc_37EE: | ||
− | SuperHyper_PalCycle_Revert: ; | + | SuperHyper_PalCycle_Revert: ; Runs the fade-in transition backwards |
− | cmpi.w #4,(Player_mode).w ; Check if character is Blue Knuckles | + | cmpi.w #4,(Player_mode).w ; Check if character is Blue Knuckles |
− | beq.s SuperHyper_PalCycle_RevertSonic ; If | + | beq.s SuperHyper_PalCycle_RevertSonic ; If character is Blue Knuckles branch to Sonic's reverting palette transition |
− | cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific | + | cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific |
− | bhs.s SuperHyper_PalCycle_RevertNotSonic ; | + | bhs.s SuperHyper_PalCycle_RevertNotSonic ; (doesn't need to be changed as "Blue Knuckles' code" branched before) |
− | SuperHyper_PalCycle_RevertSonic: | + | SuperHyper_PalCycle_RevertSonic: ; Apply for Sonic and Blue Knuckles |
; run frame timer | ; run frame timer | ||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 310: | Line 294: | ||
==Unfixed bugs== | ==Unfixed bugs== | ||
− | + | Unfortunately Blue Knuckles has some bugs yet to be fixed: | |
<ul> | <ul> | ||
− | <li>He is messed up in the Slot Bonus Stage. | + | <li>He is messed up in the Slot Bonus Stage. ''See optional steps for [[SCHG_How-to:Fix Blue Knuckles#How to prevent Blue Knuckles from accessing the Slot Bonus Stage (hotfix)|hotfix]]'' |
− | <li>Blue Super/Hyper Knuckles turns Red, but at least reverts Blue. | + | <li>Blue Super/Hyper Knuckles turns Red, but at least reverts Blue. ''See optional steps for [[SCHG_How-to:Fix Blue Knuckles#How to "Fix" Super/Hyper Blue Knuckles using Super/Hyper Sonic's palette cycles (fast fix)|fast fix]] or [[SCHG_How-to:Fix Blue Knuckles#How to Fix Super/Hyper Blue Knuckles using a custom palette cycle|complete fix]]'' |
</ul> | </ul> | ||
Line 320: | Line 304: | ||
==Optional steps== | ==Optional steps== | ||
− | ===How to prevent Blue Knuckles from accessing the Slot Bonus Stage ( | + | ===How to prevent Blue Knuckles from accessing the Slot Bonus Stage (hotfix)=== |
− | This isn't the best way to do it, but in this case bugged is worse than nothing. | + | This surely isn't the best way to do it, but in this case bugged is way worse than nothing. |
Just go to ''loc_2D47E'' and change this: | Just go to ''loc_2D47E'' and change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
+ | loc_2D47E: | ||
... | ... | ||
beq.s loc_2D506 | beq.s loc_2D506 | ||
Line 336: | Line 321: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
+ | loc_2D47E: | ||
... | ... | ||
− | beq.w loc_2D506 | + | beq.w loc_2D506 ; (word used instead of short: jump distance too big) |
move.b #2,(Special_bonus_entry_flag).w | move.b #2,(Special_bonus_entry_flag).w | ||
− | move.w #$1500,d1 | + | move.w #$1500,d1 ; Load the Slot Bonus Stage |
− | cmpi.w #4,(Player_mode).w | + | cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles |
− | bne.s | + | bne.s .notBlueKnuckles ; Skip if not Blue Knuckles |
− | move.w #$1400,d1 | + | move.w #$1400,d1 ; Load Pachinko instead of Slot for Blue Knuckles |
− | + | ||
+ | .notBlueKnuckles: | ||
... | ... | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | As you see, this forces Blue Knux to enter Pachinko instead of Slot Bonus. You can use $1300 to load the Gumball Machine instead...or any stage or even code you want, at your own risk. | ||
===How to "Fix" Super/Hyper Blue Knuckles using Super/Hyper Sonic's palette cycles (fast fix)=== | ===How to "Fix" Super/Hyper Blue Knuckles using Super/Hyper Sonic's palette cycles (fast fix)=== | ||
− | In my case, since I don't want to make Super/Hyper Blue Knuckles appear like a "bad copy" of his famous red brother nor create a custom palette cycle I figured out how to make his palette flash like Sonic's, | + | In my case, since I don't want to make Super/Hyper Blue Knuckles appear like a "bad copy" of his famous red brother nor create a custom palette cycle, I figured out how to make his palette flash like Sonic's, fixing the "Blue Super/Hyper Knuckles turns Red" bug listed above in a cool and easy way. |
− | + | Go to ''SuperHyper_PalCycle_Normal / loc_3854'': | |
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
Line 360: | Line 350: | ||
beq.w SuperHyper_PalCycle_NormalTails | beq.w SuperHyper_PalCycle_NormalTails | ||
cmpi.w #3,(Player_mode).w ; ...or Knuckles, branch, making this code Sonic-specific | cmpi.w #3,(Player_mode).w ; ...or Knuckles, branch, making this code Sonic-specific | ||
− | + | bhs.w SuperHyper_PalCycle_NormalKnuckles | |
− | tst.b (Super_Sonic_Knux_flag).w ; If Hyper Sonic, branch | + | tst.b (Super_Sonic_Knux_flag).w ; If Hyper Sonic, branch |
bmi.s SuperHyper_PalCycle_HyperSonic | bmi.s SuperHyper_PalCycle_HyperSonic | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Ok, now revert " | + | Ok, now revert "bhs.w" to "beq.w". Change this: |
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | + | bhs.w SuperHyper_PalCycle_NormalKnuckles | |
</syntaxhighlight> | </syntaxhighlight> | ||
Line 374: | Line 364: | ||
To this: | To this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
− | beq.w SuperHyper_PalCycle_NormalKnuckles | + | beq.w SuperHyper_PalCycle_NormalKnuckles ; Super/Hyper Blue Knuckles now uses Super/Hyper Sonic's PalCycle (reverted Blue Knuckles Fix "bhs") |
</syntaxhighlight> | </syntaxhighlight> | ||
''Note that this code changes only the color of Super/Hyper Blue Knuckles, this means that it doesn't add Hyper Sonic "Flashing Stars".'' | ''Note that this code changes only the color of Super/Hyper Blue Knuckles, this means that it doesn't add Hyper Sonic "Flashing Stars".'' | ||
− | ===How to Fix Super/Hyper Blue Knuckles using a custom palette cycle | + | ===How to Fix Super/Hyper Blue Knuckles using a custom palette cycle=== |
− | If you want Super/Hyper Blue Knuckles to be more "original" you could create a different palette cycle for Super and Hyper Blue Knuckles by just messing around with the ''SuperHyper_PalCycle | + | If you want Super/Hyper Blue Knuckles to be more "original" instead, you could create a different palette cycle for Super and Hyper Blue Knuckles by just messing around with the ''SuperHyper_PalCycle / SuperSonic_PalFlash'' subroutine, at label ''SuperHyper_PalCycle_NormalKnuckles / loc_393C''. |
− | The cycle that overrides | + | The cycle that overrides palette on every frame is in that section and the palettes the code overwrites are at the bottom of the subroutine: you could just add a palette array by creating a copy of ''PalCycle_SuperHyperKnuckles / AnPal_SuperSonic_6'', renaming it ''PalCycle_SuperHyperBlueKnuckles'' and editing every line to make Super/Hyper Blue Knuckles similar to "Super/Hyper Knuckles but blue"; just like this: |
+ | <syntaxhighlight lang="asm"> | ||
+ | ... | ||
+ | PalCycle_SuperHyperKnucklesRevert: | ||
+ | dc.w $64E,$20C,$206 | ||
− | Than just change this: | + | ; Super/Hyper Blue Knuckles cycle |
+ | PalCycle_SuperHyperBlueKnuckles: ; New palette cycle for Super/Hyper Blue Knuckles | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 0 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 3 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 6 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 9 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame C - 12 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame F - 15 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 13 - 18 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 16 - 21 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 19 - 24 | ||
+ | dc.w $BGR,$BGR,$BGR ; Frame 1C - 27 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | Make sure you replace every "BGR" with a valid Mega Drive palette color entry suitable for your Super/Hyper Blue Knuckles. Colors should be chosen wisely with ''PalCycle_SuperHyperKnuckles / AnPal_SuperSonic_6'' taken as example. | ||
+ | |||
+ | |||
+ | Than just go to ''SuperHyper_PalCycle_NormalKnuckles / loc_393C'' and change this: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
; loc_393C: | ; loc_393C: | ||
Line 392: | Line 404: | ||
; increment palette frame and update Knuckles' palette | ; increment palette frame and update Knuckles' palette | ||
lea (PalCycle_SuperHyperKnuckles).l,a0 | lea (PalCycle_SuperHyperKnuckles).l,a0 | ||
+ | move.w (Palette_frame).w,d0 | ||
... | ... | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | To this: | |
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
+ | ; loc_393C: | ||
SuperHyper_PalCycle_NormalKnuckles: | SuperHyper_PalCycle_NormalKnuckles: | ||
... | ... | ||
; increment palette frame and update Knuckles' palette | ; increment palette frame and update Knuckles' palette | ||
− | cmpi.w #4,(Player_mode).w | + | lea (PalCycle_SuperHyperKnuckles).l,a0 ; Set to load Knuckles' palette cycle |
− | + | cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles | |
− | lea ( | + | bne.s .notBlueKnuckles ; If not Blue Knuckles branch |
− | + | lea (PalCycle_SuperHyperBlueKnuckles).l,a0 ; set to load Blue Knuckles' palette cycle | |
+ | |||
+ | .notBlueKnuckles: ; Apply selected palette cycle | ||
+ | move.w (Palette_frame).w,d0 | ||
+ | ... | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | And finally, the last edit: this is mandatory if you don't want Blue Knuckles to briefly flash yellow before reverting to normal. Undo [[SCHG How-to:Fix Blue Knuckles#Additional step 2: Revert to blue palette after Super.2FHyper Transformation|the reverting to blue step]] and go back to ''PalCycle_SuperHyperBlueKnuckles''. | ||
+ | Add this line under the palette array you just built: | ||
+ | <syntaxhighlight lang="asm"> | ||
+ | PalCycle_SuperHyperBlueKnucklesRevert: ; Restore original Blue knuckles' palette | ||
+ | dc.w $E66,$C42,$822 ; Sonic's palette line, offset $4-$6-$8 | ||
+ | </syntaxhighlight> | ||
+ | |||
− | + | '''Last step'''. Go to ''SuperHyper_PalCycle_RevertKnuckles''. Change this: | |
− | lea ( | + | <syntaxhighlight lang="asm"> |
+ | SuperHyper_PalCycle_RevertKnuckles: | ||
+ | lea (PalCycle_SuperHyperKnucklesRevert).l,a0 | ||
+ | bra.w SuperHyper_PalCycle_Apply | ||
+ | </syntaxhighlight> | ||
− | + | ||
− | + | To this: | |
+ | <syntaxhighlight lang="asm"> | ||
+ | SuperHyper_PalCycle_RevertKnuckles: | ||
+ | lea (PalCycle_SuperHyperKnucklesRevert).l,a0 ; Set to load Knuckles normal colors | ||
+ | cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles | ||
+ | blo.s .notBlueKnuckles ; If not Blue Knuckles (or character 4+) branch | ||
+ | lea (PalCycle_SuperHyperBlueKnucklesRevert).l,a0 ; Set to load Blue Knuckles normal colors (Sonic's palette line, offset $4-$6-$8) | ||
+ | |||
+ | .notBlueKnuckles: ; Apply selected colors | ||
+ | bra.w SuperHyper_PalCycle_Apply | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | And there you have it! A true Super/Hyper form for our beloved Blue | + | |
+ | And there you have it! A '''true''' Super/Hyper form for our beloved Blue Knuckles. | ||
---- | ---- | ||
− | ''(Anyways)'' Now you can | + | ''(Anyways)'' Now you can enjoy your new “Character”! |
{{S3KHowtos}} | {{S3KHowtos}} |
Revision as of 19:14, 1 May 2019
(Original guide by Tamkis)
(Additional and optional steps by AlexShx)
Contents
Who is Blue Knuckles: the bug explained
Most people do not know, but in S3&K, there is a “hidden character” that is “unlockable” via Game Genie/Action Replay codes. This hidden character is Blue Knuckles. He is more than a palette change of the normal Red Knuckles; actually, he is identified internally as the character used for values greater than 3 for the variable player_mode. This variable, as the name states, determines what character(s) are in the game. The values are as follows:
- #0. Sonic & Tails
- #1. Sonic alone
- #2. Tails alone
- #3. Red Knuckles
- #4+.Blue Knuckles
The problem with making Blue Knuckles a playable character, however, is that he is not blue in the Special Stages, and most of his level events fail to work. In the Special Stages, he transforms into Sonic (lol). These errors happen, because Sega, in the asm code of S3&K (sonic3k.asm), mostly used comparison statements such as this:
cmpi.w #3,(Player_mode).w
bne.s [label]
The label jumped to in statements like that would do something specific for when the player_mode is NOT 3 (Red Knuckles). Blue Knuckles is player_mode ID #4, so, with that statement, the game would goto the label meant for Sonic &/or Tails player modes, which is not what we want. We want Blue Knuckles to do the code after the bne.s, which is meant for Red Knuckles. This guide will fix statements of this format
The other comparison statement that is causing problems is in this format:
cmpi.w #3,(Player_mode).w
beq.s [label]
If player_mode is #3 (Red Knuckles), the game will jump to a label for special processing for Knuckles events. If player_mode is NOT #3 (Red Knuckles), then the game will execute code for Sonic &/or Tails. Since Blue Knuckles (ID #4) is NOT ID #3, the game will execute Sonic &/or Tails code for Blue Knuckles, which is not what we want. We want Blue Knuckles to execute code for Red Knuckles. This guide will also fix statements of this format.
Making Blue Knuckles selectable
Save Screen
However, before we fix level events and other similar things for Blue Knuckles, let us make him a character that can be selected through ordinary means, without GG/AR codes. First, let us make him a selectable character in the Save Screen.
In the sonic3k.asm file in your S3&K .svn disasm, goto label SaveScreen_MainLoop / loc_C802 It should look something like this:
; loc_C802
SaveScreen_MainLoop:
move.b #$1E,(V_int_routine).w
jsr (Wait_VSync).l
addq.w #1,(Level_frame_counter).w
jsr (Process_Sprites).l
move.w (Camera_X_pos_copy).w,d0
neg.w d0
move.w d0,(H_scroll_buffer+2).w
jsr (Render_Sprites).l
lea (Normal_palette_line_3+$2).w,a0
moveq #$E,d0
move.w ($FFFFE666).w,d1
addq.w #1,d1
cmpi.w #3,d1
bcs.s +
moveq #0,d1
Change this:
addq.w #1,d1
cmpi.w #3,d1
To this:
addq.w #1,d1
cmpi.w #4,d1 ; Blue Knuckles Fix: Now character #4 is the highest selectable
Then, goto label Obj_SaveScreen_NoSave_Slot / Obj_SaveScreen_D30C
It should look something like this:
Obj_SaveScreen_NoSave_Slot:
move.b #$F,$1D(a0)
move.w ($FFFFEF4C).w,d0
addq.w #3,d0
move.b d0,$22(a0)
tst.b ($FFFFEF4B).w
bne.s loc_D396
Change this:
addq.w #3,d0
To this:
addq.w #4,d0 ; Blue Knuckles Fix: No Save Slot - Now character #4 is the highest selectable
Afterwards, go to subprgm sub_D6D0; it should look like this:
sub_D6D0:
moveq #0,d2
tst.w ($FFFFB07A).w
bne.s loc_D6FA
move.b (Ctrl_1_pressed).w,d1
lsr.w #1,d1
bcc.s loc_D6EE
moveq #$5B,d2
addq.w #1,d0
cmpi.w #3,d0
bls.s loc_D6FA
moveq #0,d0
bra.s loc_D6FA
; ---------------------------------------------------------------------------
Change this:
cmpi.w #3,d0
To this:
cmpi.w #4,d0 ; Blue Knuckles Fix: Save Slot Update Character - Now character #4 is the highest selectable
Furthermore, goto label loc_D6EE.
It should look like this:
loc_D6EE:
lsr.w #1,d1
bcc.s loc_D6FA
moveq #$5B,d2
subq.w #1,d0
bpl.s loc_D6FA
moveq #3,d0
Change this:
moveq #3,d0
To this:
moveq #4,d0 ; Blue Knuckles Fix: Save Slot Update Character - Reset character to #4 if below #0 (negative)
Those modifications changed the max player_mode for the Save Screen, from #3 (Red Knuckles) to #4 (Blue Knuckles). Note that Blue Knuckles’ picture in the Save screen shows part of the “Del” sign seen when deleting a save, instead of a picture of a blue Knuckles. You will have to repoint manually the art to a suitable picture for blue knuckles. Use SonMapED and modify General\Save Menu\Map - Save Screen General.asm
Level Select Screen
Next, we will fix the character select for the Level Select screen. This character selection is done by pressing C on the level select screen. Pressing C will increment the player_mode. As before, we will change the max character from #3 (Red Knuckles) to #4 (Blue Knuckles).
There is only on step to fix it here. Goto loc_7F46. It should look like this:
loc_7F46:
btst #5,(Ctrl_1_pressed).w
beq.s locret_7F60
addq.w #1,(Player_option).w
cmpi.w #4,(Player_option).w
bcs.s locret_7F60
move.w #0,(Player_option).w
Change this:
cmpi.w #4,(Player_option).w
bcs.s locret_7F60
To this:
cmpi.w #5,(Player_option).w ; Blue Knuckles Fix: 04 is the highest selectable player_option
blo.s locret_7F60 ; Used mnemonic "blo" instead of "bcs" - if player_option is lower than 5 don't reset to 0
Note: you can make Blue Knuckles available only in the Level Select Screen.
Fixing bugs
Now that Blue Knuckles is available for selection by normal means, we still have to fix all of his level events and other bugs. To do so, we will have to fix the player_mode comparison statements that were shown before. Search for every instance of “cmpi.w #3, (player_mode).w”:
- If the statement afterwards is “beq.s [label]”, change it to “bhs.s [label]”. (Branch if Higher or Same, the assembler will convert it to “bcc.s” when assembling)
- If the statement afterwards is “bne.s [label]”, change it to “blo.s [label]”. (Branch if LOwer than, the assembler will convert it to “bcs.s” when assembling)
If you did all of the replacements correctly, all of the level events and most other things for Blue Knuckles will work. But wait! In replacing ALL of those conditional statements, you inadvertently made player #4 (Blue Knuckles) red and fixed the bugs that made him blue! The following steps will restore the bugs that made player #4 blue.
Goto the following labels and revert what you changed back to the original code (i.e. change “bhs.s [label]” to “beq.s [label]” and “blo.s [label]” to “bne.s [label]”),
The labels, and what reverting the code back does:
- loc_61BE - Makes player #4 blue above water.
- loc_7A18 - Makes player #4 blue underwater.
- loc_8284 - Makes player #4 blue in Special Stages.
- loc_55C84 - Makes player #4 blue when entering the pyramid after SOZ miniboss.
If you did that step and all of the other steps right, you should now be able to select Blue Knuckles from the Save and Level Select Screens. Most of the bugs involving Blue Knuckles should be fixed now too.
Additional step 1: Fix End of Level Signpost
Now, as soon as we can, we have to fix the end of level signpost graphic for Blue Knuckles. This is as easy as "weird".
Go to FrameArray_EndSign, change this:
FrameArray_EndSign: dc.b 0, 0, 1, 2
To this:
FrameArray_EndSign: dc.b 0, 0, 1, 2, 2, 2, 2, 2 ; Character shown per ID: 00 - Sonic, 01 - Sonic, 02 - Tails, 03 - Knuckles, 04to07 - Blue Knuckles (Knuckles with blue palette)
Done. This loads and displays the variant #2 of the End Signpost instead of a null one, and since Knuckles' palette is blue, the displayed character will be Blue Knuckles.
Additional step 2: Revert to blue palette after Super/Hyper Transformation
Ok, now we need to fix Super/Hyper Blue Knuckles reverting back in Red to his "normal form". This happens because he uses the "Red" Knuckles' palette transition when reverting back to "normal form".
Go to SuperHyper_PalCycle_Revert / loc_37EE:
It should look like this:
; loc_37EE:
SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards
cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific
bhs.s SuperHyper_PalCycle_RevertNotSonic
; run frame timer
subq.b #1,(Palette_timer).w
...
Ok, now change this:
; loc_37EE:
SuperHyper_PalCycle_Revert: ; runs the fade in transition backwards
cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific
bhs.s SuperHyper_PalCycle_RevertNotSonic (loc_3820 in older disassemblies)
; run frame timer
To this:
; loc_37EE:
SuperHyper_PalCycle_Revert: ; Runs the fade-in transition backwards
cmpi.w #4,(Player_mode).w ; Check if character is Blue Knuckles
beq.s SuperHyper_PalCycle_RevertSonic ; If character is Blue Knuckles branch to Sonic's reverting palette transition
cmpi.w #2,(Player_mode).w ; If Tails or Knuckles, branch, making this code Sonic-specific
bhs.s SuperHyper_PalCycle_RevertNotSonic ; (doesn't need to be changed as "Blue Knuckles' code" branched before)
SuperHyper_PalCycle_RevertSonic: ; Apply for Sonic and Blue Knuckles
; run frame timer
Now Super/Hyper Blue Knuckles uses Super/Hyper Sonic's "reverting" transition wich makes him blue (and pretty) again after Super/Hyper form.
Unfixed bugs
Unfortunately Blue Knuckles has some bugs yet to be fixed:
- He is messed up in the Slot Bonus Stage. See optional steps for hotfix
- Blue Super/Hyper Knuckles turns Red, but at least reverts Blue. See optional steps for fast fix or complete fix
Optional steps
How to prevent Blue Knuckles from accessing the Slot Bonus Stage (hotfix)
This surely isn't the best way to do it, but in this case bugged is way worse than nothing.
Just go to loc_2D47E and change this:
loc_2D47E:
...
beq.s loc_2D506
move.b #2,(Special_bonus_entry_flag).w
move.w #$1500,d1
...
To this:
loc_2D47E:
...
beq.w loc_2D506 ; (word used instead of short: jump distance too big)
move.b #2,(Special_bonus_entry_flag).w
move.w #$1500,d1 ; Load the Slot Bonus Stage
cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles
bne.s .notBlueKnuckles ; Skip if not Blue Knuckles
move.w #$1400,d1 ; Load Pachinko instead of Slot for Blue Knuckles
.notBlueKnuckles:
...
As you see, this forces Blue Knux to enter Pachinko instead of Slot Bonus. You can use $1300 to load the Gumball Machine instead...or any stage or even code you want, at your own risk.
How to "Fix" Super/Hyper Blue Knuckles using Super/Hyper Sonic's palette cycles (fast fix)
In my case, since I don't want to make Super/Hyper Blue Knuckles appear like a "bad copy" of his famous red brother nor create a custom palette cycle, I figured out how to make his palette flash like Sonic's, fixing the "Blue Super/Hyper Knuckles turns Red" bug listed above in a cool and easy way.
Go to SuperHyper_PalCycle_Normal / loc_3854:
; loc_3854:
SuperHyper_PalCycle_Normal:
cmpi.w #2,(Player_mode).w ; If Tails...
beq.w SuperHyper_PalCycle_NormalTails
cmpi.w #3,(Player_mode).w ; ...or Knuckles, branch, making this code Sonic-specific
bhs.w SuperHyper_PalCycle_NormalKnuckles
tst.b (Super_Sonic_Knux_flag).w ; If Hyper Sonic, branch
bmi.s SuperHyper_PalCycle_HyperSonic
Ok, now revert "bhs.w" to "beq.w". Change this:
bhs.w SuperHyper_PalCycle_NormalKnuckles
To this:
beq.w SuperHyper_PalCycle_NormalKnuckles ; Super/Hyper Blue Knuckles now uses Super/Hyper Sonic's PalCycle (reverted Blue Knuckles Fix "bhs")
Note that this code changes only the color of Super/Hyper Blue Knuckles, this means that it doesn't add Hyper Sonic "Flashing Stars".
How to Fix Super/Hyper Blue Knuckles using a custom palette cycle
If you want Super/Hyper Blue Knuckles to be more "original" instead, you could create a different palette cycle for Super and Hyper Blue Knuckles by just messing around with the SuperHyper_PalCycle / SuperSonic_PalFlash subroutine, at label SuperHyper_PalCycle_NormalKnuckles / loc_393C.
The cycle that overrides palette on every frame is in that section and the palettes the code overwrites are at the bottom of the subroutine: you could just add a palette array by creating a copy of PalCycle_SuperHyperKnuckles / AnPal_SuperSonic_6, renaming it PalCycle_SuperHyperBlueKnuckles and editing every line to make Super/Hyper Blue Knuckles similar to "Super/Hyper Knuckles but blue"; just like this:
...
PalCycle_SuperHyperKnucklesRevert:
dc.w $64E,$20C,$206
; Super/Hyper Blue Knuckles cycle
PalCycle_SuperHyperBlueKnuckles: ; New palette cycle for Super/Hyper Blue Knuckles
dc.w $BGR,$BGR,$BGR ; Frame 0
dc.w $BGR,$BGR,$BGR ; Frame 3
dc.w $BGR,$BGR,$BGR ; Frame 6
dc.w $BGR,$BGR,$BGR ; Frame 9
dc.w $BGR,$BGR,$BGR ; Frame C - 12
dc.w $BGR,$BGR,$BGR ; Frame F - 15
dc.w $BGR,$BGR,$BGR ; Frame 13 - 18
dc.w $BGR,$BGR,$BGR ; Frame 16 - 21
dc.w $BGR,$BGR,$BGR ; Frame 19 - 24
dc.w $BGR,$BGR,$BGR ; Frame 1C - 27
Make sure you replace every "BGR" with a valid Mega Drive palette color entry suitable for your Super/Hyper Blue Knuckles. Colors should be chosen wisely with PalCycle_SuperHyperKnuckles / AnPal_SuperSonic_6 taken as example.
Than just go to SuperHyper_PalCycle_NormalKnuckles / loc_393C and change this:
; loc_393C:
SuperHyper_PalCycle_NormalKnuckles:
...
; increment palette frame and update Knuckles' palette
lea (PalCycle_SuperHyperKnuckles).l,a0
move.w (Palette_frame).w,d0
...
To this:
; loc_393C:
SuperHyper_PalCycle_NormalKnuckles:
...
; increment palette frame and update Knuckles' palette
lea (PalCycle_SuperHyperKnuckles).l,a0 ; Set to load Knuckles' palette cycle
cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles
bne.s .notBlueKnuckles ; If not Blue Knuckles branch
lea (PalCycle_SuperHyperBlueKnuckles).l,a0 ; set to load Blue Knuckles' palette cycle
.notBlueKnuckles: ; Apply selected palette cycle
move.w (Palette_frame).w,d0
...
And finally, the last edit: this is mandatory if you don't want Blue Knuckles to briefly flash yellow before reverting to normal. Undo the reverting to blue step and go back to PalCycle_SuperHyperBlueKnuckles.
Add this line under the palette array you just built:
PalCycle_SuperHyperBlueKnucklesRevert: ; Restore original Blue knuckles' palette
dc.w $E66,$C42,$822 ; Sonic's palette line, offset $4-$6-$8
Last step. Go to SuperHyper_PalCycle_RevertKnuckles. Change this:
SuperHyper_PalCycle_RevertKnuckles:
lea (PalCycle_SuperHyperKnucklesRevert).l,a0
bra.w SuperHyper_PalCycle_Apply
To this:
SuperHyper_PalCycle_RevertKnuckles:
lea (PalCycle_SuperHyperKnucklesRevert).l,a0 ; Set to load Knuckles normal colors
cmpi.w #4,(Player_mode).w ; Check if player is Blue Knuckles
blo.s .notBlueKnuckles ; If not Blue Knuckles (or character 4+) branch
lea (PalCycle_SuperHyperBlueKnucklesRevert).l,a0 ; Set to load Blue Knuckles normal colors (Sonic's palette line, offset $4-$6-$8)
.notBlueKnuckles: ; Apply selected colors
bra.w SuperHyper_PalCycle_Apply
And there you have it! A true Super/Hyper form for our beloved Blue Knuckles.
(Anyways) Now you can enjoy your new “Character”!
SCHG How-To Guide: Sonic the Hedgehog 3 and Knuckles |
---|
Fixing Bugs |
Fix Blue Knuckles | Fix Tails' Respawn Speeds | Fix Super Sonic Bugs |
Design Choices |
Fix Scattered Rings' Underwater Physics | Edit Level Select Text & Pointers | Work with Water | Make the Slots Bonus Game Rotate Smoothly |
Adding Features |
Restore (Sonic 2) Options Menu |