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