.TITLE SHIPS .IDENT /V 1.0/ ;+ ; SHIPS.MAC ; ; WRITTEN 3/10/81 BY M.D.LAMPI ; ; THIS PROGRAM MAKES USE OF THE TELERAY-12 TERMINAL SCREEN CONTROL ; CHARACTERISTICS (INSERT CHARACTER/DELETE CHARACTER, ETC.) TO MAKE ; A SIMPLE SHIP VS. SUBMARINES GAME WHERE YOU, THE USER, CONTROL THE ; RIGHT/LEFT MOTION OF THE SHIP WITH THE RIGHT & LEFT ARROW KEYS AS ; WELL AS CONTROL THE FIRING OF A DEPTH CHARGE. THE SUBMARINES (MAX. ; OF 3 AT ANY ONE TIME) ARE CONTROLLED BY THE COMPUTER AND WILL, AT ; SOME TIME IN THE FUTURE, FIRE BACK AT THE SHIP. NOTE THAT THIS IS ; AN UNFINISHED VERSION AND NOT ALL THE FEATURES WORK AS WELL AS THEY ; SHOULD. SEE ACCOMPANYING .DOC FILE FOR MORE INFO. ; ; WORKS FAIRLY WELL AT 9600 BAUD, MUCH BETTER AT 19.2KB ;- .ENABL LC .MCALL ASTX$S,MRKT$,QIOW$,QIO$,DIR$,STSE$S,EXIT$S,DSCP$S .MCALL SETF$S,CLEF$S ; TIMPER=6 ;UPDATE TIME EVERY 6 CYCLES SUBMAX=3 ;TOTAL OF 3 SUBS SHIPRT=6 ;EVENT FLAGS FOR SHIP CONTROL SHIPLT=7 DFLAG=5 WAITIM=10 ; OBJECT=%3 ;REGISTER DEFINITIONS FOR SUBROUTINES SPEED=%4 LINE=%5 ; START: CLEF$S #DFLAG ;CLEAR DEPTH CHARGE START FLAG DIR$ #CLEAR ;CLEAR SCREEN DIR$ #MRKT ;WAIT A SECOND DSCP$S ;DISABLE CHECKPOINTING STSE$S #2 ;WAIT FOR CLEAR TO TAKE EFFECT DIR$ #SETCHR ;INITIALIZE TERMINAL PARAMETERS CMP #IS.SUC,IOSB ;SEE IF SUCCESSFUL BEQ 5$ ;IF EQ, YES MOV IOSB,R0 ;ELSE ERR OUT TRAP 5$: DIR$ #SETUP ;SET UP SCREEN DIR$ #ESC ;SET UP FOR ESCAPE SEQUENCING DIR$ #AST ;SET UP QIO W/AST NOTIFICATION ; ; MOTION UPDATING STARTS HERE WITH THE DEPTH CHARGE ; 10$: TSTB ENDBYT ;FIRST SEE IF WE SHOULD QUIT BEQ 11$ ;IF EQ, NO JMP ENDIT ;ELSE QUIT 11$: DIR$ #WAITM ;SET UP MARK TIME TST DCHG ;SEE IF DEPTH CHARGE IS MOVING BEQ 17$ ;IF EQ, NO - IGNORE IT ADD DCHGSP,DCHG ;ELSE MOVE IT 'DCHGSP' LINES DOWN CMP #BOT,DCHG ;SEE IF IT HAS HIT BOTTOM BGT 15$ MOV DCHG,R0 ;ELSE BLANK IT OUT SUB DCHGSP,R0 ;POINT TO OLD POSITION FIRST MOV DCHG+2,R1 ; CALL XYPOS MOVB #40,R5 CALL INSBUF CLR DCHG ;CLEAR MOTION FLAG (Y-COORDINATE) BR 20$ 15$: MOV DCHG,R0 ;NOW MOVE IT SUB DCHGSP,R0 ;POINT TO OLD POSITION MOV DCHG+2,R1 MOV DCHGSP,SPEED ;GET SPEED MOVB #'*,OBJECT ;DEFINE OBJECT CALL MOVEV ;MOVE IT VERTICALLY BR 20$ 17$: CLEF$S #DFLAG ;SEE IF DEPTH CHARGE FLAG REQUESTED CMP $DSW,#IS.SET ;WAS IT SET? BNE 20$ ;IF NE, NO - SKIP MOV SHIPX,DCHG+2 ;ELSE START IT MOVING MOV #5,DCHG ; ON LINE 5 MOV #5,R0 MOV SHIPX,R1 CALL XYPOS ;PLACE ON SCREEN MOVB #'*,R5 CALL INSBUF ; ; SHIP MOVEMENT ; 20$: CLEF$S #SHIPRT ;SHIP TO MOVE FASTER RIGHT? CMP $DSW,#IS.SET ;IF SET, YES BNE 21$ ;IF NE, NO INC SHIPSP ;SET - INCREMENT SPEED 21$: CLEF$S #SHIPLT ;SHIP TO MOVE FASTER LEFT? CMP $DSW,#IS.SET ;IF SET, YES BNE 22$ ;IF NE, NO DEC SHIPSP ;SET - INCREMENT SPEED LEFT 22$: TST SHIPSP ;TEST SHIP SPEED BMI 25$ ;IF MI, CHECK LEFT BOUNDS CMP SHIPX,#RIGHT ;SEE IF WITHIN BOUNDS OF SCREEN BGE 30$ ;IF GE, IGNORE MOTION BR 27$ ;ELSE MOVE IT 25$: CMP SHIPX,#LEFT ;SEE IF WITHIN LEFT BOUNDS BLE 30$ ;IF LE, IGNORE MOTION 27$: MOV #3,LINE ;MOVE SHIP MOV SHIPSP,SPEED CALL MOVEH ADD SHIPSP,SHIPX ;ADD SHIP X INCREMENT ; ; SUB MOVEMENT ; 30$: CLR SUBIDX ;GO THROUGH SUB LOOP NOW 31$: MOV SUBIDX,R0 TST SUBX(R0) ;THIS SUB ACTIVE? BNE 40$ ;IF NE, YES CALL RANDOM ;ELSE SEE IF WE SHOULD START IT GOING BCC 50$ ;IF CC, FORGET IT MOV SUBSX(R0),SUBX(R0);SET UP STARTING POSITION MOV SUBSX(R0),R1 MOV SUBSY(R0),R0 ;SET UP FOR XYPOS CALL XYPOS MOV #SUBDFL,R0 ;NOW SET UP TO DISPLAY SUB MOV #SUBDEF,R1 32$: MOVB (R1)+,R5 CALL INSBUF ;INSERT CHARACTERS INTO BUFFER SOB R0,32$ ; A CHARACTER AT A TIME BR 50$ ;THEN TRY NEXT SUB ; 40$: MOV SUBSY(R0),LINE ;MOVE EXISTING SUB CMP SUBX(R0),#RIGHT ;SEE IF UP AGAINST THE WALL BGE 45$ ;IF GE, YES CMP SUBX(R0),#LEFT ;AND AGAIN BGT 46$ ;IF GT, ALL IS O.K. 45$: CALL POSITN MOVB #33,R5 ;PAST BOUNDARIES - CLEAR THE LINE CALL INSBUF MOVB #'k,R5 CALL INSBUF MOV SUBIDX,R0 ;RESTORE INDEX CLR SUBX(R0) ;SHOW NO MOTION FOR THIS SUB BR 60$ 46$: ADD SUBSP(R0),SUBX(R0) ;MOVE IT ALONG MOV SUBSP(R0),SPEED ;USE MOVEH TO MOVE IT CALL MOVEH 50$: TST DCHG ;DEPTH CHARGE ACTIVE? BEQ 60$ ;IF EQ, NO - IGNORE MOV SUBIDX,R0 ;ELSE GET POINTER TO SUB DATABASE CMP DCHG,SUBSY(R0) ;SEE IF D.C. IS ON SAME LINE AS THIS SUB BNE 60$ ;IF NE, NO - IGNORE MOV SUBX(R0),R1 ;GET CURRENT SUB X POSITION (LEFT EDGE) SUB SUBSP(R0),R1 ;COMPUTE OLD LEFT EDGE (BEFORE IT MOVED) CMP R1,DCHG+2 ;DEPTH CHARGE ON LEFT OF SUB? BLT 55$ ;IF LT, NO 53$: MOV DCHG+2,R1 ;DEPTH CHARGE MISSED SUB - BLANK OUT D.C. ADD SUBSP(R0),R1 ;NEW D.C. POSITION AFTER SUB REPOSITIONING MOV DCHG,R0 ; MOVED IT FROM TRUE POSITION CALL XYPOS ;POSITION TO NEW D.C. POSITION MOVB #40,R5 ;BLANK IT OUT CALL INSBUF BR 60$ ;ALL DONE 55$: MOV SUBX(R0),R1 ;SEE IF D.C. ON RIGHT OF SUB ADD #SUBDFL,R1 ;ADD LENGTH OF SUB CMP R1,DCHG+2 ;D.C. HIT SUB?? BLE 53$ ;IF LE, NO ; ; D.C. HAS HIT SUB ; ADD SCRHIT(R0),SCOREB ;ADD NEW SCORE TO PLAYER'S TOTAL CALL SCORER ;DISPLAY NEW SCORE MOV SUBIDX,R0 ;POINT TO THIS SUB MOV SUBSY(R0),LINE ;POSITION TO LINE OF THIS SUB CLR SUBX(R0) ;ZAP SUB X POSITION (CLEAR ACTIVE FLAG) CLR DCHG ;ZAP DEPTH CHARGE ACTIVE FLAG (Y POSITION) CALL POSITN ; MOVB #33,R5 ;USE CLR EOLN (ESC k) CALL INSBUF MOVB #'k,R5 CALL INSBUF 60$: ADD #2,SUBIDX ;INCREMENT INDEX CMP #SUBMAX*2,SUBIDX ;DONE WITH SUBS? BGT 31$ ;IF GT, NO CALL BUFCHK ;SEE IF BUFFER FULL STSE$S #WAITIM ;WAIT A CYCLE DEC TIMFLG ;SEE IF WE SHOULD UPDATE TIME BNE 100$ ;IF PL, NO DEC TIMEB ;DECREMENT TIME CALL TIMER ;DISPLAY ON SCREEN TST TIMEB ;GAME OVER?? BEQ ENDIT ;IF EQ, YES - QUIT MOV #TIMPER,TIMFLG ;RESET COUNTER ; 100$: JMP 10$ ; ; ENDIT - ENDS THE GAME ; ENDIT: DIR$ #KILLER ;KILL ANY PENDING I/O DIR$ #KILLER ;ONCE MORE FOR GOOD MEASURE EXIT$S ;GOODBYE, CHARLIE ; ; AST HANDLER FOR TERMINAL INPUT ; ASTRTN: TST (SP)+ ;IGNORE IOSB ADDRESS CMP #IS.ESQ,IOSB ;SEE IF ESCAPE SEQUENCE TERMINATED IT BNE 30$ ;IF NE, NO - FORGET IT 10$: CMPB #'C,INBUF+1 ;MOVE RIGHT? BNE 12$ ;IF NE, NO CMP #3,SHIPSP ;SEE IF ALREADY AT 3 BLE 30$ ;IF LE, YES SETF$S #SHIPRT ;ELSE BUMP UP THE SPEED BR 30$ ;THEN RETURN 12$: CMPB #'D,INBUF+1 ;MOVE LEFT? BNE 14$ ;IF NE, NO CMP #-3,SHIPSP ;SEE IF ALREADY AT -3 BGE 30$ ;IF GE, YES SETF$S #SHIPLT ;ELSE BUMP (UP) DOWN SPEED BR 30$ ;THEN RETURN 14$: CMPB #'H,INBUF+1 ;DROP DEPTH CHARGE? BNE 20$ ;IF NE, NO TST DCHG ;DEPTH CHARGE ALREADY FIRED? BNE 30$ ;IF NE, YES - IGNORE FIRING REQUEST SETF$S #5 ;INDICATE THAT THE DEPTH CHARGE SHOULD START BR 30$ 20$: CMPB #'d,INBUF+1 ;LOWER-CASE D? (TELERAY-12 BACK TAB?) BNE 30$ ;IF NE, NO MOVB #1,ENDBYT ;YES - INDICATE THAT PLAYER WANTS QUITS 30$: DIR$ #AST ;START UP I/O AGAIN ASTX$S ;ELSE RETURN FROM AST ; RIGHT=80.-7. LEFT=3. BOT=22. TIMFLG: .WORD TIMPER ;TIME COUNTER SCOREB: .WORD 0 ;SCORE (BINARY) TIMEB: .WORD 200. ;TIME (BINARY) SHIPX: .WORD 38. ;SHIP'S LEFT SIDE STARTS AT COL. 38. SHIPSP: .WORD 0 ;SHIP SPEED STARTS AT 0 SUBIDX: .WORD 0 ;CURRENT SUB POINTER SUBX: .WORD 0,0,0 ;SUB POSITIONS START AT 0 SUBSP: .WORD 3,-2,1 ;SUB SPEEDS START AS INDICATED SUBSX: .WORD LEFT+1,RIGHT-1,LEFT+1 ;INITIAL SUB POSITIONS SUBSY: .WORD 12.,16.,20. ; SCRHIT: .WORD 5,10.,30. ;SCORES FOR HITING SUBS MSLX: .WORD 0,0,0 ;MISSILE POSITIONS START AT 0,0 MSLY: .WORD 0,0,0 MSLSP: .WORD 3,3,3 ;MISSILES MOVE FAST DCHG: .WORD 0,0 ;DEPTH CHARGE STARTS AT 0,0 DCHGSP: .WORD 1 ;DEPTH CHARGE MOVES SLOW DOWN ; MRKT: MRKT$ 2,20,1 ;WAIT 20 TICS WAITM: MRKT$ WAITIM,60/TIMPER,1 ;WAIT EVEN SECOND INTERVALS ; CLEAR: QIOW$ IO.WVB,5,1,,,, SETUP: QIOW$ IO.WVB,5,1,,,, ESC: QIOW$ IO.ATT!TF.ESQ,5,1 SETCHR: QIOW$ SF.SMC,5,1,,IOSB,, AST: QIO$ IO.RNE,5,3,,IOSB,ASTRTN, KILLER: QIOW$ IO.KIL,5,17 ;KILL ANY ACTIVE I/O ; IOSB: .BLKW 2 ;I/O STATUS BLOCK INBUF: .BLKW 2 ;INPUT BUFFER ; ; SETCHB: .BYTE TC.ESQ,1 ;ENABLE ESCAPE SEQUENCES .BYTE TC.ACR,0 .BYTE TC.WID,255. ;WIDTH AT 255. CHARACTERS .BYTE TC.RAT,1 ;TYPEAHEAD BUFFERING .BYTE TC.FDX,1 ;FULL-DUPLEX SETCHL=.-SETCHB ; ENDBYT: .BYTE 0 ;FLAG TO INDICATE USER WANTS QUITS ; CLEARB: .BYTE 33,'h,33,'r ;SET UP BUFFERING, ERASE SCREEN CLEARL=.-CLEARB ; SETUPB: .BYTE 33,'Y,'#,40 ;PUT WAVES ON LINE 4 .REPT 20. .ASCII /~~~~/ .ENDR .BYTE 33,'Y,'",'E ;PUT SHIP ON LINE 3, COLUMN 38 .ASCII "\____/" .BYTE 33,'Y,40,'# ;PUT SCORE ON LINE 1, COLUMN 4 .ASCII /Score: / ;NUMBERS FOR SCORE START IN SCORE: .ASCII /00000/ ; COLUMN 11 .ASCII <33>/Y dTime: / ;TIME STARTS IN COLUMN 75 TIME: .ASCII /00000/ ; SETUPL=.-SETUPB ; SUBDEF: .BYTE '< .ASCII /%%%>/ ;NEED TO DO DO IT THIS WAY RATHER THAN <%%%> SUBDFL=.-SUBDEF ; .EVEN ; ; XYPOS - INSERT ESCAPE SEQUENCE TO POSITION TO AN X,Y LOCATION ; ON SCREEN. ; R0 - LINE (1 IS TOP, 24 IS BOTTOM) ; R1 - COLUMN (1 IS LEFT, 80 IS RIGHT) ; XYPOS: MOVB #33,R5 ;ESCAPE SEQUENCES START WITH ESC CALL INSBUF ; MOVB #'Y,R5 ;POSITIONING STARTS WITH ESC Y CALL INSBUF ADD #37,R0 ; ADD #37,R1 ; MOV R0,R5 ;LINE COMES NEXT CALL INSBUF MOV R1,R5 ;FINALLY, THE COLUMN CALL INSBUF RETURN ; ; ; MOVEH - MOVE HORIZONTAL ; MOVEH: TST SPEED ;OBJECT MOVING? BEQ 50$ ;IF EQ, NO 10$: CALL POSITN ;POSITION TO OBJECT TST SPEED ;MOVING RIGHT OR LEFT? BPL 30$ ;IF PL, MOVING RIGHT 20$: CALL MOVEL ;MOVE IT ONCE LEFT INC SPEED ;LOOP UNTIL BNE 20$ ; ALL MOVED BR 40$ ;THEN FINISH UP 30$: CALL MOVER ;MOVE IT ONCE RIGHT SOB SPEED,30$ ;LOOP UNTIL MOVED ; 40$: CALL BUFCHK ;CHECK IF BUFFER FULL 50$: RETURN ;THEN RETURN ; ; MOVEV - MOVE OBJECT UP/DOWN ; MOVEV: TST SPEED ;OBJECT MOVING? BEQ 50$ ;IF EQ, NO CALL XYPOS ;POSITION TO OBJECT MOVB #40,R5 ;BLANK OUT OBJECT CALL INSBUF MOVB #10,R5 ;BACK UP OVER BLANKED-OUT SPOT CALL INSBUF TST SPEED ;MOVING UP OR DOWN? BPL 30$ ;IF PL, DOWN 20$: CALL MOVEU ;MOVE UP INC SPEED ;LOOP UNTIL MOVED BNE 20$ BR 40$ ;THEN FINISH UP 30$: CALL MOVED ;MOVE DOWN SOB SPEED,30$ 40$: MOVB OBJECT,R5 ;REDISPLAY OBJECT CALL INSBUF ; CALL BUFCHK ;CHECK IF BUFFER FULL 50$: RETURN ;THEN RETURN ; ; POSITN - POSITION TO LEFT EDGE OF SCREEN OF OBJECT ; R5 CONTAINS LINE OF OBJECT ; POSITN: MOV LINE,R0 ;USE XYPOS CODE MOV #1,R1 ; TO POSITION TO LINE,1 CALL XYPOS RETURN ; ; MOVER - MOVE RIGHT ; MOVER: MOVB #33,R5 ;USE ESC P (INSERT CHAR) CALL INSBUF MOVB #'P,R5 CALL INSBUF RETURN ; ; MOVEL - MOVE LEFT ; MOVEL: MOVB #33,R5 ;USE ESC Q (DELETE CHAR) CALL INSBUF MOVB #'Q,R5 CALL INSBUF RETURN ; ; MOVEU - MOVE UP ; MOVEU: MOVB #33,R5 ;MUST USE ESC A CALL INSBUF MOVB #'A,R5 CALL INSBUF RETURN ; ; MOVED - MOVE DOWN ; MOVED: MOVB #12,R5 ;USE (CTRL-J) CALL INSBUF RETURN ; ; INSBUF - INSERT CHARACTER INTO BUFFER ; R5 CONTAINS CHARACTER TO INSERT ; INSBUF: MOVB R5,@BUFPTR ;PUT INTO BUFFER INC BUFPTR ;POINT TO NEXT BUFFER POSITION RETURN ; ; BUFCHK - CHECK IF BUFFER (ALMOST) FULL ; DUMPS BUFFER IF FULL & SETS UP SECONDARY BUFFER ; BUFCHK: MOV BUFNUM,R0 ;GET POINTER TO BUFFER SET CMP BUFPTR,BUFLEN(R0) ;SEE IF ALMOST FULL BGE 10$ ;IF GE, IT'S TIME TO DUMP RETURN ;ELSE RETURN ; 10$: SUB BUFADR(R0),BUFPTR ;GET LENGTH OF BUFFER MOV BUFPTR,@QIOP2(R0) ;INSERT INTO QIO PARM LIST DIR$ QIO(R0) ;START I/O STSE$S R0 ;STOP UNTIL OTHER BUFFER WRITTEN OUT YET MOV NXTPTR(R0),R0 ;SET UP TO FILL NEXT BUFFER MOV R0,BUFNUM ; MOV BUFADR(R0),BUFPTR ; RETURN ; BUFLEN: .WORD 0,BUFF2+25.,BUFF4+25. ;ALMOST FULL POINTS FOR BUFFERS BUFNUM: .WORD 2 ;START WITH BUFFER 2 BUFPTR: .WORD BUFF2 ; BUFADR: .WORD 0,BUFF2,BUFF4 ;ADDRESSES OF BUFFERS QIOP2: .WORD 0,QIO2+Q.IOPL+2,QIO4+Q.IOPL+2 QIO: .WORD 0,QIO2,QIO4 ;ADDRESSES OF QIOs NXTPTR: .WORD 0,4,2 ;POINTER TO NEXT POINTER QIO2: QIO$ IO.WVB,5,4,,,, QIO4: QIO$ IO.WVB,5,2,,,, CNTR: .WORD 0 ;COUNTER (SCRATCH) TXTPTR: .WORD 0 ;POINTER (SCRATCH) ; BUFF2: .BLKW 40. BUFF4: .BLKW 40. ; ; SCORER - THIS ROUTINE UPDATES THE SCORING DISPLAY ; SCORER: MOV SCOREB,R1 ;USE SYSTEM LIBRARY FUNCTION MOV #SCORE,R0 ; MOV #27012,R2 ;SUPPRESS LEADING ZEROES CALL $CBTA ;CONVERT BINARY TO DECIMAL MAGNITUDE MOV #1,R0 ;POSITION TO SCORE MOV #4,R1 CALL XYPOS MOV #SCORE,TXTPTR ;NOW INSERT TEXT CHRINS: MOV #5,CNTR 10$: MOVB @TXTPTR,R5 CALL INSBUF INC TXTPTR DEC CNTR ;DONE WITH INSERT? BNE 10$ 20$: RETURN ; ; TIME DISPLAYER ; TIMER: MOV TIMEB,R1 ;GET BINARY TIME VALUE MOV #TIME,R0 ;POINT TO ASCII BUFFER MOV #27012,R2 ;BLANK ZERO SUPPRESSION CALL $CBTA ;CONVERT TO UNSIGNED ASCII MOV #1,R0 ;NOW POSIITON TO TIME COUNTER MOV #75.,R1 ; CALL XYPOS MOV #TIME,TXTPTR ;NOW DUMP OUT THE TEXT BR CHRINS ; ; .END START