Jump to content
IGNORED

Help - Hacking Graphics


Ranthulfr

Recommended Posts

I have been experimenting with hacking VCS game graphics, and as long as I don't alter the image (sprite) size the changes I make work fine. On the other hand if I revise the number of lines (bytes) in the image the game still runs but everything is jumbled.

 

Probably an over-simplified question, but:

Can anyone tell me why the size change causes problems and what I need to do to fix it?

 

Thanks!

Link to comment
Share on other sites

Everything in a Rom program has a specific address (or location) in the VCS memory. When graphics are being displayed, what is really happening is that the program is copying data from a rom location into Ram (which is then displayed on the screen). The way that the program "knows" how much to copy is written into the program itself...i.e. "copy 8 bytes starting from the 112th byte" (basically...it really only does one at a time). So what happens when the image is now 9 bytes? The program still hasn't changed...it still tells the VCS to copy 8 lines. And it follows into the next image as well...where the program expects a different image beginning from byte 11A. Even worse, the program itself might have a binary subroutine that begins at byte 11A. If these are changed around without consideration to what the program is supposed to do, it will most likely crash the game.

 

So the only way to correct it if you want to encode larger images is to track down where in the program these bytes are read, and change the program to do the correct number of lines. This might be accomplished by using a program like Distella to "disassemble" the game code into something readable. Wherever bytes are read from the program, Distella will attach a label to it. This label will also appear right next to the image data...so all you would need to do is find it in the program using Notepad's Find function...and then look at how the routine is constructed that transfers the image. Many times it is just a value placed into the X register...something like this:

LDX #$08

LDA $LF111,X

DEX

What is happening here is that X is given a value of 8 (because there are 8 lines in the image)...and then loading data beginning at byte 111 plus the X register, and then bumping down the X register by one. (once the X register reaches zero, the program considers the graphic image complete in this example). Notice how many games have the graphics upside-down? That's because it's grabbing the last line of the image first (byte 119...111+8 in the X register). The next time the program reads a byte, the number in X would be lower...so it would grab the next byte. This is a best-case scenario of the problem...the offset values of how big each image is are often placed into a table (a group of bytes)...and then transferred to the X register. The address where these bytes are read from are sometimes called indirectly (the program loads the image by loading the ADDRESS of where the image is...how's that for complicated?)

 

PLA ;grab the next image number in memory

TAX ;move it to the X register as an offset

LDA $LF960,X ;load the low byte from a table of the address of where the image is

STA $BE ;store it in Ram

LDA $LF970,X ;load the high byte from a table of the address of where the image is

STA $BF ;store it in the next Ram byte

LDA $LF950,X ;load the number of lines the image is supposed to have from a table

TAY ;transfer it to the Y register...this is our new counter

LDA ($BE),Y ;load the image data Y bytes from the address contained at $BE/$BF

STA $PL0 ;write it to the player data

DEY ;lower the Y register

TYA ;transfer it to the A register

PHA ;...and save it for later

 

In this case, you would need to track down the tables and change them as well (the address locations as well as the number of bytes). Naturally, Distella won't be putting those lengthy messages beside the program lines...so it can be tricky to find out where things are at times :(

The tables themselves might look like just a bunch of random figures...but in fact are very specific values concerning the images.

 

LF950: .byte $08,$08,$08,$0A,$0A,$0A,$08,$08,$08,$08,$06,$06,$06,$06,$06,$06

LF960: .byte $11,$19,$21,$2b,$35,$3f,$47,$4f,$57,$5f,$65,$6b,$71,$77,$7d,$83

LF970: .byte $f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1,$f1

 

The table at address $950 is the sizes of the images in this fake game...3 8-line objects, then 3 10-line objects ($0A is hex for 10), then 4 more 8-line objects, and 6 6-line objects. The table at $960 is the low byte of the address of where each object is in Rom memory...and the table at $970 is the high bytes. Notice the first byte in each table...it makes the address $F111 then you use them together ;) For simplicity's sake, I just placed all the images consecutively in memory...but actually the images could have been stored anywhere, since the tables tell the program exactly where to find the images needed. It's up to the programmer to manage the memory himself. So how did those labels like $LF950 get put in the disassembly? Distella did this...as it was building the disassembly, a read was done by the program (LDA $F950,X). When this happens, Distella changes the address to a label, and sticks that label at the address of where the value is pulled from. This not only helps the person looking at the disassembly, but also helps Distella distinguish data from program instructions.

 

If you wanted to make the images smaller, it's no problem at all. (just put a value of zero in some of the lines of the image). In our above example, the program is still calling 8 lines...but you would only see the non-zero ones (the bytes that contain pixels)

Link to comment
Share on other sites

Thanks for taking the time to provide such a detailed explanation, Nukey Shay. Very interesting - and it tells me what I needed to know. Some of the concepts involved in assembly programming are still new to me (as you can see).

 

Randy

Link to comment
Share on other sites

No prob. Still another method abandons indexes altogether and simply use a byte value in the shape data as a delimiter to seperate different objects (like using zero inbetween images). Since rom space is already pretty limited in a large portion of the 2600 games, you probably won't see this method used in it's games...not to mention the timing issues that would also surface using it.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...