diff --git a/RAIN.dsk b/RAIN.dsk new file mode 100644 index 0000000..5936c30 Binary files /dev/null and b/RAIN.dsk differ diff --git a/RAIN.s b/RAIN.s new file mode 100644 index 0000000..80d79e1 --- /dev/null +++ b/RAIN.s @@ -0,0 +1,779 @@ + DSK RAIN + +************************************************** +* A simple simulation of random raindrops falling, +* hitting a puddle and splashing. Use K and I +* to increase/decrease the amount of falling rain. +************************************************** +* Variables +************************************************** + +ROW EQU $FA ; row/col in text screen +COLUMN EQU $FB +CHAR EQU $FC ; char/pixel to plot +PROGRESS EQU $FD ; write to main or alt +PLOTROW EQU $FE ; row/col in text page +PLOTCOLUMN EQU $FF +RNDSEED EQU $EA ; +eb +ec +UPPERLIMIT EQU $ED ; threshold for random raindrops + +************************************************** +* Apple Standard Memory Locations +************************************************** +CLRLORES EQU $F832 +LORES EQU $C050 +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 +CH EQU $24 ; cursor Horiz +CV EQU $25 ; cursor Vert +VTAB EQU $FC22 ; Sets the cursor vertical position (from CV) +COUT EQU $FDED ; Calls the output routine whose address is stored in CSW, + ; normally COUTI +STROUT EQU $DB3A ;Y=String ptr high, A=String ptr low + +ALTTEXT EQU $C055 +ALTTEXTOFF EQU $C054 + +ROMINIT EQU $FB2F +ROMSETKBD EQU $FE89 +ROMSETVID EQU $FE93 + +ALTCHAR EQU $C00F ; enables alternative character set - mousetext + +BLINK EQU $F3 +SPEED EQU $F1 + +************************************************** +* START - sets up various fiddly zero page bits +************************************************** + + ORG $2000 ; PROGRAM DATA STARTS AT $2000 + + JSR ROMSETVID ;Init char output hook at $36/$37 + JSR ROMSETKBD ;Init key input hook at $38/$39 + JSR ROMINIT ;GR/HGR off, Text page 1 + + LDA #$01 + STA SPEED ; string/char output speed + STA ALTCHAR ; enable mousetext + STA PROGRESS ; which page do we write to + LDA #$00 + STA BLINK ; blinking text? no thanks. + + STA LORES ; low res graphics mode + JSR CLRLORES ; clear screen + +DRAWBOARD JSR HOME + STA ALTTEXTOFF ; display main text page + JSR RNDINIT ; *should* cycle the random seed. + + INC PROGRESS + + LDA #$F7 + STA UPPERLIMIT + + + +************************************************** +* blanks the screen, sets the "puddle" to dk blue +************************************************** +; FOR EACH ROW/COLUMN + + LDA #$18 ; X = 24 + STA PLOTROW +ROWLOOP2 ; (ROW 20 to 0) + DEC PLOTROW + + ; start columnloop (COLUMN 0 to 40) + LDA #$28 + STA PLOTCOLUMN +COLUMNLOOP2 DEC PLOTCOLUMN + + LDA PLOTROW ; last 4 lines, #$22 + CMP #$14 ; > 20 + BCC PLOTZERO + LDA #$22 ; last 4 lines, #$22 + JMP PLOTLINE +PLOTZERO LDA #$0 ; set all pixels to 00 +PLOTLINE STA CHAR + JSR PLOTCHAR ; plot 00 + INC PROGRESS + JSR PLOTCHAR ; plot 00 to alt + INC PROGRESS + + LDA PLOTCOLUMN ; last COLUMN? + BNE COLUMNLOOP2 ; loop + +; /columnloop2 + + LDA PLOTROW ; last ROW? + BNE ROWLOOP2 ; loop + +; /rowloop2 + +; draw raindrop + +; DK blue = 2 +; MD blue = 6 +; LT blue = 7 +; white = F +; black = 0 +; grey = 5 + +; drop: +; == F7 76 02 +; fast drop: +; == 27 60 20 + +; F7 -> 76 -> 02 +; 27 -> 60 -> 20 + +************************************************** +* MAIN LOOP +* waits for keyboard input, moves cursor, etc +************************************************** + +MAIN +MAINLOOP LDA KEY ; check for keydown +; CMP #$A0 ; space bar pause? +; BEQ GOTSPACE + CMP #$D2 ; R + BEQ GOTRESET + + CMP #$9B ; ESC + BEQ END ; exit on ESC? + + + + CMP #$C9 ; I + BEQ GOTUP + CMP #$CB ; K + BEQ GOTDOWN +; CMP #$CA ; J shift the falling drops left/right to +; BEQ GOTLEFT ; simulate wind? +; CMP #$CC ; L +; BEQ GOTRIGHT + + JSR NEXTSCREEN ; animate one frame per loop + + BNE MAINLOOP ; loop until a key + + +GOTUP STA STROBE + DEC UPPERLIMIT + JMP MAINLOOP ; back to waiting for a key +GOTDOWN STA STROBE + INC UPPERLIMIT + JMP MAINLOOP ; back to waiting for a key +;GOTLEFT STA STROBE +; STA ALTTEXTOFF +; JMP MAINLOOP ; back to waiting for a key +; +;GOTRIGHT STA STROBE +; STA ALTTEXT +; JMP MAINLOOP ; back to waiting for a key +; +;GOTSPACE JSR SPACE +; JMP MAINLOOP ; back to waiting for a key + +GOTRESET STA STROBE + STA ALTTEXTOFF + JMP DRAWBOARD + +END STA STROBE + STA ALTTEXTOFF + STA TXTSET + JSR HOME + RTS ; END + +;SPACE STA STROBE ; +; JSR NEXTSCREEN ; animate +; RTS + +;/GOTSPACE + + + +************************************************** +* subroutines +* +************************************************** + +************************************************** +* main animation loop - checks each pixel for non-zero values +************************************************** + +NEXTSCREEN ; FOR EACH ROW/COLUMN + + LDA #$14 ; X = 20 + STA PLOTROW +ROWLOOP ; (ROW 20 to 0) + DEC PLOTROW + + ; start columnloop (COLUMN 0 to 40) + LDA #$28 + STA PLOTCOLUMN +COLUMNLOOP DEC PLOTCOLUMN + + JSR GETCHAR + BEQ ZEROFOUND + + JSR EXPAND ; do the thing + + +ZEROFOUND LDA PLOTCOLUMN ; last COLUMN? + BNE COLUMNLOOP ; loop +;/columnloop + + LDA PLOTROW ; last ROW? + BEQ ROWONE ; top of the screen, do some random raindrops + BNE ROWLOOP ; loop + +;/rowloop +ROWONE ; row == 0, if RND > upperlimit, draw start of a new drop + LDA #$28 + STA PLOTCOLUMN +COLUMNLOOP3 DEC PLOTCOLUMN ; next column + + +DODROPS JSR RND ; grab a random number + CMP UPPERLIMIT ; drop threshold + BCC NODROP ; less than limit, no drop + LDA PLOTCOLUMN + ROR ; on an odd/even column + BCS LGDROP ; small/fast drops on even, large slow on odd +SMALLDROP LDA #$27 + JMP STOREDROP +LGDROP LDA #$F7 ; draw a drop +STOREDROP STA CHAR + INC PROGRESS + JSR PLOTCHAR + INC PROGRESS + JMP NODROP + + JSR GETCHAR + BEQ NODROP + JSR EXPAND ; found a non-zero pixel, process it + +NODROP LDA PLOTCOLUMN ; last COLUMN? + BNE COLUMNLOOP3 ; loop on each column for top row +;/columnloop2 + + + + + INC PROGRESS ; every other refresh, show alt page, normal page + ROR PROGRESS ; lowest bit into carry + BCC ALTSCREEN ; carry set on odd, not on even + STA ALTTEXTOFF + JMP NORMSCREEN +ALTSCREEN STA ALTTEXT + +NORMSCREEN ROL PROGRESS + + RTS +;/NEXTSCREEN + + + + +************************************************** +* process raindrop animations. +************************************************** + +DOSPLASH JSR SPLASH ; made it to the bottom of the screen + RTS ; show the splash animation + +EXPAND + ; found CHAR in A +; drop: +; == F7 76 02 +; 27 -> 60 -> 20 +; bottom up + CMP #$F7 ; if it's F7, plot 76, inc row, plot F7, + BNE SMDROP0 ; not F7, skip + INC PROGRESS + STA CHAR ; puts found character (F7) into CHAR + INC PLOTROW ; down 1 + LDA PLOTROW + CMP #$15 ; lower than row 20? + JSR PLOTCHAR ; plot F7 +DROP1 DEC PLOTROW ; back up + LDA #$76 + STA CHAR + JSR PLOTCHAR ; plot 76 + INC PROGRESS + + LDA PLOTROW + CMP #$13 ; lower than row 20? + BEQ DOSPLASH + + JMP DROPDONE + +SMDROP0 CMP #$27 + BNE DROP2 + INC PROGRESS + STA CHAR ; puts found character (27) into CHAR + INC PLOTROW ; down 1 + INC PLOTROW ; down 1 + LDA PLOTROW + CMP #$14 ; lower than row 20? + BCS SMDROP1 ; if > 20 skip over + JSR PLOTCHAR ; plot 27 down 2 px +SMDROP1 DEC PLOTROW ; back up + DEC PLOTROW ; back up + LDA #$20 ; plot 20 down 0 px + STA CHAR + JSR PLOTCHAR ; plot 20 + INC PROGRESS + JMP DROPDONE + +DROP2 CMP #$76 ; if it's 76, plot 02 + BNE SMDROP2 ; not 76, skip + INC PROGRESS + LDA #$02 + STA CHAR + JSR PLOTCHAR + INC PROGRESS + + LDA PLOTROW ; if we're at row 20ish + CMP #$13 ; should have triggered the splash + BEQ UNDOSPLASH ; undo the first splash frame + + JMP DROPDONE + +UNDOSPLASH JSR UNSPLASH + RTS + + +SMDROP2 CMP #$60 ; if it's 60, plot 60 down 2 px + BNE DROP3 ; not 60, skip + INC PLOTROW ; down 1 + INC PLOTROW ; down 1 + INC PROGRESS + STA CHAR + JSR PLOTCHAR + INC PROGRESS + DEC PLOTROW + DEC PLOTROW + LDA #$0 ; erase behind + JSR PLOTCHAR + JMP DROPDONE + +DROP3 CMP #$02 ; if it's 02, erase behind it + BNE SMDROP3 + LDA #$0 + STA CHAR + JSR PLOTCHAR + INC PROGRESS + JSR PLOTCHAR + INC PROGRESS + + LDA PLOTROW ; if we're at row 20ish + CMP #$13 ; should have triggered the splash + BEQ UNDOSPLASH ; undo the second splash frame + + + JMP DROPDONE + +SMDROP3 CMP #$20 ; if it's 20, erase behind it + BNE DROPDONE + LDA #$0 + STA CHAR + JSR PLOTCHAR + INC PROGRESS + JSR PLOTCHAR + INC PROGRESS + + +DROPDONE RTS + + +************************************************** +* prints one CHAR at PLOTROW,PLOTCOLUMN - clobbers A,Y +************************************************** +PLOTCHAR + LDY PLOTROW + TYA + CMP #$18 + BCS OUTOFBOUNDS ; stop plotting if dimensions are outside screen + + + ;LDA PROGRESS ; even or odd frame + ROR PROGRESS + BCC PLOTCHARALT ; every other frame, write to alt text page + + LDA LoLineTableL,Y + STA $0 + LDA LoLineTableH,Y + STA $1 ; now word/pointer at $0+$1 points to line + JMP LOADCHAR + +PLOTCHARALT LDA AltLineTableL,Y + STA $0 + LDA AltLineTableH,Y + STA $1 ; now word/pointer at $0+$1 points to line + +LOADCHAR ROL PROGRESS ; return progress state for next ROR + + LDY PLOTCOLUMN + TYA + CMP #$28 + BCS OUTOFBOUNDS ; stop plotting if dimensions are outside screen + + LDA CHAR ; this would be a byte with two pixels + STA ($0),Y + + +OUTOFBOUNDS RTS +;/PLOTCHAR + + +************************************************** +* GETS one CHAR at PLOTROW,PLOTCOLUMN - value returns in Accumulator +************************************************** +GETCHAR + + LDY PLOTROW + ROR PROGRESS + BCC GETCHARALT ; every other frame, write to alt text page + + LDA LoLineTableL,Y + STA $0 + LDA LoLineTableH,Y + JMP STORECHAR + +GETCHARALT LDA AltLineTableL,Y + STA $0 + LDA AltLineTableH,Y + +STORECHAR STA $1 ; now word/pointer at $0+$1 points to line + LDY PLOTCOLUMN + ROL PROGRESS ; return progress state for next ROR + LDA ($0),Y ; byte at row,col is now in accumulator + RTS +;/GETCHAR + + + + + + +************************************************** +* CLICKS and BEEPS +************************************************** +CLICK LDX #$06 +CLICKLOOP LDA #$10 ; SLIGHT DELAY + JSR WAIT + LDA SPEAKER + DEX + BNE CLICKLOOP + RTS +;/CLICK + +BEEP LDX #$30 +BEEPLOOP LDA #$08 ; short DELAY + JSR WAIT + LDA SPEAKER + DEX + BNE BEEPLOOP + RTS +;/BEEP + + +BONK LDX #$50 +BONKLOOP LDA #$20 ; longer DELAY + JSR WAIT + LDA 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. +************************************************** + + +RNDINIT + LDA $C030 ; #$AB + STA RNDSEED + LDA $4E ; #$55 + STA RNDSEED+1 + LDA PROGRESS ; #$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 + + + + +************************************************** +* Draws the two frames of the splash animation when +* a drop reaches the bottom of the screen +************************************************** + +; TO DO: if progress is odd, splash further down? + +SPLASH LDA PLOTROW + STA ROW + LDA PLOTCOLUMN + STA COLUMN + + INC PLOTROW + +;DROPDOWN ROL PROGRESS + INC PROGRESS ; draw on next frame +DECCOL DEC PLOTCOLUMN ; decrement 3 columns + DEC PLOTCOLUMN ; decrement 3 columns + DEC PLOTCOLUMN ; decrement 3 columns + LDX #$06 ; for 6 to 0 in Y +SPLASHTOP LDA SPLASH1,X ; load SPLASH1,Y + STA CHAR ; store CHAR + JSR PLOTCHAR + INC PLOTCOLUMN ; INC PLOTCOLUMN + DEX ; next Y + BPL SPLASHTOP ; x!=0, return + + INC PLOTROW ; INC ROW + LDX #$06 ; for 6 to 0 in Y +SPLASHBOTTOM LDA SPLASH2,X ; load SPLASH2,Y + STA CHAR ; store CHAR + DEC PLOTCOLUMN ; DEC PLOTCOLUMN + JSR PLOTCHAR + DEX + BPL SPLASHBOTTOM ; next Y + + DEC PLOTROW + INC PROGRESS ; draw on current frame + +SPLASHF2 LDX #$06 ; for 6 to 0 in Y +SPLASHTOPF2 LDA SPLASH3,X ; load SPLASH1,Y + STA CHAR ; store CHAR + JSR PLOTCHAR + INC PLOTCOLUMN ; INC PLOTCOLUMN + DEX ; next Y + BPL SPLASHTOPF2 ; x!=0, return + + INC PLOTROW ; INC ROW + LDX #$06 ; for 6 to 0 in Y +SPLASHBOTTOMF2 LDA SPLASH4,X ; load SPLASH2,Y + STA CHAR ; store CHAR + DEC PLOTCOLUMN ; DEC PLOTCOLUMN + JSR PLOTCHAR + DEX + BPL SPLASHBOTTOMF2 ; next Y + + + LDA ROW ; reset to row/column for next pass + STA PLOTROW + LDA COLUMN + STA PLOTCOLUMN + + RTS + + + +UNSPLASH LDA PLOTROW + STA ROW + LDA PLOTCOLUMN + STA COLUMN + + INC PLOTROW + +;DROPDOWN2 ROL PROGRESS + INC PROGRESS + +; JSR CLICK +DECCOL2 DEC PLOTCOLUMN ; decrement 3 columns + DEC PLOTCOLUMN ; decrement 3 columns + DEC PLOTCOLUMN ; decrement 3 columns + LDX #$06 ; for 6 to 0 in Y +UNDOSPLASHTOP LDA #$22 ; load SPLASH1,Y + STA CHAR ; store CHAR + JSR PLOTCHAR + INC PLOTCOLUMN ; INC PLOTCOLUMN + DEX ; next Y + BPL UNDOSPLASHTOP ; x!=0, return + INC PLOTROW ; INC ROW + LDX #$06 ; for 6 to 0 in Y + INC PROGRESS +UNDOSPLASHBOTTOM + LDA #$22 ; load SPLASH2,Y + STA CHAR ; store CHAR + DEC PLOTCOLUMN ; DEC PLOTCOLUMN + JSR PLOTCHAR + DEX + BPL UNDOSPLASHBOTTOM ; next Y + + LDA ROW ; reset to row/column for next pass + STA PLOTROW + LDA COLUMN + STA PLOTCOLUMN + + RTS + + + + +************************************************** +* Data Tables +* +************************************************** + +SPLASH1 HEX 62,22,72,F2,72,22,62 +SPLASH2 HEX 26,62,67,67,67,62,26 + +SPLASH3 HEX 22,72,22,22,22,72,22 +SPLASH4 HEX 22,22,26,26,26,22,22 + +************************************************** +* 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 +* the "plus four" lines +Lo21 equ $650 +Lo22 equ $6d0 +Lo23 equ $750 +Lo24 equ $7d0 + + +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 +* the "plus four" lines +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 + +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