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