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