- Update to r53061
[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 "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 int i, j, facedown, faceup;
131
132 if (fakeDeck.NumCards() != 0 && deck.NumCards() != 0)
133 {
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 for (j = 0; j < NUM_ONECOLOR_CARDS; j++)
149 {
150 temp.RemoveCard(0);
151 }
152 cardsFinished += NUM_ONECOLOR_CARDS;
153 pStack[i]->SetCardStack(temp);
154 /* Turn now topmost card */
155 TurnStackCard(*pStack[i]);
156 }
157 }
158 pStack[i]->SetCardStack(temp);
159 }
160 /* Remove one card from the fake ones */
161 pDeck->SetCardStack(fakeDeck.Pop(fakeDeck.NumCards() - 1));
162 }
163 pDeck->Update();
164 SpiderWnd.Redraw();
165 }
166
167 /* Cards dragged from a stack */
168 bool CARDLIBPROC StackDragProc(CardRegion &stackobj, int numDragCards)
169 {
170 int numfacedown, numcards;
171
172 stackobj.GetFaceDirection(&numfacedown);
173 numcards = stackobj.NumCards();
174
175 /* Only cards facing up */
176 if (numDragCards <= numcards - numfacedown)
177 {
178 const CardStack &mystack = stackobj.GetCardStack();
179 /* Don't allow to drag unsuited cards */
180 if (!stackLookingGood(mystack, numDragCards - 1))
181 {
182 return false;
183 }
184 /* Remember where the cards come from */
185 from = &stackobj;
186 return true;
187 }
188 else
189 {
190 return false;
191 }
192 }
193
194 /* Game finished successfully */
195 void GameFinished()
196 {
197 SpiderWnd.EmptyStacks();
198
199 MessageBox(SpiderWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
200 if( IDYES == MessageBox(SpiderWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
201 {
202 NewGame();
203 }
204 else
205 {
206 fGameStarted = false;
207 }
208 }
209
210 /* Card added, check for win situation */
211 void CARDLIBPROC StackAddProc(CardRegion &stackobj, const CardStack &added)
212 {
213 if (cardsFinished == NUM_SPIDER_CARDS)
214 {
215 GameFinished();
216 }
217 }
218
219 /* Cards dropped to a stack */
220 bool CARDLIBPROC StackDropProc(CardRegion &stackobj, CardStack &dragcards)
221 {
222 Card dragcard = dragcards[dragcards.NumCards() - 1];
223 int faceup, facedown;
224
225 /* Only drop our cards on other stacks */
226 if (stackobj.Id() == from->Id())
227 {
228 return false;
229 }
230
231 /* If stack is empty, everything can be dropped */
232 if (stackobj.NumCards() != 0)
233 {
234 const CardStack &mystack = stackobj.GetCardStack();
235
236 /* Can only drop if card is 1 less */
237 if (mystack[0].LoVal() != dragcard.LoVal() + 1)
238 {
239 return false;
240 }
241
242 /* Check if stack complete */
243 stackobj.GetFaceDirection(&facedown);
244 faceup = stackobj.NumCards() - facedown;
245
246 if (faceup + dragcards.NumCards() >= NUM_ONECOLOR_CARDS)
247 {
248 int i, max = NUM_ONECOLOR_CARDS - dragcards.NumCards() - 1;
249
250 /* Dragged cards have been checked to be in order, check stack cards */
251 if (stackLookingGood(mystack, max))
252 {
253 CardStack s = stackobj.GetCardStack();
254 CardStack f;
255
256 /* Remove from card stack */
257 for (i = 0; i < max + 1; i++)
258 {
259 s.RemoveCard(0);
260 }
261 /* Remove dragged cards */
262 dragcards = f;
263 stackobj.SetCardStack(s);
264 cardsFinished += NUM_ONECOLOR_CARDS;
265 /* Flip top card of the dest stack */
266 TurnStackCard(stackobj);
267 }
268 }
269 }
270 /* Flip the top card of the source stack */
271 TurnStackCard(*from);
272 fGameStarted = true;
273 return true;
274 }
275
276 /* Create card regions */
277 void CreateSpider()
278 {
279 int i, pos;
280
281 /* Compute the value for yRowStackCardOffset based on the height of the card, so the card number isn't hidden on larger cards */
282 yRowStackCardOffset = (int)(__cardheight / 6.7);
283
284 pDeck = SpiderWnd.CreateRegion(0, true, 0, 0, -15, 0);
285 pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
286 pDeck->SetEmptyImage(CS_EI_CIRC);
287 pDeck->SetPlacement(CS_XJUST_RIGHT, CS_YJUST_BOTTOM, - X_BORDER, - Y_BORDER);
288 pDeck->SetDragRule(CS_DRAG_NONE, 0);
289 pDeck->SetDropRule(CS_DROP_NONE, 0);
290 pDeck->SetClickReleaseProc(DeckClickProc);
291
292 /* Create the row stacks */
293 for (i = 0; i < NUM_STACKS; i++)
294 {
295 pStack[i] = SpiderWnd.CreateRegion(NUM_STACKS+i, true, 0, Y_BORDER, 0, yRowStackCardOffset);
296 pStack[i]->SetFaceDirection(CS_FACE_DOWN, 0);
297 pos = i - NUM_STACKS/2;
298 pStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
299 pos * (__cardwidth + X_BORDER) + 6 * X_BORDER, 0);
300 pStack[i]->SetEmptyImage(CS_EI_SUNK);
301 pStack[i]->SetDragRule(CS_DRAG_CALLBACK, StackDragProc);
302 pStack[i]->SetDropRule(CS_DROP_CALLBACK, StackDropProc);
303 pStack[i]->SetAddCardProc(StackAddProc);
304 }
305 }
306