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 function, 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 }
566