Sonic B&W

Discussion in 'Showroom' started by TheInvisibleSun, Dec 30, 2018.

Tags:
  1. TheInvisibleSun

    TheInvisibleSun Visible Member

    Joined:
    Jul 2, 2013
    Messages:
    287
    Location:
    Buffalo, NY, USA
    Sonic B&W



    Collect as many Rings as you can!

    Sonic B&W is a ROM hack of Sonic the Hedgehog, that adds a visual modification/gimmick to the base game; collecting rings gradually changes the colors and music of South Island! Getting hit, however, undoes this effect. Have 50 rings by the end of the stage to activate and enter special stages!

    (Epilepsy Warning: There are occasional instances of flashing background colors)

    This started out as a small tech demo a few years ago, but in the last couple of months I decided to expand upon it, add new features, and experiment with the special stages.

    Features:

    -Two ways to play: Select sound '80' in the Sound Test to toggle 'Grayscale Mode', which uses a different palette than the default.

    -Brand-New style of Special Stage, with 6 new stages available. To skip to the Special Stage you want, play sound '93' in the sound test once for every emerald (once for Stage 2, twice for Stage 3, etc.). I plan to actually make a menu for this later.

    (Tap C at Title Screen).

    -I'll add new features to this gradually in the future, to expand the project a bit.

    Current Version: Version 4
    Previous Version: Original Demo

    Screenshots:

    [​IMG]

    [​IMG]

    [​IMG]

    [​IMG]

    GrayScale Mode:

    [​IMG]

    Special Stage:

    [​IMG]

    Known Bugs:

    -There are a couple of small graphical errors in the special stages

    -Spikes do not entirely reverse the color effect, when hit.

    -Ring count in the special stages don't update consistently.

    -Palette Cycling in certain zones is disabled, as they cause crashes, for some reason.


    Special Thanks:

    Coding Help:

    MarkeyJester
    StephenUK
    FireRat
    Novidicus
    GenesisFan64/Gardeguey - For the PalLoad_Loop quick loading subroutine.

    Tools:

    MainMemory - SonLVL, S1SSE, etc.
    snkenjoi - Flex 2
    Xenowhirl - SonMapEd
     
    Last edited: Dec 30, 2018
  2. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,753
    Location:
    italy
    I've yet to play the actual hack, but:
    It's easy enough and I'm sure you can pull it off on your own since you're better than me, but I can give you the soniNeko source code if you want to save time. I might put it in a guide or something, but it's a rather niche feature and it's extremely easy anyway so I'm not sure how useful such a guide would be.
     
    TheInvisibleSun and maple_t like this.
  3. TruffledToad

    TruffledToad The Laugh, the Load, and the Lazy. Member

    Joined:
    Feb 2, 2017
    Messages:
    46
    Location:
    Hell, Michigan
    An interesting hack idea, I'll say. I like the special stages too, but I dunno if this would work for a full game. Maybe if it was exclusive to a single zone that would be a cool gimmick idea, cause I dunno if the full game is manageable with all of this (maybe an original zone with a new layout would work better for this kind of thing).

    Also small nitpick, but that remix of Rockman and Forte's Intro Stage theme is garbage, no other way to put it. It sounds so empty, and it doesn't do the original any justice at all.

    So, all in all, a neat spin on the "limbo-esque" hack, but one that feels like a one trick pony.
     
    maple_t and ProjectFM like this.
  4. Renegade

    Renegade RuthlessTheHooman Member

    Joined:
    Nov 20, 2016
    Messages:
    69
    Location:
    New York Desert
    On what TruffledToad said, if you want I could give you a version of the Rockman & Forte intro stage I made recently.

    On the hack itself, it's a unique concept, I'll give you that. I'm just not quite sure how it makes the game different other than the visuals and music.
    A cool idea would be changing Sonic's physics slightly the more rings you get, and restoring them when you get hit. I'd have no idea how to do that though.
    I liked the Special Stages, they were a nice change from the original even if they felt slow at times.
    B&W is a bit of a strange name, why not call it something like, Sonic Colour Contrast? (Bad joke was bad.)
    Good idea, nice execution, but feels like a proof of concept to me.
     
  5. TheInvisibleSun

    TheInvisibleSun Visible Member

    Joined:
    Jul 2, 2013
    Messages:
    287
    Location:
    Buffalo, NY, USA
    Although I want to improve it myself, I could definitely use your code as a reference. The way I've done menus in previous hacks was a bit sloppy/hackish, so I should spend some time getting better at making good user interfaces. Thanks, I really do appreciate the offer!

    Well, at this stage it really is just a small proof of concept/gimmick-hack; this is why the level select is enabled by default. I do want to expand on the project though, and provide a fuller experience.

    Don't worry, I don't consider this a nitpick at all! I'm aware that the port is indeed blatantly awful at the moment (this is indicative of my current SMPS ability/knowledge). But I certainly plan to improve upon it! SMPS is a bit of a struggle for me, but I do have an understanding/vision of how I would like the track to sound; I'm just not there yet skill-wise.

    Thanks for the response! I'm honestly not quite directly aiming for the 'limbo' idea/concept (which is why I started to introduce other palettes as options), although silhouetting is something I've come to enjoy in Sonic 1's art, aesthetically.

    Thanks for the offer! However, I do want to personally make my own version, and improve myself.

    Neat ideas, and thanks for the feedback (and the bad joke).

    Right now the hack is pretty much is a proof of concept; a base point from which to create something more substantial in the future. I released this demo out of curiosity to see what people thought of the ideas presented, so I appreciate the comments!
     
    TruffledToad and maple_t like this.
  6. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,753
    Location:
    italy
    Very well then. I'll just paste it here instead of sending it privately, so if there are any blatant errors, someone better than me can improve it. As I said, it's quite simple, I literally copied the Sound Test selector; this requires a free byte in RAM to hold the Special Stage number. How to use the Special Stage number in the Special Stage routine is even simpler (just copy that byte to $FFFFFE16), so that's left to the reader. I'll paste from the line before the first modified one, to the line after the last modified one.

    Original code:
    Code:
    		bsr.w	LevSel_ChgLine
    		move.w	#$E680,d3
    		cmpi.w	#$14,($FFFFFF82).w
    		bne.s	loc_3550
    		move.w	#$C680,d3
    
    loc_3550:
    		move.l	#$6C300003,($C00004).l ; screen	position (sound	test)
    		move.w	($FFFFFF84).w,d0
    		addi.w	#$80,d0
    		move.b	d0,d2
    		lsr.b	#4,d0
    		bsr.w	LevSel_ChgSnd
    		move.b	d2,d0
    		bsr.w	LevSel_ChgSnd
    		rts	
    ; End of function LevSelTextLoad
    Modified code:
    Code:
    		bsr.w	LevSel_ChgLine
    
    loc_3550:			; sound test number
    		move.w	#$E680,d3		; set gray color
    		cmpi.w	#$15,($FFFFFF82).w		; am I sound testing?
    		bne.s	loc_3550_gray		; if not, use gray color
    		move.w	#$C680,d3		; if yes, use yellow color
    
    loc_3550_gray:
    		move.l	#$6C300003,($C00004).l	; screen position (sound test)
    		move.w	($FFFFFF84).w,d0		; song number in sound test
    		addi.w	#$80,d0
    		move.b	d0,d2
    		lsr.b	#4,d0
    		bsr.w	LevSel_ChgSnd
    		move.b	d2,d0
    		bsr.w	LevSel_ChgSnd
    
    loc_3550b:		; special stage number
    		move.w	#$E680,d3		; set gray color
    		cmpi.w	#$14,($FFFFFF82).w		; am I special staging?
    		bne.s	loc_3550b_gray		; if not, use gray color
    		move.w	#$C680,d3		; if yes, use yellow color
    
    loc_3550b_gray:
    		move.l	#$6BB00003,($C00004).l	; screen position (special stage)
    		move.b	($FFFFFFFF).w,d0		; special stage number
    		addi.w	#$1,d0
    		move.b	d0,d2
    		lsr.b	#4,d0
    		bsr.w	LevSel_ChgSnd
    		move.b	d2,d0
    		bsr.w	LevSel_ChgSnd
    
    loc_3550_common:
    		rts
    More original code:
    Code:
    LevSel_SndTest:				; XREF: LevSelControls
    		cmpi.w	#$14,($FFFFFF82).w ; is	item $14 selected?
    		bne.s	LevSel_NoMove	; if not, branch
    		move.b	($FFFFF605).w,d1
    		andi.b	#$C,d1		; is left/right	pressed?
    		beq.s	LevSel_NoMove	; if not, branch
    		move.w	($FFFFFF84).w,d0
    		btst	#2,d1		; is left pressed?
    		beq.s	LevSel_Right	; if not, branch
    		subq.w	#1,d0		; subtract 1 from sound	test
    		bcc.s	LevSel_Right
    		moveq	#$4F,d0		; if sound test	moves below 0, set to $4F
    
    LevSel_Right:
    		btst	#3,d1		; is right pressed?
    		beq.s	LevSel_Refresh2	; if not, branch
    		addq.w	#1,d0		; add 1	to sound test
    		cmpi.w	#$50,d0
    		bcs.s	LevSel_Refresh2
    		moveq	#0,d0		; if sound test	moves above $4F, set to	0
    
    LevSel_Refresh2:
    		move.w	d0,($FFFFFF84).w ; set sound test number
    		bsr.w	LevSelTextLoad	; refresh text
    
    LevSel_NoMove:
    		rts
    More modified code:
    Code:
    LevSel_SndTest:				; XREF: LevSelControls
    
    		move.w	($FFFFFF84).w,d0	; check the sound ID
    		cmpi.w	#$0,d0		; is it zero? (aka 80)
    		bne.s	LevSelAllRight	; if not, branch
    		moveq	#1,d0		; if sound test is 80 (100) then it turns to 1 (81)
    		bra.s	LevSel_Refresh3	; no need to check it more if I set it to 1 (81) kthx
    		
    
    LevSelAllRight:
    		cmpi.w	#$15,($FFFFFF82).w ; is	item $15 selected? (sound test)
    		bne.s	LevSel_AllRightB	; if not, branch
    		move.b	($FFFFF605).w,d1
    		andi.b	#$C,d1		; is left/right	pressed?
    		beq.w	LevSel_NoMove	; if not, branch
    		move.w	($FFFFFF84).w,d0
    		btst	#2,d1		; is left pressed?
    		beq.s	LevSel_Right	; if not, branch
    		subq.w	#1,d0		; subtract 1 from sound	test
    
    		cmpi.w	#$0,d0		; is it zero?
    		bne.s	LevSel_Refresh2	; if not, branch
    		moveq	#$7F,d0		; if sound test is 0 (80) then it turns to 7F (FF)
    		bra.s	LevSel_Refresh3	; no need to check it more if I set it to 7F (FF) kthx
    
    LevSel_Right:
    		btst	#3,d1		; is right pressed?
    		beq.s	LevSel_Refresh3	; if not, branch
    		addq.w	#1,d0		; add 1 to sound test
    		cmpi.w	#$80,d0		; is it 80? (100)
    		bne.s	LevSel_Refresh2	; if not, branch
    		moveq	#1,d0		; if sound test is 80 (100) then it turns to 1 (81)
    		bra.s	LevSel_Refresh3	; no need to check it more if I set it to 1 (81) kthx
    
    		; here I am writing a NINEKODE to add a gap in the middle of the sound test list
    LevSel_Refresh2:
    		cmpi.w	#$20,d0		; is it 20? (A0)
    		bne.s	LevSel_Refresh22	; if not, branch
    		moveq	#song1,d0	; if sound test is 20 (A0) then it turns to song1 (smallest of the highest allowed values)
    		bra.s	LevSel_Refresh3	; no need to check it more if I set it to song1 kthx
    LevSel_Refresh22:
    		cmpi.w	#song2,d0	; is it song2 (one unit smaller than the smallest of the highest allowed values)
    		bne.s	LevSel_Refresh3	; if not, branch
    		moveq	#$1F,d0		; if sound test is song2 then it turns to 1F (9F)
    
    LevSel_Refresh3:
    		move.w	d0,($FFFFFF84).w ; set sound test number
    		bsr.w	LevSelTextLoad	; refresh text
    		
    		bra.w	LevSel_NoMove	; at this point, we're done
    
    LevSel_AllRightB:
    		cmpi.w	#$14,($FFFFFF82).w ; is	item $14 selected? (special stage)
    		bne.s	LevSel_NoMove	; if not, branch
    		move.b	($FFFFF605).w,d1
    		andi.b	#$C,d1		; is left/right	pressed?
    		beq.s	LevSel_NoMove	; if not, branch
    		move.b	($FFFFFFFF).w,d0
    		btst	#2,d1		; is left pressed?
    		beq.s	LevSel_RightB	; if not, branch
    		subq.b	#1,d0		; subtract 1 from sound	test
    
    		cmpi.b	#-1,d0		; is it -1?
    		bne.s	LevSel_Refresh3B	; if not, branch
    		moveq	#$5,d0		; if special stage is -1 (0) then it turns to 5 (6)
    		bra.s	LevSel_Refresh3B	; no need to check it more if I set it to 5 (6) kthx
    
    LevSel_RightB:
    		btst	#3,d1		; is right pressed?
    		beq.s	LevSel_Refresh3B	; if not, branch
    		addq.b	#1,d0		; add 1 to sound test
    		cmpi.b	#$6,d0		; is it 6? (7)
    		bne.s	LevSel_Refresh3B	; if not, branch
    		moveq	#0,d0		; if special stage is 6 (7) then it turns to 0 (1)
    ;		bra.s	LevSel_Refresh3B	; no need to check it more if I set it to 0 (1) kthx
    
    LevSel_Refresh3B:
    		move.b	d0,($FFFFFFFF).w	; set special stage number
    		bsr.w	LevSelTextLoad	; refresh text
    
    LevSel_NoMove:
    		rts
    Please note that I added one line because of Good Morning Zone, so the $14 and the $15 should probably be $13 and $14 respectively (since the Sound Test is $14 in the original code), but I'm not in a position to double check that right now. Also, you might have added/removed levels in your hack as well, so it's a good thing to make sure that the line numbers are correct.
    Also please note that I used address $FFFFFFFF for the Special Stage number, but any free byte will do. I also advise to clear that byte AND the collected emeralds when starting a regular game, or you might get bizarre behaviour instead of playing the first Special Stage when you enter the first big ring in the game (one might even play all 6 Special Stages from the Level Select and start the game with all the Emeralds). I'm not sure why I didn't use $FFFFFE16 directly, I did that 10 years ago and I don't remember a thing. It is very well possible that I was just being stupid and that $FFFFFE16 is safe to use, so you don't even need to copy from $FFFFFFFF to $FFFFFE16 when you load the Special Stage. Again, not sure about this, there might have been a valid reason.
    Also also please note that I added a "hole" in the Sound Test to exclude the Sound Effects and the invalid IDs, so only actual songs are shown (song1 and song2 are two constants declared at the top of the code). You probably don't want that, but as I said, I'm so rusty with asm after 10 years that I felt more comfortable to just give you my code as it is instead of tampering with it myself.

    I hope that this helps. And I also hope that I didn't forget any relevant modification, maybe it would have been better if I just sent you the source code as a whole and call it a day as I originally planned, it wouldn't have been a problem if the code was all mine, but other people helped (mainly Puto) and I'm not sure if they would be ok with me sharing their code without permission, so I only pasted code which I'm sure I wrote myself.

    Sorry if this is even worse than you expected. The fact that not even then I was very good at asm, and that 10 years passed on top of that, is starting to make me think that posting all this stuff might not have been my brightest idea, the "Tech Member" status on Sonic Retro should be stripped from me after this.

    Also sorry that I derailed your topic. If you feel I went overboard, this can be split somewhere else.

    Man I hate myself.
     
    Last edited: Jan 7, 2019
    TheInvisibleSun likes this.
  7. Catswell

    Catswell Newcomer Prospect

    Joined:
    Aug 2, 2017
    Messages:
    10
    Location:
    Star Light Zone
    Sonic Limbo: The Origins.

    Aside the jokes, hack is awesome. I'd love to see some new versions ^^
     
  8. TruffledToad

    TruffledToad The Laugh, the Load, and the Lazy. Member

    Joined:
    Feb 2, 2017
    Messages:
    46
    Location:
    Hell, Michigan
    Might want to make your posts a bit more meaty. Quality over quantity.
     
    TheInvisibleSun, HyaDoki and Natsumi like this.
  9. TheInvisibleSun

    TheInvisibleSun Visible Member

    Joined:
    Jul 2, 2013
    Messages:
    287
    Location:
    Buffalo, NY, USA
    Thanks again man, I appreciate the reference.

    Woah, don't get so down on yourself! You're a household name in the community, and you have a lot to be proud of. You've inspired and helped a lot of people over the years, including myself.
     
    ProjectFM likes this.