[SPIDER]
[reactos.git] / reactos / base / applications / games / spider / spigame.cpp
1 /*
2 * PROJECT: Spider Solitaire
3 * LICENSE: See COPYING in top level directory
4 * FILE: base/applications/games/spider/spigame.cpp
5 * PURPOSE: Spider Solitaire game functions
6 * PROGRAMMER: Gregor Schneider
7 */
8
9 #include "spider.h"
10
11 #define NUM_DECK_CARDS 5
12 #define NUM_SMALLER_STACKS 4
13 #define NUM_CARD_COLORS 4
14 #define NUM_ONECOLOR_CARDS 13
15 #define NUM_STD_CARDS 52
16 #define NUM_SPIDER_CARDS 104
17
18 CardStack deck;
19 CardRegion *from;
20 CardRegion *pDeck;
21 CardRegion *pStack[NUM_STACKS];
22 bool fGameStarted = false;
23 int yRowStackCardOffset;
24 int cardsFinished;
25 extern TCHAR MsgDeal[];
26 extern TCHAR MsgWin[];
27
28 CardStack CreatePlayDeck()
29 {
30 CardStack newStack;
31 int i, colors = 1, num = 0;
32
33 switch (dwDifficulty)
34 {
35 case IDC_DIF_ONECOLOR:
36 colors = 1;
37 break;
38 case IDC_DIF_TWOCOLORS:
39 colors = 2;
40 break;
41 case IDC_DIF_FOURCOLORS:
42 colors = 4;
43 break;
44 }
45 for (i = 0; i < NUM_SPIDER_CARDS; i++)
46 {
47 num += NUM_CARD_COLORS / colors;
48 Card newCard(num % NUM_STD_CARDS);
49 newStack.Push(newCard);
50 }
51 return newStack;
52 }
53
54 void NewGame(void)
55 {
56 int i, j;
57 /* First four stack with five, all other with 4 */
58 int covCards = 5;
59 CardStack fakeDeck, temp;
60
61 SpiderWnd.EmptyStacks();
62
63 /* Create a new card-deck, fake deck */
64 deck = CreatePlayDeck();
65 deck.Shuffle();
66 fakeDeck.NewDeck();
67 fakeDeck.Shuffle();
68
69 /* Reset progress value */
70 cardsFinished = 0;
71
72 /* Deal to each stack */
73 for (i = 0; i < NUM_STACKS; i++)
74 {
75 temp.Clear();
76 if (i == NUM_SMALLER_STACKS)
77 {
78 covCards--;
79 }
80 for (j = 0; j <= covCards; j++)
81 {
82 temp.Push(deck.Pop(1));
83 }
84 pStack[i]->SetFaceDirection(CS_FACE_DOWNUP, covCards);
85 pStack[i]->SetCardStack(temp);
86 }
87 /* Deal five fake cards to the deck */
88 pDeck->SetCardStack(fakeDeck.Pop(5));
89
90 SpiderWnd.Redraw();
91 fGameStarted = false;
92 }
93
94 bool stackLookingGood(const CardStack &mystack, int numChecks)
95 {
96 int i;
97 for (i = 0; i < numChecks; i++)
98 {
99 if (mystack[i].LoVal() != mystack[i + 1].LoVal() - 1)
100 {
101 return false;
102 }
103 if (mystack[i].Suit() != mystack[i + 1].Suit())
104 {
105 return false;
106 }
107 }
108 return true;
109 }
110
111 /* Card to be turned from a stack */
112 void TurnStackCard(CardRegion &stackobj)
113 {
114 int numfacedown;
115
116 stackobj.GetFaceDirection(&numfacedown);
117 if (stackobj.NumCards() <= numfacedown)
118 {
119 if (numfacedown > 0) numfacedown--;
120 stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
121 stackobj.Redraw();
122 }
123 }
124
125 /* Click on the deck */
126 void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int NumDragCards)
127 {
128 CardStack temp, fakeDeck = pDeck->GetCardStack();
129 fGameStarted = true;
130
131 if (fakeDeck.NumCards() != 0 && deck.NumCards() != 0)
132 {
133 int i, facedown, faceup;
134 /* Add one card to every stack */
135 for (i = 0; i < NUM_STACKS; i++)
136 {
137 temp = pStack[i]->GetCardStack();
138 temp.Push(deck.Pop());
139
140 /* Check if we accidentally finished a row */
141 pStack[i]->GetFaceDirection(&facedown);
142 faceup = temp.NumCards() - facedown;
143 if (faceup >= NUM_ONECOLOR_CARDS)
144 {
145 /* Check stack finished, remove cards if so */
146 if (stackLookingGood(temp, NUM_ONECOLOR_CARDS - 1))
147 {
148 int j;
149 for (j = 0; j < NUM_ONECOLOR_CARDS; j++)
150 {
151 temp.RemoveCard(0);
152 }
153 cardsFinished += NUM_ONECOLOR_CARDS;
154 pStack[i]->SetCardStack(temp);
155 /* Turn now topmost card */
156 TurnStackCard(*pStack[i]);
157 }
158 }
159 pStack[i]->SetCardStack(temp);
160 }
161 /* Remove one card from the fake ones */
162 pDeck->SetCardStack(fakeDeck.Pop(fakeDeck.NumCards() - 1));
163 }
164 pDeck->Update();
165 SpiderWnd.Redraw();
166 }
167
168 /* Cards dragged from a stack */
169 bool CARDLIBPROC StackDragProc(CardRegion &stackobj, int numDragCards)
170 {
171 int numfacedown, numcards;
172
173 stackobj.GetFaceDirection(&numfacedown);
174 numcards = stackobj.NumCards();
175
176 /* Only cards facing up */
177 if (numDragCards <= numcards - numfacedown)
178 {
179 const CardStack &mystack = stackobj.GetCardStack();
180 /* Don't allow to drag unsuited cards */
181 if (!stackLookingGood(mystack, numDragCards - 1))
182 {
183 return false;
184 }
185 /* Remember where the cards come from */
186 from = &stackobj;
187 return true;
188 }
189 else
190 {
191 return false;
192 }
193 }
194
195 /* Game finished successfully */
196 void GameFinished()
197 {
198 SpiderWnd.EmptyStacks();
199
200 MessageBox(SpiderWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
201 if( IDYES == MessageBox(SpiderWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
202 {
203 NewGame();
204 }
205 else
206 {
207 fGameStarted = false;
208 }
209 }
210
211 /* Card added, check for win situation */
212 void CARDLIBPROC StackAddProc(CardRegion &stackobj, const CardStack &added)
213 {
214 if (cardsFinished == NUM_SPIDER_CARDS)
215 {
216 GameFinished();
217 }
218 }
219
220 /* Cards dropped to a stack */
221 bool CARDLIBPROC StackDropProc(CardRegion &stackobj, CardStack &dragcards)
222 {
223 Card dragcard = dragcards[dragcards.NumCards() - 1];
224 int faceup, facedown;
225
226 /* Only drop our cards on other stacks */
227 if (stackobj.Id() == from->Id())
228 {
229 return false;
230 }
231
232 /* If stack is empty, everything can be dropped */
233 if (stackobj.NumCards() != 0)
234 {
235 const CardStack &mystack = stackobj.GetCardStack();
236
237 /* Can only drop if card is 1 less */
238 if (mystack[0].LoVal() != dragcard.LoVal() + 1)
239 {
240 return false;
241 }
242
243 /* Check if stack complete */
244 stackobj.GetFaceDirection(&facedown);
245 faceup = stackobj.NumCards() - facedown;
246
247 if (faceup + dragcards.NumCards() >= NUM_ONECOLOR_CARDS)
248 {
249 int i, max = NUM_ONECOLOR_CARDS - dragcards.NumCards() - 1;
250
251 /* Dragged cards have been checked to be in order, check stack cards */
252 if (mystack[0].Suit() == dragcard.Suit() &&
253 stackLookingGood(mystack, max))
254 {
255 CardStack s = stackobj.GetCardStack();
256 CardStack f;
257
258 /* Remove from card stack */
259 for (i = 0; i < max + 1; i++)
260 {
261 s.RemoveCard(0);
262 }
263 /* Remove dragged cards */
264 dragcards = f;
265 stackobj.SetCardStack(s);
266 cardsFinished += NUM_ONECOLOR_CARDS;
267 /* Flip top card of the dest stack */
268 TurnStackCard(stackobj);
269 }
270 }
271 }
272 /* Flip the top card of the source stack */
273 TurnStackCard(*from);
274 fGameStarted = true;
275 return true;
276 }
277
278 /* Create card regions */
279 void CreateSpider()
280 {
281 int i, pos;
282
283 /* 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 */
284 yRowStackCardOffset = (int)(__cardheight / 6.4);
285
286 pDeck = SpiderWnd.CreateRegion(0, true, 0, 0, -15, 0);
287 pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
288 pDeck->SetEmptyImage(CS_EI_CIRC);
289 pDeck->SetPlacement(CS_XJUST_RIGHT, CS_YJUST_BOTTOM, - X_BORDER, - Y_BORDER);
290 pDeck->SetDragRule(CS_DRAG_NONE, 0);
291 pDeck->SetDropRule(CS_DROP_NONE, 0);
292 pDeck->SetClickReleaseProc(DeckClickProc);
293
294 /* Create the row stacks */
295 for (i = 0; i < NUM_STACKS; i++)
296 {
297 pStack[i] = SpiderWnd.CreateRegion(NUM_STACKS+i, true, 0, Y_BORDER, 0, yRowStackCardOffset);
298 pStack[i]->SetFaceDirection(CS_FACE_DOWN, 0);
299 pos = i - NUM_STACKS/2;
300 pStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
301 pos * (__cardwidth + X_BORDER) + 6 * (X_BORDER + 1) + 3, 0);
302 pStack[i]->SetEmptyImage(CS_EI_SUNK);
303 pStack[i]->SetDragRule(CS_DRAG_CALLBACK, StackDragProc);
304 pStack[i]->SetDropRule(CS_DROP_CALLBACK, StackDropProc);
305 pStack[i]->SetAddCardProc(StackAddProc);
306 }
307 }
308