.TITLE PNG - VIDEO PING PONG GAME .IDENT /03/ .ENABL LC ;+ ; ; 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 ; ; Version 3.0 modified for VT100 on 12-Nov-81 by Robin Miller. ; ; PNG, VIDEO TERMINAL PONG (VT52,VT55, & VT100) ; ; *** VT52=0 must be defined to assemble for VT52 or VT55 terminal. *** ; ;- .MCALL ASTX$S, DIR$, DSAR$S, EXIT$S, GLUN$ .MCALL MRKT$, QIO$, QIOW$, SETF$, WTSE$, WTLO$ .ENABL AMA .NLIST BEX .SBTTL LOCAL EQUATES ; ; Local equates: ; NULL = 0 ; ASCII FOR NULL CTRLC = 3 ; ASCII FOR CONTROL/C BELL = 7 ; ASCII FOR BELL BS = 10 ; ASCII FOR BACKSPACE HT = 11 ; ASCII FOR HORIZONTAL TAB LF = 12 ; ASCII FOR LINE FEED CR = 15 ; ASCII FOR CARRIAGE RETURN CTRLZ = 32 ; ASCII FOR CONTROL/Z ESC = 33 ; ASCII FOR ESCAPE SPACE = 40 ; ASCII FOR SPACE BOX = 141 ; CHARACTER FOR VT52 BOX BIAS = 37 ; BIAS FOR VT52 CURSER ADDR NET = 140 ; DIAMOND FOR NET ON VT100 BAR = 170 ; VERTICAL BAR ON VT100 ; ; BALL equates: ; PSAD = 1 ; PAD SMALL AMOUNT DOWN PSAU = -1 ; PAD SMALL AMOUNT UP PLAD = 3 ; PAD LARGE AMOUNT DOWN (WAS 4) PLAU = -3 ; PAD LARGE AMOUNT UP (WAS -4) TOP = 1 ; TOP OF COURT BOTTOM = 24. ; BOTTOM OF COURT RTPAD = 78. ; RIGHT PADDLE (WAS 72.) LEFT = 1 ; LEFT MARGIN RIGHT = RTPAD-1 ; RIGHT MARGIN MIDY = BOTTOM/2 ; MIDDLE Y VALUE (ROW) MIDX = RTPAD/2 ; MIDDLE X VALUE (COLUMN) .IF DF VT52 YINCRL = 6 ; Y-INCR LIMIT FOR VT52 ; (MULI RICOCHET AVOID) YFINEL = 10. ; # BARS MAX BEFORE NEXT CHAR YSOFLT = 9. ; Y SOFT TOP LIMIT ; IF PADY=Y+1 & YFINE.GE.YSOFLT, HIT .IFF ; VT100 RT0 = <*10.>>+48.> ; LOW RTPAD ASCII DIGIT RT1 = <+48.> ; HIGH RTPAD ASCII DIGIT MIDX0 = <*10.>>+48.> ; LOW MIDX ASCII DIGIT MIDX1 = <+48.> ; HIGH MIDX ASCII DIGIT YINCRL = 4 ; Y-INCR LIMIT FOR VT100 YFINEL = 5. ; # BARS MAX BEFORE NEXT CHAR YSOFLT = 4. ; Y SOFT TOP LIMIT .ENDC YSOFLB = 2 ; Y SOFT BOTTOM LIMIT ; IF PADY=Y-1 & YFINE.LE.YSOFLB, HIT ; ; $ 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,,TIOSB,, ; READ 1 CHR AFTER INTRO INTRMR: MRKT$ 8.,5,3 ; 5-MINUTE WAIT INTRWT: WTLO$ 0,300 ; WT EITHER 7 OR 8 AFTER INTRO VTW: QIOW$ IO.WAL,5,5,,TIOSB,, ; GEN'L MAIN LOOP OUTPUT 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 (17 TICKS) CERASE: QIOW$ IO.WAL,5,4,,TIOSB,, ; CLEAR COURT ERASE: QIOW$ IO.WAL,5,4,,TIOSB,, ; ERASE SCREEN GETLU6: GLUN$ 6,LUNBUF ; GET INFORMATION ON LUN 6 ATT5: QIOW$ IO.ATA,5,4,,TIOSB,, ; ATTACH WITH UNSOLICITED AST INPUT DET5: QIOW$ IO.DET,5,4 ; DETACH THE TERMINAL KIL5: QIOW$ IO.KIL,5,4 ; CANCEL OUTSTANDING I/O TIOSB: .BLKW 2 ; TERMINAL I/O STATUS BLOCK ; ; ADJUSTMENTS TO $ DPB'S ; SPEED = BALLMR+M.KTMG ; BALL MARKTIME ADJ. ; ; BUFFERS FOR QIO'S (& REQUIRED ADJACENT ITEMS) ; BUF:: .BLKB 256. ; GEN'L BUF MAIN LOOP OUTPUTS BUFL = .-BUF BEEPC: .BYTE , ; BYTE FOR BEEPS LUNBUF: .BLKW 6 ; GET LUN INFO BFR (WANT UNIT #) ; ; PADDLE 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 ; ; BALL DATA BASE: ; X:: .WORD MIDX ; HORIZONTAL: LEFT TO RIGHT (COLUMN) Y:: .WORD MIDY ; VERTICAL: TOP TO BOTTOM (ROW) 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) YFINE:: .WORD 0 ; BAR POSN IN NEXT BALL CHR ; ; BYTE STRING TO MOVE BALL: ; .IF DF VT52 BALMOV:: .BYTE ,'Y ; ADR CURS BALMOR: .BYTE ; ROW BALMOC: .BYTE ; COL BALMOL: .BYTE 154 ; BALL (BAR) BALSIZ = .-BALMOV .IFF ; VT100 BALMOV:: .BYTE ,'[ ; CURSER ADDRESS BALMOR: .BYTE 0,'1 ; ROW .BYTE '; ; SEPARATOR BALMOC: .BYTE 0,'1 ; COLUMN .BYTE 'H ; CURSER CONTROL BALMOL: .BYTE 157 ; BALL (BAR) BALSIZ = .-BALMOV .ENDC ; ; BALL CHRS (FIRST BLK UNUSED, LAST BLKS = INVIS. BALL) ; .IF DF VT52 BALCHR:: .BYTE ,154,155,156,157,160,161,162,163,, .IFF ; VT100 BALCHR:: .BYTE ,157,160,161,162,163,, .ENDC .EVEN ; ; 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 ; AUTO (RIGHT WALL) BYTBR: .WORD 26,23,25,22 ; RIGHT KEYS UPS, DNS, UPL, DNL BYTBRA: .WORD 'P ; AUTO (LEFT WALL) .WORD CTRLC,CTRLZ ; QUIT ON CTRL/C OR CTRL/Z .WORD 'R,'N ; 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,QIT ; QUIT ON CTRL/C OR CTRL/Z .WORD RAPID,NORMAL ; RAPID, NORMAL .WORD HAFPAD,FULPAD,INTRE ; HALF PAD, FULL PAD, INTRO RELIST .WORD ODT ; ODT BKPT HOOK .WORD PADDON ; IGNORE UNRECOGNIZED CHR ; ; LEFT PADDLE TABLES: ; PADLZ:: .WORD 40. ; INIT PENLTY CREDIT BACKCOURT MOTION PADLY:: .WORD MIDY ; Y .IF DF VT52 PBUFLB: .BYTE ,'Y,, ; UL CORNER CURS ADR YOFF = 3 ; OFFSET PAST CURSER ADDRESS .IFF ; VT100 PBUFLB: .ASCII %[01;01H% ; UL CORNER CURSER ADDRESS YOFF = 7 ; OFFSET PAST CURSER ADDRESS .ENDC PBUFL: .REPT 11. .BYTE ,, .ENDR .IF DF VT52 .BYTE ,,,,, ; PAD,BS,LF TWICE (FULL PAD DEFAULT) .IFF ; VT100 .BYTE ,,,,, ; PADDLE FOR VT100 .ENDC .REPT 10. .BYTE ,, .ENDR .BYTE , PADSIZ = <<.-PBUFLB>-1> PADLC:: .BYTE ; LAST CMD (FOR AUTO TEST) .EVEN ; ; LEFT PADDLE WALL (AUT MODE) ; .IF DF VT52 PBUFLA: .BYTE ,'Y,, .REPT 23. .BYTE ,, .ENDR .BYTE , .IFF ; VT100 PBUFLA: .ASCII %[01;01H% .REPT 23. .BYTE ,, .ENDR .BYTE , .ENDC .EVEN ; ; RIGHT PADDLE TABLES: ; PADRZ:: .WORD 40. ; INIT PENLTY CREDIT BACKCOURT MOTION PADRY:: .WORD MIDY ; Y VALUE .IF DF VT52 PBUFRB: .BYTE ,'Y,, .IFF ; VT100 PBUFRB: .BYTE ,'[,'0,'1,';,RT1,RT0,'H .ENDC PBUFR: .REPT 11. .BYTE ,, .ENDR .IF DF VT52 .BYTE ,,,,, ; PAD,BS,LF TWICE (FULL PAD DEFAULT) .IFF ; VT100 .BYTE ,,,,, ; PADDLE FOR VT100 .ENDC .REPT 10. .BYTE ,, .ENDR .BYTE , PADRC:: .BYTE ; LAST CMD (FOR AUT TEST) .EVEN ; ; RT PADDLE WALL (AUT MODE) ; .IF DF VT52 PBUFRA: .BYTE ,'Y,, .IFF ; VT100 PBUFRA: .BYTE ,'[,'0,'1,';,RT1,RT0,'H .ENDC .IF DF VT52 .REPT 23. .BYTE ,, .ENDR .BYTE , .IFF ; VT100 .REPT 23. .BYTE ,, .ENDR .BYTE , .ENDC .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 ; ; CLEAR COURT (ERASE SCORE & TRACE OF BALL) CCOURT:: .IF DF VT52 .BYTE ,'Y,, .BYTE ,'F ; ENTER GRAPHICS MODE .REPT 21. .BYTE ,'K, ; ERASE TO END OF LINE .ENDR .BYTE ,'K ; LAST LINE ; NOW REDRAW THE NET. .BYTE ,'Y,,, .BYTE ,'Y,,, .BYTE ,'Y,,, .BYTE ,'Y,,, .IFF ; VT100 .BYTE ,'[,'2,';,'1,'H ; LINE 2, COLUMN 1 .REPT 21. .BYTE ,'[,'K, ; ERASE TO END OF LINE .ENDR .BYTE ,'[,'K ; LAST LINE ; NOW REDRAW THE NET. .BYTE ,'(,'0 ; ENTER GRAPHICS MODE .BYTE ,'[,'0,'5,';,MIDX1,MIDX0,'H, .BYTE ,'[,'1,'0,';,MIDX1,MIDX0,'H, .BYTE ,'[,'1,'5,';,MIDX1,MIDX0,'H, .BYTE ,'[,'2,'0,';,MIDX1,MIDX0,'H, .ENDC CCSIZ = .-CCOURT ; DRAW COURT (SIDE LINES AND NET) DCOURT:: .IF DF VT52 .BYTE ,'H,,'J,,'F .IFF ; VT100 .BYTE ,'[,'H,,'[,'J,,'(,'0 .ENDC .REPT RIGHT .BYTE 163 ; LOWER BAR FOR TOP ROW .ENDR .IF DF VT52 .BYTE ,'Y,,, .BYTE ,'Y,,, .BYTE ,'Y,,, .BYTE ,'Y,,, .BYTE ,'Y,, .REPT RIGHT .BYTE 154 ; UPPER BAR FOR BOTTOM ROW .ENDR .IFF ; VT100 .BYTE ,'[,'0,'5,';,MIDX1,MIDX0,'H, .BYTE ,'[,'1,'0,';,MIDX1,MIDX0,'H, .BYTE ,'[,'1,'5,';,MIDX1,MIDX0,'H, .BYTE ,'[,'2,'0,';,MIDX1,MIDX0,'H, .BYTE ,'[,'2,'4,';,'0,'1,'H .REPT RIGHT .BYTE 157 ; UPPER BAR FOR BOTTOM ROW .ENDR .ENDC .BYTE ; TERMINATOR ; ERASE COURT: .IF DF VT52 ECOURT: .BYTE ,,,,'H,,'J,,'G ECSIZ = .-ECOURT .IFF ; VT100 ECOURT: .BYTE ,,,,'[,'H,,'[,'J,,'(,'B ECSIZ = .-ECOURT .ENDC ; ; SCORE ROW & COLUMN ; SCOREX = ; START OF SCORE X (COLUMN) .IF DF VT52 SCORRC: .BYTE ,'Y,,, .IFF ; VT100 SCR0 = <*10.>>+48.> ; LOW SCORE ASCII DIGIT SCR1 = <+48.> ; HIGH SCORE ASCII DIGIT SCORRC: .BYTE ,'[,'7,';,SCR1,SCR0,'H, .ENDC ; ; SCORE SPACE OVER TO RIGHT HALF COURT: ; SCORSP: .REPT 21. .BYTE .ENDR .BYTE ; TERMINATOR ; ; BLOCK DIGITS 5 X 7 ; DIGN: .REPT 7 ; NULL DIGIT .BYTE ,,,, .BYTE ,,,,, .ENDR .IF DF VT52 .REPT 7 .BYTE ,'A .ENDR .IFF ; VT100 .BYTE ,'[,'7,'A .ENDC .BYTE ,,,,,, ; ZERO DIGIT. DIG0: .BYTE ,,,,, .REPT 6 .BYTE ,, .ENDR .REPT 4 .BYTE ,, .ENDR .IF DF VT52 .REPT 5 .BYTE ,'A,, .ENDR .BYTE ,'A ; CURSOR UP .REPT 6 .BYTE ,'C ; CURSOR RIGHT .ENDR .IFF ; VT100 .REPT 5 .BYTE ,'[,'A,, .ENDR .BYTE ,'[,'A .BYTE ,'[,'6,'C .ENDC .BYTE ; TERMINATOR ; DIGIT ONE. DIG1: .BYTE , .REPT 7 .BYTE ,, .ENDR .IF DF VT52 .REPT 7 .BYTE ,'A .ENDR .REPT 4 .BYTE ,'C .ENDR .IFF ; VT100 .BYTE ,'[,'7,'A .BYTE ,'[,'4,'C .ENDC .BYTE ; TERMINATOR ; THE DIGIT 2. DIG2: .BYTE ,,,,, .REPT 3 .BYTE ,, .ENDR .REPT 4 .BYTE ,, .ENDR .REPT 3 .BYTE ,, .ENDR .IF DF VT52 .BYTE ,'C,,,,, .REPT 6 .BYTE ,'A .ENDR .IFF .BYTE ,'[,'C,,,,, .BYTE ,'[,'6,'A .ENDC .BYTE ; DIG3: .BYTE ,,,,, ; THREE .REPT 6 .BYTE ,, .ENDR .BYTE ,,,,,,, .IF DF VT52 .REPT 3 .BYTE ,'A, .ENDR .IFF .REPT 3 .BYTE ,'[,'A, .ENDR .ENDC .BYTE ,,,, .IF DF VT52 .REPT 3 .BYTE ,'A,,'C .ENDR .IFF .REPT 3 .BYTE ,'[,'A,,'[,'C .ENDR .ENDC .BYTE ; DIG4: .REPT 3 ; FOUR .BYTE ,, .ENDR .BYTE ,,,,,,, .IF DF VT52 .REPT 7 .BYTE ,'A,, .ENDR .BYTE ,'C,, .IFF .REPT 7 .BYTE ,'[,'A,, .ENDR .BYTE ,'[,'C,, .ENDC ; DIG5: .BYTE ,,,,,,,,, ; FIVE .REPT 3 .BYTE ,, .ENDR .BYTE ,,, .REPT 4 .BYTE ,, .ENDR .IF DF VT52 .BYTE ,'A,,,,,,,, .REPT 6 .BYTE ,'A .ENDR .IFF .BYTE ,'[,'A,,,,,,,, .BYTE ,'[,'6,'A .ENDC .BYTE ,, ; DIG6: .REPT 6 ; SIX .BYTE ,, .ENDR .BYTE ,,,, .IF DF VT52 .REPT 3 .BYTE ,,'A, .ENDR .IFF .REPT 3 .BYTE ,,'[,'A, .ENDR .ENDC .BYTE ,,,,,,,, .IF DF VT52 .REPT 3 .BYTE ,'A .ENDR .IFF .BYTE ,'[,'3,'A .ENDC .BYTE ; DIG7: .BYTE ,,,, ; SEVEN .REPT 6 .BYTE ,, .ENDR .IF DF VT52 .REPT 6 .BYTE ,'A .ENDR .BYTE ,'[,'6,'A .ENDC .BYTE , ; DIG8: .BYTE ,,,,, ; EIGHT .REPT 6 .BYTE ,, .ENDR .REPT 4 .BYTE ,, .ENDR .IF DF VT52 .REPT 5 .BYTE ,'A,, .ENDR .IFF .REPT 5 .BYTE ,'[,'A,, .ENDR .ENDC .BYTE ,,,,,, .IF DF VT52 .REPT 3 .BYTE ,'A .ENDR .IFF .BYTE ,'[,'3,'A .ENDC .BYTE , ; DIG9: .BYTE ,,,,,,,,, ; NINE .REPT 3 .BYTE ,, .ENDR .BYTE ,,,, .IF DF VT52 .BYTE ,'A,,'A .IFF .BYTE ,'[,'2,'A .ENDC .REPT 6 .BYTE ,, .ENDR .IF DF VT52 .REPT 7 .BYTE ,'A .ENDR .IFF .BYTE ,'[,'7,'A .ENDC .BYTE ,, .EVEN .SBTTL INTRO - INTRODUCTORY TEXT ; ; INTRODUCTORY TEXT: ; .IF DF VT52 INTRO: .BYTE ,'H,,'J,,'G,,'>, .IFF INTRO: .BYTE ,'<,,'[,'H,,'[,'J,,'(,'B,,'> .BYTE ,'[,'1,';,'7,'m, .ENDC .ASCII /Welcome to Video Terminal Pong. Here's how it works:/ .IF NDF VT52 .BYTE ,'[,'m .ENDC .BYTE ,,, .ASCII /LEFT Player keys:/ .BYTE , .ASCII / Q = Paddle up slowly / .ASCII / W = Paddle up quickly/ .BYTE , .ASCII / A = Paddle down slowly / .ASCII / S = Paddle down quickly/ .BYTE ,, .ASCII / T = cop out (replace paddle with wall until next / .ASCII /move command)/ .BYTE ,,, .ASCII /RIGHT Player keys:/ .BYTE , .ASCII / 6 = Paddle up slowly / .ASCII / 5 = Paddle up quickly/ .BYTE , .ASCII / 3 = Paddle down slowly / .ASCII / 2 = Paddle down quickly/ .BYTE ,, .ASCII / P = cop out (replace paddle with wall until next move / .ASCII /command)/ .BYTE ,,, .ASCII /EITHER Player keys:/ .BYTE ,, .ASCII / R = Rapid ball, N = NORMAL TOO MANY/ .BYTE , .ASCII / H = Half paddle, F = FULL BACK COURT MOVES/ .BYTE , .ASCII / I = Intro re-list AND YOU'RE/ .BYTE , .ASCII % CTRL/C or CTRL/Z = Exit game HALF-FAST% .BYTE , .ASCII / G = GAME START/ .BYTE .EVEN .SBTTL NARRATIVE ;+ ; VTPONG: ; RSX-11M task to play Ping Pong using VT52 or VT55 terminal ; strictly free fun: not for commercial or monetary use. ; ; Environment: ; VT100, 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. ; ; Features: ; Beep when ball hits. ; '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 VT52 graphic bar characters ; 8 (5 on VT100) bar positions per vertical character space ; top 8 print, bottom 2 are blank. ; ; Build Procedure: ; ; >MAC PNG=PNG ! Must define VT52=0 for VT52/VT55 version. ; >TKB ; TKB>PNG/CP/-FP=PNG ; / ; ENTER OPTIONS: ; TKB>ASG=TI:5:6 ; TKB>// ; ;- .SBTTL INITIALIZE ; PNG:: DIR$ #ATT5 ; ATTACH WITH UNSOLICITED AST INPUT ; RESTART ENTRY POINT. BEGIN: MOVB #CTRLZ,BUF ; SELF-DESTRUCT UNLESS KEPT ALIVE INC PADLOK ; IGNORE KB PADDLE MOVES MOV #INTRO,R5 ; INTRODUCTION LIST CALL WRT ; WRITE INTRODUCTION PAGE DIR$ #INTQIO ; LOOK FOR 1 CHAR DIR$ #INTRMR ; LOOK FOR TIMEOUT DIR$ #INTRWT ; ACT UPON EITHER BICB #240,BUF ; LOP OFF PARITY AND LOWERCASE BITS CMPB BUF,#CTRLZ ; END OF GAME REQUESTED ? BNE DWCORT ; IF NE, NO JMP DONE ; FINISHED GAME ; DRAW THE COURT. DWCORT: MOV #DCOURT,R5 ; DRAW THE COURT CALL WRT ; DRAW COURT, SET GRAPHICS MODE MOV #PBUFLB,R5 ; SET TO WRITE LEFT PADDLE CALL WRT ; AND DO IT MOV #PBUFRB,R5 ; SET TO WRITE RIGHT PADDLE CALL WRT ; AND DO IT TST INTREL ; WAS INTRO RELIST REQUESTED? BEQ BALLIN ; IF EQ, 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 LEFT SCORE CLR RS ; & RIGHT SCORE MOV PADZI,PADLZ ; INIT PENLTY CREDIT BACKCOURT MOTION MOV PADZI,PADRZ .SBTTL SCORE - DISPLAY BLOCK SCORES SCORE:: CMPB #LEFT,X ; BALL AT LEFT MARGIN ? BNE 10$ ; IF NE, NO INC RS ; YES: BUMP RIGHT SCORE 10$: CMPB #RIGHT,X ; BALL AT RIGHT MARGIN ? BNE DWBLOK ; IF NE, NO INC LS ; YES: BUMP LEFT SCORE ; ; DRAW BLOCK DIGITS FOR SCORE ; DWBLOK: MOV #SCORRC,R5 ; ADR CURS FOR SCORE INC PADLOK ; IGNORE KB MOMENTARILY INC SCORNW ; SHOW SCORE STATE NOW CALL WRT ; WRITE THE SCORE ; ; CVT LEFT SCORE TO BLOCK DIGITS ; MOV LS,R4 ; GET LEFT 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 CALL WRT ; & WRT IT MOV (R4),R5 ; MOV 2ND DIGIT ADR TO WKG REG CALL WRT ; & WRT IT MOV #SCORSP,R5 ; SPACE OVER TO WRT RIGHT SCORE CALL WRT ; ; CVT RT SCOR TO BLOCK DIGITS ; MOV RS,R4 ; GET RIGHT 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 CALL WRT ; & WRT IT MOV (R4),R5 ; MOV 2ND DIGIT ADR TO WKG REG CALL 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$ ; IF EQ, YES (GAME OVER) CMP RS,#15. ; RIGHT SCORE 15. ? BEQ 20$ ; IF EQ, YES (GAME OVER) TST QUIT ; DID PLAYER ASK TO QUIT EARLY ? BEQ 15$ ; IF EQ, NO 10$: JMP DONE ; IF YES, DONE 15$: TST INTREL ; WAS INTRO RELIST REQUESTED ? BEQ SERVE ; IF EQ, NO: SERVE JMP BEGIN ; ELSE DO IT, THEN SERVE ; ; IF THIS GAME RAN TO COMPLETION, ASK IF ANOTHER: ; 20$: CLR INTREL ; CLEAR INTO RELIST FLAG JMP BEGIN ; AND RESTART THE PROGRAM .SBTTL SERVE - SERVE BALL FROM MID COURT 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 ; # OF BEEPS TO OUTPUT CALL BEEP ; AND GO DO IT SERVER:: DIR$ #CERASE ; ERASE THE COURT INC PADLOK ; IGNORE KB MOMENTARILY ; ; SEE IF BOTH PADDLES HV BEEN IN SIMULTANEOUS AUTO TOO LONG: ; AUTLIM: CMPB PADLC,BYTBLA ; LEFT AUT0 ? BNE REPADL ; IF NE, NO CMPB PADRC,BYTBRA ; RIGHT AUTO ? BNE REPADL ; IF NE, NO INC AUTLR ; COUNT # OF TIMES CMP AUTLR,AUTLRM ; FOR MORE THAN MAX # TIMES? BLE REPADL ; IF LE, NO CLRB PADLC ; IF SO, SHUT OFF LEFT AUTO CLRB PADRC ; AND RIGHT AUTO CLR AUTLR ; & RESET COUNT REPADL: MOV #PBUFLB,R5 ; ALSO REDRAW LEFT PADDLE, CMPB PADLC,BYTBLA ; LEFT AUTO ? BNE 10$ ; IF NE, NO MOV #PBUFLA,R5 ; IF SO, WRT LEFT PAD WALL 10$: CALL WRT ; MOV #PBUFRB,R5 ; & RIGHT CMPB PADRC,BYTBRA ; RIGHT AUTO ? BNE 20$ ; IF NE, NO MOV #PBUFRA,R5 ; IF SO, WRT RIGHT PAD WALL 20$: CALL WRT CLR PADLOK ; RESTORE KB CLR SCORNW ; TURN OFF 'SCORING NOW' STATE DIR$ #SETEFB ; INITIALLY SIGNIFY BALL MOVED O.K. .SBTTL SLEEP - NEXT BALL POSITIONING & TIMING 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$ ; IF LE, YES SUB #YFINEL,YFINE ; NO, FURTHER DOWN INC Y ; SET FOR NEXT ROW ; ; NOTE: THE CHECK FOR THE Y BOUNDRYS WAS ADDED HERE BECAUSE A ; WINDOW EXISTED WHERE THE Y BOUNDRYS WOULD NOT GET CHECKED ; IF THE BALL HIT IN THE TOP OR BOTTOM OF THE COURT. ; ; CHECK FOR Y AT BOTTOM OF COURT. CMP Y,#BOTTOM ; BOTTOM OF COURT ? BNE XBND ; IF NE, NO (CHECK X) TST YINCR ; GOING UP ALREADY ? BMI XBND ; IF MI, YES (LEAVE ALONE) NEG YINCR ; REVERSE DIRECTION BR XBND ; AND CONTINUE... 5$: TST YFINE BGT XBND ; YES ADD #YFINEL,YFINE ; NO, FURTHER UP DEC Y ; CHECK FOR Y AT TOP OF COURT. CMP Y,#TOP ; TOP OF COURT ? BNE XBND ; IF NE, NO (CHECK X) TST YINCR ; GOING DOWN ALREADY ? BPL XBND ; IF PL, YES (LEAVE ALONE) NEG YINCR ; REVERSE DIRECTION ; ; TEST IF BALL AT X BNDRY: ; XBND:: CMP #LEFT,X ; X AT LEFT MARGIN ? BNE XBND2 ; IF NE, NO (CHECK RIGHT) ; ; X AT LEFT BOUNDARY: ; XBNDL:: CMPB PADLC,BYTBLA ; LEFT AUTO (WALL)? BEQ SWAT ; IF EQ, YES: ALWAYS SWAT MOV PADLY,R0 ; ELSE MOVE PADDLE Y TO R0, BR BNDX ; & USE COMMON BOUNDARY CODE XBND2:: CMP #RIGHT,X ; X AT RIGHT MARGIN ? BNE YBND ; IF NE, NO (CHECK Y BOUNDARYS) ; ; X AT RIGHT BOUNDARY: ; XBNDR:: CMPB PADRC,BYTBRA ; RIGHT AUTO (WALL) ? BEQ SWAT ; IF EQ, 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 ; IF EQ, 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 1 HIGHER THAN ACT CMP R0,Y ; NOW DOES IT MATCH BALL? BNE BNDBSP ; IF NE, 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 ; IF GE, 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 ; IF NE, YES ; ; FULL PADDLE BEING USED: R0 NOW PTS TO 2ND HALF OF IT: ; BNDFUL:: CMP R0,Y ; PADDLE BOT HALF MATCH BALL? BEQ SWAT ; IF EQ, 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 ; IF NE, 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 ; IF LE, YES BR GONE ; ELSE MISSED ; ; MISSED ; GONE:: INC PADLOK ; PREVENT FURTHER PADDLE MOTION CALL SAILER ; CALC & WRT LAST BALL MOV #3,R5 ; # OF BEEPS TO OUTPUT CALL BEEP ; AND GO DO IT JMP SCORE ; GO WRITE THE SCORE ; ; HIT ; SWAT:: NEG XINCR ; REVERSE HORIZ SENSE CALL SPDCHG ; SEE IF SPEEDUP CALL YINCRM ; MODIFY YINCR ; ; RESET SUCCESSFUL SWATTER'S BACKCOURT PENALTY COUNT: ; CMP #RIGHT,X ; ARE WE AT RIGHT MARGIN ? BEQ PADRZI ; IF EQ, YES PADLZI: MOV PADZI,PADLZ ; RESET LEFT PENALTY COUNT BR BEEP1 PADRZI: MOV PADZI,PADRZ ; RESET RIGHT PENALTY COUNT BEEP1: MOV #1,R5 ; # OF BEEPS TO OUTPUT CALL BEEP ; AND GO DO IT JMP SERVER ; ERASE PREV PATH ; ; BALL IS NOT AT X BOUNDRY: CHECK Y BOUNDRYS (TOP & BOTTOM). ; *** NOTE: THIS CHECK IS ONLY MADE IF BALL IS NOT AT X BOUNDRY *** ; YINCR IS MODIFIED ABOVE IN BALL, IT IS NOT NEEDED HERE. ; YBND:: YBNDT:: CMP Y,#TOP ; TOP OF COURT ? BNE YBNDB ; IF NE, NO (CHECK BOTTOM) ;* TST YINCR ; GOING DOWN ALREADY ? ;* BPL SAIL ; IF PL, YES (LEAVE ALONE) BR SIDE ; NO: REVERSE (BOUNCE) ; CHECK FOR Y AT BOTTOM OF COURT. YBNDB:: CMP Y,#BOTTOM ; BOTTOM OF COURT ? BNE SAIL ; IF NE, NO (SAIL BALL) ;* TST YINCR ; GOING UP ALREADY ? ;* BMI SAIL ; IF MI, YES (LEAVE ALONE) ; ; BALL AT TOP OR BOT & GOING THRU: REVERSE (BOUNCE) ; SIDE:: ;* NEG YINCR ; REVERSE VERT SENSE MOV #1,R5 ; # OF BEEPS TO OUTPUT CALL BEEP ; AND GO DO IT JMP SLEEP ; WAIT FOR NEXT BALL JUMP ; ; BALL IN FREE SPACE: SAIL ; SAIL:: CALL SAILER ; CALC & WRT NEXT BALL JMP SLEEP ; WAIT FOR NEXT BALL JUMP .SBTTL DONE - GAME OVER, CLEANUP DONE:: DSAR$S ; DISABLE PADDLES DIR$ #KIL5 ; CANCEL OTHER I/O DIR$ #ERASE ; ERASE SCREEN DIR$ #DET5 ; DETACH THE TERMINAL EXIT$S ; AND FINALLY EXIT .SBTTL PAD - 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) CMPB BYTBS,#CTRLC ; CONTROL/C TYPED ? BEQ QIT ; YEP, PREPARE TO QUIT CMPB BYTBS,#CTRLZ ; CONTROL/Z TYPED ? BEQ QIT ; YEP, PREPARE TO QUIT ; ; DON'T PUT OUT QIO'S IF THEY'D MESS UP NON-AST CURSOR ADDR ; (SCORE OR DRAW COURT/PADDLES IN PROGRESS) ; TST PADLOK ; LOCK OUT PADDLE COMMANDS ? BEQ PADACT ; IF EQ, NO JMP PADDON ; YES, SO IGNORE COMMAND ; ; 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 COMMAND TABLE BEQ PADJMP ; MUST FIND MATCH (MAYBE STOPPER) TST (R0)+ ; POINT TO NEXT ENTRY BR PADCMP ; AND LOOP ... 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 #SPACE,R2 ; PREP TO MAKE 2ND HALF FULL PAD BLANK BR CHGPAD FULPAD: CLR PADHAF ; CLR HALF-PADDLE FLG .IF DF VT52 MOV #BOX,R2 ; PREP TO MAKE 2ND HALF FUL PD SOLID RECT .IFF MOV #BAR,R2 ; .ENDC ; ; 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 CALL PADM2 ; MOVE CHR INTO 2ND HALF OF PADDLE ;* ADD #2,R1 ; GET BFR ADR PBUFLB, ;* MOV R1,PADQIO+Q.IOPL ; & PUT INTO DPB MOV #PBUFLB,PADQIO+Q.IOPL ; SET ADDRESS OF PBUFLB DIR$ #PADQIO ; WRT NEW LEFT 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 CALL PADM2 ; MOVE CHR INTO 2ND HALF OF PADDLE ;* ADD #2,R1 ; GET BFR ADR PBUFRB, ;* MOV R1,PADQIO+Q.IOPL ; & PUT INTO DPB MOV #PBUFRB,PADQIO+Q.IOPL ; SET ADDRESS OF PBUFRB DIR$ #PADQIO ; WRT NEW RIGHT 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:: ;* BPT ; BREAK POINT TO ODT (FOR DEBUG ONLY) 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 ; SMALL AMOUNT UP BR LP LDS: MOV #PSAD,R0 ; SMALL AMOUNT DOWN BR LP LUL: MOV #PLAU,R0 ; LARGE AMOUNT UP BR LP LDL: MOV #PLAD,R0 ; LARGE AMOUNT DOWN LP: MOV #PADLY,R1 MOVB BYTBS,PADLC ; SAVE LAST CMD ; ; FORGET ABOUT PENALTIES DURING SCORE STATE: ; CSLF: TST SCORNW ; SCORE STATE NOW ? BEQ CSL ; IF EQ, 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 ; IF MI, 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 ; IF GT, 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 ; SMALL AMOUNT UP BR RP RDS: MOV #PSAD,R0 ; SMALL AMOUNT DOWN BR RP RUL: MOV #PLAU,R0 ; LARGE AMOUNT UP BR RP RDL: MOV #PLAD,R0 ; LARGE AMOUNT DOWN RP: MOV #PADRY,R1 MOVB BYTBS,PADRC ; SAVE LAST CMD ; ; FORGET ABOUT PENALTIES DURING SCORE STATE: ; CSRF: TST SCORNW ; SCORE STATE NOW? BEQ CSR ; IF EQ, 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 ; IF PL, TOWARD RIGHT ; ; 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 ; IF GT, 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: ; R0 = AMOUNT TO MOVE PADDLE. ; PADMOV:: MOVB #SPACE,R2 ; FIRST WRT BLANK CALL PADM ; IN OLD PADDLE LOC TO ERASE .IF DF VT52 MOVB #BOX,R2 ; NOW SOLID RECT IS NEW PAD CHR .IFF MOVB #BAR,R2 ; VERTICAL BAR NEW PAD CHARACTER .ENDC MOV (R1),R3 ; PADDLE Y 10$: ADD R0,R3 ; FIGURE NEW TENTATIVE PADDLE Y MOV R3,(R1) ; & STORE NEW Y VALUE TST R3 ; HIGHER THAN (TOP-1) ? BGE 15$ ; IF GE, NO MOV #-1,(R1) ; YES: STORE TOP-2 & SHOW X BR 20$ 15$: CMP R3,#BOTTOM ; LOWER THAN BOT? BLE 20$ MOV #BOTTOM,(R1) ; YES: STORE BOT+1 & SHOW X INC (R1) MOVB #'X,R2 20$: CALL PADM ; PUT NEW PADDLE CHR IN ARRAY ADD #2,R1 ; POINT TO BUFFER ADRESS PADWRT:: MOV R1,PADQIO+Q.IOPL ; & PUT INTO DPB DIR$ #PADQIO ; WRT NEW PADDLE PADDON: MOV (SP)+,R3 ; RESTORE R0-R3 FROM 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 ; COPY Y VALUE ; ; DON'T WRITE OUTSIDE ARRAY ; BGT 5$ ; IF GT, OK MOV #1,R3 ; IF .LE. 0, MAKE TOP .IF DF VT52 CMP R2,#BOX ; WAS PAD CHR ASKED? .IFF CMP R2,#BAR ; WAS PAD CHARACTER ASKED ? .ENDC BNE PADM1 ; IF NE, NO MOVB #'X,R2 ; IF SO, REPLACE WITH X BR PADM1 ; AND CONTINUE... 5$: CMP R3,#BOTTOM ; GOING PAST BOTTOM ? BLE PADM1 ; IF LE, NO DEC R3 ; IF B+1, MAKE BOTTOM ; ; WITHIN ARRAY: CALC BYTE ADR & MOVE IT IN ; R1 = ADDRESS OF Y VALUE WORD. ; R2 = CHARACTER TO PUT IN ARRAY. ; R3 = Y VALUE (LINE NUMBER). ; PADM1:: MUL #3,R3 ; *3 TO GET OFFSET INTO ARRAY ADD #YOFF,R3 ; + OFFSET TO SKIP OVER CURS ADR ADD R1,R3 ; + PADDLE DB BEGIN=PADDLE CHR ADR MOVB R2,(R3) ; REPLACE CHARACTER IN ARRAY ; ; SEE IF FULL PADDLE BEING USED: ; TST PADHAF ; HALF PADDLES ONLY? BNE PADM5 ; IF NE, YES: RETURN ; ; FULL PADDLES: ; 15$: TST BOTH ; BOTH HALVES DONE? BNE PADM4 ; IF NE, YES PADM2:: INC BOTH ; ELSE SET FLG SHOWING 2ND HALF MOV (R1),R3 ; RESTORE ORIGINAL Y VALUE BLT PADM4 ; IF LT, IT WOULD MAKE 2ND HALF ALSO HIGHER ; THAN TOP BGT 35$ ; IF GT, 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$ ; IF NE, YES CMP R2,#SPACE ; WAS NEW PAD CHR BLANK? BEQ 40$ ; IF EQ, YES: LEAVE AS IS .IF DF VT52 MOV #BOX,R2 ; ELSE BE SURE 'X IS REPL W SOLID RECT .IFF MOV #BAR,R2 ; REPLACE 'X WITH VERTICAL BAR .ENDC BR 40$ ; ; PADDLE SIZE CHG 2ND HALF RE-DO: ; 30$: CMP R2,#SPACE ; WAS NEW PAD CHR BLANK? BNE 40$ ; IF NE, 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,#BOTTOM ; WAS ORIG Y AT BOTTOM OR BELOW? BGE PADM4 ; IF GE, 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: RETURN ; ; SEE IF SPEEDUP ; SPDCHG: CMP SPEED,SPEEDS ; FIRST HIT AFTER SERVE? BNE SPDC ; IF NE, 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: RETURN ; ; CHANGEG YINCR ON BOUNCE: ; YINCRM:: MOV YINCR,R0 ; MOV CURR YINCR TO R0 TST R0 ; NEGATIVE ? BPL 5$ ; IF PL, NO NEG R0 ; CONVERT TO POSITIVE 5$: INC R0 ; AND BUMP IT CMP R0,#YINCRL ; ABOVE LIMIT ? BLE 10$ ; IF LE, NO MOV #1,R0 ; YES: RESET TO 1 10$: TST YINCR ; WAS PREV NEGATIVE ? BPL 15$ ; IF PL, NO NEG R0 ; MAKE IT POSITIVE 15$: MOV R0,YINCR ; PUT NEW INTO OLD RETURN .SBTTL BEEP - OUTPUT BEEP (BELL) CHARACTERS ;+ ; ; BEEP, OUTPUT BEEP (BELL) CHARACTERS ; R5 = # OF TIMES TO BEEP. ; ;- BEEP:: DIR$ #BEEPO ; OUTPUT A BEEP DIR$ #BEEPMR ; BEEP MARKTIME BCS 10$ ; IF CS, DON'T WAIT DIR$ #BEEPWT ; WAIT FOR MARKTIME DEC R5 ; MORE BEEPS ? BGT BEEP ; IF GT, YES 10$: RETURN ; ELSE, RETURN .SBTTL WRT - WRITE-ALL STRING TO THE TERMINAL ;+ ; ; WRT, WRITE A BYTE STRING W NULL STOPPER ; R5 = ADDRESS OF STRING TO OUTPUT ; ;- WRT:: JSR R2,$SAVVR ; SAVE R0 - R2 MOV #BUF,R0 ; OUTPUT BUFFER 10$: MOVB (R5)+,(R0)+ ; MOVE A BYTE OUT TSTB (R5) ; NEXT BYTE NULL ? BEQ 20$ ; IF EQ, YES CMP R0,#BUF+BUFL ; BUFFER FULL ? BNE 10$ ; IF NE, NO 20$: SUB #BUF,R0 ; CALCULATE BYTE COUNT MOV R0,VTW+Q.IOPL+2 ; THEN TO DPB DIR$ #VTW ; OUTPUT THE BUFFER TSTB (R5) ; WRITE EVERYTHING ? BNE WRT ; IF NE, NO (LOOP) RETURN .SBTTL SAILER - SAIL BALL IN FREE SPACE ;+ ; ; SAILER, SAIL BALL IN FREE SPACE ; ;- SAILER:: .IF DF VT52 MOV Y,R0 ; VERT POS ADD #BIAS,R0 ; + CHR BIAS MOVB R0,BALMOR ; TO ROW CURS ADR MOV X,R0 ; HORIZ POS ADD #BIAS,R0 ; + CHR BIAS MOVB R0,BALMOC ; TO COL CURS ADR .IFF ; VT100 JSR R2,$SAVVR ; SAVE R0 - R2 MOV #BALMOR,R0 ; SET OUTPUT ADDRESS MOV Y,R1 ; VERT POS MOV #11012,R2 ; RADIX=10.,NOSUP,WIDTH=2 CALL $CBTA ; DO THE CONVERSION MOV #BALMOC,R0 ; SET OUTPUT ADDRESS MOV X,R1 ; HORIZONTAL POSITION MOV #11012,R2 ; RADIX=10.,NOSUP,WIDTH=2 CALL $CBTA ; DO THE CONVERSION .ENDC MOV YFINE,R0 ; LINE WITHIN BAR CHR MOVB BALCHR(R0),BALMOL ; TO BAR CHR (BALL) DIR$ #BALLJP ; MOVE BALL PATH RETURN .END PNG ; TRANSFER ADDRESS