1///////////////////////////////////////////////////////////////////////////// 2// Name: game.cpp 3// Purpose: Forty Thieves patience game 4// Author: Chris Breeze 5// Modified by: 6// Created: 21/07/97 7// RCS-ID: $Id: game.cpp 44498 2007-02-13 23:20:12Z VZ $ 8// Copyright: (c) 1993-1998 Chris Breeze 9// Licence: wxWindows licence 10//--------------------------------------------------------------------------- 11// Last modified: 22nd July 1998 - ported to wxWidgets 2.0 12///////////////////////////////////////////////////////////////////////////// 13 14// For compilers that support precompilation, includes "wx/wx.h". 15#include "wx/wxprec.h" 16 17#ifdef __BORLANDC__ 18#pragma hdrstop 19#endif 20 21#ifndef WX_PRECOMP 22#include "wx/wx.h" 23#endif 24 25#include <stdlib.h> 26#include <stdio.h> 27#include <time.h> 28#include <string.h> 29#include "forty.h" 30#include "game.h" 31 32Game::Game(int wins, int games, int score) : 33 m_inPlay(false), 34 m_moveIndex(0), 35 m_redoIndex(0), 36 m_bmap(0), 37 m_bmapCard(0) 38{ 39 int i; 40 41 m_pack = new Pack(2, 2 + 4 * (CardHeight + 2)); 42 srand(time(0)); 43 44 for (i = 0; i < 5; i++) m_pack->Shuffle(); 45 46 m_discard = new Discard(2, 2 + 5 * (CardHeight + 2)); 47 48 for (i = 0; i < 8; i++) 49 { 50 m_foundations[i] = new Foundation(2 + (i / 4) * (CardWidth + 2), 51 2 + (i % 4) * (CardHeight + 2)); 52 } 53 54 for (i = 0; i < 10; i++) 55 { 56 m_bases[i] = new Base(8 + (i + 2) * (CardWidth + 2), 2); 57 } 58 Deal(); 59 m_srcPile = 0; 60 m_liftedCard = 0; 61 62 // copy the input parameters for future reference 63 m_numWins = wins; 64 m_numGames = games; 65 m_totalScore = score; 66 m_currentScore = 0; 67} 68 69 70void Game::Layout() 71{ 72 int i; 73 74 m_pack->SetPos(2, 2 + 4 * (CardHeight + 2)); 75 76 m_discard->SetPos(2, 2 + 5 * (CardHeight + 2)); 77 78 for (i = 0; i < 8; i++) 79 { 80 m_foundations[i]->SetPos(2 + (i / 4) * (CardWidth + 2), 81 2 + (i % 4) * (CardHeight + 2)); 82 } 83 84 for (i = 0; i < 10; i++) 85 { 86 m_bases[i]->SetPos(8 + (i + 2) * (CardWidth + 2), 2); 87 } 88 delete m_bmap; 89 delete m_bmapCard; 90 m_bmap = 0; 91 m_bmapCard = 0; 92} 93 94// Make sure we delete all objects created by the game object 95Game::~Game() 96{ 97 int i; 98 99 delete m_pack; 100 delete m_discard; 101 for (i = 0; i < 8; i++) 102 { 103 delete m_foundations[i]; 104 } 105 for (i = 0; i < 10; i++) 106 { 107 delete m_bases[i]; 108 } 109 delete m_bmap; 110 delete m_bmapCard; 111} 112 113/* 114Set the score for a new player. 115NB: call Deal() first if the new player is to start 116a new game 117*/ 118void Game::NewPlayer(int wins, int games, int score) 119{ 120 m_numWins = wins; 121 m_numGames = games; 122 m_totalScore = score; 123 m_currentScore = 0; 124} 125 126// Undo the last move 127void Game::Undo(wxDC& dc) 128{ 129 if (m_moveIndex > 0) 130 { 131 m_moveIndex--; 132 Card* card = m_moves[m_moveIndex].dest->RemoveTopCard(dc); 133 m_moves[m_moveIndex].src->AddCard(dc, card); 134 DisplayScore(dc); 135 } 136} 137 138// Redo the last move 139void Game::Redo(wxDC& dc) 140{ 141 if (m_moveIndex < m_redoIndex) 142 { 143 Card* card = m_moves[m_moveIndex].src->RemoveTopCard(dc); 144 if (m_moves[m_moveIndex].src == m_pack) 145 { 146 m_pack->Redraw(dc); 147 card->TurnCard(faceup); 148 } 149 m_moves[m_moveIndex].dest->AddCard(dc, card); 150 DisplayScore(dc); 151 m_moveIndex++; 152 } 153} 154 155void Game::DoMove(wxDC& dc, Pile* src, Pile* dest) 156{ 157 if (m_moveIndex < MaxMoves) 158 { 159 if (src == dest) 160 { 161 wxMessageBox(_T("Game::DoMove() src == dest"), _T("Debug message"), 162 wxOK | wxICON_EXCLAMATION); 163 } 164 m_moves[m_moveIndex].src = src; 165 m_moves[m_moveIndex].dest = dest; 166 m_moveIndex++; 167 168 // when we do a move any moves in redo buffer are discarded 169 m_redoIndex = m_moveIndex; 170 } 171 else 172 { 173 wxMessageBox(_T("Game::DoMove() Undo buffer full"), _T("Debug message"), 174 wxOK | wxICON_EXCLAMATION); 175 } 176 177 if (!m_inPlay) 178 { 179 m_inPlay = true; 180 m_numGames++; 181 } 182 DisplayScore(dc); 183 184 if (HaveYouWon()) 185 { 186 wxWindow *frame = wxTheApp->GetTopWindow(); 187 wxWindow *canvas = (wxWindow *) NULL; 188 189 if (frame) 190 { 191 wxWindowList::compatibility_iterator node = frame->GetChildren().GetFirst(); 192 if (node) canvas = (wxWindow*)node->GetData(); 193 } 194 195 // This game is over 196 m_inPlay = false; 197 198 // Redraw the score box to update games won 199 DisplayScore(dc); 200 201 if (wxMessageBox(_T("Do you wish to play again?"), 202 _T("Well Done, You have won!"), wxYES_NO | wxICON_QUESTION) == wxYES) 203 { 204 Deal(); 205 canvas->Refresh(); 206 } 207 else 208 { 209 // user cancelled the dialog - exit the app 210 ((wxFrame*)canvas->GetParent())->Close(true); 211 } 212 } 213} 214 215 216void Game::DisplayScore(wxDC& dc) 217{ 218 wxColour bgColour = FortyApp::BackgroundColour(); 219 wxPen* pen = wxThePenList->FindOrCreatePen(bgColour, 1, wxSOLID); 220 dc.SetTextBackground(bgColour); 221 dc.SetTextForeground(FortyApp::TextColour()); 222 dc.SetBrush(FortyApp::BackgroundBrush()); 223 dc.SetPen(* pen); 224 225 // count the number of cards in foundations 226 m_currentScore = 0; 227 for (int i = 0; i < 8; i++) 228 { 229 m_currentScore += m_foundations[i]->GetNumCards(); 230 } 231 232 int x, y; 233 m_pack->GetTopCardPos(x, y); 234 x += 12 * CardWidth - 105; 235 236 int w, h; 237 { 238 long width, height; 239 dc.GetTextExtent(_T("Average score:m_x"), &width, &height); 240 w = width; 241 h = height; 242 } 243 dc.DrawRectangle(x + w, y, 20, 4 * h); 244 245 wxString str; 246 str.Printf(_T("%d"), m_currentScore); 247 dc.DrawText(_T("Score:"), x, y); 248 dc.DrawText(str, x + w, y); 249 y += h; 250 251 str.Printf(_T("%d"), m_numGames); 252 dc.DrawText(_T("Games played:"), x, y); 253 dc.DrawText(str, x + w, y); 254 y += h; 255 256 str.Printf(_T("%d"), m_numWins); 257 dc.DrawText(_T("Games won:"), x, y); 258 dc.DrawText(str, x + w, y); 259 y += h; 260 261 int average = 0; 262 if (m_numGames > 0) 263 { 264 average = (2 * (m_currentScore + m_totalScore) + m_numGames ) / (2 * m_numGames); 265 } 266 str.Printf(_T("%d"), average); 267 dc.DrawText(_T("Average score:"), x, y); 268 dc.DrawText(str, x + w, y); 269} 270 271 272// Shuffle the m_pack and deal the cards 273void Game::Deal() 274{ 275 int i, j; 276 Card* card; 277 278 // Reset all the piles, the undo buffer and shuffle the m_pack 279 m_moveIndex = 0; 280 m_pack->ResetPile(); 281 for (i = 0; i < 5; i++) 282 { 283 m_pack->Shuffle(); 284 } 285 m_discard->ResetPile(); 286 for (i = 0; i < 10; i++) 287 { 288 m_bases[i]->ResetPile(); 289 } 290 for (i = 0; i < 8; i++) 291 { 292 m_foundations[i]->ResetPile(); 293 } 294 295 // Deal the initial 40 cards onto the bases 296 for (i = 0; i < 10; i++) 297 { 298 for (j = 1; j <= 4; j++) 299 { 300 card = m_pack->RemoveTopCard(); 301 card->TurnCard(faceup); 302 m_bases[i]->AddCard(card); 303 } 304 } 305 306 if (m_inPlay) 307 { 308 // player has started the game and then redealt 309 // and so we must add the score for this game to the total score 310 m_totalScore += m_currentScore; 311 } 312 m_currentScore = 0; 313 m_inPlay = false; 314} 315 316 317// Redraw the m_pack, discard pile, the bases and the foundations 318void Game::Redraw(wxDC& dc) 319{ 320 int i; 321 m_pack->Redraw(dc); 322 m_discard->Redraw(dc); 323 for (i = 0; i < 8; i++) 324 { 325 m_foundations[i]->Redraw(dc); 326 } 327 for (i = 0; i < 10; i++) 328 { 329 m_bases[i]->Redraw(dc); 330 } 331 DisplayScore(dc); 332 333 if (m_bmap == 0) 334 { 335 m_bmap = new wxBitmap(CardWidth, CardHeight); 336 m_bmapCard = new wxBitmap(CardWidth, CardHeight); 337 338 // Initialise the card bitmap to the background colour 339 wxMemoryDC memoryDC; 340 memoryDC.SelectObject(*m_bmapCard); 341 memoryDC.SetPen( *wxTRANSPARENT_PEN ); 342 memoryDC.SetBrush(FortyApp::BackgroundBrush()); 343 memoryDC.DrawRectangle(0, 0, CardWidth, CardHeight); 344 memoryDC.SelectObject(*m_bmap); 345 memoryDC.DrawRectangle(0, 0, CardWidth, CardHeight); 346 memoryDC.SelectObject(wxNullBitmap); 347 } 348} 349 350 351// Test to see if the point (x, y) is over the top card of one of the piles 352// Returns pointer to the pile, or 0 if (x, y) is not over a pile 353// or the pile is empty 354Pile* Game::WhichPile(int x, int y) 355{ 356 if (m_pack->GetCard(x, y) && 357 m_pack->GetCard(x, y) == m_pack->GetTopCard()) 358 { 359 return m_pack; 360 } 361 362 if (m_discard->GetCard(x, y) && 363 m_discard->GetCard(x, y) == m_discard->GetTopCard()) 364 { 365 return m_discard; 366 } 367 368 int i; 369 for (i = 0; i < 8; i++) 370 { 371 if (m_foundations[i]->GetCard(x, y) && 372 m_foundations[i]->GetCard(x, y) == m_foundations[i]->GetTopCard()) 373 { 374 return m_foundations[i]; 375 } 376 } 377 378 for (i = 0; i < 10; i++) 379 { 380 if (m_bases[i]->GetCard(x, y) && 381 m_bases[i]->GetCard(x, y) == m_bases[i]->GetTopCard()) 382 { 383 return m_bases[i]; 384 } 385 } 386 return 0; 387} 388 389 390// Left button is pressed - if cursor is over the m_pack then deal a card 391// otherwise if it is over a card pick it up ready to be dragged - see MouseMove() 392bool Game::LButtonDown(wxDC& dc, int x, int y) 393{ 394 m_srcPile = WhichPile(x, y); 395 if (m_srcPile == m_pack) 396 { 397 Card* card = m_pack->RemoveTopCard(); 398 if (card) 399 { 400 m_pack->Redraw(dc); 401 card->TurnCard(faceup); 402 m_discard->AddCard(dc, card); 403 DoMove(dc, m_pack, m_discard); 404 } 405 m_srcPile = 0; 406 } 407 else if (m_srcPile) 408 { 409 m_srcPile->GetTopCardPos(m_xPos, m_yPos); 410 m_xOffset = m_xPos - x; 411 m_yOffset = m_yPos - y; 412 413 // Copy the area under the card 414 // Initialise the card bitmap to the background colour 415 { 416 wxMemoryDC memoryDC; 417 memoryDC.SelectObject(*m_bmap); 418 m_liftedCard = m_srcPile->RemoveTopCard(memoryDC, m_xPos, m_yPos); 419 } 420 421 // Draw the card in card bitmap ready for blitting onto 422 // the screen 423 { 424 wxMemoryDC memoryDC; 425 memoryDC.SelectObject(*m_bmapCard); 426 m_liftedCard->Draw(memoryDC, 0, 0); 427 } 428 } 429 return m_srcPile != 0; 430} 431 432// Called when the left button is double clicked 433// If a card is under the pointer and it can move elsewhere then move it. 434// Move onto a foundation as first choice, a populated base as second and 435// an empty base as third choice. 436// NB Cards in the m_pack cannot be moved in this way - they aren't in play 437// yet 438void Game::LButtonDblClk(wxDC& dc, int x, int y) 439{ 440 Pile* pile = WhichPile(x, y); 441 if (!pile) return; 442 443 // Double click on m_pack is the same as left button down 444 if (pile == m_pack) 445 { 446 LButtonDown(dc, x, y); 447 } 448 else 449 { 450 Card* card = pile->GetTopCard(); 451 452 if (card) 453 { 454 int i; 455 456 // if the card is an ace then try to place it next 457 // to an ace of the same suit 458 if (card->GetPipValue() == 1) 459 { 460 for(i = 0; i < 4; i++) 461 { 462 Card* m_topCard = m_foundations[i]->GetTopCard(); 463 if ( m_topCard ) 464 { 465 if (m_topCard->GetSuit() == card->GetSuit() && 466 m_foundations[i + 4] != pile && 467 m_foundations[i + 4]->GetTopCard() == 0) 468 { 469 pile->RemoveTopCard(dc); 470 m_foundations[i + 4]->AddCard(dc, card); 471 DoMove(dc, pile, m_foundations[i + 4]); 472 return; 473 } 474 } 475 } 476 } 477 478 // try to place the card on a foundation 479 for(i = 0; i < 8; i++) 480 { 481 if (m_foundations[i]->AcceptCard(card) && m_foundations[i] != pile) 482 { 483 pile->RemoveTopCard(dc); 484 m_foundations[i]->AddCard(dc, card); 485 DoMove(dc, pile, m_foundations[i]); 486 return; 487 } 488 } 489 // try to place the card on a populated base 490 for(i = 0; i < 10; i++) 491 { 492 if (m_bases[i]->AcceptCard(card) && 493 m_bases[i] != pile && 494 m_bases[i]->GetTopCard()) 495 { 496 pile->RemoveTopCard(dc); 497 m_bases[i]->AddCard(dc, card); 498 DoMove(dc, pile, m_bases[i]); 499 return; 500 } 501 } 502 // try to place the card on any base 503 for(i = 0; i < 10; i++) 504 { 505 if (m_bases[i]->AcceptCard(card) && m_bases[i] != pile) 506 { 507 pile->RemoveTopCard(dc); 508 m_bases[i]->AddCard(dc, card); 509 DoMove(dc, pile, m_bases[i]); 510 return; 511 } 512 } 513 } 514 } 515} 516 517 518// Test to see whether the game has been won: 519// i.e. m_pack, discard and bases are empty 520bool Game::HaveYouWon() 521{ 522 if (m_pack->GetTopCard()) return false; 523 if (m_discard->GetTopCard()) return false; 524 for(int i = 0; i < 10; i++) 525 { 526 if (m_bases[i]->GetTopCard()) return false; 527 } 528 m_numWins++; 529 m_totalScore += m_currentScore; 530 m_currentScore = 0; 531 return true; 532} 533 534 535// See whether the card under the cursor can be moved somewhere else 536// Returns 'true' if it can be moved, 'false' otherwise 537bool Game::CanYouGo(int x, int y) 538{ 539 Pile* pile = WhichPile(x, y); 540 if (pile && pile != m_pack) 541 { 542 Card* card = pile->GetTopCard(); 543 544 if (card) 545 { 546 int i; 547 for(i = 0; i < 8; i++) 548 { 549 if (m_foundations[i]->AcceptCard(card) && m_foundations[i] != pile) 550 { 551 return true; 552 } 553 } 554 for(i = 0; i < 10; i++) 555 { 556 if (m_bases[i]->GetTopCard() && 557 m_bases[i]->AcceptCard(card) && 558 m_bases[i] != pile) 559 { 560 return true; 561 } 562 } 563 } 564 } 565 return false; 566} 567 568 569// Called when the left button is released after dragging a card 570// Scan the piles to see if this card overlaps a pile and can be added 571// to the pile. If the card overlaps more than one pile on which it can be placed 572// then put it on the nearest pile. 573void Game::LButtonUp(wxDC& dc, int x, int y) 574{ 575 if (m_srcPile) 576 { 577 // work out the position of the dragged card 578 x += m_xOffset; 579 y += m_yOffset; 580 581 Pile* nearestPile = 0; 582 int distance = (CardHeight + CardWidth) * (CardHeight + CardWidth); 583 584 // find the nearest pile which will accept the card 585 int i; 586 for (i = 0; i < 8; i++) 587 { 588 if (DropCard(x, y, m_foundations[i], m_liftedCard)) 589 { 590 if (m_foundations[i]->CalcDistance(x, y) < distance) 591 { 592 nearestPile = m_foundations[i]; 593 distance = nearestPile->CalcDistance(x, y); 594 } 595 } 596 } 597 for (i = 0; i < 10; i++) 598 { 599 if (DropCard(x, y, m_bases[i], m_liftedCard)) 600 { 601 if (m_bases[i]->CalcDistance(x, y) < distance) 602 { 603 nearestPile = m_bases[i]; 604 distance = nearestPile->CalcDistance(x, y); 605 } 606 } 607 } 608 609 // Restore the area under the card 610 wxMemoryDC memoryDC; 611 memoryDC.SelectObject(*m_bmap); 612 dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight, 613 &memoryDC, 0, 0, wxCOPY); 614 615 // Draw the card in its new position 616 if (nearestPile) 617 { 618 // Add to new pile 619 nearestPile->AddCard(dc, m_liftedCard); 620 if (nearestPile != m_srcPile) 621 { 622 DoMove(dc, m_srcPile, nearestPile); 623 } 624 } 625 else 626 { 627 // Return card to src pile 628 m_srcPile->AddCard(dc, m_liftedCard); 629 } 630 m_srcPile = 0; 631 m_liftedCard = 0; 632 } 633} 634 635 636 637 638bool Game::DropCard(int x, int y, Pile* pile, Card* card) 639{ 640 bool retval = false; 641 if (pile->Overlap(x, y)) 642 { 643 if (pile->AcceptCard(card)) 644 { 645 retval = true; 646 } 647 } 648 return retval; 649} 650 651 652void Game::MouseMove(wxDC& dc, int mx, int my) 653{ 654 if (m_liftedCard) 655 { 656 wxMemoryDC memoryDC; 657 memoryDC.SelectObject(*m_bmap); 658 659 int dx = mx + m_xOffset - m_xPos; 660 int dy = my + m_yOffset - m_yPos; 661 662 if (abs(dx) >= CardWidth || abs(dy) >= CardHeight) 663 { 664 // Restore the area under the card 665 dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight, 666 &memoryDC, 0, 0, wxCOPY); 667 668 // Copy the area under the card in the new position 669 memoryDC.Blit(0, 0, CardWidth, CardHeight, 670 &dc, m_xPos + dx, m_yPos + dy, wxCOPY); 671 } 672 else if (dx >= 0) 673 { 674 // dx >= 0 675 dc.Blit(m_xPos, m_yPos, dx, CardHeight, &memoryDC, 0, 0, wxCOPY); 676 if (dy >= 0) 677 { 678 // dy >= 0 679 dc.Blit(m_xPos + dx, m_yPos, CardWidth - dx, dy, &memoryDC, dx, 0, wxCOPY); 680 memoryDC.Blit(0, 0, CardWidth - dx, CardHeight - dy, 681 &memoryDC, dx, dy, wxCOPY); 682 memoryDC.Blit(0, CardHeight - dy, CardWidth - dx, dy, 683 &dc, m_xPos + dx, m_yPos + CardHeight, wxCOPY); 684 } 685 else 686 { 687 // dy < 0 688 dc.Blit(m_xPos + dx, m_yPos + dy + CardHeight, CardWidth - dx, -dy, 689 &memoryDC, dx, CardHeight + dy, wxCOPY); 690 memoryDC.Blit(0, -dy, CardWidth - dx, CardHeight + dy, 691 &memoryDC, dx, 0, wxCOPY); 692 memoryDC.Blit(0, 0, CardWidth - dx, -dy, 693 &dc, m_xPos + dx, m_yPos + dy, wxCOPY); 694 } 695 memoryDC.Blit(CardWidth - dx, 0, dx, CardHeight, 696 &dc, m_xPos + CardWidth, m_yPos + dy, wxCOPY); 697 } 698 else 699 { 700 // dx < 0 701 dc.Blit(m_xPos + CardWidth + dx, m_yPos, -dx, CardHeight, 702 &memoryDC, CardWidth + dx, 0, wxCOPY); 703 if (dy >= 0) 704 { 705 dc.Blit(m_xPos, m_yPos, CardWidth + dx, dy, &memoryDC, 0, 0, wxCOPY); 706 memoryDC.Blit(-dx, 0, CardWidth + dx, CardHeight - dy, 707 &memoryDC, 0, dy, wxCOPY); 708 memoryDC.Blit(-dx, CardHeight - dy, CardWidth + dx, dy, 709 &dc, m_xPos, m_yPos + CardHeight, wxCOPY); 710 } 711 else 712 { 713 // dy < 0 714 dc.Blit(m_xPos, m_yPos + CardHeight + dy, CardWidth + dx, -dy, 715 &memoryDC, 0, CardHeight + dy, wxCOPY); 716 memoryDC.Blit(-dx, -dy, CardWidth + dx, CardHeight + dy, 717 &memoryDC, 0, 0, wxCOPY); 718 memoryDC.Blit(-dx, 0, CardWidth + dx, -dy, 719 &dc, m_xPos, m_yPos + dy, wxCOPY); 720 } 721 memoryDC.Blit(0, 0, -dx, CardHeight, 722 &dc, m_xPos + dx, m_yPos + dy, wxCOPY); 723 } 724 m_xPos += dx; 725 m_yPos += dy; 726 727 // draw the card in its new position 728 memoryDC.SelectObject(*m_bmapCard); 729 dc.Blit(m_xPos, m_yPos, CardWidth, CardHeight, 730 &memoryDC, 0, 0, wxCOPY); 731 } 732} 733 734 735 736//----------------------------------------------// 737// The Pack class: holds the two decks of cards // 738//----------------------------------------------// 739Pack::Pack(int x, int y) : Pile(x, y, 0, 0) 740{ 741 for (m_topCard = 0; m_topCard < NumCards; m_topCard++) 742 { 743 m_cards[m_topCard] = new Card(1 + m_topCard / 2, facedown); 744 } 745 m_topCard = NumCards - 1; 746} 747 748 749void Pack::Shuffle() 750{ 751 Card* temp[NumCards]; 752 int i; 753 754 // Don't try to shuffle an empty m_pack! 755 if (m_topCard < 0) return; 756 757 // Copy the cards into a temporary array. Start by clearing 758 // the array and then copy the card into a random position. 759 // If the position is occupied then find the next lower position. 760 for (i = 0; i <= m_topCard; i++) 761 { 762 temp[i] = 0; 763 } 764 for (i = 0; i <= m_topCard; i++) 765 { 766 int pos = rand() % (m_topCard + 1); 767 while (temp[pos]) 768 { 769 pos--; 770 if (pos < 0) pos = m_topCard; 771 } 772 m_cards[i]->TurnCard(facedown); 773 temp[pos] = m_cards[i]; 774 m_cards[i] = 0; 775 } 776 777 // Copy each card back into the m_pack in a random 778 // position. If position is occupied then find nearest 779 // unoccupied position after the random position. 780 for (i = 0; i <= m_topCard; i++) 781 { 782 int pos = rand() % (m_topCard + 1); 783 while (m_cards[pos]) 784 { 785 pos++; 786 if (pos > m_topCard) pos = 0; 787 } 788 m_cards[pos] = temp[i]; 789 } 790} 791 792void Pack::Redraw(wxDC& dc) 793{ 794 Pile::Redraw(dc); 795 796 wxString str; 797 str.Printf(_T("%d "), m_topCard + 1); 798 799 dc.SetBackgroundMode( wxSOLID ); 800 dc.SetTextBackground(FortyApp::BackgroundColour()); 801 dc.SetTextForeground(FortyApp::TextColour()); 802 dc.DrawText(str, m_x + CardWidth + 5, m_y + CardHeight / 2); 803 804} 805 806void Pack::AddCard(Card* card) 807{ 808 if (card == m_cards[m_topCard + 1]) 809 { 810 m_topCard++; 811 } 812 else 813 { 814 wxMessageBox(_T("Pack::AddCard() Undo error"), _T("Forty Thieves: Warning"), 815 wxOK | wxICON_EXCLAMATION); 816 } 817 card->TurnCard(facedown); 818} 819 820 821Pack::~Pack() 822{ 823 for (m_topCard = 0; m_topCard < NumCards; m_topCard++) 824 { 825 delete m_cards[m_topCard]; 826 } 827} 828 829 830//------------------------------------------------------// 831// The Base class: holds the initial pile of four cards // 832//------------------------------------------------------// 833Base::Base(int x, int y) : Pile(x, y, 0, 12) 834{ 835 m_topCard = -1; 836} 837 838 839bool Base::AcceptCard(Card* card) 840{ 841 bool retval = false; 842 843 if (m_topCard >= 0) 844 { 845 if (m_cards[m_topCard]->GetSuit() == card->GetSuit() && 846 m_cards[m_topCard]->GetPipValue() - 1 == card->GetPipValue()) 847 { 848 retval = true; 849 } 850 } 851 else 852 { 853 // pile is empty - ACCEPT 854 retval = true; 855 } 856 return retval; 857} 858 859 860//----------------------------------------------------------------// 861// The Foundation class: holds the cards built up from the ace... // 862//----------------------------------------------------------------// 863Foundation::Foundation(int x, int y) : Pile(x, y, 0, 0) 864{ 865 m_topCard = -1; 866} 867 868bool Foundation::AcceptCard(Card* card) 869{ 870 bool retval = false; 871 872 if (m_topCard >= 0) 873 { 874 if (m_cards[m_topCard]->GetSuit() == card->GetSuit() && 875 m_cards[m_topCard]->GetPipValue() + 1 == card->GetPipValue()) 876 { 877 retval = true; 878 } 879 } 880 else if (card->GetPipValue() == 1) 881 { 882 // It's an ace and the pile is empty - ACCEPT 883 retval = true; 884 } 885 return retval; 886} 887 888 889//----------------------------------------------------// 890// The Discard class: holds cards dealt from the m_pack // 891//----------------------------------------------------// 892Discard::Discard(int x, int y) : Pile(x, y, 19, 0) 893{ 894 m_topCard = -1; 895} 896 897void Discard::Redraw(wxDC& dc) 898{ 899 if (m_topCard >= 0) 900 { 901 if (m_dx == 0 && m_dy == 0) 902 { 903 m_cards[m_topCard]->Draw(dc, m_x, m_y); 904 } 905 else 906 { 907 int x = m_x; 908 int y = m_y; 909 for (int i = 0; i <= m_topCard; i++) 910 { 911 m_cards[i]->Draw(dc, x, y); 912 x += m_dx; 913 y += m_dy; 914 if (i == 31) 915 { 916 x = m_x; 917 y = m_y + CardHeight / 3; 918 } 919 } 920 } 921 } 922 else 923 { 924 Card::DrawNullCard(dc, m_x, m_y); 925 } 926} 927 928 929void Discard::GetTopCardPos(int& x, int& y) 930{ 931 if (m_topCard < 0) 932 { 933 x = m_x; 934 y = m_y; 935 } 936 else if (m_topCard > 31) 937 { 938 x = m_x + m_dx * (m_topCard - 32); 939 y = m_y + CardHeight / 3; 940 } 941 else 942 { 943 x = m_x + m_dx * m_topCard; 944 y = m_y; 945 } 946} 947 948 949Card* Discard::RemoveTopCard(wxDC& dc, int m_xOffset, int m_yOffset) 950{ 951 Card* card; 952 953 if (m_topCard <= 31) 954 { 955 card = Pile::RemoveTopCard(dc, m_xOffset, m_yOffset); 956 } 957 else 958 { 959 int topX, topY, x, y; 960 GetTopCardPos(topX, topY); 961 card = Pile::RemoveTopCard(); 962 card->Erase(dc, topX - m_xOffset, topY - m_yOffset); 963 GetTopCardPos(x, y); 964 dc.SetClippingRegion(topX - m_xOffset, topY - m_yOffset, 965 CardWidth, CardHeight); 966 967 for (int i = m_topCard - 31; i <= m_topCard - 31 + CardWidth / m_dx; i++) 968 { 969 m_cards[i]->Draw(dc, m_x - m_xOffset + i * m_dx, m_y - m_yOffset); 970 } 971 if (m_topCard > 31) 972 { 973 m_cards[m_topCard]->Draw(dc, topX - m_xOffset - m_dx, topY - m_yOffset); 974 } 975 dc.DestroyClippingRegion(); 976 } 977 978 return card; 979} 980