mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 05:08:39 +00:00
566 lines
12 KiB
C++
566 lines
12 KiB
C++
#include "solitaire.h"
|
|
|
|
#if 1
|
|
#define TRACE(s)
|
|
#else
|
|
#define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
|
|
#endif
|
|
|
|
extern TCHAR MsgWin[128];
|
|
extern TCHAR MsgDeal[128];
|
|
|
|
CardStack activepile;
|
|
int LastId;
|
|
bool fGameStarted = false;
|
|
bool bAutoroute = false;
|
|
|
|
void NewGame(void)
|
|
{
|
|
TRACE("ENTER NewGame()\n");
|
|
int i, j;
|
|
|
|
if (GetScoreMode() == SCORE_VEGAS)
|
|
{
|
|
if ((dwOptions & OPTION_KEEP_SCORE) && (dwPrevMode == SCORE_VEGAS))
|
|
lScore = lScore - 52;
|
|
else
|
|
lScore = -52;
|
|
|
|
if (dwOptions & OPTION_THREE_CARDS)
|
|
dwWasteTreshold = 2;
|
|
else
|
|
dwWasteTreshold = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (dwOptions & OPTION_THREE_CARDS)
|
|
dwWasteTreshold = 3;
|
|
else
|
|
dwWasteTreshold = 0;
|
|
|
|
lScore = 0;
|
|
}
|
|
|
|
dwTime = 0;
|
|
dwWasteCount = 0;
|
|
LastId = 0;
|
|
|
|
SolWnd.EmptyStacks();
|
|
|
|
//create a new card-stack
|
|
CardStack deck;
|
|
deck.NewDeck();
|
|
deck.Shuffle();
|
|
activepile.Clear();
|
|
|
|
//deal to each row stack..
|
|
for(i = 0; i < NUM_ROW_STACKS; i++)
|
|
{
|
|
CardStack temp;
|
|
temp.Clear();
|
|
|
|
pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i);
|
|
|
|
for(j = 0; j <= i; j++)
|
|
{
|
|
temp.Push(deck.Pop());
|
|
}
|
|
|
|
pRowStack[i]->SetCardStack(temp);
|
|
}
|
|
|
|
//put the other cards onto the deck
|
|
pDeck->SetCardStack(deck);
|
|
pDeck->Update();
|
|
|
|
// For the 1-card-mode, all cards need to be completely overlapped
|
|
if(!(dwOptions & OPTION_THREE_CARDS))
|
|
pPile->SetOffsets(0, 0);
|
|
|
|
SolWnd.Redraw();
|
|
|
|
fGameStarted = false;
|
|
|
|
dwPrevMode = GetScoreMode();
|
|
|
|
UpdateStatusBar();
|
|
|
|
TRACE("EXIT NewGame()\n");
|
|
|
|
}
|
|
|
|
//
|
|
// Now follow the stack callback functions. This is where we
|
|
// provide the game functionality and rules
|
|
//
|
|
|
|
//
|
|
// Can only drag face-up cards
|
|
//
|
|
bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards)
|
|
{
|
|
TRACE("ENTER RowStackDragProc()\n");
|
|
int numfacedown;
|
|
int numcards;
|
|
|
|
SetPlayTimer();
|
|
|
|
stackobj.GetFaceDirection(&numfacedown);
|
|
|
|
numcards = stackobj.NumCards();
|
|
|
|
TRACE("EXIT RowStackDragProc()\n");
|
|
if(iNumDragCards <= numcards-numfacedown)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
}
|
|
|
|
//
|
|
// Row a row-stack, we can only drop cards
|
|
// that are lower / different colour
|
|
//
|
|
bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards)
|
|
{
|
|
TRACE("ENTER RowStackDropProc()\n");
|
|
Card dragcard = dragcards[dragcards.NumCards() - 1];
|
|
|
|
SetPlayTimer();
|
|
|
|
//if we are empty, can only drop a stack with a King at bottom
|
|
if(stackobj.NumCards() == 0)
|
|
{
|
|
if(dragcard.LoVal() != 13)
|
|
{
|
|
TRACE("EXIT RowStackDropProc(false)\n");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const CardStack &mystack = stackobj.GetCardStack();
|
|
|
|
//can only drop if card is 1 less
|
|
if(mystack[0].LoVal() != dragcard.LoVal() + 1)
|
|
{
|
|
TRACE("EXIT RowStackDropProc(false)\n");
|
|
return false;
|
|
}
|
|
|
|
//can only drop if card is different colour
|
|
if( (mystack[0].IsBlack() && !dragcard.IsRed()) ||
|
|
(!mystack[0].IsBlack() && dragcard.IsRed()) )
|
|
{
|
|
TRACE("EXIT RowStackDropProc(false)\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fGameStarted = true;
|
|
|
|
if (LastId == PILE_ID)
|
|
{
|
|
if (GetScoreMode() == SCORE_STD)
|
|
{
|
|
lScore = lScore + 5;
|
|
}
|
|
}
|
|
else if ((LastId >= SUIT_ID) && (LastId <= SUIT_ID + 3))
|
|
{
|
|
if (GetScoreMode() == SCORE_STD)
|
|
{
|
|
lScore = lScore >= 15 ? lScore - 15 : 0;
|
|
}
|
|
else if (GetScoreMode() == SCORE_VEGAS)
|
|
{
|
|
lScore = lScore >= -47 ? lScore - 5 : -52;
|
|
}
|
|
}
|
|
|
|
UpdateStatusBar();
|
|
|
|
TRACE("EXIT RowStackDropProc(true)\n");
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Can only drop a card onto a suit-stack if the
|
|
// card is 1 higher, and is the same suit
|
|
//
|
|
bool CanDrop(CardRegion &stackobj, Card card)
|
|
{
|
|
TRACE("ENTER CanDrop()\n");
|
|
int topval;
|
|
|
|
const CardStack &cardstack = stackobj.GetCardStack();
|
|
|
|
SetPlayTimer();
|
|
|
|
if(cardstack.NumCards() > 0)
|
|
{
|
|
if(card.Suit() != cardstack[0].Suit())
|
|
{
|
|
TRACE("EXIT CanDrop()\n");
|
|
return false;
|
|
}
|
|
|
|
topval = cardstack[0].LoVal();
|
|
}
|
|
else
|
|
{
|
|
topval = 0;
|
|
}
|
|
|
|
//make sure 1 higher
|
|
if(card.LoVal() != (topval + 1))
|
|
{
|
|
TRACE("EXIT CanDrop()\n");
|
|
return false;
|
|
}
|
|
|
|
TRACE("EXIT CanDrop()\n");
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// Can only drop a card onto suit stack if it is same suit, and 1 higher
|
|
//
|
|
bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards)
|
|
{
|
|
TRACE("ENTER SuitStackDropProc()\n");
|
|
|
|
SetPlayTimer();
|
|
|
|
//only drop 1 card at a time
|
|
if (!bAutoroute && dragcards.NumCards() != 1)
|
|
{
|
|
TRACE("EXIT SuitStackDropProc()\n");
|
|
return false;
|
|
}
|
|
|
|
bool b = CanDrop(stackobj, dragcards[0]);
|
|
TRACE("EXIT SuitStackDropProc()\n");
|
|
|
|
if (b)
|
|
{
|
|
if ((LastId == PILE_ID) || (LastId >= ROW_ID))
|
|
{
|
|
if (GetScoreMode() == SCORE_VEGAS)
|
|
{
|
|
lScore = lScore + 5;
|
|
}
|
|
else if (GetScoreMode() == SCORE_STD)
|
|
{
|
|
lScore = lScore + 10;
|
|
}
|
|
|
|
UpdateStatusBar();
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
//
|
|
// Single-click on one of the suit-stacks
|
|
//
|
|
void CARDLIBPROC SuitStackClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER SuitStackClickProc()\n");
|
|
|
|
fGameStarted = true;
|
|
|
|
LastId = stackobj.Id();
|
|
|
|
TRACE("EXIT SuitStackClickProc()\n");
|
|
}
|
|
|
|
//
|
|
// Single-click on one of the row-stacks
|
|
// Turn the top-card over if they are all face-down
|
|
//
|
|
void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER RowStackClickProc()\n");
|
|
int numfacedown;
|
|
|
|
stackobj.GetFaceDirection(&numfacedown);
|
|
|
|
//if all face-down, then make top card face-up
|
|
if(stackobj.NumCards() == numfacedown)
|
|
{
|
|
if(numfacedown > 0) numfacedown--;
|
|
stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
|
|
stackobj.Redraw();
|
|
|
|
if (GetScoreMode() == SCORE_STD)
|
|
{
|
|
lScore = lScore + 5;
|
|
UpdateStatusBar();
|
|
}
|
|
}
|
|
|
|
LastId = stackobj.Id();
|
|
|
|
fGameStarted = true;
|
|
|
|
TRACE("EXIT RowStackClickProc()\n");
|
|
}
|
|
|
|
//
|
|
// Find the suit-stack that can accept the specified card
|
|
//
|
|
CardRegion *FindSuitStackFromCard(Card card)
|
|
{
|
|
TRACE("ENTER FindSuitStackFromCard()\n");
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
if(CanDrop(*pSuitStack[i], card))
|
|
{
|
|
TRACE("EXIT FindSuitStackFromCard()\n");
|
|
return pSuitStack[i];
|
|
}
|
|
}
|
|
|
|
TRACE("EXIT FindSuitStackFromCard()\n");
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// What happens when we add a card to one of the suit stacks?
|
|
// Well, nothing (it is already added), but we need to
|
|
// check all four stacks (not just this one) to see if
|
|
// the game has finished.
|
|
//
|
|
void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added)
|
|
{
|
|
TRACE("ENTER SuitStackAddProc()\n");
|
|
bool fGameOver = true;
|
|
|
|
SetPlayTimer();
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
if(pSuitStack[i]->NumCards() != 13)
|
|
{
|
|
fGameOver = false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(fGameOver)
|
|
{
|
|
KillTimer(hwndMain, IDT_PLAYTIMER);
|
|
PlayTimer = 0;
|
|
|
|
if ((dwOptions & OPTION_SHOW_TIME) && (GetScoreMode() == SCORE_STD))
|
|
{
|
|
lScore = lScore + (700000 / dwTime);
|
|
}
|
|
|
|
UpdateStatusBar();
|
|
|
|
MessageBox(SolWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
{
|
|
pSuitStack[i]->Flash(11, 100);
|
|
}
|
|
|
|
if( IDYES == MessageBox(SolWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
|
|
{
|
|
NewGame();
|
|
}
|
|
else
|
|
{
|
|
SolWnd.EmptyStacks();
|
|
|
|
fGameStarted = false;
|
|
}
|
|
}
|
|
|
|
TRACE("EXIT SuitStackAddProc()\n");
|
|
}
|
|
|
|
//
|
|
// Double-click on one of the row stacks
|
|
// The aim is to find a suit-stack to move the
|
|
// double-clicked card to.
|
|
//
|
|
void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER RowStackDblClickProc()\n");
|
|
|
|
SetPlayTimer();
|
|
|
|
//can only move 1 card at a time
|
|
if(iNumClicked != 1)
|
|
{
|
|
TRACE("EXIT RowStackDblClickProc()\n");
|
|
return;
|
|
}
|
|
|
|
//find a suit-stack to move the card to...
|
|
const CardStack &cardstack = stackobj.GetCardStack();
|
|
CardRegion *pDest = FindSuitStackFromCard(cardstack[0]);
|
|
|
|
if(pDest != 0)
|
|
{
|
|
fGameStarted = true;
|
|
SetPlayTimer();
|
|
|
|
//stackobj.MoveCards(pDest, 1, true);
|
|
//use the SimulateDrag function, because we get the
|
|
//AddProc callbacks called for us on the destination stacks...
|
|
bAutoroute = true;
|
|
stackobj.SimulateDrag(pDest, 1, true);
|
|
bAutoroute = false;
|
|
}
|
|
TRACE("EXIT RowStackDblClickProc()\n");
|
|
}
|
|
|
|
//
|
|
// Face-up pile single-click
|
|
//
|
|
void CARDLIBPROC PileClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER SuitStackClickProc()\n");
|
|
|
|
fGameStarted = true;
|
|
|
|
LastId = stackobj.Id();
|
|
|
|
TRACE("EXIT SuitStackClickProc()\n");
|
|
}
|
|
|
|
//
|
|
// Face-up pile double-click
|
|
//
|
|
void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER PileDblClickProc()\n");
|
|
|
|
SetPlayTimer();
|
|
|
|
RowStackDblClickProc(stackobj, iNumClicked);
|
|
TRACE("EXIT PileDblClickProc()\n");
|
|
}
|
|
|
|
//
|
|
// What happens when a card is removed from face-up pile?
|
|
//
|
|
void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems)
|
|
{
|
|
TRACE("ENTER PileRemoveProc()\n");
|
|
|
|
SetPlayTimer();
|
|
|
|
//modify our "virtual" pile by removing the same card
|
|
//that was removed from the physical card stack
|
|
activepile.Pop(iItems);
|
|
|
|
//if there is just 1 card left, then modify the
|
|
//stack to contain ALL the face-up cards..the effect
|
|
//will be, the next time a card is dragged, all the
|
|
//previous card-triplets will be available underneath
|
|
if(stackobj.NumCards() == 1)
|
|
{
|
|
stackobj.SetOffsets(0,0);
|
|
stackobj.SetCardStack(activepile);
|
|
}
|
|
TRACE("EXIT PileRemoveProc()\n");
|
|
}
|
|
|
|
//
|
|
// Double-click on the deck
|
|
// Move 3 cards to the face-up pile
|
|
//
|
|
void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked)
|
|
{
|
|
TRACE("ENTER DeckClickProc()\n");
|
|
|
|
SetPlayTimer();
|
|
|
|
CardStack cardstack = stackobj.GetCardStack();
|
|
CardStack pile = pPile->GetCardStack();
|
|
|
|
fGameStarted = true;
|
|
SetPlayTimer();
|
|
|
|
//reset the face-up pile to represent 3 cards
|
|
if(dwOptions & OPTION_THREE_CARDS)
|
|
pPile->SetOffsets(CS_DEFXOFF, 1);
|
|
|
|
if(cardstack.NumCards() == 0)
|
|
{
|
|
if (GetScoreMode() == SCORE_VEGAS)
|
|
{
|
|
if (dwWasteCount < dwWasteTreshold)
|
|
{
|
|
pile.Clear();
|
|
|
|
activepile.Reverse();
|
|
cardstack.Push(activepile);
|
|
activepile.Clear();
|
|
}
|
|
}
|
|
else if (GetScoreMode() == SCORE_STD)
|
|
{
|
|
if ((dwWasteCount >= dwWasteTreshold) && (activepile.NumCards() != 0))
|
|
{
|
|
if (dwOptions & OPTION_THREE_CARDS)
|
|
lScore = lScore >= 20 ? lScore - 20 : 0;
|
|
else
|
|
lScore = lScore >= 100 ? lScore - 100 : 0;
|
|
}
|
|
|
|
pile.Clear();
|
|
|
|
activepile.Reverse();
|
|
cardstack.Push(activepile);
|
|
activepile.Clear();
|
|
|
|
UpdateStatusBar();
|
|
}
|
|
else
|
|
{
|
|
pile.Clear();
|
|
|
|
activepile.Reverse();
|
|
cardstack.Push(activepile);
|
|
activepile.Clear();
|
|
}
|
|
|
|
dwWasteCount++;
|
|
}
|
|
else
|
|
{
|
|
int numcards = min((dwOptions & OPTION_THREE_CARDS) ? 3 : 1, cardstack.NumCards());
|
|
|
|
//make a "visible" copy of these cards
|
|
CardStack temp;
|
|
temp = cardstack.Pop(numcards);
|
|
temp.Reverse();
|
|
|
|
if(dwOptions & OPTION_THREE_CARDS)
|
|
pile.Clear();
|
|
|
|
pile.Push(temp);
|
|
|
|
//remove the top 3 from deck
|
|
activepile.Push(temp);
|
|
}
|
|
|
|
activepile.Print();
|
|
|
|
pDeck->SetCardStack(cardstack);
|
|
pPile->SetCardStack(pile);
|
|
|
|
SolWnd.Redraw();
|
|
TRACE("EXIT DeckClickProc()\n");
|
|
}
|