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