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