Created
February 27, 2014 18:22
-
-
Save kriskowal/9255736 to your computer and use it in GitHub Desktop.
No, this is the best version of the memory game.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; | |
; CS 30 Assembly | |
; Prof. R. Farrel | |
; Kris Kowal | |
; Programming Assignment #3 | |
; | |
; Memory | |
; by Kris Kowal | |
; 2001-10-04-1604 PDT | |
; | |
; | |
; ABSTRACT: | |
; | |
; Memory is a card game where 2 players exchange turns | |
; fliping pairs of cards from an 8x8 matrix. There are | |
; 32 pairs of cards set face down on the playing board. | |
; The goal is to find the most matching pairs. | |
; | |
; | |
; EXTRAS: | |
; | |
; * Animated Cards | |
; * Mouse Support | |
; * Used XLAT to implement my own deck of cards | |
; with some extended characters for visual variety. | |
; * Card Object system: common data in ds, common | |
; code in cs, and instance specific variables in es, | |
; obtained from the 'heap'. | |
; | |
; | |
; NOTES: | |
; | |
; Failing to find out how to deallocate some of my | |
; memory chunk for a heap, I linked to the UMB's. | |
; | |
; Some time later, in an abandoned warehouse with no | |
; lights, our hero, The Intrepid Cowbert was smacked | |
; with the odd and varrying effects of research: | |
; Adam Elhardt emailed me some solutions to above | |
; problem that he found at < http://www.faqs.org | |
; /faqs/assembly-language/x86/general/part3 | |
; /section-2.html >. | |
; 1.) Resize your program's memory chunk to include | |
; only the program (round up) by tagging the | |
; last segment _end = ? to determine the size. | |
; (I opted not to use this, stuck with UMB) | |
; 2.) Use the builtin _end of .DOSSEG | |
; 3.) Link with the option "/CP:1". In the case that | |
; this program doesn't run, I recommend using the | |
; "make.bat" to this end. | |
; | |
ITSYBITSY textequ <SMALL> | |
; Dr. Pepper is a legal adictive stimulant. Loathe | |
; be the day that the F.D.A. discovers this. | |
; | |
; | |
; STATUS: | |
; | |
; Fully functional | |
; Awaiting improvements from "to do" list | |
; | |
; | |
; TO DO: | |
; | |
; * make.bat | |
; * fix the PressAnyKey to accomodate mouse actions | |
; * Write card randomizer | |
; (consider making the top left 2 match, but everthing | |
; else random and make a note for Prof. Farrel) | |
; | |
; | |
;============================================================================= | |
.MODEL ITSYBITSY | |
.386 | |
.STACK 1024 | |
;============================================================================= | |
;DATA SECTION | |
;(see sub-sections; globals defined in requested zone for portability) | |
.DATA | |
;============================================================================= | |
;CODE SECTION | |
.CODE | |
.STARTUP | |
;----------------------------------------------------------------------------- | |
;Main | |
; | |
; Algorithm: | |
; | |
; Player X is '0' | |
; | |
; DO | |
; | |
; Player 'X' Chooses | |
; | |
; Player 'X' Chooses a Second Card | |
; | |
; If the Cards Match | |
; Player 'X' Gets a Point | |
; Number of Cards Remaining Decreases by 2 | |
; If they Don't Match | |
; The Cards are flipped back | |
; | |
; Player 'X' switches | |
; | |
; WHILE Number of Cards Remaining > 0 | |
; | |
; Announce Winner | |
;===================================================================== | |
.DATA | |
Main_Running byte 1 ;controls exit of game event loop | |
; based on various conditions (user | |
; request exit, end of game) | |
Main_PlayerCurrent byte 0 ;the player number (0|FFh) who is | |
; selecting right now (1 or 2 | |
; respectively) | |
Main_ScoreRemaining byte 32 ;there can be up to 32 scores achieved | |
; in a single game given that there are | |
; 64 cards (32 pairs). this value is | |
; decremented after each score and is | |
; used to detect the end of game. | |
Main_ScorePlayer1 word 0 | |
Main_ScorePlayer2 word 0 | |
Main_CardFocus word 0 ;The offset of the current focused | |
; card | |
Main_Card1 word 0ffh ;The First Card The Player Chose | |
Main_Card2 word 0ffh ;The Second Card The Player Chose | |
;Messages (Asciiz) | |
Main_MsgMatch byte "Match! Press any key...",0 | |
Main_MsgMatchNot byte "No Match. Press any key...",0 | |
Main_MsgWinPlayer1 byte "Player 1 Wins! Press any key...",0 | |
Main_MsgWinPlayer2 byte "Player 2 Wins! Press any key...",0 | |
Main_MsgWinTie byte "Tie Game! Press any key...",0 | |
;===================================================================== | |
.CODE | |
Main PROC | |
call CLS | |
call Cursor_Hide ;rudely shoves the blinking cursor | |
; into Never Never Land | |
;--------------------------------------------------------------------- | |
;get a heap (link to Upper Memory Blocks) | |
mov ah,58h | |
mov al,3 | |
mov bx,1 | |
int 21h | |
;--------------------------------------------------------------------- | |
;START | |
;initialize our Cards array | |
call Cards_Ctor | |
;enable mouse use | |
mov ax,01h | |
int 33h | |
;set initial focus to the first card | |
mov si,offset Cards | |
mov es,[si] | |
call Card_ToggleFocus | |
;print out the initial scores (and current player) | |
call Main_ShowScore | |
;--------------------------------------------------------------------- | |
;RUN | |
;begin an event driven game loop | |
Main_EventLoop: | |
;------------------------------------------------------------- | |
;check keyboard | |
call GetChar | |
;check for no read | |
cmp ah,0ffh | |
je Main_KeyboardEnd | |
;check for exit | |
cmp al,'x' | |
je Main_KeyboardExit | |
cmp al,'q' | |
je Main_KeyboardExit | |
cmp ax,27d ;escape | |
je Main_KeyboardExit | |
;check for advance horizontal | |
cmp al,09h ;tab | |
je Main_KeyboardAdvanceX | |
cmp al,4dh ;right arrow | |
je Main_KeyboardAdvanceX | |
;check for retreat horizontal | |
cmp al,0fh ;shift-tab | |
je Main_KeyboardRetreatX | |
cmp al,4bh ;left arrow | |
je Main_KeyboardRetreatX | |
;check for advance vertical | |
cmp al,50h ;down arrow | |
je Main_KeyboardAdvanceY | |
;check for retreat vertical | |
cmp al,48h ;up arrow | |
je Main_KeyboardRetreatY | |
;check for card select | |
cmp al,13d ;enter | |
je Main_KeyboardSelectCard | |
cmp al,20h ;space | |
je Main_KeyboardSelectCard | |
;end | |
jmp Main_KeyboardEnd | |
Main_KeyboardExit: | |
mov Main_Running,0 | |
jmp Main_KeyboardEnd | |
Main_KeyboardAdvanceX: | |
mov ax,Main_CardFocus | |
add ax,2 ;advance 1 card | |
and ax,1111111b ;cheap way of doing a mod 64 | |
call Main_ChangeCard | |
jmp Main_KeyboardEnd | |
Main_KeyboardRetreatX: | |
mov ax,Main_CardFocus | |
sub ax,2 ;retreat 1 card | |
and ax,1111111b ;cheap way of doing a mod 64 | |
call Main_ChangeCard | |
jmp Main_KeyboardEnd | |
Main_KeyboardAdvanceY: | |
mov ax,Main_CardFocus | |
add ax,16 ;advance 1 row | |
and ax,1111111b ;cheap way of doing a mod 64 | |
call Main_ChangeCard | |
jmp Main_KeyboardEnd | |
Main_KeyboardRetreatY: | |
mov ax,Main_CardFocus | |
sub ax,16 ;advance 1 row | |
and ax,1111111b ;cheap way of doing a mod 64 | |
call Main_ChangeCard | |
jmp Main_KeyboardEnd | |
Main_KeyboardSelectCard: | |
mov ax,Main_CardFocus | |
call Main_SelectCard | |
jmp Main_KeyboardEnd | |
Main_KeyboardEnd: | |
;------------------------------------------------------------- | |
;check mouse | |
mov ax,3h ;query mouse position and status | |
int 33h ;mouse | |
cmp bx,0 ;check for mouse button event | |
je MouseEnd | |
;divide coordinates by 8 | |
shr cx,3 | |
shr dx,3 | |
;make sure the coordinates are within the box | |
cmp cx,20d | |
jl MouseEnd | |
cmp cx,60d | |
jge MouseEnd | |
cmp dx,24d | |
jge MouseEnd | |
;now that we've afirmed that the mouse is in the clickable area | |
sub cx,20 ;shift area left 20 | |
;divide the horizontal by 5 | |
push ax | |
mov al,cl | |
mov bl,5 | |
div bl | |
mov cl,al | |
pop ax | |
;divide the vertical by 3 | |
push ax | |
mov al,dl | |
mov bl,3 | |
div bl | |
mov dl,al | |
pop ax | |
;now, cx,dx is the coordinate of the card in question, | |
;translate to the card number | |
mov ax,dx | |
shl ax,3 | |
add ax,cx | |
shl ax,1 ;mult by 2 to accomodate word size | |
;select that card | |
call Main_SelectCard | |
MouseEnd: | |
;------------------------------------------------------------- | |
cmp Main_Running,0 | |
jne Main_EventLoop | |
;--------------------------------------------------------------------- | |
;STOP | |
;deallocate all memory. unnecessary, granted, but good | |
; practice | |
call Cards_Dtor | |
call CLS | |
call Terminate | |
Main ENDP | |
;----------------------------------------------------------------------------- | |
;Main_ChangeCard | |
; | |
; Moves focus (blinking) from the old card to a new card. | |
; | |
;Expects: | |
; ax, the card offset (card number * 2) to change to | |
; Main_CardFocus, the card to change from | |
;Results: | |
; card at Main_CardFocus ax will be defocused | |
; Main_CardFocus will become ax | |
; the new Main_CardFocus card will be focused | |
Main_ChangeCard PROC | |
push ax | |
push es | |
push si | |
;defocus previous card | |
mov si,offset Cards | |
add si,Main_CardFocus | |
mov es,[si] | |
call Card_ToggleFocus | |
;focus will move to the new card | |
mov Main_CardFocus,ax | |
;focus on the card | |
mov si,offset Cards | |
add si,ax | |
mov es,[si] | |
call Card_ToggleFocus | |
pop si | |
pop es | |
pop ax | |
ret | |
Main_ChangeCard ENDP | |
;----------------------------------------------------------------------------- | |
;Main Select Card | |
; | |
; This is the major game event. When a card is selected (albeit via | |
; mouse click, or keyboard enter or space), the card initiates the card | |
; select. | |
; | |
;Expects: | |
; ax, the card to try to select | |
; | |
;Algorithm: | |
; | |
; If the card is disabled (already used), break out. | |
; | |
; if first card selected by the current player | |
; flip the card | |
; | |
; if second card selected by the current player | |
; | |
; if it's the same card as the first card that was selected | |
; break out | |
; | |
; flip the card | |
; | |
; if the cards don't match | |
; flip both cards back face down | |
; | |
; if the second card matches the first | |
; disable both cards | |
; increase the current player's score | |
; end game if they were the last 2 cards | |
; | |
; switch players | |
; | |
Main_SelectCard PROC | |
push ax | |
push es | |
push si | |
;------------------------------------------------------------- | |
;find card in question | |
mov si,offset Cards | |
add si,ax | |
mov es,[si] | |
;if the card is disabled, no event occurs | |
cmp Card_Disabled,0 | |
jne Main_SelectCardEnd | |
;determine whether this is the first or second card selected | |
; by the given player | |
cmp Main_Card1,0FFh ;check whether the first card has been filled yet | |
jne Main_SelectCardSecond | |
;je Main_SelectCardFirst | |
;------------------------------------------------------------- | |
;if it's the first card, flip it and wait for next card | |
Main_SelectCardFirst: | |
mov Main_Card1,es | |
call Card_Flip | |
jmp Main_SelectCardEnd | |
;------------------------------------------------------------- | |
;If it's the second card, check if match, judge scores, etc. | |
Main_SelectCardSecond: | |
;make sure it isn't the same card as the first | |
mov ax,es | |
cmp ax,Main_Card1 | |
je Main_SelectCardEnd | |
;otherwise, it's just plain nifty to go on flipping this card | |
call Card_Flip | |
mov Main_Card2,es | |
mov ah,Card_Value | |
mov es,Main_Card1 | |
mov al,Card_Value | |
;switch to the next player | |
not Main_PlayerCurrent | |
cmp ah,al | |
jne Main_SelectCardMatchNot | |
;je Main_SelectCardMatch | |
Main_SelectCardMatch: | |
;------------------------------------------------------------- | |
;modify score | |
;check which player's turn it is | |
cmp Main_PlayerCurrent,0 | |
je Main_SelectCardMatchPlayer2 | |
;jne Main_SelectCardMatchPlayer1 | |
Main_SelectCardMatchPlayer1: | |
inc Main_ScorePlayer1 | |
jmp Main_SelectCardMatchPlayerEnd | |
Main_SelectCardMatchPlayer2: | |
inc Main_ScorePlayer2 | |
;jmp Main_SelectCardMatchPlayerEnd | |
Main_SelectCardMatchPlayerEnd: | |
;------------------------------------------------------------- | |
;check for end of game | |
dec Main_ScoreRemaining | |
cmp Main_ScoreRemaining,0 | |
je Main_SelectCardGameEnd | |
;------------------------------------------------------------- | |
;pause, show victory message, reprint score | |
mov dh,20d ;print victory message | |
mov dl,24d | |
call Locate | |
mov si,offset Main_MsgMatch | |
call Asciiz_Print | |
call PressAnyKey ;pause for user | |
call Main_ShowScore ;print out the scores | |
call Card_ToggleDisabled | |
mov es,Main_Card2 | |
call Card_ToggleDisabled | |
;reset the card order | |
mov Main_Card1,0FFh | |
jmp Main_SelectCardEnd ;break | |
;------------------------------------------------------------- | |
Main_SelectCardMatchNot: | |
;pause, show fail message, reprint score | |
mov dh,20d ;print fail message | |
mov dl,24d | |
call Locate | |
mov si,offset Main_MsgMatchNot | |
call Asciiz_Print | |
call PressAnyKey ;pause for user | |
call Main_ShowScore ;print out the scores | |
;flip both cards back down | |
call Card_Flip | |
mov es,Main_Card2 | |
call Card_Flip | |
;reset the card order | |
mov Main_Card1,0FFh | |
jmp Main_SelectCardEnd | |
;------------------------------------------------------------- | |
Main_SelectCardGameEnd: | |
;compare the scores | |
mov ax,Main_ScorePlayer2 | |
cmp Main_ScorePlayer1,ax | |
;select appropriate game end message | |
mov si,offset Main_MsgWinPlayer1 | |
ja Main_SelectCardGameEndFurther | |
mov si,offset Main_MsgWinPlayer2 | |
jb Main_SelectCardGameEndFurther | |
mov si,offset Main_MsgWinTie | |
Main_SelectCardGameEndFurther: | |
mov dh,20d ;print winner | |
mov dl,24d | |
call Locate | |
call Asciiz_Print | |
call PressAnyKey | |
mov Main_Running,0 ;close game | |
;jmp Main_SelectCardEnd | |
;------------------------------------------------------------- | |
Main_SelectCardEnd: | |
pop si | |
pop es | |
pop ax | |
ret | |
Main_SelectCard ENDP | |
;----------------------------------------------------------------------------- | |
;Main Show Scores | |
; | |
; Prints out both players' scores at the bottom of the screen. | |
; Also, highlights the current player. | |
; | |
;Expects: | |
; Main_ScorePlayer1, the score of the first player | |
; Main_ScorePlayer2, the score of the second player | |
; | |
;===================================================================== | |
.DATA | |
Main_ShowScoreDecimalTable byte '0123456789' | |
;translation table | |
Main_MsgScore1 byte "Player 1: " ;the static section | |
Main_MsgScorePlayer1 byte " " ;the mutable section (changes | |
byte 0 ; depending on current score) | |
Main_MsgScore2 byte "Player 2: " | |
Main_MsgScorePlayer2 byte " " | |
byte 0 | |
;===================================================================== | |
.CODE | |
Main_ShowScore PROC | |
push ax | |
push bx | |
push cx | |
push dx | |
push si | |
push di | |
;------------------------------------------------------------- | |
;write the current scores to the score message section | |
mov dl,10d ;for division by 10 general case | |
mov bx,offset Main_ShowScoreDecimalTable ;for xlat | |
;player1 | |
mov ax,Main_ScorePlayer1 | |
div dl | |
;al contains the major digit, al contains the lesser | |
;translate both digits | |
xlat Main_ShowScoreDecimalTable | |
xchg ah,al | |
xlat Main_ShowScoreDecimalTable | |
xchg ah,al | |
mov di,offset Main_MsgScorePlayer1 | |
mov [di],byte ptr al | |
inc di | |
mov [di],byte ptr ah | |
;player2 | |
mov ax,Main_ScorePlayer2 | |
div dl | |
;al contains the major digit, al contains the lesser | |
;translate both digits | |
xlat Main_ShowScoreDecimalTable | |
xchg ah,al | |
xlat Main_ShowScoreDecimalTable | |
xchg ah,al | |
;print out both digits of the score | |
mov di,offset Main_MsgScorePlayer2 | |
mov [di],byte ptr al | |
inc di | |
mov [di],byte ptr ah | |
;------------------------------------------------------------- | |
;set colors for player 1 and 2 score section (to highlight | |
; the current player) | |
;the default color set (bright white and grey respectively) | |
mov ch,0fh | |
mov cl,08h | |
;switch the colors if it's the second player's turn | |
cmp Main_PlayerCurrent,0 | |
je Main_ShowScorePlayer1 | |
xchg ch,cl | |
Main_ShowScorePlayer1: | |
;------------------------------------------------------------- | |
;write player 1 score | |
;set destination to correct coordinates | |
mov dh,20d | |
mov dl,24d | |
call Locate | |
;white (bright or dark depending on player current) | |
mov dl,ch | |
;print score | |
mov si,offset Main_MsgScore1 | |
call Asciiz_PrintAttrib | |
;------------------------------------------------------------- | |
;write player 2 score | |
;set destination to correct coordinates (di) | |
mov dh,40d | |
mov dl,24d | |
call Locate | |
;white (bright or dark depending on player current) | |
mov dl,cl | |
;print the score | |
mov si,offset Main_MsgScore2 | |
call Asciiz_PrintAttrib | |
;------------------------------------------------------------- | |
pop di | |
pop si | |
pop dx | |
pop cx | |
pop bx | |
pop ax | |
ret | |
Main_ShowScore ENDP | |
;----------------------------------------------------------------------------- | |
;Cards Functions | |
; | |
;The cards 'object' only has one instance in static memory. These functions | |
;initialize and deallocate the 64 card array. | |
; | |
;===================================================================== | |
.DATA | |
Cards word 64 dup ( 0 ) | |
;an 8x8 array of cards | |
Cards_ValueTable byte "ABCabcXYZxyz123��?�!�+-/\" | |
;the face values of each pair of cards | |
;===================================================================== | |
.CODE | |
;--------------------------------------------------------------------- | |
;initializes the array of Cards | |
; | |
;Expects: world peace | |
;Results: Cards got Card objects in it | |
Cards_Ctor PROC | |
push ax | |
push bx | |
push cx | |
push dx | |
push di | |
;set up the value table for translation (xlat) | |
mov bx,offset Cards_ValueTable | |
mov dh,20d ;our moving X coordinate | |
mov dl,0d ;our moving Y coordinate | |
mov al,0d ;our moving card value offset * 2 | |
mov cx,64d ;the number of cards to do | |
mov di,offset Cards | |
Cards_CtorLoop: | |
;store the card number for next use and translate into | |
; a face value | |
push ax | |
shr ax,1 | |
xlat Cards_ValueTable | |
;create the card and initialize its values | |
call Card_Ctor | |
mov Card_X,dh | |
mov Card_Y,dl | |
mov Card_Value,al | |
mov Card_Frame,0 | |
mov Card_Disabled,0 | |
mov Card_Focus,0 | |
call Card_Print | |
;save the card's segment to the array of cards | |
mov [di],es | |
;get the old value of ax back (the card number for | |
;calculating its face value) | |
pop ax | |
;increment di for next card's save location | |
add di,2 | |
;increment card number * 2 | |
inc ax | |
;increment coordinates | |
;X | |
add dh,5d | |
cmp dh,60d | |
jb Cards_CtorLoopNoY | |
;Y | |
add dl,3 | |
mov dh,20d | |
Cards_CtorLoopNoY: | |
loop Cards_CtorLoop | |
pop di | |
pop dx | |
pop cx | |
pop bx | |
pop ax | |
ret | |
Cards_Ctor ENDP | |
;--------------------------------------------------------------------- | |
;Cards Destructor | |
; | |
;Expects: Cards contains a complete set of initialized cards | |
;Results: destruction, mayhem and all that | |
Cards_Dtor PROC | |
push cx | |
push di | |
mov cx,64d | |
mov di,offset Cards | |
Cards_DtorLoop: | |
mov es,[di] | |
call Card_Dtor | |
add di,2 | |
loop Cards_DtorLoop | |
pop di | |
pop cx | |
ret | |
Cards_Dtor ENDP | |
;----------------------------------------------------------------------------- | |
;Card Object | |
; | |
;A card object is an instance of the 'Card' type which contains instance | |
;variables in the segment ES. | |
; | |
Card_X equ byte ptr es:[0] ;the card's X screen coord. | |
Card_Y equ byte ptr es:[1] ;...vertical coordinate | |
Card_Value equ byte ptr es:[2] ;the face value of the card | |
Card_Frame equ byte ptr es:[3] ;which animation frame (0-4) | |
Card_Disabled equ byte ptr es:[4] ;true if unflipable, greyed | |
Card_Focus equ byte ptr es:[5] ;if true, blinks | |
;===================================================================== | |
.DATA | |
;--------------------------------------------------------------------- | |
; | |
; 2 Dimensional Strings (null term) for each visual frame that a card | |
; | |
; FaceUp FaceDown | |
; 4 3 2 1 0 | |
; ���ķ �ķ ɸ � ��� | |
; � A � � � ��� � � � ? � | |
; ���ͼ �ͼ Լ ��� ����� | |
; | |
Card_Frame0 byte "���",0 | |
byte "� ? �",0 | |
byte "�����",0 | |
byte 0 | |
Card_Frame1 byte " � ",0 | |
byte " � � ",0 | |
byte " ��� ",0 | |
byte 0 | |
Card_Frame2 byte " ɸ ",0 | |
byte " ��� ",0 | |
byte " Լ ",0 | |
byte 0 | |
Card_Frame3 byte " �ķ ",0 | |
byte " � � ",0 | |
byte " �ͼ ",0 | |
byte 0 | |
Card_Frame4 byte "���ķ",0 | |
byte "� �",0 | |
byte "���ͼ",0 | |
byte 0 | |
;===================================================================== | |
.CODE | |
;--------------------------------------------------------------------- | |
;Card constructor. | |
; | |
;allocates a paragraph of memory from the heap to the card and returns | |
; it in the extra segment. if an error occurs, breaks the program | |
; | |
;Expects: Got Computer? | |
;Results: es contains segment of a new card's instance vars | |
Card_Ctor PROC | |
push ax | |
push bx | |
mov ah,48h ;allocate memory | |
mov bx,01h ;request 16 bytes | |
int 21h ;DOS interrupt | |
;ax now contains the Card's segment | |
; on the Heap | |
jc Error_Memory | |
mov es,ax ;place the card's segment in fs | |
pop bx | |
pop ax | |
ret | |
Card_Ctor ENDP | |
;--------------------------------------------------------------------- | |
;Card destructor | |
; | |
;deallocates the same paragraph that was initialized by Card_Ctor | |
; | |
;Expects: es contains segment of card to be destroyed | |
;Results: *poof* be gone 'es' | |
Card_Dtor PROC | |
push ax | |
mov ah,49h ;deallocate memory function | |
;es already contains the segment of the card | |
int 21h ;DOS interrupt | |
pop ax | |
ret | |
Card_Dtor ENDP | |
;--------------------------------------------------------------------- | |
;print Card to screen | |
; | |
;sends the appropriate card frame to video memory at the card's | |
;coordinates | |
; | |
;Expects: fully initialized Card in es | |
; Card_X | |
; Card_Y | |
; Card_Frame | |
; Card_Disabled | |
; Card_Focus | |
Card_Print PROC | |
push ax | |
push dx | |
push si | |
push di | |
push es | |
push fs | |
;------------------------------------------------------------- | |
;find which frame to print through this tree of al comparisons: | |
; | |
; >3 CardPrint4 | |
; >2 =3 CardPrint3 | |
; =2 CardPrint2 | |
; <2 =1 CardPrint1 | |
; <1 CardPrint0 | |
; | |
mov al,Card_Frame | |
cmp al,2 | |
je Card_Print2 | |
ja Card_Print2Above | |
;jmp Card_Print2Below | |
Card_Print2Below: | |
cmp al,1 | |
je Card_Print1 | |
;jmp Card_Print0 | |
Card_Print0: | |
mov si, offset Card_Frame0 | |
jmp Card_PrintContinue | |
Card_Print2Above: | |
cmp al,3 | |
je Card_Print3 | |
;jmp Card_Print4 | |
Card_Print4: | |
mov si, offset Card_Frame4 | |
jmp Card_PrintContinue | |
Card_Print1: | |
mov si, offset Card_Frame1 | |
jmp Card_PrintContinue | |
Card_Print2: | |
mov si, offset Card_Frame2 | |
jmp Card_PrintContinue | |
Card_Print3: | |
mov si, offset Card_Frame3 | |
;jmp Card_PrintContinue | |
Card_PrintContinue: | |
;------------------------------------------------------------- | |
;get appropriate DI for the card's coordinates | |
mov dh,Card_X | |
mov dl,Card_Y | |
call Locate ;seting di to reflext (x,y) of card | |
;------------------------------------------------------------- | |
;determine the card's color | |
cmp Card_Disabled,0 | |
jne Card_PrintColor1Disabled | |
;je Card_PrintColor1Enabled | |
Card_PrintColor1Enabled: | |
mov dl,0eh ;yellow normally | |
jmp Card_PrintColor1End | |
Card_PrintColor1Disabled: | |
mov dl,08h ;grey if disabled | |
;jmp Card_PrintColor1End | |
Card_PrintColor1End: | |
;------------------------------------------------------------- | |
;determine whether the card is the current focus (blink) | |
cmp Card_Focus,0 | |
je Card_PrintBlinkOff | |
;jne Card_PrintBlinkOn | |
;set the blink bit | |
Card_PrintBlinkOn: | |
or dl,80h | |
jmp Card_PrintBlinkEnd | |
;don't set the blink bit | |
Card_PrintBlinkOff: | |
;jmp Card_PrintBlinkEnd | |
Card_PrintBlinkEnd: | |
;------------------------------------------------------------- | |
;print the card | |
call Asciiz_Print2dAttrib | |
;------------------------------------------------------------- | |
;check whether to print out the value (Frame 3 and 4) | |
cmp al,3 | |
jb Card_PrintNoValue | |
;print the value out | |
mov dh,Card_X ;restore the x coord | |
add dh,2 ;X offset of card val | |
mov dl,Card_Y ;restore the y coord | |
add dl,1 ;Y offset of card val | |
call Locate ;set DI to the coord | |
;make dx a word to put into vram (endian) | |
mov dl,Card_Value | |
;----------------------------------------------------- | |
;determine the card face's foreground color | |
cmp Card_Disabled,0 | |
jne Card_PrintColor2Disabled | |
;je Card_PrintColor2Enabled | |
;white normally | |
Card_PrintColor2Enabled: | |
mov dh,0fh | |
jmp Card_PrintColor2End | |
;grey if disabled | |
Card_PrintColor2Disabled: | |
mov dh,07h | |
;jmp Card_PrintColor2End | |
Card_PrintColor2End: | |
;----------------------------------------------------- | |
;write it directly to vram | |
mov ax,0b800h | |
mov fs,ax ;use FS for the video since | |
;ES is our object segment | |
mov fs:[di],dx ;write the character to the | |
;screen | |
Card_PrintNoValue: | |
;------------------------------------------------------------- | |
pop fs | |
pop es | |
pop di | |
pop si | |
pop dx | |
pop ax | |
ret | |
Card_Print ENDP | |
;--------------------------------------------------------------------- | |
;Card Flipper | |
; | |
; shows a nifty animation sequence of the card flipping. | |
; | |
;Expects: | |
; es, the card's segment | |
;Results: | |
; nifty flippy thing | |
Card_Flip PROC | |
push ax | |
;figure out which way we need to flip this card based on what | |
;frame it is in right now | |
mov al,Card_Frame | |
cmp al,0 | |
jne Card_FlipDown ;Frame 4 = Face Up -> Flip Down | |
;je Card_FlipUp ;Frame 0 = Face Down -> Flip Up | |
Card_FlipUp: | |
;Display an animation sequence of a card 'fliping' | |
mov Card_Frame,1 ;frame number to draw (2d string) | |
call Card_Print ;draw directly to video page 0 | |
call Blink ;pause for animation effect | |
mov Card_Frame,2 | |
call Card_Print | |
call Blink | |
mov Card_Frame,3 | |
call Card_Print | |
call Blink | |
mov Card_Frame,4 | |
call Card_Print | |
jmp Card_FlipEnd | |
Card_FlipDown: | |
mov Card_Frame,3 | |
call Card_Print | |
call Blink | |
mov Card_Frame,2 | |
call Card_Print | |
call Blink | |
mov Card_Frame,1 | |
call Card_Print | |
call Blink | |
mov Card_Frame,0 | |
call Card_Print | |
;jmp Card_FlipEnd | |
Card_FlipEnd: | |
pop ax | |
ret | |
Card_Flip ENDP | |
;--------------------------------------------------------------------- | |
;Toggles between enabled and disabled, then reprints | |
Card_ToggleDisabled PROC | |
xor Card_Disabled,1 | |
call Card_Print | |
ret | |
Card_ToggleDisabled ENDP | |
;--------------------------------------------------------------------- | |
;Toggles the focus value on this card, then reprints | |
Card_ToggleFocus PROC | |
xor Card_Focus,1 | |
call Card_Print | |
ret | |
Card_ToggleFocus ENDP | |
;----------------------------------------------------------------------------- | |
;Timing Functions | |
; | |
;--------------------------------------------------------------------- | |
; | |
Blink PROC | |
push ax | |
push bx | |
push ds | |
push di | |
mov ax,0h ;move to the universal seg | |
mov ds,ax | |
mov di,046Ch ;location of the current | |
; 'time' | |
mov ax,[di] | |
add ax,2h ;number of 'ticks' | |
BlinkLoop: | |
mov bx,[di] ;put the current time in bx | |
cmp ax,bx ;if the current time > first time + | |
; pause time | |
jge BlinkLoop | |
pop di | |
pop ds | |
pop bx | |
pop ax | |
ret | |
Blink ENDP | |
;----------------------------------------------------------------------------- | |
;Keyboard Functions | |
; | |
;--------------------------------------------------------------------- | |
;Wait for character from keyboard and ignore | |
; | |
;Expects: | |
; a constant flow of electrons | |
;Results: | |
; time as sufficiently wasted to accomodate the user's | |
; inability to think fast enough :-). | |
PressAnyKey PROC | |
push ax | |
PressAnyKeyLoop: | |
call GetChar | |
cmp ah,0ffh | |
je PressAnyKeyLoop | |
pop ax | |
ret | |
PressAnyKey ENDP | |
;--------------------------------------------------------------------- | |
;Get a character | |
; | |
;Expects: | |
; nada | |
;Results: | |
; ah 0 for normals, 77, for extendeds, ff for no read | |
; al the determinite character (first for normals, second for extendeds) | |
GetChar PROC | |
push bx | |
push dx | |
mov ah,06h ;check for character input | |
mov dl,0ffh ;request case | |
int 21h ;dos | |
;if there was no key read | |
jz GetCharNone | |
cmp dl,0h | |
je GetCharSpecial ;extended character | |
;jne GetCharNormal ;single normal character | |
;------------------------------------------------------------- | |
GetCharNormal: | |
;set return data | |
mov ah,0 | |
;mov al,al | |
jmp GetCharEnd | |
;------------------------------------------------------------- | |
GetCharSpecial: | |
;if it's an extended character, get the second byte | |
mov ah,06h ;check for character input | |
mov dl,077h ;request case | |
int 21h ;dos | |
;set the return data | |
mov ah,0ffh | |
;mov al,al | |
jmp GetCharEnd | |
;------------------------------------------------------------- | |
GetCharNone: | |
;set the return data | |
mov ah,0ffh | |
mov al,0h | |
;jmp GetCharEnd | |
;------------------------------------------------------------- | |
GetCharEnd: | |
pop dx | |
pop bx | |
ret | |
GetChar ENDP | |
;--------------------------------------------------------------------- | |
;----------------------------------------------------------------------------- | |
;Mouse Functions | |
; | |
;--------------------------------------------------------------------- | |
;Hide the mouse | |
Mouse_Hide PROC | |
push ax | |
mov ax,02h ;hide | |
int 33h ;mouse | |
pop ax | |
ret | |
Mouse_Hide ENDP | |
;--------------------------------------------------------------------- | |
;Show the mouse | |
Mouse_Show PROC | |
push ax | |
mov ax,01h ;show | |
int 33h ;mouse | |
pop ax | |
ret | |
Mouse_Show ENDP | |
;----------------------------------------------------------------------------- | |
;Video Functions | |
;--------------------------------------------------------------------- | |
;Clear Screen | |
Cls PROC | |
push ax | |
;set video mode | |
mov ah,00h | |
mov al,03h | |
int 10h | |
pop ax | |
ret | |
Cls ENDP | |
;--------------------------------------------------------------------- | |
;Hide the Cursor | |
Cursor_Hide PROC | |
push ax | |
push bx | |
push dx | |
mov ah,02h ;function 2, set curosr position | |
mov bh,0h ;video page 0 | |
mov dl,0d ;x = 0 | |
mov dh,27d ;y = beyond screen | |
int 10h ;video interrupt | |
pop dx | |
pop bx | |
pop ax | |
ret | |
Cursor_Hide ENDP | |
;--------------------------------------------------------------------- | |
;Locates an X and Y coordinate by setting DI to X + Y*80 | |
; | |
;Expects: | |
; dl x | |
; dh y | |
;Results: | |
; di x + 80y | |
; | |
Locate PROC | |
push ax | |
push bx | |
push cx | |
movzx ax,dh ;put the x coordinate in ax | |
shl ax,1 ;multiply by 2 (word size) | |
push ax ;put it on the stack | |
movzx ax,dl ;put the y coordinate in ax | |
shl ax,5 ;multiply by 2 (word size) and 80 | |
imul ax,5h ; (row size) | |
pop bx ;take the x offset off the stack | |
add ax,bx ;add the y offset | |
mov di,ax ;put the the total offset in the destination | |
;index to prep print functions | |
pop cx | |
pop bx | |
pop ax | |
ret | |
Locate ENDP | |
;--------------------------------------------------------------------- | |
;Prints a null terminated ASCII string starting at si to coordinate | |
;Expects: | |
; si offset in the data segment where the string can be found | |
; di offset (x+y*80) where we need to print | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Asciiz_Print PROC | |
push ax | |
push es | |
pushfd | |
call Mouse_Hide | |
;set the extra segment to video memory | |
mov ax,0B800h | |
mov es,ax | |
;push the destination index so we can preserve its | |
; value, adding 80 for the next line after we're done | |
push di | |
;clear the direction flag so string opperations | |
; increment | |
cld | |
Asciiz_PrintLoop: | |
lodsb ;get the character from the source string | |
mov ah,07h ;set its attribute | |
stosw ;put the character in vram | |
;check whether to loop (stop if at null | |
cmp [si],byte ptr 00h | |
jne Asciiz_PrintLoop | |
inc si ;increment the source index for | |
; possible further string ops | |
pop di ; | |
add di,160d ;set to the next line | |
call Mouse_Show | |
popfd | |
pop es | |
pop ax | |
ret | |
Asciiz_Print ENDP | |
;--------------------------------------------------------------------- | |
;Prints a null terminated ASCII string starting at si to coordinate | |
; Allows you to define what text attribute all characters will be. | |
;Expects: | |
; si offset in the data segment where the string can be found | |
; di offset (x+y*80) where we need to print | |
; dl text attribute | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Asciiz_PrintAttrib PROC | |
push ax | |
push es | |
pushfd | |
call Mouse_Hide | |
;set the extra segment to video memory | |
mov ax,0B800h | |
mov es,ax | |
;push the destination index so we can preserve its | |
; value, adding 80 for the next line after we're done | |
push di | |
;clear the direction flag so string opperations | |
; increment | |
cld | |
Asciiz_PrintAttribLoop: | |
lodsb ;get the character from the source string | |
mov ah,dl ;set its attribute to dl | |
stosw ;put the character in vram | |
;check whether to loop (stop if at null | |
cmp [si],byte ptr 00h | |
jne Asciiz_PrintAttribLoop | |
inc si ;increment the source index for | |
; possible further string ops | |
pop di ; | |
add di,160d ;set to the next line | |
call Mouse_Show | |
popfd | |
pop es | |
pop ax | |
ret | |
Asciiz_PrintAttrib ENDP | |
;--------------------------------------------------------------------- | |
;Ascii String Printer 2D | |
;Prints a set of sequential null terminated strings until it reaches | |
; a double null. | |
;Expects: | |
; si offset in the data segment where the strings can be found | |
; di offset (x+y*80) where we need to print | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Asciiz_Print2d PROC | |
;print out each string until the double null | |
Asciiz_Print2dLoop: | |
call Asciiz_Print | |
cmp [si],byte ptr 00h | |
jne Asciiz_Print2dLoop | |
ret | |
Asciiz_Print2d ENDP | |
;--------------------------------------------------------------------- | |
;Ascii String Printer 2D With Attribute | |
;Prints a set of sequential null terminated strings until it reaches | |
; a double null. | |
;Expects: | |
; si offset in the data segment where the strings can be found | |
; di offset (x+y*80) where we need to print | |
; dl text attribute | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Asciiz_Print2dAttrib PROC | |
;print out each string until the double null | |
Asciiz_Print2dAttribLoop: | |
call Asciiz_PrintAttrib | |
cmp [si],byte ptr 00h | |
jne Asciiz_Print2dAttribLoop | |
ret | |
Asciiz_Print2dAttrib ENDP | |
;--------------------------------------------------------------------- | |
;Print null terminated VRAM string | |
;Expects: | |
; si offset in the data segment where the strings can be found | |
; di offset (x+y*80) where we need to print | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Vramz_Print PROC | |
push ax | |
push es | |
pushfd | |
call Mouse_Hide | |
;set the extra segment to video memory | |
mov ax,0B800h | |
mov es,ax | |
;push the destination index so we can preserve its | |
; value, adding 80 for the next line after we're done | |
push di | |
;clear the direction flag so string opperations | |
; increment | |
cld | |
Vramz_PrintLoop: | |
lodsw ;get the character and attrib from the source string | |
stosw ;put the character and attrib in vram | |
;check whether to loop (stop if at null | |
cmp [si],byte ptr 00h | |
jne Vramz_PrintLoop | |
inc si ;increment the source index for | |
; possible further string ops | |
pop di ; | |
add di,160d ;set to the next line | |
call Mouse_Show | |
popfd | |
pop es | |
pop ax | |
ret | |
Vramz_Print ENDP | |
;--------------------------------------------------------------------- | |
;Print rows of null terminated VRAM strings | |
;Expects: | |
; si offset in the data segment where the strings can be found | |
; di offset (x+y*80) where we need to print | |
;Results: | |
; si ready for another string print immediately following | |
; the first string's location | |
; di ready for another string print on the next line | |
Vramz_Print2d PROC | |
;print out each string until the double null | |
Vramz_Print2dLoop: | |
call Vramz_Print | |
cmp [si],byte ptr 00h | |
jne Vramz_Print2dLoop | |
ret | |
Vramz_Print2d ENDP | |
;----------------------------------------------------------------------------- | |
;Standard Functions | |
;===================================================================== | |
.DATA | |
ErrorMsg_Memory byte "Memory Error!",0 | |
;===================================================================== | |
.CODE | |
;--------------------------------------------------------------------- | |
;Memory Allocation Error Handler | |
Error_Memory: | |
mov si,offset ErrorMsg_Memory | |
mov di,0 | |
call CLS | |
call Asciiz_Print | |
call Terminate | |
call Terminate | |
;--------------------------------------------------------------------- | |
;End the Program Gracefully | |
Terminate PROC | |
mov ah,4Ch | |
mov al,0h | |
int 21h | |
Terminate ENDP | |
;--------------------------------------------------------------------- | |
;============================================================================= | |
END |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment