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