mirror of
https://github.com/reactos/reactos.git
synced 2024-08-17 08:58:30 +00:00
309 lines
8.3 KiB
C++
309 lines
8.3 KiB
C++
/*
|
|
* PROJECT: Spider Solitaire
|
|
* LICENSE: See COPYING in top level directory
|
|
* FILE: base/applications/games/spider/spigame.cpp
|
|
* PURPOSE: Spider Solitaire game functions
|
|
* PROGRAMMER: Gregor Schneider
|
|
*/
|
|
|
|
#include "spider.h"
|
|
|
|
#define NUM_DECK_CARDS 5
|
|
#define NUM_SMALLER_STACKS 4
|
|
#define NUM_CARD_COLORS 4
|
|
#define NUM_ONECOLOR_CARDS 13
|
|
#define NUM_STD_CARDS 52
|
|
#define NUM_SPIDER_CARDS 104
|
|
|
|
CardStack deck;
|
|
CardRegion *from;
|
|
CardRegion *pDeck;
|
|
CardRegion *pStack[NUM_STACKS];
|
|
bool fGameStarted = false;
|
|
int yRowStackCardOffset;
|
|
int cardsFinished;
|
|
extern TCHAR MsgDeal[];
|
|
extern TCHAR MsgWin[];
|
|
|
|
CardStack CreatePlayDeck()
|
|
{
|
|
CardStack newStack;
|
|
int i, colors = 1, num = 0;
|
|
|
|
switch (dwDifficulty)
|
|
{
|
|
case IDC_DIF_ONECOLOR:
|
|
colors = 1;
|
|
break;
|
|
case IDC_DIF_TWOCOLORS:
|
|
colors = 2;
|
|
break;
|
|
case IDC_DIF_FOURCOLORS:
|
|
colors = 4;
|
|
break;
|
|
}
|
|
for (i = 0; i < NUM_SPIDER_CARDS; i++)
|
|
{
|
|
num += NUM_CARD_COLORS / colors;
|
|
Card newCard(num % NUM_STD_CARDS);
|
|
newStack.Push(newCard);
|
|
}
|
|
return newStack;
|
|
}
|
|
|
|
void NewGame(void)
|
|
{
|
|
int i, j;
|
|
/* First four stack with five, all other with 4 */
|
|
int covCards = 5;
|
|
CardStack fakeDeck, temp;
|
|
|
|
SpiderWnd.EmptyStacks();
|
|
|
|
/* Create a new card-deck, fake deck */
|
|
deck = CreatePlayDeck();
|
|
deck.Shuffle();
|
|
fakeDeck.NewDeck();
|
|
fakeDeck.Shuffle();
|
|
|
|
/* Reset progress value */
|
|
cardsFinished = 0;
|
|
|
|
/* Deal to each stack */
|
|
for (i = 0; i < NUM_STACKS; i++)
|
|
{
|
|
temp.Clear();
|
|
if (i == NUM_SMALLER_STACKS)
|
|
{
|
|
covCards--;
|
|
}
|
|
for (j = 0; j <= covCards; j++)
|
|
{
|
|
temp.Push(deck.Pop(1));
|
|
}
|
|
pStack[i]->SetFaceDirection(CS_FACE_DOWNUP, covCards);
|
|
pStack[i]->SetCardStack(temp);
|
|
}
|
|
/* Deal five fake cards to the deck */
|
|
pDeck->SetCardStack(fakeDeck.Pop(5));
|
|
|
|
SpiderWnd.Redraw();
|
|
fGameStarted = false;
|
|
}
|
|
|
|
bool stackLookingGood(const CardStack &mystack, int numChecks)
|
|
{
|
|
int i;
|
|
for (i = 0; i < numChecks; i++)
|
|
{
|
|
if (mystack[i].LoVal() != mystack[i + 1].LoVal() - 1)
|
|
{
|
|
return false;
|
|
}
|
|
if (mystack[i].Suit() != mystack[i + 1].Suit())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* Card to be turned from a stack */
|
|
void TurnStackCard(CardRegion &stackobj)
|
|
{
|
|
int numfacedown;
|
|
|
|
stackobj.GetFaceDirection(&numfacedown);
|
|
if (stackobj.NumCards() <= numfacedown)
|
|
{
|
|
if (numfacedown > 0) numfacedown--;
|
|
stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
|
|
stackobj.Redraw();
|
|
}
|
|
}
|
|
|
|
/* Click on the deck */
|
|
void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int NumDragCards)
|
|
{
|
|
CardStack temp, fakeDeck = pDeck->GetCardStack();
|
|
fGameStarted = true;
|
|
|
|
if (fakeDeck.NumCards() != 0 && deck.NumCards() != 0)
|
|
{
|
|
int i, facedown, faceup;
|
|
/* Add one card to every stack */
|
|
for (i = 0; i < NUM_STACKS; i++)
|
|
{
|
|
temp = pStack[i]->GetCardStack();
|
|
temp.Push(deck.Pop());
|
|
|
|
/* Check if we accidentally finished a row */
|
|
pStack[i]->GetFaceDirection(&facedown);
|
|
faceup = temp.NumCards() - facedown;
|
|
if (faceup >= NUM_ONECOLOR_CARDS)
|
|
{
|
|
/* Check stack finished, remove cards if so */
|
|
if (stackLookingGood(temp, NUM_ONECOLOR_CARDS - 1))
|
|
{
|
|
int j;
|
|
for (j = 0; j < NUM_ONECOLOR_CARDS; j++)
|
|
{
|
|
temp.RemoveCard(0);
|
|
}
|
|
cardsFinished += NUM_ONECOLOR_CARDS;
|
|
pStack[i]->SetCardStack(temp);
|
|
/* Turn now topmost card */
|
|
TurnStackCard(*pStack[i]);
|
|
}
|
|
}
|
|
pStack[i]->SetCardStack(temp);
|
|
}
|
|
/* Remove one card from the fake ones */
|
|
pDeck->SetCardStack(fakeDeck.Pop(fakeDeck.NumCards() - 1));
|
|
}
|
|
pDeck->Update();
|
|
SpiderWnd.Redraw();
|
|
}
|
|
|
|
/* Cards dragged from a stack */
|
|
bool CARDLIBPROC StackDragProc(CardRegion &stackobj, int numDragCards)
|
|
{
|
|
int numfacedown, numcards;
|
|
|
|
stackobj.GetFaceDirection(&numfacedown);
|
|
numcards = stackobj.NumCards();
|
|
|
|
/* Only cards facing up */
|
|
if (numDragCards <= numcards - numfacedown)
|
|
{
|
|
const CardStack &mystack = stackobj.GetCardStack();
|
|
/* Don't allow to drag unsuited cards */
|
|
if (!stackLookingGood(mystack, numDragCards - 1))
|
|
{
|
|
return false;
|
|
}
|
|
/* Remember where the cards come from */
|
|
from = &stackobj;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Game finished successfully */
|
|
void GameFinished()
|
|
{
|
|
SpiderWnd.EmptyStacks();
|
|
|
|
MessageBox(SpiderWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
|
|
if( IDYES == MessageBox(SpiderWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
|
|
{
|
|
NewGame();
|
|
}
|
|
else
|
|
{
|
|
fGameStarted = false;
|
|
}
|
|
}
|
|
|
|
/* Card added, check for win situation */
|
|
void CARDLIBPROC StackAddProc(CardRegion &stackobj, const CardStack &added)
|
|
{
|
|
if (cardsFinished == NUM_SPIDER_CARDS)
|
|
{
|
|
GameFinished();
|
|
}
|
|
}
|
|
|
|
/* Cards dropped to a stack */
|
|
bool CARDLIBPROC StackDropProc(CardRegion &stackobj, CardStack &dragcards)
|
|
{
|
|
Card dragcard = dragcards[dragcards.NumCards() - 1];
|
|
int faceup, facedown;
|
|
|
|
/* Only drop our cards on other stacks */
|
|
if (stackobj.Id() == from->Id())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* If stack is empty, everything can be dropped */
|
|
if (stackobj.NumCards() != 0)
|
|
{
|
|
const CardStack &mystack = stackobj.GetCardStack();
|
|
|
|
/* Can only drop if card is 1 less */
|
|
if (mystack[0].LoVal() != dragcard.LoVal() + 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* Check if stack complete */
|
|
stackobj.GetFaceDirection(&facedown);
|
|
faceup = stackobj.NumCards() - facedown;
|
|
|
|
if (faceup + dragcards.NumCards() >= NUM_ONECOLOR_CARDS)
|
|
{
|
|
int i, max = NUM_ONECOLOR_CARDS - dragcards.NumCards() - 1;
|
|
|
|
/* Dragged cards have been checked to be in order, check stack cards */
|
|
if (mystack[0].Suit() == dragcard.Suit() &&
|
|
stackLookingGood(mystack, max))
|
|
{
|
|
CardStack s = stackobj.GetCardStack();
|
|
CardStack f;
|
|
|
|
/* Remove from card stack */
|
|
for (i = 0; i < max + 1; i++)
|
|
{
|
|
s.RemoveCard(0);
|
|
}
|
|
/* Remove dragged cards */
|
|
dragcards = f;
|
|
stackobj.SetCardStack(s);
|
|
cardsFinished += NUM_ONECOLOR_CARDS;
|
|
/* Flip top card of the dest stack */
|
|
TurnStackCard(stackobj);
|
|
}
|
|
}
|
|
}
|
|
/* Flip the top card of the source stack */
|
|
TurnStackCard(*from);
|
|
fGameStarted = true;
|
|
return true;
|
|
}
|
|
|
|
/* Create card regions */
|
|
void CreateSpider()
|
|
{
|
|
int i, pos;
|
|
|
|
/* Compute the value for yRowStackCardOffset based on the height of the card, so the card number and suite isn't hidden on larger cards except Ace */
|
|
yRowStackCardOffset = (int)(__cardheight / 6.4);
|
|
|
|
pDeck = SpiderWnd.CreateRegion(0, true, 0, 0, -15, 0);
|
|
pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
|
|
pDeck->SetEmptyImage(CS_EI_CIRC);
|
|
pDeck->SetPlacement(CS_XJUST_RIGHT, CS_YJUST_BOTTOM, - X_BORDER, - Y_BORDER);
|
|
pDeck->SetDragRule(CS_DRAG_NONE, 0);
|
|
pDeck->SetDropRule(CS_DROP_NONE, 0);
|
|
pDeck->SetClickReleaseProc(DeckClickProc);
|
|
|
|
/* Create the row stacks */
|
|
for (i = 0; i < NUM_STACKS; i++)
|
|
{
|
|
pStack[i] = SpiderWnd.CreateRegion(NUM_STACKS+i, true, 0, Y_BORDER, 0, yRowStackCardOffset);
|
|
pStack[i]->SetFaceDirection(CS_FACE_DOWN, 0);
|
|
pos = i - NUM_STACKS/2;
|
|
pStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
|
|
pos * (__cardwidth + X_BORDER) + 6 * (X_BORDER + 1) + 3, 0);
|
|
pStack[i]->SetEmptyImage(CS_EI_SUNK);
|
|
pStack[i]->SetDragRule(CS_DRAG_CALLBACK, StackDragProc);
|
|
pStack[i]->SetDropRule(CS_DROP_CALLBACK, StackDropProc);
|
|
pStack[i]->SetAddCardProc(StackAddProc);
|
|
}
|
|
}
|
|
|