; ; Lunokhod 3! ; ; Copyright 2012 ; Trent McNair ; ; Many of the comments in this file are horribly out of date. ; PROCESSOR 6502 include "vcs.h" include "macro.h" SEG ORG $F000 ; set the ROM page ; ; Variable declarations ; audio2count equ $80 ; shotcount equ $81 ; used in various places as a counter p0x equ $82 ; screen x position of player 0 [20,132] p0s equ $83 ; x speed of player 0 [-4,4] p0vxlo equ $84 ; player 0 virtual x position low byte temp1lo equ $85 ; temporary 16 temp1hi equ $86 ; temporary 16 temp2lo equ $87 ; temporary 16 temp2hi equ $88 ; temporary 16 temp3 equ $89 ; sdtimer equ $8a ; p0 slowdown timer scrollpos equ $8b ; the scroll position of the bottom set vxoffsetlo equ $8c ; scrollpos2 equ $8d ; nexty equ $8e ; m0vxlo equ $8f ; virtual x position of missile 0 m0ys equ $90 ; y position of missile 0 m1vxlo equ $91 ; virtual x position of missile 1 m1ys equ $92 ; y position of missile 1 m2vxlo equ $93 ; virtual x position of missile 2 m2ys equ $94 ; y position of missile 2 m3vxlo equ $95 ; virtual x position of missile 3 m3ys equ $96 ; y position of missile 3 enemyvx equ $97 ; 97-9E enemyinfo equ $9f ; 9F-A6 enemyx equ $a7 ; A7-AE enemyy equ $af ; AF-B6 frameCount equ $b7 ; count the current frame. enemyCount equ $b8 ; number of current enemies ; free equ $b9 ; p1dataptrlo equ $ba ; p1dataptrhi equ $bb ; animcount equ $bc ; p1colorlo equ $bd ; p1colorhi equ $be ; spritecount equ $bf ; spritelist equ $c0 ; C0-C7 sprite1lo equ $c8 ; sprite1hi equ $c9 ; sprite2lo equ $ca ; sprite2hi equ $cb ; sprite3lo equ $cc ; sprite3hi equ $cd ; sprite4lo equ $ce ; sprite4hi equ $cf ; sprite5lo equ $d0 ; sprite5hi equ $d1 ; sprite6lo equ $d2 ; sprite6hi equ $d3 ; sprite7lo equ $d4 ; sprite7hi equ $d5 ; sprite8lo equ $d6 ; sprite8hi equ $d7 ; score equ $D8 ; D8-D9 Two byte BDC score mode equ $DA ; 0=nogame, 1=game, >1 gamepause boltcount equ $DB ; audio2type equ $DC ; random equ $DD ; radarRam equ $DE ; DE-FD (two bytes left for stack!!) ; ; Constants ; MISSILE_FOLLOWS_SHIP = 0; MOONSCAPE = 1; FAST_ENEMIES = 1; SHARP_ANGLES = 1; MAXSPEED equ #2 ; the max speed of the sled MINSPEED equ #-2 ; the min speed of the sled MINXPOS equ #61 ; minimum screen positionof the sled (32) MAXXPOS equ #93 ; maximum screen position of the sled (112) POSDELTA equ #MAXXPOS-MINXPOS ; this must be equal to maxpos-minpos (80) P0CENTER equ #4 ; offset to center of player 0 MISSILESPEED equ #4 MISSILESIZE equ #7 #if MOONSCAPE = 1 GAUGECOLOR equ #$32 SCORECOLOR equ #$0e SKYCOLOR equ #$00 MTNCOLOR equ #$04 MTNCAPSCOLOR equ #$04 GRADIENT1 equ #$04 GRADIENT2 equ #$04 GRADIENT3 equ #$02 RADARCOLOR equ #$0e RADARCOLOR2 equ #$4a GROUNDCOLOR equ #$00 SNOWCOLOR equ #$06 RAILCOLOR equ #$02 PLATFORMCOLOR equ #$04 PLAYFIELDSZ equ #132 ENEMYHEIGHT equ #17 #endif #if MOONSCAPE = 0 GAUGECOLOR equ #$42 SCORECOLOR equ #$00 SKYCOLOR equ #$9E MTNCOLOR equ #$9c MTNCAPSCOLOR equ #$0E GRADIENT1 equ #$a6 GRADIENT2 equ #$a8 GRADIENT3 equ #$aa RADARCOLOR equ #$A6 RADARCOLOR2 equ #$00 GROUNDCOLOR equ #$AC SNOWCOLOR equ #$0E RAILCOLOR equ #$04 PLATFORMCOLOR equ #$0D PLAYFIELDSZ equ #132 ENEMYHEIGHT equ #17 #endif ; ; Initialize system (Andrew Davie's 8 byte init) ; sysinit ldx #0 txa sysinit_clear dex txs pha bne sysinit_clear lda #0 sta mode jsr non_system_init lda #0 sta mode jmp main_loop sysinit_end ; ; Non-system initialization ; non_system_init lda #0 ldx #$7c clear_loop sta #$80,x dex cpx #0 bne clear_loop lda #4 sta sdtimer lda #52 sta audio2type lda #$FF sta m0ys sta m1ys sta m2ys sta m3ys lda #sprite1Frame1 sta p1dataptrhi lda #$70 sta vxoffsetlo lda #$4d sta p0x lda #$80 sta p0vxlo lda #$08 sta scrollpos lda #$08 sta scrollpos2 lda #128 sta mode rts non_system_init_end ; ; main_loop: ; ; This is comprised of the following sections: ; 1) vertical sync/blank ; 2) kernel ; 3) overscan main_loop ; ; Start the vertical blank interrupt ; TIME: ~4 scanlines ; ENDS: 8 ; vblank_start lda #2 ; wait for horizontal sync sta WSYNC ; "" sta VSYNC ; turn on vsync sta WSYNC ; wait three lines sta WSYNC ; "" lda #0 ; "" sta WSYNC ; "" sta VSYNC ; turn off vsync lda #48 ; Set the timer for 2812 cycles sta TIM64T ; "" vblank_start_end ; ; If the game has been reset then the mode will be $FF ; do_handle_reset lda mode cmp #$FF bne do_handle_reset_end jsr non_system_init do_handle_reset_end inc frameCount ; 5, 13 do_shot_audio ; 38 lda shotcount ; 3 lsr ; 2 sta AUDV0 ; 3 lda shotcount ; 3 cmp #0 ; 2 beq do_shot_audio_end ; 2/3 dec shotcount ; 5 lda #15 ; 2 sec ; 2 sbc shotcount ; 2 clc ; 2 adc #24 ; 2 tweak to alter timber of shot sta AUDF0 ; 3 lda #8 ; 2 ; tweak to alter shot distortion sta AUDC0 ; 3 do_shot_audio_end do_audio2 lda audio2count ; set the volume and #%00111111 lsr sta AUDV1 lda audio2count ; if there is cmp #0 beq do_soundtrack cmp #1 bne keeptype lda #52 sta audio2type keeptype dec audio2count lda frameCount and #%00100110 clc adc audio2type ; 52 or 128 or 192 sta AUDF1 lda #15 sta AUDC1 jmp do_audio2_end do_soundtrack ; jmp do_audio2_end lda frameCount and #%00000100 bne do_audio2_end lda spritecount and #%00000110 sta AUDV1 clc lda frameCount adc #228 sta AUDF1 lda #15 sta AUDC1 do_audio2_end ; ; Every 8th frame we update the animation counter ; TIME: 26 cycles ; ENDS: MAX 39 ; update_animcount lda frameCount ; 3 ; every 8 frames we increment the anim count and #%00000011 ; 2 cmp #%00000011 ; 2 bne update_animcount_end ; 2 inc animcount ; 5 inc animcount ; lda animcount ; 3 cmp #16 ; 2 bcc update_animcount_end ; 2 lda #0 ; 2 sta animcount ; 3 update_animcount_end ; +1 (10, 22, 26) ; ; Initialize the first sprite position, this triggers finding ; the next sprite in the kernel. ; TIME: 9 cycles ; ENDS: MAX 48 ; init_first_sprite lda #PLAYFIELDSZ ; 2 ; this will trigger finding a new sprite clc ; 2 ; "" adc #ENEMYHEIGHT+1 ; 2 ; "" sta nexty ; 3 ; "" init_first_sprite_end ; ; set up the ball, we use it to hide HMOVE bars ; Time: does a WSYNC and then 122 cycles. ; init_ball sta WSYNC ; 3, 0 STA RESBL ; 3, 3 ; Reset the ball LDA #$22 ; 2, 5 ; Set the horizontal ball motion (+2) STA HMBL ; 3, 8 ; STA ENABL ; 3, 11 ;Enable the ball (02) lda #%00110000 ; 2, 13 sta CTRLPF ; 3, 16 sta WSYNC ; 3, -76- sta HMOVE ; 3, 3 init_ball_end adjust_missiles lda m0ys cmp #$FF beq adjust_1 cmp #132 bcs reset_missile_0 clc adc #MISSILESPEED sta m0ys jmp adjust_1 reset_missile_0 lda #$FF sta m0ys adjust_1 lda m1ys cmp #$FF beq adjust_2 cmp #132 bcs reset_missile_1 clc adc #MISSILESPEED sta m1ys jmp adjust_2 reset_missile_1 lda #$FF sta m1ys adjust_2 lda m2ys cmp #$FF beq adjust_3 cmp #132 bcs reset_missile_2 clc adc #MISSILESPEED sta m2ys jmp adjust_3 reset_missile_2 lda #$FF sta m2ys adjust_3 lda m3ys cmp #$FF beq adjust_missiles_end cmp #132 bcs reset_missile_3 clc adc #MISSILESPEED sta m3ys jmp adjust_missiles_end reset_missile_3 lda #$FF sta m3ys adjust_missiles_end sta HMCLR ; clear the ball init move_missiles lda frameCount and #%0000001 cmp #0 beq move_missiles_even jmp move_missiles_odd move_missiles_even lda m0ys cmp #$FF beq move_missiles_even_1 lda m0vxlo sta temp2lo jsr convert_virtual_xpos clc adc #P0CENTER ; add to align with center of ship #if MISSILE_FOLLOWS_SHIP = 1 lda p0x ; missle follows ship clc ; "" adc #4 ; "" #endif ldx #3 jsr do_sprite_move move_missiles_even_1 lda m1ys cmp #$FF beq move_missiles_even_end lda m1vxlo sta temp2lo jsr convert_virtual_xpos clc adc #P0CENTER ; add to align with center of ship #if MISSILE_FOLLOWS_SHIP = 1 lda p0x ; missle follows ship clc ; "" adc #4 ; "" #endif ldx #2 sta HMCLR jsr do_sprite_move move_missiles_even_end jmp move_missiles_odd_end move_missiles_odd lda m2ys cmp #$FF beq move_missiles_odd_3 lda m2vxlo sta temp2lo jsr convert_virtual_xpos clc adc #P0CENTER ; add to align with center of ship #if MISSILE_FOLLOWS_SHIP = 1 lda p0x ; missle follows ship clc ; "" adc #4 ; "" #endif ldx #3 jsr do_sprite_move move_missiles_odd_3 lda m3ys cmp #$FF beq move_missiles_odd_end lda m3vxlo sta temp2lo jsr convert_virtual_xpos clc adc #P0CENTER ; add to align with center of ship #if MISSILE_FOLLOWS_SHIP = 1 lda p0x ; missle follows ship clc ; "" adc #4 ; "" #endif ldx #2 sta HMCLR jsr do_sprite_move move_missiles_odd_end move_missiles_end ; ; We are keeping state for 4 missiles. Every other frame we ; map even or odd missiles to M0/M1. ; swap_missiles1 lda frameCount and #%0000001 cmp #0 beq swap_missiles1_end ldx m0ys lda m2ys sta m0ys stx m2ys ldx m1ys lda m3ys sta m1ys stx m3ys swap_missiles1_end sta HMCLR ; ; Check the bottom enemy moved and see if it needs to be ; removed ; remove_stale_enemies ldx enemyCount cpx #0 beq remove_stale_enemies_end dex lda enemyy,x cmp #3 ; should be bcs remove_stale_enemies_end dec enemyCount lda enemyinfo,x and #%00111111 cmp #%00000000 bne remove_stale_enemies_end lda #31 sta audio2count lda #128 sta audio2type lda boltcount lsr clc adc #128 sta boltcount cmp #$FF bne remove_stale_enemies_end lda #0 sta mode sta enemyCount remove_stale_enemies_end ; ; Move the enemies downward and adjust horizontal screen positions ; according to the the current scroll position. Load the visible ; sprites into spritelist. ; move_enemies lda #0 sta spritecount ldx enemyCount cpx #0 bne no_move_enemies_end jmp move_enemies_end no_move_enemies_end ldx #0 move_enemies_loop lda enemyinfo,x ; 4 lsr ; 2 lsr ; 2 lsr ; 2 tay ; 2 lda frameCount ; 3 and andTable,y ; 5 cmp #0 ; 2 bne nohorizmove ; 2 clc ; 2 lda enemyvx,x ; 4 adc moveTable,y ; 5 sta enemyvx,x ; 4, 43 nohorizmove lda frameCount ; Decriment y postion every other frame and #%00000001 ; "" cmp #0 ; "" #if FAST_ENEMIES = 0 beq noDec ; "" #endif dec enemyy,x ; "" noDec lda enemyvx,x ; calcluate the screen x position sta temp2lo ; "" lda enemyinfo,x and #%00000111 ; check to see if this enemy has been removed cmp #%00000111 bne continue_with_convert lda #$FF sta enemyx,x jmp set_to_ff continue_with_convert jsr convert_virtual_xpos sta enemyx,x ; "" set_to_ff cmp #$FF ; if the x position is FF do not add to the list beq move_enemies_skip ; "" stx temp3 ; store the original value of x lda enemyinfo,x ; increment the condemned counter if applicable. and #%00000111 cmp #0 beq skipincrement sta temp1lo inc temp1lo lda enemyinfo,x and #%11111000 ora temp1lo sta enemyinfo,x lda #explosionFrameTable sta temp2hi jmp skipspriteselect skipincrement lda enemyinfo,x ; load the correct sprite and #%00111000 lsr lsr tax lda spriteTable,x sta temp2lo lda spriteTable+1,x sta temp2hi skipspriteselect ldx temp3 ; reload the original value of x lda enemyinfo,x ; and now select the specific frame based on the vx position lsr ; added with animcount clc adc animcount and #%00001110 tay lda (temp2lo),y sta temp1lo iny lda (temp2lo),y sta temp1hi ldx temp3 txa ldx spritecount ; add this enemy to the list of sprites to draw sta spritelist,x ; "" lda temp1lo sta sprite1lo,x lda temp1hi sta sprite1lo+8,x ldx temp3 inc spritecount move_enemies_skip inx cpx enemyCount beq move_enemies_end jmp move_enemies_loop move_enemies_end ; ; load the score pointers to be used later in the kernel ; loadScore lda score ; load half the player score and #$0F ; and out the low nibble tax lda scoreTable,x ; sta spritelist ; lda scoreTable+10,x ; sta spritelist+1 ; lda score ; load half the player score lsr ; extract the high nibble lsr lsr lsr tax lda scoreTable,x ; sta spritelist+2 ; lda scoreTable+10,x ; sta spritelist+3 ; lda score+1 ; load half the player score and #$0F ; and out the low nibble tax lda scoreTable,x ; sta spritelist+4 ; lda scoreTable+10,x ; sta spritelist+5 ; lda score+1 ; load half the player score lsr ; extract the high nibble lsr lsr lsr tax lda scoreTable,x ; sta spritelist+6 ; lda scoreTable+10,x ; sta spritelist+7 ; ; ; Map the player onto the radar ; map_player ldy #0 lda p0vxlo cmp #64 bcc no1 iny no1 cmp #128 bcc no2 iny no2 cmp #192 bcc no3 iny no3 sty temp1lo lda p0vxlo ; divide lsr lsr lsr tay lda map_enemies_table,y sta temp2lo lda temp1lo tay lda radarRam,y ora temp2lo sta radarRam,y map_player_end ; ; End the vertical blank ; vblank_end waitOnVblank lda INTIM bne waitOnVblank lda #0 ; turn off the vblank sta VBLANK ; "" sta WSYNC ; wait for the next line. vblank_end_end ldy #0 ; 2, 2 ; ; Draw the score ; lda #SKYCOLOR ; 2, 4 sta COLUBK ; 3, 7 draw_score sta WSYNC ; 3, - lda #3 ; 2, 2 sta HMCLR ; 3, 5 sta NUSIZ0 ; 3, 8 sta NUSIZ1 ; 3, 11 lda #SCORECOLOR ; 2, 13 sta COLUP0 ; 3, 16 sta COLUP1 ; 3, 19 SLEEP 20 ; 20, 39 sta RESP0 ; 3, 42 sta RESP1 ; 3, 45 lda #%11110000 ; 2, 47 sta HMP0 ; 3, 50 lda #%00000000 ; 2, 52 sta HMP1 ; 3, 55 sty nexty ; 3, 58 ldy #7 ; 2, 60 sta WSYNC ; 3, 0 sta HMOVE ; 3, 3 nop ; 2, 5 score_loop ; +1, 5 dey ; 2, 7 lda (spritelist+6),y ; 6, 13 sta GRP0 ; 3, 16 lda (spritelist+4),y ; 6, 22 sta GRP1 ; 3, 25 lda (spritelist),y ; 6, 31 tax ; 2, 33 lda (spritelist+2),y ; 6, 39 sty temp1lo ; 3, 42 ldy #0 ; 2, 44 sleep 4 ; 4, 48 sta GRP0 ; 3, 51 stx GRP1 ; 3, 54 sty GRP0 ; 3, 57 sty GRP1 ; 3, 60 ldy temp1lo ; 3, 63 sta WSYNC ; 3, 66 cpy #0 ; 2, 2 bne score_loop ; 2, 4 lda #0 ; 2, 6 sta GRP1 ; 3, 9 sta GRP0 ; 3, 12 lda #%00010000 ; 2, 14 sta NUSIZ0 ; 3, 17 sta NUSIZ1 ; 3, 20 ldy #10 ; 2, 22 ; ; Draw the sky area between the score and the mountains. During this time we ; also need to load the spritelist and then preload the first enemy sprite. ; This ends up taking a variable amount of time so we'll just set a timer ; here and do the things we need then wait for it to expire. ; lda #7 sta TIM64T ; ; load the list of currently visible enemy sprites ; into spriteList. Uses 200 cycles. Call it right after a wsync and ; follow it with a wync it will use 3 scan lines. ; load_visible_sprites lda enemyCount ; 3, 14 cmp #0 ; 2, 16 beq load_visible_sprites_end ; 2, 18 sty temp1lo ; 3, 21 ; store original value of Y ldx #0 ; 2, 23 ; index ldy #0 ; 2, 25 ; for spritecount lvs_loop ; max loop time (when enemycount = 8) is 175 cycles lda enemyx,x ; 4 cmp #$FF ; 2 beq lvs_skip ; 2/3 stx spritelist,y ; 4 iny ; 2 lvs_skip inx ; 2 cpx enemyCount ; 3 bne lvs_loop ; 3 ; MAX LOOP TIME = 22 * 8 - 1 = 175 sty spritecount ; 3, 203 ; set spritecount ldy temp1lo ; 3 206 ; restore Y load_visible_sprites_end ; ; preload pointers for the first enemy sprite to be used later ; in the kernel. ; preload_sprite lda spritecount cmp #0 beq preload_sprite_end ldx #0 lda sprite1lo,x sta p1dataptrlo lda sprite1lo+8,x sta p1dataptrhi ldy #17 ; 2, 33 ; lda (p1dataptrlo),y ; 6, 39 ; sta p1colorlo ; 3, 42 ; iny ; 2, 44 ; lda (p1dataptrlo),y ; 6, 50 ; sta p1colorhi ; 3, 53 ; ldy #0 ldx spritelist,y lda enemyy,x sta nexty lda enemyx,x ldx #1 jsr do_sprite_move sleep #20 sta HMCLR preload_sprite_end sky_wait lda INTIM ; 3, 203 bne sky_wait ; 2, 205 sta WSYNC ldy #15 ; ; Draw the top skyline ; ENDS: 23 ; draw_skyline lda scrollpos2 ; 3, 9 asl ; 2, 11 asl ; 2, 13 clc ; 2, 15 adc #4 ; 2, 17 tax ; 2, 19 sta WSYNC sta HMOVE ; 3, 3 lda #MTNCAPSCOLOR ; 2, 5 sta COLUPF ; 3, 8 lda PFData0-1,X ; 4, [14,15] sta PF0 ; 3, 18 lda PFData1-1,X ; 4, 22 sta PF1 ; 3, 25 lda PFData2-1,X ; 4, 29 sta PF2 ; 3, 32 dex ; 2, 34 iny sta WSYNC sta HMOVE ; 3, 3 lda PFData0-1,X ; 4, [14,15] sta PF0 ; 3, 18 lda PFData1-1,X ; 4, 22 sta PF1 ; 3, 25 lda PFData2-1,X ; 4, 29 sta PF2 ; 3, 32 dex ; 2, 34 iny sta WSYNC sta HMOVE ; 3, 3 lda #MTNCOLOR ; 2, 5 sta COLUPF ; 3, 8 lda PFData0-1,X ; 4, [14,15] sta PF0 ; 3, 18 lda PFData1-1,X ; 4, 22 sta PF1 ; 3, 25 lda PFData2-1,X ; 4, 29 sta PF2 ; 3, 32 dex ; 2, 34 iny sta WSYNC sta HMOVE ; 3, 3 lda PFData0-1,X ; 4, [14,15] sta PF0 ; 3, 18 lda PFData1-1,X ; 4, 22 sta PF1 ; 3, 25 lda PFData2-1,X ; 4, 29 sta PF2 ; 3, 32 dex ; 2, 34 iny sta WSYNC sta HMOVE lda #MTNCOLOR ; 2, ; set the background to extend bottom of mountains sta COLUBK ; 3, ; "" lda #0 ; 2, 57 ; clear playfield data sta PF0 ; 3, 60 ; "" sta PF1 ; 3, 63 ; "" sta PF2 ; 3, 66 ; "" iny iny draw_skyline_end ; ; extend the mountains down and draw the transition gradient. ; ENDS: 7 more_mountains lda #$00 ; set the pf color to black for HMOVE hiding sta COLUPF sta WSYNC iny cpy #23 bne more_mountains lda #GRADIENT1 ; gradient sta COLUBK sta WSYNC iny lda #GRADIENT2 ; gradient sta COLUBK sta WSYNC iny lda #GRADIENT3 ; gradient sta COLUBK sta WSYNC ; 3, lda #GROUNDCOLOR ; 2, 2 ; playfield background sta COLUBK ; 3, 5 iny ; 2, 7 more_mountains_end ; ; Find the next sprite and set up the x and y coords. This must be called before ; the 27th cycle ; ; nop ; these nop's are to adjust the code position ; nop ; to make page boundary crossing happen how ; we want draw_playfield lda #1 ; 2, 9 sta temp3 ; 3, 12 ldx #PLAYFIELDSZ ; 2, 14 do_playfield ; +1, [9,23] sec ; 2, 25 ; --------------------------------------------- txa ; 2, 27 ; sbc m1ys ; 3, 30 ; draw missile 0, max 16 cycles adc #MISSILESIZE ; 2, 32 ; lda #2 ; 2, 34 ; adc #$ff ; 2, 36 ; sta ENAM0 ; 3, 39 ; --------------------------------------------- sec ; 2, 41 txa ; 2, 43 ; --------------------------------------------- sbc m0ys ; 3, 46 ; draw missile 1, max 16 cycles adc #MISSILESIZE ; 2, 48 ; lda #2 ; 2, 50 ; adc #$ff ; 2, 52 ; sta ENAM1 ; 3, 55 ; --------------------------------------------- txa ; 2, 57 ; --------------------------------------------- sec ; 2, 59 ; set up player1 - max 16 cycles sbc nexty ; 3, 62 ; adc #ENEMYHEIGHT ; 2, 64 ; bcc finishedSprite ; 2, 66 ; tay ; 2, 68 ; 4 FREE CYCLES !! sta WSYNC ; 3, 71 ; --------------------------------------------- lda (p1dataptrlo),y ; 6, 6 ; --------------------------------------------- sta GRP1 ; 3, 9 ; draw player 1 w/ colors - max 17 cyles lda (p1colorlo),y ; 5, 14 ; sta COLUP1 ; 3, 17 ; --------------------------------------------- dex ; 2, 19 ; bne do_playfield ; 2, 21 ; jmp doneSkipDraw ; 3, 24 ; finishedSprite ; +1, 67 ; cmp #$FF ; 2, 69 ; we just finished the last line of a sprite beq load_next_sprite; 2, 71 ; sta WSYNC ; 3, 74 ; 2 FREE CYCLES dex ; 2, 2 ; bne do_playfield ; 2, 4 ; jmp doneSkipDraw ; 3, 7 ; load_next_sprite ; +1, 72 sta WSYNC ; 3, 75 ; 1 FREE CYCLE lda temp3 ; 3, 3 ; cmp spritecount ; 3, 6 ; bcs no_more_sprites ; 2, 8 ; stx temp1lo ; 3, 11 ; dynamically load sprite data tax ; 2, 13 lda sprite1lo,x ; 4, 17 ; "" sta p1dataptrlo ; 3, 20 ; "" lda sprite1lo+8,x ; 4, 24 ; "" sta p1dataptrhi ; 3, 27 ; "" ldy #17 ; 2, 29 ; lda (p1dataptrlo),y ; 6*, 35 ; sta p1colorlo ; 3, 38 ; iny ; 2, 40 ; lda (p1dataptrlo),y ; 6*, 46 ; sta p1colorhi ; 3, 49 ; ldy temp3 ; 3, 52 ; get the next sprite from spritelist ldx spritelist,y ; 4, 56 ; "" inc temp3 ; 3, 59 ; "" lda enemyy,x ; 4, 63 ; "" sta nexty ; 3, 66 ; "" lda enemyx,x ; 4, 70 ; setup A and X for do_sprite_move sta WSYNC sec ; 2, 2 DivideLoop1 ; This loop MAX 54 cycles if A is < 160, MIN 4 sbc #15 ; 2, [4 bcs DivideLoop1 ; 2/3 [6,56] tay ; 2, [8,58] lda FineAdjustTableEnd,Y ; 5, [13,63] ldx #1 sta HMP0,X ; 3 [19,69] sta RESP0,x ; 4 [23,73] sta WSYNC ; 3 [26,76] sta HMOVE ; 3, 3 ldx temp1lo ; 3, 12 ; dex ; 2, 14 ; dex ; 2, 16 ; dex ; 2, 18 ; jmp do_playfield ; 2, 20 ; checking dex is not required here - we know there is at least one more sprite no_more_sprites ; +1, 9 ; lda #$ff ; 2, 11 sta nexty ; 3, 14 dex ; 2, 16 ; beq doneSkipDraw ; 2, 18 ; jmp do_playfield ; 2, 20 ; doneSkipDraw ; [7,24] ldy #158 ; 2, 26 ; this is what scanline we are at. ; tay ; 2, 28 draw_playfield_end ; ; Draw the snowy hills. ; draw_hills lda scrollpos ; 3, 36 asl ; 2, 38 asl ; 2, 40 clc ; 2, 42 adc #4 ; 2, 44 tax ; 2, 46 lda #SNOWCOLOR ; 2, 48 sta COLUPF ; 3, 51 change foreground to blue lda #4 ; 2, 53 sta temp1lo ; 3, 56 sta WSYNC sta HMOVE lda #0 ; 2, 30 sta GRP1 ; 3, 33 hills_loop lda PFData0-1,X ; 4, 4 sta PF0 ; 3, 7 lda PFData1-1,X ; 4, 11 sta PF1 ; 3, 14 lda PFData2-1,X ; 4, 18 sta PF2 ; 3, 21 dex iny ; 2, 23 sta WSYNC sta HMOVE ; 3, 3 dec temp1lo ; 5, 8 bne hills_loop ; 2, 10 draw_hills_end lda #SNOWCOLOR ; 2, 12 ; change the background color to white sta COLUBK ; 3, 15 ; "" lda #0 ; 2, 12 ; Clear playfield data. sta PF0 ; 3, 15 ; "" sta PF1 ; 3, 18 ; "" sta PF2 ; 3, 21 ; "" lda #0 ; 2, 23 ; turn off the missiles sta ENAM0 ; 3, 26 ; "" sta ENAM1 ; 3, 29 ; "" lda #$00 ; 2, 31 ; set the pf color to black for HMOVE hiding sta COLUPF ; 3, 34 ; "" ; ; Draw the sled and rail ; draw_sled_and_rail sty temp1lo lda p0x ldx #0 jsr do_sprite_move ldy temp1lo ldx #10 dey do_sled lda PlayerSprite,X sta GRP0 lda PlayerColor,X sta COLUP0 sta WSYNC dex iny cpy #171 bne do_sled lda #RAILCOLOR sta COLUBK lda PlayerSprite,X sta GRP0 sta WSYNC dex iny lda #PLATFORMCOLOR sta COLUBK lda #0 sta GRP0 draw_sled_and_rail_end draw_gauge ; sty temp1lo lda #%00000111 sta NUSIZ0 lda #63 ldx #0 jsr do_sprite_move lda boltcount sta GRP0 lda #GAUGECOLOR sta COLUP0 ; ldy temp1lo sta WSYNC sta HMCLR ; iny ; iny ; iny ; iny sta WSYNC sta HMOVE lda #0 sta GRP0 lda #%11110000 ; 2 sta PF2 ; 3 lda #%00110001 ; 2 sta CTRLPF ; 3 lda #PLATFORMCOLOR sta COLUPF draw_gauge_end ; ;Draw the radar and surrounding area. ; ; draw_radar sta WSYNC sta HMOVE lda #3 ; 2, 2 sta HMCLR ; 3, 5 sta NUSIZ0 ; 3, 8 sta NUSIZ1 ; 3, 11 lda #RADARCOLOR ; 2, 16 sta COLUP0 ; 3, 19 sta COLUP1 ; 3, 14 SLEEP 17 ; 20, 39 sta RESP0 ; 3, 42 sta RESP1 ; 3, 45 lda #%11110000 ; 2, 47 sta HMP0 ; 3, 50 lda #%00000000 ; 2, 52 sta HMP1 ; 3, 55 sty nexty ; 3, 58 ldx #32 ; 2, 60 lda #0 sta COLUPF ; 3, 6 sta WSYNC ; 3, 0 sta HMOVE ; 3, 3 nop ; 2, 5 radar_loop ; +1, 5 dex ; 2, 7 dex ; 2, 9 dex ; 2 11 dex ; 2, 13 lda radarRam,x ; 4, 17 sta GRP0 ; 3, 20 lda radarRam+1,x ; 4, 24 sta GRP1 ; 3, 27 ldy radarRam+3,x ; 4, 31 lda radarRam+2,x ; 4, 35 stx temp1lo ; 3, 38 ldx #0 ; 2, 40 sleep 4 ; 4, 44 sta GRP0 ; 3, 47 sty GRP1 ; 3, 50 stx GRP0 ; 3, 53 stx GRP1 ; 3, 56 ldx temp1lo ; 3, 59 lda #RADARCOLOR2 sta WSYNC ; 3, 75 cpx #4 ; 2, 2 bne radar_loop ; 2, 4 sta COLUP1 ; 3, 7 sta COLUP0 ; 3, 10 ldx #0 ; 2, 12 lda radarRam,x ; 4, 16 sta GRP0 ; 3, 19 ; this must be on cycle 19 or 20 lda radarRam+1,x ; 4, 23 sta GRP1 ; 3, 26 ; this must be on cycle 26 or 27 ldy radarRam+3,x ; 4, 30 lda radarRam+2,x ; 4, 34 stx temp1lo ; 3, 37 ldx #0 ; 2, 39 sleep 5 ; 5, 44 sta GRP0 ; 3, 47 ; these three must start on cycle 47 sty GRP1 ; 3, 50 stx GRP0 ; 3, 53 stx GRP1 ; 3, 56 sta WSYNC sleep 10 ; 10, 10 ldx #0 ; 2, 12 lda radarRam,x ; 4, 16 sta GRP0 ; 3, 19 ; this must be on cycle 19 or 20 lda radarRam+1,x ; 4, 23 sta GRP1 ; 3, 26 ; this must be on cycle 26 or 27 ldy radarRam+3,x ; 4, 30 lda radarRam+2,x ; 4, 34 stx temp1lo ; 3, 37 ldx #0 ; 2, 39 sleep 5 ; 5, 44 sta GRP0 ; 3, 47 ; these three must start on cycle 47 sty GRP1 ; 3, 50 stx GRP0 ; 3, 53 stx GRP1 ; 3, 56 sta WSYNC lda #$0e ; 2, 16 sta COLUP0 ; 3, 19 sta COLUP1 ; 3, 14 lda #0 ; 2, 6 sta GRP1 ; 3, 9 sta GRP0 ; 3, 12 sta PF2 sta NUSIZ0 ; 3, 26 sta NUSIZ1 ; 3, 29 sta WSYNC sta WSYNC overscan_start lda #2 ; turn on the vblank sta VBLANK ; "" lda #32 ; wait for 4544 cycles then sync sta TIM64T ; "" overscan_start_end ; ; Process collisions ; do_collisions lda CXM0P ; 3 ; Check if any collisions were measured with missile 0 and #%10000000 ; 2 ; "" cmp #0 ; 2 ; "" beq no_m0_collision ; 2 ; "" ldx #0 ; 2 ; Walk through the enemy list checking for collisions m0_collision_loop ; +1 ; "" lda enemyy,x ; 4 ; "" sec ; 2 ; "" sbc m1ys ; 3 ; "" cmp #$FD ; 2 ; "" bcs found_m0 ; 2 ; "" cmp #ENEMYHEIGHT ; 2 ; bcc found_m0 ; 2 ; "" jmp no_pm0_collision ; 3 ; "" found_m0 lda enemyinfo,x ; if the enemy is in condemned state this is not a collision and #%00000111 ; "" cmp #0 ; "" bne no_pm0_collision ; "" jsr remove_enemy lda #$FF sta m1ys jmp no_m0_collision no_pm0_collision inx cpx enemyCount bcc m0_collision_loop no_m0_collision lda CXM1P ; 3 ; Check if missile 1 has a collision and #%01000000 ; ; "" cmp #0 ; ; "" beq no_m1_collision ; ; "" ldx #0 m1_collision_loop lda enemyy,x sec sbc m0ys cmp #$FD bcs found_m1 cmp #ENEMYHEIGHT bcc found_m1 jmp no_pm1_collision found_m1 lda enemyinfo,x ; if the enemy is in a condemned state this is not a collision and #%00000111 ; "" cmp #0 ; "" bne no_pm1_collision ; "" jsr remove_enemy lda #$FF sta m0ys jmp no_m1_collision no_pm1_collision inx cpx enemyCount bcc m1_collision_loop no_m1_collision sta CXCLR do_collisions_end swap_missiles2 lda frameCount ; every other frame we swap the missiles and #%0000001 cmp #0 beq swap_missiles2_end ldx m0ys ; swap missiles 0 and 2 lda m2ys sta m0ys stx m2ys ldx m1ys ; swap missiles 1 and 3 lda m3ys sta m1ys stx m3ys swap_missiles2_end ; ; Check if the reset button was pressed ; check_for_reset lda SWCHB ; check to see if the reset or select switch was triggered and #1 bne check_for_reset_end lda #$FF sta mode jmp overscan_end check_for_reset_end lda mode cmp #1 bcs do_joystick jmp skip_positioning ;check_trig_reset ; lda INPT4 ; first check the trigger ; bmi do_joystick_end ; jmp startgame ; jmp do_joystick_end ;check_trig_reset_end ; ; Process joystick movement to set the horizontal vector for ; player 0. ; do_joystick lda INPT4 ; first check the trigger bmi no_button jmp create_missile create_missile_cb no_button lda #%01000000 ; Left? bit SWCHA ; bne do_joystick_1 ; Nope, check Right dec p0s jmp check_bounds do_joystick_1 lda #%10000000 ; Right? bit SWCHA ; bne do_slowdown ; Nope, start slowing down inc p0s jmp check_bounds do_slowdown dec sdtimer lda sdtimer cmp #0 bne do_joystick_end do_slowdown_1 lda #4 sta sdtimer lda p0s cmp #0 ; Not moving, return beq do_joystick_end ; "" bpl do_slowdown_2 ; If p0s is > 0 inc p0s jmp check_bounds do_slowdown_2 dec p0s check_bounds lda p0s cmp #MINSPEED bmi less_than_1 cmp #MAXSPEED+1 bpl greater_than_1 jmp do_joystick_end less_than_1 lda #MINSPEED sta p0s jmp do_joystick_end greater_than_1 lda #MAXSPEED sta p0s do_joystick_end ; ; If there was no joystick movement, then skip the positioning routines. ; lda p0s bne p0_position jmp skip_positioning ; ; p0_position determine the position for player 0, which also ; determines the virtual screen offset ; p0_position lda #0 sta temp3 lda p0s cmp #0 bmi left_move clc ; Ensure carry is clear lda p0vxlo ; Add the two least significant bytes adc p0s sta temp1lo ; ... and store the result lda #0 ; add teh two most significant bytes adc #0 ; ... and any propagated carry bit sta temp1hi ; ... and store the result jmp p0_position_check_bounds left_move clc ; negate p0s eor #$FF ; "" adc #1 ; "" sta temp1lo lda p0vxlo ; Add the two least significant bytes sec sbc temp1lo sta temp1lo ; ... and store the result lda #0 ; add teh two most significant bytes sbc #0 ; ... and any propagated carry bit sta temp1hi ; ... and store the result p0_position_check_bounds cmp #1 ; if temp1hi is < 2 then we are fine bmi msb_in_bounds ; "" lda #0 ; otherwise set our vx position at the sta temp3 lda #255 sta p0vxlo jmp p0_position_end msb_in_bounds cmp #0 bpl lsb_in_bounds ; if temp1hi >= 0 we're fine lda #0 ; otherwise set our vx position at the left limit and we're done sta p0vxlo lda #1 sta temp3 jmp p0_position_end lsb_in_bounds lda temp1lo sta p0vxlo p0_position_end ; ; Compute the screen position of the player and scroll offset ; lda temp3 cmp #1 bne continuep0x lda #MINXPOS sta p0x jmp min_limit continuep0x lda p0x clc adc p0s sta p0x cmp #MAXXPOS+1 bcc less_than_maxxpos lda #MAXXPOS sta p0x jmp max_limit less_than_maxxpos cmp #MINXPOS bcs done_scroll_offset lda #MINXPOS sta p0x min_limit lda p0vxlo sta vxoffsetlo jmp done_scroll_offset max_limit sec lda p0vxlo sbc #POSDELTA sta vxoffsetlo done_scroll_offset ; ; Adjust playfield scroll position. Divide vx by 4 mod 20 ; ldx #0 ccc stx temp1lo lda vxoffsetlo and #%00000011 cmp #0 beq noAdjust inc temp1lo noAdjust lda vxoffsetlo lsr ; divide by 4 lsr clc adc temp1lo sec DivideBy20 sbc #20 bcs DivideBy20 adc #20 ; at the end of this loop a has the remainder sta scrollpos ; ; Adjust playfield scroll position 2. Di ; ldx #0 ccc2 lda vxoffsetlo sec DivideBy inx sbc #16 bcs DivideBy txa sec DivideBy202 sbc #20 bcs DivideBy202 adc #20 ; at the end of this loop a has the remainder sta scrollpos2 skip_positioning create_enemy lda mode cmp #1 beq ce_continue cmp #2 bcs decriment_mode jmp create_enemy_end decriment_mode dec mode jmp create_enemy_end ce_continue lda enemyCount ; make sure there is a slot left cmp #8 ; "" beq create_enemy_end; "" lda enemyy ; make sure there is enough space for a new enemy cmp #124 ; "" bcs create_enemy_end; "" ldx #6 ; shift the list down (this can take up to 350 cycles - ouch!) shift_down ; +1 "" lda enemyvx,x ; 4 "" sta enemyvx+1,x ; 4 "" lda enemyinfo,x ; 4 "" sta enemyinfo+1,x ; 4 "" lda enemyy,x ; 4 "" sta enemyy+1,x ; 4 "" cpx #0 ; 2 "" beq done_shift_down ; 2 "" dex ; "" jmp shift_down ; " done_shift_down lda #143 sta enemyy lda random asl asl eor p0vxlo adc random adc frameCount sta random sta enemyvx ; "" and #%00111000 ; info sta enemyinfo ; "" lsr lsr lsr tay lda enemyvx cmp minRange,y bcc addMinRange cmp maxRange,y bcs addMaxRange jmp create_enemy_move_down addMinRange clc adc minRange,y jmp create_enemy_move_down addMaxRange clc adc maxRange,y create_enemy_move_down sta enemyvx inc enemyCount lda enemyCount cmp #8 bcc create_enemy_end lda #8 sta enemyCount create_enemy_end lda #0 sta COLUBK ; so the first line on the top will be black ; ; Clear the RAM that we will use to build the radar. ; Unrolled to reduce cycle use. (110 cycles) ; lda #$00 ; 2, 11 sta radarRam ; 3, 14 sta radarRam+1 ; 3, 17 sta radarRam+2 ; 3, 20 sta radarRam+3 ; 3, 23 sta radarRam+4 ; 3, 26 sta radarRam+5 ; 3, 29 sta radarRam+6 ; 3, 32 sta radarRam+7 ; 3, 35 sta radarRam+8 ; 3, 38 sta radarRam+9 ; 3, 41 sta radarRam+10 ; 3, 44 sta radarRam+11 ; 3, 47 sta radarRam+12 ; 3, 50 sta radarRam+13 ; 3, 53 sta radarRam+14 ; 3, 56 sta radarRam+15 ; 3, 59 sta radarRam+16 ; 3, 62 sta radarRam+17 ; 3, 65 sta radarRam+18 ; 3, 68 sta radarRam+19 ; 3, 71 sta radarRam+20 ; 3, 74 sta radarRam+21 ; 3, 77 ----- scanline + 1 sta radarRam+22 ; 3, 2 sta radarRam+23 ; 3, 5 sta radarRam+24 ; 3, 8 sta radarRam+25 ; 3, 11 sta radarRam+26 ; 3, 14 sta radarRam+27 ; 3, 17 sta radarRam+28 ; 3, 20 sta radarRam+29 ; 3, 23 sta radarRam+30 ; 3, 26 sta radarRam+31 ; 3, 29 iny ; 2, 31 iny ; 2, 33 ; ; Draw our enemies onto the radar. radar memory is a 4x8 byte area arranged ; by row: ; ; column ; 00 01 02 03 ; 00 00000000 00000000 00000000 00000000 ; 01 00000000 00000000 00000000 00000000 ; r 02 00000000 00000000 00000000 00000000 ; o 03 00000000 00000000 00000000 00000000 ; w 04 00000000 00000000 00000000 00000000 ; 05 00000000 00000000 00000000 00000000 ; 06 00000000 00000000 00000000 00000000 ; 07 00000000 00000000 00000000 00000000 ; map_enemies ldx enemyCount cpx #0 beq map_enemies_done ldx #0 map_enemies_loop lda enemyinfo,x ; skip the enmy if it has been condemned and #%00000001 cmp #%00000001 beq skip_enemy ldy #0 lda enemyvx,x cmp #64 bcc no1a iny no1a cmp #128 bcc no2a iny no2a cmp #192 bcc no3a iny no3a sty temp1lo lda enemyy,x ; map y position [0-131] to a row offset [0-6] lsr ; "" (divide by 16) lsr ; "" lsr ; "" lsr ; "" clc adc #1 cmp #8 ; "" (adjust to 7 if >= 8) bcc endymap1 ; "" lda #7 ; "" endymap1 ; "" asl ; "" (multiple result by 4) asl ; "" clc ; Add row and column offsets together to adc temp1lo ; get our insert offset sta temp1lo ; "" lda enemyvx,x ; calculate the remainder put it in Y lsr ; "" lsr ; "" lsr ; "" ; lsr ; "" tay ; "" lda map_enemies_table,y sta temp2lo lda temp1lo tay lda radarRam,y ora temp2lo sta radarRam,y skip_enemy inx cpx enemyCount beq map_enemies_done jmp map_enemies_loop map_enemies_done overscan_end waitOnOverscan ; wait for overscan to finish lda INTIM ; "" bne waitOnOverscan ; "" overscan_end_end jmp main_loop ; ; The trigger was pressed, create a missile if we can ; create_missile lda shotcount cmp #0 bne no_free_missiles ldx #12 check_missile_n cpx #0 beq no_free_missiles dex dex lda m0vxlo+1,x cmp #$FF bne check_missile_n lda #8 sta shotcount lda #0 sta m0vxlo+1,x lda p0vxlo ; add the P0center to align with the ship sta m0vxlo,x no_free_missiles jmp create_missile_cb ; ; ; Remove and enemy at position X, add a point to the score. ; * Set the condemned countdown timer in enemyinfo (0xxx0000) to 001 ; * Set the sprite index in enemyinfo (00000XXX) to 100 ; * Result: 0001100 remove_enemy lda audio2type cmp #128 beq skipNoise lda #31 ; 2 sta audio2count ; 3 skipNoise lda enemyinfo,x ; 4 and #%00111000 ; 2 ora #%00000001 ; 2 sta enemyinfo,x ; 4 sed ; Add 1 to the player's score clc ; "" lda #1 ; "" adc score ; "" sta score ; "" lda #0 ; "" adc score+1 ; "" sta score+1 ; "" cld ; "" rts ; 6 remove_enemy_end ; ; Horizontal position routine. Found by members of the Stella mailing list ; in code for Atari Battlezone. HMOVE needs to be called some time after ; invoking this routine. ; ; Inputs: ; A = Desired position. ; X = Desired object to be positioned (0-5). ; scanlines: ; If control comes on or before cycle 73 then 1 scanline is consumed. ; If control comes after cycle 73 then 2 scanlines are consumed. ; Outputs: ; X = unchanged ; A = Fine Adjustment value. ; Y = the "remainder" of the division by 15 minus an additional 15. ; control is returned on cycle 6 of the next scanline. do_sprite_move sta WSYNC ; 3, ? sec ; 2, 2 DivideLoop ; This loop MAX 54 cycles if A is < 160, MIN 4 sbc #15 ; 2, [4 bcs DivideLoop ; 2/3 [6,56] tay ; 2, [8,58] lda FineAdjustTableEnd,Y ; 5, [13,63] nop ; 2, [15,65] sta HMP0,X ; 4 [19,69] sta RESP0,x ; 4 [23,73] sta WSYNC ; 3 [26,76] sta HMOVE ; 3, 3 rts ; 6, 9 ; ; Input: ; temp2lo : least significat byte of vx position to convert ; vxoffsetlo : least significant byte of scroll offset ; Output: ; A : xposition or $FF if would be off screen convert_virtual_xpos clc ; 2, 2 lda temp2lo ; 3, 5 adc #MINXPOS ; 2, 7 sta temp2lo ; 3, 10 lda #0 adc #0 ; 2, 15 sta temp2hi ; 3, 18 sec ; 2, 20 lda temp2lo ; 3, 23 sbc vxoffsetlo ; 3, 26 sta temp1lo ; 3, 29 lda temp2hi ; 3, 32 sbc #0 sta temp1hi ; 3, 38 cmp #0 ; 2, 40 beq convert_lo ; 2, 42 lda #$FF ; 2, 44 rts ; 6, 50 convert_lo ; +1, 43 lda temp1lo ; 3, 47 cmp #8 ; 2, 49 bcc under8 ; 2, 51 cmp #153 ; 2, 53 bcs under8 ; 2, 55 rts ; 6, 61 under8 ; +1, 52/56 lda #$FF ; 2, 54/58 clc ; 2, 56/60 rts ; 6, 62/66 convert_virtual_xpos_end ORG $FA00 map_enemies_table .byte #%10000000 .byte #%01000000 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%00000010 .byte #%00000001 .byte #%10000000 .byte #%01000000 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%00000010 .byte #%00000001 .byte #%10000000 .byte #%01000000 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%00000010 .byte #%00000001 .byte #%10000000 .byte #%01000000 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%00000010 .byte #%00000001 andTable .byte #%00000000 .byte #%00000011 .byte #%00000000 .byte #%00000001 .byte #%00000011 .byte #%00000000 .byte #%00000001 .byte #%00000000 moveTable .byte #$00 .byte #1 .byte #0 .byte #1 .byte #255 .byte #0 .byte #255 .byte #0 minRange .byte #24 ; 000 down .byte #0 ; 001 right .byte #0 ; 010 down .byte #0 ; 011 right .byte #32 ; 100 left .byte #0 ; 101 down .byte #64 ; 110 left .byte #0 ; 111 down maxRange .byte #231 ; 000 down .byte #223 ; 001 right .byte #255 ; 010 down .byte #191 ; 011 right .byte #255 ; 100 left .byte #255 ; 101 down .byte #255 ; 110 left .byte #255 ; 111 down ; ; Game Data ; PlayerSprite .byte #%01000010 .byte #%10100101 .byte #%01000010 .byte #%00111100 .byte #%01111110 .byte #%01111110 .byte #%11111111 .byte #%11111111 .byte #%00011000 .byte #%00011000 .byte #%00011000 PlayerColor .byte #$0a .byte #$0a .byte #$0a .byte #$0a .byte #$0a .byte #$0a .byte #$0c .byte #$0e .byte #$02 .byte #$42 .byte #$42 spriteTable .byte #sprite1FrameTable .byte #sprite7FrameTable .byte #sprite2FrameTable .byte #sprite7FrameTable .byte #sprite6FrameTable .byte #sprite2FrameTable .byte #sprite6FrameTable .byte #sprite2FrameTable sprite1FrameTable .byte #sprite1Frame1 .byte #sprite1Frame2 .byte #sprite1Frame3 .byte #sprite1Frame4 .byte #sprite1Frame5 .byte #sprite1Frame6 .byte #sprite1Frame7 .byte #sprite1Frame8 sprite2FrameTable .byte #sprite2Frame1 .byte #sprite2Frame1 .byte #sprite2Frame2 .byte #sprite2Frame2 .byte #sprite2Frame1 .byte #sprite2Frame1 .byte #sprite2Frame2 .byte #sprite2Frame2 sprite7FrameTable .byte #sprite7Frame1 .byte #sprite7Frame1 .byte #sprite7Frame2 .byte #sprite7Frame2 .byte #sprite7Frame1 .byte #sprite7Frame1 .byte #sprite7Frame2 .byte #sprite7Frame2 sprite6FrameTable .byte #sprite6Frame1 .byte #sprite6Frame1 .byte #sprite6Frame2 .byte #sprite6Frame2 .byte #sprite6Frame1 .byte #sprite6Frame1 .byte #sprite6Frame2 .byte #sprite6Frame2 explosionFrameTable .byte #explosionSprite1 .byte #explosionSprite1 .byte #explosionSprite1 .byte #explosionSprite1 .byte #explosionSprite2 .byte #explosionSprite2 .byte #explosionSprite2 .byte #explosionSprite2 sprite1Frame1 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors1 sprite1Frame2 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors2 sprite1Frame3 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors3 sprite1Frame4 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors4 sprite1Frame5 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors5 sprite1Frame6 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors6 sprite1Frame7 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors7 sprite1Frame8 .byte #%00000000 .byte #%00000000 .byte #%00000001 .byte #%00000010 .byte #%00000110 .byte #%00001100 .byte #%00011100 .byte #%00111000 .byte #%01111100 .byte #%00111110 .byte #%00011100 .byte #%00111000 .byte #%00110000 .byte #%01100000 .byte #%01000000 .byte #%10000000 .byte #%00000000 .byte #boltColors8 sprite2Frame1 .byte #%00000000 .byte #%00111000 .byte #%01100110 .byte #%11111011 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%01111111 .byte #%01111110 .byte #%00011100 .byte #%10000001 .byte #%0100100 .byte #%01000100 .byte #%00010000 .byte #%00000000 .byte #%00000000 .byte #EnemyColor1 sprite2Frame2 .byte #%00000000 .byte #%00111000 .byte #%01100110 .byte #%11111011 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%01111111 .byte #%01111110 .byte #%00011100 .byte #%00000000 .byte #%00100100 .byte #%00010000 .byte #%00100100 .byte #%00010000 .byte #%00000000 .byte #EnemyColor1 sprite2Frame3 .byte #%00000000 .byte #%01111110 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%01111110 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #EnemyColor1 sprite2Frame4 .byte #%00000000 .byte #%01111110 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%11111111 .byte #%01111110 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #%00000000 .byte #EnemyColor1 sprite6Frame1 .byte #%00000000 .byte #%00000000 .byte #%01110000 .byte #%11011000 .byte #%10111000 .byte #%11111000 .byte #%11111000 .byte #%11111010 .byte #%11111000 .byte #%11111010 .byte #%01110010 .byte #%00000100 .byte #%01011001 .byte #%00000010 .byte #%00001000 .byte #%00000000 .byte #%00000000 .byte #EnemyColor1 sprite6Frame2 .byte #%00000000 .byte #%00000000 .byte #%01110000 .byte #%11011000 .byte #%10111000 .byte #%11111000 .byte #%11111000 .byte #%11111000 .byte #%11111001 .byte #%11111000 .byte #%01110001 .byte #%00000001 .byte #%00000010 .byte #%00101100 .byte #%00000001 .byte #%00000100 .byte #%00000000 .byte #EnemyColor1 sprite7Frame1 .byte #%00000000 .byte #%00000000 .byte #%00001110 .byte #%00011011 .byte #%00011101 .byte #%00011111 .byte #%00010111 .byte #%01011111 .byte #%00011111 .byte #%01011111 .byte #%01001110 .byte #%00100000 .byte #%10011010 .byte #%01000000 .byte #%00010000 .byte #%00000000 .byte #%00000000 .byte #EnemyColor1 sprite7Frame2 .byte #%00000000 .byte #%00000000 .byte #%00001110 .byte #%00011011 .byte #%00011101 .byte #%00011111 .byte #%00010111 .byte #%00011111 .byte #%10011111 .byte #%00011111 .byte #%10001110 .byte #%10000000 .byte #%01000000 .byte #%00110100 .byte #%10000000 .byte #%00100000 .byte #%00000000 .byte #EnemyColor1 EnemyColor1 .byte #$0e .byte #$02 .byte #$02 .byte #$02 .byte #$04 .byte #$06 .byte #$08 .byte #$0a .byte #$0e .byte #$0c .byte #$0a .byte #$08 .byte #$06 .byte #$04 .byte #$02 .byte #$02 .byte #$02 boltColors8 .byte #$0e .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 boltColors7 .byte #$0e .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 boltColors6 .byte #$0e .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 boltColors5 .byte #$0e .byte #$12 .byte #$12 .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 boltColors4 .byte #$0e .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 .byte #$12 .byte #$12 boltColors3 .byte #$0e .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 .byte #$14 .byte #$12 boltColors2 .byte #$0e .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a .byte #$18 .byte #$16 boltColors1 .byte #$0e .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$12 .byte #$14 .byte #$16 .byte #$18 .byte #$1a .byte #$1e .byte #$1a explosionSprite1 .byte #%00000000 .byte #%00000000 .byte #%00101000 .byte #%10000100 .byte #%00101000 .byte #%10010010 .byte #%00101001 .byte #%01000000 .byte #%10001001 .byte #%00100000 .byte #%10001010 .byte #%01001001 .byte #%00000100 .byte #%00100000 .byte #%01001000 .byte #%00010000 .byte #%00000000 .byte #explosionColors explosionSprite2 .byte #%00000000 .byte #%00000000 .byte #%00101000 .byte #%10010010 .byte #%01000000 .byte #%10001001 .byte #%00100000 .byte #%00101001 .byte #%10001010 .byte #%01001001 .byte #%00000100 .byte #%00100000 .byte #%01001001 .byte #%00000100 .byte #%00010000 .byte #%00100000 .byte #%00000000 .byte #explosionColors explosionColors .byte #$0e .byte #$02 .byte #$08 .byte #$0a .byte #$0a .byte #$0e .byte #$0e .byte #$0e .byte #$0e .byte #$0e .byte #$0e .byte #$0e .byte #$0e .byte #$0a .byte #$0a .byte #$08 .byte #$08 scoreTable .byte #scoreZero .byte #>scoreOne .byte #>scoreTwo .byte #>scoreThree .byte #>scoreFour .byte #>scoreFive .byte #>scoreSix .byte #>scoreSeven .byte #>scoreEight .byte #>scoreNine scoreZero .byte #%00111000 .byte #%01000100 .byte #%01000100 .byte #%01000100 .byte #%01000100 .byte #%01000100 .byte #%00111000 scoreOne .byte #%00111000 .byte #%00010000 .byte #%00010000 .byte #%00010000 .byte #%00010000 .byte #%00110000 .byte #%00010000 scoreTwo .byte #%01111100 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%01000100 .byte #%00111000 scoreThree .byte #%00111000 .byte #%01000100 .byte #%00000100 .byte #%00111000 .byte #%00000100 .byte #%01000100 .byte #%00111000 scoreFour .byte #%00001000 .byte #%00001000 .byte #%00001000 .byte #%01111100 .byte #%01001000 .byte #%01001000 .byte #%01001000 scoreFive .byte #%00111000 .byte #%01000100 .byte #%00000100 .byte #%00000100 .byte #%01111000 .byte #%01000000 .byte #%01111100 scoreSix .byte #%00111000 .byte #%01000100 .byte #%01000100 .byte #%01111000 .byte #%01000000 .byte #%01000100 .byte #%00111000 scoreSeven .byte #%00100000 .byte #%00100000 .byte #%00010000 .byte #%00001000 .byte #%00000100 .byte #%00000100 .byte #%01111000 scoreEight .byte #%00111000 .byte #%01000100 .byte #%01000100 .byte #%00111000 .byte #%01000100 .byte #%01000100 .byte #%00111000 scoreNine .byte #%00111000 .byte #%01000100 .byte #%00000100 .byte #%00111100 .byte #%01000100 .byte #%01000100 .byte #%00111000 include "pfdata.asm" ; This table converts the "remainder" of the division by 15 (-1 to -15) to the correct ; fine adjustment value. This table is on a page boundary to guarantee the processor ; will cross a page boundary and waste a cycle in order to be at the precise position ; for a RESP0,x write FineAdjustTableBegin .byte %01100000 ;left 6 .byte %01010000 .byte %01000000 .byte %00110000 .byte %00100000 .byte %00010000 .byte %00000000 ;left/right 0 .byte %11110000 .byte %11100000 .byte %11010000 .byte %11000000 .byte %10110000 .byte %10100000 .byte %10010000 .byte %10000000 ;right 8 FineAdjustTableEnd = FineAdjustTableBegin - 241 ; ; The 2600 looks at this memory location to find the program entry point ; ORG $FFFA .word sysinit ; NMI .word sysinit ; RESET .word sysinit ; IRQ END ; ; Each sprite has the following overhead: ; frame table : 16 bytes ; color table : 16 bytes ; each frame : 17 bytes ; each color frame : 17 bytes ; at least one entry in the index : 2 bytes ; So, a sprite with 8 full color frames takes 16 + 16 + 2 + 17x8 + 17x8 = 306 bytes ; A sprite with 2 full color frames = 102 bytes ; A sprite with 1 frame = 68 bytes ;