[BTRFS]
[reactos.git] / base / applications / games / solitaire / solgame.cpp
1 #include "solitaire.h"
2
3 #if 1
4 #define TRACE(s)
5 #else
6 #define TRACE(s) printf("%s(%i): %s",__FILE__,__LINE__,s)
7 #endif
8
9 extern TCHAR MsgWin[128];
10 extern TCHAR MsgDeal[128];
11
12 CardStack activepile;
13 int LastId;
14 bool fGameStarted = false;
15 bool bAutoroute = false;
16
17 void NewGame(void)
18 {
19 TRACE("ENTER NewGame()\n");
20 int i, j;
21
22 if (GetScoreMode() == SCORE_VEGAS)
23 {
24 if ((dwOptions & OPTION_KEEP_SCORE) && (dwPrevMode == SCORE_VEGAS))
25 lScore = lScore - 52;
26 else
27 lScore = -52;
28
29 if (dwOptions & OPTION_THREE_CARDS)
30 dwWasteTreshold = 2;
31 else
32 dwWasteTreshold = 0;
33
34 }
35 else
36 {
37 if (dwOptions & OPTION_THREE_CARDS)
38 dwWasteTreshold = 3;
39 else
40 dwWasteTreshold = 0;
41
42 lScore = 0;
43 }
44
45 dwTime = 0;
46 dwWasteCount = 0;
47 LastId = 0;
48
49 SolWnd.EmptyStacks();
50
51 //create a new card-stack
52 CardStack deck;
53 deck.NewDeck();
54 deck.Shuffle();
55 activepile.Clear();
56
57 //deal to each row stack..
58 for(i = 0; i < NUM_ROW_STACKS; i++)
59 {
60 CardStack temp;
61 temp.Clear();
62
63 pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i);
64
65 for(j = 0; j <= i; j++)
66 {
67 temp.Push(deck.Pop());
68 }
69
70 pRowStack[i]->SetCardStack(temp);
71 }
72
73 //put the other cards onto the deck
74 pDeck->SetCardStack(deck);
75 pDeck->Update();
76
77 // For the 1-card-mode, all cards need to be completely overlapped
78 if(!(dwOptions & OPTION_THREE_CARDS))
79 pPile->SetOffsets(0, 0);
80
81 SolWnd.Redraw();
82
83 fGameStarted = false;
84
85 dwPrevMode = GetScoreMode();
86
87 UpdateStatusBar();
88
89 TRACE("EXIT NewGame()\n");
90
91 }
92
93 //
94 // Now follow the stack callback functions. This is where we
95 // provide the game functionality and rules
96 //
97
98 //
99 // Can only drag face-up cards
100 //
101 bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards)
102 {
103 TRACE("ENTER RowStackDragProc()\n");
104 int numfacedown;
105 int numcards;
106
107 SetPlayTimer();
108
109 stackobj.GetFaceDirection(&numfacedown);
110
111 numcards = stackobj.NumCards();
112
113 TRACE("EXIT RowStackDragProc()\n");
114 if(iNumDragCards <= numcards-numfacedown)
115 return true;
116 else
117 return false;
118
119 }
120
121 //
122 // Row a row-stack, we can only drop cards
123 // that are lower / different colour
124 //
125 bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards)
126 {
127 TRACE("ENTER RowStackDropProc()\n");
128 Card dragcard = dragcards[dragcards.NumCards() - 1];
129
130 SetPlayTimer();
131
132 //if we are empty, can only drop a stack with a King at bottom
133 if(stackobj.NumCards() == 0)
134 {
135 if(dragcard.LoVal() != 13)
136 {
137 TRACE("EXIT RowStackDropProc(false)\n");
138 return false;
139 }
140 }
141 else
142 {
143 const CardStack &mystack = stackobj.GetCardStack();
144
145 //can only drop if card is 1 less
146 if(mystack[0].LoVal() != dragcard.LoVal() + 1)
147 {
148 TRACE("EXIT RowStackDropProc(false)\n");
149 return false;
150 }
151
152 //can only drop if card is different colour
153 if( (mystack[0].IsBlack() && !dragcard.IsRed()) ||
154 (!mystack[0].IsBlack() && dragcard.IsRed()) )
155 {
156 TRACE("EXIT RowStackDropProc(false)\n");
157 return false;
158 }
159 }
160
161 fGameStarted = true;
162
163 if (LastId == PILE_ID)
164 {
165 if (GetScoreMode() == SCORE_STD)
166 {
167 lScore = lScore + 5;
168 }
169 }
170 else if ((LastId >= SUIT_ID) && (LastId <= SUIT_ID + 3))
171 {
172 if (GetScoreMode() == SCORE_STD)
173 {
174 lScore = lScore >= 15 ? lScore - 15 : 0;
175 }
176 else if (GetScoreMode() == SCORE_VEGAS)
177 {
178 lScore = lScore >= -47 ? lScore - 5 : -52;
179 }
180 }
181
182 UpdateStatusBar();
183
184 TRACE("EXIT RowStackDropProc(true)\n");
185 return true;
186 }
187
188 //
189 // Can only drop a card onto a suit-stack if the
190 // card is 1 higher, and is the same suit
191 //
192 bool CanDrop(CardRegion &stackobj, Card card)
193 {
194 TRACE("ENTER CanDrop()\n");
195 int topval;
196
197 const CardStack &cardstack = stackobj.GetCardStack();
198
199 SetPlayTimer();
200
201 if(cardstack.NumCards() > 0)
202 {
203 if(card.Suit() != cardstack[0].Suit())
204 {
205 TRACE("EXIT CanDrop()\n");
206 return false;
207 }
208
209 topval = cardstack[0].LoVal();
210 }
211 else
212 {
213 topval = 0;
214 }
215
216 //make sure 1 higher
217 if(card.LoVal() != (topval + 1))
218 {
219 TRACE("EXIT CanDrop()\n");
220 return false;
221 }
222
223 TRACE("EXIT CanDrop()\n");
224 return true;
225 }
226
227 //
228 // Can only drop a card onto suit stack if it is same suit, and 1 higher
229 //
230 bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards)
231 {
232 TRACE("ENTER SuitStackDropProc()\n");
233
234 SetPlayTimer();
235
236 //only drop 1 card at a time
237 if (!bAutoroute && dragcards.NumCards() != 1)
238 {
239 TRACE("EXIT SuitStackDropProc()\n");
240 return false;
241 }
242
243 bool b = CanDrop(stackobj, dragcards[0]);
244 TRACE("EXIT SuitStackDropProc()\n");
245
246 if (b)
247 {
248 if ((LastId == PILE_ID) || (LastId >= ROW_ID))
249 {
250 if (GetScoreMode() == SCORE_VEGAS)
251 {
252 lScore = lScore + 5;
253 }
254 else if (GetScoreMode() == SCORE_STD)
255 {
256 lScore = lScore + 10;
257 }
258
259 UpdateStatusBar();
260 }
261 }
262
263 return b;
264 }
265
266 //
267 // Single-click on one of the suit-stacks
268 //
269 void CARDLIBPROC SuitStackClickProc(CardRegion &stackobj, int iNumClicked)
270 {
271 TRACE("ENTER SuitStackClickProc()\n");
272
273 fGameStarted = true;
274
275 LastId = stackobj.Id();
276
277 TRACE("EXIT SuitStackClickProc()\n");
278 }
279
280 //
281 // Single-click on one of the row-stacks
282 // Turn the top-card over if they are all face-down
283 //
284 void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked)
285 {
286 TRACE("ENTER RowStackClickProc()\n");
287 int numfacedown;
288
289 stackobj.GetFaceDirection(&numfacedown);
290
291 //if all face-down, then make top card face-up
292 if(stackobj.NumCards() == numfacedown)
293 {
294 if(numfacedown > 0) numfacedown--;
295 stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
296 stackobj.Redraw();
297
298 if (GetScoreMode() == SCORE_STD)
299 {
300 lScore = lScore + 5;
301 UpdateStatusBar();
302 }
303 }
304
305 LastId = stackobj.Id();
306
307 fGameStarted = true;
308
309 TRACE("EXIT RowStackClickProc()\n");
310 }
311
312 //
313 // Find the suit-stack that can accept the specified card
314 //
315 CardRegion *FindSuitStackFromCard(Card card)
316 {
317 TRACE("ENTER FindSuitStackFromCard()\n");
318
319 for(int i = 0; i < 4; i++)
320 {
321 if(CanDrop(*pSuitStack[i], card))
322 {
323 TRACE("EXIT FindSuitStackFromCard()\n");
324 return pSuitStack[i];
325 }
326 }
327
328 TRACE("EXIT FindSuitStackFromCard()\n");
329 return 0;
330 }
331
332 //
333 // What happens when we add a card to one of the suit stacks?
334 // Well, nothing (it is already added), but we need to
335 // check all four stacks (not just this one) to see if
336 // the game has finished.
337 //
338 void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added)
339 {
340 TRACE("ENTER SuitStackAddProc()\n");
341 bool fGameOver = true;
342
343 SetPlayTimer();
344
345 for(int i = 0; i < 4; i++)
346 {
347 if(pSuitStack[i]->NumCards() != 13)
348 {
349 fGameOver = false;
350
351 break;
352 }
353 }
354
355 if(fGameOver)
356 {
357 KillTimer(hwndMain, IDT_PLAYTIMER);
358 PlayTimer = 0;
359
360 if ((dwOptions & OPTION_SHOW_TIME) && (GetScoreMode() == SCORE_STD))
361 {
362 lScore = lScore + (700000 / dwTime);
363 }
364
365 UpdateStatusBar();
366
367 MessageBox(SolWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
368
369 for(int i = 0; i < 4; i++)
370 {
371 pSuitStack[i]->Flash(11, 100);
372 }
373
374 if( IDYES == MessageBox(SolWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
375 {
376 NewGame();
377 }
378 else
379 {
380 SolWnd.EmptyStacks();
381
382 fGameStarted = false;
383 }
384 }
385
386 TRACE("EXIT SuitStackAddProc()\n");
387 }
388
389 //
390 // Double-click on one of the row stacks
391 // The aim is to find a suit-stack to move the
392 // double-clicked card to.
393 //
394 void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked)
395 {
396 TRACE("ENTER RowStackDblClickProc()\n");
397
398 SetPlayTimer();
399
400 //can only move 1 card at a time
401 if(iNumClicked != 1)
402 {
403 TRACE("EXIT RowStackDblClickProc()\n");
404 return;
405 }
406
407 //find a suit-stack to move the card to...
408 const CardStack &cardstack = stackobj.GetCardStack();
409 CardRegion *pDest = FindSuitStackFromCard(cardstack[0]);
410
411 if(pDest != 0)
412 {
413 fGameStarted = true;
414 SetPlayTimer();
415
416 //stackobj.MoveCards(pDest, 1, true);
417 //use the SimulateDrag funcion, because we get the
418 //AddProc callbacks called for us on the destination stacks...
419 bAutoroute = true;
420 stackobj.SimulateDrag(pDest, 1, true);
421 bAutoroute = false;
422 }
423 TRACE("EXIT RowStackDblClickProc()\n");
424 }
425
426 //
427 // Face-up pile single-click
428 //
429 void CARDLIBPROC PileClickProc(CardRegion &stackobj, int iNumClicked)
430 {
431 TRACE("ENTER SuitStackClickProc()\n");
432
433 fGameStarted = true;
434
435 LastId = stackobj.Id();
436
437 TRACE("EXIT SuitStackClickProc()\n");
438 }
439
440 //
441 // Face-up pile double-click
442 //
443 void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked)
444 {
445 TRACE("ENTER PileDblClickProc()\n");
446
447 SetPlayTimer();
448
449 RowStackDblClickProc(stackobj, iNumClicked);
450 TRACE("EXIT PileDblClickProc()\n");
451 }
452
453 //
454 // What happens when a card is removed from face-up pile?
455 //
456 void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems)
457 {
458 TRACE("ENTER PileRemoveProc()\n");
459
460 SetPlayTimer();
461
462 //modify our "virtual" pile by removing the same card
463 //that was removed from the physical card stack
464 activepile.Pop(iItems);
465
466 //if there is just 1 card left, then modify the
467 //stack to contain ALL the face-up cards..the effect
468 //will be, the next time a card is dragged, all the
469 //previous card-triplets will be available underneath
470 if(stackobj.NumCards() == 1)
471 {
472 stackobj.SetOffsets(0,0);
473 stackobj.SetCardStack(activepile);
474 }
475 TRACE("EXIT PileRemoveProc()\n");
476 }
477
478 //
479 // Double-click on the deck
480 // Move 3 cards to the face-up pile
481 //
482 void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked)
483 {
484 TRACE("ENTER DeckClickProc()\n");
485
486 SetPlayTimer();
487
488 CardStack cardstack = stackobj.GetCardStack();
489 CardStack pile = pPile->GetCardStack();
490
491 fGameStarted = true;
492 SetPlayTimer();
493
494 //reset the face-up pile to represent 3 cards
495 if(dwOptions & OPTION_THREE_CARDS)
496 pPile->SetOffsets(CS_DEFXOFF, 1);
497
498 if(cardstack.NumCards() == 0)
499 {
500 if (GetScoreMode() == SCORE_VEGAS)
501 {
502 if (dwWasteCount < dwWasteTreshold)
503 {
504 pile.Clear();
505
506 activepile.Reverse();
507 cardstack.Push(activepile);
508 activepile.Clear();
509 }
510 }
511 else if (GetScoreMode() == SCORE_STD)
512 {
513 if ((dwWasteCount >= dwWasteTreshold) && (activepile.NumCards() != 0))
514 {
515 if (dwOptions & OPTION_THREE_CARDS)
516 lScore = lScore >= 20 ? lScore - 20 : 0;
517 else
518 lScore = lScore >= 100 ? lScore - 100 : 0;
519 }
520
521 pile.Clear();
522
523 activepile.Reverse();
524 cardstack.Push(activepile);
525 activepile.Clear();
526
527 UpdateStatusBar();
528 }
529 else
530 {
531 pile.Clear();
532
533 activepile.Reverse();
534 cardstack.Push(activepile);
535 activepile.Clear();
536 }
537
538 dwWasteCount++;
539 }
540 else
541 {
542 int numcards = min((dwOptions & OPTION_THREE_CARDS) ? 3 : 1, cardstack.NumCards());
543
544 //make a "visible" copy of these cards
545 CardStack temp;
546 temp = cardstack.Pop(numcards);
547 temp.Reverse();
548
549 if(dwOptions & OPTION_THREE_CARDS)
550 pile.Clear();
551
552 pile.Push(temp);
553
554 //remove the top 3 from deck
555 activepile.Push(temp);
556 }
557
558 activepile.Print();
559
560 pDeck->SetCardStack(cardstack);
561 pPile->SetCardStack(pile);
562
563 SolWnd.Redraw();
564 TRACE("EXIT DeckClickProc()\n");
565 }