/**********************************************************
* PROGRAM: Spades                                         *
* AUTHOR: Gregory M. Stelmack                             *
* COMPILER: SAS/C 5.10                                    *
*      Copyright (C) 1988 Lattice, Inc.                   *
*      Copyright (C) 1990 SAS Institute, Inc.             *
* VESRION DATES:                                          *
*      Version 1.0  -- February 5, 1990                   *
*      Version 1.1  -- April 28, 1990                     *
*           Images used for cards -- file "Spades.images" *
*           must be in current directory to run.          *
*           Title graphics added. New routine for         *
*           choosing dealer.                              *
*      Version 1.11 -- August 23, 1990                    *
*           Fixed memory freeing bug. Added some prompts. *
*      Version 1.12 -- October 3, 1990                    *
*           Removed LIBRARY_VERSION from OpenLibrary()    *
*           calls, replacing it with zero. An attempt to  *
*           let it run under pre-1.3.                     *
*      Version 1.20 -- April 4, 1991                      *
*           Error messages now pause. Revised strategy.   *
*           Window can be sized and dragged, and screen   *
*           moved to back to allow other things to be     *
*           done.                                         *
*                                                         *
* Tab stops set to 8,16,24,32,40,48,... for this listing. *
**********************************************************/

/* Include files */

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <exec/libraries.h>
#include <graphics/gfxmacros.h>
#include <proto/all.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include "Spades.proto"

/* Structures needed for libraries */

struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct Library       *DiskfontBase;

/* Intuition Structures */

struct Screen       *CustScr;
struct Window       *Wdw;
struct Viewport     *WVP;
struct IntuiMessage *Message;

/************** Program Constants **************/
#define RP       Wdw->RPort      /* Raster Port for Graphics Routines */
#define PENS        8            /* Number of Pens                    */
#define DEPTH       3            /* Number of BitPlanes               */
#define MLEFT       1            /* Left Mouse Button Pressed         */
#define MRIGHT      2            /* Right Mouse Button Pressed        */

#define DIAMONDS    0            /* Suit Definitions */
#define CLUBS       1
#define HEARTS      2
#define SPADES      3

#define WHITE  0xFFF             /* Palette Data */
#define RED    0xF00
#define GREEN  0x0F0
#define BLUE   0x00F
#define CYAN   0x0FF
#define PURPLE 0xF0F
#define YELLOW 0xFF0
#define BLACK  0x000

#define CARDMEMSIZE  52*126*2*3  /* Memory needed for card data */

/************** Color Map Data *****************/
static USHORT colormap[PENS] =
{
	BLUE,      /* Pen  0 */
	BLACK,     /* Pen  1 */
	RED,       /* Pen  2 */
	GREEN,     /* Pen  3 */
	WHITE,     /* Pen  4 */
	YELLOW,    /* Pen  5 */
	PURPLE,    /* Pen  6 */
	CYAN       /* Pen  7 */
};

#define BLUP 0
#define BLKP 1
#define REDP 2
#define GRNP 3
#define WHTP 4
#define YELP 5
#define PURP 6
#define CYNP 7

/************** Text Structure *****************/
struct TextAttr StdFont =
{
	"topaz.font",
	TOPAZ_EIGHTY,
	FS_NORMAL,
	FPF_ROMFONT,
};

/*********** NewScreen Structure **********/
struct NewScreen NewCustScr =
{
	0,0,            /* Left Edge, Top Edge       */
	320,200,DEPTH,  /* Width, Height, Depth      */
	WHTP,BLUP,      /* Detail Pen, Block Pen     */
	NULL,           /* View Mode                 */
	CUSTOMSCREEN,   /* Screen Type               */
	&StdFont,       /* Pointer to Font           */
	NULL,           /* Pointer to Title Text     */
	NULL,           /* Pointer to Screen Gadgets */
	NULL,           /* Pointer to CustomBitMap   */
};

/**************** Gadgets ******************/

struct IntuiText IText1 = {
        YELP,BLKP,JAM2,	/* front and back text pens, drawmode and fill byte */
        -1,0,	/* XY origin relative to container TopLeft */
        NULL,	/* font pointer or NULL for default */
        "HIDE",	/* pointer to text */
        NULL	/* next IntuiText structure */
};

struct Gadget HideGadget = {
	NULL,	/* next gadget */
	265,1,	/* origin XY of hit box relative to window TopLeft */
	32,8,	/* hit box width and height */
	NULL,	/* gadget flags */
	RELVERIFY+TOPBORDER,	/* activation flags */
	BOOLGADGET+GZZGADGET,	/* gadget type flags */
	NULL,   /* gadget border or image to be rendered */
	NULL,	/* alternate imagery for selection */
	&IText1,	/* first IntuiText structure */
	NULL,	/* gadget mutual-exclude long word */
	NULL,	/* SpecialInfo structure */
	NULL,	/* user-definable data */
	NULL	/* pointer to user-definable data */
};

/*********** NewWindow Structure **********/
struct NewWindow NewWdw =
{
	0,0,            /* Left Edge, Top Edge          */
	320,200,        /* Width, Height                */
	BLKP,WHTP,      /* Block Pen, Detail Pen        */
	MOUSEBUTTONS | CLOSEWINDOW | GADGETUP,   /* IDCMP Flags */
	SMART_REFRESH | ACTIVATE | GIMMEZEROZERO | RMBTRAP | WINDOWCLOSE,
	&HideGadget,    /* Pointer to First Gadget      */
	NULL,           /* Pointer to Check Mark image  */
	"Spades 1.20, by Greg Stelmack",       /* Title */
	NULL,           /* Pointer to Screen structure  */
	NULL,           /* Pointer to custom Bit Map    */
	320,100,        /* Minimum Width, Height        */
	0,0,            /* Maximum Width, Height        */
	CUSTOMSCREEN    /* Type of Screen it resides on */
};

/************************* Image Data *************************/
struct Image CardImage =
{
  0, 0,                        /* LeftEdge, TopEdge     */
  42, 42, 3,                   /* Width, Height, Depth  */
  NULL,                        /* Image Data            */
  7, 0,                        /* PlanePick, PlaneOnOff */
  NULL                         /* *NextImage            */
};

#include "Spades.h"

/*************************** Arrays ***************************/

/***************************************
* Deck: status of cards.               *
*      0 = Undealt or played.          *
*  1 thru 4 = Player who holds card.   *
***************************************/
int Deck[52] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

/***************************************
* Hand: cards in each player's hand.   *
*      0 = Played.                     *
*  1 thru 52 = Card number.            *
***************************************/
int Hand[4][13] = { {0,0,0,0,0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0,0,0,0,0},
                    {0,0,0,0,0,0,0,0,0,0,0,0,0} };

/********************************************
* Bid: number of tricks bid by each player. *
********************************************/          
int Bid[4] = {0,0,0,0};

/********************************************
* Mode: aggressiveness of each player.      *
*   The number in this array is added to    *
*   the strength of the hand to determine   *
*   the number of tricks to bid. Higher     *
*   number equals more tricks.              *
********************************************/
int Mode[4] = {0,0,0,0};
  
/********************************************
* HighCardLeft: the highest unplayed card   *
*   in each suit.                           *
********************************************/
int HighCardLeft[4] = {0,0,0,0};

/********************************************
* Card: the card played in a trick by each  *
*   player.                                 *
********************************************/
int Card[4] = {0,0,0,0};
  
/********************************************
* Value: the point value of each card held  *
*   in a hand. Used by computer to determine*
*   which card to play.                     *
********************************************/
int Value[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0};

/********************************************
* SuitNumber: the number of cards in each   *
*   suit held by a player.                  *
********************************************/
int SuitNumber[4] = {0,0,0,0};
  
/********************************************
* CardX & CardY: The X and Y positions for  *
*   the played card for each player.        *
* MsgX & MsgY: The X and Y positions for    *
*   single character messages for each      *
*   player.                                 *
********************************************/
int CardX[4] = {100,1,100,209};
int CardY[4] = {99,60,1,60};
  
int MsgX[4] = {116,45,116,195};
int MsgY[4] = {96,84,50,84};
  
/********************************************
* OutOfSuit: Whether or not a player is out *
*   of a suit.                              *
********************************************/
BOOL OutOfSuit[4][4] = { {0,0,0,0},
                         {0,0,0,0},
                         {0,0,0,0},
                         {0,0,0,0} };
                          
/******************** Other Global Variables ******************/
char *String = "      "; /* Temporary String Storage */

int PlayerScore=0, CompScore=0, PlayerTricks=0, CompTricks=0;
int HandLead=0, Button=0, TrickLead=0, PlayerBid=0, CompBid=0;
int ShortSuit=0, LongSuit=0, HighCard=0, Winner=0;
BOOL SpadePlayed=FALSE, AllDone=FALSE, ScreenOpen=FALSE;
char *CardData;

SHORT Mx=0, My=0;        /* Mouse Coordinates */

/********************* Program Begins Here ********************/

/**********************************************************
* Function: main                                          *
* Purpose: Open everything, play the game, close          *
*          everything.                                    *
**********************************************************/
main()
{
        int fh;
        unsigned int count=0;
        
	/* Open the Intuition and Graphics libraries. */
  
	IntuitionBase = (struct IntuitionBase *)
	     OpenLibrary("intuition.library",0);
	if (IntuitionBase == NULL) 
                PError("Can't open Intuition Library");
	
	GfxBase = (struct GfxBase *)
	     OpenLibrary("graphics.library",0);
	if (GfxBase == NULL)
                PError("Can't open Graphics Library");

        /* Load Graphic Images */
  
        CardData = (char *)AllocMem(CARDMEMSIZE,MEMF_CHIP);
        if (!CardData)
                PError("Could not allocate image memory!");
        fh = open("Spades.images",O_RDONLY,0);
        if (fh==-1)
                PError("Can't open images file!");
        count = read(fh,CardData,CARDMEMSIZE);
        if (count==-1)
                PError("Error reading images file!");

        /* Open the screen and window */
	
	if ((NewWdw.Screen = CustScr =
	  (struct Screen *)OpenScreen(&NewCustScr)) == NULL)
                PError("Can't open new screen");
  	
        ScreenOpen = TRUE;
        
	if (( Wdw = (struct Window *)OpenWindow(&NewWdw)) == NULL)
                PError("Can't open new window");
  	
	/* Find the viewport and load color map */
	
	WVP = (struct ViewPort *)ViewPortAddress(Wdw);
	LoadRGB4(WVP,&colormap[0],PENS);
	
        /* Seed random number generator with TIMER */
  
        srand(time(NULL));
  
    
        /* Start Game */
	
        Spades();
		
        /* Close Everything */
  
        WrapUp();
}

/**********************************************************
* Function: PError                                        *
* Parameters: s -- pointer to string to print             *
* Return Values: None                                     *
* Purpose: Handle a fatal error                           *
**********************************************************/
void PError(s)
char *s;
{
        char c=' ';
        
        printf("%s\n",s);
        if (!ScreenOpen)
        {
                printf("Please press RETURN...");
                c=getchar();
        }
        WrapUp();
}

/**********************************************************
* Function: WrapUp                                        *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: close everything and exit                      *
**********************************************************/
void WrapUp()
{
        if (CardData)      FreeMem((char *)CardData,CARDMEMSIZE);
	if (Wdw)           CloseWindow(Wdw);
	if (CustScr)       CloseScreen(CustScr);
	if (GfxBase)       CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
        exit(0);
}

/**********************************************************
* Function: Spades                                        *
* Parameters: None                                        *
* Return Values: None                                     *
* Purpose: Play a game of spades. Loop until someone      *
*          scores 500.                                    *
**********************************************************/
void Spades()
{
        Title();

        AllDone=FALSE;
  
        /* Loop until player no longer wants to play. */
  
        while (!AllDone)
        {
                PlayerScore=CompScore=0;
                HandLead=FindDealer();
    
                /* Loop until someone reaches 500 and there is no tie. */
    
                while (((PlayerScore<500)&&(CompScore<500))||(PlayerScore==CompScore))
                {
                        SetUpScreen();
                        InitVars();
                        PrintScore();
                        DealCards();
                        GetBids();
                        PrintBids();
                        PlayHand();
                }
    
                FinishRoutine();
        }
}

/**********************************************************
* Function: Title                                         *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: draw title graphics.                           *
**********************************************************/
void Title()
{
        int i=0;
  
        SetRast(RP,BLUP);              /* Clear screen */
        SetAPen(RP,YELP);
        SetBPen(RP,BLUP);
  
        /* Draw card backs */
  
        for (i=0; i<6 ; i++)
        {
                DrawImage(RP,&Image25,(i*50)+15,65);
        }
  
        /* Flip S */
  
        Delay(5);
        DrawImage(RP,&Image24,15,65);
        Delay(5);
        DrawImage(RP,&Image23,15,65);
        Delay(5);
        DrawImage(RP,&Image22,15,65);
        Delay(5);
        DrawImage(RP,&Image21,15,65);
        Delay(5);
        DrawImage(RP,&Image17,15,65);
        Delay(5);
        DrawImage(RP,&Image18,15,65);
        Delay(5);
        DrawImage(RP,&Image19,15,65);
        Delay(5);
        DrawImage(RP,&Image20,15,65);
  
        /* Flip P */
  
        Delay(5);
        DrawImage(RP,&Image24,65,65);
        Delay(5);
        DrawImage(RP,&Image23,65,65);
        Delay(5);
        DrawImage(RP,&Image22,65,65);
        Delay(5);
        DrawImage(RP,&Image21,65,65);
        Delay(5);
        DrawImage(RP,&Image13,65,65);
        Delay(5);
        DrawImage(RP,&Image14,65,65);
        Delay(5);
        DrawImage(RP,&Image15,65,65);
        Delay(5);
        DrawImage(RP,&Image16,65,65);
  
        /* Flip A */
  
        Delay(5);
        DrawImage(RP,&Image24,115,65);
        Delay(5);
        DrawImage(RP,&Image23,115,65);
        Delay(5);
        DrawImage(RP,&Image22,115,65);
        Delay(5);
        DrawImage(RP,&Image21,115,65);
        Delay(5);
        DrawImage(RP,&Image9,115,65);
        Delay(5);
        DrawImage(RP,&Image10,115,65);
        Delay(5);
        DrawImage(RP,&Image11,115,65);
        Delay(5);
        DrawImage(RP,&Image12,115,65);
  
        /* Flip D */
  
        Delay(5);
        DrawImage(RP,&Image24,165,65);
        Delay(5);
        DrawImage(RP,&Image23,165,65);
        Delay(5);
        DrawImage(RP,&Image22,165,65);
        Delay(5);
        DrawImage(RP,&Image21,165,65);
        Delay(5);
        DrawImage(RP,&Image5,165,65);
        Delay(5);
        DrawImage(RP,&Image6,165,65);
        Delay(5);
        DrawImage(RP,&Image7,165,65);
        Delay(5);
        DrawImage(RP,&Image8,165,65);
  
        /* Flip E */
  
        Delay(5);
        DrawImage(RP,&Image24,215,65);
        Delay(5);
        DrawImage(RP,&Image23,215,65);
        Delay(5);
        DrawImage(RP,&Image22,215,65);
        Delay(5);
        DrawImage(RP,&Image21,215,65);
        Delay(5);
        DrawImage(RP,&Image1,215,65);
        Delay(5);
        DrawImage(RP,&Image2,215,65);
        Delay(5);
        DrawImage(RP,&Image3,215,65);
        Delay(5);
        DrawImage(RP,&Image4,215,65);
  
        /* Flip S */
  
        Delay(5);
        DrawImage(RP,&Image24,265,65);
        Delay(5);
        DrawImage(RP,&Image23,265,65);
        Delay(5);
        DrawImage(RP,&Image22,265,65);
        Delay(5);
        DrawImage(RP,&Image21,265,65);
        Delay(5);
        DrawImage(RP,&Image17,265,65);
        Delay(5);
        DrawImage(RP,&Image18,265,65);
        Delay(5);
        DrawImage(RP,&Image19,265,65);
        Delay(5);
        DrawImage(RP,&Image20,265,65);
  
        /* Prompt for pause */
  
        Move(RP,50,180);
        Text(RP,"Click any mouse button...",25);
  
        ReadMouse();                   /* Pause for click */
}

/**********************************************************
* Function: FindDealer                                    *
* Parameters: none                                        *
* Return Values: the player determined to initially deal. *
* Purpose: find out who deals first in a game.            *
**********************************************************/
int FindDealer()
{
        int player=0, card=0, i;
        BOOL done=FALSE;

        SetRast(RP,BLUP);              /* Clear Screen */  
        SetAPen(RP,YELP);
        SetBPen(RP,BLUP);
  
        for (i=0 ; i<52 ; i++) Deck[i]=0;    /* Set deck to undealt */
  
        Move(RP,70,70);                /* Warn player of what's happening */
        Text(RP,"Ace of Spades",13);
        Move(RP,98,78);
        Text(RP,"deals",5);
  
        while(!done)                   /* Loop until dealer found */
        {
                while(Deck[card=rand()%52]) ;      /* Find undealt card */
                Deck[card]=1;                      /* Mark card as dealt */
                DrawCard(CardX[player],CardY[player],card);
                                                   /* Draw card */
                Delay(10);                         /* Pause */
                if (card==51)                      /* Ace of Spades */
                {
                        done=TRUE;
                        Move(RP,MsgX[player],MsgY[player]);
                        Text(RP,"*",1);
                }
                player=(++player)%4;   /* Increment player */
        }
  
        Move(RP,200,150);              /* Wait for player */
        Text(RP,"Click mouse",11);
        ReadMouse();
  
        SetRast(RP,BLUP);
        return((++player)%4);          /* Must return player 2 to left of */
                                       /* dealer. Program will later */
                                       /* decrement player to find lead */
                                       /* who should be to left of dealer */
}
  
/**********************************************************
* Function: SetUpScreen                                   *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: gets the screen ready for a new hand.          *
**********************************************************/
void SetUpScreen()
{
        /* Clear the Screen */
  
        SetRast(RP,BLUP);
        SetAPen(RP,YELP);
        SetBPen(RP,BLKP);
        
        /* Draw the Score Box */
  
        Move(RP,215,6);
        Text(RP," YOU   CMP ",11);
        Move(RP,215,14);
        Text(RP,"SCORE SCORE",11);
        Move(RP,215,22);
        Text(RP,"           ",11);
        Move(RP,215,30);
        Text(RP," BID   BID ",11);
        Move(RP,215,38);
        Text(RP,"           ",11);
        Move(RP,215,46);
        Text(RP,"TRICK TRICK",11);
        Move(RP,215,54);
        Text(RP,"           ",11); 
        SetAPen(RP,WHTP);
        Move(RP,215,7);
        Draw(RP,302,7);
        Move(RP,258,0);
        Draw(RP,258,55);
}

/**********************************************************
* Function: InitVars                                      *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Initialize variables and arrays for a new hand.*
**********************************************************/
void InitVars()
{
        int i;
  
        /* Set Leader */
  
        HandLead=(--HandLead+4)%4;
        TrickLead=HandLead;
  
        /* Reset HighCardLeft */
  
        HighCardLeft[0]=12;
        HighCardLeft[1]=12;
        HighCardLeft[2]=12;
        HighCardLeft[3]=12;
  
        /* Reset OutOfSuit */
  
        for (i=0 ; i<4 ; i++)
        {
                OutOfSuit[i][DIAMONDS]=FALSE;
                OutOfSuit[i][CLUBS]   =FALSE;
                OutOfSuit[i][HEARTS]  =FALSE;
                OutOfSuit[i][SPADES]  =FALSE;
        }
  
        /* Determine Modes */
  
        for (i=0 ; i<4 ; i++)
        {
                Mode[i]=0;
                if (i==HandLead) Mode[i]+=2;   /* Leader should bid higher */
                if (i==0||i==2)                /* Human players -- check score */
                {
                        if ((PlayerScore>400)&&(CompScore<350)) Mode[i]-=1;
                        if (PlayerScore<(CompScore-100)) Mode[i]+=1;
                        if (PlayerScore<(CompScore-200)) Mode[i]+=1;
                        if (PlayerScore>(CompScore+100)) Mode[i]-=1;
                }
                if (i==1||i==3)                /* Computer players -- check score */
                {
                        if ((CompScore>400)&&(PlayerScore<350)) Mode[i]-=1;
                        if (CompScore<(PlayerScore-100)) Mode[i]+=1;
                        if (CompScore<(PlayerScore-200)) Mode[i]+=1;
                        if (CompScore>(PlayerScore+100)) Mode[i]-=1;
                }
        }
}

/**********************************************************
* Function: DealCards                                     *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Shuffle & deal the deck to the players.        *
**********************************************************/
void DealCards()
{
        int i,j,player,cardnum[4];
  
        for (i=0 ; i<4 ; i++) cardnum[i]=0; /* Reset cards for each player */
        for (i=0 ; i<52 ; i++) Deck[i]=0;   /* Set whole deck to undealt */
  
        /* Shuffle and Deal Deck */
  
        for (i=0 ; i<52 ; i++)
        {
                while(Deck[j=rand()%52]) ;       /* Find undealt card */
                Deck[j]=((i/13)+1);              /* Store owning player */
        }
  
        /* Transfer cards to player hands */
  
        for (i=0 ; i<52 ; i++)
        {
                player=Deck[i]-1;                     /* Get owning player */
                Hand[player][cardnum[player]++]=i+1;  /* Store card, increment counter */
        }
}

/**********************************************************
* Function: ShowHand                                      *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: To display the player's hand.                  *
**********************************************************/
void ShowHand()
{
        int i;
  
        /* Erase old hand */
  
        SetAPen(RP,BLUP);
        SetOPen(RP,BLUP);
        RectFill(RP,21,145,183,186);

        /* Draw each card, overlaying part of the previous one */

        for (i=0 ; i<13 ; i++)
        {
                if (Hand[0][i])  /* Only draw if card hasn't been played */
                        DrawCard(((i*10)+21),145,((Hand[0][i])-1));
        }
}

/**********************************************************
* Function: GetBids                                       *
* Parameters: none                                        *
* Return values: none                                     *
* Purpose: Get each player's bid.                         *
**********************************************************/
void GetBids()
{
        int i;
  
        for (i=0 ; i<4 ; i++) Bid[i]=0;   /* Reset bids for each player */
  
        /* Loop through each player */
  
        i=HandLead;
        do
        {
                if (i)
                        Bid[i]=CalcBid(i);        /* Computer Player */
                else 
                        Bid[i]=GetPlayerBid();    /* Human Player */
                i=(++i)%4;
        }  while (i!=HandLead);
  
        /* Calculate team contracts */
  
        PlayerBid=Bid[0]+Bid[2];
        CompBid=Bid[1]+Bid[3];
  
        /* Pause for click */

        SetAPen(RP,YELP);
        Move(RP,200,150);
        Text(RP,"Click mouse",11);
        ReadMouse();
        Move(RP,200,150);
        Text(RP,"           ",11);
        
        /* Erase Bids */
  
        SetBPen(RP,BLUP);
        for (i=0 ; i<4 ; i++)
        {
                Move(RP,MsgX[i],MsgY[i]);
                Text(RP," ",1);
        }
}

/**********************************************************
* Function: GetPlayerBid                                  *
* Parameters: none                                        *
* Return Values: bid -- number of tricks bid              *
* Purpose: Get the human player's bid. Could use gadgets, *
*          but this is easier to program.                 *
**********************************************************/
int GetPlayerBid()
{
        int bid=1,length;
        BOOL havebid=FALSE;

        ShowHand();

        /* Draw input box */
  
        SetAPen(RP,YELP);
        SetBPen(RP,BLKP);
        Move(RP,258,142);
        Text(RP,"BID",3);
        Move(RP,250,150);
        Text(RP,"  +  ",5);
        Move(RP,250,158);
        Text(RP,"   OK",5);
        Move(RP,250,166);
        Text(RP,"  -  ",5);
  
        /* Loop until OK is clicked */
  
        while(!havebid)
        {
    
                /* Draw Current Bid */
    
                SetAPen(RP,GRNP);
                SetBPen(RP,BLKP);
                Move(RP,250,158);
                Text(RP,"  ",2);
                itoa(bid,String);
                length=strlen(String);
                Move(RP,(258-(4*length)),158);
                Text(RP,String,length);
    
                /* Wait for Mouse input */
    
                ReadMouse();
                if (Button==MLEFT)    /* Left Button Pressed */
                {
                        if ((Mx>265)&&(Mx<274)&&(My>143)&&(My<152)) bid++;  /* plus sign  */
                        if ((Mx>273)&&(Mx<290)&&(My>151)&&(My<160)) havebid=TRUE; /* OK   */
                        if ((Mx>265)&&(Mx<274)&&(My>159)&&(My<168)) bid--;  /* minus sign */
                }
                if (Button==MRIGHT)   /* Right Button Pressed */
                {
                        bid=CalcBid(0);     /* Suggest a Bid */
                }
    
                /* Make sure bid is valid */
    
                if (bid<1)  bid=1;
                if (bid>12) bid=12;
        }
  
        /* Erase Input Box */
  
        SetAPen(RP,BLUP);
        SetOPen(RP,BLUP);
        RectFill(RP,250,135,291,168);
  
        /* Display the bid */
  
        SetAPen(RP,YELP);
        SetBPen(RP,BLUP);
        itoa(bid,String);
        Move(RP,MsgX[0],MsgY[0]);
        Text(RP,String,strlen(String));
  
        /* Send the bid back */
  
        return(bid);
}

/**********************************************************
* Function: CalcBid                                       *
* Parameters: player -- number of player to calculate for *
* Return Values: bid -- number of tricks                  *
* Purpose: To calculate the number of tricks bid by a     *
*          player.                                        *
**********************************************************/
int CalcBid(player)
int player;
{
        int i,j,numsuit,points,suit,bid;
        int k,numspades;
        
        points=0;

        /* Calculate spades */
  
        numspades=0;
    
        /* Count Spades  */
    
        for (j=39 ; j<52 ; j++)
                if (Deck[j]==player+1) numspades++;

        numsuit = numspades;
        
        /* Add points for Spades -- if enough to cover, count it */

        for (j=51 ; j>38 ; j--)
        {
                k = 12-(j%13);
                if ((Deck[j]==player+1)&&(numsuit>k))
                {
                        points+=4;
                        numspades=numsuit-k;    /* Used to make sure we don't
                                                   count tricks twice for
                                                   short-suitedness */
                }
        }

        /* Add up points for the non-spades suits */
  
        for (i=DIAMONDS ; i<SPADES ; i++)  /* Loop thru suits */
        {
                numsuit=0;
                suit=i*13;
    
                /* Count cards for suit */
    
                for (j=0 ; j<13 ; j++)
                        if (Deck[suit+j]==player+1) numsuit++;
                
                /* Short-Suitedness */

                if (numspades>2)
                {
                        if (numsuit==0)
                                points+=8;
                        else if (numsuit==1)
                                points+=4;
                        else if (numsuit==2)
                                points+=2;
                }
                else if (numspades==2)
                {
                        if (numsuit==0)
                                points+=5;
                        else if (numsuit==1)
                                points+=2;
                }
                else if (numspades==1)
                {
                        if (numsuit==0)
                                points+=3;
                }
                
                /* Add points for face cards */
    
                if (Deck[suit+12]==player+1)    /* Ace   */
                {
                        if (numsuit<6) points+=4;
                        else if (numsuit<8) points+=2;
                        else points+=1;
                }
                if (Deck[suit+11]==player+1)    /* King  */
                {
                        if ((numsuit<5)&&(numsuit>1)) points+=4;
                        else if ((numsuit<6)&&(numsuit>1)) points+=2;
                        else if ((numsuit<7)&&(numsuit>1)) points+=1;
                }
                if (Deck[suit+10]==player+1)    /* Queen */
                {
                        if (numsuit==3) points+=2;
                }
        }
  

        points+=Mode[player];        /* Adjust for aggressiveness */
        if (points<4) points=4;      /* Validate number of points */
        bid=points/4;                /* Find Bid */
  
        /* Make sure total team bid not greater than 13 */
  
        i=(player+2)%4;              /* Find partner */
        if ((bid+Bid[i])>13) bid=13-Bid[i];
  
        /* Display Bid */
  
        itoa(bid,String);
        SetAPen(RP,YELP);
        SetBPen(RP,BLUP);
        Move(RP,MsgX[player],MsgY[player]);
        Text(RP,String,strlen(String));
  
        /* Send bid back */
  
        return(bid);
}

/**********************************************************
* Function: PlayHand                                      *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Play out a hand until all 13 tricks are taken. *
**********************************************************/
void PlayHand()
{
        int i;
  
        /* Initialize */
  
        PlayerTricks=CompTricks=0;
        SpadePlayed=FALSE;
        PrintTricks();
  
        /* Loop through all 13 tricks */
  
        for (i=0 ; i<13 ; i++)
        {
                TrickLead=TakeTrick();                /* Play a trick */
                if ((TrickLead==0)||(TrickLead==2))   /* Who won? */
                        PlayerTricks++;
                else
                        CompTricks++;
                PrintTricks();         /* Display new trick total */
    
                /* Indicate who won with an '*' */
    
                SetAPen(RP,YELP);
                SetBPen(RP,BLUP);
                Move(RP,MsgX[TrickLead],MsgY[TrickLead]);
                Text(RP,"*",1);
    
                /* Pause for click */

                SetAPen(RP,YELP);
                Move(RP,200,150);
                Text(RP,"Click mouse",11);
                ReadMouse();
                Move(RP,200,150);
                Text(RP,"           ",11);
    
                /* Erase winner indicator */
    
                Move(RP,MsgX[TrickLead],MsgY[TrickLead]);
                Text(RP," ",1);
        }
  
        /* Calculate new score */
  
        if (PlayerTricks<PlayerBid)
                PlayerScore-=(10*PlayerBid);
        if (CompTricks<CompBid)
                CompScore-=(10*CompBid);
        if (PlayerTricks>=PlayerBid)
                PlayerScore+=((10*PlayerBid)+(PlayerTricks-PlayerBid));
        if (CompTricks>=CompBid)
                CompScore+=((10*CompBid)+(CompTricks-CompBid));
    
        /* Pause for click */

        SetAPen(RP,YELP);
        Move(RP,200,150);
        Text(RP,"Click mouse",11);
        ReadMouse();
        Move(RP,200,150);
        Text(RP,"           ",11);
}

/**********************************************************
* Function: TakeTrick                                     *
* Parameters: none                                        *
* Return Values: winner of trick                          *
* Purpose: Each player plays a card, then determine trick *
*          winner.                                        *
**********************************************************/
int TakeTrick()
{
        int i,j,leadsuit,suit,value;
  
        /* Clear previously played cards */
  
        SetAPen(RP,BLUP);
        SetOPen(RP,BLUP);
        for (i=0 ; i<4 ; i++)
                RectFill(RP,CardX[i],CardY[i],(CardX[i]+41),(CardY[i]+41));
  
        /* Get played cards */
  
        i=TrickLead;
        do
        {
                if (!i)
                        Card[i]=GetPlayerCard();
                else
                        Card[i]=GetCompCard(i);
                if (i==TrickLead)      /* First card played wins so far */
                {
                        HighCard=Card[i];
                        leadsuit=Card[i]/13;
                        Winner=i;
                }
                else
                {
                        suit=Card[i]/13;
      
                        /* See if this card is the new winner */
      
                        if (((suit==leadsuit)||(suit==SPADES))&&(Card[i]>HighCard))
                        {
                                HighCard=Card[i];
                                Winner=i;
                        }
      
                        /* Was player out of the lead suit ? */
      
                        if (suit!=leadsuit) OutOfSuit[i][leadsuit]=TRUE;
                }
                i=(++i)%4;
        } while (i!=TrickLead);
  
        ShowHand();
  
        /* Set highest card played in each suit */
  
        for (i=0 ; i<4 ; i++)
        {
                for (j=0 ; j<4 ; j++)    /* Need two loops to make sure we get all */
                {
                        value=Card[j]%13;
                        suit=Card[j]/13;
                        if (value==HighCardLeft[suit]) HighCardLeft[suit]=value-1;
                }
        }
  
        /* Send back trick winner */
  
        return(Winner);
}

/**********************************************************
* Function: GetPlayerCard                                 *
* Parameters: none                                        *
* Return Values: card picked to play                      *
* Purpose: Allow player to pick card to play.             *
**********************************************************/
int GetPlayerCard()
{
        int i,x,card;
  
        /* Let player know that it's his/her turn */
  
        SetBPen(RP,BLUP);
        SetAPen(RP,YELP);
        Move(RP,200,150);
        Text(RP,"PLAY A CARD",11);
  
        /* Loop until we get a good card */
  
        FOREVER
        {
                ReadMouse();                         /* Wait for mouse click */ 
                if (Button==MRIGHT) SuggestCard();   /* Player wants a suggestion */
                if (Button==MLEFT)                   /* Did player pick a card ? */
                {
                        for (i=12 ; i>=0 ; i--)      /* Check from right to left */
                        {
                                x=(i*10)+21;         /* Set left corner for card */
        
                                /* See if clicked inside this card and if card is still unplayed */
        
                                if ((My<187)&&(My>144)&&(Mx<(x+42))&&(Mx>=x)&&(Hand[0][i]))
                                {
                                        if (ValidCard(i))  /* Was this a playable card ? */
                                        {
                                                card=Hand[0][i]-1;
                                                Hand[0][i]=0;   /* Mark card as played */
                                                if ((card/13)==SPADES) SpadePlayed=TRUE; /* Spades have been broken */
            
                                                /* Erase suggestion '*' */
            
                                                SetAPen(RP,BLUP);
                                                SetOPen(RP,BLUP);
                                                RectFill(RP,21,136,170,144);
            
                                                DrawCard(CardX[0],CardY[0],card); /* Draw played card */
            
                                                /* Erase prompt message */
            
                                                SetBPen(RP,BLUP);
                                                Move(RP,200,150);
                                                Text(RP,"           ",11);
            
                                                /* Send back played card */
            
                                                return(card);
                                        }
                                        else
          
                                                /* if chosen card was not valid, need a new card */
            
                                                i=-1;
                                }
                        }
                }
        }
}

/**********************************************************
* Function: ValidCard                                     *
* Parameters: card -- card in player's hand to check      *
* Return Values: was card valid or not?                   *
* Purpose: To determine if the card chosen by the player  *
*   was valid or not.                                     *
**********************************************************/
BOOL ValidCard(card)
int card;
{
        int i,suit,leadsuit;
  
        SuitNumber[DIAMONDS]=0;
        SuitNumber[CLUBS]   =0;
        SuitNumber[HEARTS]  =0;
        SuitNumber[SPADES]  =0;
  
        /* Count number of cards player has in each suit */
  
        for (i=0 ; i<13 ; i++)
        {
                if (Hand[0][i]) SuitNumber[(Hand[0][i]-1)/13]++;
        }
  
        suit=(Hand[0][card]-1)/13; /* Find suit of played card */
  
        if (!TrickLead)            /* Player is leading */
        {
                /* If he didn't lead a spade, it was a good play */
                if (suit!=SPADES) return(TRUE);
    
                /* If he only has spades, he has no choice */ 
                if ((!SuitNumber[0])&&(!SuitNumber[1])&&(!SuitNumber[2])) return(TRUE);
    
                /* If spades have been played, he can lead anything */
                if (SpadePlayed) return(TRUE);
    
                /* Must have lead a spade when it was illegal to */
                return(FALSE);
        }
  
        /* Player doesn't lead */
  
        leadsuit=Card[TrickLead]/13;       /* Find suit that was lead */
  
        /* If he played the suit that was lead, he is OK */
        if (suit==leadsuit) return(TRUE);
  
        /* If he didn't have any, he's OK */
        if (!SuitNumber[leadsuit]) return(TRUE);
  
        /* Must have had some but didn't play them */
        return(FALSE);
}

/**********************************************************
* Function: CountCards                                    *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Count cards in each suit for a player.         *
*   Determine short and long suits.                       *
**********************************************************/
void CountCards(player)
int player;
{
        int i,card,suit,maximum,minimum;
  
        /* Initialization */
  
        SuitNumber[DIAMONDS]=0;
        SuitNumber[CLUBS]   =0;
        SuitNumber[HEARTS]  =0;
        SuitNumber[SPADES]  =0;
  
        /* Loop through all cards in the player's hand */
  
        for (i=0 ; i<13 ; i++)
        {
                if (Hand[player][i])        /* Make sure card hasn't been played */
                {
                        card=Hand[player][i]-1;
                        suit=card/13;
                        Value[i]=13-card;         /* Give lower cards a slight priority */
                        SuitNumber[suit]++;       /* Count Number of Suit held */
                }
                else
                        Value[i]=-50000;          /* Don't throw previously played cards */
        }
  
        /* Find short and long suits */
  
        minimum=14;
        maximum=0;
        ShortSuit=LongSuit=3;
        for (i=DIAMONDS ; i<SPADES ; i++)
        {
                if ((SuitNumber[i]<minimum)&&(SuitNumber[i]>0))
                {
                        minimum=SuitNumber[i];
                        ShortSuit=i;
                }
                if (SuitNumber[i]>maximum)
                {
                        maximum=SuitNumber[i];
                        LongSuit=i;
                }
        }
}
  
/**********************************************************
* Function: SuggestCard                                   *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Suggest a card for player to play.             *
**********************************************************/
void SuggestCard()
{
        int i,pick,maximum;
  
        CountCards(0);

        /* Go to appropriate point calculating routine */
  
        if (!TrickLead)
                CalcLead(0);
        else
                CalcFollow(0);
  
        /* Find best card (the one with the most points) */
  
        pick=0;
        maximum=Value[0];
        for (i=1 ; i<13 ; i++)
        {
                if (Value[i]>maximum)
                {
                        maximum=Value[i];
                        pick=i;
                }
        }
  
        /* Display an '*' over suggested card */
  
        SetAPen(RP,YELP);
        SetBPen(RP,BLUP);
        Move(RP,((pick*10))+22,142);
        Text(RP,"*",1);
}

/**********************************************************
* Function: GetCompCard                                   *
* Parameters: player -- player to play                    *
* Return Values: card played                              *
* Purpose: Determine which card a computer-controlled     *
*   player will play.                                     *
**********************************************************/
int GetCompCard(player)
int player;
{
        int i,pick,card,maximum;
  
        CountCards(player);

        /* Go to appropriate point calculating routine */
  
        if (player==TrickLead)
                CalcLead(player);
        else
                CalcFollow(player);
  
        /* Find best card (the one with the most points) */
  
        pick=0;
        maximum=Value[0];
        for (i=1 ; i<13 ; i++)
        {
                if (Value[i]>maximum)
                {
                        maximum=Value[i];
                        pick=i;
                }
        }
  
        card=Hand[player][pick]-1;
        if ((card/13)==3) SpadePlayed=TRUE;  /* Mark that spades have been broken */
        Hand[player][pick]=0;                /* Card has now been played */
        DrawCard(CardX[player],CardY[player],card);  /* Draw the played card */
        return(card);                        /* Send the played card back */
}

/**********************************************************
* Function: CalcLead                                      *
* Parameters: player -- whose hand to calculate           *
* Return Values: none                                     *
* Purpose: To calculate the value of each card in a hand  *
*          to determine which card should be played if    *
*          the hand is leading.                           *
**********************************************************/
void CalcLead(player)
int player;
{
        int i,card,suit,value;
        BOOL opponentsout=FALSE, partnerout=FALSE;
  
        /* Loop through all cards in hand */
  
        for (i=0 ; i<13 ; i++)
        {
                if (Hand[player][i])   /* Make sure card hasn't been played */
                {
      
                        /* Find suit and face value */
      
                        card=Hand[player][i]-1;
                        suit=card/13;
                        value=card%13;
      
                        if ((OutOfSuit[(player+1)%4][suit])||(OutOfSuit[(player+3)%4][suit]))
                                opponentsout=TRUE;
        
                        if (OutOfSuit[(player+2)%4][suit])
                                partnerout=TRUE;
      
                        if (value==HighCardLeft[suit])  /* Card is highest left in a suit */
                        {
                                if (suit==SPADES)       /* Spades don't matter if someone is */
                                        Value[i]+=50;   /* out. */
                                else
                                {  
                                        /* If opponents are out
                                           (or likely to be), don't waste */
                                        if ((opponentsout)||(value<11))
                                                Value[i]-=50;   /* high cards. */
                                        else
                                                Value[i]+=500;
                                }  
                        }
      
                        /* If player holds spades, get rid of short suit */
                        if ((SuitNumber[SPADES])&&(suit==ShortSuit)) Value[i]+=250;
      
                        /* If player doesn't hold spades, get rid of long suit */
                        if ((!SuitNumber[SPADES])&&(suit==LongSuit)) Value[i]+=250;
      
                        /* If spades aren't broken, they can't be lead */
                        if ((suit==SPADES)&&(!SpadePlayed)) Value[i]-=5000;
      
                        /* Lead suits your partner is out of */
                        if ((suit!=SPADES)&&(partnerout)&&(!opponentsout)) Value[i]+=100;
                }
        }
}

/**********************************************************
* Function: CalcFollow                                    *
* Parameters: player -- whose hand to calculate           *
* Return Values: none                                     *
* Purpose: To calculate the value of each card in a hand  *
*          to determine which card should be played if    *
*          the hand is not leading.                       *
**********************************************************/
void CalcFollow(player)
int player;
{
        int i,card,suit,value,leadsuit;
        BOOL alreadywon;
  
        leadsuit=Card[TrickLead]/13;  /* Calculate the suit that was lead */
  
        /* See if partner has already won the trick */
  
        alreadywon=FALSE;
        /* See if win is guaranteed (player is last to play) */
        if ((Winner==((player+2)%4))&&(TrickLead==((player+1)%4)))
                alreadywon=TRUE;  
    
        /* See if win is probable (player is next to last to play) */
        if ((Winner==TrickLead)&&(TrickLead==((player+2)%4)))
        {
                value=Card[TrickLead]%13;
                if ((value==HighCardLeft[leadsuit])&&(value>9)&&
                    !OutOfSuit[(player+3)%4][leadsuit]) alreadywon=TRUE;
        }

        /* Loop through all cards in hand */
  
        for (i=0 ; i<13 ; i++)
        {
                if (Hand[player][i])  /* Make sure card hasn't been played */
                {
      
                        /* Find suit and face value of card */
      
                        card=Hand[player][i]-1;
                        suit=card/13;
                        value=card%13;
      
                        if (suit==leadsuit)   /* Card is of lead suit */
                        { 
                                Value[i]+=5000;
        
                                /* If it is the highest one left in that suit, throw it */
                                if ((value==HighCardLeft[suit])&&(TrickLead!=((player+1)%4))&&(card>HighCard)&&!OutOfSuit[(player+1)%4][suit])
                                        Value[i]+=70;
          
                                /* See if card will beat those previously played */
                                if (card>HighCard)
                                {
                                        if (!alreadywon)  /* Team hasn't won yet */  
                                        {
                                                if (TrickLead==((player+1)%4))  /* Can definitely take trick */
                                                        Value[i]+=100;
                                                else                 
                                                        Value[i]+=10;   /* Maybe take trick */
                                        }    
                                        else
                                                Value[i]-=75;   /* If the team has won, hold high cards */
                                }
        
                                /* If team has already won the trick, throw low cards */
                                if ((card<HighCard)&&alreadywon) Value[i]+=75;
                        }
      
                        /* If player is going to throw a spade, make sure it has a chance of
                           winning */
                        if ((suit==SPADES)&&(card>HighCard))
                        {
                                if (!alreadywon)
                                        Value[i]+=10;   /* If team hasn't won, throw the spade */
                                else
                                        Value[i]-=1000; /* If team has won, hold high spades */
                        }
                        if ((suit==SPADES)&&(card<HighCard))
                        {
                                if (!alreadywon)
                                        Value[i]-=1000; /* If the team hasn't won, don't throw a losing spade */
                                else
                                        Value[i]+=10;   /* If the team has one, throw a low spade */
                        }
      
                        /* If player is out of the lead suit, don't throw important cards
                           in other suits */
                        if ((suit!=leadsuit)&&(value==HighCardLeft[suit])) Value[i]-=100;
      
                        /* If player is out of lead suit, let's see about trumping */
                        if ((!SuitNumber[leadsuit])&&(suit==SPADES))
                        {
                                if (!alreadywon)
                                        Value[i]+=100;  /* If team hasn't won, trump */
                                else
                                        Value[i]-=1000; /* If team has won, no need to trump */
                        }
      
                        /* If player is out of lead suit and out of spades, throw the long
                           suit left (keep as many suits as possible in hand) */
                        if ((!SuitNumber[leadsuit])&&(!SuitNumber[SPADES])&&(suit==LongSuit))
                        {
                                Value[i]+=100;
                        }
      
                        /* Give short suit a priority */
                        if (suit==ShortSuit) Value[i]+=45;
                }
        }
}

/**********************************************************
* Function: PrintBids                                     *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Display the number of tricks bid by each team  *
*          in the score box.                              *
**********************************************************/
void PrintBids()
{
        int length=0;
  
        SetAPen(RP,GRNP);
        SetBPen(RP,BLKP);
        itoa(PlayerBid,String);
        length=strlen(String);
        Move(RP,(235-(4*length)),38);
        Text(RP,String,length);
        itoa(CompBid,String);
        length=strlen(String);
        Move(RP,(283-(4*length)),38);
        Text(RP,String,length);
}

/**********************************************************
* Function: PrintScore                                    *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Display each team's score in the score box.    *
**********************************************************/
void PrintScore()
{
        int length=0;
  
        SetAPen(RP,GRNP);
        SetBPen(RP,BLKP);
        itoa(PlayerScore,String);
        length=strlen(String);
        Move(RP,(235-(4*length)),22);
        Text(RP,String,length);
        itoa(CompScore,String);
        length=strlen(String);
        Move(RP,(283-(4*length)),22);
        Text(RP,String,length);
}

/**********************************************************
* Function: PrintTricks                                   *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Display the number of tricks taken by each     *
*          team in the score box.                         *
**********************************************************/
void PrintTricks()
{
        int length=0;
  
        SetAPen(RP,GRNP);
        SetBPen(RP,BLKP);
        itoa(PlayerTricks,String);
        length=strlen(String);
        Move(RP,(235-(4*length)),54);
        Text(RP,String,length);
        itoa(CompTricks,String);
        length=strlen(String);
        Move(RP,(283-(4*length)),54);
        Text(RP,String,length);
}

/**********************************************************
* Function: ReadMouse                                     *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Wait for mouse input, and update the mouse     *
*          variables accordingly.                         *
**********************************************************/
void ReadMouse()
{
        ULONG class;
        USHORT code;
        BOOL gotmouse=FALSE;

        /* Loop until we have a mouse message */
  
        while(!gotmouse)
        {
    
                /* Wait for Intuition Message */
    
                if ((Message=(struct IntuiMessage *) GetMsg(Wdw->UserPort)) == NULL)
                { 
                        Wait(1L<<Wdw->UserPort->mp_SigBit);
                        continue;
                }
    
                /* Interpret Message */
    
                class = Message->Class;
                code = Message->Code;
                Mx=((SHORT) Message->MouseX) - 4;  /* Adjustments for      */
                My=((SHORT) Message->MouseY) - 12; /* GIMMEZEROZERO Window */

                ReplyMsg((struct Message *)Message);

                /* See if Window Close Box clicked */
    
                if (class & CLOSEWINDOW) WrapUp();

                /* See if Hide Gadget clicked */
                
                if (class & GADGETUP) 
                {
                        ScreenToBack(CustScr);
                        return;
                }
                                
                /* Otherwise, make sure Message was caused by mouse */
    
                if (class & MOUSEBUTTONS)
                {
                        switch(code)
                        {
        
                                /* Left Button Released */
        
                                case SELECTUP:
                                        Button=MLEFT;
                                        gotmouse=TRUE;
                                        break;
        
                                /* Right Button Released */
        
                                case MENUUP:   
                                        Button=MRIGHT;
                                        gotmouse=TRUE;
                                        break;
           
                                /* Other Input */
        
                                default:
                                        gotmouse=FALSE;
                        }   
                }
        }
} 

/**********************************************************
* Function: DrawCard                                      *
* Parameters: x -- x coordinate of top left corner        *
*             y -- y coordinate of top left corner        *
*           card -- number of card to draw                *
* Return Values: none                                     *
* Purpose: Draw a card.                                   *
**********************************************************/   
void DrawCard(x, y, card)
int x, y, card;
{
        CardImage.ImageData = (UWORD *)(CardData+card*126*6);
        DrawImage(RP, &CardImage, x, y);
}

/**********************************************************
* Function: FinishRoutine                                 *
* Parameters: none                                        *
* Return Values: none                                     *
* Purpose: Display final score, ask to play again.        *
**********************************************************/
void FinishRoutine()
{
        BOOL haveinput;
  
        SetRast(RP,BLUP);
  
        SetAPen(RP,WHTP);
        SetBPen(RP,BLUP);
  
        Move(RP,112,56);
        Text(RP,"FINAL SCORE:",12);
        Move(RP,80,72);
        Text(RP,"YOU:",4);
        Move(RP,184,72);
        Text(RP,"ME:",3);
        SetAPen(RP,YELP);
        itoa(PlayerScore,String);
        Move(RP,116,72);
        Text(RP,String,strlen(String));
        itoa(CompScore,String);
        Move(RP,212,72);
        Text(RP,String,strlen(String));
  
        Move(RP,112,96);
        Text(RP,"PLAY AGAIN ?",12);
        SetAPen(RP,BLKP);
        SetBPen(RP,WHTP);
        Move(RP,112,112);
        Text(RP,"YES",3);
        Move(RP,188,112);
        Text(RP,"NO",2);
  
        haveinput=FALSE;
        while (!haveinput)
        {
                ReadMouse();
                if ((Mx>111)&&(Mx<136)&&(My>105)&&(My<114))
                {
                        haveinput=TRUE;
                        AllDone=FALSE;
                }
                if ((Mx>187)&&(Mx<204)&&(My>105)&&(My<114))
                {
                        haveinput=TRUE;
                        AllDone=TRUE;
                }
        }
}

/**********************************************************
* Function: itoa                                          *
* Parameters: n -- number to convert                      *
*             s -- pointer to result string               *
* Return Values: none                                     *
* Purpose: Convert an integer to a string so it can be    *
*          used by the Text function. Lattice does not    *
*          have one.                                      *
**********************************************************/
void itoa(n,s)
char *s;
int n;
{
        int i=0;
        BOOL sign=FALSE;
  
        if (n<0)
        {
                sign=TRUE;
                n=-n;
        }
        do
        {
                s[i++]=n%10+'0';
        } while((n/=10)>0);
        if (sign) s[i++]='-';
        s[i]='\0';
        strrev(s);
}