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