DSK OCTOPEDE ************************************************** * Setup * pede coords to 0,0 * player to center, bottom * draw mushrooms - how many? how to randomize? * Do each frame: * read joystick * update player position * if button and not already firing, create missile * if already firing, update missile row * if missile new position is non-blank, collision * * update pede positions. * if pede new position is non-blank, collision * interframe delay based on "score" ************************************************** * Variables ************************************************** ROW EQU $FA ; row/col in text screen COLUMN EQU $FB CHAR EQU $FC ; char/pixel to plot CURRENTPEDE EQU $0F ; 0-F which segment to operate on SPIDERROW EQU $FE ; row/col of spider's left half SPIDERCOLUMN EQU $FF SPIDERDELAY EQU $F9 ; how quick to move the spider? CH EQU $24 ; cursor Horiz CV EQU $25 ; cursor Vert WNDWDTH EQU $21 ; Width of text window WNDTOP EQU $22 ; Top of text window RNDSEED EQU $EA ; +eb +ec PEDEDELAY EQU $CE ; how many frames to delay the pede's walking PEDECOUNTER EQU $CD ; how many frames to delay the pede's walking SHROOMCOUNT EQU $CC ; how many mushrooms to start with PEDEBYTE EQU $1D ; 1 bit per segment MISSILEDELAY EQU $1E ; dropping block column PLAYERCOLUMN EQU $09 ; Where is the player shooting from? PLAYERROW EQU $0A ; Where is the player shooting from? PLAYERDELAY EQU $40 ; how quick to move the player PROGRESS EQU $FD ; How many lives? REVERSEPEDES EQU $1F ; which segments are going UP? CSW EQU $36 BASL EQU $28 TABLEPOS EQU $3C ; (BAS2) SCRN EQU $3E ; (A4) VECT EQU $3EA ITERATIONS EQU $F8 ************************************************** * Apple Standard Memory Locations ************************************************** CLRLORES EQU $F832 LORES EQU $C050 HIRES EQU $C057 TXTSET EQU $C051 MIXCLR EQU $C052 MIXSET EQU $C053 TXTPAGE1 EQU $C054 TXTPAGE2 EQU $C055 KEY EQU $C000 C80STOREOFF EQU $C000 C80STOREON EQU $C001 STROBE EQU $C010 SPEAKER EQU $C030 VBL EQU $C02E RDVBLBAR EQU $C019 ; not VBL (VBL signal low WAIT EQU $FCA8 RAMWRTAUX EQU $C005 RAMWRTMAIN EQU $C004 SETAN3 EQU $C05E ; Set annunciator-3 output to 0 SET80VID EQU $C00D ; enable 80-column display mode (WR-only) HOME EQU $FC58 ; clear the text screen ; VTAB EQU $FC22 ; Sets the cursor vertical position (from CV) COUT EQU $FDED ; Calls the output routine whose address is stored in CSW, ; normally COUT1 COUT1 EQU $FDF0 COUT2 EQU $FBF0 PRBYTE EQU $FDDA ; print hex byte in A STROUT EQU $DB3A ; Y=String ptr high, A=String ptr low ALTTEXT EQU $C055 ALTTEXTOFF EQU $C054 PB0 EQU $C061 ; paddle 0 button. high bit set when pressed. PDL0 EQU $C064 ; paddle 0 value, or should I use PREAD? PREAD EQU $FB1E ROMINIT EQU $FB2F ROMSETKBD EQU $FE89 ROMSETVID EQU $FE93 ALTCHAR EQU $C00F ; enables alternative character set - mousetext BLINK EQU $F3 SPEED EQU $F1 HGR EQU $F3E2 ; Initializes to hi-res page1, clears screen. HGR2 EQU $F3D8 ; Initializes to hi-res page2, clears screen. HCLR EQU $F3F2 ; Clears current screen to black ************************************************** * START - sets up various fiddly zero page bits ************************************************** ORG $0800 ; PROGRAM DATA STARTS AT $0800 RESETSCORE LDA #$00 STA PLAYERSCORE STA PLAYERSCORE+1 STA PLAYERSCORE+2 STA PLAYERSCORE+3 LDA #$03 STA PROGRESS RESTART DEC PROGRESS BMI RESETSCORE ; no more lives left? start back at 3. JSR FILLSCREENFAST ; clear screen to black JSR HGR ; clear HGR BIT LORES ; GRAPHIQUES BIT MIXCLR ; PLEIN G. BIT HIRES ; HAUTE RESOLUTION BIT TXTPAGE1 ; PAGE1 BIT $C00C ; 40 COL. JSR HOOK ; set HRCG output LDA #$00 STA PEDECOUNTER LDA #$29 ; keeps COUT from linebreaking STA WNDWDTH ; CLC ROR ADC #$01 STA PLAYERCOLUMN ; middle-ish LDA #$17 STA PLAYERROW ; bottom line LDA #$14 STA SPIDERROW LDA #$27 STA SPIDERCOLUMN RELOAD JSR RNDINIT ; *should* cycle the random seed. LDA #$00 ; zeros out accumulator for score display. JSR UPDATESCORE JSR DISPLAYHISCORE LDA #$07 STA PEDEDELAY STA MISSILEDELAY ; bit of a break between missile shots LDA #$FF ; 11111111 STA PEDEBYTE ; all segments live LDY #$07 LDX #$00 RESETPEDE LDA #$00 STA REVERSEPEDES ; all pedes going down STA PEDECOORDS,X ; segment ROW INX TYA STA PEDECOORDS,X ; segment COLUMN INX DEY BPL RESETPEDE ; Y=0 JSR DRAWSHROOMS ; puts mushrooms in random locations between row 0 and 23 LDA PROGRESS BEQ EVERYFRAME ; skip if no lives left. JSR DRAWLIVES ; updates "progress" player lives indicator ************************************************** * MAIN LOOP * waits for keyboard input, moves cursor, etc ************************************************** * Do each frame: * read joystick * update player position * if button and not already firing, create missile * if already firing, update missile row * if missile new position is non-blank, collision * * update pede positions. * if pede new position is non-blank, collision * interframe delay based on "score" ? EVERYFRAME LDA PLAYERROW BEQ RESTART ; player dead if row=0 LDA PEDEBYTE ; pedes all dead if 0 BEQ RELOAD LDA #$00 STA CURRENTPEDE ; start each frame on first segment JSR UPDATEPLAYER JSR UPDATEMISSILE JSR UPDATEPEDE JSR UPDATESPIDER JSR INTERFRAME LDA #$00 ; oops. i'm stuck if this rolls over STA ITERATIONS ; then what? RTS? JMP EVERYFRAME ; loopty loop ;/EVERYFRAME ************************************************** INTERFRAME LDA #$30 ; wait a bit JSR WAIT ANRTS RTS ;/INTERFRAME ************************************************** UPDATESPIDER LDA SPIDERDELAY BEQ STARTSPIDER DEC SPIDERDELAY RTS STARTSPIDER LDA #$0D STA SPIDERDELAY LDA SPIDERROW ; mark for erase STA ROW LDA SPIDERCOLUMN STA COLUMN MOVESPIDER ; get random number, 0-FF, clear high nibble, divide by 4. JSR RND ; 0-FF AND #$03 ; 0-3 BEQ DONEMOVING ; 0 stay ROR ; 1 or 3 - carry set BCC JUMPSPIDER ; 2 - carry clear, left BEQ JUMPUP ; zero, jump up JUMPDOWN INC SPIDERROW ; 1, jump down LDA SPIDERROW CMP #$18 BNE JUMPSPIDER LDA #$17 STA SPIDERROW JMP JUMPSPIDER JUMPUP DEC SPIDERROW LDA SPIDERROW CMP #$0A BNE JUMPSPIDER LDA #$0B STA SPIDERROW JUMPSPIDER ; determine if the spider is jumping left or right at the moment. ; if the 100s score is odd, jump left. Otherwise, right. LDA PLAYERSCORE+2 ROR BCC JUMPRIGHT JUMPLEFT DEC SPIDERCOLUMN BPL DONEMOVING LDA #$28 ; column zero, reset STA SPIDERCOLUMN JMP DONEMOVING JUMPRIGHT INC SPIDERCOLUMN LDA SPIDERCOLUMN CMP #$28 BCC DONEMOVING ; > 28, reset. LDA #$00 ; column zero, reset STA SPIDERCOLUMN DONEMOVING ERASESPIDER ;LDA #$A0 ;STA CHAR LDA ROW STA CV VTAB LDA COLUMN STA CH COLLIDESPIDER JSR GETCHAR ; hit the player? CMP #$F0 BEQ KILLTHEPLAYER CMP #$F1 BEQ KILLTHEPLAYER INC CH ; right side test. JSR GETCHAR CMP #$F0 BEQ KILLTHEPLAYER CMP #$F1 BEQ KILLTHEPLAYER DEC CH ; LDA #$A0 ; JSR PLOTQUICK ; otherwise, clobber mushrooms and pedes. ; JSR PLOTQUICK JSR ERASEQUICK JSR ERASEQUICK DRAWSPIDER LDA SPIDERCOLUMN STA CH LDA SPIDERROW STA CV VTAB LDA #$C8 ; spider, left side = C8 ; STA CHAR JSR PLOTQUICK ; INC CHAR ; spider, right side = CA ; INC CHAR LDA #$CA ; spider, left side = C8 JSR PLOTQUICK RTS KILLTHEPLAYER JMP KILLPLAYER ************************************************** UPDATEPLAYER LDA PLAYERDELAY ; counts down to 0 BEQ STARTPLAYER ; if 0, set to delay value, and draw the pede DEC PLAYERDELAY ; otherwise, decrement RTS ; exit if countdown isn't done yet. STARTPLAYER LDA #$0B STA PLAYERDELAY ; erase current player position ; calculate new player position ; render new player position LDA PLAYERCOLUMN ; load current position STA CH ; PLOTCOLUMN STA COLUMN ; store for erasing later LDA PLAYERROW STA CV ; PLOTROW ; hang onto these in case there's a collision STA ROW ; store for erasing later BIT ANRTS ; set overflow = no movement yet ; read joystickX/pdl0, if less than 0x64(100) move left. if over 0x96(150) move right. MOVEPLAYER LDX #$00 ; PDL 0 JSR PREAD ; returns in Y TYA ; Y to Accumulator? CMP #$64 BCC MOVEPLAYERLEFT CMP #$96 BCS MOVEPLAYERRIGHT JMP MOVEPLAYER2 ; no L/R, check U/D MOVEPLAYERRIGHT LDA PLAYERCOLUMN ; already at col 39? CMP #$27 BEQ COLLIDEPLAYER INC PLAYERCOLUMN CLV JMP MOVEPLAYER2 MOVEPLAYERLEFT LDA PLAYERCOLUMN ; already at zero BEQ COLLIDEPLAYER DEC PLAYERCOLUMN ; otherwise, go left CLV MOVEPLAYER2 LDX #$01 ; PDL 1 JSR PREAD ; returns in Y TYA ; Y to Accumulator? CMP #$64 BCC MOVEPLAYERUP CMP #$96 BCS MOVEPLAYERDOWN JMP COLLIDEPLAYER ; no U/D, plot as-is MOVEPLAYERUP LDA PLAYERROW ; already at col 39? CMP #$13 BEQ COLLIDEPLAYER DEC PLAYERROW CLV JMP COLLIDEPLAYER ; moving, check collision MOVEPLAYERDOWN LDA PLAYERROW ; already at zero CMP #$17 BEQ COLLIDEPLAYER INC PLAYERROW ; otherwise, go DOWN CLV COLLIDEPLAYER ; check new position for collisions BVS PLOTPLAYER ; overflow still set, skip the move/collide math ; LDA #$A0 ; plotrow/col should still be intact ; STA CHAR JSR ERASEQUICK ; erase current position LDA PLAYERCOLUMN STA CH ; PLOTCOLUMN LDA PLAYERROW STA CV ; PLOTROW JSR GETCHAR ; not zero, collision. revert to old position. AND #$F0 ; Ax = space CMP #$A0 BEQ PLOTPLAYER ; not zero, collision. revert to old position. CMP #$C0 ; hit a 'pede or spider. DIE. BEQ PLAYERDIED LDA ROW STA CV ; PLOTROW STA PLAYERROW LDA COLUMN STA CH ; PLOTCOLUMN STA PLAYERCOLUMN JSR CLICK PLOTPLAYER LDA #$F0 ;F0 ; STA CHAR JSR PLOTQUICK ; plot the player RTS DONEPLAYER RTS ;/UPDATEPLAYER PLAYERDIED ; moved into a 'pede or the spider. jump to killplayer? JMP KILLPLAYER ************************************************** UPDATEMISSILE * if button and not already firing, create missile * if already firing, update missile row, display byte * if missile new position is non-blank, collision LDA PLAYERMISSILE ; row of missile will be FF if not firing BMI NOMISSILE STA CV ; PLOTROW ; erase missile at current coords ; LDX #$01 LDA PLAYERMISSILE+1 STA CH ; PLOTCOLUMN ; LDA #$A0 ; STA CHAR JSR ERASEQUICK NEWMISSILE ;LDX #$02 ; update missile coords LDA PLAYERMISSILE+2 ; if displaybyte is AE . , make it A7 ', don't update row. CMP #$FB BEQ MISSILESTAY MISSILEUP DEC PLAYERMISSILE ; dec missile row BMI MISSILEDONE ; if FF, all done. LDA #$FB JMP MISSILECHAR MISSILESTAY LDA #$FD ; STA PLAYERMISSILE+2 MISSILECHAR ;STA CHAR ; display updated missile at new coords LDA PLAYERMISSILE STA CV ; PLOTROW ;DEX LDA PLAYERMISSILE+1 STA CH ; PLOTCOLUMN JSR GETCHAR ; check missile collision AND #$F0 ; Ax = space CMP #$A0 BNE COLLIDEMISSILE LDA PLAYERMISSILE+2 JSR PLOTQUICK RTS ; if there's no missile on the screen yet, put one there, as long as it has been at least N frames since last shot NOMISSILE LDA MISSILEDELAY BEQ NOMISSILE2 DEC MISSILEDELAY ; count down to zero, bit of a break between shots JMP MISSILEDONE NOMISSILE2 ; countdown done? check button LDA PB0 ; no missile on screen. Check for button press to create one. BPL MISSILEDONE ; otherwise, create new missile at player column, row 23 ADDMISSILE LDA #$30 STA MISSILEDELAY ; reset delay for next shot. LDX #$2 ; set missile display byte to #$F0 LDA #$FD ; . #$F0 STA PLAYERMISSILE,X STA CHAR DEX LDA PLAYERCOLUMN ; get player COLUMN STA PLAYERMISSILE,X DEX LDA PLAYERROW ; set row to player - 1 STA PLAYERMISSILE,X JMP NEWMISSILE ; UPDATEMISSILE ; put it on screen. MISSILEDONE RTS COLLIDEMISSILE LDX #$00 ; accumulator should tell us what we collided with STX MISSILEDELAY ; hit something, set delay to zero, to fire again. ; PLOTROW and PLOTCOLUMN are intact AND #$F0 ; clear low nibble to C0 or C1 CMP #$C0 ; @ ; IS IT A PEDE SEGMENT (Cx)? BNE COLLIDESHROOM ; NO? check for mushroom LDA #$D0 ; full shroom ;STA CHAR JSR PLOTQUICK LDA #$25 ; 25 points for a pede JSR UPDATESCORE HITPEDE ; hit a pede segment - or SPIDER ; determine which segment was hit ; for each segment ; check if segment's COLUMN == missile's column ; set PEDECOORD,X==FF to remove from board. LDY #$08 WHICHPEDE DEY ; next pede segment 7-0 BPL WHICHPEDE2 ; rolled over? KILLED SPIDER JMP KILLSPIDER ; spider dead. RTS WHICHPEDE2 TYA CLC ROL TAX ; segment x 2 = segment ROW INX LDA PEDECOORDS,X ; get segment COLUMN LDX #$01 CMP PLAYERMISSILE,X ; compare to missile column BNE WHICHPEDE ; not the right segment, go again ; correct segment COLUMN, CHECK ROW TYA CLC ROL TAX LDA PEDECOORDS,X ; get segment ROW CMP PLAYERMISSILE ; compare to missile ROW BNE WHICHPEDE ; wrong segment, go again ; correct COLUMN AND ROW TYA CLC ROL TAX LDA #$FF ; set segment ROW again STA PEDECOORDS,X ; got the right segment, remove it JSR CLICK ; clear the missile LDA #$FF STA PLAYERMISSILE ; missile row to top, clears missile SETPEDEBYTE LDA #$00 ; zero out A SEC ; set carry SETPEDEBYTE2 ROL ; carry into A DEY ; set for next segment BPL SETPEDEBYTE2 ; if rolled over, done EOR PEDEBYTE ; 11111111 ; 00001000 EOR STA PEDEBYTE ;=11110111 RTS COLLIDESHROOM CMP #$B0 BEQ KILLSCORE ; you hit the score, skippy. CMP #$F0 BEQ KILLSCORE ; hit the player lives icons CMP #$D0 ; ? ; 5F = turn mushrooms into partial mushroom BNE KILLSHROOM LDA #$E0 ; _ JMP KILLSHROOM2 KILLSHROOM CMP #$E0 ; _ ; 05 = remove partial mushrooms LDA #$A0 KILLSHROOM2 ;STA CHAR JSR PLOTQUICK LDA #$10 ; 10 points for a mushroom JSR UPDATESCORE KILLSCORE LDA #$FF ; reset the missile's coords to off-screen STA PLAYERMISSILE JSR CLICK RTS KILLSPIDER ; erase spider LDA SPIDERROW STA CV VTAB LDA SPIDERCOLUMN STA CH ; LDA #$A0 ; STA CHAR JSR ERASEQUICK JSR ERASEQUICK ; set spider countdown to 0 LDA #$FF STA SPIDERDELAY ; reset spider coords LDA #$28 STA SPIDERCOLUMN LDA #$50 ; 50 points for the spider JSR UPDATESCORE LDA #$50 ; 50 more points for the spider? JSR UPDATESCORE RTS ;/UPDATEMISSILE ************************************************** UPDATEPEDE ; check if frames of delay have elapsed, slows down the pede LDA PEDECOUNTER ; counts down to 0 BEQ STARTPEDE ; if 0, set to delay value, and draw the pede DEC PEDECOUNTER ; otherwise, decrement RTS ; exit if countdown isn't done yet. STARTPEDE LDA PEDEDELAY STA PEDECOUNTER NEXTPEDE LDA CURRENTPEDE ; which segment 0-7 CLC ROL ; multiply by 2 TAX LDA PEDECOORDS,X ; segment's row CMP #$FF ; if FF, ignore BEQ SKIPPEDE PLOTPEDE STA CV ; PLOTROW ; current plot row STA ROW INX LDA PEDECOORDS,X ; segment's column STA CH ; PLOTCOLUMN ; current plot column STA COLUMN JSR GETCHAR ; erasing something other than a pede segment? AND #$F0 ; Ax = space CMP #$A0 BEQ CONTINUEPEDE ; 00 - skip the erase step AND #$F0 ; clear low nibble Cn = PEDE CMP #$C0 ; @ BNE CONTINUEPEDE ; skip the erase step if not 4C ; hit another pede segment, no worries. CONTINUEPEDE JSR WALKLOOP ; calculates next position ; plots new position SKIPPEDE INC CURRENTPEDE ; repeat with next segment LDA CURRENTPEDE CMP #$08 ; done all 8 segments? RTS. BNE NEXTPEDE LDA #$00 ; start over with segment 0 STA CURRENTPEDE RTS ;/UPDATEPEDE WALKLOOP ; calculates next position ; erases previous position ; plots new position NEXTPOS JSR EVENORODDROW ; calculate next position JSR GETCHAR ; if next position not 00, then down and reverse CMP #$AF ; less than AF = empty, plottable BCS NEXTROW ; decides which pede direction to plot ERASEPEDE LDA CHAR PHA ; push CHAR LDA CH ; PLOTCOLUMN ; push PLOTCOLUMN PHA LDA CV ; PLOTROW ; push PLOTROW PHA LDA ROW ; segment old position STA CV ; PLOTROW LDA COLUMN STA CH ; PLOTCOLUMN ; LDA #$A0 ; erase current segment previous position ; STA CHAR ; load the char JSR ERASEQUICK ; erases current segment previous position PLA ; pull PLOTROW STA CV ; PLOTROW PLA STA CH ; PLOTCOLUMN ; pull PLOTCOLUMN PLA ; STA CHAR ; pull CHAR JSR PLOTQUICK ; plots pede at new position RTS ;/WALKLOOP EVENORODDROW LDA CURRENTPEDE ; segment 0-8 CLC ROL ; *2 TAX ; to X LDA PEDECOORDS,X ; segment ROW STA CV ; PLOTROW ; for checking char at next position ROR ; ROW = odd, then carry set BCS ODDROW ;/EVENORODDROW EVENROW INX ; INX to get to CURRENTPEDE,COLUMN LDY PEDECOORDS,X ; inc segment column INY TYA STY CH ; PLOTCOLUMN ; to PLOTCOLUMN STA PEDECOORDS,X CMP #$28 ; if PLOTCOLUMN == #$27, then inc PLOTROW BEQ NEXTROW ; else, loop on current row. JSR GETCHAR ; get character at next position. CMP #$AF ; < AF = empty space. BCS NEXTROW LDA #$C0 ; @ LDY CURRENTPEDE BNE EVENPLOT LDA #$C4 ; "head" EVENPLOT STA CHAR RTS ; return and draw pixel ;/EVENROW ODDROW INX ; INX to get to CURRENTPEDE,COLUMN LDY PEDECOORDS,X ; DEC segment column DEY BMI NEXTROW ; if PLOTCOLUMN rolled over, then inc PLOTROW TYA STA PEDECOORDS,X STA CH ; PLOTCOLUMN ; to PLOTCOLUMN JSR GETCHAR ; get char at next position CMP #$AF ; less than AF, space. BCS NEXTROW LDA #$C2 ; A LDY CURRENTPEDE BNE ODDPLOT LDA #$C6 ; "head" ODDPLOT STA CHAR RTS ; return and draw pixel ;/ODDROW NEXTROW INC ITERATIONS ; if I'm stuck on a loop too long, kill the pede and move on BEQ KILLPEDE ; hit something, bounce, kill or die. or EOL. ; char in A ; hit the player? CMP #$F0 ; hit the player. BEEP and RESTART BEQ KILLPLAYER CMP #$F1 ; hit the player. BEEP and RESTART BEQ KILLPLAYER ; did I hit a missile? ;AND #$F0 ;CMP #$F0 ; F = missile ;BEQ KILLPEDE ; must be a mushroom or end of line ; going up or down now? LDA #$00 ; ACC back to 0 SEC ; set carry LDX CURRENTPEDE ; X = currentpede UPORDOWN ROL ; ROL carry into A DEX ; loop on X BPL UPORDOWN AND REVERSEPEDES ; bit in position AND to check REVERSEPEDES BEQ DOWNPEDE UPPEDE LDA CURRENTPEDE CLC ROL TAX LDY PEDECOORDS,X ; DEC PEDE ROW DEY TYA STA PEDECOORDS,X ; otherwise, keep climbing up CMP #$13 ; what's the bounce point? #$14? BEQ UPPEDE2 JMP EVENORODDROW ; above #$14, head back down UPPEDE2 LDA #$00 SEC LDY CURRENTPEDE ; Y = currentpede BACKDOWNPEDE ROL ; ROL carry into A DEY ; loop on Y BPL BACKDOWNPEDE EOR REVERSEPEDES ; OR with REVERSEPEDES STA REVERSEPEDES ; store new REVERSEPEDES JMP EVENORODDROW ; continue as down. DOWNPEDE LDA CURRENTPEDE CLC ROL TAX LDY PEDECOORDS,X ; INC PEDE ROW INY TYA STA PEDECOORDS,X ; store in PEDE.ROW CMP #$18 ; if PLOTROW == #$18, done BNE JMPEVENODD ; spaghetti. ; == 18, bottom of screen ; bottom of the screen? now what? ; need to start back up the screen for a bit, then back down. Oof. LDA #$16 ; go back up a row STA PEDECOORDS,X LDA #$00 ; ACC back to 0 SEC ; set carry LDX CURRENTPEDE ; X = currentpede BACKPEDE ROL ; ROL carry into A DEX ; loop on X BPL BACKPEDE ORA REVERSEPEDES ; OR with REVERSEPEDES STA REVERSEPEDES ; store new REVERSEPEDES JMPEVENODD JMP EVENORODDROW ; X = (PEDE.ROW) ;/NEXTROW ; kill this segment KILLPEDE JSR COLLIDEMISSILE ;HITPEDE RTS KILLPLAYER ; hit by a pede segment, or moved into one. JSR BEEP LDA #$00 STA PLAYERROW RTS ************************************************** * subroutines ************************************************** DRAWSHROOMS ; blank screen routine, counts down random number between placing mushrooms LDA #$18 STA SHROOMCOUNT ; how many mushrooms to draw LDA #$16 ; start at bottom ROW STA CV ; PLOTROW JSR RND ; returns with 0-ff in A ROR ; 1/2 TAX ; random steps between mushrooms in X SHROOMROW DEC CV ; PLOTROW ; next row up BNE SHROOMROW2 ; not yet done, next row LDA SHROOMCOUNT ; row 0 AND shroomcount 0? All done. BEQ SHROOMSDONE ; LDA #$16 ; still not done, reset at row 23 STA CV ; PLOTROW SHROOMROW2 LDA #$28 ; start at column 40 STA CH ; PLOTCOLUMN SHROOMCOL DEC CH ; PLOTCOLUMN ; next column BEQ SHROOMROW ; column == 0? next row DEX ; otherwise, DEX and check if it's mushroom time BNE SHROOMCOL ; x=0? LDA #$D0 ; ? ; shroom char ; STA CHAR JSR PLOTQUICK ; draw mushroom Here DEC SHROOMCOUNT BEQ SHROOMSDONE ; done drawing 24 shrooms? ; no - do another NEXTSHROOM ;JSR RNDINIT JSR CLICK LDA #$80 JSR WAIT JSR RND ; returns with 0-ff in A TAX ; random steps between mushrooms in X JMP SHROOMCOL SHROOMSDONE RTS ;/DRAWSHROOMS ************************************************** DRAWLIVES LDX #$00 STX CV ; PLOTROW ; start at row 0, column 40 LDX #$25 STX CH ; PLOTCOLUMN LDA #$F0 ; player icon ; STA CHAR LDX PROGRESS ; for each PROGRESS, dec column DRAWLIVES2 JSR PLOTQUICK ; increments CH automatically. feh. DEX BNE DRAWLIVES2 ; repeat draw. RTS ;/DRAWLIVES UPDATESCORE ; takes A and adds it to PLAYERSCORE+3 SED ; decimal mode CLC ADC PLAYERSCORE+3 ; tens/ones STA PLAYERSCORE+3 BCC SCOREDONE ; carry set? add to next digit. LDA #$00 ADC PLAYERSCORE+2 ; 1000/100 STA PLAYERSCORE+2 BCC SCOREDONE ; carry set? add to next digit. LDA #$00 ADC PLAYERSCORE+1 ; 100.000/10.000 STA PLAYERSCORE+1 BCC SCOREDONE ; carry set? add to next digit. LDA #$00 ADC PLAYERSCORE ; 10.000.000/1.000.000 STA PLAYERSCORE SCOREDONE CLD ; prints score at col #$1D, row 0 LDA #$1D STA CH LDA #$00 STA CV VTAB LDA PLAYERSCORE JSR PRBYTE LDA PLAYERSCORE+1 JSR PRBYTE LDA PLAYERSCORE+2 JSR PRBYTE LDA PLAYERSCORE+3 JSR PRBYTE SETHISCORE ; compare bytes of PLAYERSCORE with HISCORE CLC LDA HISCORE ; +0 equal, check score+1 CMP PLAYERSCORE BCC NEWHISCORE ; PLAYERSCORE higher than HISCORE BNE KEEPHISCORE LDA HISCORE+1 ; +1 equal, check +2 CMP PLAYERSCORE+1 BCC NEWHISCORE ; PLAYERSCORE higher than HISCORE BNE KEEPHISCORE LDA HISCORE+2 ; +2 equal, check +3 CMP PLAYERSCORE+2 BCC NEWHISCORE ; PLAYERSCORE higher than HISCORE BNE KEEPHISCORE LDA HISCORE+3 CMP PLAYERSCORE+3 BCC NEWHISCORE ; PLAYERSCORE higher than HISCORE BNE KEEPHISCORE ; player lower, no new hiscore NEWHISCORE ; copy the PLAYERSCORE to HISCORE and display LDA PLAYERSCORE+3 STA HISCORE+3 LDA PLAYERSCORE+2 STA HISCORE+2 LDA PLAYERSCORE+1 STA HISCORE+1 LDA PLAYERSCORE STA HISCORE DISPLAYHISCORE ; prints score at col #$1D, row 0 LDA #$10 STA CH LDA #$00 STA CV VTAB LDA HISCORE JSR PRBYTE LDA HISCORE+1 JSR PRBYTE LDA HISCORE+2 JSR PRBYTE LDA HISCORE+3 JSR PRBYTE KEEPHISCORE RTS ************************************************** * blanks the screen ************************************************** FILLSCREENFAST ; 5,403 instructions LDA #$A0 ; space LDY #$78 FILL1 DEY STA $400, Y STA $480, Y STA $500, Y STA $580, Y STA $600, Y STA $680, Y STA $700, Y STA $780, Y BNE FILL1 RTS ************************************************** * prints one CHAR at PLOTROW,PLOTCOLUMN - clobbers A,Y * used for plotting background elements that don't need collision detection ************************************************** PLOTQUICK ; using COUT so I can maybe update to a HRCG later. ; TXA ; save X ; PHA VTAB ; LDA CHAR JMP COUT ; sends out through ENTRY ; PLA ; TAX ; restore X ; RTS ;/PLOTQUICK ERASEQUICK VTAB STY $01 JMP ZEROBYTES ;/ERASEQUICK ************************************************** * GETS one CHAR at PLOTROW,PLOTCOLUMN - value returns in Accumulator - clobbers Y ************************************************** GETCHAR LDY CV ; PLOTROW LDA LoLineTableL,Y STA $0 LDA LoLineTableH,Y STA $1 ; now word/pointer at $0+$1 points to line LDY CH ; PLOTCOLUMN LDA ($0),Y ; byte at row,col is now in accumulator RTS ;/GETCHAR VTAB MAC LDY CV ; sets the Vertical Row memory loc. for COUT LDA LoLineTableH,Y STA BASL+1 LDA LoLineTableL,Y STA BASL <<< ; End of Macro ************************************************** * CLICKS and BEEPS - clobbers X,Y,A ************************************************** CLICK LDX #$06 CLICKLOOP LDA #$10 ; SLIGHT DELAY JSR WAIT STA SPEAKER DEX BNE CLICKLOOP RTS ;/CLICK BEEP LDX #$30 BEEPLOOP LDA #$08 ; short DELAY JSR WAIT STA SPEAKER DEX BNE BEEPLOOP RTS ;/BEEP BONK LDX #$50 BONKLOOP LDA #$20 ; longer DELAY JSR WAIT STA SPEAKER DEX BNE BONKLOOP RTS ;/BONK ************************************************** * DATASOFT RND 6502 * BY JAMES GARON * 10/02/86 * Thanks to John Brooks for this. I modified it slightly. * * returns a randomish number in Accumulator. ************************************************** RNDINIT LDA $C030 ; #$AB STA RNDSEED LDA PLAYERSCORE+3 ; $4E ; #$55 STA RNDSEED+1 LDA $C060 ; #$7E STA RNDSEED+2 RTS * RESULT IN ACC RND LDA RNDSEED ROL RNDSEED EOR RNDSEED ROR RNDSEED INC RNDSEED+1 BNE RND10 LDA RNDSEED+2 INC RNDSEED+2 RND10 ADC RNDSEED+1 BVC RND20 INC RNDSEED+1 BNE RND20 LDA RNDSEED+2 INC RNDSEED+2 RND20 STA RNDSEED RTS RND16 JSR RND ; limits RND output to 0-F AND #$0F ; strips high nibble RTS ************************************************** * Data Tables * ************************************************** DS \ PEDECOORDS HEX 00,07,00,06,00,05,00,04,00,03,00,02,00,01,00,00 ; row/col byte pairs for each segment of the OCTOPEDE PLAYERMISSILE HEX FF,FF,E0 ; row, column, displaybyte PLAYERSCORE DS 4 ; DEC mode 0 - 99999999 HISCORE DS 4 ; DEC mode 0 - 99999999 ************************************************** * Lores/Text lines * Thanks to Dagen Brock for this. ************************************************** Lo01 equ $400 Lo02 equ $480 Lo03 equ $500 Lo04 equ $580 Lo05 equ $600 Lo06 equ $680 Lo07 equ $700 Lo08 equ $780 Lo09 equ $428 Lo10 equ $4a8 Lo11 equ $528 Lo12 equ $5a8 Lo13 equ $628 Lo14 equ $6a8 Lo15 equ $728 Lo16 equ $7a8 Lo17 equ $450 Lo18 equ $4d0 Lo19 equ $550 Lo20 equ $5d0 Lo21 equ $650 Lo22 equ $6d0 Lo23 equ $750 Lo24 equ $7d0 ; alt text page lines Alt01 equ $800 Alt02 equ $880 Alt03 equ $900 Alt04 equ $980 Alt05 equ $A00 Alt06 equ $A80 Alt07 equ $B00 Alt08 equ $B80 Alt09 equ $828 Alt10 equ $8a8 Alt11 equ $928 Alt12 equ $9a8 Alt13 equ $A28 Alt14 equ $Aa8 Alt15 equ $B28 Alt16 equ $Ba8 Alt17 equ $850 Alt18 equ $8d0 Alt19 equ $950 Alt20 equ $9d0 Alt21 equ $A50 Alt22 equ $Ad0 Alt23 equ $B50 Alt24 equ $Bd0 LoLineTable da Lo01,Lo02,Lo03,Lo04 da Lo05,Lo06,Lo07,Lo08 da Lo09,Lo10,Lo11,Lo12 da Lo13,Lo14,Lo15,Lo16 da Lo17,Lo18,Lo19,Lo20 da Lo21,Lo22,Lo23,Lo24 ; alt text page AltLineTable da Alt01,Alt02,Alt03,Alt04 da Alt05,Alt06,Alt07,Alt08 da Alt09,Alt10,Alt11,Alt12 da Alt13,Alt14,Alt15,Alt16 da Alt17,Alt18,Alt19,Alt20 da Alt21,Alt22,Alt23,Alt24 ** Here we split the table for an optimization ** We can directly get our line numbers now ** Without using ASL LoLineTableH db >Lo01,>Lo02,>Lo03 db >Lo04,>Lo05,>Lo06 db >Lo07,>Lo08,>Lo09 db >Lo10,>Lo11,>Lo12 db >Lo13,>Lo14,>Lo15 db >Lo16,>Lo17,>Lo18 db >Lo19,>Lo20,>Lo21 db >Lo22,>Lo23,>Lo24 LoLineTableL db Alt01,>Alt02,>Alt03 db >Alt04,>Alt05,>Alt06 db >Alt07,>Alt08,>Alt09 db >Alt10,>Alt11,>Alt12 db >Alt13,>Alt14,>Alt15 db >Alt16,>Alt17,>Alt18 db >Alt19,>Alt20,>Alt21 db >Alt22,>Alt23,>Alt24 AltLineTableL db ENTRY ; #> PRODUCES HIGH BYTE STA CSW+1 RTS ENTRY STY $01 ; stow Y for later CMP #$A0 ; CHAR = space? skip the math and zero the bytes BEQ ZEROBYTES EVEODDCOL STA $00 ;PHA ; STORE CHAR ;PHA ; SAVE Y, since it gets clobbered LDY #$00 STY TABLEPOS+1 ; tablepos hi byte LDA $00 CMP #$BA ; 0-9? BCC CLEARHI LDA CH ; horiz column AND #$01 ; even or odd? ROR ; odd bit into carry LDA $00 ; CHAR back ADC #$00 ; add carry to CHAR, odd ones = CHAR + 1 CLEARHI AND #$7F ; CLEAR HI BIT CALC1 SEC SBC #$20 ; CHAR < 96 ASL ;TABLEPOS ; *2 = CHAR < 192 ASL ;TABLEPOS ; *4 < 384 ROL TABLEPOS+1 ASL ;TABLEPOS ; *8 < 768 ROL TABLEPOS+1 STA TABLEPOS * * TABLEPOS = (ASCII - $20) * 8 BYTES PER CHAR * CLC LDA #CHARTABLE ; LOW BYTE ADC TABLEPOS STA TABLEPOS LDA #>CHARTABLE ; HIGH BYTE ADC TABLEPOS+1 STA TABLEPOS+1 ; TABLEPOS = TABLEPOS + CHARTABLE ADDR CALC2 CLC LDA BASL ; low byte of GR address ADC CH ; add horiz offset STA SCRN ; set HR low byte LDA BASL+1 ; get GR hi BYTE ADC #$1C ; bump into HR space STA SCRN+1 ; SCRN = BASL + CH + $1C00 GETBYTE LDY #$00 G1 LDA (TABLEPOS),Y ; first byte of character at TABLEPOS STA (SCRN),Y ; pop into HR screen INC INY ; next byte CLC LDA SCRN ; adjust for next HR address ADC #$FF STA SCRN LDA SCRN+1 ADC #$03 STA SCRN+1 ; SCRN=SCRN+$3FF * * $3FF TO MAKE UP FOR GROWING VALUE OF 'Y' * DONE? CPY #$08 BCC G1 YES LDA $00 ;PLA LDY $01 ;TAY ; RESTORE Y ;PLA ; RESTORE CHAR OUT JMP COUT3 ZEROBYTES CLC LDA BASL ; low byte of GR address ADC CH ; add horiz offset STA SCRN ; set HR low byte LDA BASL+1 ; get GR hi BYTE ADC #$1C ; bump into HR space STA SCRN+1 ; SCRN = BASL + CH + $1C00 LDY #$00 G2 LDA #$00 ; Zero out the pixels STA (SCRN),Y ; pop into HR screen INY ; next byte CLC LDA SCRN ; adjust for next HR address ADC #$FF STA SCRN LDA SCRN+1 ADC #$03 STA SCRN+1 ; SCRN=SCRN+$3FF CPY #$08 BCC G2 LDA #$A0 ;PLA LDY $01 ;TAY ; RESTORE Y JMP COUT3 COUT3 ; mine. doesn't increment CV on CH rollover LDY CH STA (BASL),Y INC CH RTS DS \ ; CHAR TABLE now aligned with page boundary, ; so each 8 bytes will stay on a single hi byte address CHARTABLE EQU * HEX 0000000000000000 ; SPACE A0 HEX 0000000000000000 ; BLANK A1 HEX 0000000000000000 ; ! HEX 0000000000000000 ; ! HEX 0000000000000000 ; ! HEX 0000000000000000 ; ! HEX 1414140000000000 ; " HEX 14143E143E141400 ; # HEX 083C0A1C281E0800 ; $ HEX 0626100804323000 ; % HEX 040A0A042A122C00 ; & HEX 0810202020100800 ; ) HEX 082A1C081C2A0800 ; * HEX 0008083E08080000 ; + HEX 0000000000000804 ; , HEX 0000003E00000000 ; - HEX 1C22322A26221C00 ; 0 B0 HEX 080C080808081C00 ; 1 HEX 1C22201804023E00 ; 2 HEX 3E20101820221C00 ; 3 HEX 101814123E101000 ; 4 HEX 3E021E2020221C00 ; 5 HEX 1804021E22221C00 ; 6 HEX 3E20100804040400 ; 7 HEX 1C22221C22221C00 ; 8 HEX 1C22223C20100C00 ; 9 B9 HEX 1008040204081000 ; < BA HEX 1008040204081000 ; < BB HEX 1008040204081000 ; < BC HEX 1008040204081000 ; < BD HEX D5D5FFFFFFFFD5D5 ; = progress bar BF HEX AAAAFFFFFFFFAAAA ; = progress bar BE HEX 00007E7F7F7E2A2A ; C0 PEDE <- C0 ; 0000 0000 ; 0000 0000 ; 0111 1110 ; 0111 1111 ; 0111 1111 ; 0111 1110 ; 0010 1010 ; 0010 1010 HEX 00007E7F7F7E5454 ; C0 PEDE <- C1 ; 0000 0000 ; 0000 0000 ; 0111 1110 ; 0111 1111 ; 0111 1111 ; 0111 1110 ; 0101 0100 ; 0101 0100 HEX 00003F7F7F3F2A2A ; C2 PEDE -> C2 ; 0000 0000 ; 0000 0000 ; 0011 1111 ; 0111 1111 ; 0111 1111 ; 0011 1111 ; 0010 1010 ; 0010 1010 HEX 00003F7F7F3F1515 ; C2 PEDE -> C3 ; 0000 0000 ; 0000 0000 ; 0011 1111 ; 0111 1111 ; 0111 1111 ; 0011 1111 ; 0001 0101 ; 0001 0101 HEX D0D0BFFFFFBF2828 ; C6 PEDE HEAD -> C4 ; 1101 0000 ; 1101 0000 ; 1011 1111 ; 1111 1111 ; 1111 1111 ; 1011 1111 ; 0010 1000 green ; 0010 1000 HEX A0A0BFFFFFBF5454 ; C6 PEDE HEAD -> C5 ; 1010 0000 ; 1010 0000 ; 1011 1111 ; 1111 1111 ; 1111 1111 ; 1011 1111 ; 0101 0100 green ; 0101 0100 HEX 8585FEFFFFFE2828 ; C4 PEDE HEAD <- C6 ; 1000 0101 ; 1000 0101 ; 1111 1110 ; 1111 1111 ; 1111 1111 ; 1111 1110 ; 0010 1000 green ; 0010 1000 HEX 8A8AFEFFFFFE5454 ; C4 PEDE HEAD <- C7 ; 1000 1010 ; 1000 1010 ; 1111 1110 ; 1111 1111 ; 1111 1111 ; 1111 1110 ; 0101 0100 green ; 0101 0100 HEX 0101247070541111 ; J C8 - SPIDER LEFT ; 0000 0001 ; 0000 0100 ; 0010 0100 ; 0111 0000 ; 0111 0000 ; 0101 0100 ; 0001 0001 ; 0001 0001 HEX 0208407070280202 ; K C9 - SPIDER LEFT ODD ; 0000 0010 ; 0000 1000 ; 0100 0000 green eyes ; 0111 0000 white body ; 0111 0000 ; 0010 1000 ; 0000 0010 ; 0000 0010 HEX 4010020707154141 ; H CA - SPIDER RIGHT ; 0100 0000 ; 0001 0000 ; 0000 0010 ; 0000 0111 ; 0000 0111 ; 0001 0101 ; 0100 0001 ; 0100 0001 HEX 20200907070A2222 ; I CB - SPIDER RIGHT ODD ; 0010 0000 ; 0000 1000 ; 0000 1001 ; 0000 0111 ; 0000 0111 ; 0000 1010 ; 0010 0010 ; 0010 0010 HEX 0202020202023E00 ; L HEX 22362A2A22222200 ; M HEX 2222262A32222200 ; N HEX 1C22222222221C00 ; O HEX BEAAAAAAFF181818 ; : mushroom high EVEN D0 ; 1011 1110 ; ORANGE top ; 1010 1010 ; 1010 1010 ; 1010 1010 ; 1111 1111 ; white line ; 0001 1000 ; white bottom ; 0001 1000 ; 0001 1000 HEX BED5D5D5FF181818 ; ; mushroom high ODD D1 ; 1011 1110 ; ORANGE top ; 1101 0101 ; 1101 0101 ; 1101 0101 ; 1111 1111 ; white line ; 0001 1000 ; white bottom ; 0001 1000 ; 0001 1000 HEX 1E22221E0A122200 ; R HEX 1C22021C20221C00 ; S HEX 3E08080808080800 ; T HEX 2222222222221C00 ; U HEX 2222222222140800 ; V HEX 2222222A2A362200 ; W HEX 2222140814222200 ; X HEX 2222221408080800 ; Y HEX 3E20100804023E00 ; Z HEX 3E06060606063E00 ; [ HEX 3E06060606063E00 ; [ HEX 3E06060606063E00 ; [ HEX 0002040810200000 ; \ HEX 0002040810200000 ; \ HEX 00000000FF181818 ; _ mushroom low E0 ; 0000 0000 ; 0000 0000 ; 0000 0000 ; 0000 0000 ; 1111 1111 ; 0001 1000 ; white bottom ; 0001 1000 ; 0001 1000 HEX 00000000FF181818 ; _ mushroom low E1 ; 0000 0000 ; 0000 0000 ; 0000 0000 ; 0000 0000 ; 1111 1111 ; 0001 1000 ; white bottom ; 0001 1000 ; 0001 1000 HEX 02021E2222221E00 ; b HEX 00003C0202023C00 ; c HEX 20203C2222223C00 ; d HEX 00001C223E023C00 ; e HEX 1824041E04040400 ; f HEX 00001C22223C201C ; g HEX 02021E2222222200 ; h HEX 08000C0808081C00 ; i HEX 100018101010120C ; j HEX 020222120E122200 ; k HEX 0C08080808081C00 ; l HEX 0000362A2A2A2200 ; m HEX 00001E2222222200 ; n HEX 00001C2222221C00 ; o HEX 949494B6B6BEFFFF ; ^ player F0 ; 1001 0100 ; 1001 0100 ; 1001 0100 ; 1011 0110 ; 1011 0110 ; 1011 1110 ; 1111 1111 ; 1111 1111 HEX 8A8A8A9B9B9FFFFF ; ^ player F1 ; 1000 1010 ; 1000 1010 ; 1000 1010 ; 1001 1011 ; 1001 1011 ; 1001 1111 ; 1111 1111 ; 1111 1111 HEX 00003A0602020200 ; r HEX 00003C021C201E00 ; s HEX 04041E0404241800 ; t HEX 0000222222322C00 ; u HEX 0000222222140800 ; v HEX 000022222A2A3600 ; w HEX 0000221408142200 ; x HEX 0000222214080806 ; y HEX 00003E1008043E00 ; z HEX 0000000018181800 ; . bullet low FB HEX 0000000018181800 ; . bullet low FC HEX 1818180000000000 ; ' bullet high FD HEX 1818180000000000 ; ' bullet high FE HEX 7F7F7F7F7F7F7F7F ; CURSOR