Wickeycolumbus Posted January 7, 2008 Share Posted January 7, 2008 I recently disassembled bowling (2k) and am interested in hacking the graphics and gameplay, but want at least 4k of space. How can I convert the rom from 2k to 4k? Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 8, 2008 Share Posted January 8, 2008 I recently disassembled bowling (2k) and am interested in hacking the graphics and gameplay, but want at least 4k of space. How can I convert the rom from 2k to 4k? After disassembly, move the last 4 bytes of it 2k forward. This is accomplished just by adding an ORG $xFFC instruction above those 4 bytes (where "x" is the same digit used at the top ORG in the disassembly). To move things around, however, you'll need to have the program reverse-engineered far enough so that all of the vectors (values used for indirect loading) pointing to existing data have been converted into labels that reflect the actual spots in the disassembly. For a small 2k game, it shouldn't take too long to create one if it hasn't been done already. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 8, 2008 Share Posted January 8, 2008 Already had one that I forgot about At the end of the file, just change this... .word START LF7FE: .byte $40; | X | $F7FE .byte $80; |X | $F7FF ...to this: ORG $FFFC .word START LF7FE: .byte $40; | X | $F7FE .byte $80; |X | $F7FF There was only 1 indirect instruction used in the program. It uses ram addresses $AA and $AB to store an address. Note how the data table LF7E8 uses label tags instead of values. After disassembly, this table was identified just by searching for all signs of indirect loading (just look for a left parenthesis character), and that happens with ram address $AA. So searching for where ram address $AA and $AB were stored to identified the correct label locations. Bowling.zip Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 8, 2008 Author Share Posted January 8, 2008 Already had one that I forgot about At the end of the file, just change this... .word START LF7FE: .byte $40; | X | $F7FE .byte $80; |X | $F7FF ...to this: ORG $FFFC .word START LF7FE: .byte $40; | X | $F7FE .byte $80; |X | $F7FF There was only 1 indirect instruction used in the program. It uses ram addresses $AA and $AB to store an address. Note how the data table LF7E8 uses label tags instead of values. After disassembly, this table was identified just by searching for all signs of indirect loading (just look for a left parenthesis character), and that happens with ram address $AA. So searching for where ram address $AA and $AB were stored to identified the correct label locations. wow, thanks, this helps alot. I am planning on adding a title screen and improved graphis. Thank you very much! Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 8, 2008 Share Posted January 8, 2008 (edited) No prob. Keep in mind that you'll need to keep addresses of the bowler bitmaps all on the same "page" in memory. Tho the address loading routine could be altered easily to make it possible for them to exist on multiple pages...just add instructions to save the MSB to ram location $AB. You'll also need to insure that some tables used in time-critical areas do not cross page boundries. The long gfx bitmap holding digit pixels should not be allowed to cross a page boundry, for example. You've got 2k of free space, so just add ORG instructions to easily insure this. Also, I hope that you are not planning on trying to make pin-shaped objects. Since the kernal is using a single 8-bit sprite to do this, it wouldn't be possible without a kernal rewrite. It's easily possible to change the number of frames used to animate the bowler tho (for smoother movement). Just change the routine that updates ram $8D to happen quicker rather than the 16 frames it currently uses... lda $80 ;load frame counter and #$0F ;check the contents of the lower nybble bne LF497;branch if anything but 0 (15 of 16 frames) LF495: inc $8D ;Otherwise, bump the animation frame # LF497: jmp LF62B;...program continues Without additional work, you could use AND values #$07, #$03, or #$01 to bump the animation frame following (7 of , (3 of 4), or (1 of 2) frames respectively. Then increase the number of addresses held in table LF7E8. You'll need to adjust the value wherever $8D is checked to be the same number of bytes. Like this one... LF354: ldy $8D ;check the animation frame # cpy #$05 ;on the last frame? beq LF378;branch if so bcs LF3D8;branch if already reached before So if the table holds 9 bitmaps, you'd need to cpy #$09...for example. Edited January 8, 2008 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 9, 2008 Author Share Posted January 9, 2008 I havent studdied the code very much, but would it be ok If i made a different kernel for the title screen before Label Start? would I have to modify anything. Keep in mind, i am not a very good 2600 programmer yet, I am using this project to get better at programming so i can work towards making my own game. Thank you, you have been a lot of help! Quote Link to comment Share on other sites More sharing options...
Atari Dogs Posted January 9, 2008 Share Posted January 9, 2008 2008 Holiday Cart, Elf Bowling. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 9, 2008 Share Posted January 9, 2008 I havent studdied the code very much, but would it be ok If i made a different kernel for the title screen before Label Start? would I have to modify anything. Keep in mind, i am not a very good 2600 programmer yet, I am using this project to get better at programming so i can work towards making my own game. Thank you, you have been a lot of help! The start address performs a ram clear loop (it fills all ram with the value of 0). This must happen in all programs, because the hardware powers up in an unknown state. The graphics registers, sound registers, etc. all hold gibberish...basically why you see/hear this gibberish repeated over and over when powering up without a cartridge plugged in, there's no program present to instruct it otherwise. A better solution is to use an unused ram location to hold a value to instruct the program to skip the normal display, and execute a different one instead. At the end of this other display, jump back to where the regular one ends. That way, you don't need to worry about timing issues between the 2 displays (if it doesn't match, the screen would roll on the frame that the program no longer branches to this custom display). Bowling has a bit of ram untouched. Looks to be addresses $F5 up to $FD (with $FE and $FF used by the program stack...holding a return address wherever a JSR executes). That should be plenty to use for title screen variables. So the easy solution is to throw a value into one of these ram locations just following the ram clear loop, and clear the value after displaying the last frame of the title display. Let the program decide which of the displays to use when the screen is being drawn, by checking the ram location for the value you used. If present, jump to a different routine that draws a different screen. $80 is used as the frame counter in the game, so you could reuse this ram location in your display...checking for a specific value for when to clear the "display title screen" variable. Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 9, 2008 Author Share Posted January 9, 2008 2008 Holiday Cart, Elf Bowling. OOOO good ideah! How can I get involved in one of these projects? Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 9, 2008 Author Share Posted January 9, 2008 I havent studdied the code very much, but would it be ok If i made a different kernel for the title screen before Label Start? would I have to modify anything. Keep in mind, i am not a very good 2600 programmer yet, I am using this project to get better at programming so i can work towards making my own game. Thank you, you have been a lot of help! The start address performs a ram clear loop (it fills all ram with the value of 0). This must happen in all programs, because the hardware powers up in an unknown state. The graphics registers, sound registers, etc. all hold gibberish...basically why you see/hear this gibberish repeated over and over when powering up without a cartridge plugged in, there's no program present to instruct it otherwise. A better solution is to use an unused ram location to hold a value to instruct the program to skip the normal display, and execute a different one instead. At the end of this other display, jump back to where the regular one ends. That way, you don't need to worry about timing issues between the 2 displays (if it doesn't match, the screen would roll on the frame that the program no longer branches to this custom display). Bowling has a bit of ram untouched. Looks to be addresses $F5 up to $FD (with $FE and $FF used by the program stack...holding a return address wherever a JSR executes). That should be plenty to use for title screen variables. So the easy solution is to throw a value into one of these ram locations just following the ram clear loop, and clear the value after displaying the last frame of the title display. Let the program decide which of the displays to use when the screen is being drawn, by checking the ram location for the value you used. If present, jump to a different routine that draws a different screen. $80 is used as the frame counter in the game, so you could reuse this ram location in your display...checking for a specific value for when to clear the "display title screen" variable. So I have 9 bytes of ram to play around with? sweet, i was assuming that all ram was used up in the actual game, that is why i would make a different kernel just for the title screen and then clear all the variables and tia registers after the joystick button is pressed, and then it would go to the real game. Also, I noticed that player graphics for the bowler are upside down (starting at LF7B8), why is that? Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 9, 2008 Share Posted January 9, 2008 Same principle...clear the ram value used for the "display title screen?" variable when INPT4 shows a trigger press. You only need 1 bit...and you could merge INPT4 + INPT5 (via AND) to check both triggers instead if you wanted. Might be a good idea to also check the console switches by reading SWCHB (so the player doesn't need to be informed about how to skip ahead). The ram addresses $FE-$FF are also free when a subroutine doesn't have it's return address occupying the stack. The stack builds itself downward using the current stack pointer as subroutines are executed via JSR instructions, RTS pulls off the last stored return address (2 bytes) and bumps the stack pointer back up. The stack pointer keeps track (that's why it's normally reset to #$FF following ram clear...indicating the first ram location to use for anything that affects the stack). And most games use reversed GFX...it's just simpler to start drawing the image from it's last value (the image start address + the value of the index register), and decrement the counter until it rolls over. This rollover detection doesn't require a compare instruction that way...just decrement the index register and check it with BPL (loop back for the next line unless the counter has rolled negative). Because multiple images exist for the player's sprite, the Y register is often used in games. Initially load Y with the number of scanlines the image requires, load the gfx using an indirect-Y instruction, DEY to bump the index down, then loop unless it fell negative. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 10, 2008 Share Posted January 10, 2008 Here's a sample assembly that does the above. A different display is shown on powerup, exited by any change of the triggers or console switches. I didn't mess with timing, so the demo display only allows a limited number of scanlines so that both displays end w/262 shown (no need to use a "show title screen?" variable)...but more scanlines could be drawn if you want to use seperate timer loops. There's plenty of time to set up variables (location shown), and all ram can be used apart from address $81 (stores a copy of the console switch status). The bowler bitmaps have been moved to a seperate page for easy editing. Bowling4k.zip Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 11, 2008 Author Share Posted January 11, 2008 Here's a sample assembly that does the above. A different display is shown on powerup, exited by any change of the triggers or console switches. I didn't mess with timing, so the demo display only allows a limited number of scanlines so that both displays end w/262 shown (no need to use a "show title screen?" variable)...but more scanlines could be drawn if you want to use seperate timer loops. There's plenty of time to set up variables (location shown), and all ram can be used apart from address $81 (stores a copy of the console switch status). The bowler bitmaps have been moved to a seperate page for easy editing. I noticed that when you pull the reset switch on the title screen, it starts to play the game. how can this be fixed? Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 12, 2008 Share Posted January 12, 2008 The easy way would be to go back to the original idea...ignore the switches on the title screen by commenting off these lines... ;...below label LF005 ; lda SWCHB ;3 ; sta $81 ;3 save current console switches ...and... ;...below label FillScreen ; lda SWCHB ;3 check console switches ; cmp $81 ;3 compare with previous ; bne Exit ;2 branch if different (and exit) ; sta $81 ;3 ...otherwise, store to ram for next time Just throw a semicolon at the front of each line to make Dasm ignore them. But those lines do provide a quick way to start a game. I don't see a problem with it. You can exit the display by altering any switch or joystick trigger. You could also have it exit if any stick is moved (SWCHA = $FF when neither is moved). Alternately, you could perform an AND #FC after loading SWCHB in both code segments...to have it ignore reset and game select switch presses.... ;...below label LF005 lda SWCHB ;3 and #$FC ;2 ignore reset & select sta $81 ;3 save current console switches ...and... ;...below label FillScreen lda SWCHB ;3 check console switches and #$FC ;2 ignore reset & select cmp $81 ;3 compare with previous bne Exit ;2 branch if different (and exit) sta $81 ;3 ...otherwise, store to ram for next time The way that works is the AND instruction only keeps the 6 left bits (and throws away bit 1 and 0...which correspond to the select and reset switches respectively). Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 I did some hacking to it and this is what i came up with (i changed the numbers and the player a bit, and made the pins and part of the ball white) Bowling24k.bin Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 12, 2008 Share Posted January 12, 2008 The ball is made of the ball sprite and sprite0's missile. Changing the pin color automatically changes the missile part of the ball, because it's shared. So just throw a PF color store in there too... ; lda $CF ;3 (original) lda #$0F ;2 load white color sta COLUP0 ;3 store to sprite0/missile0 sta COLUPF ;3 ...also store to the ball Don't forget to use the # symbol when loading values directly. BTW you bumped up the number of scanlines on the title screen. If you do this, you should use seperate timer loops so that the screens are always at 262. Lower the value given to TIM64T after drawing the display (to #$38), and put 2 more lines in the exit routine... Exit: lda #$38 ;2 store time to waste (seperate from title screen) sta TIM64T ;4 jmp LF2A7 ;3 finally, go to the game program In this case, it didn't matter (because both values should be at $38 after adding that single scanline). But if you want to give Y a higher value than #$A9 to be able to draw more lines in the title display, you'll need to reduce the first value given to TIM64T to bring the scanline count back down to 262. The exit routine's value might not always match, so you'll be able to adjust it independantly. You need at least a few clicks so that the program has time to initialize the variables for the ingame screen. The switch to display scanline count is -n in Z26...as in Z26 Bowling -n. If a game does not hold a steady count, it could cause a television display to jump when the count changes. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 12, 2008 Share Posted January 12, 2008 BTW a better method would be to reduce the ball sprite width on the upper and lower lines (so that the bowling ball can be colored independantly with no need to use a missile sprite). Working... Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 I fixed the white ball, thanks for telling me how, i would have never been able to figure it out. I know the answer to this is probably a no, but is there a way other than a flicker to make the ball black and the pins white? As for the title screen, i needed it to be full resolution for the screen that i wanted, but i will fiddle around with that later on. I noticed that all of the instructions have comments with the number of machine cycles, is there a switch in distella that does this for you? Thank you Bowling24k.bin Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 oops, never mind my question about the ball, i guess i did not read your last post carefully... Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 12, 2008 Share Posted January 12, 2008 (edited) The option is enabled with the -s switch during disassembly. I always use the string -pafs (plus the -c switch, if I have a config file). p = show processor type at the top of the disassembly a = omit "A" when instruction acts on the accumulator s = show cycle count for each instruction f = force correct address length (show MSB for ram access) c = use configuration file to specify code/data/gfx areas Distella displays the switches when you use it alone, as a help screen. If you disassemble without using p, a, or f...the disassembly could generate errors when you use Dasm to reassemble it. So it's always good practice to at least use those 3 switches. When hacking display kernals like this, the s switch comes in handy (so you know exactly the number of cycles used in any given area without having to figure them out). Changes to make the ball a standalone object: The easy way is to use the native horizontal motion register so that the ball's position can be adjusted slightly after resizing it (NOTE: this will cause the "comb" to be displayed...other edits can be made to eliminate it if you find it to be unacceptable). HMBL isn't defined, so add that first to the top... HMBL = $24 Next, change the color stores slightly so that you can use independant colors. Also, throw in the HMCLR instruction to clear all motion prior to drawing the sprites... ; lda $CF ;3 lda #$0F ;2 load pin color sta COLUP0 ;3 store to sprite0/missile0 lda #$00 ;2 load ball color sta COLUPF ;3 store to the ball sta HMCLR ;3 clear horizontal motion When drawing the sprites, no playfield pixels are being used...so you don't need to worry about funky CTRLPF values (CTRLPF is also used to resize the ball sprite). Luckily, enough cycle time remains to squeeze in a seperate table load (for reading where to position the sprite). So apply HMOVE to the code, and add some lines to read and adjust the ball position... LF233: sta WSYNC ;3 sta HMOVE ;3 added line sta GRP1 ;3 ldy $D5 ;3 lda LF72E,Y ;4 sta ENABL ;3 ; asl ;2 (no longer using the missile) ; sta ENAM0 ;3 "" sta CTRLPF ;3 added lines... lda Motion,Y ;4 "" sta HMBL ;3 "" ;original code continues... cpx #$22 ;2 bcs LF249 ;2 lda $DA,X ;4 sta GRP0 ;3 A new table name (Motion) was used above...so edit the data area a bit to add it. Also, the missile is no longer used, so those data lines can be changed to just hold the ball sprite width and where to enable it... LF72E: ;original lines... ; .byte $02; | X | $F72E bottom ; .byte $03; | XX| $F72F ; .byte $03; | XX| $F730 ; .byte $03; | XX| $F731 ; .byte $02; | X | $F732 top ; .byte $00; | | $F733 ;new lines... .byte $12; | x X | $F72E bottom .byte $22; | x X | $F72F .byte $22; | x X | $F730 .byte $22; | x X | $F731 .byte $12; | x X | $F732 top Motion:;ball sprite position adjustment .byte $00; | | $F72E bottom (shared) .byte $F0; |XXXX | $F72F move right .byte $00; | | $F730 .byte $00; | | $F731 .byte $10; | X | $F732 (move left) .byte $00; | | $F733 top Notice that I placed small x's in the first table to help show you the changes to the upper nybble (now used to set the ball sprite width). The "Motion" table is applied after each line is drawn, so it's offset by 1 byte. The $10 value moves the sprite to the left so that the wider ball is centered with the line above it on the screen...and $F0 shifts it back to the right. The data area has been increased in size, so the ORG definition above it needs to be edited too... ; ORG $FF51 ;new origin... ORG $FF4C There ya go Bowling4k.zip Edited January 12, 2008 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 Thanks alot, i did not try it yet, but what is up with the black area behind the bowler? can they be removed? Thank you Quote Link to comment Share on other sites More sharing options...
supercat Posted January 12, 2008 Share Posted January 12, 2008 (edited) Thanks alot, i did not try it yet, but what is up with the black area behind the bowler? can they be removed? The black area behind the bowler is sometimes called the "comb". There is no way to avoid having a black line at the left of the screen on the bottom scan line of the ball (since its sprite has to move rightward). The code as written throws the black line on every scan line where the bottom of the ball could (at least theoretically) be. Changing it to eliminate all but the scan lines where the ball appears probably wouldn't be too hard. Changing it to appear on the ball's bottom scan line only might be tougher. If the black lines track the ball, you could pretend they were "aiming assistance" or somesuch nonsense. Another alternative, although you may want to change the ball color in this case, would be to set the background color to black for every other scan line. That might be an interesting effect. Not sure if there are enough cycles for that. Edited January 12, 2008 by supercat Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted January 12, 2008 Share Posted January 12, 2008 (edited) The black lines is the "comb" I mentioned. This is a direct result of using HMOVE to shift sprite positions. There are a number of ways to hide it...you can: ...Reset the background color to black (easiest) ...Use #$30 and store that to PF0 (ok if the ball color is going to be black anyway...and so long as the playfield is reflected and no pixels are otherwise needed) ...Perform an HMOVE on every single line (more difficult...especially since the HMBL doesn't take effect right away in this example). ...Use cycle-specific timing in the display to avoid using HMOVE (can't help you with that one). Of those, the 2nd solution should work OK if you don't mind the bowling area to be narrower than the top (because the playfield pixels are used to draw the score - which uses a changing color). To make the screen the same width on all lines, you could just edit the score color to always be black. The easiest way will always be the first solution...reset the background color to be black for the entire screen (HMOVE lines are always black, and this effectively hides them if there are no foreground pixels being drawn). Of course, since the ball shares the foreground color you'd need to use a color other than black for the ball. The "comb" generally doesn't bother those that are familiar with the 2600 library. We grew up looking at it in many games. Edited January 12, 2008 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 (edited) made your changes and changed the shape of the six, but it still looks like crap(the six). Bowling24k.bin Edited January 12, 2008 by Wickeycolumbus Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted January 12, 2008 Author Share Posted January 12, 2008 After doing some experiments, i decided to keep the comb. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.