Jump to content

SpiceWare

+AtariAge Subscriber
  • Posts

    18,545
  • Joined

  • Last visited

  • Days Won

    11

Blog Entries posted by SpiceWare

  1. SpiceWare

    Vectrex
    This is a followup to the MenuMaker 0.2 blog entry from 2014.

    @eyelyft approached me in 2019 about recompiling MenuMaker as it was a 32-bit program and MacOS is now 64-bit only. I'd done a clean install of my Mac since then, so downloaded the source from blog post but discovered it was missing files.  I wasn't able to find the missing files so thought I'd lost part of the source during the clean install.
     
    Last week during a @ZeroPage Homebrew stream on Twitch discussion turned to Vectrex and MenuMaker. @Nathan Strum made a comment about getting the original source from @Richard H. again.
     
    Yesterday I was thinking about that so on a whim searched my email and found this:
     

     
     
     
    The original AtariAge message is long gone, but the email did have the source that Richard had sent me all those years ago. On another whim I did a Spotlight search using some variable names from the source and found what appears to be the complete source for this project (I won't know for sure until I can attempt to rebuild it - bummer, turned out not to be as seen in the followup comments below).
     
     
    Now I need to figure out how to get the current version of Lazarus to work so I can rebuild MenuMaker as a 64-bit program. After upgrading Lazarus it complained that it couldn't find Make or Debugger, which means it's not able to build any programs.
     
     
    So I uninstalled Lazarus, then reinstalled it using brew which I had installed over the summer so I could install ImageMagick to do some SVG experiments* for work.  With the brew installation Lazarus is able to find both Make and Debugger:
     

     

     
     
    however it can't find FPC sources:
     

     
    Have plans with my folks today, so this is where I'm leaving off for now.
     
    To be continued...
     
     
     
    * which failed, ImageMagick's support for SVGs was really bad. I ended up using the .Net WebBrowser control to render the SVGs, which worked but results in the loss of the SVG's alpha channel that I needed.  I figured out how to recreate it by rendering each SVG twice, once on a black background and once on a white - diffing the pixels allowed me to recreate the alpha channel.
  2. SpiceWare

    Vectrex
    I've wanted a Vectrex ever since they came out - 30 years later I finally got one. I won it yesterday on eBay and was surprised when it arrived today via UPS! Turns out the seller is located in Beaumont, a mere 84 miles to the east of Houston.
     
    The unit came with Fortress of Narzod and it's overlay, but not the overlay for the built in game Mine Storm. It also has 2 controllers though one of them auto-centers horizontally, but not vertically, and rattles a bit when moved (this was noted in the ebay listing). Looks like somebody tried to open it up to fix it as there's a lot of gouged plastic where the top and bottom halves of the controller join together.
     
    I've taken Fortress of Narzod and Mine Storm for a brief spin to test the unit. Both games are quite challenging.
     
    My unit is one of the earlier units that has the buzz, so I'll have to look into fixing that - I found some instructions on how to do that at the bottom of this page of this site.
  3. SpiceWare

    Vectrex
    NOTE: use MenuMaker 0.4. It fixes a bug found in version 0.3, and adds support for the 2019+ VecMulti.
     
    MenuMaker has been updated for 64-bit macOS. This will create the menu for @Richard H.'s VecMulti SD cartridge for the Vectrex.
     
     

     

    Program with source:
    MenuMaker20211211.zip
     
    Port was done using Lazarus, which is available for Linux, Mac, and Windows.
     
    Use MenuMaker 0.2 if you're still on a 32-bit version of macOS.
  4. SpiceWare

    Vectrex
    Turns out there's an updated version of VecMulti that requires a slightly different format for the menu file. The menu created with MenuMaker 0.3 would show extra characters on those VecMulti cartridges, resulting in the names shifting.
     
     

     
    Starting with Page 2 the names would no longer line up with the numbers 1-4 (game 1 on page 2 is AllGoodThings).
     

     
    With the help of @NeonPeon I've been able to reverse engineer the new format, and have updated MenuMaker to support both versions.
     
     

     
     
    By default the menu will be created for the Original VecMulti. If the resulting menu is shifted, then select 2019+ VecMulti to create the menu with the new format.  The selection will be remembered.
     
    Also fixed a one-off bug I discovered in version 0.3 that caused the last game in the Games directory to not show up in the menu.
     
    Program with Source
    MenuMaker20220110.zip
     
  5. SpiceWare
    Let's review the TIA Timing diagram from last time:

     
    We used that to determine when we could safely update the playfield data in order to draw the score and timer. For moveable objects(player0, player1, missile0, missile1 and ball) if you update their graphics during the Visible Screen (cycles 23-76) you run the risk of shearing. For something that's moving fast, like the snowball in Stay Frosty 2, shearing may be an acceptable design compromise:

     
    That snowball should be square, but the left edge has sheared due to the ball object being updated mid-scanline.
     
    To prevent shearing we need to update the objects on cycles 0-22. There's a lot of calculations to be done in the kernel to draw just one player. For Collect I'm using DoDraw, which looks like this for drawing player0:
    DoDraw0: lda #HUMAN_HEIGHT-1 ; 2 2 - height of the humanoid graphics, subtract 1 due to starting with 0 dcp HumanDraw ; 5 7 - Decrement HumanDraw and compare with height bcs DoDrawGrp0 ; 2 9 - (3 10) if Carry is Set, then humanoid is on current scanline lda #0 ; 2 11 - otherwise use 0 to turn off player0 .byte $2C ; 4 15 - $2C = BIT with absolute addressing, trick that ; causes the lda (HumanPtr),y to be skipped DoDrawGrp0: ; 10 - from bcs DoDrawGrp0 lda (HumanPtr),y ; 5 15 - load the shape for player0 sta GRP0 ; 3 18 - update player0 to draw Human    
     
    That's 18 cycles to draw a single player. One way to make it easier to fit all the code in is to use a 2 Line Kernel (2LK). In a 2LK we update TIA's registers over 2 scanlines in order to build the display. For Collect, the current routines are updating them like this:
    player0, playfield player1, playfield  
    The actual code looks like this:
    ldy #ARENA_HEIGHT ; 2 7 - the arena will be 180 scanlines (from 0-89)*2 ArenaLoop: ; 13 - from bpl ArenaLoop ; continuation of line 2 of the 2LK ; this precalculates data that's used on line 1 of the 2LK lda #HUMAN_HEIGHT-1 ; 2 15 - height of the humanoid graphics, subtract 1 due to starting with 0 dcp HumanDraw ; 5 20 - Decrement HumanDraw and compare with height bcs DoDrawGrp0 ; 2 22 - (3 23) if Carry is Set, then humanoid is on current scanline lda #0 ; 2 24 - otherwise use 0 to turn off player0 .byte $2C ; 4 28 - $2C = BIT with absolute addressing, trick that ; causes the lda (HumanPtr),y to be skipped DoDrawGrp0: ; 23 - from bcs DoDrawGrp0 lda (HumanPtr),y ; 5 28 - load the shape for player0 sta WSYNC ; 3 31 ;--------------------------------------- ; start of line 1 of the 2LK sta GRP0 ; 3 3 - @ 0-22, update player0 to draw Human ldx #%11111111 ; 2 5 - playfield pattern for vertical alignment testing stx PF0 ; 3 8 - @ 0-22 ; precalculate data that's needed for line 2 of the 2LK lda #HUMAN_HEIGHT-1 ; 2 10 - height of the humanoid graphics, dcp BoxDraw ; 5 15 - Decrement BoxDraw and compare with height bcs DoDrawGrp1 ; 2 17 - (3 18) if Carry is Set, then box is on current scanline lda #0 ; 2 19 - otherwise use 0 to turn off player1 .byte $2C ; 4 23 - $2C = BIT with absolute addressing, trick that ; causes the lda (BoxPtr),y to be skipped DoDrawGrp1: ; 18 - from bcs DoDrawGRP1 lda (BoxPtr),y ; 5 23 - load the shape for the box sta WSYNC ; 3 26 ;--------------------------------------- ; start of line 2 of the 2LK sta GRP1 ; 3 3 - @0-22, update player1 to draw box ldx #0 ; 2 5 - PF pattern for alignment testing stx PF0 ; 3 8 - @0-22 dey ; 2 10 - decrease the 2LK loop counter bpl ArenaLoop ; 2 12 - (3 13) branch if there's more Arena to draw    
     
    If you look at that closely, you'll see I'm splitting DoDraw a bit so that this is how the 2LK works:
    updates player0, playfield, precalc player1 for line 2 updates player1, playfield, precalc player0 for line 1 By pre-calculating data during the visible portion of the scanline, we'll have more time during the critical 0-22 cycles for when we add the other objects.
     
    Since we're updating the players on every other scanline, each byte of graphic data is displayed twice (compare the thickness of the humanoid pixels with the red lines drawn with the playfield). Also, the players never line up as they're never updated on the same scanlines:

    closeup:

     
    The designers of TIA planned for this by adding a Vertical Delay feature to the players and ball (though sadly not the missiles). The TIA registers for this are VDELP0, VDELP1 and VDELBL. For this update to Collect, I've tied the Vertical Delay to the difficulty switches, putting the switch in position A will turn on the delay for that player so we can experiment with how that works. For the next update I'll set the Vertical Delay based on the Y position of the player (this also means the maximum Y value will be double that of this build).
     
    Left Difficulty A, Right Difficulty B so VDELP0 = 1 and VDELP1 = 0. Sprites line up with the same Y

    closeup:

     
    Left Difficulty B, Right Difficulty A so VDELP0 = 0 and VDELP1 = 1. Sprites line up when player1's Y = player0's Y + 1

    Closeup:

     
     
    The code that preps the data used by DoDraw looks like this:
    ; HumanDraw = ARENA_HEIGHT + HUMAN_HEIGHT - Y position lda #(ARENA_HEIGHT + HUMAN_HEIGHT) sec sbc ObjectY sta HumanDraw ; HumanPtr = HumanGfx + HUMAN_HEIGHT - 1 - Y position lda #<(HumanGfx + HUMAN_HEIGHT - 1) sec sbc ObjectY sta HumanPtr lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta HumanPtr+1 ; BoxDraw = ARENA_HEIGHT + HUMAN_HEIGHT - Y position lda #(ARENA_HEIGHT + HUMAN_HEIGHT) sec sbc ObjectY+1 sta BoxDraw ; BoxPtr = HumanGfx + HUMAN_HEIGHT - 1 - Y position lda #<(HumanGfx + HUMAN_HEIGHT - 1) sec sbc ObjectY+1 sta BoxPtr lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta BoxPtr+1 ... HumanGfx: .byte %00011100 .byte %00011000 .byte %00011000 .byte %00011000 .byte %01011010 .byte %01011010 .byte %00111100 .byte %00000000 .byte %00011000 .byte %00011000 HUMAN_HEIGHT = * - HumanGfx    
     
    The graphics are much easier to see using my mode file for jEdit:
     

     
    I'm sure some of you are wondering why the human graphics are upside down. If you wanted to loop thru something 10 times, you'd normally think to write the code like this:
    ldy #0 Loop: ; do some work iny cpy #10 bne Loop    
     
    But the 6507 does an automatic check for 0 (as well as positive/negative) which lets you save 2 cycles of processing time by eliminating the CPY command:
    ldy #10 Loop: ; do some work dey bne Loop    
     
    Alternatively, if your initial value is less than 128, you can use this:
    ldy #(10-1) Loop: ; do some work dey bpl Loop    
     
    Making the loop count down instead of up saves 2 cycles, but doing so requires the graphics to be upside down. 2 cycles doesn't sound like much, but in a scanline that's 2.6% of your processing time and saving it might be what allows you to update everything you want. In Kernels I've written, I often use every cycle - and that includes eliminating the sta WSYNC to buy back 3 cycles of processing time. See the reposition kernels in this post about Draconian.
     
    I've also added joystick support that will let you move around the players. Pressing FIRE will slow down the movement, making it easier to line things up. The score (on the left) is used to display player0's Y position, and the timer is used for player1. As an added bonus, I'm showing how you can save ROM space by creating graphics that only face in one direction by using REFP0 and REFP1 (REFlect Player) to make the graphics face the other way. The routine's fairly sizable, so I'm not posting it here so download the source code and check it out!
     
    ROM
    collect_20140703.bin
     
    Source
     
    Collect_20140703.zip
     
    COLLECT TUTORIAL NAVIGATION
    <PREVIOUS> <INDEX> <NEXT>
  6. SpiceWare
    Static images that just slide around the screen work OK, but we can do better - so for this update we'll add a couple new images so we can animate the players as they run around the arena.

     
    While you can have as many frames of animation as you'd like, the code is most efficient if the number of frames is a power of 2 (2, 4, 8, 16, etc). The code that cycles through 4 frames is this:
    Example: inc frame lda frame and #3 ; limits values from 0-3, if A was 4 it becomes 0 after the and sta frame    
    Just change the #3 to #7 (8 frames), #15 (16 frames) and so on. If you wanted to cycle thru a non-power of 2 count, say for example 5 frames, the code would look like this:
    Example: ldx frame inx cpx #5 bne save ldx #0 save: stx frame    
    For Collect we're going to use 4 frames. You might be wondering why there's only 3 humanoid images - it's because we're going to use 1 of the images twice:
    HumanGfx HumanRunning0 HumanRunning1 HumanRunning0  
    In order to animate the players we'll need to keep track of which frame they're showing, so let's add 2 new RAM variables:
    ; indexes for player animation sequences Animation0: ds 1 ; stored in $B3 Animation1: ds 1 ; stored in $B4   Then modify PositionObjects so it will animate the images when it preps the variables for the 2LK, but only when the player is in motion:
    PositionObjects: ... ; select image to show for Player0 lda ObjectX ; get current X location for player 0 cmp SavedX ; compare with prior X location bne Animate0 ; if different, animate player 0 lda ObjectY ; otherwise check current Y location cmp SavedY ; against prior Y location bne Animate0 ; and animate player 0 if they're different lda #0 ; if X and Y didn't change then select 0, the beq SaveFrame0 ; stationary image, and save it Animate0: inc Animation0 ; increment to select the next frame lda Animation0 ; load it and #3 ; limit to 0-3 (if it was 4, it's now 0) SaveFrame0: sta Animation0 ; save it tax ; Transfer A to X ; Player0Ptr = HumanGfx + HUMAN_HEIGHT - 1 - Y position lda ShapePtrLow,x ; select image as specified in X sec sbc Temp sta Player0Ptr lda ShapePtrHi,x ; select image as specified in X sbc #0 sta Player0Ptr+1 ... ShapePtrLow: .byte <(HumanGfx + HUMAN_HEIGHT - 1) .byte <(HumanRunning0 + HUMAN_HEIGHT - 1) .byte <(HumanRunning1 + HUMAN_HEIGHT - 1) .byte <(HumanRunning0 + HUMAN_HEIGHT - 1) .byte <(BoxGfx + HUMAN_HEIGHT - 1) ShapePtrHi: .byte >(HumanGfx + HUMAN_HEIGHT - 1) .byte >(HumanRunning0 + HUMAN_HEIGHT - 1) .byte >(HumanRunning1 + HUMAN_HEIGHT - 1) .byte >(HumanRunning0 + HUMAN_HEIGHT - 1) .byte >(BoxGfx + HUMAN_HEIGHT - 1)   The code for player 1 is almost the same, though it adds a test so the box image will be displayed for one player game variations:
    ; select image to show for Player1 bit Players bpl UseBoxImage ; if 1 player game then draw the box lda ObjectX+1 ; get current X location for player 1 cmp SavedX+1 ; compare with prior X location bne Animate1 ; if different, animate player 1 lda ObjectY+1 ; otherwise check current Y location cmp SavedY+1 ; against prior Y location bne Animate1 ; and animate player 1 if they're different lda #0 ; if X and Y didn't change then select 0, the beq SaveFrame1 ; stationary image, and save it Animate1: inc Animation1 ; increment to select the next frame lda Animation1 ; load it and #3 ; limit to 0-3 (if it was 4, it's now 0) SaveFrame1: sta Animation1 ; save it tax ; Transfer A to X .byte $2C ; $2C = BIT with absolute addressing, trick that ; causes the ldx #4 to be skipped over UseBoxImage: ldx #4 ; select the Box Image ; Player1Ptr = BoxGfx + HUMAN_HEIGHT - 1 - Y position lda ShapePtrLow,x ; select image as specified in X sec sbc Temp sta Player1Ptr lda ShapePtrHi,x ; select image as specified in X sbc #0 sta Player1Ptr+1    

     
     
    It works, but the players move so fast they look spastic.
     
    collect_20140714_toofast.bin
     
    To fix that, well revise it to use an image over multiple frames. For testing, we'll make the left player use each image for 2 frames while the right uses each image for 4:
    Animate0: inc Animation0 ; increment to select the next frame lda Animation0 ; load it and #7 ; limit to 0-7 (if it was 8, it's now 0) SaveFrame0: sta Animation0 ; save it lsr ; divide by 2 for 0-3 - this means we show the same ; image twice in succession tax ; Transfer A to X ... Animate1: inc Animation1 ; increment to select the next frame lda Animation1 ; load it and #15 ; limit to 0-15 (if it was 16, it's now 0) SaveFrame1: sta Animation1 ; save it lsr ; divide by 4 for 0-3 - this means we show the same lsr ; image four times in succession tax ; Transfer A to X    
    collect_20140714_speedtest.bin
     
    Both look OK, though I think the left player looks a little better so the final version will use each image twice. One minor thing happens when the game is over - if the players were in motion, the animation keeps on going even though the players are no longer in motion.

     
    To fix that, well add a Game Over check (same logic was added for Player1) that will select the stationary image:
    ; select image to show for Player0 bit GameState bpl StopAnimation0 ; if game is inactive, stop animation lda ObjectX ; get current X location for player 0 cmp SavedX ; compare with prior X location bne Animate0 ; if different, animate player 0 lda ObjectY ; otherwise check current Y location cmp SavedY ; against prior Y location bne Animate0 ; and animate player 0 if they're different StopAnimation0: lda #0 ; if X and Y didn't change then select 0, the beq SaveFrame0 ; stationary image, and save it    

     
     
    ROM
     
    collect_20140714.bin
     
    Source:
     
    Collect_20140714.zip
     
    COLLECT TUTORIAL NAVIGATION
    <PREVIOUS> <INDEX> <NEXT>
     
  7. SpiceWare
    Awesome cover of Paint it Black by Harp Twins and Volfgang Twins.
     
     
     
    I saw them perform it live back in November at the Houston Arcade Expo:
     

     
    For those of you in Europe they are currently touring in your neck of the woods. Well worth seeing them live if you can.  
     

     
  8. SpiceWare
    new main menu title graphic
    shield sound effect changes pitch based on shield time remaining
    new ship "blink" feedback ship will blink while shields are active
    ship will blink during respawn temporary immunity
    blink rate will increase as shield life/immunity remaining runs out



     
    ROMs
    spacerocks20121129_NTSC.bin
    spacerocks20121129_PAL.bin
     
    Source
    spacerocks20121129.zip
  9. SpiceWare

    Draconian
    While getting ROMs together for Nathan for his RetroN 77 contribution to the Stella-thon 12 Hour Gaming Marathon Fundraiser! event I realized I've yet to publish the final ROM for Draconian.
     
    ROM:
    draconian_20171020_RC8.bin
     
    NOTE: newer versions of the Harmony Cartridge use a different chip that does not work with the above ROM. batari posted this patched version of the final ROM in this topic where he explains why the patch was needed:
    Draconian_Harmony_fix.bin
     
     
    Source*:
    draconian_linux.zip
     
    * linux is in the zipped directory name because I used my Linux laptop to finish Draconian on the way to PRGE.
  10. SpiceWare

    Warlords
    In this topic about the exciting new RGB mod for the 2600, collinp reported that the XRGB-mini had problems syncing with Warlords.

    I took a quick look and noticed that VSYNC was set before the WSYNC, instead of after, which resulted in the sync signal starting late in the scanline.


    I did a quick hack via Stella to swap the order. The hack resulted in the kings getting shifted to the right, but was enough for collinp to confirm that moving the VSYNC after the WSYNC did indeed fix the problem.


    Today I fixed the sync and king positions by modifying the source I documented back in 2006. The source can be used to compile the original ROM or an XRGB-mini compatible build by use of the constant XRGBMINI:
    ; set to 1 for VSYNC fix for XRGBMINI, set to 0 for original XRGBMINI = 1 ... StartOfFrame: LDA #$82 ; P-----V- P-paddles are dumped to ground, V-vertical Blank is started if XRGBMINI = 1 ldx #$50 ; move left 5 STA VBLANK STA WSYNC ; Wait until end of 1st V-Sync scan Line STA VSYNC ; Start Vertical Sync STX HMM0 STX HMM1 else STA VBLANK STA VSYNC ; Start Vertical Sync STA WSYNC ; Wait until end of 1st V-Sync scan Line LDA #$20 ; Move Left 2 STA HMM0 ; 3 5 STA HMM1 ; 3 8 endif  
    ROM
    warlords_xrgbmini.bin
     

    Source
    warlords.asm
     
     
    Defender
    defender_vsync.bin
     
    defender_vblank.bin
     
     
    Source
    Defender (1982) (Atari).asm.zip
  11. SpiceWare

    Miscellaneous
    Picked up a Mac Studio today.  It's a stock M2 Ultra version. I used the Migration Assistant and transferred everything over from my nearly 9 year old Mac Pro. 
     

     
    I ordered a couple USB-C to mini DisplayPort adapters to use my existing cables to connect the Studio to my 4K monitors.
     
    AtariAge is noticeably more responsive on the Studio, I was not expecting that.
     
    Like I did with classic Doctor Who, I've been doing a rewatch of Star Trek in air date order. I'm currently in season 6 of The Next generation, just a few episodes from when Deep Space Nine begins, so have been ripping my Deep Space Nine DVDs.  Since I had everything handy I decided to run a test of converting an episode.
     
    Handbrake results on Mac Pro:
     

    on Mac Studio:
     

     
    The Studio has been running a bunch of background tasks, such as the initial spotlight indexing and first Time Machine backup, so I plan run another test tomorrow to see if performance improves.
     
    Screenshots are different sizes because my Mac Pro is now hooked up to a 1080p display.
  12. SpiceWare
    First things first - head over to MiniDig - best of stella and download the Stella Programmer's Guide from the docs page. I've also attached it to this blog entry, but you should still check out what's available over at MiniDig.

    Also, for this tutorial you'll need to have DASM to compile the code as well as Stella and/or a real 2600 with a Harmony cart to run your code.

    The heart of the Atari is TIA, the Television Interface Adaptor. It's the video chip, sound generator, and also handles some of the controller input. As a video chip, TIA is very unusual. Most video game systems have memory that holds the current state of the display. Their video chip reads that memory and uses that information to generate the display. But not TIA - memory was very expensive at the time, so TIA was designed with a handful of registers that contain just the information needed to draw a single scanline. It's up to our program to change those registers in realtime so that each scanline shows what its supposed to. It's also up to our program to generate a "sync signal" that tells the TV when its time to start generating a new image.

    Turn to page 2 of the programmer's guide. You'll find the following diagram, which I've slightly modified:




    The Horizontal Blank is part of each scanline, so we don't need to worry about generating it. Everything else though is up to us! We need to generate a sync signal over 3 scanlines, after which we need to wait 37 scanlines before we tell TIA to "turn on" the image output. After that we need to update TIA so each of the 192 scanlines that comprise visible portion of the display show what they're supposed to. Once that's done, we "turn off" the image output and wait 30 scanlines before we start all over again.

    In the source code, available below, you can see the Main loop which follows the diagram:
    Main: jsr VerticalSync ; Jump to SubRoutine VerticalSync jsr VerticalBlank ; Jump to SubRoutine VerticalBlank jsr Kernel ; Jump to SubRoutine Kernel jsr OverScan ; Jump to SubRoutine OverScan jmp Main ; JuMP to Main  

    Each of the subroutines handles what's needed, such as this section which generates the sync signal:
    VerticalSync: lda #2 ; LoaD Accumulator with 2 so D1=1 sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) sta VSYNC ; Accumulator D1=1, turns on Vertical Sync signal sta WSYNC ; Wait for Sync - halts CPU until end of 1st scanline of VSYNC sta WSYNC ; wait until end of 2nd scanline of VSYNC lda #0 ; LoaD Accumulator with 0 so D1=0 sta WSYNC ; wait until end of 3rd scanline of VSYNC sta VSYNC ; Accumulator D1=0, turns off Vertical Sync signal rts ; ReTurn from Subroutine  

    Currently there's no game logic, so the VerticalBlank just waits for the 37 scanlines to pass:
    VerticalBlank: ldx #37 ; LoaD X with 37 vbLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) dex ; DEcrement X by 1 bne vbLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine  

    The Kernel is the section of code that draws the screen.
    Kernel: ; turn on the display sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) lda #0 ; LoaD Accumulator with 0 so D1=0 sta VBLANK ; Accumulator D1=1, turns off Vertical Blank signal (image output on) ; draw the screen ldx #192 ; Load X with 192 KernelLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) stx COLUBK ; STore X into TIA's background color register dex ; DEcrement X by 1 bne KernelLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine  

    For this initial build it just changes the background color so we can see that we're generating a stable picture:


    Like Vertical Blank, OverScan doesn't have anything to do besides turning off the image output, so it just waits for enough scanlines to pass so that the total scanline count is 262.
    OverScan: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) lda #2 ; LoaD Accumulator with 2 so D1=1 sta VBLANK ; STore Accumulator to VBLANK, D1=1 turns image output off ldx #27 ; LoaD X with 27 osLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) dex ; DEcrement X by 1 bne osLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine  

    Anyway, download the source and take a look - there's comments galore.


    ROM
    collect_20140624.bin
     
    Source
    Collect_20140624.zip
     
    Stella Programmer's Guide
    Stella Programmers Guide.pdf
     
    Addendum on Keynote - what the audience sees:


     
    What I see on the iPad:

     
    COLLECT TUTORIAL NAVIGATION
    <PREVIOUS> <INDEX> <NEXT>
  13. SpiceWare

    Draconian
    A while back, Nathan posted some well thought out mockups detailing how to do Bosconian on the Atari 2600. There was a bit of discussion, including a suggestion by supercat for drawing the stations using players instead of the playfield. But nothing came of it - until today.
     
    Two weeks ago I approached Nathan about possibly using the routines from Space Rocks to implement his ideas. Those routines seemed ideal as they support objects with unique colors as well as the ability to set their size and do the left/right shifting for supercat's station suggestion. I expressed the desire to have something to post today, which is the eight year anniversary of that blog post.
     
    After that I decided Nathan's original idea of using the playfield would look better (less flicker) so it would make sense to use Frantic's routines instead. One problem I had was Bosconian can have a lot of shots flying around and Frantic's routines were limited to just 6 shots. So I started to revise it to support missile repositioning. Ended up having to drop the ball object to make that work but I was able to figure out how to reuse the missile objects. Tricky part was keeping the size changes of the missiles and players in sync (as each player/missile pair uses a single register to control their sizes). The solution was to only worry about the player size when repositioning the player, and likewise for the missile size and its repositioning. After all the objects have been repositioned, then run a "clean up" routine that fixes all the size changes. If you care to look in the code, available below, check out function FixSizes().
     
    I then had second thoughts about using the playfield due to the shear amount of data that would be moving around due to the desire to use single line resolution for the station detail:

     
    So I decided to drop the playfield and add back the ball object. That's when I figured out that Slick Kernel that can reposition an object on every scanline. Since I could reuse the objects so frequently, I decided to update COLUPF when repositiong the ball instead of CTRPPF. This means the ball is a fixed size, but each instance of the ball can be a unique color.
     
    One thing not really worked out was the radar display. Nathan's mockup included the ingenious idea of using an indicator on the edges of the display:

     
    But recently Ed Fries posted Rally X were he'd worked out a rather slick radar implementation that shows the flags, cars and player position all in different colors without any flicker.

     
    I thought that would work well for Bosconian. Since the radar uses both players, the normal 6-digit score routine can't be used in the same screen section as the radar. Since the radar would look odd all by itself, I decided to go old-school and use the playfield to display the score and lives information.
     
    After a couple weeks of late night coding sessions, we have something to show. It's not yet a playable game, though you can fly around the sector (or quadrant, we haven't decided ).
     
    Start of the menu

     
    Game screen. I'm rather pleased with how the starfield turned out. The arrangement and color is randomly generated at the start of each round. Each star maintains its color, even as they move in the background.

     
    Diagnostic display showing processing time remaining for Vertical Blank and Overscan:

     
    The divider line and corners of radar are used for the "Condition Color". Above you can see Green and Yellow - it can also be Red:

     
    An early build displayed the condition using a colored character:

    Controls:
    Left Difficulty - A= Diagnostic (time remaining in Vertical Blank and OverScan) Left Difficulty - B = score display (currently just counts up and shows in hex to test the digits) Right Difficulty - A = freeze ship (useful for looking at station damage) Right Difficulty - B = ship moves SELECT = return to menu START = start game Joystick = move around in sector/quadrant Fire = shoot (collision detection is not yet in place) Please remember this is very early build. You'll see issues such as flight angles(I'm look at you 45° ) that are not compensating for the non-square pixels as well as occasional jitter. Using the diagnostic display I can tell that Vertical Blank is overrunning when there's a lot of objects onscreen (see level 6), and Over Scan is sometimes overrunning when you start a new level. I believe that's due to the level init routines that prevent the randomly placed asteroids and mines from overlapping each other or the stations.
     
    If you're checking this out with Stella, be sure to turn on phosphor mode!
    open Draconian in Stella hit TAB for the in-game-menu select Game Properties Select the Display tab change Use Phosphor to Yes click OK select Exit Menu Reload the ROM (Control-R) ROM
    draconian_20140328.bin
     
    Source
    Draconian_20140328.zip
  14. SpiceWare

    DVR Project
    If you're interested in cutting the cord now might be a good time to get started!
     
    Your Choice: SiliconDust Streaming Boxes
     
    $149.99 - Simple.TV
    $119.99 - HDHomeRun PLUS
    $ 79.99 - HDHomeRun DUAL <-- this is what I'm using
     
    All of these are dual-tuner units.
     
    I'm not familiar with Simple.TV unit and don't have time to research it this morning. At first glance it appears to be a DVR that you add an external drive to, though it appears to be geared towards watching on your computer or portable device as it doesn't connect to your TV. Looks like you could use a Roku or similar device to watch it on your TV.
     
    HDHomeRun Plus is similiar to the HDHomeRun DUAL's that I use, though they add DLNA support and also convert the signal to H.264 (from MPEG2) which takes up less bandwidth on your network. Interesting idea, though I'd like to see it in action to get a feel for how good the on-the-fly conversion is.
     
    I'm using two of the HDHomeRun DUAL units, for the ability to tune up to 4 channels at the same time. I'm quite happy with them. Do note that I bought mine in 2012 and these newer models now have DLNA support.
  15. SpiceWare

    Draconian
    Station and station pod explosion sequences using placeholder images I whipped up as Nathan's been busy Station explosions are not deadly to the player's ship.
     
    Pod Explosion

     
    Station Explosion

     
    ROM
    draconian_20140513.bin
     
    Source
    Draconian_20140513.zip
     
     
  16. SpiceWare

    DVR Project
    Read this on the USA Today app on my iPad yesterday - TiVo is also catering to cord cutters.
     
    The $200 Roamio will record 4 shows at once (same as my Mac mini setup). It can also hook up to optional equipment like Mini to watch live and recorded TV in other rooms as well as Stream for watching TV on your mobile device from anywhere you have internet access.
     
    The $150 $75 (appears to be on sale) Premiere will record 2 shows at once and will also work with Stream.
     
    Both require a $15 monthly subscription or $129 annual subscription. Both record up to 75 hours of HD content, and can be expand with an external drive.
     
    The AirBox I blogged about last week doesn't specify number of tuners - if it's just 1 then a TiVo might be a better option, even with the slightly higher monthly cost. Also the TiVo will work in cities that don't have AirBox (I suspect these are the only markets that Airbox is available in).
  17. SpiceWare

    Draconian
    One issue with the station graphics is the gaps in the image which are used to create a shadow effect. They look great, but play havoc with collision testing. I built a test version, available below, that lets you move a horizontal shot around with the right joystick. It denotes a collision by changing the score to 888888:

     
    If the shot ends up in a shadow there's nothing to collide with, so the score shows 0:

     
    Collision tests are done row-by-row, so I got to thinking that a way to handle that would be to also consider the rows above and below the row being tested. I should be able to fill in the shadows by ANDing the above and below rows together then ORing that with the row being tested. In pseudo code that'd be (row-1 & row+1) | row.
     
    To test the idea, I wrote a quick a command line program. It first outputs the rows of the station using ASCII graphics:
    ............XXXX................ ............XXXX................ ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ......XXXXXXXX....XXXX.......... ..........XXXXXXXX.............. ......XXXXXXXX....XXXX.......... ..........XXXXXXXX.............. ..XXXX................XXXX...... ............XXXX................ XXXXXXXX............XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXX........XXXX....XXXX........ XXXXXXXX............XXXXXXXX.... XXXX........XXXX....XXXX........ XXXXXXXX....XXXX....XXXXXXXX.... XXXX....XXXXXXXXXXXXXXXX........ XXXXXXXX....XXXX....XXXXXXXX.... XXXX....XXXXXXXXXXXXXXXX........ XXXXXXXX............XXXXXXXX.... ............XXXX................ ..XXXX................XXXX...... ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..XXXX................XXXX...... ............XXXX................ XXXXXXXX............XXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXX....XXXXXXXXXXXXXXXX........ XXXXXXXX....XXXX....XXXXXXXX.... XXXX........XXXX....XXXX........ XXXXXXXX............XXXXXXXX.... XXXX........XXXX....XXXX........ XXXXXXXX....XXXX....XXXXXXXX.... XXXX........XXXX....XXXX........ XXXXXXXX............XXXXXXXX.... ............XXXX................ ..XXXX................XXXX...... ..........XXXXXXXX.............. ......XXXXXXXXXXXXXXXX.......... ..........XXXXXXXX.............. ......XXXXXXXX....XXXX.......... ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ..........XXXX.................. ..........XXXXXXXX.............. ................................ ............XXXX................    
    then again as each row would appear for collision testing:
    ............XXXX................ ............XXXX................ ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ......XXXXXXXXXXXXXXXX.......... ......XXXXXXXXXXXXXXXX.......... ......XXXXXXXXXXXXXXXX.......... ..........XXXXXXXX.............. ..XXXX......XXXX......XXXX...... ..XXXX......XXXX......XXXX...... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... ..XXXX......XXXX......XXXX...... ..XXXX......XXXX......XXXX...... ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..XXXX......XXXX......XXXX...... ..XXXX......XXXX......XXXX...... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXXXXXXXXXXXXXXXXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... XXXXXXXX....XXXX....XXXXXXXX.... ..XXXX......XXXX......XXXX...... ..XXXX......XXXX......XXXX...... ..........XXXXXXXX.............. ......XXXXXXXXXXXXXXXX.......... ......XXXXXXXXXXXXXXXX.......... ......XXXXXXXXXXXXXXXX.......... ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ..........XXXXXXXX.............. ............XXXX................ ............XXXX................   The test can be found in the source in subdirectory quadtest. The results looked good, so I dropped it in. We now get a collision in the shadows:

     
    but not in empty spaces outside the image.

     
    I also changed it so that flying into the station will destroy the station as well as the ship.
     
    ROMs
    draconian_20140508.bin
    draconian_20140508_test.bin
     
    Source
    Draconian_20140508.zip
  18. SpiceWare

    Draconian
    Added a new function, CollisionQuad(), that lets me test for collisions with the stations. So far only the shot routines have been updated to use this function. What this means is you can no longer take out all 6 station pods while remaining on a single side! You can still fly through a station without getting killed - though odds are that a station shot will take you out.
     
    I made these changes while walking on my new TreadMill Desk. So far I have my MacBook Pro and a secondary monitor setup on it. I plan to get some monitor arms before I move my work computer over to it.

     
    As a safety feature there's a tether that attaches to yourself. If you happen to fall the treadmill will turn itself off.

     
    It also has bluetooth for syncing information with a tracking program on your computer.

     
     
    ROM
    draconian_20140507.bin
     
    Source
    Draconian_20140507.zip
  19. SpiceWare

    Draconian
    ARM routine InitLevel() is now run mid-screen to eliminate problem where OverScan occasionally ran out of time screen shifted down to give more time to Vertical Blank player shots are faster station shots are slower, and once again deadly asteroid explosions are no longer deadly. They're also faster than mine explosions. Non-Deadly explosions are now drawn in white. Have not seen any jitter since making these changes. Let me know if you encounter any as I may need to shift the screen down another scanline or two.
     
    If you hold RESET you can visually see how long the ARM routine InitLevel() takes to run, it's denoted by the white bar at the top of the screen. You'll notice that it varies by a scanline or two, this is due to the routines randomly positioning the asteroids and mines and having to sometimes reposition them to prevent objects from overlapping.

     
    If you hold RESET in Stella, you'll only see a thin white line. This is because Stella does not emulate how long it takes ARM code takes to run.

     
     
    ROM
    draconian_20140502.bin
     
    Source
    Draconian_20140502.zip
  20. SpiceWare

    DVR Project
    Heard good stuff about the new show Fargo so bought the season via iTunes. That puts April's savings at $123, with cumulative savings of $1915. Balance remaining to pay off the setup is $1149.
     
    Haven't watched any episodes of Fargo yet, been to busy with other projects like emptying out my office so I can get ready for my new Treadmill Desk, which will be delivered Monday. My Roomba's been busy vacuuming the office - after it recharges I send it in for another pass. I plan keep doing that over the next 2 days, then shampoo the carpet Saturday morning. It should be nice and dry by Monday.
     
    Haven't been able to find out any more info on that new channel, The Works. It's not listed in TV Guide either, so I never know what will be on it.
  21. SpiceWare

    Draconian
    I took a look at the energy field routines while eating lunch, so here's a new build in just 2 days rather that a few weeks
    each station type (Horizontal and Vertical) has its own Energy Field design (2 flickered shapes for each design) last Energy Field flickered shape kept track for each station, so Energy Field will always alternate between its 2 shapes regardless of Station flicker rate. Added X-Y check to make sure energy field is onscreen before drawing it. This appears to have fixed all the drawing glitches
     
     
     
    ROM
    draconian_20140428.bin
     
    Source
    Draconian_20140428.zip
  22. SpiceWare

    Draconian
    Test of preliminary routines that open the center pod and show the "energy field" that can be hit to destroy the station in one shot.

     

     
    The energy field is drawn using a missile. If the station is drawn with player0, the energy field is drawn with missile1. Likewise missile0 is used for stations drawn with player1. I did this as we can't control the color of the missiles, so this gives us a chance for the energy field to be a color other than green.
     
    At the time the stations are drawn, the "draw shots" routine has yet to run, so the energy field has a higher priority than shots. I think this will be OK most of the time, though for levels like 4 this might cause a problem as shots could be invisible when they cross the horizontal zone (boxed in red in the screenshot) with the energy fields. It depends on whether or not other sprites are flickering in that section - in this screenshot the player's ship is part of the flicker with the stations, so a station shot does show up in the zone on the left.

    This also shows a minor issue with these preliminary routines - the energy field is only drawn if the sprite is drawn, and which of the two energy field shapes is selected by bit 1 of the FRAME counter, so at certain sprite flicker rates the energy field doesn't appear to alternate between its two shapes. To fix this I'll just keep track of which energy field was shown last for each station.
     
    I've turned off collision detection for the station shots to make it easier to view the changes. Right Difficulty=A will stop your ship from moving, which also helps to see what's happening.
     
    I think it works out quite well, though will probably change it so that each station can have a different energy field shape as the current shape doesn't look quite right with the Vertical Station.
     
    There are some quirks that I've not yet looked into


     
    I've ordered a Treadmill Desk that will be delivered on the 5th. Starting tomorrow I'm going to move everything out of my office. I figure it'll take a few days, but I want to shampoo the carpet next weekend before the new desk is delivered. Over the course of the week of the 5th I'll be setting up the Treadmill Desk and figuring out how to arrange everything (except the old desk) back into my office.
     
    The weekend of the 10th I'll have family in town for the Houston Art Car Parade. I've posted photos from prior years of this parade in my Houston blog entries.
     
    Due to all this, I suspect it'll be a few weeks before the next Draconian build is posted.
     
    ROM
    draconian_20140426.bin
     
    Source
    Draconian_20140426.zip
  23. SpiceWare

    Draconian
    preliminary explosion sequence asteroids, mines and enemy ships are deadly to touch station shots are deadly Player Lost a Life routine added a buffer space around the ships spawn point so asteroids/mines aren't placed next, or even on, the ship. Collision routines don't support quad sized sprites yet, so flying thru a station won't kill you (their shots on the other hand...)
     
    The new buffer space around the spawn point increased the odds of there being screen jitter or roll when a level is initialized. I plan to revise the way the routines work so that the level init is run mid-screen like I do in Stay Frosty 2.
     
    In Stay Frosty 2 I originally used RLE to compress 2328 bytes of level data down to 1524. Thomas Jentzsch worked up Huffman coding routines which got that down to 959 bytes*, but the decompression routines took longer which caused jitter when starting some levels. I ended up changing it so that instead of decompressing during Over Scan it would decompress mid-screen. For testing I changed the background color so you could see how long it took:
     
    Level 1 - the white scanlines below the horizon is how long the decompression took to run

     
    Level 11 - longer

     
    Level 31 - longest

     
    ROM
    draconian_20140423.bin
     
    Source
    Draconian_20140423.zip
     
    *The savings were used to add the branch object and additional unique levels (some levels reuse previous layouts).
     
    Edit: Station Collision Images

×
×
  • Create New...