reactos/base/applications/games/spider/spigame.cpp

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);
}
}