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