; **********************************************************************;  Program: MP4.ASM -- space invaders;  Author: Scott Teresi, www.teresi.us;  Created: November 13, 1995	 Last modification: November 30, 1995;  Compiling instructions: link this program to STRING and BINTOASC;  Description: This program approximates the video game Space Invaders.; *********************************************************************; *********************************************************************;       Shared information; *********************************************************************	EXTRN SCROLL_SCREEN: FAR	EXTRN INPUT_ROUTINE: FAR	EXTRN OUTPUT_STRING: FAR	EXTRN BINARY_TO_ASCII: FAR; *********************************************************************;       Stack Segment; *********************************************************************STAKSEG SEGMENT STACK 'STACK'		DB 1024 DUP ('?')	 ; default stack size is 1kSTAKSEG ENDS; *********************************************************************;       Data Segment; *********************************************************************DATASEG SEGMENT PARA PUBLIC 'DATA';KEYBOARD INTERRUPT	INT_SEG 	DW ?	    ; segment of old interrupt	INT_OFF         DW ?        ; offset of old interrupt	SCFLAG          DB 0        ; flag set when keyboard interrupt called	SCAN            DB ?        ; save scan code during interrupt;MISC.	BULLET_DISAPP	DB 0	    ; 0 = bullet travels to top of screen				    ; 1 = bullet disappears if fired again	SCORE		DW 0	    ; player's score	SCORE_STRING	DB 'SCORE: ', 0;FLAGS	ENDFLAG 	DB 1	    ; flags program when quit key is pressed	PAUSE_FLAG	DB 0	    ; is program in pause mode?	MOVED_DOWN	DB 0	    ; have aliens just moved down the screen?	ALIENS_GONE	DB 0	    ; flag is on if all aliens are shot	GAME_OVER	DB 0	    ; flag to indicate when player has lost;KEYS DEFINED	;LEFT_KEY	DB 4BH	    ; key to move ship left	;RIGHT_KEY	DB 4DH	    ; key to move ship right	LEFT_KEY	DB 33H	    ; key to move ship left	KEY_LEFT	DB ', key', 0	RIGHT_KEY	DB 34H	    ; key to move ship right	KEY_RIGHT	DB '. key', 0	FIRE_KEY	DB 1DH	    ; key to fire at aliens	KEY_TO_FIRE	DB 'control', 0	QUIT_KEY	DB 10H	    ; key to quit game	KEY_TO_QUIT	DB 'Q', 0	PAUSE_KEY	DB 19H	    ; key to pause game	KEY_TO_PAUSE	DB 'P', 0;SCREEN SPECS	TOP_SCRN	DB 2	BOTTOM_SCRN	DB 24	RGHT_SCRN	DB 76	LEFT_SCRN	DB 1;CHARACTERS	SPACE_SHIP	DB 201, 219, 187, 0	ALIEN_SHIP	DB 174, 2, 175, 0	SHIP_GONE	DB '   ', 0	BETWEEN_ALIENS	DB '  ', 0	PAD_SPACES	DB '          ', 0	; must be = or > length of...				; ALIEN_SHIP + BETWEEN_ALIENS + ALIEN_SPEED	SHIP_FIRE	DB 179, 0	ALIEN_BOMB	DB 173, 0	BLANK		DB ' ', 0;POSITIONS	SHIP_X		DB 40	    ; ship's coordinate at bottom of screen	SHIP_HIT        DB 0        ; has ship been hit?	ALIENS_X	DB 0	    ; x and y positions of the block of...	ALIENS_Y	DB ?	    ; ...aliens that exist	BULLET_X	DB 10 DUP (?) ; coordinates for each bullet	BULLET_Y	DB 10 DUP (?);ALIEN FORMATION	NUM_ROWS	DB 4	    ; number of rows of aliens	ARRAY_WIDTH	DB 16	    ; number of alien "spaces" in a row	ALIEN_ROW	DB 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0			DB 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0			DB 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0			DB 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0;ALIEN SPECS	ROW_COLOR	DB 1, 9, 3, 11		  ; colors for each row	ROW_POINTS	DW 100, 25, 10, 5	  ; point values of each row	LEFTMOST	DB ?	    ; leftmost alien's array position	RIGHTMOST	DB ?	    ; rightmost alien's array position	OLD_LEFT	DB ?	OLD_RIGHT	DB ?	ALIEN_COUNT	DB 0	    ; number of aliens alive	ALIEN_POS	DB 0	    ; which alien is being checked?	ALIEN_CHOSEN	DB 0	    ; which alien was chosen to drop a bomb?;SPEEDS AND DELAYS	SHIP_SPEED	  DB 2	    ; spaces ship moves each keypress	ALIEN_SPEED	  DB 1	    ; spaces and direction aliens move	ALIEN_TOP_DELAY   DW 1000   ; no. of loops before aliens move	ALIEN_DELAY	  DW 0	    ; counter for above variable	BULLET_TOP_DELAY  DW 300    ; no. of loops before bullet moves	BULLET_DELAY	  DW 0	    ; counter for above variable	BOMB_TOP_DELAY	  DW 1000   ; no. of loops before bombs move	BOMB_DELAY	  DW 0	    ; counter for above variable	BETWEEN_BOMBS_TOP DW 1000   ; minimum no. of loops between bomb drops	BETWEEN_BOMBS	  DW 0	    ; counter for above variable;BOMB SPECS	BOMB_FACTOR	DB 4	    ; higher number drops fewer bombs	MAX_BOMBS	DB 20	    ; maximum number of bombs on screen	BOMB_X		DB 20 DUP (?)	BOMB_Y		DB 20 DUP (?)	BOMB_EXIST	DB 20 DUP (0);	BOMB_X		DB 5, 20, 45, 75, 10, 46, 47, 48, 49, 50;			DB 5 DUP (?) ; coordinates for each bomb;	BOMB_Y		DB 4, 5, 6, 7, 8, 9, 10, 11, 12, 13;			DB 5 DUP (?);	BOMB_EXIST	DB 1, 1, 1, 1, 1, 1, 1, 1, 1, 1	; flag to indicate the bomb exists;INSTRUCTIONS	SCRATCH 	DB 80, 0, 80 DUP (?)	TOP_LINE	DB 218, 31 DUP (196), 191, 0	GAME_TITLE	DB 179, '  S P A C E   I N V A D E R S  ', 179, 0	BOTTOM_LINE	DB 192, 31 DUP (196), 217, 0	THE_ALIENS	DB 'The aliens:', 0	DOTS		DB '  . . . .  ', 0	POINTS		DB ' points', 0	KEYS		DB '   Use these keys... ', 0	INSTR_FIRE	DB '          To fire: ', 0	INSTR_LEFT	DB '     To move left: ', 0	INSTR_RIGHT	DB '    To move right: ', 0	INSTR_PAUSE	DB 'To pause the game: ', 0	INSTR_QUIT	DB ' To quit the game: ', 0	PROMPT		DB 'Press return to start the game. ', 0	ME		DB 'by Scott Teresi, Nov. 1995', 0	WIN_STRING1	DB 'Y O U   W I N !', 0	LOSE_STRING1	DB 'Y O U   L O S E !', 0	GAME_TOP_LINE	DB 'S P A C E   I N V A D E R S', 0DATASEG ENDS; *********************************************************************;       Code Segment; *********************************************************************CODESEG SEGMENT PARA PUBLIC 'CODE'MAIN    PROC   FAR		ASSUME CS:CODESEG,DS:DATASEG,SS:STAKSEG	MOV    AX,DATASEG	; put address of start of data segment in AX	MOV    DS,AX            ; and then in DS to initialize the register	CALL INIT_SCREEN	CALL SET_KEYBD_INT	; set an interrupt to catch keyboard inputMAIN_LOOP:	MOV  CX, 0300H	WASTE_TIME:		; loop to slow down program altogether	LOOP WASTE_TIME	CALL MOVE_BULLETS	; update bullets' motions	CALL CHECK_ALIENS	; see if the bullet has hit an alien	CMP  ALIENS_GONE, 0	; see if all aliens have been killed	JNZ  WON_GAME		; if so, jump out of loop	CALL MOVE_ALIENS	; update aliens' motions	CALL MOVE_BOMBS		; update bombs' motions	CALL GENERATE_BOMB	; randomly add another bomb	CALL CHECK_BOMBS	; see if any bombs have hit the space ship	CMP  GAME_OVER, 0	; see if player has lost the game	JNZ  LOST_GAME		; if so, jump out of loop	CMP  ENDFLAG, 0 	; see if it's time to end the game	JNZ  MAIN_LOOP		; if not, then continue the loopEND_PROGRAM:	CALL RESTORE_OLD_INT	; restore interrupt from keyboard vector	CALL SCROLL_SCREEN	; clear the screen at the end of the game	JMP  DOS_EXIT		; exit to DOSWON_GAME:	CALL RESTORE_OLD_INT	; restore interrupt from keyboard vector	CALL YOU_WIN		; print win screen	JMP  DOS_EXITLOST_GAME:	CALL RESTORE_OLD_INT	; restore interrupt from keyboard vector	CALL YOU_LOSE		; print lose screen	JMP  DOS_EXITMAIN ENDP; *********************************************************************;       Procedures; *********************************************************************INIT_SCREEN PROC FAR; Display instructions, wait for keypress, then clear screen and display the; score and the aliens in their initial position, ready to start the game.; On entry: <nothing>; On exit:  <nothing>	LEA SI, BOMB_EXIST	CALL SCROLL_SCREEN	; clear screen	CALL INSTRUCTIONS	; display instructions	CALL SCROLL_SCREEN	; clear screen after keypress	PUSH AX	MOV AL, TOP_SCRN	; get top of screen value	MOV ALIENS_Y, AL	; set aliens' start position at top of screen	POP AX	CALL FIND_EDGES 	; find bounds of the alien formation	CALL PRINT_ALIENS	; output the block of aliens	CALL OUTPUT_SCORE	; display player's score	RETINIT_SCREEN ENDPINSTRUCTIONS PROC FAR; Display colorful game instructions and wait for a keypress.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH CX	PUSH DX	PUSH SI	PUSH DI	MOV AH, 0BH	    ; set interrupt 10H function	MOV BH, 0	MOV BL, 1	    ; set border color to dark blue	INT 10H 	    ; call DOS service	MOV DL, 23	    ; set x coordinate (to center the string)	MOV DH, 1	    ; set y coordinate (top line)	MOV BL, 3	    ; set text color	LEA SI, TOP_LINE    ; output top line of title's frame	CALL OUTPUT_STRING	MOV DL, 23	INC DH		    ; move down a line	LEA SI, GAME_TITLE  ; output game title	CALL OUTPUT_STRING	MOV DL, 23	INC DH	LEA SI, BOTTOM_LINE ; output bottom line of title's frame	CALL OUTPUT_STRING	MOV DL, 26	INC DH	INC DH	MOV BL, 9	LEA SI, ME	CALL OUTPUT_STRING  ; output program's author	MOV DL, 34	INC DH	INC DH	INC DH	MOV BL, 5	LEA SI, THE_ALIENS  ; display heading for listing of aliens	CALL OUTPUT_STRING	MOV CX, 0	INC DHALIEN_SCORES:	MOV DL, 31	INC DH		    ; move down a line	MOV BX, CX	MOV BL, ROW_COLOR+[BX] ; set color of alien	LEA SI, ALIEN_SHIP  ; display alien ship characters	CALL OUTPUT_STRING	LEA SI, DOTS	    ; display a line of dots	CALL OUTPUT_STRING	PUSH BX	MOV BX, CX	ADD BX, CX	MOV AX, ROW_POINTS+[BX] ; get point value for alien	MOV BX, 10	LEA SI, SCRATCH     ; specify a string for binary_to_ascii procedure	CALL BINARY_TO_ASCII	POP BX	CALL OUTPUT_STRING  ; output point value for alien	INC CL	CMP CL, NUM_ROWS    ; see if all rows of aliens have been output	JB  ALIEN_SCORES    ; if not, output next row	MOV AL, 24	MOV DL, AL	INC DH	INC DH	INC DH	LEA SI, INSTR_FIRE  ; output instructions on the fire key	CALL OUTPUT_STRING	LEA SI, KEY_TO_FIRE ; output fire key	CALL OUTPUT_STRING	MOV DL, AL	INC DH	LEA SI, INSTR_LEFT  ; output instructions on the move-left key	CALL OUTPUT_STRING	LEA SI, KEY_LEFT    ; output the move-left key	CALL OUTPUT_STRING	MOV DL, AL	INC DH	LEA SI, INSTR_RIGHT ; output instructions on the move-right key	CALL OUTPUT_STRING	LEA SI, KEY_RIGHT   ; output the move-right key	CALL OUTPUT_STRING	MOV DL, AL	INC DH	LEA SI, INSTR_PAUSE ; output instructions on pausing	CALL OUTPUT_STRING	LEA SI, KEY_TO_PAUSE ; output the pause key	CALL OUTPUT_STRING	MOV DL, AL	INC DH	LEA SI, INSTR_QUIT  ; output instructions on quitting the program	CALL OUTPUT_STRING	LEA SI, KEY_TO_QUIT ; output quit key	CALL OUTPUT_STRING	MOV DL, AL	INC DH	INC DH	MOV AH, 2	MOV BH, 0	MOV BL, 15	INT 10H 	    ; change attributes/coord. for the input prompt	LEA SI, SCRATCH	LEA DI, PROMPT	    ; specify prompt	CALL INPUT_ROUTINE  ; get a return keypress	POP DI	POP SI	POP DX	POP CX	POP BX	POP AX	RETINSTRUCTIONS ENDPYOU_WIN PROC FAR; Display win screen.; On entry: <nothing>; On exit:  <nothing>	PUSH BX	PUSH DX	PUSH SI	CALL SCROLL_SCREEN	; clear the screen	MOV DL, 33	MOV DH, 12	MOV BL, 135		; specify flashing characters	LEA SI, WIN_STRING1	; display win string	CALL OUTPUT_STRING	POP SI	POP DX	POP BX	RETYOU_WIN ENDPYOU_LOSE PROC FAR; Display lose screen.; On entry: <nothing>; On exit:  <nothing>	PUSH BX	PUSH DX	PUSH SI	CALL SCROLL_SCREEN	; clear the screen	MOV DL, 32	MOV DH, 12	MOV BL, 135		; display flashing characters	LEA SI, LOSE_STRING1	; display the lose string	CALL OUTPUT_STRING	POP SI	POP DX	POP BX	RETYOU_LOSE ENDPSET_KEYBD_INT PROC FAR; This procedure taken from Dr. Estell's KB.ASM hand-out.; Change the interrupt vector INT 21H, function 9H to catch keyboard input.; On entry: <nothing>; On exit:  INT_SEG and INT_OFF are set to segment and offset of old vector.	PUSH AX                 ; save registers	PUSH BX	PUSH CX	PUSH DX	PUSH DS	PUSH ES	MOV AH, 35H             ; get the current vector for the divide by	MOV AL, 9H              ; calling INT 21H, function 35H	INT 21H	MOV AX, ES              ; result is passed in ES:BX	MOV INT_SEG, AX         ; store old interrupt for restoration	MOV INT_OFF, BX	MOV AX, SEG KEYBD_INPUT ; load the address for new...	MOV DS, AX              ; ...keyboard interrupt routine	MOV DX, OFFSET KEYBD_INPUT	MOV AH, 25H             ; set up interrupt vector specified in AL...	MOV AL, 9H              ; ...to the address given in DS:DX	INT 21H	POP ES	POP DS	POP DX	POP CX	POP BX	POP AX	RETSET_KEYBD_INT ENDPKEYBD_INPUT PROC FAR; Interrupt routine to get a key from the keyboard when one is pressed.; On entry: <nothing>; On exit:  SCFLAG is set, SCAN contains key pressed	PUSH AX 	    ; save registers	PUSH DS	MOV AX, SEG DATASEG ; make sure correct data segment is selected	MOV DS, AX	CLI                 ; disable interruptsGET_STATUS:	IN   AL, 64H	    ; test the status port	TEST AL, 02H	    ; is the coding complete?	LOOPNZ GET_STATUS   ; no - wait	IN  AL, 60H     ; yes - get code	STI             ; enable interrupts again	MOV SCAN, AL    ; save the scan code	MOV SCFLAG, 1   ; set the scan flag	MOV AL, 20H     ; needed for correct operations of...	OUT 20H, AL     ; ...interrupt controller	CALL CHECK_KEYS	POP DS		; restore registers	POP AX	IRETKEYBD_INPUT ENDPCHECK_KEYS PROC FAR; On entry: <nothing>; On exit:  ENDFLAG = 0 if quit key was pressed	PUSH AX	PUSH BX	PUSH CX	PUSH DX	PUSH SI	MOV CL, SHIP_XCHECK_MOVE_LEFT:	MOV AL, LEFT_KEY	CMP SCAN, AL		    ; compare scan code with left key code	JNE CHECK_MOVE_RIGHT	    ; if not left, check other keys	MOV DL, CL		    ; get ship coordinate	SUB CL, SHIP_SPEED	    ; move ship left	JMP MOVE_SHIPCHECK_MOVE_RIGHT:	MOV AL, RIGHT_KEY	CMP SCAN, AL		    ; compare scan code with right key code	JNE CHECK_FOR_SHOT	    ; if not right, check other keys	MOV DL, CL		    ; get ship coordinate	ADD CL, SHIP_SPEED	    ; move ship rightMOVE_SHIP:	CALL CHECK_EDGE 	; check if at edge of screen	MOV SHIP_X, CL		; store x coordinate	LEA SI, SHIP_GONE	MOV DH, BOTTOM_SCRN	; specify y coordinate	MOV BL, 7	CALL OUTPUT_STRING	; erase old position	LEA SI, SPACE_SHIP	MOV DL, SHIP_X		; specify x coordinate	MOV DH, BOTTOM_SCRN	; specify y coordinate	MOV BL, 4	CALL OUTPUT_STRING	; plot new position	CALL CHECK_ALIENS	; check if aliens have landed	JMP FINISHED_CHECKINGCHECK_FOR_SHOT:	MOV AL, FIRE_KEY	; check if fire key was pressed	CMP SCAN, AL	JNE NO_FIRE		; if not, check other keys	CMP BULLET_DISAPP, 0	; see if BULLET_DISAPP is set to zero	JNZ GET_NEW_BULLET	; if not, bullet will disappear if...				; ...fire key is pressed again	MOV AL, TOP_SCRN	CMP BULLET_Y, AL	; see if any bullets are on screen	JA  NO_FIRE		; if so, don't shoot another oneGET_NEW_BULLET:	LEA SI, BLANK		; string to plot (blank space)	MOV DL, BULLET_X	; x coordinate of bullet	MOV DH, BULLET_Y	; y coordinate of bullet	MOV BL, 7	CALL OUTPUT_STRING	; output string specified	MOV AL, SHIP_X	INC AL			; start bullet at middle of ship	MOV BULLET_X, AL	; x coordinate for start of bullet	MOV AH, BOTTOM_SCRN	DEC AH	MOV BULLET_Y, AH	; y coordinate for start of bullet	LEA SI, SHIP_FIRE	; string to plot	MOV DL, AL		; x coordinate	MOV DH, AH		; y coordinate	MOV BL, 12	CALL OUTPUT_STRING	; output bullet	CALL CHECK_ALIENS	; check if bullet has hit any aliens	JMP FINISHED_CHECKINGNO_FIRE:	MOV AL, SCAN		; get keypress scan code	AND AL, 7FH		; clear upper bit	CMP AL, QUIT_KEY	; see if the quit key was pressed	JE  TIME_TO_QUIT	CMP AL, PAUSE_KEY	; see if the pause key was pressed	JE  PAUSE	JMP FINISHED_CHECKINGTIME_TO_QUIT:	MOV ENDFLAG, 0		; set flag to indicate time to quit	JMP FINISHED_CHECKINGPAUSE:	MOV SCFLAG, 0	CMP PAUSE_FLAG, 0	; see if in pause mode already	JNZ FINISHED_CHECKING	MOV PAUSE_FLAG, 1	; go into pause mode	PUSH CX	MOV CX, 0FFFFH		; loop to wait for user to stop hitting key	WASTE_TIME2:	PUSH CX	MOV CX, 030H	WASTE_TIME1:	LOOP WASTE_TIME1	POP CX	LOOP WASTE_TIME2	POP CX	MOV SCFLAG, 0	JMP NO_DISPLAY		; bypass the following debugging routine	PUSH SI 	   ; ROUTINE TO DISPLAY BOMB ARRAY ELEMENTS' EXISTENCE	PUSH AX	PUSH BX	PUSH CX	PUSH DX	MOV BX, 0PRINT_ARRAY:	LEA SI, BOMB_EXIST	MOV AH, 0	MOV AL, [BX][SI]	MOV CX, BX	LEA SI, SCRATCH	MOV BX, 10	CALL BINARY_TO_ASCII	MOV DL, 20	MOV DH, CL	CALL OUTPUT_STRING	MOV BX, CX	INC BL	CMP BL, MAX_BOMBS	JB  PRINT_ARRAY	POP DX	POP CX	POP BX	POP AX	POP SINO_DISPLAY:PAUSE_LOOP:	CMP SCFLAG, 0	JE  PAUSE_LOOP	    ; wait for keypress to leave pause loop	MOV SCFLAG, 0	MOV PAUSE_FLAG, 0   ; set flag to indicate pause loop is overFINISHED_CHECKING:	POP SI	POP DX	POP CX	POP BX	POP AX	RETCHECK_KEYS ENDPCHECK_EDGE PROC FAR; Check to see if the x screen coordinate is off the edge of the text screen.; On entry: CL = coordinate to check and correct; On exit:  CL = a valid screen coordinateCHECK_LEFT_EDGE:	CMP CL, LEFT_SCRN	    ; see if at left edge of screen	JGE CHECK_RIGHT_EDGE	MOV CL, LEFT_SCRN	    ; if past left edge, set to left edgeCHECK_RIGHT_EDGE:	CMP CL, RGHT_SCRN	    ; see if at right edge of screen	JBE COORD_ADJUSTED	MOV CL, RGHT_SCRN	    ; if past right edge, set to right edgeCOORD_ADJUSTED:	RETCHECK_EDGE ENDPOUTPUT_SCORE PROC FAR; Display player's score at the top of the screen.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH DX	PUSH SI	MOV DL, 27		    ; specify x coordinate	MOV DH, 0		    ; specify y coordinate	MOV BL, 3		    ; specify text color	LEA SI, GAME_TOP_LINE	    ; point to game title string	CALL OUTPUT_STRING	    ; print it	MOV DL, 68		    ; x coordinate	MOV DH, 0		    ; y coordinate	MOV BL, 5		    ; color	LEA SI, SCORE_STRING	CALL OUTPUT_STRING	    ; output string that says SCORE:	MOV AX, SCORE		    ; pass score value	MOV BX, 10		    ; pass radix value	LEA SI, SCRATCH 	    ; point to loc. to store output string	CALL BINARY_TO_ASCII	    ; convert AX to ASCII and store at SI	MOV BL, 13		    ; set text color	CALL OUTPUT_STRING	    ; output the string at SI	POP SI	POP DX	POP BX	POP AX	RETOUTPUT_SCORE ENDPMOVE_BULLETS PROC FAR; Updates the bullet's progress up the screen; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH DX	PUSH SI	MOV AL, TOP_SCRN	CMP BULLET_Y, AL	; see if any bullets are on screen	JB  DONE_BULLET	MOV AX, BULLET_TOP_DELAY	INC BULLET_DELAY	; increment bullet delay	CMP BULLET_DELAY, AX	; see if bullet delay has reached maximum	JB  DONE_BULLET 	; if not, don't move bullet yet	MOV BULLET_DELAY, 0	; if so, reset delayMOVE_BULLET:	LEA SI, BLANK		; string to plot	MOV DL, BULLET_X	; x coordinate of bullet	MOV DH, BULLET_Y	; y coordinate of bullet	MOV BL, 12	CALL OUTPUT_STRING	; erase old position	DEC DH			; move bullet up screen (negative Y direction)	MOV AL, TOP_SCRN	CMP DH, AL		; check if bullet is off screen	JB  DONE_BULLET 	; if so, no movement is done	MOV BULLET_Y, DH	; update bullet y position	LEA SI, SHIP_FIRE	; specify string to plot	MOV DL, BULLET_X	CALL OUTPUT_STRING	; output new bullet	JMP DONE_BULLETDONE_BULLET:	POP SI	POP DX	POP BX	POP AX	RETMOVE_BULLETS ENDPMOVE_ALIENS PROC FAR; Slide aliens over left or right on the screen.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH CX	MOV AX, ALIEN_TOP_DELAY	INC ALIEN_DELAY 	    ; increase the delay count	CMP ALIEN_DELAY, AX	    ; compare it with the threshhold	JB  DONE_WITH_ALIENS	    ; if below, bypass any movement	MOV ALIEN_DELAY, 0	    ; otherwise, reset the delay & move aliens	MOV AL, ALIEN_SPEED	ADD ALIENS_X, AL	    ; increment x coordinateCHECK_LEFT_SIDE:	MOV AH, LEFT_SCRN	CMP ALIENS_X, AH	    ; see if aliens have hit left side	JGE CHECK_RIGHT_SIDE	JMP REVERSE_DIRECTION	    ; if so, reverse their directionCHECK_RIGHT_SIDE:	MOV CL, RIGHTMOST	; get right-most array index	SUB CL, LEFTMOST	; ...subtract left-most array index from it	INC CL			; add one; CL = number of aliens wide	MOV AL, 5		; width of each alien = 5 spaces	MUL CL			; AX = CL * AL; get width of alien array	SUB AL, 5		; subtract extra spaces (last alien)	ADD AL, ALIENS_X	; add number to x coordinate	MOV AH, RGHT_SCRN	; get right-most edge of screen	CMP AL, AH		; see if x coordinate is off screen	JLE DONE_ALIEN_CHECKING ; if not, then all doneREVERSE_DIRECTION:	NEG ALIEN_SPEED 	; reverse direction of aliens	MOV AL, ALIEN_SPEED	ADD ALIENS_X, AL	; move them	MOV MOVED_DOWN, 1	; set flag saying aliens have just moved down	INC ALIENS_Y		; increase the y coordinate toward scrn bottomDONE_ALIEN_CHECKING:	CALL PRINT_ALIENS	; display the aliens in new positionDONE_WITH_ALIENS:	POP CX	POP AX	RETMOVE_ALIENS ENDPPRINT_ALIENS PROC FAR; Output the block of aliens on the screen at coordinates ALIEN_X, ALIEN_Y.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH CX	PUSH DX	PUSH SI	PUSH DI	CALL FIND_EDGES 	; find leftmost and rightmost aliens	MOV CL, 0		; alien array row numberERASE_OLD_POSITION:	CMP MOVED_DOWN, 0	; check if aliens have recently moved down	JZ  PRINT_ROW		; if not, don't print spaces above the group	MOV MOVED_DOWN, 0	; reset the flag	MOV BH, 0		; set the page	MOV DL, 0		; set x to left side of screen	MOV CL, NUM_ROWS	; set CL to be size of formation	ADD CL, NUM_ROWS	; add NUM_ROWS twice because double-spaced    PRINT_LINES:	MOV DH, ALIENS_Y	; get y coordinate	DEC DH			; set y to just above the alien formation	DEC DH	ADD DH, CL		; start to erase at bottom row	MOV AH, 2		; specify DOS function to set cursor position	INT 10H 		; plot cursor position	MOV AH, 9		; specify DOS function to output characters	MOV AL, 32		; specify "space" as the character	MOV BL, 7		; set the color	PUSH CX	MOV CX, 80		; specify to print the space 80 times	INT 10H 		; print 80 spaces	POP CX	LOOP PRINT_LINES	MOV CL, 0PRINT_ROW:	MOV DL, ALIENS_X	; specify x coordinate	SUB DL, 10		; go left ten spaces (two aliens)	CMP DL, LEFT_SCRN	; see if off screen	JGE PAD_LEFT_SIDE	MOV DL, LEFT_SCRN	; set DL (x coordinate) to at least LEFT_SCRNPAD_LEFT_SIDE:	MOV DH, ALIENS_Y	; get y coordinate	ADD DH, CL		; add offset from formation's top coordinate	ADD DH, CL		; add it again (double-space the aliens)	MOV AH, 2		; specify DOS function to set cursor position	MOV BH, 0		; set the page	INT 10H 		; plot cursor position	MOV BL, 7	LEA SI, PAD_SPACES	; get address of spaces	CALL OUTPUT_STRING	MOV DL, ALIENS_X	; specify x coordinate	INT 10H 		; plot cursor position	MOV BH, 0		; clear upper byte of BX for offset addressing	LEA DI, ALIEN_ROW	; base address for alien row array	MOV AL, ARRAY_WIDTH	; number of aliens in a row	MUL CL			; multiplies array_width * row number = AX...	ADD DI, AX		; move DI to point to start of current row	MOV BL, 0		; start at first alien in rowPRINT_EACH_ALIEN:	CMP BL, LEFTMOST	; see if array index is past leftmost alien	JB  NEXT_ALIEN		; if so, skip plotting anything	CMP BL, RIGHTMOST	; see if array index is past rightmost alien	JA  NEXT_ALIEN		; if so, skip plotting anything	CMP BYTE PTR [DI][BX], 0 ; see if 0 or 1 in alien row array	JZ  NO_ALIEN		; if zero, no alien exists in that positionPLOT_ALIEN:	PUSH BX	LEA SI, ROW_COLOR	MOV BH, 0	MOV BL, CL	MOV AL, [SI][BX]	; get color of row	MOV BL, AL	LEA SI, ALIEN_SHIP	; get ready to plot an alien ship	JMP ALIEN_SPACERNO_ALIEN:	PUSH BX	MOV BL, 7	LEA SI, SHIP_GONE	; get ready to plot space where no alien isALIEN_SPACER:	CALL OUTPUT_STRING	; plot the string noted above by SI	POP BX	PUSH BX	MOV BL, 6	LEA SI, BETWEEN_ALIENS	CALL OUTPUT_STRING	; plot the spacer between aliens	POP BX	CMP BL, RIGHTMOST	; check if at rightmost alien	JNE NEXT_ALIEN		; if not don't print any extra spaces	PUSH BX 		; otherwise, plot some erasing space	MOV BL, 7	LEA SI, PAD_SPACES	; blank space string	CALL OUTPUT_STRING	POP BXNEXT_ALIEN:	INC BL			; go to next memory (array) location	CMP BL, ARRAY_WIDTH	; see if all aliens were plotted yet	JB  PRINT_EACH_ALIEN	; if not, plot the next one in the row	INC CL			; otherwise, go to next row	CMP CL, NUM_ROWS	; see if all rows were printed	JB  PRINT_ROW		; if not, print next row	LEA SI, SPACE_SHIP	; specify SPACE_SHIP string	MOV DL, SHIP_X		; specify ship's x coordinate	MOV DH, BOTTOM_SCRN	; specify ship' y coordinate	MOV BL, 4		; specify color	CALL OUTPUT_STRING	; refresh the ship on the screen	POP DI	POP SI	POP DX	POP CX	POP BX	POP AX	RETPRINT_ALIENS ENDPFIND_EDGES PROC FAR; Locates the most extreme left and right aliens in the block of aliens; and updates the "variables" LEFMOST and RIGHTMOST.; On entry: <nothing>; On exit:  <nothing>	PUSH AX 		; save registers	PUSH BX	PUSH CX	PUSH DX	PUSH DI	MOV AL, LEFTMOST	; save old LEFTMOST value	MOV OLD_LEFT, AL	MOV AL, RIGHTMOST	; save old RIGHTMOST value	MOV OLD_RIGHT, AL	MOV AL, ARRAY_WIDTH	; get furthest x position right	MOV LEFTMOST, AL	; reset LEFTMOST to furthest x position right	MOV RIGHTMOST, 0	; reset RIGHTMOST to furthest x position left	MOV CL, 0		; start at first row numberTRAVERSE_ROW:	MOV BH, 0		; clear upper byte of BX for offset addressing	LEA DI, ALIEN_ROW	; base address for alien row array	MOV AL, ARRAY_WIDTH	; number of aliens in a row	MUL CL			; multiplies array_width * row number = AX...	ADD DI, AX		; move DI to point to start of current row	MOV BL, 0		; start at first alien in rowCHECK_EACH_ALIEN:	CMP BYTE PTR [DI][BX], 0 ; see if 0 or 1 in alien row array	JZ  TRY_NEXT_ALIEN	; if zero, no alien exists in that position	CMP BL, LEFTMOST	; see if alien is further left than LEFTMOST	JB  NEW_LEFTMOST	; if so, update LEFTMOSTCHECK_RIGHT_TOO:	CMP BL, RIGHTMOST	; see if alien is further right than RIGHTMOST	JA  NEW_RIGHTMOST	; if so, update RIGHTMOST	JMP TRY_NEXT_ALIENNEW_LEFTMOST:	MOV LEFTMOST, BL	; reset LEFTMOST alien position	JMP CHECK_RIGHT_TOONEW_RIGHTMOST:	MOV RIGHTMOST, BL	; reset RIGHTMOST alien position	JMP TRY_NEXT_ALIENTRY_NEXT_ALIEN:	INC BL			; go to next memory (array) location	CMP BL, ARRAY_WIDTH	; see if all aliens were checked yet	JB  CHECK_EACH_ALIEN	; if not, go to the next one in the row	INC CL			; otherwise, go to next row	CMP CL, NUM_ROWS	; see if all rows were checked	JB  TRAVERSE_ROW	; if not, print next row	MOV AL, LEFTMOST	CMP AL, OLD_LEFT	; see if leftmost alien position has changed	JE  NO_X_COORD_CHANGE	; if not, aliens continue moving with same x	SUB AL, OLD_LEFT	; otherwise, find out how much it's changed	MOV BL, 5		; get alien width	MUL BL			; multiply width by number of aliens changed	ADD ALIENS_X, AL	; update ALIEN_X for smooth animationNO_X_COORD_CHANGE:	POP DI			; restore registers	POP DX	POP CX	POP BX	POP AX	RETFIND_EDGES ENDPCHECK_ALIENS PROC FAR; Comb over the array of aliens to see if a bullet has hit any.; On entry: <nothing>; On exit:  <nothing>	PUSH AX 		; save registers	PUSH BX	PUSH CX	PUSH DX	PUSH SI	PUSH DI	MOV ALIEN_COUNT, 0	; start with zero aliens accounted for	MOV ALIENS_GONE, 1	; initialize flag to indicate all aliens dead	MOV CL, 0		; start at first row numberINSPECT_ROW:	MOV BH, 0		; clear upper byte of BX for offset addressing	LEA DI, ALIEN_ROW	; base address for alien row array	MOV AL, ARRAY_WIDTH	; number of aliens in a row	MUL CL			; multiplies array_width * row number = AX...	ADD DI, AX		; move DI to point to start of current row	MOV BL, LEFTMOST	; start at first alien in rowINSPECT_ALIEN:	CMP BYTE PTR [DI][BX], 0 ; see if 0 or 1 in alien row array	JZ  MOVE_TO_NEXT_ALIEN	 ; if zero, no alien exists in that positionFIND_COORDS:	MOV AX, 5		; width of an alien	MOV BH, BL	SUB BH, LEFTMOST	; shift in alien array to leftmost alien	MUL BH			; convert from array position to screen offset				; by multiplying 5 * num. of aliens (BH) = AL	MOV BH, 0		; reset BH back to the zero it used to be	ADD AL, ALIENS_X	; add offset to starting x coordinate	MOV AH, AL		; get a copy of alien x coordinate	CMP AL, BULLET_X	; see if x's are same (alien and bullet)	JE  BULLET_X_EQUAL	INC AL			; increment to middle alien character piece	CMP AL, BULLET_X	JE  BULLET_X_EQUAL	INC AL			; increment to last alien character piece	CMP AL, BULLET_X	JE  BULLET_X_EQUAL	JMP ALIEN_FOUNDBULLET_X_EQUAL:	MOV AL, CL		; get y coordinate offset	ADD AL, CL		; double-spaced	ADD AL, ALIENS_Y	; add to starting y coordinate	CMP AL, BULLET_Y	; see if y's are equal	JE  BULLET_Y_EQUAL	JMP ALIEN_FOUNDBULLET_Y_EQUAL:			    ; x and y coords. match; alien dead	MOV BYTE PTR [DI][BX], 0    ; alien killed, place a 0 in the array	PUSH BX	PUSH DX	MOV DL, AH	    ; set x coordinate of alien ship	MOV DH, AL	    ; set y coordinate	MOV BL, 7	    ; set color attribute	LEA SI, SHIP_GONE   ; specify string to print	CALL OUTPUT_STRING  ; print a blank space to erase ship	POP DX	POP BX	MOV AL, TOP_SCRN	DEC AL	MOV BULLET_Y, AL	    ; move bullet off screen (inactivate)	PUSH BX	MOV AX, SCORE		    ; get score	LEA SI, ROW_POINTS	    ; get loc. of start of point val. array	MOV BL, CL	ADD BL, CL		    ; move two spaces in array for each row	ADD AX, WORD PTR [SI][BX]   ; add alien point value to score	MOV SCORE, AX		    ; store the score	POP BX	CALL OUTPUT_SCORE	JMP MOVE_TO_NEXT_ALIENALIEN_FOUND:	MOV ALIENS_GONE, 0	; not all aliens are gone yet	INC ALIEN_COUNT 	; count the number of aliens aliveINSPECT_SHIP:	MOV AL, CL		; get y coordinate offset	ADD AL, CL		; double-spaced	ADD AL, ALIENS_Y	; add to starting y coordinate	CMP AL, BOTTOM_SCRN	; see if alien has reached bottom of screen	JNE MOVE_TO_NEXT_ALIEN	; if not, check next alien	MOV GAME_OVER, 1	; set game over flag to true	CALL PRINT_ALIENS	; print aliens in end-game positionMOVE_TO_NEXT_ALIEN:	INC BL			; go to next memory (array) location	CMP BL, ARRAY_WIDTH	; see if all aliens were checked yet	JB  INSPECT_ALIEN	; if not, go to the next one in the row	INC CL			; otherwise, go to next row	CMP CL, NUM_ROWS	; see if all rows were checked	JB  INSPECT_ROW		; if not, print next rowALIENS_ON_SCREEN:	POP DI			; restore registers	POP SI	POP DX	POP CX	POP BX	POP AX	RETCHECK_ALIENS ENDPMOVE_BOMBS PROC FAR; Updates each bomb's position down the screen.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH CX	PUSH SI	MOV AX, BOMB_DELAY	INC AX			    ; increment the delay for the bombs	MOV BOMB_DELAY, AX	CMP AX, BOMB_TOP_DELAY	    ; see if delay has reached maximum	JB  DONE_MOVING_BOMBS	    ; if not, the bombs aren't moved yet	MOV WORD PTR BOMB_DELAY, 0  ; if so, reset the delay and move them	MOV BX, 0		    ; set array index to zeroADVANCE_ALIVE_BOMBS:	CMP BYTE PTR [BX][SI], 0    ; check if bomb exists	JZ  INC_NEXT_BOMB	    ; if flag is zero, no bomb here	CALL ADVANCE_BOMB	    ; otherwise, advance bomb down the screenINC_NEXT_BOMB:	INC BL			    ; go to next bomb in array	CMP BL, MAX_BOMBS	    ; see if all bombs have been checked	JB  ADVANCE_ALIVE_BOMBS	    ; if not, check next oneDONE_MOVING_BOMBS:	POP SI	POP CX	POP BX	POP AX	RETMOVE_BOMBS ENDPADVANCE_BOMB PROC FAR; Erases bomb's old position, moves it down the screen, checks if the bomb; is still on screen, and draws it again.; On entry: BX = array index of bomb to advance; On exit:  <nothing>	PUSH AX	PUSH DX	PUSH SI	LEA SI, BOMB_X		; store x coordinate in DL	MOV DL, [SI][BX]	LEA SI, BOMB_Y		; store y coordinate in DH	MOV DH, [SI][BX]	PUSH BX	LEA SI, BLANK		; specify a BLANK space to erase bomb old pos.	MOV BL, 7	CALL OUTPUT_STRING	POP BX	INC DH			; move bomb down screen (positive Y direction)	LEA SI, BOMB_Y	MOV [SI][BX], DH	; update bomb y position	CMP DH, BOTTOM_SCRN	; see if bomb is off screen	JA  BOMB_GONE		; if so, no animation is done	PUSH BX	LEA SI, BOMB_X		; store x coordinate in DL	MOV DL, [SI][BX]	LEA SI, ALIEN_BOMB	; specify string to plot	;PUSH AX		; ROUTINE TO PRINT BOMB NO. INSTEAD OF CHAR.	;PUSH BX	;PUSH DX	;MOV AX, BX	;MOV BX, 16	;LEA SI, SCRATCH	;CALL BINARY_TO_ASCII	;POP DX	;POP BX	;POP AX	MOV BL, 12		; specify color of bomb	CALL OUTPUT_STRING	; plot bomb in new position	POP BX	JMP DONE_ADVANCINGBOMB_GONE:	LEA SI, BOMB_EXIST	 ; get array index flag for bomb existence	MOV BYTE PTR [SI][BX], 0 ; set flag indicating bomb no longer existsDONE_ADVANCING:	POP SI	POP DX	POP AX	RETADVANCE_BOMB ENDPGENERATE_BOMB PROC FAR; Decides if another bomb should be dropped, and if so, where.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH CX	PUSH DX	PUSH SI	PUSH DI	MOV AX, BETWEEN_BOMBS	CMP AX, 0	JZ  GET_NEW_BOMB	INC AX	MOV BETWEEN_BOMBS, AX	CMP AX, BETWEEN_BOMBS_TOP	JB  NO_NEW_BOMB	MOV WORD PTR BETWEEN_BOMBS, 0GET_NEW_BOMB:	MOV AH, 2CH	; specify function to get system time	INT 21H 	; call DOS service	MOV AX, 0	; clear register	MOV AL, DL	; place hundredths of a second into AL	MOV CX, AX	; copy AX into CX for later	DIV BYTE PTR BOMB_FACTOR ; reduce chances of bomb appearing...	CMP AH, 0	; ...by checking remainder of division by BOMB_FACTOR	JNZ NO_NEW_BOMB ; if remainder zero, a new bomb is dropped	MOV AX, CX		 ; place the random number into AX again	DIV BYTE PTR ALIEN_COUNT ; choose an alien using MOD function	MOV ALIEN_CHOSEN, AH	 ; place the alien chosen (remainder) aside	MOV ALIEN_POS, 0	; start at alien zero	MOV CL, 0		; start at first row numberCOUNT_THRU_ROWS:	MOV BH, 0		; clear upper byte of BX for offset addressing	LEA DI, ALIEN_ROW	; base address for alien row array	MOV AL, ARRAY_WIDTH	; number of aliens in a row	MUL CL			; multiplies array_width * row number = AX...	ADD DI, AX		; move DI to point to start of current row	MOV BL, LEFTMOST	; start at first alien in rowCOUNT_THRU_ALIENS:	CMP BYTE PTR [DI][BX], 0 ; see if 0 or 1 in alien row array	JZ  GO_TO_NEXT_ALIEN	 ; if zero, no alien exists in that position	INC ALIEN_POS		; increment count of aliens inspected so far	MOV AL, ALIEN_CHOSEN	CMP ALIEN_POS, AL	; see if chosen alien matches current	JNE GO_TO_NEXT_ALIEN	; chosen alien hasn't been found yetFIND_BOMB_COORDS:	MOV AX, 5		; width of an alien	MOV BH, BL	SUB BH, LEFTMOST	; shift in alien array to leftmost alien	MUL BH			; convert from array position to screen offset				; by multiplying 5 * num. of aliens (BH) = AL	MOV BH, 0		; reset BH back to the zero it used to be	ADD AL, ALIENS_X	; add offset to starting x coordinate	INC AL			; set AL to middle of alien, not left side	MOV AH, CL		; get y coordinate offset	ADD AH, CL		; double-spaced	ADD AH, ALIENS_Y	; add to starting y coordinate	MOV BX, 0		; set temporary bomb count register to zeroFIND_EMPTY_INDEX:	LEA SI, BOMB_EXIST	 ; start at beginning of bomb existence array	CMP BYTE PTR [SI][BX], 0 ; see if bomb at this position exists	JZ  FOUND_SPACE 	 ; if not, space is found for a new bomb	INC BL			; go to next array position	CMP BL, MAX_BOMBS	; see if all bombs have been checked	JB  FIND_EMPTY_INDEX	; if not, check next one for empty space	JMP NO_NEW_BOMB 	; otherwise, there's no empty spacesFOUND_SPACE:	;PUSH AX	;PUSH DX	;MOV DL, BEEP	;MOV AH, 02	;INT 21H	;POP DX	;POP AX	LEA SI, BOMB_X	MOV [SI][BX], AL	 ; set bomb starting x position	LEA SI, BOMB_Y	MOV [SI][BX], AH	 ; set bomb starting y position	LEA SI, BOMB_EXIST	MOV BYTE PTR [SI][BX], 1 ; set bomb existence flag to true	MOV WORD PTR BETWEEN_BOMBS, 1  ; start between-bomb loop counter	JMP NO_NEW_BOMBGO_TO_NEXT_ALIEN:	INC BL			; go to next memory (array) location	CMP BL, ARRAY_WIDTH	; see if all aliens were checked yet	JB  COUNT_THRU_ALIENS	; if not, go to the next one in the row	INC CL			; otherwise, go to next row	CMP CL, NUM_ROWS	; see if all rows were checked	JB  COUNT_THRU_ROWS	; if not, print next rowNO_NEW_BOMB:	POP DI	POP SI	POP DX	POP CX	POP BX	POP AX	RETGENERATE_BOMB ENDPCHECK_BOMBS PROC FAR; Checks bombs to see if they've hit the ship.; On entry: <nothing>; On exit:  <nothing>	PUSH AX	PUSH BX	PUSH DX	PUSH SI	MOV BX, 0		    ; set array index to first elementINSPECT_BOMBS:	LEA SI, BOMB_EXIST	    ; start at beginning of BOMB_EXIST array	CMP BYTE PTR [BX][SI], 0    ; check if bomb exists	JZ  CHECK_NEXT_BOMB	    ; if flag is zero, no bomb here	LEA SI, BOMB_X		    ; put bomb x coordinates in DL	MOV DL, [SI][BX]	LEA SI, BOMB_Y		    ; put bomb y coordinate in DH	MOV DH, [SI][BX]	CMP DH, BOTTOM_SCRN	    ; compare y coordinates (bomb and ship)	JNE CHECK_NEXT_BOMB	    ; if not equal, bomb hasn't hit ship	MOV AL, SHIP_X		    ; get ship's x coordinate	CMP DL, AL		    ; compare x coordinates (bomb and ship)	JE  BOMB_HIT		    ; if equal, bomb has hit target	INC AL			    ; check middle character of ship	CMP DL, AL	JE  BOMB_HIT	INC AL			    ; check last character of ship	CMP DL, AL	JE  BOMB_HIT	JMP CHECK_NEXT_BOMB	    ; no x coordinates match; try other bombsBOMB_HIT:	MOV GAME_OVER, 1	    ; ship has been hit, game is overCHECK_NEXT_BOMB:	INC BL			    ; go to next bomb in array	CMP BL, MAX_BOMBS	    ; see if all bombs have been checked	JB  INSPECT_BOMBS	    ; ...if not, check next one	POP SI	POP DX	POP BX	POP AX	RETCHECK_BOMBS ENDPRESTORE_OLD_INT PROC FAR; This procedure taken from Dr. Estell's KB.ASM hand-out.; Restores old interrupt vector, after it had been assigned to be a; keyboard interrupt vector.; On entry: INT_OFF, INT_SEG hold offset and segment of old vector.; On exit:  <nothing>	PUSH AX	PUSH DX	PUSH DS	MOV DX, INT_OFF     ; restore keyboard interrupt vector...	MOV AX, INT_SEG     ; ...the routine pointed to by the...	MOV DS, AX          ; ...address stored in DS:DX	MOV AH, 25H         ; set interrupt vector specified in AL to...	MOV AL, 9H          ; ...the address in DS:DX	INT 21H	POP DS	POP DX	POP AX	RETRESTORE_OLD_INT ENDPDOS_EXIT PROC FAR; Control returned from program to DOS using service 4Ch.; On entry: nothing; On exit:  <no exit>RESTORE_CURSOR:	MOV AH, 2	    ; specify cursor position service	MOV AL, 0	    ; specify null character	MOV BL, 7	    ; set attribute	MOV BH, 0	    ; set page one	MOV CX, 1	    ; print only once	MOV DL, 1	    ; cursor x position	MOV DH, 0	    ; cursor y position	INT 10H		    ; call DOS service	MOV AH, 0BH	    ; set interrupt 10H function	MOV BH, 0	MOV BL, 0	    ; set border color to black	INT 10H 	    ; call DOS serviceQUIT_TO_DOS:	MOV AH, 4CH	; specify MS-DOS service request code	MOV AL, 0       ; specify no error code to be returned	INT 21H         ; to MS-DOSDOS_EXIT ENDPCODESEG ENDS	END     MAIN    ; end of program
