You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
464 lines
10 KiB
464 lines
10 KiB
#include "pile.h"
|
|
#include "dealer.h"
|
|
#include <kdebug.h>
|
|
#include <qpainter.h>
|
|
#include "cardmaps.h"
|
|
#include <assert.h>
|
|
#include "speeds.h"
|
|
|
|
const int Pile::RTTI = 1002;
|
|
|
|
const int Pile::Default = 0x0000;
|
|
const int Pile::disallow = 0x0001;
|
|
const int Pile::several = 0x0002; // default: move one card
|
|
|
|
// Add-flags
|
|
const int Pile::addSpread = 0x0100;
|
|
|
|
// Remove-flags
|
|
const int Pile::autoTurnTop = 0x0200;
|
|
const int Pile::wholeColumn = 0x0400;
|
|
|
|
|
|
|
|
Pile::Pile( int _index, Dealer* _dealer)
|
|
: QCanvasRectangle( _dealer->canvas() ),
|
|
m_dealer(_dealer),
|
|
m_atype(Custom),
|
|
m_rtype(Custom),
|
|
myIndex(_index),
|
|
_target(false)
|
|
{
|
|
// Make the patience aware of this pile.
|
|
dealer()->addPile(this);
|
|
|
|
QCanvasRectangle::setVisible(true); // default
|
|
_checkIndex = -1;
|
|
m_addFlags = 0;
|
|
m_removeFlags = 0;
|
|
|
|
setBrush(Qt::black);
|
|
setPen(QPen(Qt::black));
|
|
|
|
setZ(0);
|
|
initSizes();
|
|
}
|
|
|
|
|
|
void Pile::initSizes()
|
|
{
|
|
setSpread( cardMap::CARDY() / 5 + 1 );
|
|
setHSpread( cardMap::CARDX() / 9 + 1 );
|
|
setDSpread( cardMap::CARDY() / 8 );
|
|
|
|
setSize( cardMap::CARDX(), cardMap::CARDY() );
|
|
}
|
|
|
|
void Pile::setType(PileType type)
|
|
{
|
|
setAddType(type);
|
|
setRemoveType(type);
|
|
}
|
|
|
|
void Pile::setAddType(PileType _type)
|
|
{
|
|
m_atype = _type;
|
|
switch (_type) {
|
|
case Custom:
|
|
case FreeCell:
|
|
break;
|
|
case KlondikeTarget:
|
|
setTarget(true);
|
|
break;
|
|
case KlondikeStore:
|
|
case GypsyStore:
|
|
case FreecellStore:
|
|
setAddFlags(Pile::addSpread | Pile::several);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Pile::setRemoveType(PileType _type)
|
|
{
|
|
m_rtype = _type;
|
|
switch (_type) {
|
|
case Custom:
|
|
break;
|
|
case KlondikeTarget:
|
|
setRemoveFlags(Pile::disallow);
|
|
break;
|
|
case KlondikeStore:
|
|
case GypsyStore:
|
|
case FreeCell:
|
|
break;
|
|
case FreecellStore:
|
|
setRemoveFlags(Pile::several | Pile::autoTurnTop);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Pile::~Pile()
|
|
{
|
|
dealer()->removePile(this);
|
|
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
if ((*it)->source() != this) {
|
|
int i = -13;
|
|
if ((*it)->source())
|
|
i = (*it)->source()->index();
|
|
kdDebug(11111) << "pile doesn't match " << index() << " - " << i << endl;
|
|
}
|
|
(*it)->setSource(0);
|
|
}
|
|
}
|
|
|
|
void Pile::resetCache()
|
|
{
|
|
cache.resize(0, 0);
|
|
cache_selected.resize(0, 0);
|
|
}
|
|
|
|
void Pile::drawShape ( QPainter & painter )
|
|
{
|
|
if (isSelected()) {
|
|
if (cache.isNull())
|
|
dealer()->drawPile(cache, this, false);
|
|
painter.drawPixmap(int(x()), int(y()), cache);
|
|
} else {
|
|
if (cache_selected.isNull())
|
|
dealer()->drawPile(cache_selected, this, true);
|
|
painter.drawPixmap(int(x()), int(y()), cache_selected);
|
|
}
|
|
}
|
|
|
|
bool Pile::legalAdd( const CardList& _cards ) const
|
|
{
|
|
if ( m_addFlags & disallow )
|
|
return false;
|
|
|
|
if ( !( m_addFlags & several ) && _cards.count() > 1 )
|
|
return false;
|
|
|
|
// getHint removes cards without turning, so it could be it
|
|
// checks later if cards can be added to a face down card
|
|
if (top() && !top()->realFace())
|
|
return false;
|
|
|
|
switch (addType()) {
|
|
case Custom:
|
|
return dealer()->checkAdd( checkIndex(), this, _cards );
|
|
break;
|
|
case KlondikeTarget:
|
|
return add_klondikeTarget(_cards);
|
|
break;
|
|
case FreecellStore:
|
|
case KlondikeStore:
|
|
return add_klondikeStore(_cards);
|
|
break;
|
|
case GypsyStore:
|
|
return add_gypsyStore(_cards);
|
|
break;
|
|
case FreeCell:
|
|
return add_freeCell(_cards);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Pile::legalRemove(const Card *c) const
|
|
{
|
|
if ( m_removeFlags & disallow ) {
|
|
return false;
|
|
}
|
|
if ( !( m_removeFlags & several ) && top() != c)
|
|
return false;
|
|
|
|
switch (removeType()) {
|
|
case Custom:
|
|
return dealer()->checkRemove( checkIndex(), this, c);
|
|
break;
|
|
case KlondikeTarget:
|
|
case GypsyStore:
|
|
case KlondikeStore:
|
|
break;
|
|
case FreecellStore:
|
|
return remove_freecellStore(c);
|
|
break;
|
|
case FreeCell:
|
|
return (top() == c);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Pile::setVisible(bool vis)
|
|
{
|
|
QCanvasRectangle::setVisible(vis);
|
|
dealer()->enlargeCanvas(this);
|
|
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
(*it)->setVisible(vis);
|
|
dealer()->enlargeCanvas(*it);
|
|
}
|
|
}
|
|
|
|
void Pile::moveBy(double dx, double dy)
|
|
{
|
|
QCanvasRectangle::moveBy(dx, dy);
|
|
dealer()->enlargeCanvas(this);
|
|
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
(*it)->moveBy(dx, dy);
|
|
dealer()->enlargeCanvas(*it);
|
|
}
|
|
}
|
|
|
|
int Pile::indexOf(const Card *c) const
|
|
{
|
|
assert(c->source() == this);
|
|
return m_cards.findIndex(const_cast<Card*>(c)); // the list is of non-const cards
|
|
}
|
|
|
|
Card *Pile::at(int index) const
|
|
{
|
|
if (index < 0 || index >= int(m_cards.count()))
|
|
return 0;
|
|
return *m_cards.at(index);
|
|
}
|
|
|
|
// Return the top card of this pile.
|
|
//
|
|
|
|
Card *Pile::top() const
|
|
{
|
|
if (m_cards.isEmpty())
|
|
return 0;
|
|
|
|
return m_cards.last();
|
|
}
|
|
|
|
void Pile::clear()
|
|
{
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
(*it)->setSource(0);
|
|
}
|
|
m_cards.clear();
|
|
}
|
|
|
|
void Pile::add( Card *_card, int index)
|
|
{
|
|
if (_card->source() == this)
|
|
return;
|
|
|
|
Pile *source = _card->source();
|
|
if (source) {
|
|
_card->setTakenDown(source->target() && !target());
|
|
source->remove(_card);
|
|
}
|
|
|
|
_card->setSource(this);
|
|
|
|
if (index == -1)
|
|
m_cards.append(_card);
|
|
else {
|
|
while (m_cards.count() <= uint(index))
|
|
m_cards.append(0);
|
|
assert(m_cards[index] == 0);
|
|
m_cards[index] = _card;
|
|
}
|
|
}
|
|
|
|
|
|
// Return the number of pixels in x and y that the card should be
|
|
// offset from the start position of the pile.
|
|
//
|
|
// Note: Default is to only have vertical spread (Y direction).
|
|
|
|
QSize Pile::cardOffset( bool _spread, bool _facedown, const Card *before) const
|
|
{
|
|
if (_spread) {
|
|
if (_facedown)
|
|
return QSize(0, dspread());
|
|
else {
|
|
if (before && !before->isFaceUp())
|
|
return QSize(0, dspread());
|
|
else
|
|
return QSize(0, spread());
|
|
}
|
|
}
|
|
|
|
return QSize(0, 0);
|
|
}
|
|
|
|
/* override cardtype (for initial deal ) */
|
|
void Pile::add( Card* _card, bool _facedown, bool _spread )
|
|
{
|
|
if (!_card)
|
|
return;
|
|
|
|
// The top card
|
|
Card *t = top();
|
|
|
|
// If this pile is visible, then also show the card.
|
|
if (isVisible())
|
|
_card->show();
|
|
else
|
|
_card->hide();
|
|
|
|
_card->turn( !_facedown );
|
|
|
|
QSize offset = cardOffset(_spread, _facedown, t);
|
|
|
|
int x2, y2, z2;
|
|
|
|
if (t) {
|
|
x2 = int(t->realX() + offset.width());
|
|
y2 = int(t->realY() + offset.height());
|
|
z2 = int(t->realZ() + 1);
|
|
} else {
|
|
x2 = int(x());
|
|
y2 = int(y());
|
|
z2 = int(z() + 1);
|
|
}
|
|
|
|
add(_card);
|
|
|
|
if (_facedown || !isVisible()) {
|
|
_card->move( x2, y2 );
|
|
_card->setZ( z2 );
|
|
} else {
|
|
_card->moveTo(x2, y2, z2, STEPS_INITIALDEAL);
|
|
}
|
|
|
|
dealer()->enlargeCanvas(_card);
|
|
}
|
|
|
|
void Pile::remove(Card *c)
|
|
{
|
|
assert(m_cards.contains(c));
|
|
m_cards.remove(c);
|
|
}
|
|
|
|
void Pile::hideCards( const CardList & cards )
|
|
{
|
|
for (CardList::ConstIterator it = cards.begin(); it != cards.end(); ++it)
|
|
m_cards.remove(*it);
|
|
}
|
|
|
|
void Pile::unhideCards( const CardList & cards )
|
|
{
|
|
for (CardList::ConstIterator it = cards.begin(); it != cards.end(); ++it)
|
|
m_cards.append(*it);
|
|
}
|
|
|
|
CardList Pile::cardPressed(Card *c)
|
|
{
|
|
CardList result;
|
|
|
|
if (!legalRemove(c))
|
|
return result;
|
|
|
|
int below = -1;
|
|
|
|
if (!c->isFaceUp())
|
|
return result;
|
|
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
if (c == *it) {
|
|
below = 0;
|
|
}
|
|
if (below >= 0) {
|
|
(*it)->setAnimated(false);
|
|
(*it)->setZ(128 + below);
|
|
below++;
|
|
result.append(*it);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void Pile::moveCards(CardList &cl, Pile *to)
|
|
{
|
|
if (!cl.count())
|
|
return;
|
|
|
|
for (CardList::Iterator it = cl.begin(); it != cl.end(); ++it)
|
|
to->add(*it);
|
|
|
|
if (m_removeFlags & autoTurnTop && top()) {
|
|
Card *t = top();
|
|
if (!t->isFaceUp()) {
|
|
t->flipTo(int(t->x()), int(t->y()), 8);
|
|
canvas()->update();
|
|
}
|
|
}
|
|
|
|
to->moveCardsBack(cl, false);
|
|
}
|
|
|
|
void Pile::moveCardsBack(CardList &cl, bool anim)
|
|
{
|
|
if (!cl.count())
|
|
return;
|
|
|
|
Card *c = cl.first();
|
|
|
|
Card *before = 0;
|
|
QSize off;
|
|
|
|
int steps = STEPS_MOVEBACK;
|
|
if (!anim)
|
|
steps = 0;
|
|
|
|
for (CardList::Iterator it = m_cards.begin(); it != m_cards.end(); ++it)
|
|
{
|
|
if (c == *it) {
|
|
if (before) {
|
|
off = cardOffset(m_addFlags & Pile::addSpread, false, before);
|
|
c->moveTo( before->realX() + off.width(),
|
|
before->realY() + off.height(),
|
|
before->realZ() + 1, steps);
|
|
dealer()->enlargeCanvas(c);
|
|
}
|
|
else {
|
|
c->moveTo( int(x()), int(y()), int(z()) + 1, steps);
|
|
}
|
|
break;
|
|
} else
|
|
before = *it;
|
|
}
|
|
|
|
before = c;
|
|
CardList::Iterator it = cl.begin(); // == c
|
|
++it;
|
|
|
|
off = cardOffset(m_addFlags & Pile::addSpread, false, 0);
|
|
|
|
for (; it != cl.end(); ++it)
|
|
{
|
|
(*it)->moveTo( before->realX() + off.width(),
|
|
before->realY() + off.height(),
|
|
before->realZ() + 1, steps);
|
|
dealer()->enlargeCanvas(*it);
|
|
before = *it;
|
|
}
|
|
}
|
|
|
|
bool Pile::cardClicked(Card *c)
|
|
{
|
|
emit clicked(c);
|
|
return false;
|
|
}
|
|
|
|
bool Pile::cardDblClicked(Card *c)
|
|
{
|
|
emit dblClicked(c);
|
|
return false;
|
|
}
|
|
|
|
#include "pile.moc"
|