Page 1 of 1

Text output in Kid Icarus status screen

Posted: Sat Apr 12, 2014 12:29 pm
by mikaelmoizt
Hello! I hope you can bear this n00bish question :)

Ok, so I am working on a hack that involves adding text inside the pause screen in Kid Icarus. (No, not changing it. Adding text.)
I got everything set up for a seperated subroutine that will execute upon pressing the start button.

The issue is that, unlike with my hack of SMB, there are no shortcuts in VRAM for text output ($0300-$03FF), it outputs all text thru $2007 instead.

Basically, I would like to do something like this:

LDA #$22
STA $2006
LDA #$08
STA $2006
LDA $whatever
STA $2007
RTS

So, once the pause screen is drawn, and I try to make writes to the screen, the game crashes. (Or if I modify the code to not write to $2006, nothing at all happens)
I kinda know why this happens (sort of), but is there a way to fix this? Am I missing something?

Re: Text output in Kid Icarus status screen

Posted: Sat Apr 12, 2014 1:44 pm
by Kasumi
So if I wanted to program this myself, in a game I wrote, I'd know how to do it and could probably help you with what you've given me.

Code: Select all

bit $2002;Only needed if the game is really strange, and doesn't double write to $2006/$2005 always
lda mirrorof2000;The previous value stored to $2000 which I'd hope
;the game has stored somewhere
and #%11111011;Clear this bit so writing to $2007 increments by 1, not 32
sta $2000;Store to the register so the value takes effect
sta mirrorof2000;And the mirror
;The above may not be necessary if you know that bit is already cleared

lda #HIGHBYTEOFWHERETODRAWTEXT
sta $2006
lda #LOWBYTEOFWHERETODRAWTEXT
sta $2006

ldy #$04;Length of text to add
textloop:
lda TEXTTOADD,y
sta $2007
bpl textloop


;Elsewhere, where the code won't run into it
TEXTTOADD:
.db 'o', 'l', 'l', 'e', 'H';Reversed to avoid a compare
But since this is a hack, you haven't really provided enough information to make it easy to help unless you expect us to disassemble the game to find things you've already found.

Where/what exactly/how are you inserting? HOW does it crash? Infinite loop? Running into data? Is there free space in the rom? Are you sure where you're putting stuff is free, and is not a string of $FFs that's actually needed by the game?

One potential issue is that what you're adding is making it so the game's NMI takes longer and ends up writing to $2007 while the game is rendering which would crash it.

But then again, this game leads me to believe it draws its pause screen by disabling rendering because it draws it too fast for it to be done in the small vblank period. I bet you know that! I bet you've found exactly where the routine that draws the pause screen is! Why not post the relevant addresses? Help us help you. :wink: Another thing that might be wrong, (since you say you're trying to draw your own text AFTER the screen is drawn) is that you're trying to draw after the pause screen render routine has turned PPU rendering back on causing a similar problem to the first potential issue. That's if you're trying to hack the routine that draws it directly.

Edit: Or, if you have no idea where the actual screen is drawn (or if you know where it is, but have simply put your code in a separate subroutine totally after that is done), the issue is almost certainly writing $2007 while rendering. The reason I guess this is because you have you have a separate routine that is run while start is pressed, which doesn't make it sound like you're hacking the draw routine directly. Because if that WERE the case, start would have already been detected to begin it, and you wouldn't need to do that.

tl;dr: More info, please.

Re: Text output in Kid Icarus status screen

Posted: Sat Apr 12, 2014 3:32 pm
by mikaelmoizt
Oh thank you. I will look at the code you pasted.
Ofcourse I will share more information on this.
Once I get this to look anything like what I want, there is locations in code and sourcecode to be pasted here for future hacking pleasures.

The ROM I am using is the Kid Icarus (E).
What I am trying to add is a "peek and change" kind of system where you can edit RAM values while game is running. Why? Because it looks really cool :)
I wanted the game to have the option of the "debug" mode rather than always enabled.

At the start of the game, I added 2 options (more like one with possibilty to expand if there is a need). No big chore changing amount of text there.

My starting JSR originates from $EE71 where I replaced JSR $EB39 to my own routine @ $FD20. $1FD30 in ROM file. There is a large chunk of $00 and $FF located here.
Also, since I replaced code, I copied what was originally @ $EE71 and put it first in my subroutine so nothing will mess up. (JSR $EB39)
Code near $EE71 has to do with polling and saving joypad input to zeropage locations.
So, every frame, this jump occurs and checks if PauseMode ($38) is active and if so, check my DebugActive flag ($6F0) is set.

If not -> Reurn and load the standard pause screen if START was pressed. Yes, this method is a bit backwards, but there is no easy way to rewrite code for "what happens when START is pressed" in any other place (or I just haven't found it). So technically, my routine triggers on the PauseScreen active flag rather than START was pressed.
Data for this screen can be found @ $E96D and is read @ $EA4B. This is where the output happens. Also, if you take a look at the code in a debugger, you can see how it becomes a bit more tricky with LDA ($08),Y. These (two) memory location seems to handle more than the pause screen too (bank number?). I haven't had the patience to find out more about this.

If DebugActive is true -> jump to a routine located @ $FD50 that will do exactly the same as above, but read data located elsewhere so that the design can be changed to make room for my system. It doesnt matter right now where it's placed in code. All I can say is that it was a timeconsuming task to alter the graphics.

This is where I am right now.
After the (slightly messed up) pause screen gets loaded I now would like to print out text and values, update somehow and add a cursor for editing. There might be some need of conversion for >09 values later.

Here is where the crash occurs when trying to write to PPU. Screen gets misaligned and everything stops. I never actually needed to deal with the PPU writes (!) and such, therefore I am a NES noob.. with many hours of experience ;)

I hope this helps.

Re: Text output in Kid Icarus status screen

Posted: Sat Apr 12, 2014 6:51 pm
by Kasumi
Aight. So almost definitely it's crashing because you're writing to $2007 while rendering. (or... like the code you added is not in the fixed bank, but it seems like that's a thing you'd know about. I'm gonna... not check that out unless I really have to!) The deal is you can't write to $2007 at anytime. You can write to it when rendering is disabled. You can write to it for a short time after vblank begins (usually when the NMI routine fires, if NMIs are enabled). If you're aware of this, tell me so! If not, here's a plan that may or may not work because I don't have access to what you're doing.

First, ask yourself this question: Is it possible for my pause check code (that also writes $2007) to run on a frame where I can actually see the pause screen (instead of like... black)? If yes, you're writing to $2007 during rendering, no question. Unless... the code you said was doing an identical thing (using different data) to the pause screen already disables rendering if which case I have no idea, I'd have to look at the patch.

If yes, here's a super hacky plan to try to fix it.
1. I'm assuming your debug active flag currently has two states. Zero (we'll say for off), and non zero (we'll say for on).
2. Based on this assumption, you want to give it a third state. #$00 = off, #$01 = on, have not drawn pause screen, #$02 = on, have drawn pause screen.

Your routine that hooks the pause screen probably looks something like this:

Code: Select all

JSR $EB39;Junk copied from the original EE71 
lda $38;check pause flag
beq PauseStubEnd;if zero, do nothing
lda $06F0;Check debugflag
beq PauseStubEnd

LDA #$22
STA $2006
LDA #$08
STA $2006
LDA $whatever
STA $2007

PauseStubEnd:
rts
Of course, that means you'll end up writing to $2007 during rendering at some point. Because if this runs every frame, and rendering is not disabled every frame then...

3. So try changing it to something like this:

Code: Select all

JSR $EB39;Junk copied from the original EE71 
ldy $06F0;Check debugflag
beq PauseStubEnd;If zero, do nothing
;If here, debug mode is active
lda $38;Check pause mode
bne PauseStubCheckDebug;if active, continue
;If here, debug mode is active,
;But the game is NOT paused
lda #$01
sta $06F0;Set debugflag to on, have not drawn pause screen
;We do that every time the game isn't paused
;So the next time the game is paused
;We'll know to draw the screen just once...
bne PauseStubEnd;bne will always branch here. Exit routine, because game is not paused. 

PauseStubCheckDebug:
;If here, the game is paused
;and debugmode is enabled.
;Debugmode flag is still in y
dey;If after subtracting 1, it's still above 0, that means it was 2.
bne PauseStubEnd;Which means we already drew the pause screen and shouldn't again
;If here, debug flag is 1. Debug is on, we're paused, but we haven't drawn the extra stuff.

lda #$00;DISABLE RENDERING!
sta $2001;
;The reason we do the whole song and dance
;with the extra debug state
;Is that if rendering was disabled
;every frame, some odd things
;might prevent the player
;from seeing the screen!

;The extra state allows us to
;disable it ONCE to draw
;and then the text will 
;remain there without
;us drawing it again

;bit $2002;Try it without first, if you're tight on space. if it still fails, try with
;As stated in the previous post, it's only REALLY needed in weird cases

LDA #$22
STA $2006
LDA #$08
STA $2006
LDA $whatever
STA $2007

lda #%00011110;Turn rendering back on
sta $2001;I think this is how Kid Icarus would have it set.
;If not, read the docs here to get a better value
;http://wiki.nesdev.com/w/index.php/PPU_registers#Mask_.28.242001.29_.3E_write

lda #$02;Set debug mode flag
sta $06F0;to on, have drawn pause screen.
PauseStubEnd:
rts
It's commented, but the short version is the new checks set it up so
1. When the game is not paused, your debug flag knows.
2. Thanks to the above, you can detect the first frame of being paused
3. When you've drawn the screen, you can detect that and not draw it again.

Be aware! The above code is based entirely on a guess. I have not run this game through a debugger, yet. (I'll only do that if I need to, and it won't take me ALL DAY to figure out.) There are all kinds of things that could go wrong, like $EB39 returns a value in A, X, or Y or sets flags that you're destroying with your routine before it gets used after your own RTS. (which would bring it back to the next thing that would use $EB39 info.) But I assume you checked that. (If you didn't or aren't sure there's a fix for that by storing all of that to the stack, then restoring it all when you finish. It's the next thing I'd try if this doesn't work.) Also, it could be this doesn't crash, but you see nothing changed on the pause screen. Which probably means your code is drawing to the pause screen before the pause screen is fully drawn, and then it's overwritten by the actual pause screen. (Which you can easily fix by just waiting more frames to draw yours.)
I haven't had the patience to find out more about this.
Err... you need to find it, or you should give up. Because reading your plan, it sounds much harder than just this.

PS, and it's probably bad news! If you really want to make the pause screen also react to input, this method isn't really great for that. Because every time the player makes an input that would change the menu, you'd need to disable rendering which will... look weird. You'll need to figure out how this game updates the screen in the NMI if you want to draw without disabling rendering. (Could actually just do a similar check for pause inside the NMI, and draw what you need while paused.) Or use sprites for the interactive stuff, while the text stays put.

Apologies in advance is none of that is any help. It seems like you know the obvious stuff, but I'm trying to cover all the bases here. If it ain't helpful, yeah... post a patch and I'll take a look but no guarantees if I gotta go super deep.

Edit: Correct big whoops. Said $2000 disables rendering instead of $2001.
Edit2: While I'm at it, Kid Icarus shows sprites and the background on the left 8 pixels of the screen.
Edit3: Oh snap. And for extra safety, probably also want to set $2000 to be sure $2007 writes increment by one as stated in the previous post. I'm starting to bet there won't be room for all this in one place... I didn't add any $2000 stuff to the code in this post, though. More curious if it doesn't crash. We can go from there.

Re: Text output in Kid Icarus status screen

Posted: Sun Apr 13, 2014 1:26 am
by mikaelmoizt
You have no idea how helpfull your reply was to me 8-)

For now, I left the DebugFlag unread and just tried to output something while in the pause screen. My edited pause screen will need some reworking, so I will save that for some rainy day.

The text will be put out when pressing LEFT on the controller for now.
Since the entire screen is redrawn each time you press LEFT, it looks a little strange at the moment.

Now, I will work on getting some kind of interactivity into this.

Code: Select all

@FD20
JSR $EB39
LDA $0038 ;PauseScreen Flag
CMP #$02 ;Is it drawn?
BEQ CheckJoypad
RTS

CheckJoypad:
LDA $00F6 ;Contoller 1 button pressed
CMP #$02 ;Equals $02? (Left)
BEQ PressedLeft
RTS 

PressedLeft:
LDX #$00 ;I could have TXA,PHA here to be safe, but time will tell if something goes wrong
LDA #$00
STA $2001 ;Disable rendering
LDA #$20 ;PPUHI
STA $2006
LDA #$42 ;PPULOW
STA $2006

GetChar:
LDA $textsource,X
STA $2007
INX
CPX #$1C ;This is just for making sure text gets printed in between the frame 
BNE $GetChar

LDA #$00
STA $2006 ;This reset needs to be made to not make the screen weird.
STA $2006 ;It took me a while to find that out
LDA #$1E
STA $2001 ;Turn rendering back on. Yes, Kid Icarus liked this.
RTS

Re: Text output in Kid Icarus status screen

Posted: Sun Apr 13, 2014 4:43 pm
by Kasumi
Cool! For interactivity, you can pretty much do the same trick except in the NMI. (Which... amazingly doesn't preserve all the registers at first. But it looks like it ends up going to a jump table that does whatever behavior is needed for that frame, where at least the one I checked does preserve them.)

(Also, wow, I branched to an RTS instead of just using RTS in my code. :? )

Basically you do what you've planned doing now (with checking pause state/your debug flag), but don't disable rendering. After the NMI fires, you have around 2270 cycles before rendering actually starts so it's safe to write $2007.

Now, normally, you have to worry about adding things. If what you add takes even a slightly long time, it may make it so after you return the original game's code will write to $2007 during rendering.

But you seem to have lucked out! It seems the pause screen doesn't write to $2007 at ALL in the NMI (I checked with the debugger, because static screen alone doesn't necessarily mean anything!) So it should be relatively safe to add your own writes there while the game is paused, so long as just your own code doesn't write to $2007 after 2270 cycles. All you have to do is only update what has changed, and you'd never pass that unless you want to update a large part of the screen or something.

Anyway, good luck!

Edit:

Code: Select all

LDA #$00
STA $2006 ;This reset needs to be made to not make the screen weird.
STA $2006 ;It took me a while to find that out
Ah, yeah. I forgot about that. Writing to $2006 can also mess with the scroll. (In ways that honestly, I don't fully understand.) I bet this would also work:

Code: Select all

LDA #$00
STA $2005 
STA $2005
(could be wrong, I haven't specifically tried these in the way you're using them)
You can read about the specifics of $2005/$2006 interaction here: http://wiki.nesdev.com/w/index.php/The_ ... _scrolling (Which is exactly what I meant when I said I don't fully understand)
And about just $2005 here: http://wiki.nesdev.com/w/index.php/PPU_ ... E_write_x2

I'm actually really shocked the Kid Icarus doesn't write two zeros to $2005 when the game is paused. In most games, what you did would break the scrolling, but the game would just fix it next frame. Kid Icarus doesn't write anything to the $2005 or $2007 while paused. Interesting.