.TITLE SPACE INVADERS ; 24-MAR-80 J. C. VENN ; 04-JUL-80 VT52 BY MIKE BROOK ; 18-JAN-81 VT100 BY KEN BELL ; 09-MAR-82 Steve Brecher-- ; | user-selected level of expertise, with instruction for beginner; ; | avoid infinite loop in DBOMB routine by returning immediately ; | if no invaders left; ; | new random number generator; ; | always randomize bombs if no kills yet; ; | keep count of invaders per column, reject empty column ; | immediately in DBOMB routine; ; V add fast spaceship for 200 extra points. ; 10-MAR-82 correct "Ctrl-Q" to ""Q"" in intructions; ; | don't allow fire until previous missile moves up from base; ; | change macro and formal parameter names for compatibility with ; | HT-11; expand "CALL" and "RETURN" in case those not ; | compatible; ; V some optimization of UP and its subroutines. ; If not using VT-52-type terminal, uncomment one of following 3 definitions: ; ;;;SCOPE = 1 ; CONFIGURE FOR H1510 ;;;SCOPE = 2 ; CONFIGURE FOR TVI912/920 SCOPE = 4 ; CONFIGURE FOR VT100 .IIF NDF SCOPE SCOPE = 3 ; DEFAULT TO VT52 .MCALL .REGDEF,.PRINT,.TTINR,.TTYIN,.GTIM,.EXIT .MCALL .LOOKUP,.ENTER,.READW,.WRITW,.CLOSE .REGDEF .MACRO .CP .X,.Y MOVB .X,-(SP) MOVB .Y,1(SP) JSR PC,CPOS .ENDM .MACRO .SHOW .ADDR JSR R5,PRINT .WORD .ADDR .ENDM .MACRO .PUTCH .CHAR MOVB .CHAR,(R4)+ .ENDM .MACRO .PUSH .ARG MOV .ARG,-(SP) .ENDM .MACRO .POP .ARG MOV (SP)+,.ARG .ENDM .PAGE NBASES=3 ; NUMBER OF BASES TO START WITH CTIME=1 ; number of hardware clock ticks per program clock tick NTIMES=4. ; NUMBER OF CTIMES BETWEEN INVADER MOVES (INITIALLY) BSLEEP=5. ; NUMBER OF CTIMES BEFORE NEW BASE SUPPLIED WTIME=120. ; NUMBER OF CTIMES NEW BASE ALLOWED TO WAIT BEFORE MOVING NSHIP=100. ; NUMBER OF CTIMES BETWEEN SPACE SHIPS SSLEEP=60. ; NUMBER OF CTIMES BEFORE SPACE SHIP DEBRIS CLEARED AWAY NROWS=6. ; NUMBER OF ROWS OF INVADERS NCOLS=8. ; NUMBER OF COLUMNS OF INVADERS TOP=10. ; INITIAL TOP ROW OF INVADERS .PAGE START: MOV #2,R2 ;init #missiles-1 for beginner CLR R3 ;and #bombs-1 .PRINT #EXPMSG ;prompt for level of expertise .TTYIN MOV R0,R1 .TTYIN ;soak up CR/LF .TTYIN CMPB R1,#'B ;beginner? BEQ HELP ;if so, go print instructions DEC R2 ;assume intermediate INC R3 CMPB R1,#'I ;intermediate? BEQ STRTED DEC R2 ;assume expert INC R3 CMPB R1,#'E ;expert? BEQ STRTED BR START ;ask the dummy again HELP: .PRINT #HLPMSG .TTYIN STRTED: MOV R2,NMIM1 MOV R3,NBOM1 BIS #10100,@#44 ; 04-JUL-80 .GTIM #AREA,#TBLK MOV TBLK+2,SEED CLR PRVMAX .LOOKUP #AREA,#1,#DEVBLK BCS RESTRT .READW #AREA,#1,#PRVMAX,#1,#0 .CLOSE #1 RESTRT: JSR PC,INIT0 ; INITIALIZE FOR START OF NEW GAME NEXT: JSR PC,INIT ; INITIALIZE EVERYTHING ELSE LOOP: .TTINR BCS COMMON TST DEADB ; BASE DEAD ? BNE COMMON ; YES MOVB R0,KTABE MOV #KTAB,R1 10$: CMPB R0,(R1)+ BNE 10$ SUB #KTAB+1,R1 ASL R1 JMP @KADDR(R1) KTAB: .BYTE ', ; BASE LEFT .BYTE '. ; BASE RIGHT .BYTE 40 ; STOP BASE AND FIRE .BYTE 'Q ; STOP/START BLEEP .BYTE 33 ; EXIT KTABE: .BYTE 0 KADDR: .WORD LEFT,RIGHT,SHOOT,QUIET,EXIT,STOP LEFT: MOV #BASEL,BSUB ;BASE LEFT BR COMMON RIGHT: MOV #BASER,BSUB ; BASE RIGHT BR COMMON SHOOT: CLR BSUB ; STOP BASE MOVING JSR PC,FIRE BR COMMON QUIET: SWAB BELL ; TOGGLE AUDIO EFFECT BR COMMON STOP: CLR BSUB ; ANY OTHER KEY STOPS BASE COMMON: .GTIM #AREA,#TBLK MOV TBLK+2,R0 SUB CLOCK,R0 BMI 50$ MOV TBLK+2,CLOCK ADD #CTIME,CLOCK TOCKS==.-4 COM TWO ; HALF TIMEBASE COUNTER BNE 10$ COM FOUR ; QUARTER 10$: TST DEADB BEQ 20$ DEC DEADB BNE 40$ TST NLIVES ; ALL BASES USED ? BEQ EXIT ; YES JSR PC,CLRBAS ; REMOVE OLD BASE MOV #2,BASEX ; MOVE NEW BASE TO INITIAL POSITION JSR PC,DSPBAS MOV #WTIME,WLIMIT 20$: TST BSUB BNE 30$ CMP BASEX,#8. BHIS 40$ DEC WLIMIT BGT 40$ MOV #BASER,BSUB ; FORCE BASE OUT INTO THE OPEN 30$: JSR PC,@BSUB ; MOVE BASE 40$: JSR PC,UP ; MOVE MISSILES UP JSR PC,DOWN ; MOVE BOMBS DOWN JSR PC,MOVE ; MOVE INVADERS ABOUT JSR PC,SHIP ; MOVE SPACESHIP CMP R4,#BUFF BEQ 80$ BR 60$ 50$: CMP R4,#BUFF BEQ LOOP 60$: JSR PC,DISP ; DISPLAY 70$: BR LOOP 80$: TST NUMINV ; ANY INVADERS LEFT ? BNE LOOP ; YES TST SHIPX ; ANY SPACESHIP ? BNE 70$ ; YES TST NLIVES ; STILL ALIVE ? BLE EXIT INC NLIVES JMP NEXT ; YES - GENERATE SOME MORE INVADERS .PAGE EXIT: CMP POINTS,PRVMAX BLOS 20$ MOV POINTS,PRVMAX .LOOKUP #AREA,#1,#DEVBLK BCC 10$ .ENTER #AREA,#1,#DEVBLK,#1 BCS 20$ 10$: .WRITW #AREA,#1,#PRVMAX,#1,#0 .CLOSE #1 20$: JSR PC,CLRBAS ; REMOVE BASE .CP #1,#24. .SHOW FGND .SHOW AMSG MOV #AMSGLN-2,BASEX JSR PC,DISP 30$: .TTYIN CMPB R0,#33 BEQ 40$ CMPB R0,#15 BNE 30$ JMP RESTRT 40$: MOV #BUFF,R4 .SHOW CLRSCR JSR PC,DISP ; CLEAR SCREEN .EXIT .PAGE BASER: CMP BASEX,#71. BHIS NOMOVE ; ALREADY MAX RIGHT INC BASEX BR DSPBAS ;------------------------------- BASEL: CMP BASEX,#8. BLOS NOMOVE ; ALREADY MAX LEFT DEC BASEX DSPBAS: .CP BASEX,#24. .SHOW BASE RTS PC ;------------------------------- CLRBAS: .CP BASEX,#24. JSR PC,BLANK RTS PC ;------------------------------- NOMOVE: CLR BSUB RTS PC .PAGE UP: BIT TWO,FOUR ; missiles move 3 out of four ticks BEQ 10$ RTS PC 10$: MOV NMIM1,R5 20$: MOVB UPX(R5),R3 BEQ 100$ ; NO MISSILE MOV R3,OKFIRE ; set flag, ok to fire again MOVB UPY(R5),R0 .CP R3,R0 .PUTCH #40 DEC R0 ; MOVE MISSILE UP TST SHIPX BGT 30$ CMPB R0,#4 BLOS 90$ 30$: CMPB R0,#2 ; TOP OF SCREEN ? BEQ 90$ ; YES MOVB R0,UPY(R5) CMPB R0,#22. ; BARRIER LINE ? BLO 40$ ; NO, ABOVE JSR PC,CBARR ; CHECK FOR HIT ON BARRIER BNE 90$ ; YES 40$: MOV R0,R1 INC R1 ; OLD Y POSITION CMPB R0,#3 ; on spaceship line? BNE 50$ ; no TST SHIPX ; SPACESHIP MOVING ? BLE 50$ ; NO JSR PC,CSHIP ; CHECK FOR HIT ON SPACESHIP BEQ 90$ ; YES 50$: JSR PC,CBOMB ; CHECK FOR COLLISION WITH BOMB BEQ 90$ ; YES CLR R2 ; CHECK FOR HIT ON INVADERS, top row to bottom 60$: CMP R0,ROWY(R2) ; now on same line as row of invaders? BEQ 70$ ; yes CMP R1,ROWY(R2) ; was on invader line pre-UP? BLO 130$ ; no, previously above invaders BEQ 70$ ; yes, invader moved down on missile? TST (R2)+ CMP R2,#*2 BLE 60$ ; TRY NEXT ROW BR 130$ ; BELOW INVADERS 70$: MOV ROW(R2),R0 ; missile at row, check each column MOV #NCOLS,R1 80$: MOV @R0,R3 BEQ 120$ ; ALREADY DEAD BLT 110$ ; cloud of smoke, missile cleans the air ADD #4,R3 CMPB UPX(R5),R3 BHI 120$ ; missile to right of this invader CMPB UPX(R5),@R0 BLO 130$ ; missile to left of this invader MOV (R0),R1 ; invader x coord BIS #100000,(R0) ; mark as exploded SUB ROW(R2),R0 MOV R0,DEAD DEC COLCNT(R0) .CP R1,ROWY(R2) JSR PC,EXPLOD ADD PNTS(R2),POINTS JSR PC,SCORE ; UPDATE SCORE DEC NUMINV ; ONE LESS INVADER BGT 90$ ; but some left TST SHIPX ; SPACESHIP MOVING ? BGT 90$ ; YES - DON'T DISABLE BASE YET CLR BSUB ; STOP BASE MOVING MOV #BSLEEP,DEADB 90$: CLRB UPX(R5) ; DESTROY MISSILE 100$: BR 140$ 110$: .CP @R0,ROWY(R2) JSR PC,BLANK CLR @R0 MOVB UPX(R5),R3 INCB R3 .CP R3,UPY(R5) ; REPOSITION CURSOR 120$: TST (R0)+ ; TRY NEXT ON THIS ROW DEC R1 BNE 80$ 130$: .SHOW CSUP .SHOW FGND .PUTCH MISSLE .SHOW BGND 140$: DEC R5 BLT 150$ JMP 20$ 150$: RTS PC .PAGE CSHIP: MOV R3,-(SP) SUB SHIPX,(SP) CMP (SP)+,#4 BHI 10$ ; MISSED .CP SHIPX,R0 JSR PC,EXPLOD JSR PC,RAND CLR R3 ; use 2-high order bits of R0 for word offset ASL R0 ROL R3 ASL R0 ROL R3 ASL R3 MOV SPNTS(R3),R0 ASR SHIPM ; fast ship? BCS 5$ ADD #200.,R0 ; 200. extra! 5$: ADD R0,POINTS .CP SHIPX,#4 .SHOW FGND .PUTCH #'( MOV #3,R3 JSR PC,BNW2A$ .PUTCH #') .SHOW BGND JSR PC,SCORE ; UPDATE SCORE MOVB #-1,SHIPX+1 SEZ 10$: RTS PC .PAGE CBOMB: MOV NBOM1,R2 ; CHECK FOR COLLISION WITH BOMB 10$: CMPB R3,BOMBX(R2) BNE 30$ TSTB BOMBS(R2) BMI 30$ CMPB R1,BOMBY(R2) ; did bomb move to stilled missile last tick? BEQ 20$ ; yes (CRT spot has been wiped by UP routine) CMPB R0,BOMBY(R2) ; missile moving to bomb this tick? BNE 30$ .SHOW CSUP .PUTCH #40 ; blank the bomb 20$: CLRB BOMBX(R2) ; DESTROY BOMB BR 40$ ; DESTROY MISSILE (RETURN Z=1) 30$: DEC R2 BGE 10$ 40$: RTS PC .PAGE CBARR: MOV R3,R1 DEC R1 ASL R1 ADD R0,R1 ;+ line#, 22 or 23 TSTB BARR-22.(R1) ;line 23 barrier data in odd bytes, hence -22. BEQ 10$ DECB BARR-22.(R1) MOVB BARR-22.(R1),R1 .CP R3,R0 .PUTCH BCHAR(R1) 10$: RTS PC .PAGE FIRE: TST OKFIRE BEQ 30$ MOV NMIM1,R5 10$: TSTB UPX(R5) ; LOOK FOR SPARE MISSILE SLOT BNE 20$ MOV BASEX,R0 CMP R0,#8. BLO 30$ ADD #2,R0 MOVB R0,UPX(R5) MOVB #24.,UPY(R5) CLR OKFIRE ; Can't fire again 'til this missile moved up BR 30$ 20$: DEC R5 BGE 10$ 30$: RTS PC .PAGE DOWN: MOV NBOM1,R2 ; MOVE BOMBS DOWN 10$: MOVB BOMBX(R2),R3 BEQ 80$ ; NO BOMB BIT TWO,FOUR ; all move on 1 out of 4 ticks, missiles still BNE 20$ TSTB BOMBS(R2) ; FAST BOMB ? BLE 80$ ; NO CMP TWO,FOUR ; fast bombs move 3 out of 4 ticks BEQ 80$ 20$: MOVB BOMBY(R2),R0 TSTB BOMBS(R2) ; FIRST MOVEMENT ? BMI 30$ ; YES .CP R3,R0 .PUTCH #40 BR 40$ 30$: INCB R3 .CP R3,R0 DECB R3 BICB #200,BOMBS(R2) 40$: INCB BOMBY(R2) INC R0 CMP R0,#25. ; BOTTOM OF SCREEN ? BEQ 60$ ; YES CMP R0,#24. ; BASE LINE ? BEQ 50$ ; YES CMP R0,#22. ; BARRIER LINE ? BLO 70$ ; NO JSR PC,CBARR ; CHECK FOR HIT ON BARRIER BEQ 70$ ; NO BR 60$ ; YES 50$: TST DEADB ; BASE ALREADY DEAD ? BNE 70$ ; YES CMP R3,BASEX BLO 70$ SUB #4,R3 CMP R3,BASEX BHI 70$ .CP BASEX,#24. JSR PC,EXPLOD CLR BSUB ; STOP BASE MOVEMENT MOV #BSLEEP,DEADB ; DEAD BASE DEC NLIVES .SHOW FGND JSR PC,DLIVES ; UPDATE NUMBER OF BASES LEFT 60$: CLRB BOMBX(R2) ; CLEAR BOMB BR 80$ 70$: .SHOW CSDN .SHOW FGND .PUTCH BOMB .SHOW BGND 80$: DEC R2 BGE 10$ 90$: RTS PC .PAGE MOVE: DEC TCOUNT BEQ 10$ JMP DBOMB 10$: MOV TIME,TCOUNT CLR R5 ; MOVED SOMETHING FLAG 20$: MOV TROW,R2 MOV ROWY(R2),R0 BEQ 140$ ; NO INVADERS IN THIS ROW TST VMOVE BEQ 50$ MOV ROW(R2),R1 MOV #8.,R3 30$: TST @R1 BEQ 40$ .CP @R1,R0 JSR PC,BLANK TST @R1 BPL 40$ CLR @R1 ; DESTROYED 40$: TST (R1)+ DEC R3 BNE 30$ INC ROWY(R2) ; DOWN ONE ROW INC R0 50$: MOV ROW(R2),R1 MOV #8.,R3 60$: TST @R1 BLE 120$ ; INVADER DEAD ADD HMOVE,@R1 ; HORIZONTAL MOVE CMP @R1,#8. ; LEFT LIMIT FOR INVADERS BLOS 70$ CMP @R1,#72. ; RIGHT LIMIT BLO 80$ 70$: MOV SP,EFLAG ; HIT EDGE 80$: CMP R0,#23. ; LOWEST LINE FOR INVADERS BNE 90$ MOV SP,BFLAG 90$: CMP R0,#22. BLO 100$ JSR PC,WBARR ; WIPE OUT ANY BARRIERS 100$: INC R5 ; MOVED SOMETHING .CP @R1,R0 110$: JSR PC,SETIN .SHOW INVADR BR 130$ 120$: TST @R1 BGE 130$ TST VMOVE BNE 130$ .CP @R1,R0 JSR PC,BLANK CLR @R1 ; DESTROYED 130$: TST (R1)+ ; NEXT INVADER DEC R3 BNE 60$ TST R5 BNE 140$ CLR ROWY(R2) ; NO INVADERS IN THIS COLUMN 140$: SUB #2,TROW BLT 160$ TST R5 BNE 150$ JMP 20$ 150$: MOV R5,TIME ; NEW TIME DELAY BR DBOMB 160$: MOV #10.,TROW ; MOVED ALL ROWS COM INSW TST VMOVE BEQ 170$ CLR VMOVE BR 180$ 170$: TST EFLAG ; HIT EDGE ? BEQ 180$ NEG HMOVE ; CHANGE DIRECTION TST BFLAG BNE 180$ ; HIT BOTTOM MOV #1,VMOVE ; AND MOVE DOWN ONE LINE 180$: CLR EFLAG CLR BFLAG DBOMB: TST NUMINV ; any invaders to drop bombs? BEQ 20$ BIT TWO,FOUR BEQ 20$ MOV NBOM1,R2 10$: TSTB BOMBX(R2) BEQ 30$ ; FOUND UNUSED BOMB SLOT DEC R2 BGE 10$ 20$: RTS PC 30$: JSR PC,RAND BIT BMASK,R0 BNE 80$ JSR PC,RAND MOV DEAD,R1 ; column of last kill BMI 35$ ; br if no kills yet TST COLCNT(R1) BLE 35$ ; br if last kill was of last invader in column ASL R0 BCS 40$ ; 50% chance of bomb from col of last kill 35$: CLR R1 ; colmn = remaining hi order 3 bits of R0 ASL R0 ROL R1 ASL R0 ROL R1 ASL R0 ROL R1 ASL R1 ; word index TST COLCNT(R1) ; any invaders in this column? BLE 30$ ; br if not 40$: MOV #ROW+12.,R0 50$: MOV -(R0),R3 ; look for bottom invader in column ADD R1,R3 TST @R3 BLE 50$ 60$: MOVB @R3,R3 ; DROP BOMB ADD #2,R3 MOVB R3,BOMBX(R2) MOVB ROWY-ROW(R0),BOMBY(R2) MOVB #200,BOMBS(R2) CMP R0,#ROW BEQ 70$ ; TOP ROW ALWAYS DROPS FAST BOMBS JSR PC,RAND BIT FMASK,R0 BNE 80$ 70$: INCB BOMBS(R2) ; FAST BOMB ! 80$: RTS PC .PAGE WBARR: .PUSH R3 MOV @R1,R3 SUB #1,R3 TST HMOVE BMI 10$ DEC R3 10$: ASL R3 ADD R0,R3 SUB #22.,R3 .PUSH #7 20$: CLRB BARR(R3) ADD #2,R3 DEC @SP BNE 20$ TST (SP)+ .POP R3 RTS PC .PAGE SETIN: BIT #1,R3 BNE 20$ TST INSW BNE 30$ 10$: MOVB #INV1,IN1 MOVB #INV5,IN5 RTS PC 20$: TST INSW BNE 10$ 30$: MOVB #INV5,IN1 MOVB #INV1,IN5 RTS PC .PAGE SHIP: MOV SHIPX,R2 ; SHIP MOVING ? BGT 10$ ; YES DEC SCOUNT BNE 50$ MOV #NSHIP,SCOUNT MOV #1,R2 ; START SPACESHIP MOV R2,SHIPM MOV #SLOSHP,SHIPIC CLR R1 JSR PC,RAND ASL R0 BCC 5$ ASL R0 BCC 5$ INC SHIPM ; 25% chance of fast ship MOV #FASSHP,SHIPIC MOV #FASSIZ,R1 5$: TST R0 BPL 10$ NEG SHIPM ; 50% chance right-to-left ADD R1,SHIPIC MOV #74.,R2 10$: TST TWO BNE 40$ TST FOUR BNE 40$ ; move once per 4 ticks - when missiles still TST SHIPM BMI 20$ CMPB R2,#73. ; EDGE OF SCREEN ? BEQ 60$ BR 30$ 20$: CMPB R2,#2 BEQ 60$ 30$: ADD SHIPM,R2 .CP R2,#3 JSR PC,DSHIP 40$: MOV R2,SHIPX RTS PC 50$: TST R2 BEQ 70$ ; SHIP NOT THERE AT ALL CMP SCOUNT,#NSHIP-SSLEEP BGT 70$ 60$: .CP R2,#3 ; REMOVE SHIP JSR PC,BLANK .CP R2,#4 ; AND ANY SCORE JSR PC,BLANK CLR SHIPX TST NUMINV BGT 70$ CLR BSUB ; STOP BASE MOVING MOV #BSLEEP,DEADB 70$: RTS PC DSHIP: .SHOW FGND JSR R5,PRINT SHIPIC: .BLKW 1 .SHOW BGND RTS PC ;------------------------------- BLANK: .SHOW BLNK RTS PC ;------------------------------- EXPLOD: .PUTCH BELL .SHOW FGND .SHOW EXPLD .SHOW BGND RTS PC .PAGE ; Return random R0 -- linear congruential sequence with maximum period, ; R0 := 2053.*seed + 13849., modulo 2**16 ; seed := R0 ; Note: high-order bits of result are "more random" than low-order. ; RAND: MOV SEED,R0 SWAB R0 CLRB R0 ASL R0 ;*512. ADD SEED,R0 ;*513. ASL R0 ASL R0 ;*2052. ADD SEED,R0 ;*2053. ADD #13849.,R0 MOV R0,SEED RTS PC SEED: .BLKW 1 .PAGE ; ; SUBROUTINE CPOS ; X = 2(SP) COLUMN NUMBER ; Y = 3(SP) LINE NUMBER ; CPOS: .SHOW CSPSN .IF EQ SCOPE - 1 ; H1510 .PUSH R0 MOVB 4(SP),R0 ; FETCH COLUMN (X) DEC R0 CMPB R0,#32. BHIS 10$ ADD #96.,R0 10$: .PUTCH R0 MOVB 5(SP),R0 ; FETCH LINE (Y) ADD #95.,R0 .PUTCH R0 .POP R0 .ENDC .IF EQ SCOPE-2 ; TVI912/920 .PUSH R0 MOVB 5(SP),R0 ; FETCH LINE (Y) ADD #31.,R0 .PUTCH R0 MOVB 4(SP),R0 ; FETCH COLUMN (X) ADD #31.,R0 .PUTCH R0 .POP R0 .ENDC .IF EQ SCOPE-3 ; VT52 .PUSH R0 MOVB 5(SP),R0 ; FETCH LINE (Y) ADD #31.,R0 .PUTCH R0 MOVB 4(SP),R0 ; FETCH COLUMN (X) ADD #31.,R0 .PUTCH R0 .POP R0 .ENDC .IF EQ SCOPE-4 ; VT100 .PUSH R0 .PUSH R3 MOVB 7(SP),R0 ; FETCH LINE (Y) MOV #-2,R3 JSR PC,BNW2A$ .PUTCH #73 MOVB 6(SP),R0 ; FETCH COLUMN (X) MOV #-2,R3 JSR PC,BNW2A$ .PUTCH #110 .POP R3 .POP R0 .ENDC MOV (SP)+,(SP) RTS PC .PAGE PRINT: .PUSH R0 MOV (R5)+,R0 10$: MOVB (R0)+,(R4)+ BNE 10$ DEC R4 .POP R0 RTS R5 ;---------------------------------------------- DISP: MOV BASEX,R0 ADD #2,R0 .CP R0,#24. ; POSITION CURSOR ON BASE MOVB #200,(R4) .PRINT #BUFF MOV #BUFF,R4 RTS PC ;------------------------------- SCORE: MOV POINTS,R0 MOV #5,R3 .CP #43.,#2 .SHOW FGND JSR PC,BNW2A$ DLIVES: MOV NLIVES,R0 MOV #3,R3 .CP #31.,#2 JSR PC,BNW2A$ .SHOW BGND RTS PC POINTS: .WORD 0 PRVMAX: .WORD 0 .PAGE ; BINARY TO ASCII ; R0=VALUE ; R3=FIELD WIDTH ( - = LEADING ZEROES) ; R4=OUTPUT STRING ADDRESS BNW2A$: .PUSH R1 .PUSH R2 .PUSH R5 CLR -(SP) ; OUTPUT STARTED FLAG. TST R3 BMI 10$ MOV #40,LEAD BR 20$ 10$: NEG R3 MOV #60,LEAD 20$: MOV R3,R5 BEQ 90$ MOV #VALEND,R2 ASL R5 SUB R5,R2 30$: CLR R5 ; DIGIT COUNTER. MOV (R2)+,R1 ; NEXT DECIMAL STAGE VALUE. BEQ 90$ ; FINISHED. 40$: SUB R1,R0 ; EXTRACT DIGIT VALUE. BLO 50$ INC R5 ; UPDATE DIGIT. BR 40$ 50$: ADD R1,R0 ; CORRECT OVERSHOOT. TST (SP) ; HAS OUTPUT STARTED ? BNE 70$ ; NO. TST R5 ; IS THIS A ZERO DIGIT? BEQ 60$ INC (SP) ; MARK OUTPUT STARTED. BR 70$ 60$: CMP R3,#1 ; IS IT THE LAST DIGIT? BEQ 70$ TST @R2 ; IS IT THE LAST DIGIT? BEQ 70$ MOVB LEAD,R5 BR 80$ 70$: ADD #60,R5 80$: .PUTCH R5 ; OUTPUT DIGIT. DEC R3 BNE 30$ 90$: TST (SP)+ ; CLEAR OFF OUTPUT FLAG. .POP R5 .POP R2 .POP R1 RTS PC LEAD: .WORD 40 .WORD 10000.,1000.,100.,10.,1. VALEND: .WORD 0 .PAGE INIT0: MOV #NBASES,NLIVES CLR POINTS MOV #174000,FMASK MOV #160000,BMASK MOV #BAR1,R1 MOV #6,R0 10$: MOV #10.,R2 20$: MOVB #STRNG,(R1)+ DEC R2 BNE 20$ ADD #10.,R1 DEC R0 BNE 10$ .GTIM #AREA,#TBLK MOV TBLK+2,CLOCK RTS PC .PAGE INIT: MOV #ROWY,R1 MOV #NROWS,R0 MOV #5,R2 ; Y POSITION 10$: MOV R2,(R1)+ ADD #2,R2 DEC R0 BNE 10$ CLR R1 MOV #NCOLS,R0 MOV #11.,R2 20$: MOV R2,ROW5(R1) MOV R2,ROW7(R1) MOV R2,ROW9(R1) MOV R2,ROW11(R1) MOV R2,ROW13(R1) MOV R2,ROW15(R1) MOV #NROWS,COLCNT(R1) TST (R1)+ ADD #8.,R2 DEC R0 BNE 20$ MOV #ZB,R1 MOV #/2,R0 30$: CLR (R1)+ DEC R0 BNE 30$ MOV #-1,DEAD MOV #,NUMINV ; NUMBER OF INVADERS MOV #2,BASEX MOV #WTIME,WLIMIT MOV #TOP,TROW MOV #NTIMES,TCOUNT MOV #NTIMES,TIME MOV #NSHIP,SCOUNT MOV #1,HMOVE ASL FMASK ; MAKE MORE FAST BOMBS ! ASL BMASK ; MAKE MORE BOMBS ! BNE 40$ ASR BMASK ; NEVER GETS TO ZERO 40$: MOV #BUFF,R4 ; TEXT BUFFER .SHOW CLRSCR .SHOW FGND .CP #2,#24. .SHOW BASE .CP #2,#2 .SHOW TITLE1 .SHOW BGND .SHOW TITLE2 DEC R4 JSR PC,DISP .CP #1,#22. ; DISPLAY BARRIERS MOV #BARR,R0 JSR PC,70$ .CP #1,#23. MOV #BARR+1,R0 JSR PC,70$ JSR PC,DISP JSR PC,SCORE ; DISPLAY SCORE MOV PRVMAX,R0 MOV #5,R3 .CP #62.,#2 JSR PC,BNW2A$ JSR PC,DISP MOV #ROWY,R0 MOV #NROWS,R2 ; NOW DISPLAY INVADERS MOV ROW,R1 50$: MOV #NCOLS,R3 MOV R3,OKFIRE ; set flag (any nonzero value) 60$: .CP (R1)+,@R0 INC R1 JSR PC,SETIN .SHOW INVADR DEC R3 BNE 60$ .PUSH R0 JSR PC,DISP .POP R0 TST (R0)+ DEC R2 BNE 50$ COM INSW RTS PC 70$: MOV #70.,R1 80$: MOVB (R0)+,R2 INC R0 .PUTCH BCHAR(R2) DEC R1 BNE 80$ RTS PC .PAGE INSW: .WORD 0 ROW: .WORD ROW5,ROW7,ROW9,ROW11,ROW13,ROW15 ROWY: .BLKW NROWS COLCNT: .BLKW NCOLS PNTS: .WORD 30.,25.,20.,15.,10.,05. ROW5: .BLKW NCOLS ROW7: .BLKW NCOLS ROW9: .BLKW NCOLS ROW11: .BLKW NCOLS ROW13: .BLKW NCOLS ROW15: .BLKW NCOLS BARR: .BLKB 2*80. BAR1=BARR+<2*11.> BCHAR: .BYTE 40,'-,'+,'*,'#,0 STRNG = .-BCHAR-2 ZB=. BOMBX: .BLKB 3 ; BOMB POSITIONS BOMBY: .BLKB 3 BOMBS: .BLKB 3 ; BOMB SPEEDS .EVEN UPX: .BLKB 3 ; MISSILE POSITIONS UPY: .BLKB 3 TWO: .WORD 0 ; HALF TIMEBASE COUNTER FOUR: .WORD 0 ; QUARTER TIMEBASE COUNTER BSUB: .WORD 0 ; BASE MOVEMENT SUBROUTINE ADDRESS DEADB: .WORD 0 VMOVE: .WORD 0 ; VERT. MOVE EFLAG: .WORD 0 ; EDGE CONDITION FLAG BFLAG: .WORD 0 ; BOTTOM FLAG SHIPX: .WORD 0 ZE=. ;Level of expertise parameters, initially set for beginner-- NMIM1: .WORD 2 ; NUMBER OF SIMULTANEOUS MISSILES IN FLIGHT - 1 NBOM1: .WORD 0 ; NUMBER OF SIMULTANEOUS BOMBS - 1 DEAD: .WORD -1 ; if >0, column word index of last invader kill OKFIRE: .WORD 1 ; flag: previous missile has moved above base FMASK: .WORD 0 BMASK: .WORD 0 SHIPM: .WORD 0 NUMINV: .WORD 0 BASEX: .WORD 0 ; INITIAL X POSITION OF BASE WLIMIT: .WORD 0 NLIVES: .WORD 0 ; NUMBER OF BASES TO START WITH TROW: .WORD 0 TCOUNT: .WORD 0 SCOUNT: .WORD 0 HMOVE: .WORD 0 ; HORIZ. MOVE SSFLAG: .WORD 0 BELL: .BYTE 7,4 ; BELL,QUIET BELL TIME: .WORD NTIMES SPNTS: .WORD 50.,100.,150.,200. .ENABL LC TITLE1: .ASCIZ 'SPACE INVADERS! ' TITLE2: .ASCIZ 'Bases: Score: Highest: ' AMSG: .ASCIZ 'Press RETURN to play again, ESC to quit: ' AMSGLN=.-AMSG-1 EXPMSG: .ASCII <15><12>'SPACE INVADERS! Beginner, Intermediate, or Expert?' .ASCII ' (B/I/E): '<200> HLPMSG: .BYTE 15,12,12 .ASCII 'The "," (lowercase "<") key moves left;'<15><12><12> .ASCII 'The "." (lowercase ">") key moves right;'<15><12><12> .ASCII 'Press the spacebar to stop and fire;'<15><12><12> .ASCII '"Q" toggles sound effects off/on (for those late night ' .ASCII 'sessions);'<15><12><12> .ASCII 'Press any other key to stop without firing;'<15><12><12> .ASCII 'Insert quarter in nearest programmer and press RETURN ' .ASCII 'to start game: '<200> .IF EQ SCOPE-1 ;HAZELTINE 1510 CLRSCR: .BYTE 176,34,0 ; CLEAR SCREEN CSUP: .BYTE 176,14,10,0 ; CURSOR UP, BACKSPACE CSDN: .BYTE 12,10,0 ; CURSOR DOWN (LF), BACKSPACE CSPSN: .BYTE 176,21,0 ; CURSOR POSITION FGND: .BYTE 176,37,0 ; FOREGROUND MODE (HIGH INTENSITY) BGND: .BYTE 176,31,0 ; BACKGROUND MODE (LOW INTENSITY) .ENDC .IF EQ SCOPE-2 ;TELEVIDEO 912/920 CLRSCR: .BYTE 33,132,0 CSUP: .BYTE 13,10,0 CSDN: .BYTE 12,10,0 CSPSN: .BYTE 33,75,0 FGND: BGND: .BYTE 0 .ENDC .IF EQ SCOPE-3 ;VT52 CLRSCR: .BYTE 33,110,33,112,0 CSUP: .BYTE 33,101,10,0 CSDN: .BYTE 12,10,0 CSPSN: .BYTE 33,131,0 FGND: BGND: .BYTE 0 .ENDC .IF EQ SCOPE-4 ;VT100 CLRSCR: .BYTE 33,133,62,112,0 CSUP: .BYTE 33,133,101,10,0 CSDN: .BYTE 12,10,0 CSPSN: .BYTE 33,133,0 FGND: BGND: .BYTE 0 .ENDC BASE: .ASCIZ <10>' -- -- ' INVADR: .ASCII <10>' ' IN1: .ASCII '/-O-' IN5: .ASCIZ '\ ' INV1='/ INV5='\ SLOSHP: .ASCIZ <10>' -=O=- ' FASSHP: .ASCIZ <10><10>' =*>>>' FASSIZ=.-FASSHP .ASCIZ '<<<*= ' EXPLD: .ASCIZ '*****' BLNK: .ASCIZ ' ' MISSLE: .ASCII '!' BOMB: .IF EQ SCOPE-1 .ASCII '`' ;solid block on Hazeltine .IFF .ASCII 'O' .ENDC .EVEN ;------------------------------- DEVBLK: .RAD50 'DK SPCINVDAT' AREA: .BLKW 5 TBLK: .WORD 0,0 CLOCK: .WORD 0 .WORD 0 BUFF: .BLKB 300. .END START