.MODEL SMALL .DATA ;THIS IS VIDEO BUFFER ;WE DRAW THE PICTURE HERE, THEN COPY IT TO THE SCREEN ;THIS WAY THE DRAWING LOOKS SMOOTH SCROLLBUFFER DW 80*50+80*16 DUP(0) ;SIZE OF THE SCREEN VIDEO MEMORY PLUS 16 LINES FOR SCROLLING ;A GREEN TREE ON BLACK BACKGROUND ;7 CHARACHTERS WIDE ;9 CHARACHTERS HIGH TREE DW 0020H, 0020H, 0020H, 021EH, 0020H, 0020H, 0020H DW 0020H, 0020H, 021EH, 021EH, 021EH, 0020H, 0020H DW 0020H, 0020H, 0020H, 021EH, 0020H, 0020H, 0020H DW 0020H, 0020H, 021EH, 021EH, 021EH, 0020H, 0020H DW 0020H, 021EH, 021EH, 021EH, 021EH, 021EH, 0020H DW 0020H, 0020H, 0020H, 021EH, 0020H, 0020H, 0020H DW 0020H, 0020H, 021EH, 021EH, 021EH, 0020H, 0020H DW 0020H, 021EH, 021EH, 021EH, 021EH, 021EH, 0020H DW 021EH, 021EH, 021EH, 021EH, 021EH, 021EH, 021EH ;COLORFUL CAR (FORWARD) ;5 CHARACTERS WIDE ;7 CHARACTERS HIGH ;CAR BACKGROUND MUST BE BLUE CARF DW 1020H, 18DCH, 1020H, 18DCH, 1020H DW 10DBH, 4ADAH, 4AC4H, 4ABFH, 10DBH DW 10DBH, 4AB3H, 4FB1H, 4AB3H, 10DBH DW 1020H, 4AC3H, 4AC4H, 4AB4H, 1020H DW 10DBH, 4AB3H, 4A1EH, 4AB3H, 10DBH DW 10DBH, 4AB3H, 4A1EH, 4AB3H, 10DBH DW 4ACDH, 4ACFH, 4ACDH, 4ACFH, 4ACDH ;COLORFUL CAR (BACKWARD) ;5 CHARACTERS WIDE ;7 CHARACTERS HIGH ;CAR BACKGROUND MUST BE BLUE CARB DW 4ACDH, 4AD1H, 4ACDH, 4AD1H, 4ACDH DW 10DBH, 4AB3H, 4A1FH, 4AB3H, 10DBH DW 10DBH, 4AB3H, 4A1FH, 4AB3H, 10DBH DW 1020H, 4AC3H, 4AC4H, 4AB4H, 1020H DW 10DBH, 4AB3H, 4FB1H, 4AB3H, 10DBH DW 10DBH, 4AC0H, 4AC4H, 4AD9H, 10DBH DW 1020H, 18DFH, 1020H, 18DFH, 1020H ;THIS BUFFER CONTAINS WHAT IS UNDER THE CAR UNDERCAR DW 5*7 DUP(0) UNDERCAR_X DW 0 ; X COORDINATE OF THE CAR UNDERCAR_Y DW 0 ; Y COORDINATE OF THE CAR ;MAJOR VARIABLES SPEED DW 10 SCROLL DW 0 CAR_X DW 45 CAR_Y DW 45 LASTKEY DB 0 RNDSEED DW 1658H MUSIC DW 1700,1000,1250,0FFFFh .CODE .STARTUP ;Initialize video memory, clear screen mov ah, 6 ;function code mov al, 0 ;clear screen mov ch, 0 ;upper left row mov cl, 0 ;upper left column mov dh, 49 ;lower right row mov dl, 79 ;lower right column mov bh, 00000111b ;screen attribute for cleared area int 10h ;INITIALIZE ES TO BE EQUAL DS ;OTHERWISE THE STRING INSTRUCTIONS MAY NOT WORK PUSH DS POP ES ;SET AUTOINCREMENT FOR STRING OPERATIONS CLD ;CLEAR SCREEN CALL CLEARSCREEN ;DRAW THE ROAD MOV AX, 66 CALL DRAWROAD ;DRAW A CAR FACING FORWARD MOV AX, 67 MOV BX, 23 MOV CX, 0 CALL DRAWACAR ;DRAW A CAR FACING BACKWARD MOV AX, 30 MOV BX, 15 MOV CX, 1 CALL DRAWACAR ;DRAW ANOTHER CAR FACING BACKWARD MOV AX, 15 MOV BX, 35 MOV CX, 1 CALL DRAWACAR ;DRAW ONE MORE CAR FACING BACKWARD MOV AX, 25 MOV BX, 35 MOV CX, 1 CALL DRAWACAR ;DRAW A TREE MOV AX, 4 MOV BX, 30 CALL DRAWATREE ;DRAW A TREE MOV AX, 67 MOV BX, 15 CALL DRAWATREE ;DRAW A TREE MOV AX, 4 MOV BX, 70 CALL DRAWATREE ;DRAW A TREE MOV AX, 72 MOV BX, 37 CALL DRAWATREE ;DRAW A TREE MOV AX, 45 MOV BX, 30 CALL DRAWATREE ;CONTROL LOOP MOV DX, 16 MOV AX, 45 MOV BX, 35 MOV CX, 0 CALL SAVEUNDERCAR CONTROL: ;CHECK IF A KEY HAS BEEN PRESSED, RETRIEVE THE LAST KEY MOV LASTKEY, 0 ; RESET LAST KEY BY WRITING 0 GETAKEY: MOV AH,1 ;CHECK IF THERE IS A KEY IN THE BUFFER INT 16H JZ KEYTESTS MOV AH,0 INT 16H MOV LASTKEY, AL JMP GETAKEY ;REMOVE ALL KEYS FROM THE BUFFER ;THE RESULT IS IN LASTKEY KEYTESTS: CMP LASTKEY, 27; ESCAPE JE TERMINATE CMP LASTKEY, 2CH ;TEST FOR LEFT < JNE CMP1 ;IF LEFT ARROW AND CAR_X>20, DECREMENT CAR_X, ELSE GO TO NEXT COMPARISON DEC cAR_X CMP CAR_X, 20 JAE CMP1 MOV CAR_X,20 CMP1: CMP LASTKEY, 2EH ;TEST FOR RIGHT > JNE CMP2 ;IF RIGHT ARROW AND CAR_X<55, INCREMENT CAR_X, ELSE GO TO NEXT COMPARISON INC cAR_X CMP CAR_X, 55 JBE CMP2 MOV CAR_X, 55 CMP2: CMP LASTKEY, 7AH ;TEST Z (SPEED UP) JNE CMP3 ;IF Z AND SPEED >1, DECREMENT SPEED, ELSE GO TO NEXT COMPARISON DEC SPEED CMP SPEED, 1 JAE CMP3 MOV SPEED, 1 CMP3: CMP LASTKEY, 78H ;TEST FOR X (BREAK) JNE NOKEY ;IF X AND SPEED <10, INCREMENT SPEED, ELSE GO TO NEXT COMPARISON INC SPEED CMP SPEED, 10 JBE NOKEY MOV SPEED, 10 NOKEY: CALL RESTOREUNDERCAR ;IF SPEED IS EQUAL TO 10, STOP SCROLLING CMP SPEED, 10 JE SKIPDRAWNEW CALL SCROLLVIDEO INC SCROLL CMP SCROLL, 16 JNZ SKIPDRAWNEW CALL DRAWNEW MOV SCROLL, 0 ;DRAW A CAR FACING FORWARD SKIPDRAWNEW: MOV AX, CAR_X MOV BX, CAR_Y MOV CX, 0 CALL SAVEUNDERCAR CALL DRAWACAR ;COPY ALL TO THE SCREEN CALL COPYTOSCREEN ;CHECK FOR COLLISION CALL CHECKCOLLISION CMP AX, 0 JNZ TERMINATE PUSH AX MOV AX, SPEED CALL DELAY POP AX DEC DX JMP CONTROL TERMINATE: CALL PLAYATUNE MOV AH,0 INT 16H .EXIT ;CLEARSCREEN DOES NOT TAKE ANY PARAMETERS ;IT FILLS THE SCROLLBUFFER WITH BLACK/DARKGRAY SPACES CLEARSCREEN PROC NEAR PUSH AX PUSH CX PUSH DI MOV AX, 0820H MOV CX, 80*66 ; NUMBER OF WORDS TO COPY MOV DI, OFFSET SCROLLBUFFER REP STOSW POP DI POP CX POP AX RET CLEARSCREEN ENDP ;THIS PROCEDURE TAKES THE NUMBER OF HORIZONTAL LINES IN AX ;THE MODIFICATIONS ARE PERFORMED IN SCROLLBUFFER ;IT SHOULD DRAW A BLUE STRIPE VERTICALLY FROM X=20 TO X=60 ;IT SHOULD ALSO DRAW YELLOW DASHED SEPARATOR LINE DRAWROAD PROC NEAR USES AX BX CX DI MOV cX, AX ;COUNTER MOV AX, 1120H ;BLUE/BLUE SPACE MOV DI, OFFSET SCROLLBUFFER+40 ;ADD TWICE THE AMOUNT OF SPACES ASTRIPE: MOV BX, CX ; TEMPORARY SAVE MOV CX, 40 ;WIDTH OF THE ROAD REP STOSW ;DRAW A HORIZONTAL STRIPE RCR BX,1 ;ROTATE RIGHT TWICE (DIVIDE BY 4) RCR BX,1 ;ROTATE RIGHT TWICE (DIVIDE BY 4) JC SKIP ;DO NOT DRAW IF C=1 MOV [DI-40], WORD PTR 7EDBH ;sUBTRACT TWICE THE AMOUNT OF FILLED SPACES SKIP: RCL BX,1 ;RESTORE BX RCL BX,1 ;RESTORE BX ADD DI, 80 ;ADDRESS FOR THE NEXT STRIPE MOV CX, BX LOOP ASTRIPE RET DRAWROAD ENDP ;THIS PROCEDURE DOES NOT HAVE PARAMETERS ;COPIES THE CONTENT OF THE LOWER PART OF SCROLLBUFFER TO A MEMORY BLOCK STARTING ;AT B800:0000 COPYTOSCREEN PROC NEAR USES ES SI DI CX MOV DI, 0B800H MOV ES, DI MOV DI, 0 MOV SI, OFFSET SCROLLBUFFER + 2*16*80 MOV CX, 80*50 REP MOVSW RET COPYTOSCREEN ENDP ;THIS PROCEDURE TAKES 0<=X<=73 AND 0<=Y<=57 OF THE UPPER LEFT CORNER OF THE TREE IMAGE ;AS INPUT PARAMETERS IN THE REGISTERS Ax (X) AND BX (Y) ;IF X>73 OR 1257 THEN RETURN WITHOUT DOING ANYTING ;ELSE COPY THE TREE IMAGE INTO THE SPECIFIED POSITION IN VIDEO BUFFER DRAWATREE PROC NEAR PUSH BX PUSH CX PUSH DI CMP BX, 57 ;CHECK Y JA RETURN CMP AX, 73 ;cHECK X JA RETURN CMP AX, 12 ;CHECK X JBE DRAW CMP AX, 61 ;CHECK X JB RETURN DRAW: ;COMPUTE THE INITIAL DESTINATION OFFSET FOR DI MOV DI, OFFSET SCROLLBUFFER ADD DI, AX ADD DI, AX ;X COORDINATE PUSH AX ; COMPUTE Y*160 WHERE 160 IS THE SIZE OF A HORIZONTAL LINE ON THE SCREEN MOV AX, 160 MUL BL ADD DI, AX POP AX ;COPY TO THE SCROLLBUFFER MOV CX, 9 ; 9 HORIZONTAL LINES MOV SI, OFFSET TREE ; TAKE DATA FROM HERE COPY: MOV BX, CX ; SAVE TEMPORARILY MOV CX, 7 ; 7 WORDS REP MOVSW ; COPY THE DATA ADD DI, 146 ; NEXT HORIZONTAL LINE (ADD 160-14 BYTES) MOV CX, BX ; RESTORE LINE COUNTER LOOP COPY RETURN: POP DI POP CX POP BX RET DRAWATREE ENDP ;THIS PROCEDURE TAKES 20<=X<=55 AND 0<=Y<=59 OF THE UPPER LEFT CORNER OF THE CAR IMAGE ;AS INPUT PARAMETERS IN THE REGISTERS Ax (X) AND BX (Y) ;IF X>55 OR X<20 OR Y>59 THEN RETURN WITHOUT DOING ANYTING ;ELSE COPY THE CAR IMAGE INTO THE SPECIFIED POSITION IN VIDEO BUFFER ;ANOTHER PARAMETER IS CAR DIRECTION: ;CL=0 - FORWARD DIRECTION (TO THE TOP OF THE SCREEN) ;CL=1 - BACKWARD DIRECTION (TO THE BOTTOM OF THE SCREEN) DRAWACAR PROC NEAR PUSH BX PUSH CX PUSH DI CMP BX, 59 ;CHECK Y JA RETURN CMP AX, 20 ;cHECK X JB RETURN CMP AX, 55 ;CHECK X JA RETURN ;COMPUTE THE INITIAL DESTINATION OFFSET FOR DI MOV DI, OFFSET SCROLLBUFFER ADD DI, AX ADD DI, AX ;X COORDINATE PUSH AX ; COMPUTE Y*160 WHERE 160 IS THE SIZE OF A HORIZONTAL LINE ON THE SCREEN MOV AX, 160 MUL BL ADD DI, AX POP AX ;SELECT DRAWING FORWARD OR BACKWARDS MOV SI, OFFSET CARF TEST CL, CL JZ SKIP MOV SI, OFFSET CARB ;COPY CAR IMAGE TO THE SCROLLBUFFER SKIP: MOV CX, 7 ; 7 HORIZONTAL LINES COPY: MOV BX, CX ; SAVE TEMPORARILY MOV CX, 5 ; 5 WORDS REP MOVSW ; COPY THE DATA ADD DI, 150 ; NEXT HORIZONTAL LINE (ADD 160-10 BYTES) MOV CX, BX ; RESTORE LINE COUNTER LOOP COPY RETURN: POP DI POP CX POP BX RET DRAWACAR ENDP ;THIS PROCEDURE SCROLLS THE VIDEO BUFFER ONE LINE DOWN ;MUST USE AUTODECREMENT MODE FOR STRING OPERATIONS SCROLLVIDEO PROC NEAR USES SI DI CX MOV DI, OFFSET SCROLLBUFFER + 2*80*66 ; THE LAST BYTE OF THE VIDEO BUFFER MOV SI, OFFSET SCROLLBUFFER + 2*80*65 ; THE LAST BYTE OF THE PREVIOUS LINE MOV CX, 80*65 ;COPY 65 LINES STD ;USE AUTODECREMENT REP MOVSW CLD ;RESTORE AUTOINCREMENT RET SCROLLVIDEO ENDP ;THIS PROCEDURE CREATES A SMALL DELAY ;VALUE IN THE AX SPECIFIES THE DELAY (1-10) ;AX=1 IS THE SHORTEST DELAY ;THE TIMING LOOPS MAY NEED TO BE ADJUSTED DEPENDING ON THE PROCESSOR SPEED DELAY PROC NEAR USES AX CX BX L: MOV BX, 00100H L1: MOV CX, 0FFFFH L2: NOP LOOP L2 DEC BX JNZ L1 DEC AX JNZ L RET DELAY ENDP ;AX - X ;BX - Y ; CAR SIZE IS 5X7 SAVEUNDERCAR PROC NEAR USES SI DI CX BX MOV UNDERCAR_X, AX ; SAVE X AND Y IN MEMORY (UNDERCAR_X AND UNDERCAR_Y) MOV UNDERCAR_Y, BX ;COMPUTE THE INITIAL SOURCE OFFSET FOR SI MOV SI, OFFSET SCROLLBUFFER ADD SI, AX ADD SI, AX ;X COORDINATE PUSH AX ; COMPUTE Y*160 WHERE 160 IS THE SIZE OF A HORIZONTAL LINE ON THE SCREEN MOV AX, 160 MUL BL ADD SI, AX POP AX MOV DI, OFFSET UNDERCAR ;COPY MOV BX, 7 COPY: MOV CX, 5 REP MOVSW ADD SI, 150 ; NEXT LINE ADD 160-5*2 DEC BX JNZ COPY RET SAVEUNDERCAR ENDP RESTOREUNDERCAR PROC NEAR USES AX BX SI DI CX MOV AX,UNDERCAR_X ; RESTORE X AND Y FROM MEMORY (UNDERCAR_X AND UNDERCAR_Y) MOV BX,UNDERCAR_Y ;COMPUTE THE INITIAL DESTINATION OFFSET FOR DI MOV DI, OFFSET SCROLLBUFFER ADD DI, AX ADD DI, AX ;X COORDINATE PUSH AX ; COMPUTE Y*160 WHERE 160 IS THE SIZE OF A HORIZONTAL LINE ON THE SCREEN MOV AX, 160 MUL BL ADD DI, AX POP AX MOV SI, OFFSET UNDERCAR MOV BX, 7 COPY: MOV CX, 5 REP MOVSW ADD DI, 150 ; NEXT LINE ADD 160-5*2 DEC BX JNZ COPY RET RESTOREUNDERCAR ENDP ;TASK 1 ;16 LINES HAVE BEEN SCROLLED OUT ;RANDOMLY DRAW NEW STUFF ON TOP OF THE SCROLLBUFFER DRAWNEW PROC NEAR USES AX BX ; In this procedure you have to redraw 16 lines of the road ; and randomly draw trees on the sides and cars on both lanes ; (in the SCROLLBUFFER) ; This procedure is called after the sreen has been scrolled ; 16 times, therefore it is time to draw new stuff on it ; First, redraw 16 rows of the road by calling DRAWROAD with ; properly set parameters ; Second, randomly draw a car either in the left or right lane. ; You will use function RANDOM that returns a value between ; 0000H-FFFFH in register AX. ; - call RANDOM and use the result returned in AX to decide ; whether to draw a car in the left or right lane ; One way to do so is to compare the result to a threshold value ; If AX is more then threshold choose one lane, if less - another ; - call RANDOM again. Use binary masks and AND instruction to ; make sure that value in AX is between 0 and 15 ; if the car is to be drawn in the left lane, add 20 to AX ; if the car is to be drawn in the right lane, add 39 to AX ; This will be X coordinate for the car. Temporary store it. ; - call RANDOM again. Reduce the value in AX to 0-7 range using ; the same technique as before. This will be Y coordinate for the ; car. ; - make sure that parameters are properly set and call DRAWCAR. ; If you are drawing a car in the left lane, make sure it faces down, ; and faces up in the right lane. (it is a parameter for DRAWCAR) ; Third, draw a tree on the left side ; -call RANDOM, reduce the result to 0-15 range. This is X coordinate. ; -set Y to be 5 (a parameter DRAWTREE takes) and call DRAWTREE ; Fourth, draw a tree on the right side ; -call RANDOM, reduce the result to 0-15 range. ; Add 61 to the AX. This is X coordinate. ; -set Y to be 5 (a parameter DRAWTREE takes) and call DRAWTREE RET DRAWNEW ENDP ;THIS PROCEDURE DOES NOT TAKE PARAMETERS ;RETURNS A RANDOM NUMBER 0-65535 IN AX RANDOM PROC NEAR PUSH DX MOV AX, RNDSEED MOV DX,45439 TEST AX, AX JE RANDHI MUL DX RANDHI: SUB AX, DX ADC AX,0 MOV RNDSEED, AX POP DX RET RANDOM ENDP PLAYATUNE PROC NEAR USES AX CX DX SI MOV SI, OFFSET MUSIC MORE: MOV BX,[SI] ; NOTE IN HZ INC SI INC SI CMP BX, 0FFFFH ; JE STOP MOV AX,34DDH MOV DX,0012H CMP DX,BX JNC STOP DIV BX MOV BX,AX IN AL,61H TEST AL,3 JNZ L99 OR AL,3 OUT 61H,AL MOV AL,0B6H OUT 43H,AL L99: MOV AL,BL OUT 42H,AL MOV AL,BH OUT 42H,AL MOV AX,10 CALL DELAY JMP MORE STOP: IN AL, 61H ;{ Now turn off the speaker } AND AL, 0FCh OUT 61H, AL RET PLAYATUNE ENDP ; TASK 2 CHECKCOLLISION PROC NEAR ; in a loop look through the content of UNDERCAR ; if any 16-bit word inside UNDERCAR is not equal to ; 1120H (space with blue background) or not equal to ; 7EDB (filled rectangle with yellow foreground) ; then set AX to be 1 (indicate collision) ; otherwise set AX to be 0 (indicate no collision: ; ; Make sure you do not change any registers other than AX RET CHECKCOLLISION ENDP END