Merge trunk HEAD (46152)
[reactos.git] / base / applications / games / solitaire / solgame.cpp
1 #include <windows.h>
2 #include <commctrl.h>
3 #include <tchar.h>
4 #include <stdio.h>
5 #include "resource.h"
6 #include "cardlib.h"
7 #include "solitaire.h"
8
9 #if 1
10 #define TRACE(s)
11 #else
12 #define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
13 #endif
14
15 extern TCHAR MsgWin[128];
16 extern TCHAR MsgDeal[128];
17
18 CardStack activepile;
19 bool fGameStarted = false;
20
21 void NewGame(void)
22 {
23 TRACE("ENTER NewGame()\n");
24 int i, j;
25
26 SolWnd.EmptyStacks();
27
28 //create a new card-stack
29 CardStack deck;
30 deck.NewDeck();
31 deck.Shuffle();
32 activepile.Clear();
33
34 //deal to each row stack..
35 for(i = 0; i < NUM_ROW_STACKS; i++)
36 {
37 CardStack temp;
38 temp.Clear();
39
40 pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i);
41
42 for(j = 0; j <= i; j++)
43 {
44 temp.Push(deck.Pop());
45 }
46
47 pRowStack[i]->SetCardStack(temp);
48 }
49
50 //put the other cards onto the deck
51 pDeck->SetCardStack(deck);
52 pDeck->Update();
53
54 // For the 1-card-mode, all cards need to be completely overlapped
55 if(!(dwOptions & OPTION_THREE_CARDS))
56 pPile->SetOffsets(0, 0);
57
58 SolWnd.Redraw();
59
60 fGameStarted = false;
61 TRACE("EXIT NewGame()\n");
62 }
63
64 //
65 // Now follow the stack callback functions. This is where we
66 // provide the game functionality and rules
67 //
68
69 //
70 // Can only drag face-up cards
71 //
72 bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards)
73 {
74 TRACE("ENTER RowStackDragProc()\n");
75 int numfacedown;
76 int numcards;
77
78 stackobj.GetFaceDirection(&numfacedown);
79
80 numcards = stackobj.NumCards();
81
82 TRACE("EXIT RowStackDragProc()\n");
83 if(iNumDragCards <= numcards-numfacedown)
84 return true;
85 else
86 return false;
87
88 }
89
90 //
91 // Row a row-stack, we can only drop cards
92 // that are lower / different colour
93 //
94 bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards)
95 {
96 TRACE("ENTER RowStackDropProc()\n");
97 Card dragcard = dragcards[dragcards.NumCards() - 1];
98
99 //if we are empty, can only drop a stack with a King at bottom
100 if(stackobj.NumCards() == 0)
101 {
102 if(dragcard.LoVal() != 13)
103 {
104 TRACE("EXIT RowStackDropProc(false)\n");
105 return false;
106 }
107 }
108 else
109 {
110 const CardStack &mystack = stackobj.GetCardStack();
111
112 //can only drop if card is 1 less
113 if(mystack[0].LoVal() != dragcard.LoVal() + 1)
114 {
115 TRACE("EXIT RowStackDropProc(false)\n");
116 return false;
117 }
118
119 //can only drop if card is different colour
120 if( (mystack[0].IsBlack() && !dragcard.IsRed()) ||
121 (!mystack[0].IsBlack() && dragcard.IsRed()) )
122 {
123 TRACE("EXIT RowStackDropProc(false)\n");
124 return false;
125 }
126 }
127
128 fGameStarted = true;
129
130 TRACE("EXIT RowStackDropProc(true)\n");
131 return true;
132 }
133
134 //
135 // Can only drop a card onto a suit-stack if the
136 // card is 1 higher, and is the same suit
137 //
138 bool CanDrop(CardRegion &stackobj, Card card)
139 {
140 TRACE("ENTER CanDrop()\n");
141 int topval;
142
143 const CardStack &cardstack = stackobj.GetCardStack();
144
145 if(cardstack.NumCards() > 0)
146 {
147 if(card.Suit() != cardstack[0].Suit())
148 {
149 TRACE("EXIT CanDrop()\n");
150 return false;
151 }
152
153 topval = cardstack[0].LoVal();
154 }
155 else
156 {
157 topval = 0;
158 }
159
160 //make sure 1 higher
161 if(card.LoVal() != (topval + 1))
162 {
163 TRACE("EXIT CanDrop()\n");
164 return false;
165 }
166
167 TRACE("EXIT CanDrop()\n");
168 return true;
169 }
170
171 //
172 // Can only drop a card onto suit stack if it is same suit, and 1 higher
173 //
174 bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards)
175 {
176 TRACE("ENTER SuitStackDropProc()\n");
177 //only drop 1 card at a time
178 if(dragcards.NumCards() != 1)
179 {
180 TRACE("EXIT SuitStackDropProc()\n");
181 return false;
182 }
183
184 bool b = CanDrop(stackobj, dragcards[0]);
185 TRACE("EXIT SuitStackDropProc()\n");
186 return b;
187 }
188
189 //
190 // Single-click on one of the row-stacks
191 // Turn the top-card over if they are all face-down
192 //
193 void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked)
194 {
195 TRACE("ENTER RowStackClickProc()\n");
196 int numfacedown;
197
198 stackobj.GetFaceDirection(&numfacedown);
199
200 //if all face-down, then make top card face-up
201 if(stackobj.NumCards() == numfacedown)
202 {
203 if(numfacedown > 0) numfacedown--;
204 stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
205 stackobj.Redraw();
206 }
207 TRACE("EXIT RowStackClickProc()\n");
208 }
209
210 //
211 // Find the suit-stack that can accept the specified card
212 //
213 CardRegion *FindSuitStackFromCard(Card card)
214 {
215 TRACE("ENTER FindSuitStackFromCard()\n");
216 for(int i = 0; i < 4; i++)
217 {
218 if(CanDrop(*pSuitStack[i], card))
219 {
220 TRACE("EXIT FindSuitStackFromCard()\n");
221 return pSuitStack[i];
222 }
223 }
224
225 TRACE("EXIT FindSuitStackFromCard()\n");
226 return 0;
227 }
228
229 //
230 // What happens when we add a card to one of the suit stacks?
231 // Well, nothing (it is already added), but we need to
232 // check all four stacks (not just this one) to see if
233 // the game has finished.
234 //
235 void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added)
236 {
237 TRACE("ENTER SuitStackAddProc()\n");
238 bool fGameOver = true;
239
240 for(int i = 0; i < 4; i++)
241 {
242 if(pSuitStack[i]->NumCards() != 13)
243 {
244 fGameOver = false;
245 break;
246 }
247 }
248
249 if(fGameOver)
250 {
251 MessageBox(SolWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
252
253 for(int i = 0; i < 4; i++)
254 {
255 pSuitStack[i]->Flash(11, 100);
256 }
257
258 if( IDYES == MessageBox(SolWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
259 {
260 NewGame();
261 }
262 else
263 {
264 SolWnd.EmptyStacks();
265
266 fGameStarted = false;
267 }
268 }
269
270 TRACE("EXIT SuitStackAddProc()\n");
271 }
272
273 //
274 // Double-click on one of the row stacks
275 // The aim is to find a suit-stack to move the
276 // double-clicked card to.
277 //
278 void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked)
279 {
280 TRACE("ENTER RowStackDblClickProc()\n");
281 //can only move 1 card at a time
282 if(iNumClicked != 1)
283 {
284 TRACE("EXIT RowStackDblClickProc()\n");
285 return;
286 }
287
288 //find a suit-stack to move the card to...
289 const CardStack &cardstack = stackobj.GetCardStack();
290 CardRegion *pDest = FindSuitStackFromCard(cardstack[0]);
291
292 if(pDest != 0)
293 {
294 fGameStarted = true;
295
296 //stackobj.MoveCards(pDest, 1, true);
297 //use the SimulateDrag funcion, because we get the
298 //AddProc callbacks called for us on the destination stacks...
299 stackobj.SimulateDrag(pDest, 1, true);
300 }
301 TRACE("EXIT RowStackDblClickProc()\n");
302 }
303
304 //
305 // Face-up pile double-click
306 //
307 void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked)
308 {
309 TRACE("ENTER PileDblClickProc()\n");
310 RowStackDblClickProc(stackobj, iNumClicked);
311 TRACE("EXIT PileDblClickProc()\n");
312 }
313
314 //
315 // What happens when a card is removed from face-up pile?
316 //
317 void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems)
318 {
319 TRACE("ENTER PileRemoveProc()\n");
320 //modify our "virtual" pile by removing the same card
321 //that was removed from the physical card stack
322 activepile.Pop(iItems);
323
324 //if there is just 1 card left, then modify the
325 //stack to contain ALL the face-up cards..the effect
326 //will be, the next time a card is dragged, all the
327 //previous card-triplets will be available underneath
328 if(stackobj.NumCards() == 1)
329 {
330 stackobj.SetOffsets(0,0);
331 stackobj.SetCardStack(activepile);
332 }
333 TRACE("EXIT PileRemoveProc()\n");
334 }
335
336 //
337 // Double-click on the deck
338 // Move 3 cards to the face-up pile
339 //
340 void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked)
341 {
342 TRACE("ENTER DeckClickProc()\n");
343 CardStack cardstack = stackobj.GetCardStack();
344 CardStack pile = pPile->GetCardStack();
345
346 fGameStarted = true;
347
348 //reset the face-up pile to represent 3 cards
349 if(dwOptions & OPTION_THREE_CARDS)
350 pPile->SetOffsets(CS_DEFXOFF, 1);
351
352 if(cardstack.NumCards() == 0)
353 {
354 pile.Clear();
355
356 activepile.Reverse();
357 cardstack.Push(activepile);
358 activepile.Clear();
359 }
360 else
361 {
362 int numcards = min((dwOptions & OPTION_THREE_CARDS) ? 3 : 1, cardstack.NumCards());
363
364 //make a "visible" copy of these cards
365 CardStack temp;
366 temp = cardstack.Pop(numcards);
367 temp.Reverse();
368
369 if(dwOptions & OPTION_THREE_CARDS)
370 pile.Clear();
371
372 pile.Push(temp);
373
374 //remove the top 3 from deck
375 activepile.Push(temp);
376 }
377
378 activepile.Print();
379
380 pDeck->SetCardStack(cardstack);
381 pPile->SetCardStack(pile);
382
383 SolWnd.Redraw();
384 TRACE("EXIT DeckClickProc()\n");
385 }