How to expand the life counter in Sonic 2 sms Alright I always hated that you couldn't have more than 9 lives in Sonic 2, so I decided to change that. Note: this is from the wiki version of the disassembly. First look for CapLifeCounterValue in S2.asm. It should look like this: LABEL_25AC: ld a, ($D292) or a ret nz ld a, (LifeCounter) cp $09 ;cap the life display at 9 jr c, + ld a, $09 +: rlca and $1E add a, $10 ld ($DBA9), a ret Now, delete every line after "ret nz" and add this: ld a, (LifeCounter) and $0F rlca and $1E add a, $10 ld ($DBA9), a This sets up the last nibble of the life counter. This is what your code should look like at this point: ld a, ($D292) or a ret nz ld a, ($D292) or a ret nz ld a, (LifeCounter) and $0F rlca and $1E add a, $10 ld ($DBA9), a Alright time for a brief explination, the rlca operand allows the display to be updated, while the other parts of the code updates the display. We need to change it to where it can set another nibble for the counter. Right after "ld ($DBA9), a" add this: ld a, (LifeCounter) and $F0 rrca rrca rrca and $1E add a, $10 ld ($DBAF), a This will allow the "x" on the counter to become the other nibble. That does allow the counter to display the proper numbers, but when Sonic gains a life after 9, it still displays the wrong value in the wrong nibble. So we need to change that. Find Collision_Monitor_Life in the source code, it should look like this: res 1, (hl) ld a, ($D298) inc a ld (LifeCounter), a ld a, SFX_ExtraLife ld ($DD04), a jp LABEL_25AC First, bellow res 1,(hl) add these lines: ld a, (LifeCounter) cp $99 ret z This will allow the game to cap the life counter after 99 lives. Next we need to change these lines: ld a, ($D298) inc a ld (LifeCounter), a To this: ld a, (LifeCounter) add a, $01 daa (LifeCounter),a The "daa" operand is used for counters, which is why the "inc" operand wouldn't work here. After that, save build and enjoy. This is what the routine looks like after everything is added: CapLifeCounterValue: LABEL_25AC: ld a, ($D292) or a ret nz ld a, (LifeCounter) and $0F rlca and $1E add a, $10 ld ($DBA9), a ld a, (LifeCounter) and $F0 rrca rrca rrca and $1E add a, $10 ld ($DBAF), a ret Collision_Monitor_Life: res 1, (hl) ld a, (LifeCounter) cp $99 ret z add a, $01 daa ld (LifeCounter), a ld a, SFX_ExtraLife ld ($DD04), a jp LABEL_25AC
Nice work! One thing I am curious of is; does the game lag slightly more with the extra digit? That's the only reason I could think of as to why they never allowed more than 9 lives (the process of converting hex to decimal for that extra digit), but if it doesn't lag then what other reason is there to not have an extra digit?
I really doubt it adds any lag, given that this code is only run the moment the number of lives changes. I suppose it may have to do with the fact that they wanted to put the cross there. Sonic's face eats up 2 sprites, the cross eats up another and the digit another one, making up for 4 sprites on a single line - 50% of the sprite limit for any given line. Making it any larger would leave little room for other sprites to appear in the same lines as the HUD. The same applies to the timer and the rings counter.
Hello. I downloaded the Sonic 2 disassembly and edited the code. However, in MEKA, it slows the game and causes problems. From the beginning, it works, but the upper half of the screen blinks in the background cyan colour (see screenshot). I wonder which is the problem. After a few seconds, the game restarts or crashes. I would like to point out a mistake in your code. The instruction Code (Text): daa (LifeCounter),a does not exist. At the end of the post, you wrote it correctly: Code (Text): daa ld (LifeCounter), a Also, after Code (Text): ld a, (LifeCounter) and $F0 rrca rrca rrca and $1E add a, $10 ld ($DBAF), a you forgot Code (Text): ret Thank you.
I'm only guessing here but it sounds like something in the code is jumping into nothing. Empty space in the rom is filled in with $FF bytes, which the Z80 decodes as a "RST $38". This has the effect of repeatedly calling into the VDP interrupt handler. You might want to place a breakpoint on the code so that you can step through it and see where it's going.
Oops, I posted this early in the morning and forgot to proof read it. :v: Also I ported the code from Sonic Chaos if that matters. But I didn't test the ROM in MEKA, but in Fusion and Gens+. (My gf doesn't want me to download any more emulators. :\) It works fine in both emulators. Does MEKA handle VRAM differently from Fusion/Gens+ since it has debugging options?
Perhaps. I quote myself from the screenshot topic: The edges of the levels disappear. And if I poke the code of the monitors, the game crashes. You might want to place a breakpoint on the code so that you can step through it and see where it's going. Well, I did this in MEKA debugger, but I didn't find anything.
No, that's NTSC/PAL shenanigans, and I think Meka defaults to PAL (while usually Fusion defaults to NTSC). That said, gotta love how that snippet Maxim posted wouldn't work anyways (the OR should be an AND). Otherwise that code should work even with interrupts disabled, since the F flag gets set when vblank starts, regardless of the interrupt status (and gets cleared after the port is read).
Perhaps you should post the corrections in that thread, guests can post on smspower. It's not good if a snippet which is supposed to be a reference is wrong... Don't be shy, we're all friends on smspower
Well, I think it will be good if everyone knows what I'm doing. So I'll link to the source code. I'm using Glitch's disassembly and only modified the main "s2.asm" file. Download (56 KB) Password: sonicsez It contains 2 files, the "s2.asm" itself and a list of differences with the original, made with a .BAT file, called "diff.asm". However, in "s2.asm" I marked all my modifications with the text Code (Text): ;***CHANGED*** before it, so you can search for this word in your editor. Still, I don't know why the limits of the level don't work, if I haven't touched anything related to them.
After I add some lines of code, this happens: Using MEKA Debugger, I caught the "offending" code. That damn $FF byte is at 0x75C00. Nearly the end of the ROM Normally, the counter shouldn't go there. What makes the counter go to the end of the ROM? Still I don't know, but I guess what happens. When assembling, the command line gives me these message: Code (Text): Assembling... MEM_INSERT: 2. write into $3d16 (old: $22, new: $00). MEM_INSERT: 2. write into $3d17 (old: $11, new: $00). MEM_INSERT: 2. write into $3d18 (old: $d5, new: $00). MEM_INSERT: 2. write into $3d19 (old: $af, new: $00). MEM_INSERT: 2. write into $3d1a (old: $32, new: $00). MEM_INSERT: 2. write into $3d1b (old: $10, new: $00). MEM_INSERT: 2. write into $3d1c (old: $d5, new: $00). MEM_INSERT: 2. write into $3d1d (old: $18, new: $00). MEM_INSERT: 2. write into $3d1f (old: $2a, new: $00). MEM_INSERT: 2. write into $3d20 (old: $74, new: $00). MEM_INSERT: 2. write into $3d21 (old: $d1, new: $00). MEM_INSERT: 2. write into $3d22 (old: $09, new: $00). MEM_INSERT: 2. write into $3d23 (old: $22, new: $00). MEM_INSERT: 2. write into $3d24 (old: $11, new: $00). MEM_INSERT: 2. write into $3d25 (old: $d5, new: $00). MEM_INSERT: 2. write into $3d26 (old: $af, new: $00). MEM_INSERT: 2. write into $3d27 (old: $32, new: $00). MEM_INSERT: 2. write into $3d28 (old: $10, new: $00). MEM_INSERT: 2. write into $3d29 (old: $d5, new: $00). MEM_INSERT: 2. write into $3d2a (old: $2a, new: $f0). MEM_INSERT: 2. write into $3d2b (old: $10, new: $ff). MEM_INSERT: 2. write into $3d2c (old: $d5, new: $10). MEM_INSERT: 2. write into $3d2d (old: $ed, new: $00). MEM_INSERT: 2. write into $3d2e (old: $5b, new: $f0). MEM_INSERT: 2. write into $3d2f (old: $16, new: $ff). MEM_INSERT: 2. write into $3d30 (old: $d5, new: $10). MEM_INSERT: 2. write into $3d31 (old: $0e, new: $00). MEM_INSERT: 2. write into $3d32 (old: $00, new: $e0). MEM_INSERT: 2. write into $3d33 (old: $cb, new: $ff). MEM_INSERT: 2. write into $3d34 (old: $7a, new: $20). MEM_INSERT: 2. write into $3d35 (old: $28, new: $00). MEM_INSERT: 1. write into $3d36 (old: $00, new: $e0). MEM_INSERT: 2. write into $3d37 (old: $0d, new: $ff). MEM_INSERT: 2. write into $3d38 (old: $af, new: $20). MEM_INSERT: 2. write into $3d39 (old: $ed, new: $00). MEM_INSERT: 2. write into $3d3a (old: $52, new: $f0). MEM_INSERT: 2. write into $3d3b (old: $22, new: $ff). MEM_INSERT: 2. write into $3d3c (old: $10, new: $fc). MEM_INSERT: 2. write into $3d3d (old: $d5, new: $ff). MEM_INSERT: 2. write into $3d3e (old: $dd, new: $c0). MEM_INSERT: 2. write into $3d3f (old: $7e, new: $ff). MEM_INSERT: 2. write into $3d40 (old: $12, new: $10). MEM_INSERT: 2. write into $3d41 (old: $99, new: $00). MEM_INSERT: 2. write into $3d42 (old: $dd, new: $c0). MEM_INSERT: 2. write into $3d43 (old: $77, new: $ff). MEM_INSERT: 2. write into $3d44 (old: $12, new: $10). MEM_INSERT: 2. write into $3d45 (old: $21, new: $00). MEM_INSERT: 2. write into $3d48 (old: $22, new: $00). MEM_INSERT: 2. write into $3d49 (old: $6f, new: $00). MEM_INSERT: 2. write into $3d4a (old: $d3, new: $00). MEM_INSERT: 2. write into $3d4b (old: $22, new: $00). MEM_INSERT: 2. write into $3d4c (old: $16, new: $00). MEM_INSERT: 2. write into $3d4d (old: $d5, new: $00). MEM_INSERT: 2. write into $3d4e (old: $c9, new: $f0). MEM_INSERT: 2. write into $7ff0 (old: $bf, new: $54). MEM_INSERT: 2. write into $7ff1 (old: $06, new: $4d). MEM_INSERT: 2. write into $7ff2 (old: $80, new: $52). MEM_INSERT: 2. write into $7ff3 (old: $0e, new: $20). MEM_INSERT: 2. write into $7ff4 (old: $be, new: $53). MEM_INSERT: 2. write into $7ff5 (old: $ed, new: $45). MEM_INSERT: 2. write into $7ff6 (old: $b3, new: $47). MEM_INSERT: 2. write into $7ff7 (old: $c9, new: $41). Free space at $13f80-$13fff. Free space at $17e00-$17fff. Free space at $1bfd0-$1bfff. Free space at $1fab4-$1ffff. Free space at $23c72-$23fff. Free space at $27e51-$27fff. Free space at $2b812-$2bfff. Free space at $2fa48-$2ffff. Free space at $33d9d-$33fff. Free space at $37d0c-$37fff. Free space at $3b723-$3bfff. Free space at $3fc5e-$3ffff. Free space at $43eda-$43fff. Free space at $47e00-$47fff. Free space at $4be06-$4bfff. Free space at $4fc2a-$4ffff. Free space at $53c60-$53fff. Free space at $57f9a-$57fff. Free space at $5b900-$5bfff. Free space at $5fb06-$5ffff. Free space at $633cc-$63fff. Free space at $67f06-$67fff. Free space at $6bd8a-$6bfff. Free space at $6f719-$6ffff. Free space at $73fac-$73fff. Free space at $77732-$77fff. Free space at $7bbe7-$7bfff. Free space at $7ffe3-$7ffff. 27534 unused bytes of total 524288. Total 524288 additional bytes (from headers and footers). Total size 1048576 bytes. Linking... ========================== Build Success. ========================== Presione una tecla para continuar . . . So I guess there isn't space in the first two blocks (both dedicated to the main code of the game) and the assembler overwrites some bytes, causing it to crash. I'll see if I can compress/simplify the code in some way.
Yeah. That's basically what's happening. You've added some code which is overflowing into $3D16. The assembler is overwriting your code with the acceleration constants ("accel_values_right.bin"). Incidentally, the code that enforces the camera limit is also around that area. That's probably the cause of your level bounds issues. There's precious little free space in the first two ROM banks. If you can get away with it, you'd be better off putting your new code in one of the later banks (which have plenty of free space) and swapping it in as you need it.
Thanks, but how to do this? Just call the label, or I need to somehow call the bank? Also, now I got a weird error in the command line. It never happened before and there's no way for me to ged rid of it. Code (Text): MEM_INSERT: Origin ($4000) overflows from bank (1). Perhaps it has something to do with the .org at $3D16? I don't know, but this error keeps going on with or without that .org label. (Edit: Minor error)
^ I've seen that error plenty of times while modifying code. The compiler is telling you that the stack pointer is literally overflowing with data, due to recursive function calls or mis-matched pushes to the stack. I got this problem when I had too many ret operands in my code. And don't you have to page in the bank that contains the free space you want to use? (Like paging in bank 08 if you wanted to use the free space at $23C72 and then setting it to an empty offset?)
That error means that you're including data in a bank which is overflowing the bank boundary. Each bank is 16KB (16384 bytes) in size. The data is simply overflowing the 16,384th byte. It doesn't have anything to do with the stack pointer. WLA-DX doesn't perform any stack analysis. It's the programmer's job to maintain the stack. If you happen to execute too many RETs or forget to pop something off you'll encounter some strange bugs. Such is the nature of low-level development; it's not a flaw in the assembler. As for swapping in a bank: you need to write the bank number into one of the paging registers. This changes the part of ROM that is visible in each 16KB slot of the Z80's address space. WLA-DX can automatically calculate the bank number for you. If you prefix a label with a colon WLA-DX will replace it with the bank number: Code (Text): LD A, :SomeLabel
Thanks. Now I can successfully link to code in other banks. I tried it and it works. Everything works perfectly except for one thing. In the final boss, in less than a minute of play, the game crashes. The sprites grow larger and then the game gets stucks or reboots.