Xcard - Card game framework --------------------------- INTRODUCTION Xcard is a framework for Xt card games. It revolves around a special widget called a 'Stack', which holds a stack of cards. Cards cannot be drawn on their own: anywhere a card needs to be displayed, a stack widget must be created to contain it. Stack widgets provide only a handful of methods for adding and removing cards. Each card is identified by a short integer, which is composed of bits to indicate suit and face value, and a bit to indicate whether the card is face up or face down. Stacks can be configured to display their cards in a spread fashion (with gravities of 'South', 'East', 'West', 'North') or only to show the top card ('Center' gravity). Stack widgets automatically provide graphical drag and drop. Callback procedures on the stacks are invoked to determine if the stack (or a substack) can be picked up ('split') with the cursor, or if a stack should accept a 'drop' of new cards on it. A collection of card artwork pixmaps is supplied. RESOURCES Stack widgets have various resources, other than those of Core: foreground - colour used for drawing bitmaps dropCallback - query if a particular drop is allowed splitCallback - query if a stack split or pick-up is allowed dropNotify - called when a stack drop actually occurs hitNotify - called on a hit() action (normally a single click) compact - indicates the widget should keep a minimal size highlight - the border highlight colour highlightWidth highlightHeight - size of the highlight rectangle reserved around the stack gravity - the spread gravity: indicates orientation of 'bottom' card. vStepMin vStepMax hStepMin hStepMax - the card overlap dimensions (only with non-Center gravity) placeholderPixmap - image drawn when the stack is empty (or mising pixmap) backPixmap - image drawn for a card when it is 'face down' aceDiamondsPixmap - 'face up' card artwork for the Ace of Diamonds twoDiamondsPixmap - 'face up' card artwork for the Two of Diamonds ...etc - ...etc NOTE: All card pixmaps should be the same dimensions. (They need not be, but it will look messy if they're not.) Some built-in callback procedures for dropCallback are supplied: StackAlwaysDrop - always allow cards to drop on this stack StackNeverDrop - always deny a drop Some built-in callback procedures for splitCallback are supplied: StackAlwaysSplit - allow any split and drag of cards on this stack StackNeverSplit - always deny a stack split/pickup PROGRAMMING API Xcard does not actually implement any game logic. Instead, it just provides a widget class for a normal X application to use for displaying a stack of cards, and maintaining a stack's state. I feel this way gives the programmer much more freedom for table and control layouts. It does mean that the game logic must be written in an event/callback fashion though. The Stack widget class is a subtype of Composite, but you should NOT manually insert anything into a Stacks (with XtCreateWidget for example). Use StackPush(), StackPop() and StackMove() instead. These functions create and release managed CardObject children that you should never need to know about. STACK UTILITIES The public functions used to manipulate and use Stack widgets are: Widget StackCreateDragAndDropPopup(Widget toplevel, String name) Creates an unrealized popup widget to be used when performing drag-and-drop. This must be called once by the application at an early stage, and passed the toplevel shell widget. During drag-and drop, the toplevel widget and its descendents are searched for stacks that will accept a drop. 'name' is the name to be given to the popup shell widget. (You don't need to call this if you don't want drag-and-drop.) Also, you can discard the return result if you wish, since the popup is automatically popped-up when needed. Cardinal StackDepth(Widget stack) Returns the number of cards on the stack. A return value of zero means the stack is empty. CardID StackPeek(Widget stack, Cardinal depth) Returns the card value at the given depth, where the top card's depth is zero. If depth exceeds the number of cards in the stack, then CARD_NONE is returned. CardID StackTop(Widget stack) Equivalent to StackPeek(stack, 0). void StackPush(Widget stack, CardID card) Places the card on top of the stack. Pushing CARD_NONE has no effect. (Cards of the same value can exist more than once in a stack.) Remember to bitwise-or CARD_DOWN with the card ID if you want the card to be drawn face-down. CardID StackPop(Widget stack) Removes the top card from the stack and returns it. If the stack was empty, returns CARD_NONE. void StackClear(Widget stack) Removes all the cards from the given stack. Useful for resetting stacks. void StackMove(Widget dest, Widget source, Cardinal count) Moves the top 'count' cards from 'source' over and onto the top of 'dest' without reordering them. This is the same operation performed by a successful drag-and-drop. (It is an error if 'count' is too large for 'source'.) CARD UTILITIES Cards themselves are identified by short integers. Card values have their own collection of utility macros and constants: typedef short CardID; CardID CARD_SUIT(card) Returns the suit indicator for the card, usually one of SUIT_DIAMONDS - Diamonds suit SUIT_HEARTS - Hearts suit SUIT_CLUBS - Clubs suit SUIT_SPADES - Spades suit SUIT_SPECIAL - Special cards such as the Joker CardID CARD_FACE(card) If the card is a normal suit card (with the SUIT_NORMAL bit) then this macro returns the face value of the card. This is a number between 1 and 13 inclusive. Helpful constants are: FACE_ACE - 1 FACE_TEN - 10 FACE_JACK - 11 FACE_QUEEN - 12 FACE_KING - 13 CardID CARD_COLOUR(card) Return the colour of the card. This is one of COLOUR_RED - red COLOUR_BLACK - black Boolean CARD_IS_DOWN(card) Returns True if the card is face down. The bit in the card value that indicates if it is up or down is CARD_DOWN. CARD_NONE - reserved to indicate a missing card CARD_BLACK_JOKER - a black joker CARD_RED_JOKER - a red joker Some utility functions for shuffling decks (arrays) of cards are also provided: void CardFillStandardDeck(deck) CardID *deck; This procedure fills the 'deck' array with one of each of the 52 normal playing cards. There must be sufficient space in the array for those cards. The macro CARD_STANDARD_DECK_SIZE is set at 52. (Note that jokers are not added by this procedure.) void CardShuffle(deck, deck_length) CardID *deck; Cardinal deck_length; Shuffles the deck using srand()/rand(). Note that srand is initially seeded by the Unix clock, so the program should not be called more than once per second. String CardSuitName(card) CardID card; Returns a read-only string representation of the card's suit for debugging purposes. String CardFaceName(card) CardID card; Returns a read-only string representation of a card's face value for debugging purposes. CALLBACKS 'Split' callback procedures have the following signature Boolean split_proc(source, closure, depth) Widget source; XtPointer closure; Cardinal depth; The procedure should return True or False to permit/deny the stack from being split and picked up.. 'source' is the stack widget being split by the user. 'closure' is always NULL. 'depth' is the number of cards from the top of source that the user is attempting to pick up. Note that if a split callback returns False, the stack is able to be 'hit'. 'Drop' callback procedures have the following signature Boolean drop_proc(target, closure, cards, num_cards, source) Widget target; XtPointer closure; CardID *cards; Cardinal num_cards; Widget source; The procedure should return True or False to permit/deny the stack from accepting the impending drop. 'target' is the widget on which the drop is to occur. 'cards' is a read-only array of CardIDs, with the bottom card value at index 0. 'num_cards' indicates the length of the array. 'source' is the widget from which the cards were picked up from. 'Drop' notify procedures have the following signature void drop_notify_proc(widget, closure, data) Widget widget; XtPointer closure; XtPointer data; 'widget' is the stack that has been hit 'closure' is always NULL. 'data' is a pointer to a StackDropEvent structure. The fields of 'data' are source - the stack that the cards were taken from target - the stack where the cards are now count - the number of cards transferred 'Hit' notify procedures have the following signature void hit_notify_proc(widget, closure, data) Widget widget; XtPointer closure; XtPointer data; 'widget' is the stack that has been hit 'closure' is always NULL. 'data' are always NULL. Note that if a stack is able to be split, the default translations will not allow it to be 'hit' (since the mouse button down will initiates a drag). AUTHOR David Leonard, 2003. $Id: NOTES,v 1.6 2003/04/23 00:54:57 d Exp $