Alyce Alyce Jul 11, 2011 - "Undeleted revision of Jul 11, 2011 8:34 am"

QCard DLL Lesson 10

Lesson 9 Lesson 11

- Alyce Alyce
QCard DLL Lesson 10 | More on Card Dragging | Blocked Cards | Blocking Some Cards | Preventing the Drag of Blocked Cards | Offset Value | DEMO
See Lesson 1 for QCard DLL and WAV files needed for the demo code.

More on Card Dragging


In the previous demo we allowed the user to right-click on a card and drag it around. When the user released the button the card was dropped in a new position. We paid no attention to the card's status or to the location it was dropped. In a real game we'd need to monitor all such activity.

Blocked Cards


QCard has two functions to set and query the blocked status of a card. A card can be marked as blocked if it is covered or partially covered by another card. QCard lets us set the "blocked" status with AdjustCardBlocked. We can query the "blocked" status of a card with GetCardBlocked. The API calls look like this:

    calldll #qc, "AdjustCardBlocked",_
        nC as long,_     'index of card to block/unblock
        bValue as long,_ '1=blocked, 0=unblocked
        re as void       'no return
 
    calldll #qc, "GetCardBlocked",_
        nC as long,_       'index of card to query
        isBlocked as long  '1=blocked, 0=unblocked

Blocking Some Cards


In our demo, we'll change the display so that the rows of cards overlap. Each row is 20 pixels below the previous row. When we deal the first three rows we'll also set the "blocked" status of each card in that row to "blocked". We will leave the cards in the fourth row with the default "unblocked" status. We've introduced a variable called "row" to keep track of the row being dealt.

    x=10:y=2:row=1
    for i = 1 to 24
        Call DealCard hBox,card(i),x,y
        'When creating a row or pile of cards,
        'only the topmost card should have an
        'IsBlocked value of FALSE.
        if row<4 then call AdjustCardBlocked card(i),1
 
        x=x+100
        if x>510 then   'move to next row
            x=10
            y=y+offset
            row=row+1
        end if
        playwave "card.wav",sync
 
       'pause 100 milliseconds between cards
        call Pause 100
        scan
    next

Preventing the Drag of Blocked Cards


When the user right-clicks the mouse we'll use the coordinates from the deal to discover which card in our card array was clicked by comparing MouseX and MouseY positions with the locations in the grid. Once we find the array index we can get the value of the card at that index and query its blocked status.

If the card is blocked we document that at the bottom of the display and halt the routine. If it is not blocked, we begin the dragging procedure, as we did in the last lesson.

[initDrag]
    gosub [checkIndex]      'find out which card on table was clicked
    if clickCard=0 then wait
    nCard=card(clickCard)   'find value of card from our card array
    isBlocked=GetCardBlocked(nCard)    'see if card is blocked
    if isBlocked<>0 then
        'if card is blocked, inform user, then do nothing
        #1.g "place 10 420;\BLOCKED Card Index is ";nCard;space$(100)
        wait
    end if
    cardIndex=InitDrag(hBox,MouseX,MouseY)
    #1.g "place 10 420;\Drag Card Index is ";nCard;space$(100)
    #1.g "when rightButtonMove [doDrag]"
    wait

In a real game you'd want to set the blocked status of the newly uncovered card to 0. You'd also need to set the card that was just covered by the dragged card to "blocked". We did not complicate the code with these routines in order to keep the demo program short and understandable.

Offset Value


QCard has a default offset value of 16 pixels. The cards are 70x95 pixels and if one card is dealt atop another, but 16 pixels lower both card values will be visible. This offset is important in block dragging operations. We are dragging a single card, so it is not critical to our demo.

Even though it is not necessary for our demo, we've used this opportunity to show how to change the offset with SetOffSet.

    calldll #qc, "SetOffSet",_  'change pixel offset for vertical colums of cards
        offset as long,_        'number of pixels to offset
        re as void


DEMO

See Lesson 1 for QCard DLL and WAV files needed for the demo code.

The demo deals the cards in four overlapped rows. It sets the blocked status of cards in the first three rows. It checks the blocked status of the card clicked by the user. It allows the user to drag the card if the designated card status is "unblocked".

'An open project card game, begun by Alyce Watson, May 27, 2003.
'Uses Qcard32.dll, a freeware library of playing card images.
'DLL by Stephen Murphy.  Qcard32.DLL website:
'http://www.telusplanet.net/public/stevem/
 
dim card(24)            'array to hold cards
gosub [fillCardArray]   'fill array with card values
newIndex=0              'used when shuffling
tempCard=0              'temp var used when shuffling
 
[varSetup]
i=0         'i will be our counter var in for/next loops
design=1    'default design is circles
offset=20   'offset for card vertical spacing for dragging purposes
 
nomainwin
    WindowWidth=640:WindowHeight=480
    UpperLeftX=1:UpperLeftY=1
 
    menu #1, "&File", "&New",[new],"E&xit", [quit]
    graphicbox #1.g, 0, 0, 640, 440
    open "Dragging Cards" for window_nf as #1
    #1 "trapclose [quit]"
 
    'get graphicbox handle
    hBox=hwnd(#1.g)
 
    'open the dll
    open "qcard32.dll" for dll as #qc
    'initialize the deck
    Call InitializeDeck hBox
 
[new]
    Call SetDefaultValues
 
    'draw a nice background
    #1.g "down; fill 10 190 225"
    #1.g "backcolor 10 190 225"
    'temp message for this demo only
    #1.g "place 10 420"
    #1.g "\Right-click on a card, then move mouse to drag and drop it."
    gosub [shuffleCards]
 
    offset=20
    call SetOffSet offset    'set offset to 20 pixels - default is 16
 
    'set xy location to start deal
    x=10:y=2:row=1
    for i = 1 to 24
        Call DealCard hBox,card(i),x,y
        'When creating a row or pile of cards,
        'only the topmost card should have an
        'IsBlocked value of FALSE.
        if row<4 then call AdjustCardBlocked card(i),1
 
        x=x+100
        if x>510 then   'move to next row
            x=10
            y=y+offset
            row=row+1
        end if
        playwave "card.wav",sync
 
       'pause 100 milliseconds between cards
        call Pause 100
        scan
    next
    #1.g "when rightButtonDown [initDrag]"
wait
 
[initDrag]
    gosub [checkIndex]      'find out which card on table was clicked
    if clickCard=0 then wait
    nCard=card(clickCard)   'find value of card from our card array
    isBlocked=GetCardBlocked(nCard)    'see if card is blocked
    if isBlocked<>0 then
        'if card is blocked, inform user, then do nothing
        #1.g "place 10 420;\BLOCKED Card Index is ";nCard;space$(100)
        wait
    end if
    cardIndex=InitDrag(hBox,MouseX,MouseY)
    #1.g "place 10 420;\Drag Card Index is ";nCard;space$(100)
    #1.g "when rightButtonMove [doDrag]"
    wait
 
[doDrag]
    call DoDrag hBox, MouseX, MouseY
    #1.g "when rightButtonUp [endDrag]"
    wait
 
[endDrag]
    #1.g "when rightButtonUp"
    cardIndex=EndDrag(hBox,MouseX,MouseY)
    #1.g "place 10 420;\Destination Card Index is ";cardIndex;space$(100)
    wait
 
[checkIndex]
    clickCard=0''reset values
    mx=MouseX   : my=MouseY 'mouse x and y location
    'each row is incremented by offset of 20
    select case
    case my<=22                    'first row
        if mx<=90 then clickCard=1
        if (mx>=110) and (mx<=190) then clickCard=2
        if (mx>=210) and (mx<=290) then clickCard=3
        if (mx>=310) and (mx<=390) then clickCard=4
        if (mx>=410) and (mx<=490) then clickCard=5
        if (mx>=510) and (mx<=590) then clickCard=6
    case (my>=22) and (my<42)     'second row
        if mx<=90 then clickCard=7
        if (mx>=110) and (mx<=190) then clickCard=8
        if (mx>=210) and (mx<=290) then clickCard=9
        if (mx>=310) and (mx<=390) then clickCard=10
        if (mx>=410) and (mx<=490) then clickCard=11
        if (mx>=510) and (mx<=590) then clickCard=12
    case (my>=42) and (my<62)     'third row
        if mx<=90 then clickCard=13
        if (mx>=110) and (mx<=190) then clickCard=14
        if (mx>=210) and (mx<=290) then clickCard=15
        if (mx>=310) and (mx<=390) then clickCard=16
        if (mx>=410) and (mx<=490) then clickCard=17
        if (mx>=510) and (mx<=590) then clickCard=18
    case (my>=62) and (my<162)     'fourth row, full card height
        if mx<=90 then clickCard=19
        if (mx>=110) and (mx<=190) then clickCard=20
        if (mx>=210) and (mx<=290) then clickCard=21
        if (mx>=310) and (mx<=390) then clickCard=22
        if (mx>=410) and (mx<=490) then clickCard=23
        if (mx>=510) and (mx<=590) then clickCard=24
    case else
        clickCard=0
    end select
    return
 
[fillCardArray]
    'fill card array
    'cards 1 to 52 are in the first deck
    'cards 53 to 104 are in the second deck
    'use cards Jack through King in each suit, first deck
    card(1)=11  'jack of clubs
    card(2)=12  'queen
    card(3)=13  'king
    card(4)=24  'jack of diamonds
    card(5)=25  'queen
    card(6)=26  'king
    card(7)=37  'jack of hearts
    card(8)=38  'queen
    card(9)=39  'king
    card(10)=50  'jack of spades
    card(11)=51  'queen
    card(12)=52  'king
 
    'now use second deck, to fill second half of array
    for i = 1 to 12
        card(i+12)=card(i)+52
    next
    RETURN
 
 
[shuffleCards]
    playwave "shuffle.wav",async
    'now shuffle cards
    for i = 1 to 24
        newIndex=int(rnd(0)*24)+1
        tempCard=card(i)  'temp var to allow switching values
        card(i)=card(newIndex)  'this index now contains value from random index
        card(newIndex)=tempCard 'random index now contains value from other index
        'now card(i) has switched values with a random card in the array
    next
    playwave "shuffle.wav",sync
    RETURN
 
[quit] close #qc:close #1:end
 
 
''''''''''''''''''''
'subs and functions:
Sub Pause ms
    'pause ms number of milliseconds
    calldll #kernel32,"Sleep",_
    ms as long, re as void
    End Sub
 
Sub SetOffSet offset
    calldll #qc, "SetOffSet",offset as long,_
        re as void
    end sub
 
Sub AdjustCardBlocked nC, bValue
    calldll #qc, "AdjustCardBlocked",_
        nC as long, bValue as long, re as void
    end sub
 
Function GetCardBlocked(nC)
    calldll #qc, "GetCardBlocked",nC as long,_
        GetCardBlocked as long
    end function
 
Function InitDrag(hndle, x, y)
    calldll #qc, "InitDrag",_
        hndle as ulong, x as long, y as long,_
        InitDrag as long
    end function
 
Sub DoDrag hndle,x,y
    calldll #qc, "DoDrag",hndle as ulong,_
    x as long, y as long, r as void
    end sub
 
Function EndDrag(hndle,x,y)
    calldll #qc, "EndDrag",hndle as ulong,_
    x as long, y as long, EndDrag as long
    end function
 
Sub InitializeDeck hndle
    calldll #qc, "InitializeDeck",_
    hndle as ulong,r as long
    End Sub
 
Sub DealCard hndle,nC,x,y
    'places card on window whose handle is hndle at x,y
    'nC is number of card - 1-52 in first deck and
    '53-104 in second deck, if used
    calldll #qc, "DealCard",hndle as ulong,nC as long,_
    x as long,y as long,r as void
    End Sub
 
Sub SetDefaultValues
    'reset all card properties back to their default values.
    calldll #qc, "SetDefaultValues",r as void
    End Sub

QCard DLL Lesson 10 | More on Card Dragging | Blocked Cards | Blocking Some Cards | Preventing the Drag of Blocked Cards | Offset Value | DEMO
Lesson 9 Lesson 11