; compile with dasm (http://dasm-dillon.sourceforge.net/) processor 6502 org $801 dc.w .next, 10 dc.b $9e, " 14912", 0 .next dc.w 0 org $2f00 ds.b $100, $01 org $3000 ; color data ds.b 1000, $01 org $3400 ; sprite data dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $f0, $07, $80 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $80, $00 dc.b $00, $00, $00 dc.b $00, $00, $00 .missiletick dc.b $01 .missilegentick dc.b $40 .level dc.b $38 .rnglo dc.b $aa .rnghi dc.b $aa .circleradius ; $00-$78, low nibble should be zero or 8 dc.b $00 .circlelo dc.b $00 .circlehi dc.b $24 .circleoff dc.b $02 .circleradiuscounter dc.b $0 .scratch ds.b 3, $00 .circlewaspressed dc.b $00 .hitsound dc.b $00 .circlesound dc.b $00 align 8 .bitlookup dc.b $80, $40, $20, $10, $08, $04, $02, $01 .sqrtlut ; make sure this doesn't cross a page boundary ; byte(.sqrtlut + r*8 + dy) = floor(sqrt(r^2 - dy^2)) ; r is in steps of 0.5 pixel dc.b $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff dc.b $0, $ff, $ff, $ff, $ff, $ff, $ff, $ff dc.b $1, $0, $ff, $ff, $ff, $ff, $ff, $ff dc.b $1, $1, $ff, $ff, $ff, $ff, $ff, $ff dc.b $2, $1, $0, $ff, $ff, $ff, $ff, $ff dc.b $2, $2, $1, $ff, $ff, $ff, $ff, $ff dc.b $3, $2, $2, $0, $ff, $ff, $ff, $ff dc.b $3, $3, $2, $1, $ff, $ff, $ff, $ff dc.b $4, $3, $3, $2, $0, $ff, $ff, $ff dc.b $4, $4, $4, $3, $2, $ff, $ff, $ff dc.b $5, $4, $4, $4, $3, $0, $ff, $ff dc.b $5, $5, $5, $4, $3, $2, $ff, $ff dc.b $6, $5, $5, $5, $4, $3, $0, $ff dc.b $6, $6, $6, $5, $5, $4, $2, $ff dc.b $7, $6, $6, $6, $5, $4, $3, $0 dc.b $7, $7, $7, $6, $6, $5, $4, $2 .rangelut ; make sure this doesn't cross a page boundary dc.b $00, $00, $00, $00, $00, $00, $00, $01 dc.b $00, $00, $00, $00, $00, $00, $01, $03 dc.b $00, $00, $00, $00, $00, $01, $03, $07 dc.b $00, $00, $00, $00, $01, $03, $07, $0f dc.b $00, $00, $00, $01, $03, $07, $0f, $1f dc.b $00, $00, $01, $03, $07, $0f, $1f, $3f dc.b $00, $01, $03, $07, $0f, $1f, $3f, $7f dc.b $01, $03, $07, $0f, $1f, $3f, $7f, $ff dc.b $02, $07, $0f, $1f, $3f, $7f, $ff, $ff dc.b $04, $0e, $1f, $3f, $7f, $ff, $ff, $ff dc.b $08, $1c, $3e, $7f, $ff, $ff, $ff, $ff dc.b $10, $38, $7c, $fe, $ff, $ff, $ff, $ff dc.b $20, $70, $f8, $fc, $fe, $ff, $ff, $ff dc.b $40, $e0, $f0, $f8, $fc, $fe, $ff, $ff dc.b $80, $c0, $e0, $f0, $f8, $fc, $fe, $ff dc.b $00, $80, $c0, $e0, $f0, $f8, $fc, $fe dc.b $00, $00, $80, $c0, $e0, $f0, $f8, $fc dc.b $00, $00, $00, $80, $c0, $e0, $f0, $f8 dc.b $00, $00, $00, $00, $80, $c0, $e0, $f0 dc.b $00, $00, $00, $00, $00, $80, $c0, $e0 dc.b $00, $00, $00, $00, $00, $00, $80, $c0 dc.b $00, $00, $00, $00, $00, $00, $00, $80 org $358f ; it is important that .missilehi/lo/bits/slopes do not cross a page boundary .missilecount dc.b 1 ; max 8 .missilehi ds.b 8, $20 .missilelo ds.b 8, $40 .missilebits ds.b 8, $10 .missileslopes ds.b 8, $60 .missilelastvals ds.b 8, $ff .noisefreq dc.b $df .noisectl dc.b $7c .noisesr dc.b $e0 .hitfreq dc.b $f8 .hitctl dc.b $dd .hitad dc.b $ff .circlefreq dc.b $fe .circlectl dc.b $bd .circlead dc.b $fe .circlesr dc.b $ff .filtercutoff dc.b $f0 org $3a40 sei lda #$3b sta $d011 ; enable display, set high bit of raster to 0, enable bitmap lda #$35 ; turn off rom sta $01 lda #$7f ; disable some interrupts sta $dc0d ; timers sta $dd0d ; keyboard scan ; initial position for sprite 0 lda #$3f sta $d000 sta $d001 lda #$01 sta $d015 ; enable sprite 0 lda #$0a sta $d027 ; color sprite 0 lda #$00 sta $d021 ; set background color sta $d020 ; ...and border color lda #$c8 sta $d018 ; set bitmap base to $2000 and color base to $3000 lda #$d0 sta $33f8 ; set sprite 0 address to $3400 lda #$c0 sta $d012 ; break on a particular raster lda #<.raster sta $fffe lda #>.raster sta $ffff lda #$01 sta $d01a ; enable raster interrupts cli .wait lda .rnglo adc #$1 adc .rnglo sta .rnglo lda .rnghi adc #$aa sta .rnghi eor .rnglo sta .rnglo jmp .wait .drawcirclesub lda $10 sta .circleload+1 sta .circlestore+1 lda $11 sta .circleload+2 sta .circlestore+2 lda $12 clc adc #7 bmi .dontdrawline cmp #22 bcs .dontdrawline asl asl asl sta $26 ; biased dx lda .circleradius clc adc #<.sqrtlut sta .sqrtlookup+1 ldx #$7 .drawcircleloop txa clc adc $13 bpl .nonnegativey eor #$ff ; invert the number clc adc #$1 .nonnegativey cmp #$8 bcs .dontdrawline tay .sqrtlookup lda .sqrtlut,Y cmp #$ff beq .dontdrawline ora $26 tay .rangelookup lda .rangelut,Y .circleeor eor #$ff .circleload and $ffff,X .circlestore sta $ffff,X .dontdrawline dex bpl .drawcircleloop rts .drawcircleline lda #0 sec sbc .circleoff sta $12 jsr .drawcirclesub lda $12 clc adc #$8 sta $12 lda $10 clc adc #$8 sta $10 lda $11 adc #$0 sta $11 jsr .drawcirclesub lda $12 clc adc #$8 sta $12 lda $10 clc adc #$8 sta $10 lda $11 adc #$0 sta $11 jsr .drawcirclesub rts .drawcircle lda .circlelo and #$7 eor #$ff clc adc #$1 sta $13 ; .. lda .circlelo and #$f8 sta $10 lda .circlehi sta $11 jsr .drawcircleline lda $13 clc adc #$8 sta $13 ; .. lda .circlelo and #$f8 clc adc #$40 sta $10 lda .circlehi adc #$1 sta $11 jsr .drawcircleline lda $13 sec sbc #$10 sta $13 ; .. lda .circlelo and #$f8 sec sbc #$40 sta $10 lda .circlehi sbc #$1 sta $11 jsr .drawcircleline rts .raster lda #$ff sta $d019 ; clear interrupt condition cli lda #0 sta .hitsound sta .circlesound lda #$29 ; and immediate sta .circleeor lda #$5D ; eor $ffff,X sta .circleload jsr .drawcircle lda .circleradiuscounter beq .nocircle clc adc #$02 bpl .radiusup sec sbc #$08 ora #$80 .radiusup sta .circleradiuscounter and #$7f bne .noresetradiusbit sta .circleradiuscounter .noresetradiusbit and #$78 sta .circleradius .nocircle dec .missiletick beq .updatemissiles jmp .nomissiles .updatemissiles lda #$04 sta .missiletick dec .missilegentick bne .nogeneratemissile lda .level sec sbc #$1a bcs .morelevels lda #$18 ; we're generating one missile per 24 ticks, which is the limit .morelevels clc adc #$18 sta .level sta .missilegentick .generateanother ; generate a new missile ldx .missilecount cpx #$8 bcs .nogeneratemissile lda .rnglo sta .missilelo,X sta .valload+1 lda #$20 sta .missilehi,X sta .valload+2 lda .rnghi and #$f0 sta .missileslopes,X .valload lda $ffff sta .missilelastvals,X inc .missilecount lda .rnglo adc #$1 adc .rnglo sta .rnglo lda .rnghi adc #$aa adc .rnglo sta .rnghi and #3 bne .nogeneratemissile lda .level clc adc .missilegentick sta .missilegentick jmp .generateanother .nogeneratemissile lda #<.missilelo sta .mldlo+1 lda #<.missilehi sta .mldhi+1 lda #<.missilebits sta .mldbits+1 lda #<.missileslopes sta .mldslopes+1 lda #<.missilelastvals sta .mldlastvals+1 ldx #$0 lda .missilecount bne .updatemissilesloop jmp .nomissiles .updatemissilesloop ; these have labels so we can remove missiles as we loop .mldlo lda .missilelo,X sta .missilelo,X sta .comparemissile+1 .mldhi lda .missilehi,X sta .missilehi,X sta .comparemissile+2 .mldbits lda .missilebits,X sta .missilebits,X .mldslopes lda .missileslopes,X sta .missileslopes,X .mldlastvals lda .missilelastvals,X sta .missilelastvals,X .comparemissile eor $ffff and .missilebits,X bne .removemissile ; move missile downward clc lda .missilelo,X adc #$1 tay and #$7 bne .nomissileoverflowy tya clc adc #-$8 clc adc #$40 ; one row is $140 tay lda .missilehi,X adc #$1 sta .missilehi,X cmp #$40 ; don't let missiles go too far bcc .nomissileoverflowy ; this missile needs to be removed .removemissile inc .mldlo+1 inc .mldhi+1 inc .mldbits+1 inc .mldslopes+1 inc .mldlastvals+1 dec .missilecount bne .updatemissilesloop jmp .nomissiles .nomissileoverflowy tya sta .missilelo,X sta .mloadaddr+1 sta .mstoreaddr+1 lda .missilehi,X sta .mloadaddr+2 sta .mstoreaddr+2 ; move missile sideways if necessary lda .missileslopes,X tay and #$f bne .nosidewaysmissile tya lsr lsr lsr lsr adc #$01 and #$7 ora .missileslopes,X sta .missileslopes,X and #$80 bne .leftwardmissile clc lda .missilebits,X ror ror .missilebits,X bcc .nosidewaysmissile lda .missilelo,X adc #7 ; actually want 8, but carry bit is set sta .missilelo,X sta .mloadaddr+1 sta .mstoreaddr+1 lda .missilehi,X bcc .nosidewaysmissile adc #0 sta .missilehi,X sta .mloadaddr+2 sta .mstoreaddr+2 jmp .nosidewaysmissile .leftwardmissile clc lda .missilebits,X rol rol .missilebits,X bcc .nosidewaysmissile lda .missilelo,X sbc #8 sta .missilelo,X sta .mloadaddr+1 sta .mstoreaddr+1 lda .missilehi,X bcs .nosidewaysmissile sbc #0 sta .missilehi,X sta .mloadaddr+2 sta .mstoreaddr+2 .nosidewaysmissile dec .missileslopes,X .mloadaddr lda $2000 tay eor #$ff and .missilebits,X ora .hitsound sta .hitsound tya eor .missilebits,X sta .missilelastvals,X .mstoreaddr sta $2000 inx cpx .missilecount bcs .nomissiles jmp .updatemissilesloop .nomissiles .input lda $dc01 tax and #$01 bne .noup clc adc .rnglo sta .rnglo lda .rnghi adc #0 sta .rnghi dec $d001 bne .noup inc $d001 .noup txa and #$02 bne .nodown clc adc .rnglo sta .rnglo lda .rnghi adc #0 sta .rnghi inc $d001 bne .nodown dec $d001 .nodown txa and #$04 bne .noleft clc adc .rnglo sta .rnglo lda .rnghi adc #0 sta .rnghi lda $d000 bne .nocheckleft dec $d010 beq .nocheckleft inc $d010 lda #$01 .nocheckleft clc adc #$ff sta $d000 .noleft txa and #$08 bne .noright clc adc .rnglo sta .rnglo lda .rnghi adc #0 sta .rnghi inc $d000 bne .noright lda $d010 eor #$01 bne .noresetright dec $d000 eor #$01 .noresetright sta $d010 .noright txa and #$10 bne .nobutton lda .circleradius bne .nobutton clc adc .rnglo sta .rnglo lda .rnghi adc #0 sta .rnghi lda $d001 clc adc #-40 ; extra offset for crosshair sta .scratch+0 lda $d000 sec sbc #23 ; extra offset for crosshair sta .scratch+1 lda $d010 sbc #0 sta .scratch+2 jmp .pixel2offset .nobutton lda $dc01 and #$10 cmp .circlewaspressed beq .nopressedchange sta .circlewaspressed cmp #$0 beq .nopressedchange ldx .circleradius bne .nopressedchange sta .circlesound .nopressedchange lda #$49 ; eor immediate sta .circleeor lda #$3D ; and $ffff,X sta .circleload jsr .drawcircle lda .rnglo and #$0f clc adc .noisefreq eor #$ff sta $d400 sta $d401 lda .noisectl eor #$ff sta $d404 lda .noisesr eor #$ff sta $d406 lda .hitfreq eor #$ff sta $d407 sta $d408 lda .hitctl eor #$ff ldx .hitsound beq .nohitsound ora #$01 .nohitsound sta $d40B lda .hitad eor #$ff sta $d40c lda .circlefreq eor #$ff sta $d40e sta $d40f lda .circlectl eor #$ff ldx .circlesound beq .nocirclesound ora #$01 .nocirclesound sta $d412 lda .circlead eor #$ff sta $d413 lda .circlesr eor #$ff sta $d414 lda .filtercutoff eor #$ff sta $d416 lda #$01 sta $d417 lda #$1f sta $d418 jmp .wait ; in: ; .scratch+0 = y ; .scratch+1 = low x ; .scratch+2 = high x ; out: ; .circlelo = low address ; .circlehi = high address ; .circleoff = offset in byte .pixel2offset lda #$20 sta .circlehi lda #$00 sta .circlelo lda .scratch+0 ; y tay lsr lsr lsr clc beq .skipcolumnloop tax .columnloop lda #$40 ; 40 columns * 8 = 0x140 adc .circlelo sta .circlelo lda #$1 adc .circlehi sta .circlehi dex bne .columnloop .skipcolumnloop tya ; add low y bits and #$7 adc .circlelo sta .circlelo lda #$0 adc .circlehi sta .circlehi lda .scratch+1 ; x low tay and #$f8 adc .circlelo sta .circlelo lda .scratch+2 ; x high adc .circlehi sta .circlehi tya and #$7 sta .circleoff lda #2 sta .circleradius sta .circleradiuscounter jmp .nobutton ds.b $1000, $ff