- Create another branch for networking fixes
[reactos.git] / base / applications / games / spider / spigame.cpp
1 /*
2 * PROJECT: Spider Solitaire
3 * LICENSE: See COPYING in top level directory
4 * FILE: base/applications/games/spider/spigame.cpp
5 * PURPOSE: Spider Solitaire game functions
6 * PROGRAMMER: Gregor Schneider
7 */
8
9 #include <windows.h>
10 #include <commctrl.h>
11 #include <tchar.h>
12 #include <stdio.h>
13
14 #include "resource.h"
15 #include "cardlib.h"
16 #include "spider.h"
17
18 #define NUM_DECK_CARDS 5
19 #define NUM_SMALLER_STACKS 4
20 #define NUM_CARD_COLORS 4
21 #define NUM_ONECOLOR_CARDS 13
22 #define NUM_STD_CARDS 52
23 #define NUM_SPIDER_CARDS 104
24
25 CardStack deck;
26 CardRegion *from;
27 CardRegion *pDeck;
28 CardRegion *pStack[NUM_STACKS];
29 bool fGameStarted = false;
30 int yRowStackCardOffset;
31 int cardsFinished;
32 extern TCHAR MsgDeal[];
33 extern TCHAR MsgWin[];
34
35 CardStack CreatePlayDeck()
36 {
37 CardStack newStack;
38 int i, colors = 1, num = 0;
39
40 switch (dwDifficulty)
41 {
42 case IDC_DIF_ONECOLOR:
43 colors = 1;
44 break;
45 case IDC_DIF_TWOCOLORS:
46 colors = 2;
47 break;
48 case IDC_DIF_FOURCOLORS:
49 colors = 4;
50 break;
51 }
52 for (i = 0; i < NUM_SPIDER_CARDS; i++)
53 {
54 num += NUM_CARD_COLORS / colors;
55 Card newCard(num % NUM_STD_CARDS);
56 newStack.Push(newCard);
57 }
58 return newStack;
59 }
60
61 void NewGame(void)
62 {
63 int i, j;
64 /* First four stack with five, all other with 4 */
65 int covCards = 5;
66 CardStack fakeDeck, temp;
67
68 SpiderWnd.EmptyStacks();
69
70 /* Create a new card-deck, fake deck */
71 deck = CreatePlayDeck();
72 deck.Shuffle();
73 fakeDeck.NewDeck();
74 fakeDeck.Shuffle();
75
76 /* Reset progress value */
77 cardsFinished = 0;
78
79 /* Deal to each stack */
80 for (i = 0; i < NUM_STACKS; i++)
81 {
82 temp.Clear();
83 if (i == NUM_SMALLER_STACKS)
84 {
85 covCards--;
86 }
87 for (j = 0; j <= covCards; j++)
88 {
89 temp.Push(deck.Pop(1));
90 }
91 pStack[i]->SetFaceDirection(CS_FACE_DOWNUP, covCards);
92 pStack[i]->SetCardStack(temp);
93 }
94 /* Deal five fake cards to the deck */
95 pDeck->SetCardStack(fakeDeck.Pop(5));
96
97 SpiderWnd.Redraw();
98 fGameStarted = false;
99 }
100
101 bool stackLookingGood(const CardStack &mystack, int numChecks)
102 {
103 int i;
104 for (i = 0; i < numChecks; i++)
105 {
106 if (mystack[i].LoVal() != mystack[i + 1].LoVal() - 1)
107 {
108 return false;
109 }
110 if (mystack[i].Suit() != mystack[i + 1].Suit())
111 {
112 return false;
113 }
114 }
115 return true;
116 }
117
118 /* Card to be turned from a stack */
119 void TurnStackCard(CardRegion &stackobj)
120 {
121 int numfacedown;
122
123 stackobj.GetFaceDirection(&numfacedown);
124 if (stackobj.NumCards() <= numfacedown)
125 {
126 if (numfacedown > 0) numfacedown--;
127 stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown);
128 stackobj.Redraw();
129 }
130 }
131
132 /* Click on the deck */
133 void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int NumDragCards)
134 {
135 CardStack temp, fakeDeck = pDeck->GetCardStack();
136 fGameStarted = true;
137 int i, j, facedown, faceup;
138
139 if (fakeDeck.NumCards() != 0 && deck.NumCards() != 0)
140 {
141 /* Add one card to every stack */
142 for (i = 0; i < NUM_STACKS; i++)
143 {
144 temp = pStack[i]->GetCardStack();
145 temp.Push(deck.Pop());
146
147 /* Check if we accidentally finished a row */
148 pStack[i]->GetFaceDirection(&facedown);
149 faceup = temp.NumCards() - facedown;
150 if (faceup >= NUM_ONECOLOR_CARDS)
151 {
152 /* Check stack finished, remove cards if so */
153 if (stackLookingGood(temp, NUM_ONECOLOR_CARDS - 1))
154 {
155 for (j = 0; j < NUM_ONECOLOR_CARDS; j++)
156 {
157 temp.RemoveCard(0);
158 }
159 cardsFinished += NUM_ONECOLOR_CARDS;
160 pStack[i]->SetCardStack(temp);
161 /* Turn now topmost card */
162 TurnStackCard(*pStack[i]);
163 }
164 }
165 pStack[i]->SetCardStack(temp);
166 }
167 /* Remove one card from the fake ones */
168 pDeck->SetCardStack(fakeDeck.Pop(fakeDeck.NumCards() - 1));
169 }
170 pDeck->Update();
171 SpiderWnd.Redraw();
172 }
173
174 /* Cards dragged from a stack */
175 bool CARDLIBPROC StackDragProc(CardRegion &stackobj, int numDragCards)
176 {
177 int numfacedown, numcards;
178
179 stackobj.GetFaceDirection(&numfacedown);
180 numcards = stackobj.NumCards();
181
182 /* Only cards facing up */
183 if (numDragCards <= numcards - numfacedown)
184 {
185 const CardStack &mystack = stackobj.GetCardStack();
186 /* Don't allow to drag unsuited cards */
187 if (!stackLookingGood(mystack, numDragCards - 1))
188 {
189 return false;
190 }
191 /* Remember where the cards come from */
192 from = &stackobj;
193 return true;
194 }
195 else
196 {
197 return false;
198 }
199 }
200
201 /* Game finished successfully */
202 void GameFinished()
203 {
204 MessageBox(SpiderWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION);
205 if( IDYES == MessageBox(SpiderWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) )
206 {
207 NewGame();
208 }
209 else
210 {
211 SpiderWnd.EmptyStacks();
212 fGameStarted = false;
213 }
214 }
215
216 /* Card added, check for win situation */
217 void CARDLIBPROC StackAddProc(CardRegion &stackobj, const CardStack &added)
218 {
219 if (cardsFinished == NUM_SPIDER_CARDS)
220 {
221 GameFinished();
222 }
223 }
224
225 /* Cards dropped to a stack */
226 bool CARDLIBPROC StackDropProc(CardRegion &stackobj, CardStack &dragcards)
227 {
228 Card dragcard = dragcards[dragcards.NumCards() - 1];
229 int faceup, facedown;
230
231 /* Only drop our cards on other stacks */
232 if (stackobj.Id() == from->Id())
233 {
234 return false;
235 }
236
237 /* If stack is empty, everything can be dropped */
238 if (stackobj.NumCards() != 0)
239 {
240 const CardStack &mystack = stackobj.GetCardStack();
241
242 /* Can only drop if card is 1 less */
243 if (mystack[0].LoVal() != dragcard.LoVal() + 1)
244 {
245 return false;
246 }
247
248 /* Check if stack complete */
249 stackobj.GetFaceDirection(&facedown);
250 faceup = stackobj.NumCards() - facedown;
251
252 if (faceup + dragcards.NumCards() >= NUM_ONECOLOR_CARDS)
253 {
254 int i, max = NUM_ONECOLOR_CARDS - dragcards.NumCards() - 1;
255
256 /* Dragged cards have been checked to be in order, check stack cards */
257 if (stackLookingGood(mystack, max))
258 {
259 CardStack s = stackobj.GetCardStack();
260 CardStack f;
261
262 /* Remove from card stack */
263 for (i = 0; i < max + 1; i++)
264 {
265 s.RemoveCard(0);
266 }
267 /* Remove dragged cards */
268 dragcards = f;
269 stackobj.SetCardStack(s);
270 cardsFinished += NUM_ONECOLOR_CARDS;
271 /* Flip top card of the dest stack */
272 TurnStackCard(stackobj);
273 }
274 }
275 }
276 /* Flip the top card of the source stack */
277 TurnStackCard(*from);
278 fGameStarted = true;
279 return true;
280 }
281
282 /* Create card regions */
283 void CreateSpider()
284 {
285 int i, pos;
286
287 /* Compute the value for yRowStackCardOffset based on the height of the card, so the card number isn't hidden on larger cards */
288 yRowStackCardOffset = (int)(__cardheight / 6.7);
289
290 pDeck = SpiderWnd.CreateRegion(0, true, 0, 0, -15, 0);
291 pDeck->SetFaceDirection(CS_FACE_DOWN, 0);
292 pDeck->SetEmptyImage(CS_EI_CIRC);
293 pDeck->SetPlacement(CS_XJUST_RIGHT, CS_YJUST_BOTTOM, - X_BORDER, - Y_BORDER);
294 pDeck->SetDragRule(CS_DRAG_NONE, 0);
295 pDeck->SetDropRule(CS_DROP_NONE, 0);
296 pDeck->SetClickProc(DeckClickProc);
297 pDeck->SetDblClickProc(DeckClickProc);
298
299 /* Create the row stacks */
300 for (i = 0; i < NUM_STACKS; i++)
301 {
302 pStack[i] = SpiderWnd.CreateRegion(NUM_STACKS+i, true, 0, Y_BORDER, 0, yRowStackCardOffset);
303 pStack[i]->SetFaceDirection(CS_FACE_DOWN, 0);
304 pos = i - NUM_STACKS/2;
305 pStack[i]->SetPlacement(CS_XJUST_CENTER, 0,
306 pos * (__cardwidth + X_BORDER) + 6 * X_BORDER, 0);
307 pStack[i]->SetEmptyImage(CS_EI_SUNK);
308 pStack[i]->SetDragRule(CS_DRAG_CALLBACK, StackDragProc);
309 pStack[i]->SetDropRule(CS_DROP_CALLBACK, StackDropProc);
310 pStack[i]->SetAddCardProc(StackAddProc);
311 }
312 }
313