1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        pile.cpp
3 // Purpose:     Forty Thieves patience game
4 // Author:      Chris Breeze
5 // Modified by:
6 // Created:     21/07/97
7 // Copyright:   (c) 1993-1998 Chris Breeze
8 // Licence:     wxWindows licence
9 //---------------------------------------------------------------------------
10 // Last modified: 22nd July 1998 - ported to wxWidgets 2.0
11 /////////////////////////////////////////////////////////////////////////////
12 //+-------------------------------------------------------------+
13 //| Description:                                                |
14 //| The base class for holding piles of playing cards.          |
15 //+-------------------------------------------------------------+
16 
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include "wx/wxprec.h"
19 
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23 
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <time.h>
31 #include <string.h>
32 #include "card.h"
33 #include "pile.h"
34 #include "forty.h"
35 #include "canvas.h"
36 
37 #include "wx/app.h"
38 
39 //+-------------------------------------------------------------+
40 //| Pile::Pile()                                                |
41 //+-------------------------------------------------------------+
42 //| Description:                                                |
43 //| Initialise the pile to be empty of cards.                   |
44 //+-------------------------------------------------------------+
Pile(int x,int y,int dx,int dy)45 Pile::Pile(int x, int y, int dx, int dy)
46 {
47     m_x = x;
48     m_y = y;
49     m_dx = dx;
50     m_dy = dy;
51     for (m_topCard = 0; m_topCard < NumCards; m_topCard++)
52     {
53         m_cards[m_topCard] = 0;
54     }
55     m_topCard = -1; // i.e. empty
56 }
57 
58 
59 //+-------------------------------------------------------------+
60 //| Pile::Redraw()                                              |
61 //+-------------------------------------------------------------+
62 //| Description:                                                |
63 //| Redraw the pile on the screen. If the pile is empty         |
64 //| just draw a NULL card as a place holder for the pile.       |
65 //| Otherwise draw the pile from the bottom up, starting        |
66 //| at the origin of the pile, shifting each subsequent         |
67 //| card by the pile's x and y offsets.                         |
68 //+-------------------------------------------------------------+
Redraw(wxDC & dc)69 void Pile::Redraw(wxDC& dc )
70 {
71     FortyFrame *frame = (FortyFrame*) wxTheApp->GetTopWindow();
72     wxWindow *canvas = (wxWindow *) NULL;
73     if (frame)
74     {
75         canvas = frame->GetCanvas();
76     }
77 
78     if (m_topCard >= 0)
79     {
80         if (m_dx == 0 && m_dy == 0)
81         {
82             if ((canvas) && (canvas->IsExposed(m_x,m_y,(int)(Card::GetScale()*60),(int)(Card::GetScale()*200))))
83                 m_cards[m_topCard]->Draw(dc, m_x, m_y);
84         }
85         else
86         {
87             int x = m_x;
88             int y = m_y;
89             for (int i = 0; i <= m_topCard; i++)
90             {
91                 if ((canvas) && (canvas->IsExposed(x,y,(int)(Card::GetScale()*60),(int)(Card::GetScale()*200))))
92                     m_cards[i]->Draw(dc, x, y);
93                               x += (int)Card::GetScale()*m_dx;
94                               y += (int)Card::GetScale()*m_dy;
95             }
96         }
97     }
98     else
99     {
100         if ((canvas) && (canvas->IsExposed(m_x,m_y,(int)(Card::GetScale()*60),(int)(Card::GetScale()*200))))
101             Card::DrawNullCard(dc, m_x, m_y);
102     }
103 }
104 
105 
106 //+-------------------------------------------------------------+
107 //| Pile::GetTopCard()                                          |
108 //+-------------------------------------------------------------+
109 //| Description:                                                |
110 //| Return a pointer to the top card in the pile or NULL        |
111 //| if the pile is empty.                                       |
112 //| NB: Gets a copy of the card without removing it from the    |
113 //| pile.                                                       |
114 //+-------------------------------------------------------------+
GetTopCard()115 Card* Pile::GetTopCard()
116 {
117     Card* card = 0;
118 
119     if (m_topCard >= 0)
120     {
121         card = m_cards[m_topCard];
122     }
123     return card;
124 }
125 
126 
127 //+-------------------------------------------------------------+
128 //| Pile::RemoveTopCard()                                       |
129 //+-------------------------------------------------------------+
130 //| Description:                                                |
131 //| If the pile is not empty, remove the top card from the      |
132 //| pile and return the pointer to the removed card.            |
133 //| If the pile is empty return a NULL pointer.                 |
134 //+-------------------------------------------------------------+
RemoveTopCard()135 Card* Pile::RemoveTopCard()
136 {
137     Card* card = 0;
138 
139     if (m_topCard >= 0)
140     {
141         card = m_cards[m_topCard--];
142     }
143     return card;
144 }
145 
146 
147 //+-------------------------------------------------------------+
148 //| Pile::RemoveTopCard()                                       |
149 //+-------------------------------------------------------------+
150 //| Description:                                                |
151 //| As RemoveTopCard() but also redraw the top of the pile      |
152 //| after the card has been removed.                            |
153 //| NB: the offset allows for the redrawn area to be in a       |
154 //| bitmap ready for 'dragging' cards acrosss the screen.       |
155 //+-------------------------------------------------------------+
RemoveTopCard(wxDC & dc,int xOffset,int yOffset)156 Card* Pile::RemoveTopCard(wxDC& dc, int xOffset, int yOffset)
157 {
158     int topX, topY, x, y;
159 
160     GetTopCardPos(topX, topY);
161     Card* card = RemoveTopCard();
162 
163     if (card)
164     {
165         card->Erase(dc, topX - xOffset, topY - yOffset);
166         GetTopCardPos(x, y);
167         if (m_topCard < 0)
168         {
169             Card::DrawNullCard(dc, x - xOffset, y - yOffset);
170         }
171         else
172         {
173             m_cards[m_topCard]->Draw(dc, x - xOffset, y - yOffset);
174         }
175     }
176 
177     return card;
178 }
179 
180 
GetTopCardPos(int & x,int & y)181 void Pile::GetTopCardPos(int& x, int& y)
182 {
183     if (m_topCard < 0)
184     {
185         x = m_x;
186         y = m_y;
187     }
188     else
189     {
190         x = m_x + (int)Card::GetScale()*m_dx * m_topCard;
191         y = m_y + (int)Card::GetScale()*m_dy * m_topCard;
192     }
193 }
194 
AddCard(Card * card)195 void Pile::AddCard(Card* card)
196 {
197     if (m_topCard < -1) m_topCard = -1;
198 
199     m_cards[++m_topCard] = card;
200 }
201 
AddCard(wxDC & dc,Card * card)202 void Pile::AddCard(wxDC& dc, Card* card)
203 {
204     AddCard(card);
205     int x, y;
206     GetTopCardPos(x, y);
207     card->Draw(dc, x, y);
208 }
209 
210 // Can the card leave this pile.
211 // If it is a member of the pile then the answer is yes.
212 // Derived classes may override this behaviour to incorporate
213 // the rules of the game
CanCardLeave(Card * card)214 bool Pile::CanCardLeave(Card* card)
215 {
216     for (int i = 0; i <= m_topCard; i++)
217     {
218         if (card == m_cards[i]) return true;
219     }
220     return false;
221 }
222 
223 // Calculate how far x, y is from top card in the pile
224 // Returns the square of the distance
CalcDistance(int x,int y)225 int Pile::CalcDistance(int x, int y)
226 {
227     int cx, cy;
228     GetTopCardPos(cx, cy);
229     return ((cx - x) * (cx - x) + (cy - y) * (cy - y));
230 }
231 
232 
233 // Return the card at x, y. Check the top card first, then
234 // work down the pile. If a card is found then return a pointer
235 // to the card, otherwise return NULL
GetCard(int x,int y)236 Card* Pile::GetCard(int x, int y)
237 {
238     int cardX;
239     int cardY;
240     GetTopCardPos(cardX, cardY);
241 
242     for (int i = m_topCard; i >= 0; i--)
243     {
244         if (x >= cardX && x <= cardX + Card::GetWidth() &&
245             y >= cardY && y <= cardY + Card::GetHeight())
246         {
247             return m_cards[i];
248         }
249         cardX -= (int)Card::GetScale()*m_dx;
250         cardY -= (int)Card::GetScale()*m_dy;
251     }
252     return 0;
253 }
254 
255 
256 // Return the position of the given card. If it is not a member of this pile
257 // return the origin of the pile.
GetCardPos(Card * card,int & x,int & y)258 void Pile::GetCardPos(Card* card, int& x, int& y)
259 {
260     x = m_x;
261     y = m_y;
262 
263     for (int i = 0; i <= m_topCard; i++)
264     {
265         if (card == m_cards[i])
266         {
267             return;
268         }
269         x += (int)Card::GetScale()*m_dx;
270         y += (int)Card::GetScale()*m_dy;
271     }
272 
273     // card not found in pile, return origin of pile
274     x = m_x;
275     y = m_y;
276 }
277 
278 
Overlap(int x,int y)279 bool Pile::Overlap(int x, int y)
280 {
281     int cardX;
282     int cardY;
283     GetTopCardPos(cardX, cardY);
284 
285     if (x >= cardX - Card::GetWidth()  && x <= cardX + Card::GetWidth() &&
286         y >= cardY - Card::GetHeight() && y <= cardY + Card::GetHeight())
287     {
288         return true;
289     }
290     return false;
291 }
292