I'm a little confused here, and I'm slightly afraid of goofing anything up, so I've refrained from using any .exe files contained within the SA Tools Package. Any tutorials or help? Thanks.
The easy way, is just using the .bat files, so you can skip the issue of the the path name, the important part, is before the split put all files in the SADX folder, and also use a clean SADX.
The tools in SA Tools are in separate folders for each version of the games supported. So you pick the folder that matches the game you want to edit, and copy the contents of the folder into the game's main folder (for Dreamcast, this is the folder with 1ST_READ.BIN, for PC, this is the folder with sonic.exe or sonic2app.exe). After running the .bat files to split data from the game, you can use the other tools, which are all described at the SA Tools wiki page.
Jumping back to Sonic 2 for a minute... You all know the flipping blocks in the walls of Casino Night Zone, right? Well, I've been editing them and I just noticed... The very first frame isn't in the bin file with the rest! Any idea where that is? Also, what would be the most effective way to edit art that doesn't have mapping like that? Tile Layer Pro is a little dated. XD
I'm not sure what you mean by that, all the frames look like they're there to me... As far as tile editors, I use YY-CHR myself. The .NET version has some nice features like a pattern editor (create a pattern 4 width 4 height vertical orientation to display the CNZ tiles), but there's a bit of untranslated Japanese in the UI. The original version is better translated. In either case, you have to select the 4bpp MSX format for MD games. Unfortunately neither version supports importing MD palettes directly, though a converter would be simple for me to make.
Another question here, bit of a long one with examples so bare with me. Is there a way to have an object load different art (though using the same mappings, as the art works using them) for an object based on a check? Like, simply loading the art from a different file? For example, say I gain a shield (which in the monitor code sets "#1,($FFFFFE2C).w"), which of course uses the art from "shield.bin". Would I be able to use art from, let's say "shield2.bin" if the shield flag was set to "#2,($FFFFFE2C).w" instead? Whereas in the case of the Character adding guide, changing what art the character used was simply down to replacing a section relating to "Art_Sonic" with this: Code (ASM): cmpi.b #$01, ($FFFFFFFE).w ; is the multiple character flag set to $01 (Metal Sonic)? bne.s SonicArtLoad ; if not, load Sonic's art lea (Art_MetalSonic).l,a1 ; load Metal Sonic's art bra.s ContLoadPLC ; branch to rest of code SonicArtLoad: lea (Art_Sonic).l, a1 ; load Sonic's art ContLoadPLC: Which then got the art location from these: Code (ASM): ; --------------------------------------------------------------------------- ; Uncompressed graphics - Sonic ; --------------------------------------------------------------------------- Art_Sonic: incbin artunc\sonic.bin; Sonic even ; --------------------------------------------------------------------------- ; Uncompressed graphics - Metal Sonic ; --------------------------------------------------------------------------- Art_MetalSonic: incbin artunc\msonic.bin; Metal Sonic even I can't seem to find a similar scenario for the shield's art, as searching for "Nem_Shield" only returns this: Code (ASM): Nem_Shield: incbin artnem\shield.bin ; shield even And then this in a seperate PLC related file: Code (ASM): dc.l Nem_Shield ; shield dc.w $A820 From what I'm looking at and what I know, I can't seem to figure out a way to choose an art-file based on a check in the way you can with character art, and it has me pretty stumped. Any advice?
Okay, so to make this question basic, I'm trying to make Tails fall slow if a certain flag is set. I've tried all sorts of things, and I haven't been able to get it to work. Is there something simple I'm overlooking?
The main issue with what you are looking for, is compression, the reason why Sonic's art is so successful at loading; is simply because his art is completely uncompressed within the ROM, hence, it's a simple transfer to VRAM, your shield art on the other hand; is compressed in the "Nemesis" format, which is a "huffman" varient of encoding and is quite time consuming during decompression, so you might very well find that your shield object will load onto screen before the art can decompress on time, resulting in glitched graphics for a short few frames. It is recommended to have your shield art either uncompressed in the ROM and transfered directly (just like Sonic's art), or, if you are anal about ROM space and wish to keep it down, then try a compression format that is quicker to decompress, likethe "Kosinski" format, which is a "Lempel–Ziv–Storer–Szymanski" (LZSS) format and is pretty fast as it deals mainly with uncompressed data, retraced backwards. I recommend uncompressed on the basis that; it's quicker to process, and easier to code, here's a simple example of transfering uncompressed shield art to VRAM at address 0020: Code (Text): move.b ($FFFFFE2C).w,d0 ; load shield flag cmp.b ($FFFFFF90).w,d0 ; has the shield changed? beq NoShieldArt ; if not, branch move.b d0,($FFFFFF90).w ; update shield flag lea (Shield1Art).l,a0 ; load uncompressed shield 1 data address moveq #$0F,d7 ; set number of tiles to load (0x10 tiles) cmpi.b #$01,d0 ; is shield 1 selected? beq Shield01Art ; if so, branch lea (Shield2Art).l,a0 ; load uncompressed shield 2 data address moveq #$03,d7 ; set number of tiles to load (0x04 tiles) Shield01Art: lea ($C00000).l,a5 ; load VDP data port lea $04(a5),a6 ; load VDP address port move.l #$40200000,(a6) ; set VDP write mode and address LoadShieldArt: move.l (a0)+,(a5) ; write 1st line of 8 pixels move.l (a0)+,(a5) ; write 2nd line of 8 pixels move.l (a0)+,(a5) ; write 3rd line of 8 pixels move.l (a0)+,(a5) ; write 4th line of 8 pixels move.l (a0)+,(a5) ; write 5th line of 8 pixels move.l (a0)+,(a5) ; write 6th line of 8 pixels move.l (a0)+,(a5) ; write 7th line of 8 pixels move.l (a0)+,(a5) ; write last line of 8 pixels dbf d7,LoadShieldArt ; repeat until all tiles have been loaded to VRAM NoShieldArt: I recommend placing this code after the lable "loc_D50:", that's in V-blank, so there's no chance of graphical glitches, now, the "40200000" you see is the VRAM write address, I've chosen VRAM 0020 as an example, 0020 is where the level art is usually loaded, so you may want to change that to a different VRAM address, also in this example, I've used RAM address FFFFFF90 to store a redraw flag, if you're using that RAM address for something else then you'll want to consider a different RAM address, otherwise that'll be fine, and finally, the numbers being moved to d7 act as a tile counter, they set how many tiles of your shield art to transfered, there's two of them, one for shield 1, and the other for shield 2, you'll want to change those too. I'll leave you to figure the rest out as I'm sure you'll want to experiment, but that would be the basic principle for loading uncompressed art.
If you look in both Obj02_MdAir: and Obj02_MdJump: you'll see these lines right under the call to ObjectMoveAndFall: Code (ASM): btst #6,status(a0) ; is Tails underwater? beq.s + ; if not, branch subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10) + What this does is test Tails' underwater flag (bit 6 in the status byte), and if it's set, subtracts $28 from his y_vel, to reduce the $38 gravity that ObjectMoveAndFall adds. You can add your code right near this (just remember to do both places) to check your flag and reduce gravity by an amount of your choosing. However, note that when Tails is underwater, his gravity is only $10, so if you subtract too much, he could end up with zero or negative gravity, unless you check for underwater in your code as well.
So, with tweaks done to it, is this the sort of thing I'm aiming for? ("68200003" is VRAM A820, which is the original shield's VRAM...I think. And I assume tiles refers to number of tiles in the art file, which is 36 for both so in hex that'd be 24). Code (ASM): LoadShield: move.b ($FFFFFE2C).w,d0 ; load shield flag cmp.b ($FFFFFF90).w,d0 ; has the shield changed? beq NoShieldArt ; if not, branch move.b d0,($FFFFFF90).w ; update shield flag lea (Art_Shield).l,a0 ; load uncompressed shield 1 data address moveq #$24,d7 ; set number of tiles to load (0x10 tiles) cmpi.b #$01,d0 ; is shield 1 selected? beq Shield01Art ; if so, branch lea (Art_Shield2).l,a0 ; load uncompressed shield 2 data address moveq #$24,d7 ; set number of tiles to load (0x04 tiles) Shield01Art: lea ($C00000).l,a5 ; load VDP data port lea $04(a5),a6 ; load VDP address port move.l #$68200003,(a6) ; set VDP write mode and address LoadShieldArt: move.l (a0)+,(a5) ; write 1st line of 8 pixels move.l (a0)+,(a5) ; write 2nd line of 8 pixels move.l (a0)+,(a5) ; write 3rd line of 8 pixels move.l (a0)+,(a5) ; write 4th line of 8 pixels move.l (a0)+,(a5) ; write 5th line of 8 pixels move.l (a0)+,(a5) ; write 6th line of 8 pixels move.l (a0)+,(a5) ; write 7th line of 8 pixels move.l (a0)+,(a5) ; write last line of 8 pixels dbf d7,LoadShieldArt ; repeat until all tiles have been loaded to VRAM NoShieldArt: And then I went and took out the "Nem_Shield" part and put this under "Art_Sonic" (I decompressed the art files in "The Sega Data Compressor" and put then in the artunc folder). Code (ASM): ; --------------------------------------------------------------------------- ; Uncompressed graphics - Shields ; --------------------------------------------------------------------------- Art_Shield: incbin artunc\shield.bin ; shield even Art_Shield2: incbin artunc\shield2.bin ; shield even After this, is it simply a case of replacing the jump to "DisplaySprite" in this part below with one to the new "LoadShield", or is there a bit more to it? Code (ASM): Obj38_Shield: ; XREF: Obj38_Index tst.b ($FFFFFE2D).w ; does Sonic have invincibility? bne.s Obj38_RmvShield ; if yes, branch tst.b ($FFFFFE2C).w ; does Sonic have shield? beq.s Obj38_Delete ; if not, branch move.w ($FFFFD008).w,8(a0) move.w ($FFFFD00C).w,$C(a0) move.b ($FFFFD022).w,$22(a0) lea (Ani_obj38).l,a1 jsr AnimateSprite jmp DisplaySprite
The VRAM value 68200003 is E820, what you want is the VRAM value 68200002 for A820. Correct, except, you'll want the numbers as 23 in the code, as 0 counts as one tile: Code (Text): moveq #$23,d7 ; set number of tiles to load (0x24 tiles) That object code can stay exactly as it is, what's important though is... So your art loading code: You'll put that directly after the lable "loc_D50:", like so: Code (Text): ... ... move.w #$7000,(a5) move.w #$83,($FFFFF640).w move.w ($FFFFF640).w,(a5) move.b #0,($FFFFF767).w loc_D50: LoadShield: move.b ($FFFFFE2C).w,d0 ; load shield flag cmp.b ($FFFFFF90).w,d0 ; has the shield changed? beq NoShieldArt ; if not, branch move.b d0,($FFFFFF90).w ; update shield flag lea (Art_Shield).l,a0 ; load uncompressed shield 1 data address moveq #$24,d7 ; set number of tiles to load (0x10 tiles) cmpi.b #$01,d0 ; is shield 1 selected? beq Shield01Art ; if so, branch lea (Art_Shield2).l,a0 ; load uncompressed shield 2 data address moveq #$24,d7 ; set number of tiles to load (0x04 tiles) Shield01Art: lea ($C00000).l,a5 ; load VDP data port lea $04(a5),a6 ; load VDP address port move.l #$68200003,(a6) ; set VDP write mode and address LoadShieldArt: move.l (a0)+,(a5) ; write 1st line of 8 pixels move.l (a0)+,(a5) ; write 2nd line of 8 pixels move.l (a0)+,(a5) ; write 3rd line of 8 pixels move.l (a0)+,(a5) ; write 4th line of 8 pixels move.l (a0)+,(a5) ; write 5th line of 8 pixels move.l (a0)+,(a5) ; write 6th line of 8 pixels move.l (a0)+,(a5) ; write 7th line of 8 pixels move.l (a0)+,(a5) ; write last line of 8 pixels dbf d7,LoadShieldArt ; repeat until all tiles have been loaded to VRAM NoShieldArt: move.w #0,($A11100).l movem.l ($FFFFF700).w,d0-d7 movem.l d0-d7,($FFFFFF10).w movem.l ($FFFFF754).w,d0-d1 ... ... Now unless there's something we've missed, it should in theory, work well, get back to me once you've tried it out.
Oh, DIRECTLY under, I for some reason thought you meant under what was already in loc_D50. Didn't actually try it though since I didn't have much time to build and test but I imagine that would've gone horribly wrong XD I also for some reason keep forgetting tile 0 counts as the first tile...anyway, thank you very much for the corrections and thanks a bunch for the help! Worked without any issues ^_^ I originally had the second shield type load an edited invincibility art, since my hack at current isn't using invincibility, but figured it'd be better to get it to literally load the shield object with a different art file in the end just incase I a) Decide to use invincibility again or b) Want to add more types of shield.
Thanks very much, Mainmemory. This really helped, and I actually learned something really useful; that is, distinguishing between the different types of conditional branches. Some would argue I should've known that befor going in, but meh, I like to learn by doing. I appreciate everyone's help. What I was doing is essentially giving Tail's a basic flight ability in Sonic 2, and I got it working minus the physics being somewhat off. I also limited it rather strictly as the game wasn't designed around it so it's quite broken. with that said, my question is, would I have been better off porting Sonic 3's code for it in, and if so, how much easier/harder would that have been that building off of what was already there? EDIT: While I'm at it, do you know anything about editing the background scrolling in levels? Anyone?
Another random question here, how would I have Sonic 1's "Life Icon" use the 1-Up Monitor Art instead? (Since it's the same thing). Those 4 art tiles the life icon are using would really come in handy for getting something working. EDIT: Or the alternative, have the 1-up monitor icon tiles be/stay on screen where the life icon normally goes. Unless that's how it's normally done anyway, then it's not really an alternative XD
So.. I don't know if this is really a "Basic" question, but does anyone know anything about adding an actual act 3 properly into a zone in Sonic 2? If so, what if that third act should be like Scrap Brain Zone in that it used a different set of data?
Adding on to this, I'm at the moment life-iconless (though not fussed right now) since I now have the minutes numbers there...which work perfectly! Except...sometimes when loading Green Hill 1 (starting the game basically) they aren't there...but appear when the time goes up a second to 00:01. Leading on from this, when I take longer than a minute, whatever's in the "minutes" tiles gets carried over to the next stage. Again though, they revert after the first second. For example, if the previous level took 1 minute, it'd say "01:00" until "00:01", if I took 7 minutes, "07:00" until 1 seconds passes, etc. So essentially, there's some sort of loading delay for the minutes figures. Not really sure what to do here. Other than literally moving the life icon mapping to where the minutes would go (as of course that's the VRAM it's using), this is the only change I've made to it: Code (ASM): loc_1C734: move.l #$7A800003,d0 moveq #0,d1 move.b ($FFFFFE23).w,d1 ; load minutes bsr.w Hud_Secs move.l #$5EC00003,d0 moveq #0,d1 move.b ($FFFFFE24).w,d1 ; load seconds bsr.w Hud_Secs The only changes from the original here being of course, the VRAM address and that first "bsr.w Hud_Secs" which was originally "Hud_Mins", which I needed to change to have it actually update both of the 0s I'm pretty sure (allowing it to go up to and show 10 and above).
It would be much easier to make four acts than three, and either way you'd have to expand a bunch of tables and alter the formula used for indexing those tables. As for act 3 using different art, it's as simple as finding the code that loads the data you want, and adding an exception to make it load a specific set of data in that level/act. It sounds like what you're after might be easier with the MTZ3 solution: make a new zone that calls itself act 3 on the title card/score tally.
I was hoping to avoid that because all the zones in Sonic 2 proper are already (most likely) going to be used, but I guess extending the Zone Tables won't be the worst crime I've committed in Sonic Hacking. especially since Sonic 2 itself did it. So, I asked this before and I think it got missed; does anyone here know how the background layer scrolling works well enough to explain it to me? I've got a level almost finished, but the background has buildings that are moving all at different speeds, and it quite irks me.
Okay, quick question here. Although I fear that the answer would be "Port the S3K camera manager over". Does anyone know how to make the whole screen redraw itself without making it flash in Sonic 2? For example, you know in S3 at the end of Angel Island 2 with that plane dropping the bombs? Sonic runs and when reaches a certain distance, Sonic and Tails and the plane (and bombs) and the camera goes back really quick. The long time you're running is actually quite short, it just keeps resetting itself, you just don't notice it. I've got a similar thing in my hack going and it works; only problem is when it pulls this stunt off, the screen flashes (only 1 frame) but it is noticable. This happens when the RAM dirty_flag is set. It then obviously refreshes the whole screen, but causes this flash. Now, if I don't move 1 to dirty_flag, it still works and there is no flash, but then if you're moving vertically at all, the tiles get glitched a little bit, and will remain glitched untl it goes off-screen (going back to it and it's fine). If just moving horizontly, its all good, but no doubt when someone comes to play this, they'll jump and notice it. Any ideas?