EarthQuake Posted November 12, 2008 Share Posted November 12, 2008 (edited) So I was working on my Adventure hack a bit, overwhelmed with the new possibilities given Nukey's new kernal. Basically, each line of the playfield data has it's own value (stored in the lower nybble of the byte sent to PF0), which allows not only higher vertical resolution in bitmaps, but screen bitmaps where each playfield row can be of variable height, so you can increase the vertical resolution only where you need it. But, anyways, I was wondering about something and it might just be possible. IIRC, the bit in the playfield control register that controls the mirroring, could theoretically be switched on and off as the screen bitmap is drawn to achieve a playfield layout that is somewhat non-symmetrical. The engine could look for a certain bit set in the screen bitmap's PF0 byte and XOR the bit sent to the playfield register, effectively toggling it each time the condition is met. I know I'm always going on about how Adventure could extremely benefit from asymmetrical playfields, but this idea could be a great compromise. Would this even be possible? It's a long shot, but I can see amazing things resulting from this. Here's a textual result of a room that would take advantage of such an addition: .byte $F0,$FF,$0F;XXXXXXXXXXXXXXXX RRRRRRRRRRRRRRRR .byte $30,$00,$00;XX RR .byte $30,$00,$00;XX RR .byte $F0,$C0,$FC;XXXXXX XXXXXXRRRRRR RRRRRR .byte $30,$00,$00;XX MM <- * .byte $30,$00,$00;XX MM .byte $F0,$FF,$FF;XXXXXXXXXXXXXXXXXXXXMMMMMMMMMMMMMMMMMMMM * Playfield register updated on noted line. The value specified in the room data table could perhaps just be used as the initial value of the mirroring behavior. Edited November 12, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 12, 2008 Share Posted November 12, 2008 Not enough time...at least not without caching something in Ram or rewriting the kernal to use some kind of skipdraw variant. The program is already printing 2 sprites, then indirectly-loading and storing PF0 and bumping the index. So you are faced with the problem of either a loaded CTRLPF or PF1 being written too late (leading to playfield gfx clipping). It's not an issue for storing an extra value to a line counter, because this is perfectly fine to store after the playfield has already been updated. The indirect loads are cycle hogs. A possible workaround that does not require rewrites would be to not use PF0 at all. This cuts the horizontal display down by 8 pixels, but allows you to use that read to update CTRLPF instead of PF0. You could still implement a line counter (because just as before, writes for this are not time-critical). Maximum X and Y values throughout the program would need editing. Another possible solution would be to split PF0, PF1 and PF2 data into seperate tables (with seperate RoomLo/RoomHi pointers to each table). You save 4 cycles here, because INY only needs to happen once per block of data (instead of 3 times). Those cycles can be used after storing PF0... AND #$01 ;keep only the low bit ORA #$20 ;merge in the ball size STA CTRLPF ;store the value This still happens just a tad too late (due to the extra 3 cycles for a store), but it looks like only the upper line is affected. Another drawback is that the line counter is limited to even values only (use AND #$0E instead of AND #$0F to trim off the CTRLPF bit in the PF0/linecount table), but that's not as serious. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 12, 2008 Share Posted November 12, 2008 Quick 'n' dirty... Alternate method allows CTRL stores instead of a line counter (the screens use the same 21-byte format as the original game). The initial branch has been moved to the top of the routine to avoid the use of a branch later. As mentioned, there's a 2-cycle overrun that causes CTRL to hit just a little late for the very first scanline. PrintDisplay:;draw a frame... STA HMCLR ;3 Clear horizontal motion LDA Obj1X ;3 Position Player00 Sprite to the X Coordinate of Object1 LDX #$00 ;2 JSR PosSpriteX ;6 LDA Obj2X ;3 Position Player01 Sprite to the X Coordinate of Object2 INX ;2 (the subroutine PosSpriteX didn't change X) JSR PosSpriteX ;6 LDA PlayerX ;3 Position Ball Strite to the X Coordinate of the Man LDX #$04 ;2 JSR PosSpriteX ;6 STA WSYNC ;3 Wait for horizontal Blank STA HMOVE ;3 Apply Horizontal Motion STA CXCLR ;3 Clear Collision Latches LDY #$07 ;2 Use 7 lines for top line STY PixelCount ;3 Store to line counter PrintDisplay_1: LDX INTIM ;4 Wait for end of the current frame BNE PrintDisplay_1 ;2 STX Player0Def ;3 Set Player00 definition index STX Player1Def ;3 Set Player01 definition index STX RoomDefIndex ;3 Set room definition index STX GRP1 ;3 Clear any graphics for Player01 INX ;2 STX VDELP1 ;3 vertically delay Player 01 ;---------------------------------- ;skip these lines if you are using unshared variables for RoomLo/Hi LDA Control ;3 Get 3-frame room number AND #$7F ;2 (strip inactive game bit) TAY ;2 LDA RoomDataTable0,Y ;4 Get the room gfx LSB pointer STA RoomLo ;3 LDA RoomDataTable1,Y ;4 Get the room gfx MSB pointer STA RoomHi ;3 ;---------------------------------- LDA PlayerY ;3 Get the Y Coordinate of the Man SEC ;2 SBC #$04 ;2 And Adjust it (By Four Scan Lines) for printing STA PlayerYadj ;3 (so Y Coordinate Specifies Middle) CMP #$64 ;2 check if ball is on the upper portion of the screen PHP ;3 push carry status PLA ;4 pull as accumulator ASL ;2 ...and shift carry to bit 1 LDY #$00 ;2 Set initial room definition index LDX #$68 ;2 STX ScanLineCnt ;3 Set initial Scan Line Count ;NOTE: bankswitched kernal would begin here------------------------------------------ STA WSYNC ;3 Wait for horizontal Blank STY VBLANK ;3 Clear any Vertical Blank BPL Print_Top_Line ;2 always branch Print_More_Lines: LDY #$0F ;2 Enable Ball Graphic STY PixelCount ;3 Store to line counter STA WSYNC ;3 Wait for horizontal Blank STX GRP0 ;3 Display Player00 definition byte (if Wanted) Print_Top_Line: STA ENABL ;3 Enable Ball (If Wanted) LDY RoomDefIndex ;3 Get room definition index LAX (RoomLo),Y ;5 Get first room definition byte (use LAX to preserve) STA PF0 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF1 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF2 ;3 ...and display TXA ;2 Get PF0 definition back AND #$0F ;2 keep only low nybble for CTRL ORA #$20 ;2 merge in ball size STA CTRLPF ;3 Store to line counter INY ;2 bump index STY RoomDefIndex ;3 ...and save for Next Time LAX ScanLineCnt ;3 Get the scan line. Use LAX for subrtaction later DEX ;2 (save 3 cycles by using DEX instead of DEC) CPX #$08 ;2 Have we reached to within 8 scanlines of the bottom? PrintPlayer01:;Print Player01 (Object 02) STX ScanLineCnt ;3 Store the scan line LDY Player1Def ;3 Get the Player01 definition index CLC ;2 Use carry to kill off difference between X and A SBC Obj2Y ;3 Have we reached Object2's Y Coordinate? STA WSYNC ;3 Wait for horizontal Blank BPL PrintPlayer00 ;2 ...If Not, Branch LDA (Obj2Lo),Y ;5 Get the Next Player01 Definition byte STA GRP1 ;3 ...and display BEQ PrintPlayer00 ;2 If Zero then Definition finished INC Player1Def ;5 Goto next Player01 definition byte PrintPlayer00:;Print Player00 (Object01), Ball (Man) and Room. TXA ;3 Get Current Scan Line PrintPlayer00_0: LDX #$00 ;2 Clear X (player 0 gfx) SEC ;2 SBC Obj1Y ;2 Have we reached the Object1's Y coordinate? BPL PrintPlayer00_1 ;2 If not then Branch LDY Player0Def ;3 Get Player00 definition index LAX (Obj1Lo),Y ;5 Get the Next Player00 definition byte (give to X) BEQ PrintPlayer00_1 ;2 If Zero then Definition finished INC Player0Def ;5 Go to Next Player00 definition byte PrintPlayer00_1: LDA ScanLineCnt ;3 Get Scan line count SEC ;2 SBC PlayerYadj ;2 Have we reached the Man's Y Coordinate? AND #$FC ;2 Mask value to four either side (getting depth of 8) BNE PrintPlayer00_2 ;2 If >4 on either end, branch (skip ball display) LDA #$02 ;2 Enable Ball Graphic PrintPlayer00_2: DEC PixelCount ;5 decrement the line counter BMI Print_More_Lines ;2 if more lines remain, branch PrintPlayer00_3: STA WSYNC ;3 Wait for horizontal Blank STA ENABL ;3 Enable Ball (If Wanted) STX GRP0 ;3 Display Player00 definition byte (if Wanted) PrintPlayer00_4: LAX ScanLineCnt ;3 Get the scan line. Use LAX for subrtaction later DEX ;2 (save 3 cycles by using DEX instead of DEC) CPX #$08 ;2 Have we reached to within 8 scanlines of the bottom? BPL PrintPlayer01 ;2 If not, Branch STX VBLANK ;3 Turn on VBLANK, now 3 cycles earlier to fix side pixel ;NOTE: bankswitched kernal would end here-------------------------------------------- LDA #$00 ;2 STA GRP1 ;3 Clear any graphics for Player01 STA GRP0 ;3 Clear any graphics for Player00 LDA #$20 ;2 STA TIM64T ;4 Start timing this frame RTS ;6 return to main loop Then edit all of the PF0 data to include CTRLPF values for the lower nybble. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 12, 2008 Share Posted November 12, 2008 Update...I've got it figured out. Instead of bumping a Y index for each of the 2 sprites, bump it's indirect vector LSBs instead. Y can therefore remain set at zero when setting up the sprite display (saves 4 more cycles). There was also a superfluous instruction which has been removed. Because the indirect vectors are bumped, I stored the original values to the now-unused Player#def variables...and pulled them back after the display is drawn (so that they remain unchanged for the other 2 display frames). As before, the scanline count is placed in the low nybble of PF0. However, EACH line must contain a new CTRLPF value...4 values per line (PF0, PF1, PF2, CTRL). This last value should contain ball size ($20) + priority ($00 = dark, $04 = normal) + display mode ($00 = mirrored/$01 = reversed). Not enough time to implement other bits, so you'll still need to set panels up in the setup routine (the store to CTRLPF can be removed, tho). Here's the updated kernal... PrintDisplay:;draw a frame... STA HMCLR ;3 Clear horizontal motion LDA Obj1X ;3 Position Player00 Sprite to the X Coordinate of Object1 LDX #$00 ;2 JSR PosSpriteX ;6 LDA Obj2X ;3 Position Player01 Sprite to the X Coordinate of Object2 INX ;2 (the subroutine PosSpriteX didn't change X) JSR PosSpriteX ;6 LDA PlayerX ;3 Position Ball Strite to the X Coordinate of the Man LDX #$04 ;2 JSR PosSpriteX ;6 STA WSYNC ;3 Wait for horizontal Blank STA HMOVE ;3 Apply Horizontal Motion STA CXCLR ;3 Clear Collision Latches PrintDisplay_1: LDX INTIM ;4 Wait for end of the current frame BNE PrintDisplay_1 ;2 STX RoomDefIndex ;3 Set room definition index STX GRP1 ;3 Clear any graphics for Player01 INX ;2 STX VDELP1 ;3 vertically delay Player 01 ;---------------------------------------------------- ;do not use these lines if RoomLo/Hi is not shared... LDA Control ;3 Get 3-frame room number AND #$7F ;2 (strip inactive game bit) TAY ;2 LDA RoomDataTable0,Y ;4 Get the room gfx LSB pointer STA RoomLo ;3 LDA RoomDataTable1,Y ;4 Get the room gfx MSB pointer STA RoomHi ;3 ;---------------------------------------------------- LDA Obj1Lo ;3 transfer low sprite1 pointer to temp STA Player0Def ;3 LDA Obj2Lo ;3 transfer low sprite1 pointer to temp STA Player1Def ;3 LDA PlayerY ;3 Get the Y Coordinate of the Man SEC ;2 SBC #$04 ;2 And Adjust it (By Four Scan Lines) for printing STA PlayerYadj ;3 (so Y Coordinate Specifies Middle) LDY #$00 ;2 Set initial room definition index LDX #$68 ;2 STX ScanLineCnt ;3 Set initial Scan Line Count ;NOTE: bankswitched kernal would begin here------------------------------------------ STA WSYNC ;3 Wait for horizontal Blank STY VBLANK ;3 Clear any Vertical Blank BPL Print_Top_Line ;2 always branch (X=$68) Print_More_Lines: LDY RoomDefIndex ;3 Get room definition index STA WSYNC ;3 Wait for horizontal Blank STX GRP0 ;3 Display Player00 definition byte (if Wanted) STA ENABL ;3 Enable Ball (If Wanted) Print_Top_Line: LAX (RoomLo),Y ;5 Get first room definition byte (use LAX to preserve) STA PF0 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF1 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF2 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get row's CTRL value STA CTRLPF ;3 Store to playfield control TXA ;2 Get PF0 definition back AND #$0F ;2 keep only low nybble of PF0 STA PixelCount ;3 Store to line counter INY ;2 bump index STY RoomDefIndex ;3 ...and save for Next Time LAX ScanLineCnt ;3 Get the scan line. Use LAX for subrtaction later DEX ;2 (save 3 cycles by using DEX instead of DEC) PrintPlayer01:;Print Player01 (Object 02) STX ScanLineCnt ;3 Store the scan line LDY #$00 ;2 clear Y index for both indirect loads CLC ;2 Use carry to kill off difference between X and A SBC Obj2Y ;3 Have we reached Object2's Y Coordinate? STA WSYNC ;3 Wait for horizontal Blank BPL PrintPlayer00 ;2 ...If Not, Branch LDA (Obj2Lo),Y ;5 Get the Next Player01 Definition byte STA GRP1 ;3 ...and display BEQ PrintPlayer00 ;2 If Zero then Definition finished INC Obj2Lo ;5 Goto next Player01 definition byte PrintPlayer00:;Print Player00 (Object01), Ball (Man) and Room. TXA ;3 Get Current Scan Line LDX #$00 ;2 Clear X (player 0 gfx) SEC ;2 SBC Obj1Y ;2 Have we reached the Object1's Y coordinate? BPL PrintPlayer00_1 ;2 If not then Branch LAX (Obj1Lo),Y ;5 Get the Next Player00 definition byte (give to X) BEQ PrintPlayer00_1 ;2 If Zero then Definition finished INC Obj1Lo ;5 Goto next Player00 definition byte PrintPlayer00_1: LDA ScanLineCnt ;3 Get Scan line count SEC ;2 SBC PlayerYadj ;2 Have we reached the Man's Y Coordinate? AND #$FC ;2 Mask value to four either side (getting depth of 8) BNE PrintPlayer00_2 ;2 If >4 on either end, branch (skip ball display) LDA #$02 ;2 Enable Ball Graphic PrintPlayer00_2: DEC PixelCount ;5 decrement the line counter BMI Print_More_Lines ;2 if more lines remain, branch PrintPlayer00_3: STA WSYNC ;3 Wait for horizontal Blank STA ENABL ;3 Enable Ball (If Wanted) STX GRP0 ;3 Display Player00 definition byte (if Wanted) PrintPlayer00_4: LAX ScanLineCnt ;3 Get the scan line. Use LAX for subrtaction later DEX ;2 (save 3 cycles by using DEX instead of DEC) CPX #$08 ;2 Have we reached to within 8 scanlines of the bottom? BPL PrintPlayer01 ;2 If not, Branch STX VBLANK ;3 Turn on VBLANK, now 3 cycles earlier to fix side pixel ;NOTE: bankswitched kernal would end here-------------------------------------------- LDA #$00 ;2 STA GRP1 ;3 Clear any graphics for Player01 STA GRP0 ;3 Clear any graphics for Player00 LDA Player0Def ;3 Restore low pointer vectors... STA Obj1Lo ;3 LDA Player1Def ;3 STA Obj2Lo ;3 LDA #$20 ;2 STA TIM64T ;4 Start timing this frame RTS ;6 return to main loop Thanks for the suggestion! This is a very good addition. Each screen will require at least 28 bytes...but it's still possible to share bytes if you are careful. NOTE: Because the LSB's of the sprite vector is updated, it's -required- that sprites DO NOT cross a page boundry under any circumstances. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 12, 2008 Share Posted November 12, 2008 BTW since each "band" of screen gfx holds it's own ball size and priority, you could make the player sprite wider or thinner, or allow game objects to move behind playfield obstructions (hiding them from view!)...depending on what row is involved. A new wrinkle to hiding things Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 12, 2008 Author Share Posted November 12, 2008 (edited) Wow! I wasn't expecting another kernal from you! I never thought about adding another byte to each row in the bitmap to hold the playfield control. This has very huge implications. I can't find an immediate use for all the new things that are possible, but hopefully someone in the future may take advantage of it in it's entirety. The real groundbreaking thing here is being able to modify the playfield mirroring on-the-fly, allowing some really neat new worlds to be created. I'm definitely going to give this a try. The added byte per room is a killer though, especially when you got rooms that are 36, 45, 51, 63 bytes et cetera... but I think the new possibilities far outweigh the disadvantages. Some quick questions: because each row of playfield data contains the playfield control, does this make the byte in the room data table redundant or anything? Afaik, the engine still uses it for determining if a room is dark and if the missiles should display. Also, in my source, it checks the byte if the room is set as dark and establishes and recolors the surround object. The only thing that is redundant is the mirroring bit, correct? Will this interfere at all? Edited November 12, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 12, 2008 Share Posted November 12, 2008 (edited) Wow! I wasn't expecting another kernal from you! It's a very cool idea that just begs to be exploited, so I couldn't set it down until I had it nailed. I never thought about adding another byte to each row in the bitmap to hold the playfield control. This has very huge implications. I can't find an immediate use for all the new things that are possible, but hopefully someone in the future may take advantage of it in it's entirety. The real groundbreaking thing here is being able to modify the playfield mirroring on-the-fly, allowing some really neat new worlds to be created.Completely agree...and it just looks better than throwing panels all over the place I'm definitely going to give this a try. The added byte per room is a killer though, especially when you got rooms that are 36, 45, 51, 63 bytes et cetera... but I think the new possibilities far outweigh the disadvantages. This is where 8k versions become mandatory. That extra byte for each band burns 217 bytes alone for Adventure's original 31 screens (eating up most of the free space in 4k). No big deal in the 8k version's 3k of empty space. Too bad that it can't be cut down to a single bit...the AND'ing and OR'ing takes too much time. Some quick questions: because each row of playfield data contains the playfield control, does this make the byte in the room data table redundant or anything? Afaik, the engine still uses it for determining if a room is dark and if the missiles should display. Also, in my source, it checks the byte if the room is set as dark and establishes and recolors the surround object. The only thing that is redundant is the mirroring bit, correct? Will this interfere at all?The AND and STA CTRLPF above ObjectSort is now not needed (because each band sets it's own value)...setting it in the setup routine makes no difference. But yeah, the panels and surround still require that byte to function...unfortunately. That's 3 bits, so it's pretty difficult to merge it with something else. They can be grouped to the lower 3 bits now, tho...saving a bit of time. The best news is that it works with the previous additions with no gfx clipping and no cycle time lost So it's there if anybody needs it...I made it part of the 8k template that I was working on. Edited February 4, 2009 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 13, 2008 Author Share Posted November 13, 2008 (edited) Hmm, I merged the new kernal with my source code, but I have several problems. First, the objects are flickering obsessively. Not only that, but upon closer examination of each frame, the playfield seems to be changing priority continuously because one frame, a dragon would appear in front of the playfield, and on another frame it would appear behind it. Also, dragons have a difficult time biting, probably due to the bad flickering. They also seem to be cycling through states at times. I worked on this at my parent's house and there were quite a few distractions, so I'm going to give this another try and see if I get the same results. It might have had to do with where I made changes so that it was compatible with the indirect Y loading that my source uses. And what does this mean? Is it applicable to me, or should I just remove it? ;do not use these lines if RoomLo/Hi is not shared... The room display works perfectly. It's just the objects that are having the problem. I'll post back here if I figure out what it was. Oh hah, by the way, one of my bitmaps is 80 bytes, with a total of four bitmaps on the entire page filling it up exactly. Thankfully I have about 11 more pages reserved for screen bitmaps, and those four bitmaps are the most detailed of the bunch. I'm not going to have any problems filling up my entire 8k. Edited November 13, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 13, 2008 Author Share Posted November 13, 2008 Got 'er. It was indeed something I forgot. I didn't update the return code for the second bank. Now to see what neat little things I can come up with. >~ Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted November 13, 2008 Share Posted November 13, 2008 I was wondering about something and it might just be possible. IIRC, the bit in the playfield control register that controls the mirroring, could theoretically be switched on and off as the screen bitmap is drawn to achieve a playfield layout that is somewhat non-symmetrical. The engine could look for a certain bit set in the screen bitmap's PF0 byte and XOR the bit sent to the playfield register, effectively toggling it each time the condition is met. I know I'm always going on about how Adventure could extremely benefit from asymmetrical playfields, but this idea could be a great compromise. Would this even be possible? It's a long shot, but I can see amazing things resulting from this. Here's a textual result of a room that would take advantage of such an addition: .byte $F0,$FF,$0F;XXXXXXXXXXXXXXXX RRRRRRRRRRRRRRRR .byte $30,$00,$00;XX RR .byte $30,$00,$00;XX RR .byte $F0,$C0,$FC;XXXXXX XXXXXXRRRRRR RRRRRR .byte $30,$00,$00;XX MM <- * .byte $30,$00,$00;XX MM .byte $F0,$FF,$FF;XXXXXXXXXXXXXXXXXXXXMMMMMMMMMMMMMMMMMMMM * Playfield register updated on noted line. The value specified in the room data table could perhaps just be used as the initial value of the mirroring behavior. From Nukey's replies, it sounds like he's already accommodated you. I'm just writing to point out that at least one game used this type of technique-- Tutankham for the Atari 2600. I'm looking forward to seeing what you do with it. Michael Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 13, 2008 Author Share Posted November 13, 2008 It's difficult designing playfields using this. I'm tempted to write a new playfield editor (as if I haven't already written enough of them ), but I haven't a strong direction about how to do the variable row heights with the most flexibility possible without cluttering up the interface. I'll probably do things by hand until I get fed up enough to work on a new editor. I'm anxious myself to see what I can come up with. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 13, 2008 Share Posted November 13, 2008 And what does this mean? Is it applicable to me, or should I just remove it? ;do not use these lines if RoomLo/Hi is not shared... In the setup routine in the original game, RoomLo and RoomHi are stored (the vector for the screen gfx). To save 2 bytes of ram, these variables can be shared with others. In the setup routine here, the room number is stored to another ram location (Control, in this case). When the display executes, the program uses this other ram location to fetch the room number - which is then used as an offset to load the RoomLo/Hi vector. The reason that the routine does not use PlayerRoom is because the collision routine bounces it around a little bit (Try it yourself...replace LDA Control with LDA PlayerRoom and bounce against a wall as you flip screens). Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 13, 2008 Author Share Posted November 13, 2008 (edited) 68-byte preview. Oh and stuff can be hidden behind the trees. Edited November 13, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
accousticguitar Posted November 14, 2008 Share Posted November 14, 2008 Nice! Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 14, 2008 Author Share Posted November 14, 2008 (edited) I found a small glitch, Nukey. It's pretty insignificant, but if you set the playfield priority above the missiles, then missile0 overlaps the playfield by one scanline. It might be something that was present in the original adventure, or it might be a result of your improved kernal. Just set the playfield priority of any screen with missile 0 enabled. In my attached example, I set the priority about halfway down the screen and onwards. Missile 1 is pixel-perfect in the right image. If you can't reproduce the problem in your sources, then it's probably something I did. I was repositioning the missiles and I modified their width. Like I said, it's nothing major though, or at least I hope not. Edited November 14, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
accousticguitar Posted November 14, 2008 Share Posted November 14, 2008 Odyssey is going to be one sweet-looking Adventure hack! Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 14, 2008 Share Posted November 14, 2008 I found a small glitch, Nukey. It's pretty insignificant, but if you set the playfield priority above the missiles, then missile0 overlaps the playfield by one scanline. It might be something that was present in the original adventure, or it might be a result of your improved kernal. Just set the playfield priority of any screen with missile 0 enabled. In my attached example, I set the priority about halfway down the screen and onwards. Missile 1 is pixel-perfect in the right image. It's because priority isn't set until halfway through the scanline. There's no good solution to this...setting priority earlier would interfere with timing of playfield display. This is not an issue with the original game, because priority is only set once there. To fix the problem, even more cycles would need to be saved. One way would be to break up playfield data into 4 tables for each screen so that the multiple INY's are not needed (but increasing RAM overhead, because 4 display vectors would be required instead of only 1). LAX (PF0vector),Y ;5 Get first room definition byte STA PF0 ;3 ...and display LDA (CTRLvector),Y ;5 Get row's CTRL value STA CTRLPF ;3 Store to playfield control LDA (PF1vector),Y ;5 Get next room definition byte STA PF1 ;3 ...and display LDA (PF2vector),Y ;5 Get next room definition byte STA PF2 ;3 ...and display Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 14, 2008 Share Posted November 14, 2008 (edited) BTW if you are concerned about rom space wasted for generic screen layouts, you can cut this down by swapping CTRL with the linecounter (so that linecount values greater than 16 can be used). The code change is pretty simple (shown in lower-case)... Print_Top_Line: LAX (RoomLo),Y ;5 Get first room definition byte STA PF0 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF1 ;3 ...and display INY ;2 bump index LDA (RoomLo),Y ;5 Get next room definition byte STA PF2 ;3 ...and display INY ;2 bump index ;added lines... txa ;2 Get PF0 definition back and #$0F ;2 keep only low nybble of PF0 ora #$20 ;2 merge in the ball size sta CTRLPF ;3 Store to playfield control LDA (RoomLo),Y ;5 Get number of scanlines ;removed lines... ; STA CTRLPF ;3 Store to playfield control ; TXA ;2 Get PF0 definition back ; AND #$0F ;2 keep only low nybble of PF0 STA PixelCount ;3 Store to line counter INY ;2 bump index STY RoomDefIndex ;3 ...and save for Next Time LAX ScanLineCnt ;3 Get current scan line DEX ;2 ...and... PrintPlayer00_2: DEC PixelCount ;5 decrement the line counter beq Print_More_Lines ;2 branch if end of this band Any screen could then be as small as 4 bytes for the entire display. Here's the game select screen... Room00:;Number Room Definition .byte $F1,$FF,$FF,$08;8 scanlines .byte $31,$00,$00,$50;80 scanlines .byte $F1,$FF,$0F,$10;16 scanlines Edited November 14, 2008 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 14, 2008 Author Share Posted November 14, 2008 (edited) Ah! Thank you so much, I will definitely swap the CTRLPF and scanline count. It makes more sense that way anyhow. The only thing I will not be able to do on a line per line basis is change the ball width (because it needs the upper nybble), but I never planned on doing that in the first place. I had a lot of places in my room bitmaps where I would need to use multiple identical lines to fill up the screen. I can probably free up to an entire page of space or more with those changes! The bitmap you see in the screenshots above are 52 bytes. With the new code, they are 40. A 24 byte savings between just two bitmaps. Odyssey is going to be one sweet-looking Adventure hack! Oh, you probably haven't seen anything yet. I took into account the massive ROM usage when I implemented Nukey's new (new new) kernal. So I had enough room for about 4-6 screens per page and still make my 55 room goal. Now with the extra byte savings, I can make some rooms more detailed than planned. Edited November 14, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 14, 2008 Share Posted November 14, 2008 The bad thing about variable ball sizes is that it could skew when moving in the middle of the display (because CTRL isn't reset until after the left half had been drawn). If you happen to be moving on the start of a new band (which uses a different ball width), the upper line of the ball would be clipped. The kernal also doesn't include variable ball height. There are also other issues regarding using the horizontal location in calculations (such as placing the surround object). So this is a better use of the definition tables all around. Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 14, 2008 Author Share Posted November 14, 2008 88 bytes saved between all the screens I had done so far. I only have about 11 screens or so completed, so that's about 1/5th of the total I had planned. Add up those savings, and I was I correct, probably going to have an entire page of ROM that I can use to make stuff even more detailed. Quote Link to comment Share on other sites More sharing options...
accousticguitar Posted November 15, 2008 Share Posted November 15, 2008 Looks like you have your work cut out for you. I'm still looking forward to it. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted November 15, 2008 Share Posted November 15, 2008 Actually, you can increase the rom size to 16k or 32k if more space is needed. Just have each bank hold a specific stretch of rooms, check which one is currently displayed, and bankswitch accordingly. You'll need to keep your sprites positioned exactly the same in each bank (tho you could make them look different if desired). A possible use of this idea is to have all dark rooms in one bank, all lighted rooms in another...and have the dragons and things look slightly different in the "dark" Quote Link to comment Share on other sites More sharing options...
EarthQuake Posted November 15, 2008 Author Share Posted November 15, 2008 (edited) o_O "Turning Adventure into a 16k game..." Edited November 15, 2008 by EarthQuake Quote Link to comment Share on other sites More sharing options...
supercat Posted November 15, 2008 Share Posted November 15, 2008 (but increasing RAM overhead, because 4 display vectors would be required instead of only 1). How about using two pointers and one INY? 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.