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