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 VisiblePileCards; 14 int LastId; 15 bool fGameStarted = false; 16 bool bAutoroute = false; 17 18 void NewGame(void) 19 { 20 TRACE("ENTER NewGame()\n"); 21 int i, j; 22 23 if (GetScoreMode() == SCORE_VEGAS) 24 { 25 if ((dwOptions & OPTION_KEEP_SCORE) && (dwPrevMode == SCORE_VEGAS)) 26 lScore = lScore - 52; 27 else 28 lScore = -52; 29 30 if (dwOptions & OPTION_THREE_CARDS) 31 dwWasteTreshold = 2; 32 else 33 dwWasteTreshold = 0; 34 35 } 36 else 37 { 38 if (dwOptions & OPTION_THREE_CARDS) 39 dwWasteTreshold = 3; 40 else 41 dwWasteTreshold = 0; 42 43 lScore = 0; 44 } 45 46 dwTime = 0; 47 dwWasteCount = 0; 48 LastId = 0; 49 50 SolWnd.EmptyStacks(); 51 52 //create a new card-stack 53 CardStack deck; 54 deck.NewDeck(); 55 deck.Shuffle(); 56 activepile.Clear(); 57 VisiblePileCards = 0; 58 59 //deal to each row stack.. 60 for(i = 0; i < NUM_ROW_STACKS; i++) 61 { 62 CardStack temp; 63 temp.Clear(); 64 65 pRowStack[i]->SetFaceDirection(CS_FACE_DOWNUP, i); 66 67 for(j = 0; j <= i; j++) 68 { 69 temp.Push(deck.Pop()); 70 } 71 72 pRowStack[i]->SetCardStack(temp); 73 } 74 75 //put the other cards onto the deck 76 pDeck->SetCardStack(deck); 77 pDeck->Update(); 78 79 // For the 1-card-mode, all cards need to be completely overlapped 80 if(!(dwOptions & OPTION_THREE_CARDS)) 81 pPile->SetOffsets(0, 0); 82 83 SolWnd.Redraw(); 84 85 fGameStarted = false; 86 87 dwPrevMode = GetScoreMode(); 88 89 UpdateStatusBar(); 90 ClearUndo(); 91 92 TRACE("EXIT NewGame()\n"); 93 94 } 95 96 // 97 // Now follow the stack callback functions. This is where we 98 // provide the game functionality and rules 99 // 100 101 // 102 // Can only drag face-up cards 103 // 104 bool CARDLIBPROC RowStackDragProc(CardRegion &stackobj, int iNumDragCards) 105 { 106 TRACE("ENTER RowStackDragProc()\n"); 107 int numfacedown; 108 int numcards; 109 110 SetPlayTimer(); 111 112 stackobj.GetFaceDirection(&numfacedown); 113 114 numcards = stackobj.NumCards(); 115 116 TRACE("EXIT RowStackDragProc()\n"); 117 if(iNumDragCards <= numcards-numfacedown) 118 return true; 119 else 120 return false; 121 122 } 123 124 // 125 // Row a row-stack, we can only drop cards 126 // that are lower / different colour 127 // 128 bool CARDLIBPROC RowStackDropProc(CardRegion &stackobj, CardStack &dragcards) 129 { 130 TRACE("ENTER RowStackDropProc()\n"); 131 Card dragcard = dragcards[dragcards.NumCards() - 1]; 132 133 SetPlayTimer(); 134 135 //if we are empty, can only drop a stack with a King at bottom 136 if(stackobj.NumCards() == 0) 137 { 138 if(dragcard.LoVal() != 13) 139 { 140 TRACE("EXIT RowStackDropProc(false)\n"); 141 return false; 142 } 143 } 144 else 145 { 146 const CardStack &mystack = stackobj.GetCardStack(); 147 148 //can only drop if card is 1 less 149 if(mystack[0].LoVal() != dragcard.LoVal() + 1) 150 { 151 TRACE("EXIT RowStackDropProc(false)\n"); 152 return false; 153 } 154 155 //can only drop if card is different colour 156 if( (mystack[0].IsBlack() && !dragcard.IsRed()) || 157 (!mystack[0].IsBlack() && dragcard.IsRed()) ) 158 { 159 TRACE("EXIT RowStackDropProc(false)\n"); 160 return false; 161 } 162 } 163 164 fGameStarted = true; 165 166 SetUndo(LastId, stackobj.Id(), dragcards.NumCards(), lScore, VisiblePileCards); 167 168 if (LastId == PILE_ID) 169 { 170 if (GetScoreMode() == SCORE_STD) 171 { 172 lScore = lScore + 5; 173 } 174 } 175 else if ((LastId >= SUIT_ID) && (LastId <= SUIT_ID + 3)) 176 { 177 if (GetScoreMode() == SCORE_STD) 178 { 179 lScore = lScore >= 15 ? lScore - 15 : 0; 180 } 181 else if (GetScoreMode() == SCORE_VEGAS) 182 { 183 lScore = lScore >= -47 ? lScore - 5 : -52; 184 } 185 } 186 187 UpdateStatusBar(); 188 189 TRACE("EXIT RowStackDropProc(true)\n"); 190 return true; 191 } 192 193 // 194 // Can only drop a card onto a suit-stack if the 195 // card is 1 higher, and is the same suit 196 // 197 bool CanDrop(CardRegion &stackobj, Card card) 198 { 199 TRACE("ENTER CanDrop()\n"); 200 int topval; 201 202 const CardStack &cardstack = stackobj.GetCardStack(); 203 204 SetPlayTimer(); 205 206 if(cardstack.NumCards() > 0) 207 { 208 if(card.Suit() != cardstack[0].Suit()) 209 { 210 TRACE("EXIT CanDrop()\n"); 211 return false; 212 } 213 214 topval = cardstack[0].LoVal(); 215 } 216 else 217 { 218 topval = 0; 219 } 220 221 //make sure 1 higher 222 if(card.LoVal() != (topval + 1)) 223 { 224 TRACE("EXIT CanDrop()\n"); 225 return false; 226 } 227 228 TRACE("EXIT CanDrop()\n"); 229 return true; 230 } 231 232 // 233 // Can only drop a card onto suit stack if it is same suit, and 1 higher 234 // 235 bool CARDLIBPROC SuitStackDropProc(CardRegion &stackobj, CardStack &dragcards) 236 { 237 TRACE("ENTER SuitStackDropProc()\n"); 238 239 SetPlayTimer(); 240 241 //only drop 1 card at a time 242 if (!bAutoroute && dragcards.NumCards() != 1) 243 { 244 TRACE("EXIT SuitStackDropProc()\n"); 245 return false; 246 } 247 248 bool b = CanDrop(stackobj, dragcards[0]); 249 TRACE("EXIT SuitStackDropProc()\n"); 250 251 if (b) 252 { 253 SetUndo(LastId, stackobj.Id(), 1, lScore, VisiblePileCards); 254 255 if ((LastId == PILE_ID) || (LastId >= ROW_ID)) 256 { 257 if (GetScoreMode() == SCORE_VEGAS) 258 { 259 lScore = lScore + 5; 260 } 261 else if (GetScoreMode() == SCORE_STD) 262 { 263 lScore = lScore + 10; 264 } 265 266 UpdateStatusBar(); 267 } 268 } 269 270 return b; 271 } 272 273 // 274 // Single-click on one of the suit-stacks 275 // 276 void CARDLIBPROC SuitStackClickProc(CardRegion &stackobj, int iNumClicked) 277 { 278 TRACE("ENTER SuitStackClickProc()\n"); 279 280 fGameStarted = true; 281 282 LastId = stackobj.Id(); 283 284 TRACE("EXIT SuitStackClickProc()\n"); 285 } 286 287 // 288 // Single-click on one of the row-stacks 289 // Turn the top-card over if they are all face-down 290 // 291 void CARDLIBPROC RowStackClickProc(CardRegion &stackobj, int iNumClicked) 292 { 293 TRACE("ENTER RowStackClickProc()\n"); 294 int numfacedown; 295 296 stackobj.GetFaceDirection(&numfacedown); 297 298 //if all face-down, then make top card face-up 299 if(stackobj.NumCards() == numfacedown) 300 { 301 if(numfacedown > 0) numfacedown--; 302 stackobj.SetFaceDirection(CS_FACE_DOWNUP, numfacedown); 303 stackobj.Redraw(); 304 305 if (GetScoreMode() == SCORE_STD) 306 { 307 lScore = lScore + 5; 308 UpdateStatusBar(); 309 } 310 ClearUndo(); 311 } 312 313 LastId = stackobj.Id(); 314 315 fGameStarted = true; 316 317 TRACE("EXIT RowStackClickProc()\n"); 318 } 319 320 // 321 // Find the suit-stack that can accept the specified card 322 // 323 CardRegion *FindSuitStackFromCard(Card card) 324 { 325 TRACE("ENTER FindSuitStackFromCard()\n"); 326 327 for(int i = 0; i < 4; i++) 328 { 329 if(CanDrop(*pSuitStack[i], card)) 330 { 331 TRACE("EXIT FindSuitStackFromCard()\n"); 332 return pSuitStack[i]; 333 } 334 } 335 336 TRACE("EXIT FindSuitStackFromCard()\n"); 337 return 0; 338 } 339 340 // 341 // What happens when we add a card to one of the suit stacks? 342 // Well, nothing (it is already added), but we need to 343 // check all four stacks (not just this one) to see if 344 // the game has finished. 345 // 346 void CARDLIBPROC SuitStackAddProc(CardRegion &stackobj, const CardStack &added) 347 { 348 TRACE("ENTER SuitStackAddProc()\n"); 349 bool fGameOver = true; 350 351 SetPlayTimer(); 352 353 for(int i = 0; i < 4; i++) 354 { 355 if(pSuitStack[i]->NumCards() != 13) 356 { 357 fGameOver = false; 358 359 break; 360 } 361 } 362 363 if(fGameOver) 364 { 365 KillTimer(hwndMain, IDT_PLAYTIMER); 366 PlayTimer = 0; 367 368 if ((dwOptions & OPTION_SHOW_TIME) && (GetScoreMode() == SCORE_STD)) 369 { 370 lScore = lScore + (700000 / dwTime); 371 } 372 373 UpdateStatusBar(); 374 ClearUndo(); 375 376 MessageBox(SolWnd, MsgWin, szAppName, MB_OK | MB_ICONINFORMATION); 377 378 for(int i = 0; i < 4; i++) 379 { 380 pSuitStack[i]->Flash(11, 100); 381 } 382 383 if( IDYES == MessageBox(SolWnd, MsgDeal, szAppName, MB_YESNO | MB_ICONQUESTION) ) 384 { 385 NewGame(); 386 } 387 else 388 { 389 SolWnd.EmptyStacks(); 390 391 fGameStarted = false; 392 } 393 } 394 395 TRACE("EXIT SuitStackAddProc()\n"); 396 } 397 398 // 399 // Double-click on one of the row stacks 400 // The aim is to find a suit-stack to move the 401 // double-clicked card to. 402 // 403 void CARDLIBPROC RowStackDblClickProc(CardRegion &stackobj, int iNumClicked) 404 { 405 TRACE("ENTER RowStackDblClickProc()\n"); 406 407 SetPlayTimer(); 408 409 //can only move 1 card at a time 410 if(iNumClicked != 1) 411 { 412 TRACE("EXIT RowStackDblClickProc()\n"); 413 return; 414 } 415 416 //find a suit-stack to move the card to... 417 const CardStack &cardstack = stackobj.GetCardStack(); 418 CardRegion *pDest = FindSuitStackFromCard(cardstack[0]); 419 420 if(pDest != 0) 421 { 422 fGameStarted = true; 423 SetPlayTimer(); 424 425 //stackobj.MoveCards(pDest, 1, true); 426 //use the SimulateDrag function, because we get the 427 //AddProc callbacks called for us on the destination stacks... 428 bAutoroute = true; 429 stackobj.SimulateDrag(pDest, 1, true); 430 bAutoroute = false; 431 } 432 TRACE("EXIT RowStackDblClickProc()\n"); 433 } 434 435 // 436 // Face-up pile single-click 437 // 438 void CARDLIBPROC PileClickProc(CardRegion &stackobj, int iNumClicked) 439 { 440 TRACE("ENTER SuitStackClickProc()\n"); 441 442 fGameStarted = true; 443 444 LastId = stackobj.Id(); 445 446 TRACE("EXIT SuitStackClickProc()\n"); 447 } 448 449 // 450 // Face-up pile double-click 451 // 452 void CARDLIBPROC PileDblClickProc(CardRegion &stackobj, int iNumClicked) 453 { 454 TRACE("ENTER PileDblClickProc()\n"); 455 456 SetPlayTimer(); 457 458 RowStackDblClickProc(stackobj, iNumClicked); 459 TRACE("EXIT PileDblClickProc()\n"); 460 } 461 462 // 463 // Fix for the 3-card play when only 1 card left on the pile. 464 // 465 void FixIfOneCardLeft(void) 466 { 467 // If there is just 1 card left, then modify the 468 // stack to contain ALL the face-up cards. The effect 469 // will be, the next time a card is dragged, all the 470 // previous card-triplets will be available underneath. 471 if ((dwOptions & OPTION_THREE_CARDS) && pPile->NumCards() == 1) 472 { 473 pPile->SetOffsets(0, 0); 474 pPile->SetCardStack(activepile); 475 } 476 } 477 478 // 479 // What happens when a card is removed from face-up pile? 480 // 481 void CARDLIBPROC PileRemoveProc(CardRegion &stackobj, int iItems) 482 { 483 TRACE("ENTER PileRemoveProc()\n"); 484 485 SetPlayTimer(); 486 487 //modify our "virtual" pile by removing the same card 488 //that was removed from the physical card stack 489 activepile.Pop(iItems); 490 if ((dwOptions & OPTION_THREE_CARDS) && (VisiblePileCards > 1)) 491 { 492 --VisiblePileCards; 493 } 494 495 FixIfOneCardLeft(); 496 497 TRACE("EXIT PileRemoveProc()\n"); 498 } 499 500 // 501 // Double-click on the deck 502 // Move 3 cards to the face-up pile 503 // 504 void CARDLIBPROC DeckClickProc(CardRegion &stackobj, int iNumClicked) 505 { 506 TRACE("ENTER DeckClickProc()\n"); 507 508 SetPlayTimer(); 509 510 CardStack cardstack = stackobj.GetCardStack(); 511 CardStack pile = pPile->GetCardStack(); 512 513 fGameStarted = true; 514 SetPlayTimer(); 515 516 //reset the face-up pile to represent 3 cards 517 if(dwOptions & OPTION_THREE_CARDS) 518 pPile->SetOffsets(CS_DEFXOFF, 1); 519 520 if(cardstack.NumCards() == 0) 521 { 522 if (GetScoreMode() == SCORE_VEGAS) 523 { 524 if (dwWasteCount < dwWasteTreshold) 525 { 526 pile.Clear(); 527 528 activepile.Reverse(); 529 cardstack.Push(activepile); 530 activepile.Clear(); 531 SetUndo(PILE_ID, DECK_ID, cardstack.NumCards(), lScore, VisiblePileCards); 532 VisiblePileCards = 0; 533 } 534 } 535 else if (GetScoreMode() == SCORE_STD) 536 { 537 SetUndo(PILE_ID, DECK_ID, activepile.NumCards(), lScore, VisiblePileCards); 538 if ((dwWasteCount >= dwWasteTreshold) && (activepile.NumCards() != 0)) 539 { 540 if (dwOptions & OPTION_THREE_CARDS) 541 lScore = lScore >= 20 ? lScore - 20 : 0; 542 else 543 lScore = lScore >= 100 ? lScore - 100 : 0; 544 } 545 546 pile.Clear(); 547 548 activepile.Reverse(); 549 cardstack.Push(activepile); 550 activepile.Clear(); 551 VisiblePileCards = 0; 552 553 UpdateStatusBar(); 554 } 555 else 556 { 557 pile.Clear(); 558 559 activepile.Reverse(); 560 cardstack.Push(activepile); 561 activepile.Clear(); 562 SetUndo(PILE_ID, DECK_ID, cardstack.NumCards(), lScore, VisiblePileCards); 563 VisiblePileCards = 0; 564 } 565 566 dwWasteCount++; 567 } 568 else 569 { 570 int numcards = min((dwOptions & OPTION_THREE_CARDS) ? 3 : 1, cardstack.NumCards()); 571 572 SetUndo(DECK_ID, PILE_ID, numcards, lScore, VisiblePileCards); 573 574 //make a "visible" copy of these cards 575 CardStack temp; 576 temp = cardstack.Pop(numcards); 577 temp.Reverse(); 578 579 if(dwOptions & OPTION_THREE_CARDS) 580 pile.Clear(); 581 582 pile.Push(temp); 583 584 //remove the top 3 from deck 585 activepile.Push(temp); 586 587 VisiblePileCards = numcards; 588 } 589 590 activepile.Print(); 591 592 pDeck->SetCardStack(cardstack); 593 pPile->SetCardStack(pile); 594 595 FixIfOneCardLeft(); 596 597 SolWnd.Redraw(); 598 TRACE("EXIT DeckClickProc()\n"); 599 } 600