Skip to content

Instantly share code, notes, and snippets.

@kriskowal
Created February 27, 2014 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kriskowal/9255736 to your computer and use it in GitHub Desktop.
Save kriskowal/9255736 to your computer and use it in GitHub Desktop.
No, this is the best version of the memory game.
;
; 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