.TITLE V .IDENT /02.02/ .MCALL EXIT$S,DSAR$S,ASTX$S .MCALL QIO$,MRKT$,WTSE$,DIR$,WTLO$,SETF$,GLUN$ .NLIST BEX ; ; DEVELOPED OFF-HOURS AT CHEVRON RESEARCH COMPANY, RICHMOND, CA 94802 ; ; STRICTLY FREE FUN: NOT FOR COMMERCIAL OR MONETARY USE ; ; VERSION 02.02 ; ; J L FROST 23-MAY-77 ; ; V, VIDEO TERMINAL PONG (VT52,VT55) ; ; EQUATED SYMBOLS ; .SBTTL LOCAL DATA ; ; LOCAL DATA ; ; $ DPB'S ; ; EVENT FLAG USAGE ; 01 = POST-SCORE MARKTIME WAIT ; 02 = BALL MARKTIME WAIT ; 03 = BEEP SPACING MARKTIME WAIT ; 04 = KILL QIO WAIT ; 05 = GENERALIZED WRITE QIO WAIT ; 06 = BALL JUMP QIO SAFETY WAIT ; 07 = INTRO TERMINATION QIO WAIT ; 08 = INTRO TERMINATION MARKTIME WAIT ; ; LUN USAGE ; 05 = VT (INTRO QIO RD; PLAY UNSOL CHR AST RD; WRITE) ; 06 = BEEP (VT OR LA, WRITE ONLY) ; INTQIO: QIO$ IO.RAL!TF.RNE,5,7,,,, ;RD 1 CHR AFTER INTRO, ; NO ECHO INTRMR: MRKT$ 8.,5,3 ;5-MINUTE WAIT INTRWT: WTLO$ 0,300 ;WT EITHER 7 OR 8 AFTER INTRO VTW: QIO$ IO.WAL,5,5,,,, ;GEN'L MAIN LOOP OUTPUT VTWT: WTSE$ 5 SCORMR: MRKT$ 1,5,2 ;POST-SCORE MARKTIME SCORWT: WTSE$ 1 ;POST-SCORE WAIT PADQIO: QIO$ IO.WAL,5,,,,, ;WRT NEW PAD, REPL OLD BALLMR: MRKT$ 2,5,1 ;BALL MARKTIME BALLMW: WTSE$ 2 ;BALL MARKTIME WAIT SETEFB: SETF$ 6 ;SAME AS BALLJP COMPLETION BALLWT: WTSE$ 6 ;BE SURE BALL MOVE DONE BALLJP: QIO$ IO.WAL,5,6,,,, ;MAKE BALL JUMP BEEPO: QIO$ IO.WAL,6,,,,, ;OUTPUT A BEEP BEEPWT: WTSE$ 3 ;BEEP WAIT BEEPMR: MRKT$ 3,17,1 ;BEEP MARKTIME ERASE: QIO$ IO.WAL,5,4,,,, ;CR,LF,LF ;(FOR CLEAN HARDCOPY AFTER ; RULES, THEN HOME & ERASE EOS) GETLU6: GLUN$ 6,LUNBUF ;GET UNIT # LUN 6 ATT5: QIO$ IO.ATA,5,,,,, ;ATT W UNSOL INP CHR AST DET5: QIO$ IO.DET,5 ;DETACH KIL5: QIO$ IO.KIL,5,4 ;CANCEL KILWT: WTSE$ 4 ;KILL AND CANCEL WAIT ; ; ADJUSTMENTS TO $ DPB'S ; SPEED = BALLMR+M.KTMG ;BALL MARKTIME ADJ. ; ; BUFFERS FOR QIO'S (& REQUIRED ADJACENT ITEMS) ; BUF: .BLKB 72. ;GEN'L BUF MAIN LOOP OUTPUTS INBUF: .BLKW 1 ;SINGLE INPUT CHR. BEEPC: .BYTE 7,7,7,7 ;BEEP CHARS LUNBUF: .BLKW 6 ;GET LUN INFO BFR (WANT UNIT #) ; ; PADDLE DATABASE ; (SEE ALSO YSOFLT & YSOFLB IN BALL DATABASE) ; PADLOK: .WORD 1 ;IF NZ, MAKES PAD AST IGNORE CHR ; DURING SCORE & DCOURT WRITES ; ; NOTE CONVENTION: HALFSIZE PADDLE ADR IS Y, FULL IS (Y,Y+1) ; PADHAF: .WORD 0 ;FLG NZ IF HALFSIZE PADDLES PADSZC: .WORD 0 ;FLG NZ IF PADDLE SIZE BEING CHANGED BOTH: .WORD 0 ;FLG NZ IF BOTH HALVES FULL PADDLE ; HAVE BEEN WORKED ON SCORNW: .WORD 0 ;FLG NZ WHEN SCORING NOW QUIT: .WORD 0 ;FLG NZ IF EITHER PLAYER QUITS EARLY AUTLR: .WORD 0 ;# SUCCESSIVE SERVES L & R BOTH AUTO AUTLRM: .WORD 20. ;MAX LIMIT FOR AUTLR (PREVENT INF LOOP) PADZI: .WORD 40. ;INIT PENALTY CREDIT BACKCOURT MOTION ; ; KB RECOG. BYTE TABLE (FIRST BYTE OF WD) ; (NOTE BITS 5 & 7 EA CHR ARE 0 (UPPER CASE, NO PARITY) ; BYTBL: .WORD 'Q,'A,'W,'S ;LEFT KEYS UPS, DNS, UPL, DNL BYTBLA: .WORD 'T ; AUT BYTBR: .WORD 26,23,25,22 ; RT KEYS UPS, DNS, UPL, DNL BYTBRA: .WORD 'P ; AUT .WORD 'E,'R,'N ;QUIT, RAPID, NORMAL .WORD 'H,'F,'I ;HALF PADDLE, FULL PADDLE, INTRO RELIST .WORD 'O ;ODT BKPT BYTBS: .WORD 0 ;STOPPER ; ; KB RECOG. ADDR TBL CORRESP. BYTBL ; ADTBL: .WORD LUS,LDS,LUL,LDL ;LEFT PAD UPS, DNS, UPL, DNL .WORD LPA ; AUT .WORD RUS,RDS,RUL,RDL ;RT PAD UPS, DNS, UPL, DNL .WORD RPA ; AUT .WORD QIT,RAPID,NORMAL ;QUIT, RAPID, NORMAL .WORD HAFPAD,FULPAD,INTRE ;HALF PAD, FULL PAD, INTRO RELIST .WORD ODT ;ODT BKPT HOOK .WORD PADDON ;IGNORE UNRECOGNIZED CHR ; ; PADDLE LEFT: ; PADLZ: .WORD 40. ;INIT PENLTY CREDIT BACKCOURT MOTION PADLY: .WORD 12. ;Y ; PBUFLB: .BYTE 33,131,40,40 ;UL CORNER CURS ADR PBUFL: .REPT 11. .BYTE 40,10,12 ;SP,BS,LF .ENDR .BYTE 141,10,12,141,10,12 ;PAD,BS,LF TWICE (FULL PAD DEFAULT) .REPT 10. .BYTE 40,10,12 ;SP,BS,LF .ENDR .BYTE 40,0 ;LAST SP, NULL ; PADLC: .BYTE 0 ;LAST CMD (FOR AUT TEST) .EVEN ; ; LEFT PADDLE WALL (AUT MODE) ; PBUFLA: .BYTE 33,131,40,40 ;UL CRNR CURS ADR .REPT 23. .BYTE 141,10,12 ;SOLID RECT.,BS,LF .ENDR .BYTE 141,0 ;LAST SOLID RECT., NULL .EVEN ; ; PADDLE RIGHT: ; PADRZ: .WORD 40. ;INIT PENLTY CREDIT BACKCOURT MOTION PADRY: .WORD 12. ;Y ; PBUFRB: .BYTE 33,131,40,147 ;UR CORNER CURS ADR PBUFR: .REPT 11. .BYTE 40,10,12 ;SP,BS,LF .ENDR .BYTE 141,10,12,141,10,12 ;PAD,BS,LF TWICE (FULL PAD DEFAULT) .REPT 10. .BYTE 40,10,12 ;SP,BS,LF .ENDR .BYTE 40,0 ;LAST SP., NUL ; PADRC: .BYTE 0 ;LAST CMD (FOR AUT TEST) .EVEN ; ; RT PADDLE WALL (AUT MODE) ; PBUFRA: .BYTE 33,131,40,147 ;UR CRNR CURS ADR .REPT 23. .BYTE 141,10,12 ;SOLID RECT.,BS,LF .ENDR .BYTE 141,0 ;LAST SOLID RECT., NULL .EVEN ; ; PSAD: .WORD 1 ;PAD SML AMT DOWN PSAU: .WORD -1 ;PAD SML AMT UP PLAD: .WORD 4 ;PAD LGE AMT DOWN PLAU: .WORD -4 ;PAD LGE AMT UP ; ; BALL DATABASE ; X: .WORD 36. ;HORIZ: L TO R Y: .WORD 12. ;VERT: T TO B T: .WORD 1 ;TOP YVAL B: .WORD 24. ;BOT YVAL MIDY: .WORD 12. ;MID YVAL L: .WORD 1 ;LEFT XVAL R: .WORD 71. ;RIGHT XVAL MIDX: .WORD 36. ;MID XVAL SLOW: .WORD 5 ;MAX TICKS BALL MARKTIME (SLOW) FAST: .WORD 3 ;MAX TICKS BALL MARKTIME (FAST) SPEEDS: .WORD 6 ;MAX TICKS BALL MARKTIME (SERVE) SPEEDI: .WORD 5 ;INIT SPEED AFTER SERVE ; ('SLOW' OR 'FAST') SPDCNI: .WORD 2 ;MAX HITS BEFORE SPEEDUP SPDCNT: .WORD 2 ;RNG HITS BEFORE SPEEDUP XINCR: .WORD 1 ;X-INCR EA BALL JMP (CHR SPCE) YINCR: .WORD 1 ;Y-INCR EA BALL JMP (BAR AMNT) YINCRL: .WORD 6 ;Y-INCR LIMIT (MULT RICOCHET AVOID.) YFINE: .WORD 0 ;BAR POSN IN NEXT BALL CHR YFINEL: .WORD 10. ;# BARS MAX BEFORE NEXT CHR NECESSARY ; ; "SOFT PADDLE" YFINE LIMITS TOP & BOT (Y=BALL Y): ; YSOFLT: .WORD 9. ;IF PADY=Y+1 & YFINE .GE.YSOFLT, HIT YSOFLB: .WORD 2 ;IF PADY=Y-1 & YFINE .LE.YSOFLB, HIT ; NOBEWA: .WORD 0 ;FLG, NO BEEP WAIT IF NZ (LA36) ; ; BYTE STR TO MOVE BALL: ; BALMOV: .BYTE 33,131 ;ADR CURS BALMOR: .BYTE 40 ;ROW BALMOC: .BYTE 40 ;COL BALMOL: .BYTE 154 ;BALL (BAR) ; ; BALL CHRS (FIRST BLK UNUSED, LAST BLKS = INVIS. BALL) ; BALCHR: .BYTE 40,154,155,156,157,160,161,162,163,40,40 .EVEN ; ; COURT & SCORE DATABASE ; LS: .WORD 0 ;LEFT SCORE RS: .WORD 0 ;RIGHT SCORE INTREL: .WORD 0 ;FLG NZ IF INTRO RELIST BEFORE NEXT SRV ; ; SCORE DIGIT ADDRESS TABLE ; SCORAD: .WORD DIGN,DIG0,DIGN,DIG1,DIGN,DIG2 .WORD DIGN,DIG3,DIGN,DIG4,DIGN,DIG5 .WORD DIGN,DIG6,DIGN,DIG7,DIGN,DIG8 .WORD DIGN,DIG9,DIG1,DIG0,DIG1,DIG1 .WORD DIG1,DIG2,DIG1,DIG3,DIG1,DIG4 .WORD DIG1,DIG5 ; ; COURT & BLOCK DIGITS STRINGS ; ; DRAW COURT ; DCOURT: .BYTE 33,110,33,112,33,106 .REPT 71. .BYTE 163 ;LOWER BAR FOR TOP ROW .ENDR .BYTE 33,131,44,103,141,33,131,51,103,141 .BYTE 33,131,56,103,141,33,131,63,103,141 .BYTE 33,131,67,40 .REPT 71. .BYTE 154 ;UPPER BAR FOR BOT ROW .ENDR .BYTE 0 ; ; SCORE ROW & COL ; SCORRC: .BYTE 33,131,46,54,0 ; ; SCORE SPACE OVER TO RT HALF COURT: ; SCORSP: .REPT 21. .BYTE 40 .ENDR .BYTE 0 ; ; BLOCK DIGITS 5 X 7 ; DIGN: .REPT 7 ;NULL DIGIT .BYTE 40,40,40,40,40,10,10,10,10,10,12 .ENDR .REPT 7 .BYTE 33,101 .ENDR .BYTE 40,40,40,40,40,40,0 ; DIG0: .BYTE 141,141,141,141,141,10 ;ZERO DIGIT .REPT 6 .BYTE 12,141,10 .ENDR .REPT 4 .BYTE 10,141,10 .ENDR .REPT 5 .BYTE 33,101,141,10 .ENDR .BYTE 33,101 .REPT 6 .BYTE 33,103 .ENDR .BYTE 0 ; DIG1: .BYTE 40,40 ;ONE .REPT 7 .BYTE 141,12,10 .ENDR .REPT 7 .BYTE 33,101 .ENDR .REPT 4 .BYTE 33,103 .ENDR .BYTE 0 ; DIG2: .BYTE 141,141,141,141,141,10 ;TWO .REPT 3 .BYTE 12,141,10 .ENDR .REPT 4 .BYTE 10,141,10 .ENDR .REPT 3 .BYTE 12,141,10 .ENDR .BYTE 33,103,141,141,141,141,40 .REPT 6 .BYTE 33,101 .ENDR .BYTE 0 ; DIG3: .BYTE 141,141,141,141,141,10 ;THREE .REPT 6 .BYTE 12,141,10 .ENDR .BYTE 10,10,10,10,141,141,141,141 .REPT 3 .BYTE 33,101,10 .ENDR .BYTE 10,141,141,141,141 .REPT 3 .BYTE 33,101,33,103 .ENDR .BYTE 0 ; DIG4: .REPT 3 ;FOUR .BYTE 141,12,10 .ENDR .BYTE 141,141,141,141,12,12,12,12 .REPT 7 .BYTE 33,101,141,10 .ENDR .BYTE 33,103,40,0 ; DIG5: .BYTE 141,141,141,141,141,10,10,10,10,10 ;FIVE .REPT 3 .BYTE 12,141,10 .ENDR .BYTE 141,141,141,141 .REPT 4 .BYTE 141,12,10 .ENDR .BYTE 33,101,10,10,10,10,141,141,141,141 .REPT 6 .BYTE 33,101 .ENDR .BYTE 141,40,0 ; DIG6: .REPT 6 ;SIX .BYTE 141,12,10 .ENDR .BYTE 141,141,141,141,141 .REPT 3 .BYTE 10,33,101,141 .ENDR .BYTE 10,10,10,10,141,141,141,141,40 .REPT 3 .BYTE 33,101 .ENDR .BYTE 0 ; DIG7: .BYTE 141,141,141,141,141 ;SEVEN .REPT 6 .BYTE 10,12,141 .ENDR .REPT 6 .BYTE 33,101 .ENDR .BYTE 40,0 ; DIG8: .BYTE 141,141,141,141,141,10 ;EIGHT .REPT 6 .BYTE 12,141,10 .ENDR .REPT 4 .BYTE 10,141,10 .ENDR .REPT 5 .BYTE 33,101,141,10 .ENDR .BYTE 12,12,141,141,141,141,141 .REPT 3 .BYTE 33,101 .ENDR .BYTE 40,0 ; DIG9: .BYTE 141,141,141,141,141,10,10,10,10,10 ;NINE .REPT 3 .BYTE 12,141,10 .ENDR .BYTE 141,141,141,141,141 .BYTE 33,101,33,101 .REPT 6 .BYTE 141,12,10 .ENDR .REPT 7 .BYTE 33,101 .ENDR .BYTE 141,40,0 ; ECOURT: .BYTE 15,12,12,33,110,33,112 ;ERASE COURT: ; CR,LF,LF,HOME, ERASE EOS ; INTRODUCTORY TEXT: ; .ENABL LC INTRO: .BYTE 33,110,33,112,33,107,33,76,11 .ASCII /Welcome to Video Terminal Pong. / .ASCII /Here's how it works:/ .BYTE 15,12,12,12 .ASCII /LEFT Player keys:/ .BYTE 15,12,11 .ASCII /Q = Paddle up slowly / .BYTE 11,11,11 .ASCII /W = Paddle up quickly/ .BYTE 15,12,11 .ASCII /A = Paddle down slowly / .BYTE 11,11,11 .ASCII /S = Paddle down quickly/ .BYTE 15,12,12,11 .ASCII /T = cop out (replace paddle with wall until next / .ASCII /move command)/ .BYTE 15,12,12,12 .ASCII /RIGHT Player keys:/ .BYTE 15,12,11 .ASCII /6 = Paddle up slowly / .BYTE 11,11,11 .ASCII /5 = Paddle up quickly/ .BYTE 15,12,11 .ASCII /3 = Paddle down slowly / .BYTE 11,11,11 .ASCII /2 = Paddle down quickly/ .BYTE 15,12,12,11 .ASCII /P = cop out (replace paddle with wall until next move / .ASCII /command)/ .BYTE 15,12,12,12 .ASCII /EITHER Player keys:/ .BYTE 15,12,12,11 .ASCII /R = Rapid ball, N = NORMAL/ .BYTE 11,11 .ASCII /TOO MANY/ .BYTE 15,12,11 .ASCII /H = Half paddle, F = FULL/ .BYTE 11,11 .ASCII /BACK COURT MOVES/ .BYTE 15,12,11 .ASCII /I = Intro re-list/ .BYTE 11,11,11 .ASCII /AND YOU'RE/ .BYTE 15,12,11 .ASCII /E = Exit game/ .BYTE 11,11,11,11 .ASCII /HALF-FAST/ .BYTE 15,12,11 .ASCII /G = GAME START/ .BYTE 0 .DSABL LC .EVEN .PAGE .SBTTL NARRATIVE ;+ ; VTPONG ; RSX-11M TASK TO PLAY PONG USING VT52 OR VT55 TERMINAL ; STRICTLY FREE FUN: NOT FOR COMMERCIAL OR MONETARY USE ; ENVIRONMENT ; VT52 OR VT55 TERMINAL (9600 BAUD) ; RSX-11M OPERATING SYSTEM ; SUPPORT FOR IO.ATA (ATTACH W UNSOLICITED INP CHR AST) ; SUPPORT FOR TF.RNE (READ WITH NO ECHO) ; SUPPORT FOR GET LUN INFO DIRECTIVE ; LOUD VERSION ASSUMES TT0: = LA36 (BETTER BEEP THAN VT) ; ; FEATURES ; BEEP WHEN BALL HITS (LOUD VERSION: LA36, QUIET VERSION: VT) ; 'SOFT' PADDLE EDGES (HITS WHEN BALL ACCEPTABLY CLOSE TO PADDLE) ; SMALL AND LARGE PADDLE MOVE AMOUNT KEYS ; BLOCK DIGIT SCORING ; FULL AND HALF PADDLE SIZE ; LEFT AND/OR RIGHT PADDLE 'WALL' ON REQUEST (ALWAYS HITS) ; NORMAL OR RAPID BALL MOTION ; AUTOMATIC BALL SPEEDUP AFTER SUCCESSIVE HITS ; EARLY QUIT ON REQUEST ; LISTS RULES AT BEGINNING OF EACH GAME AND UPON REQUEST UNDERWAY ; AFTER FINISHING, AUTOMATICALLY RESTARTS & ASKS IF ANOTHER GAME ; BACKCOURT MOTION PENALTY (BALL GOING AWAY FROM YOU): ; TOO MANY BACKCOURT MOVES AND ; ALL BACKCOURT MOVES IGNORED ; EVERY OTHER FORECOURT MOVE IGNORED ; UNTIL NEXT HIT. ; DOES CLEANUP ON EXIT ; DEFAULT TIMEOUT EXIT (SELF-DESTRUCTS IF UNATTENDED) ; WORKS FINE WITH MULTIPLE TERMINALS (AUTO-SPAWN) ; USES VT GRAPHIC BAR CHARACTERS ; 10 BAR POSITIONS PER VERTICAL CHARACTER SPACE ; TOP 8 PRINT, BOTTOM 2 ARE BLANK ; ; TAILORING ; MAC V=V ; SET /UIC=[1,54] ; LOUD BEEPS VERSION (ASSUMES TT0: IS LA36) ; TKB V.TSK, PRI=225, ASG=TT0:6 ; ; QUIET BEEPS VERSION (BEEPS TO VT) ; TKB VQ.TSK, PRI=225, ASG=TI:6 ; ; USAGE ; RUN $V FOR LOUD VERSION ; ; RUN $VQ FOR QUIET VERSION ; ; RULES HARDCOPY: RUN FROM LA36, HIT E TO EXIT BEFORE GAME ;- .PAGE .SBTTL INITIALIZE ; INIT: DIR$ #ATT5 ;ATTACH VT W UNSOL INP AST ; ; FIND OUT UNIT# LUN 6 & SET BEEP WAIT FLG ; DIR$ #GETLU6 ;GET INFO LUN 6 (BEEP DEV) CMPB LUNBUF+G.LUNU,#0 ;IS IT LA36 (TT0:)? BNE BEGIN INC NOBEWA ;YES: SET 'NO BEEP WAIT' FLG ; BEGINN: CLR INTREL ;GAME START: BE SURE INTRO RELIST FLG CL ; BEGIN: MOVB #'E,INBUF ;SELF-DESTRUCT UNLESS KEPT ALIVE INC PADLOK ;IGNORE KB PADDLE MOVES MOV #INTRO,R5 MOV #IO.WLB,VTW+Q.IOFN ;LET RULES LIST GO TO LA36 IF RQSTD JSR PC,WRT ;WRITE INTRODUCTION PAGE DIR$ #INTQIO ;LOOK FOR 1 CHAR DIR$ #INTRMR ;LOOK FOR TIMEOUT DIR$ #INTRWT ;ACT UPON EITHER BICB #240,INBUF ;LOP OFF PARITY AND LOWERCASE BITS CMPB INBUF,#'E BNE DWCORT JMP DONE DWCORT: MOV #DCOURT,R5 ; MOV #IO.WAL,VTW+Q.IOFN ;WRT ALL BITS TO VT52 TO PLAY JSR PC,WRT ;DRAW COURT, SET GRAPHICS MODE MOV #PBUFLB,R5 JSR PC,WRT ;DRAW LEFT PADDLE, MOV #PBUFRB,R5 JSR PC,WRT ; & RIGHT. ; TST INTREL ;WAS INTRO RELIST REQUESTED? BEQ BALLIN ;BIF NO: GAME START CLR INTREL ;YES: CLR RQST, JMP SERVE ;& SERVE ; BALLIN: MOV MIDX,X ;BALL MIDDLE HORIZ, MOV MIDY,Y ;& VERT CLR LS ;CLR SCORE L, CLR RS ;& R MOV PADZI,PADLZ ;INIT PENLTY CREDIT BACKCOURT MOTION MOV PADZI,PADRZ ; ; .SBTTL BLOCK SCORES DISPLAY ; ; SCORE: CMPB L,X ;BALL AT LEFT HORIZ.? BNE 10$ INC RS ;YES: INCR RT SCORE 10$: CMPB R,X ;BALL AT RT HORIZ.? BNE DWBLOK INC LS ;YES: INCR LEFT SCORE ; ; DRAW BLOCK DIGITS ; DWBLOK: MOV #SCORRC,R5 ;ADR CURS FOR SCOR INC PADLOK ;IGNORE KB MOMENTARILY INC SCORNW ;SHOW SCORE STATE NOW JSR PC,WRT ; ; CVT LEFT SCORE TO BLOCK DIGITS ; MOV LS,R4 ;GET L SCORE ASH #2,R4 ;QUAD IT FOR BYTE OFFSET IN 2-AD TBL ADD #SCORAD,R4 ;ADD SCOR ADR TBL BIAS MOV (R4)+,R5 ;MOV FIRST DIGIT ADR TO WKG REG JSR PC,WRT ;& WRT IT MOV (R4),R5 ;MOV 2ND DIGIT ADR TO WKG REG JSR PC,WRT ;& WRT IT MOV #SCORSP,R5 ;SPACE OVER TO WRT RT SCOR JSR PC,WRT ; ; CVT RT SCOR TO BLOCK DIGITS ; MOV RS,R4 ;GET R SCORE ASH #2,R4 ;QUAD IT FOR BYTE OFFSET IN 2-AD TBL ADD #SCORAD,R4 ;ADD SCORE ADR TBL BIAS MOV (R4)+,R5 ;MOV FIRST DIGIT ADR TO WKG REG JSR PC,WRT ;& WRT IT MOV (R4),R5 ;MOV 2ND DIGIT ADR TO WKG REG JSR PC,WRT ;& WRT IT CLR PADLOK ;RESTORE KB: SCORES DRAWN DIR$ #SCORMR ;POST-SCORING MARKTIME WTBLOK: DIR$ #SCORWT ;POST-SCORING WAIT ; ; CHECK IF GAME OVER ; CMP LS,#15. ;LEFT SCORE 15., BEQ 20$ CMP RS,#15. ;OR RT SCORE 15.? BEQ 20$ ;IF SO, THIS GAME OVER TST QUIT ;OR DID PLAYER ASK TO QUIT EARLY? BEQ 15$ ;BIF NO 10$: JMP DONE ;IF YES, DONE ; 15$: TST INTREL ;WAS INTRO RELIST REQUESTED? BEQ SERVE ;BIF NO: SERVE JMP BEGIN ;ELSE DO IT, THEN SERVE ; ; IF THIS GAME RAN TO COMPLETION, ASK IF ANOTHER: ; 20$: JMP BEGINN ; ; .SBTTL SERVE ; SERVE: MOV MIDX,X ;SET HORIZ MIDCOURT MOV SPDCNI,SPDCNT ;SET MAX HITS BEFORE SPEEDUP MOV SPEEDS,SPEED ;SET INIT SPD (MAX WAIT TIME) MOV #2,R5 ;2 BEEPS OUTPUT JSR PC,BEEP SERVER: MOV #DCOURT,R5 ;REDRAW COURT (ERASES SCORES) INC PADLOK ;IGNORE KB MOMENTARILY JSR PC,WRT ; ; SEE IF BOTH PADDLES HV BEEN IN SIMULTANEOUS AUTO TOO LONG: ; AUTLIM: CMPB PADLC,BYTBLA ;LEFT AUT, BNE REPADL CMPB PADRC,BYTBRA ;& RT AUT, BNE REPADL INC AUTLR CMP AUTLR,AUTLRM ;FOR MORE THAN MAX # TIMES? BLE REPADL CLRB PADLC ;IF SO, SHUT OFF LEFT AUT CLRB PADRC ;& RT AUT CLR AUTLR ;& RESET COUNT REPADL: MOV #PBUFLB,R5 ;ALSO REDRAW LEFT PADDLE, CMPB PADLC,BYTBLA ;LEFT AUT? BNE 10$ MOV #PBUFLA,R5 ;IF SO, WRT LEFT PAD WALL 10$: JSR PC,WRT MOV #PBUFRB,R5 ;& RT CMPB PADRC,BYTBRA ;RT AUT? BNE 20$ MOV #PBUFRA,R5 ;IF SO, WRT RT PAD WALL 20$: JSR PC,WRT CLR PADLOK ;RESTORE KB CLR SCORNW ;TURN OFF 'SCORING NOW' STATE DIR$ #SETEFB ;INITIALLY SIGNIFY BALL MOVED O.K. ; ; .SBTTL NEXT BALL POS & TIMG ; SLEEP: DIR$ #BALLMR ;BALL MARKTIME DIR$ #BALLMW ;BALL MARKTIME WAIT DIR$ #BALLWT ;BE SURE BALL MOVE HAS COMPLETED BALL: ADD XINCR,X ;ADVANCE X (ALWAYS 1 CHR) ADD YINCR,YFINE ;ADVANCE Y CMP YFINE,YFINEL ;STILL WITHIN SAME CHR POS? BLE 5$ SUB YFINEL,YFINE ;NO, FURTHER DOWN INC Y BR XBND 5$: TST YFINE BGT XBND ;YES ADD YFINEL,YFINE ;NO, FURTHER UP DEC Y ; ; TEST IF BALL AT X BNDRY: ; XBND: CMP L,X ;X AT LEFT? BNE XBND2 ;BIF NO ; ; X AT LEFT BOUNDARY: ; XBNDL: CMPB PADLC,BYTBLA ;LEFT AUT (WALL)? BEQ SWAT ;BIF YES: ALWAYS SWAT MOV PADLY,R0 ;ELSE MOVE PADDLE Y TO R0, BR BNDX ;& USE COMMON BOUNDARY CODE ; XBND2: CMP R,X ;X AT RIGHT? BNE YBND ;BIF NO: CHECK Y BOUNDARIES ; ; X AT RIGHT BOUNDARY: ; XBNDR: CMPB PADRC,BYTBRA ;RIGHT AUT (WALL)? BEQ SWAT ;BIF YES: ALWAYS SWAT MOV PADRY,R0 ;ELSE MOVE PADDLE Y TO R0 ; ; COMMON (X-AT-BOUNDARY, PADDLE-MATCH-BALL?) CODE: ; BNDX: CMP R0,Y ;EXACT MATCH? BEQ SWAT ;BIF YES: HIT ; ; ADD'L BOUNDARY TESTS FOR SOFT PADDLE EDGES & FULL SIZE PADDLES: ; ; TEST FOR TOP SOFT PADDLE EDGE: ; BNDTSP: DEC R0 ;SET PSEUDO PADDLE Y ONE HIGHER THAN ACT CMP R0,Y ;NOW DOES IT MATCH BALL? BNE BNDBSP ;BIF NO ; ; BALL Y ONE HIGHER THAN PAD Y: CHECK YFINE FOR SOFT LIMIT: ; CMP YFINE,YSOFLT ;IS BALL CLOSE ENOUGH TO PADDLE TOP? BGE SWAT ;BIF YES, BR GONE ;ELSE MISSED ; ; TEST FOR BOTTOM SOFT PADDLE EDGE (OR FULL PADDLE 2ND HALF): ; BNDBSP: ADD #2,R0 ;SET PSEUDO PADDLE Y ONE LOWER THAN ACT TST PADHAF ;HALF PADDLES BEING USED? BNE BNDBS2 ;BIF YES ; ; FULL PADDLE BEING USED: R0 NOW PTS TO 2ND HALF OF IT: ; BNDFUL: CMP R0,Y ;PADDLE BOT HALF MATCH BALL? BEQ SWAT ;BIF YES, INC R0 ;ELSE SET PSEUDO PADDLE Y ONE LOWER THAN ; ; FULL OR HALF: BOTTOM SOFT PADDLE EDGE: ; ; PSEUDO PADDLE Y NOW ONE LOWER THAN ACTUAL: ; BNDBS2: CMP R0,Y ;NOW DOES IT MATCH BALL? BNE GONE ;BIF NO ; ; BALL Y ONE LOWER THAN PAD Y: CHECK YFINE FOR SOFT LIMIT: ; CMP YFINE,YSOFLB ;IS BALL CLOSE ENOUGH TO PADDLE BOT? BLE SWAT ;BIF YES, BR GONE ;ELSE MISSED ; ; MISSED ; GONE: INC PADLOK ;PREVENT FURTHER PADDLE MOTION JSR PC,SAILER ;CALC & WRT LAST BALL MOV #3,R5 ;3 BEEPS OUT JSR PC,BEEP JMP SCORE ; ; HIT ; SWAT: NEG XINCR ;REVERSE HORIZ SENSE JSR PC,SPDCHG ;SEE IF SPEEDUP YCHG: JSR PC,YINCRM ;MODIFY YINCR ; ; RESET SUCCESSFUL SWATTER'S BACKCOURT PENALTY COUNT: ; CMP R,X ;ARE WE AT RT? BEQ PADRZI ;BIF YES PADLZI: MOV PADZI,PADLZ ;RESET LEFT PENALTY COUNT BR BEEP1 PADRZI: MOV PADZI,PADRZ ;RESET RIGHT PENALTY COUNT ; BEEP1: MOV #1,R5 ;1 BEEP OUT JSR PC,BEEP JMP SERVER ;ERASE PREV PATH ; ; BALL NOT AT X BNDRY: CK Y BNDRYS ; YBND: YBNDT: CMP Y,T ;TOP? BNE YBNDB TST YINCR ;YES: GOING DOWN ALREADY? BPL SAIL ;YES: LEAVE ALONE BR SIDE ;NO: REVERSE (BOUNCE) ; YBNDB: CMP Y,B ;BOT? BNE SAIL ;NO, NEITHER BNDRY: SAIL TST YINCR ;YES: GOING UP ALREADY? BMI SAIL ;YES: LEAVE ALONE ; ; BALL AT TOP OR BOT & GOING THRU: REVERSE (BOUNCE) ; SIDE: NEG YINCR ;REVERSE VERT SENSE MOV #1,R5 ;1 BEEP OUT JSR PC,BEEP JMP SLEEP ;WAIT FOR NEXT BALL JUMP ; ; BALL IN FREE SPACE: SAIL ; SAIL: JSR PC,SAILER ;CALC & WRT NEXT BALL JMP SLEEP ;WAIT FOR NEXT BALL JUMP ; ; .SBTTL GAME OVER: CLEANUP ; ; DONE: DSAR$S ;DISABLE PADDLES (KB LISTENS & PAD OUTS) DIR$ #KIL5 ;CANCEL OTHER I/O DIR$ #KILWT ;WAIT TIL DONE DIR$ #ERASE ;ERASE SCREEN DIR$ #KILWT ;WAIT TILL DONE DIR$ #DET5 ;DETACH VT EXIT$S ; ; .SBTTL PADDLE MOVEMENT AST ; ; PAD: MOVB (SP),BYTBS ;MOVE INP BYTE TO TBL STOPPER MOV R0,-(SP) MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) ; ; DON'T PUT OUT QIO'S IF THEY'D MESS UP NON-AST CURSOR ADDR ; (SCORE OR DRAW COURT/PADDLES IN PROGRESS) ; TST PADLOK BEQ PADACT JMP PADDON ; ; ACT ON PADDLE MOV CMD: ; PADACT: BICB #240,BYTBS ;LOP OFF PARITY AND LOWERCASE BITS CLR R0 ;& INIT SWEEP OFFSET PADCMP: CMPB BYTBS,BYTBL(R0) ;SEARCH BYTE TBL BEQ PADJMP ;MUST FIND MATCH (MAYBE STOPPER) TST (R0)+ BR PADCMP PADJMP: JMP @ADTBL(R0) ;JMP TO CORRESP ADR IN ADTBL ; ; PROC COMMON TO EITHER PADDLE: ; RAPID: MOV FAST,SPEEDI ;MOVE SHORT WAIT CNT TO INIT SPEED, MOV FAST,SPEED ; & TO CURRENT SPEED JMP PADDON ; NORMAL: MOV SLOW,SPEEDI ;MOVE LONG WAIT CNT TO INIT SPEED, MOV SLOW,SPEED ; & TO CURRENT SPEED JMP PADDON ; QIT: INC QUIT ;TURN ON EARLY QUIT FLG FOR NEXT SCORE JMP PADDON ; HAFPAD: INC PADHAF ;SET HALF-PADDLE FLAG MOV #40,R2 ;PREP TO MAKE 2ND HALF FULL PAD BLANK BR CHGPAD ; FULPAD: CLR PADHAF ;CLR HALF-PADDLE FLG MOV #141,R2 ;PREP TO MAKE 2ND HALF FUL PD SOLID RECT ; ; COMMON CODE FOR CHANGING PADDLE SIZE: ; CHGPAD: INC PADSZC ;SET 'PADDLE SIZE BEING CHANGED' FLG ; ; LEFT PADDLE SIZE CHG: ; CHGPAL: MOV R2,-(SP) ;SAV R2 FROM HAFPAD OR FULPAD MOV #PADLY,R1 ;LEFT PADDLE Y TO R1 MOVB BYTBS,PADLC ;SAVE THIS CMD AS LAST GIVEN TO L PAD JSR PC,PADM2 ;MOVE CHR INTO 2ND HALF OF PADDLE ADD #2,R1 ;GET BFR ADR PBUFLB, MOV R1,PADQIO+Q.IOPL ;& PUT INTO DPB DIR$ #PADQIO ;WRT NEW L PADDLE ; ; RIGHT PADDLE SIZE CHANGE: ; CHGPAR: MOV (SP)+,R2 ;RESTORE R2 FROM HAFPAD OR FULPAD MOV #PADRY,R1 ;RT PADDLE Y TO R1 MOVB BYTBS,PADRC ;SAVE THIS CMD AS LAST GIVEN TO RT PAD JSR PC,PADM2 ;MOVE CHR INTO 2ND HALF OF PADDLE ADD #2,R1 ;GET BFR ADR PBUFRB, MOV R1,PADQIO+Q.IOPL ;& PUT INTO DPB DIR$ #PADQIO ;WRT NEW RT PADDLE ; CLR PADSZC ;CLR 'PADDLE SIZE BEING CHANGED' FLG JMP PADDON ; INTRE: INC INTREL ;SET FLG TO CALL FOR INTRO RELIST ; AFTER NEXT SCORE JMP PADDON ODT: JMP PADDON ;ODT BREAKPOINT HOOK ; ; LEFT PADDLE PROC: ; LPA: MOVB BYTBS,PADLC ;SAVE LAST CMD MOV #PBUFLA,R1 ;LEFT PAD WALL ADR TO R1 JMP PADWRT ;GO WRT IT OUT LUS: MOV PSAU,R0 ;SML AMT UP BR LP LDS: MOV PSAD,R0 ;SML AMT DN BR LP LUL: MOV PLAU,R0 ;LGE AMT UP BR LP LDL: MOV PLAD,R0 ;LGE AMT DN LP: MOV #PADLY,R1 MOVB BYTBS,PADLC ;SAVE LAST CMD ; ; FORGET ABOUT PENALTIES DURING SCORE STATE: ; CSLF: TST SCORNW ;SCORE STATE NOW? BEQ CSL ;BIF NO JMP PADMOV ;YES: ALL MOVES ALLOWED ; ; PENALIZE IDLE LEFT PLAYER FOR EXCESSIVE BACKCOURT MOVES: ; CSL: TST XINCR ;WHICH WAY IS BALL GOING? BMI CSLT ;BIF TOWARD L ; ; BALL GOING AWAY FROM L: PENALIZE ; CSLA: SUB #4,PADLZ ;KNOCK OFF 4 PER MOVE BGT PADMOV ;IF BELOW ALLOTMENT, DO IT JMP PADDON ;ELSE IGNORE ; ; BALL GOING TOWARD L: WORK OFF ANY BACKCOURT MOTION PENALTY 2 @ TIME: ; CSLT: TST PADLZ ;IS THERE A PENALTY FROM HISTORY? BGT PADMOV ;BIF NO INC PADLZ ;YES: PAY BACK ONLY 1 PER MOVE, BIT #1,PADLZ BEQ PADMOV ; DO IT IF EVEN, JMP PADDON ; & IGNORE IF ODD ; ; RT PADDLE PROC: ; RPA: MOVB BYTBS,PADRC ;SAVE LAST CMD MOV #PBUFRA,R1 ;RT PAD WALL ADR TO R1 JMP PADWRT ;GO WRT IT OUT RUS: MOV PSAU,R0 ;SML AMT UP BR RP RDS: MOV PSAD,R0 ;SML AMT DN BR RP RUL: MOV PLAU,R0 ;LGE AMT UP BR RP RDL: MOV PLAD,R0 ;LGE AMT DN RP: MOV #PADRY,R1 MOVB BYTBS,PADRC ;SAVE LAST CMD ; ; FORGET ABOUT PENALTIES DURING SCORE STATE: ; CSRF: TST SCORNW ;SCORE STATE NOW? BEQ CSR ;BIF NO JMP PADMOV ;YES: ALL MOVES ALLOWED ; ; PENALIZE IDLE RIGHT PLAYER FOR EXCESSIVE BACKCOURT MOVES: ; CSR: TST XINCR ;WHICH WAY IS BALL GOING? BPL CSRT ;BIF TOWARD R ; ; BALL GOING AWAY FROM R: PENALIZE ; CSRA: SUB #2,PADRZ ;KNOCK OFF 2 PER MOVE BGT PADMOV ;IF BELOW ALLOTMENT, DO IT JMP PADDON ;ELSE IGNORE ; ; BALL GOING TOWARD R: WORK OFF ANY BACKCOURT MOTION PENALTY 2 @ TIME: ; CSRT: TST PADRZ ;IS THERE A PENALTY FROM HISTORY? BGT PADMOV ;BIF NO INC PADRZ ;YES: PAY BACK ONLY 1 PER MOVE, BIT #1,PADRZ BEQ PADMOV ; DO IT IF EVEN, JMP PADDON ; & IGNORE IF ODD ; ; PREP TO MOVE PADDLE: ; PADMOV: MOVB #40,R2 ;FIRST WRT BLANK JSR PC,PADM ;IN OLD PADDLE LOC TO ERASE MOVB #141,R2 ;NOW SOLID RECT IS NEW PAD CHR MOV (R1),R3 ;PADDLE Y 10$: ADD R0,R3 ;FIGURE NEW TENTATIVE PADDLE Y MOV R3,(R1) ;& STORE TST R3 ;HIGHER THAN (TOP-1)? BGE 15$ MOV #-1,(R1) ;YES: STORE TOP-2 & SHOW X BR 20$ 15$: CMP R3,B ;LOWER THAN BOT? BLE 20$ MOV B,(R1) ;YES: STORE BOT+1 & SHOW X INC (R1) MOVB #'X,R2 20$: JSR PC,PADM ;PUT NEW PADDLE CHR IN ARRAY ADD #2,R1 ;GET BFR ADR PADWRT: MOV R1,PADQIO+Q.IOPL ;& PUT INTO DPB DIR$ #PADQIO ;WRT NEW PADDLE PADDON: MOV (SP)+,R3 ;RESTORE R0-R3 FM STACK MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 TST (SP)+ ;POP INPUT CHR WD ASTX$S ;AST EXIT ; ; .SBTTL SUBROUTINES ; ; ; PADDLE ERASE/MOVE IN NEW ; PADM: MOV (R1),R3 ;YVAL ; ; DON'T WRITE OUTSIDE ARRAY ; BGT 5$ MOV #1,R3 ;IF .LE. 0, MAKE T CMP R2,#141 ;WAS PAD CHR ASKED? BNE PADM1 MOVB #'X,R2 ;IF SO, REPL WITH X BR PADM1 5$: CMP R3,B BLE PADM1 DEC R3 ;IF B+1,MAKE B ; ; WITHIN ARRAY: CALC BYTE ADR & MOVE IT IN ; PADM1: MUL #3,R3 ;*3 ADD #3,R3 ;+ OFFSET TO SKIP OVER CURS ADR ADD R1,R3 ;+ PADDLE DB BEGIN=PADDLE CHR ADR MOVB R2,(R3) ;MOVE BYTE TO ADR ; ; SEE IF FULL PADDLE BEING USED: ; TST PADHAF ;HALF PADDLES ONLY? BNE PADM5 ;BIF YES: RETURN ; ; FULL PADDLES: ; 15$: TST BOTH ;BOTH HALVES DONE? BNE PADM4 ;BIF YES PADM2: INC BOTH ;ELSE SET FLG SHOWING 2ND HALF MOV (R1),R3 ;RESTORE ORIG Y BLT PADM4 ;BIF IT WOULD MAKE 2ND HALF ALSO HIGHER ; THAN TOP BGT 35$ ;BIF IT WAS TOP OR LOWER ; ; *** BEGINNING OF SPECIAL CASE: ; PREV WAS (TOP-1), SECOND HALF WILL BE (TOP) ; 25$: TST PADSZC ;IS THIS A PADDLE SIZE CHG 2ND HALF ; RE-DO? BNE 30$ ;BIF YES CMP R2,#40 ;WAS NEW PAD CHR BLANK? BEQ 40$ ;BIF YES: LEAVE AS IS MOV #141,R2 ;ELSE BE SURE 'X IS REPL W SOLID RECT BR 40$ ; ; PADDLE SIZE CHG 2ND HALF RE-DO: ; 30$: CMP R2,#40 ;WAS NEW PAD CHR BLANK? BNE 40$ ;BIF NO: LEAVE SOLID RECT ALONE MOVB #'X,R2 ;ELSE BE SURE BLANK IS REPL W 'X BR 40$ ; ; *** END OF SPECIAL CASE ; 35$: CMP R3,B ;WAS ORIG Y AT BOTTOM OR BELOW? BGE PADM4 ;BIF YES: 2ND HALF LOWER THAN BOTTOM 40$: INC R3 ;2ND HALF Y = (ORIG Y) +1 BR PADM1 ;GO DO IT ; ; FULL PADDLES: RESET 'BOTH HALVES' FLG ; PADM4: CLR BOTH ; ; FULL OR HALF PADDLES: DONE ; PADM5: RTS PC ; ; SEE IF SPEEDUP ; SPDCHG: CMP SPEED,SPEEDS ;FIRST HIT AFTER SERVE? BNE SPDC ;BIF NO, ELSE MOV SPEEDI,SPEED ;SET INITIAL SPEED ('SLOW' OR 'FAST', ; BUT ALWAYS FASTER THAN SERVE SPEED), BR SPDRET ;& RETURN (SKIP NORMAL CALC.) ; SPDC: DEC SPDCNT ;RUNNING HITS BEFORE SPEEDUP BNE SPDRET ;RETURN IF MORE TO GO MOV SPDCNI,SPDCNT ;RESTORE FOR NEXT TIME CMP SPEED,#1 ;ALREADY FASTEST? (SHORTEST WAIT=1 TICK) BEQ SPDRET DEC SPEED ;NO: SPEED UP SPDRET: RTS PC ; ; ; CHG YINCR ON BOUNCE: ; YINCRM: MOV YINCR,R0 ;MOV CURR YINCR TO R0 TST R0 ;NEG? BPL 5$ NEG R0 ;YES: GET ABS VAL 5$: INC R0 ;BUMP CMP R0,YINCRL ;ABOVE LIM? BLE 10$ ;NO, OK MOV #1,R0 ;YES: RESET TO 1 10$: TST YINCR ;WAS PREV NEG? BPL 15$ NEG R0 ;YES: SO SHOULD NEW 15$: MOV R0,YINCR ;PUT NEW INTO OLD YINRET: RTS PC ; ; ; BEEP, OUTPUT BEEP CHARS ; ; ; FOR BEEPS TO VT, WAIT BETW SINGLE-BEEP QIO'S ; FOR BEEPS TO LA, SEND ONE MULTIPLE-BEEP QIO ; BEEP: TST NOBEWA ;BEEP WAIT (VT)? BEQ BEEPS ;BIF YES MOV R5,BEEPO+Q.IOPL+2 ;ELSE PUT COUNT INTO QIO, MOV #1,R5 ;& MAKE SURE ONLY 1 QIO BR BEEPS BEEPD: DIR$ #BEEPMR ;BEEP MARKTIME DIR$ #BEEPWT ;BEEP WAIT BEEPS: DIR$ #BEEPO ;OUTPUT BEEP(S) SOB R5,BEEPD ;MORE? RTS PC ;NO, DONE ; ; ; WRT, WRITE A BYTE STRING W NULL STOPPER ; R0 (USE) = OUT BFR ADR ; R5 (IN ) = INPUT STR ADR ; WRT: MOV #BUF,R0 ;START OF OUT BUF 10$: MOVB (R5)+,(R0)+ ;MOVE A BYTE OUT TSTB (R5) ;NEXT BYTE NULL? BEQ 20$ ;YES CMP R0,#BUF+72. ;NO: BFR FULL? BNE 10$ ;NO 20$: SUB #BUF,R0 ;PREP OUTPUT: BYTE CNT TO R0 MOV R0,VTW+Q.IOPL+2 ;THEN TO DPB DIR$ #VTW ;OUTPUT THE BUFFER DIR$ #VTWT ;& WT BEFORE MODIFYING BUF OR CNT TSTB (R5) ;DONE? BNE WRT ;NO WRTRET: RTS PC ;YES: RETURN ; ; ; SAILER, SAIL BALL IN FREE SPACE ; SAILER: MOV Y,R0 ;VERT POS ADD #37,R0 ;+ CHR BIAS MOVB R0,BALMOR ;TO ROW CURS ADR MOV X,R0 ;HORIZ POS ADD #37,R0 ;+ CHR BIAS MOVB R0,BALMOC ;TO COL CURS ADR MOV YFINE,R0 ;LINE WITHIN BAR CHR MOVB BALCHR(R0),BALMOL ;TO BAR CHR (BALL) DIR$ #BALLJP ;MOVE BALL PATH RTS PC ;RETURN ; ; PATCH: .BLKW 50. .END INIT