Where do I go for general assistance with a romhack? Is there a Discord server? I'm trying to implement new moves like a double jump and it's not quite working. edit: and also, how does Sonic 1 handle pointers to walking/running sprites when Sonic is tilted?
Sonic Retro's discord server has a channel for hacking discussion. You can also use the search feature on this site to look at others' forum posts and see how they solved problems. Sonic Stuff Research Group is another forum site to look at if you can't find something here. Hope this helps.
The Obj_SOZGhosts object in SOZ2 in SK is absolute coordinates and is offscreen the entire time, according to the render flags. It sets it coordinates as 0x120 0xA0 ( X AND Y ) . It seems to be a parent object that is not displayed and is kind of a "dummy" in the sense that it creates children by loc_8F108: lea ChildObjDat_8F674(pc),a2 jmp (CreateChild6_Simple).l where: ChildObjDat_8F674: dc.w 0 dc.l loc_8F11E note loc_8F11E is a part of Obj_SOZGhostsobject What is the Obj_SOZGhostsobject then if it is a non seen parent object that isn't really a ghost but rather seems to be a spawner of the ghost and have code that controls it. Is this a common theme in sonic 1 2 3 knuckes engines to have the object name be a dummy that spawns? Why have the Obj_SOZGhosts object be at this particular coordinate point mentioned above. And why bother making it absolute? And why bother making it offscreen if there is no sprite? I am missing some fundamentals of parent child creation in sonic games i believe. Also the ghosts being made by CreateChild6_Simple take upon the Obj_SOZGhosts x and y and by default are absolute while the ghosts float left and right while they are small and only change to playfield coordinates when they move diagonally and then disappear and come back to the top are absolute only to repeat back the cycle. Any clue why? Here is a video of what is going on. I wrote a script to show the objects base slot in object ram, its object code , its coord system type ( absolute / playfield ), if its on scree and its x and y
Tried to put in a custom song for the HPZ entry in the music index, got this error that I cannot figure out for the life of me. I tried to use the +20h on its inclusion to the index like the 1up/credits/drowning track and the include asm path, still doesn't work. How do I fix this?
The error seems pretty self-explanatory to me. Your new song is too big for the decompression buffer. It even gives you a solution: add it uncompressed.
The problem is that I can't figure out how to add it uncompressed. Last time I've checked, I couldn't find anything on adding uncompressed songs.
This isn't so much of a basic question, but I've been working at this for 6 hours now with no luck, and I'm out of ideas. I'm replacing the Sega screen in my hack with a custom one: I want the neon lights to go from being off to unstable flickering, and then stays on. I've been trying to achieve this with a table of nybbles to indicate the lights are active or inactive. However no matter how many times I've rewritten this, it's either resulted in the screen just loading the initial palette and then fading out, or the lights get disabled and then it fades out to the title screen. I'm not sure if this is an issue with reading the nybbles, or how I'm handling the timer. But any help is greatly appreciated. Code (Text): moveq #PALID_KILOANDSEGA,d0 bsr.w Pal_LoadBuffer Logos_FlashLoop: moveq #0,d0 move.w (logos_flashidx).w,d0 ; Load the current flash frame. addi.w #1,(logos_flashidx).w move.b d0,d1 ; Copy it, since we're going to modify d0. tst.b d0 ; Are we at frame 0? beq.s @DontCheckEven ; If so, don't check if the frame is odd or even. btst #0,d0 ; Is this an even frame? bne.s @DontCheckEven ; If not, branch. subq.b #1,d0 ; Subtract 1, since we're working with nybbles. @DontCheckEven: lea (Logos_KiloFlashFrames).l,a0 ; Load our flash flags. adda.w d0,a0 ; And add our offset given the frame. move.b (a0),d2 ; Move it to d2 for masking. adda.w #Logos_SEGAFlashFrames-Logos_KiloFlashFrames,a0 ; And add an offset for the SEGA palette. move.b (a0),d3 ; Move it to d3 for masking. btst #0,d1 ; Is it an even frame? bne.s @Odd ; If not, branch. and.b #%10000,d2 ; Mask out lower nybble. and.b #%10000,d3 ; Mask out lower nybble. bra.s @Continue @Odd: and.b #%1,d2 ; Mask out higher nybble. and.b #%1,d3 ; Mask out higher nybble. @Continue: lea (Pal_LogoInactive).l,a0 ; Load inactive palette. tst.b d2 ; Is the frame inactive? beq.s @DoKiloPalette ; If so, branch. lea (Pal_KiloLogoActive).l,a0 ; Otherwise, load active palette. @DoKiloPalette: lea (pal_buffer+4).w,a1 ; Load palette buffer. moveq #5-1,d4 ; Set loop counter. @KiloLoop: move.w (a0)+,(a1)+ ; Write colors to palette buffer. dbf d4,@KiloLoop ; Loop. lea (Pal_LogoInactive).l,a0 ; Load inactive palette. tst.b d2 ; Is the frame inactive? beq.s @DoSEGAPalette ; If so, branch. lea (Pal_SEGALogoActive).l,a0 ; Otherwise, load active palette. @DoSEGAPalette: lea (pal_buffer+$E).w,a1 ; Load palette buffer. moveq #5-1,d4 ; Set loop counter. @SEGALoop: move.w (a0)+,(a1)+ ; Write colors to palette buffer. dbf d4,@SEGALoop ; Loop. move.b #VINTID_SEGA,d0 bsr.w VInt_Wait cmp.w #5*60,(logos_flashidx).w blt.w Logos_FlashLoop move.b #SCNID_TITLE,(scene_id).w ; Go to the title screen. rts Logos_KiloFlashFrames: dc.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 dc.b $00, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, $00, $01, $00, $00, $00, $00, $01, $01, $00, $00, $01, $00, $00, $00, $01, $11, $00, $00 dc.b $01, $10, $11, $01, $10, $00, $10, $11, $10, $00, $10, $00, $10, $01, $11, $11, $10, $11, $10, $01, $00, $11, $10, $11, $11, $11, $10, $10, $11, $11 dc.b $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11 dc.b $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11 Logos_SEGAFlashFrames: dc.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 dc.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $10, $00, $01 dc.b $11, $10, $00, $10, $11, $01, $11, $01, $01, $11, $01, $11, $10, $10, $11, $10, $01, $11, $10, $01, $11, $10, $11, $00, $01, $11, $10, $11, $11, $11 dc.b $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11 dc.b $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11, $11 Pal_LogoInactive: dc.w $000, $000, $000, $000, $000 Pal_KiloLogoActive: dc.w $EEE, $EAE, $82E, $608, $204 Pal_SEGALogoActive: dc.w $EEE, $EEA, $E82, $C00, $800
I doubt it's the cause of your issue, but FWIW the "blt.w Logos_FlashLoop" should probably be a "bcs.w", since it doesn't seem to be a signed comparison.
I always get confused on when to use bcs or bcc. blt and bgt are just easier for me to understand their condition. But thanks.
Register d3 doesn't seem to actually be checked when loading the Sega palette. Also, wouldn't it be more ideal to just divide d0 by 2 and use the bit shifted out into the carry flag to check if it was odd? Your logic for picking which index to use for the flashing is kinda weird, with the order ending up being 0, 1, 1, 3, 3, 5, 5... Maybe something like this? Code (Text): moveq #%00001,d1 ; Lower nibble lsr.w #1,d0 ; Divide frame by 2 bcs.s @GotIndex ; Branch if it was odd moveq #%10000,d1 ; High nibble @GotIndex: move.b Logos_KiloFlashFrames(pc,d0.w),d2 move.b Logos_SEGAFlashFrames(pc,d0.w),d3 and.b d1,d2 and.b d1,d3 I also assume VInt_Wait is set to take in d0 as the V-INT routine ID?
That would be because I copied the Kilo palette code and didn't change it, whoops. Gotta use a lea, the code and tables are too large to use a move with the pc d0 offset thing and it causes an illegal value when building. No problem though I can just combine this with my old code. No it does not, why did I do that. But yes! This worked, thank you so much!
This has been resolved, my wait loop checks weren't thorough enough. Not a very basic question at all, but hopefully someone will be able to help wit this snag that my Sonic CD Mode 1 project has run into. As part of it, I want to be able to check for a disc in the Mega CD and determine if it's a an audio CD or a planned data disc that will contain FMV data and CD audio. Unfortunately, I'm not having much luck getting it to work. The following code is intended to check for the presence of a disc, and if one is present, check if it's a copy of Sonic CD (or in my case,CD++), or an audio CD with 35 or more tracks. However, so far it doesn't work: whether a disc is present or not, it always returns "audio CD with 35 tracks." I can only guess I may have misunderstood something related to one of the BIOS calls given how sparse the documentation for them is. Either way, I'd appreciate some help. Code (ASM): Init: lea SetupValues(pc),a0 ; pointers to exception entry points lea (_AddressError).w,a1 ; first error vector in jump table moveq #10-1,d0 ; 9 vectors + GFX int .vectorloop: addq.w #2,a1 ; skip over instruction word move.l (a0)+,(a1)+ ; set table entry to point to exception entry point dbf d0,.vectorloop ; repeat for all vectors and GFX int move.l (a0)+,(_TimerInt+2).w ; set timer interrupt address move.b 2(a0),(mcd_timerint_interval).w ; set timer interrupt interval moveq #DriveInit,d0 jsr (_CDBIOS).w ; initialize the drive and get TOC (will start after controller finishes initializing) moveq #0,d0 clear_ram.w SubCPUGlobalVars,sizeof_SubCPUGlobalVars ; clear global variables moveq #id_FileFunc_EngineInit,d0 jsr (FileFunction).w ; initialize the file engine jmp (DriverInit).l ; initialize the PCM driver ; =========================================================================== SetupValues: dc.l AddressError dc.l IllegalInstr dc.l ZeroDivide dc.l ChkInstr dc.l TrapvInstr dc.l PrivilegeViol dc.l Trace dc.l Line1010Emu dc.l Line1111Emu dc.l GFXInt ; GFX int address dc.l RunPCMDriver ; timer int address dc.b 1,$FF ; drive init parameters dc.b 255 ; timer interrupt interval DiscType: dc.b 'SEGADISCSYSTEM ' ; dc.b 'SEGADATADISC ' arraysize DiscType HeaderTitle: dc.b 'SONIC THE HEDGEHOG-CD ' ; dc.b 'SONIC THE HEDGEHOG CD MODE 1 DATA DISC ' arraysize HeaderTitle even ; =========================================================================== Main: addq.w #4,sp ; throw away return address to BIOS usercall loop, as we will not be returning there .delay: jsr (_WaitForVBlank).w ; delay for two seconds to allow drive controller to finish initializing cmpi.b #2*60,(v_vblank_counter).w ; have we waited 120 frames? bcs.s .delay ; branch if not .waitinit: move.w #BIOSStatus,d0 jsr (_CDBIOS).w ; get BIOS status btst #drive_ready_bit,(a0) ; a0 = _BIOSStatus bne.s .waitinit ; branch if drive init hasn't finished btst #no_disc_bit,(a0) ; bit 4, but it always seems to return zero? bne.s .nodisc ; branch if no disc in drive move.w #TOCRead,d0 moveq #1,d1 jsr (_CDBIOS).w ; fetch TOC entry for track 1 tst.b d1 ; (supposed to be 0 if audio track, $FF if data track, but seems to always return 0) beq.w .checktrackcount ; if this is an audio track, it's not a CD-ROM jsr (LoadDiscHeader).w ; (routine hacked into Sonic CD's file engine that reads the first sector of disc) cmpi.w #fstatus_ok,d0 ; was the operation a success? bne.s .nodisc ; if not, assume no disc lea (FileVars+fe_dirreadbuf).l,a1 ; a1 = disc type in header lea DiscType(pc),a2 ; header type we're checking for moveq #sizeof_DiscType-1,d1 jsr (CompareStrings).w ; does the type in the header match? bne.s .checktrackcount ; if not, branch lea (FileVars+fe_dirreadbuf+Domestic_title),a1 ; game title in header lea HeaderTitle(pc),a2 ; header title we're checking for moveq #sizeof_HeaderTitle-1,d1 jsr (CompareStrings).w ; does the title in the header match? beq.s .getfiles ; if so, branch .checktrackcount: cmpi.b #35,(_CDDStatus+CDD_LastTrack).w ; does this disc have at least 35 tracks? bcc.s .audiocd ; if so, we can play music from this CD bra.s .nodisc ; otherwise, we can't use it; assume no disc ; ============================================== .getfiles: moveq #id_FileFunc_GetFiles,d0 bsr.s FileFunction ; load the disc's filesystem .waitfiles: jsr (_WaitForVBlank).w ; file engine only runs during VBlank moveq #id_FileFunc_GetStatus,d0 ; is the operation finished? bsr.s FileFunction bcs.s .waitfiles ; if not, wait addq.b #1,(v_disc_status).w ; 2 = full CD audio and FMV support .audiocd: addq.b #1,(v_disc_status).w ; 1 = CD audio only .nodisc: move.b (v_disc_status).w,(mcd_subcom_1).w ; give disc status to main CPU moveq #'R',d0 move.b d0,(mcd_subcom_0).w ; signal initialization success
Good morning. I continue to do SEEK Engine, development is very early at the moment but still ongoing. I had a doubt/question: I'm following Sonic's physics guide, which is excellent. My question is regarding the resolution and the variables that physics uses. On a Mega Drive the resolution is 320x224, if I want the engine to run at 1920x1080... How should I update the physics accordingly? Using a scalar multiplier? Or is there another way? Thank you so much!!
The physics guide assumes your base unit is 1 pixel. In theory you can just make your higher resolution assets smaller and your camera more zoomed in and work with the original value. But if you're really curious, how much you need to multiply it by is pretty simple. Just divide 1080 by 240 (240's a bit more standard than 224) so your multiplier would be 4.5.
Where can I download sonic sprites in high quality or transparent? I know about The Sprites Resources, but I want to know if there are alternatives. thank you
I'm following this guide: https://info.sonicretro.org/SCHG_How-to:Port_Knuckles_into_Sonic_2 and the error seems to be coming from the steps in the Life Icon mappings section. Before following the CNZ Slot Machines section, I decide to build the ROM, just to test it out so far, and I get an error stating that "PLCID_Tails1up" & "PLCID_Miles1up" are not symbols. The guide is outdated, sure, so I fix it and put the correct PLCIDs in there, rebuild and get an error saying: Code (Text): [...] jump distance too big bne.s ++ ; rts So, I change it back to one + instead of two, and then rebuild. New error shows up: Code (Text): [...] jump distance too big bhs.s return_2AA10 What can I do to fix both of these problems?
Change the ".s" to ".w" for both of them. ".s" indicates a "short" or "byte" branch, which only accepts a signed byte-wide distance to be branched to, which isn't very much, but the instruction only takes 2 bytes. ".w" indicates a "word" branch, which accepts a signed 16-bit word-wide distance, which is a much bigger range, but the instruction takes up 4 bytes.
So I'm trying to make the most out of my Everdrive by using the USB port to record some of the player's data (X pos, Y pos, velocity, etc.), just like how Sonic Team would have back in the 90's (Although they only recorded input timings, I'm using object data for a specific reason.) The issue is that I can't seem to get it to transmit any data. I was using one of the example programs on krikzz's site, ssf-ex-test to reference the code, and VCPTestCENET, to view any data output, but got none. I figured maybe I bit more than I could chew, the program is used for text data and not what I'm doing so I thought I'd take a step back and do something more simple, just send the letter A, but not even that worked. Could someone tell me where I went wrong? Code (Text): usb_port = $A13000 USB_DATA = 226 USB_STATUS = 228 USB_CONFIG = 230 USB_CTRL = 240 USB_READY = 2 lea (usb_port).l,a0 move.w #$8000,USB_CTRL(a0) ; Enable register access move.w #1,USB_CONFIG(a0) ; Set USB config @Wait: move.w USB_STATUS(a0),d1 ; Get USB status. and.w #USB_READY,d1 ; Check if it's ready for a write. bne.s @Wait ; If not, wait. move.b #"A",USB_DATA(a0)