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