|
|
|
#include "dealer.h"
|
|
|
|
#include <kstaticdeleter.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "deck.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include "kmainwindow.h"
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kpixmapeffect.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include "cardmaps.h"
|
|
|
|
#include "speeds.h"
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// class MoveHint
|
|
|
|
|
|
|
|
|
|
|
|
MoveHint::MoveHint(Card *card, Pile *to, bool d)
|
|
|
|
{
|
|
|
|
m_card = card;
|
|
|
|
m_to = to;
|
|
|
|
m_dropiftarget = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// class DealerInfoList
|
|
|
|
|
|
|
|
|
|
|
|
DealerInfoList *DealerInfoList::_self = 0;
|
|
|
|
static KStaticDeleter<DealerInfoList> dl;
|
|
|
|
|
|
|
|
|
|
|
|
DealerInfoList *DealerInfoList::self()
|
|
|
|
{
|
|
|
|
if (!_self)
|
|
|
|
_self = dl.setObject(_self, new DealerInfoList());
|
|
|
|
return _self;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DealerInfoList::add(DealerInfo *dealer)
|
|
|
|
{
|
|
|
|
list.append(dealer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================
|
|
|
|
// class Dealer
|
|
|
|
|
|
|
|
|
|
|
|
Dealer *Dealer::s_instance = 0;
|
|
|
|
|
|
|
|
|
|
|
|
Dealer::Dealer( KMainWindow* _parent , const char* _name )
|
|
|
|
: TQCanvasView( 0, _parent, _name ),
|
|
|
|
towait(0),
|
|
|
|
myActions(0),
|
|
|
|
ademo(0),
|
|
|
|
ahint(0),
|
|
|
|
aredeal(0),
|
|
|
|
takeTargets(false),
|
|
|
|
_won(false),
|
|
|
|
_waiting(0),
|
|
|
|
stop_demo_next(false),
|
|
|
|
_autodrop(true),
|
|
|
|
_gameRecorded(false)
|
|
|
|
{
|
|
|
|
setResizePolicy(TQScrollView::Manual);
|
|
|
|
setVScrollBarMode(AlwaysOff);
|
|
|
|
setHScrollBarMode(AlwaysOff);
|
|
|
|
|
|
|
|
setGameNumber(kapp->random());
|
|
|
|
myCanvas.setAdvancePeriod(30);
|
|
|
|
// myCanvas.setBackgroundColor( darkGreen );
|
|
|
|
setCanvas(&myCanvas);
|
|
|
|
myCanvas.setDoubleBuffering(true);
|
|
|
|
|
|
|
|
undoList.setAutoDelete(true);
|
|
|
|
|
|
|
|
demotimer = new TQTimer(this);
|
|
|
|
|
|
|
|
connect(demotimer, TQT_SIGNAL(timeout()), TQT_SLOT(demo()));
|
|
|
|
|
|
|
|
assert(!s_instance);
|
|
|
|
s_instance = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const Dealer *Dealer::instance()
|
|
|
|
{
|
|
|
|
return s_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Dealer::setBackgroundPixmap(const TQPixmap &background, const TQColor &midcolor)
|
|
|
|
{
|
|
|
|
_midcolor = midcolor;
|
|
|
|
canvas()->tqsetBackgroundPixmap(background);
|
|
|
|
for (PileList::Iterator it = piles.begin(); it != piles.end(); ++it) {
|
|
|
|
(*it)->resetCache();
|
|
|
|
(*it)->initSizes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setupActions() {
|
|
|
|
|
|
|
|
TQPtrList<KAction> actionlist;
|
|
|
|
|
|
|
|
kdDebug(11111) << "setupActions " << actions() << endl;
|
|
|
|
|
|
|
|
if (actions() & Dealer::Hint) {
|
|
|
|
|
|
|
|
ahint = new KAction( i18n("&Hint"), TQString::tqfromLatin1("wizard"), Key_H, TQT_TQOBJECT(this),
|
|
|
|
TQT_SLOT(hint()),
|
|
|
|
parent()->actionCollection(), "game_hint");
|
|
|
|
actionlist.append(ahint);
|
|
|
|
} else
|
|
|
|
ahint = 0;
|
|
|
|
|
|
|
|
if (actions() & Dealer::Demo) {
|
|
|
|
ademo = new KToggleAction( i18n("&Demo"), TQString::tqfromLatin1("1rightarrow"), CTRL+Key_D, TQT_TQOBJECT(this),
|
|
|
|
TQT_SLOT(toggleDemo()),
|
|
|
|
parent()->actionCollection(), "game_demo");
|
|
|
|
actionlist.append(ademo);
|
|
|
|
} else
|
|
|
|
ademo = 0;
|
|
|
|
|
|
|
|
if (actions() & Dealer::Redeal) {
|
|
|
|
aredeal = new KAction (i18n("&Redeal"), TQString::tqfromLatin1("queue"), 0, TQT_TQOBJECT(this),
|
|
|
|
TQT_SLOT(redeal()),
|
|
|
|
parent()->actionCollection(), "game_redeal");
|
|
|
|
actionlist.append(aredeal);
|
|
|
|
} else
|
|
|
|
aredeal = 0;
|
|
|
|
|
|
|
|
parent()->guiFactory()->plugActionList( parent(), TQString::tqfromLatin1("game_actions"), actionlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
Dealer::~Dealer()
|
|
|
|
{
|
|
|
|
if (!_won)
|
|
|
|
countLoss();
|
|
|
|
clearHints();
|
|
|
|
parent()->guiFactory()->unplugActionList( parent(), TQString::tqfromLatin1("game_actions"));
|
|
|
|
|
|
|
|
while (!piles.isEmpty())
|
|
|
|
delete piles.first(); // removes itself
|
|
|
|
|
|
|
|
if (s_instance == this)
|
|
|
|
s_instance = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMainWindow *Dealer::parent() const
|
|
|
|
{
|
|
|
|
return dynamic_cast<KMainWindow*>(TQCanvasView::parent());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
void Dealer::hint()
|
|
|
|
{
|
|
|
|
unmarkAll();
|
|
|
|
clearHints();
|
|
|
|
getHints();
|
|
|
|
for (HintList::ConstIterator it = hints.begin(); it != hints.end(); ++it)
|
|
|
|
mark((*it)->card());
|
|
|
|
clearHints();
|
|
|
|
canvas()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Dealer::getHints()
|
|
|
|
{
|
|
|
|
for (PileList::Iterator it = piles.begin(); it != piles.end(); ++it)
|
|
|
|
{
|
|
|
|
if (!takeTargetForHints() && (*it)->target())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Pile *store = *it;
|
|
|
|
if (store->isEmpty())
|
|
|
|
continue;
|
|
|
|
// kdDebug(11111) << "trying " << store->top()->name() << endl;
|
|
|
|
|
|
|
|
CardList cards = store->cards();
|
|
|
|
while (cards.count() && !cards.first()->realFace()) cards.remove(cards.begin());
|
|
|
|
|
|
|
|
CardList::Iterator iti = cards.begin();
|
|
|
|
while (iti != cards.end())
|
|
|
|
{
|
|
|
|
if (store->legalRemove(*iti)) {
|
|
|
|
// kdDebug(11111) << "could remove " << (*iti)->name() << endl;
|
|
|
|
for (PileList::Iterator pit = piles.begin(); pit != piles.end(); ++pit)
|
|
|
|
{
|
|
|
|
Pile *dest = *pit;
|
|
|
|
if (dest == store)
|
|
|
|
continue;
|
|
|
|
if (store->indexOf(*iti) == 0 && dest->isEmpty() && !dest->target())
|
|
|
|
continue;
|
|
|
|
if (!dest->legalAdd(cards))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool old_prefer = checkPrefering( dest->checkIndex(), dest, cards );
|
|
|
|
if (!takeTargetForHints() && dest->target())
|
|
|
|
newHint(new MoveHint(*iti, dest));
|
|
|
|
else {
|
|
|
|
store->hideCards(cards);
|
|
|
|
// if it could be here as well, then it's no use
|
|
|
|
if ((store->isEmpty() && !dest->isEmpty()) || !store->legalAdd(cards))
|
|
|
|
newHint(new MoveHint(*iti, dest));
|
|
|
|
else {
|
|
|
|
if (old_prefer && !checkPrefering( store->checkIndex(),
|
|
|
|
store, cards ))
|
|
|
|
{ // if checkPrefers says so, we add it nonetheless
|
|
|
|
newHint(new MoveHint(*iti, dest));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
store->unhideCards(cards);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cards.remove(iti);
|
|
|
|
iti = cards.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::checkPrefering( int /*checkIndex*/, const Pile *, const CardList& ) const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::clearHints()
|
|
|
|
{
|
|
|
|
for (HintList::Iterator it = hints.begin(); it != hints.end(); ++it)
|
|
|
|
delete *it;
|
|
|
|
hints.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::newHint(MoveHint *mh)
|
|
|
|
{
|
|
|
|
hints.append(mh);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::isMoving(Card *c) const
|
|
|
|
{
|
|
|
|
return movingCards.find(c) != movingCards.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::contentsMouseMoveEvent(TQMouseEvent* e)
|
|
|
|
{
|
|
|
|
if (movingCards.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
moved = true;
|
|
|
|
|
|
|
|
for (CardList::Iterator it = movingCards.begin(); it != movingCards.end(); ++it)
|
|
|
|
{
|
|
|
|
(*it)->moveBy(e->pos().x() - moving_start.x(),
|
|
|
|
e->pos().y() - moving_start.y());
|
|
|
|
}
|
|
|
|
|
|
|
|
PileList sources;
|
|
|
|
TQCanvasItemList list = canvas()->collisions(movingCards.first()->rect());
|
|
|
|
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
Card *c = dynamic_cast<Card*>(*it);
|
|
|
|
assert(c);
|
|
|
|
if (!c->isFaceUp())
|
|
|
|
continue;
|
|
|
|
if (c->source() == movingCards.first()->source())
|
|
|
|
continue;
|
|
|
|
if (sources.findIndex(c->source()) != -1)
|
|
|
|
continue;
|
|
|
|
sources.append(c->source());
|
|
|
|
} else {
|
|
|
|
if ((*it)->rtti() == Pile::RTTI) {
|
|
|
|
Pile *p = static_cast<Pile*>(*it);
|
|
|
|
if (p->isEmpty() && !sources.contains(p))
|
|
|
|
sources.append(p);
|
|
|
|
} else {
|
|
|
|
kdDebug(11111) << "unknown object " << *it << " " << (*it)->rtti() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO some caching of the results
|
|
|
|
unmarkAll();
|
|
|
|
|
|
|
|
for (PileList::Iterator it = sources.begin(); it != sources.end(); ++it)
|
|
|
|
{
|
|
|
|
bool b = (*it)->legalAdd(movingCards);
|
|
|
|
if (b) {
|
|
|
|
if ((*it)->isEmpty()) {
|
|
|
|
(*it)->setSelected(true);
|
|
|
|
marked.append(*it);
|
|
|
|
} else {
|
|
|
|
mark((*it)->top());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
moving_start = e->pos();
|
|
|
|
canvas()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::mark(Card *c)
|
|
|
|
{
|
|
|
|
c->setSelected(true);
|
|
|
|
if (!marked.contains(c))
|
|
|
|
marked.append(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::unmarkAll()
|
|
|
|
{
|
|
|
|
for (TQCanvasItemList::Iterator it = marked.begin(); it != marked.end(); ++it)
|
|
|
|
{
|
|
|
|
(*it)->setSelected(false);
|
|
|
|
}
|
|
|
|
marked.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::contentsMousePressEvent(TQMouseEvent* e)
|
|
|
|
{
|
|
|
|
unmarkAll();
|
|
|
|
stopDemo();
|
|
|
|
if (waiting())
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQCanvasItemList list = canvas()->collisions(e->pos());
|
|
|
|
|
|
|
|
kdDebug(11111) << "mouse pressed " << list.count() << " " << canvas()->allItems().count() << endl;
|
|
|
|
moved = false;
|
|
|
|
|
|
|
|
if (!list.count())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e->button() == Qt::LeftButton) {
|
|
|
|
if (list.first()->rtti() == Card::RTTI) {
|
|
|
|
Card *c = dynamic_cast<Card*>(list.first());
|
|
|
|
assert(c);
|
|
|
|
CardList mycards = c->source()->cardPressed(c);
|
|
|
|
for (CardList::Iterator it = mycards.begin(); it != mycards.end(); ++it)
|
|
|
|
(*it)->setAnimated(false);
|
|
|
|
movingCards = mycards;
|
|
|
|
moving_start = e->pos();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->button() == Qt::RightButton) {
|
|
|
|
if (list.first()->rtti() == Card::RTTI) {
|
|
|
|
Card *preview = dynamic_cast<Card*>(list.first());
|
|
|
|
assert(preview);
|
|
|
|
if (!preview->animated() && !isMoving(preview))
|
|
|
|
preview->getUp();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if it's nothing else, we move the cards back
|
|
|
|
contentsMouseReleaseEvent(e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class Hit {
|
|
|
|
public:
|
|
|
|
Pile *source;
|
|
|
|
TQRect intersect;
|
|
|
|
bool top;
|
|
|
|
};
|
|
|
|
typedef TQValueList<Hit> HitList;
|
|
|
|
|
|
|
|
void Dealer::contentsMouseReleaseEvent( TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
if (!moved) {
|
|
|
|
if (!movingCards.isEmpty()) {
|
|
|
|
movingCards.first()->source()->moveCardsBack(movingCards);
|
|
|
|
movingCards.clear();
|
|
|
|
}
|
|
|
|
TQCanvasItemList list = canvas()->collisions(e->pos());
|
|
|
|
if (list.isEmpty())
|
|
|
|
return;
|
|
|
|
TQCanvasItemList::Iterator it = list.begin();
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
Card *c = dynamic_cast<Card*>(*it);
|
|
|
|
assert(c);
|
|
|
|
if (!c->animated()) {
|
|
|
|
if ( cardClicked(c) ) {
|
|
|
|
countGame();
|
|
|
|
}
|
|
|
|
takeState();
|
|
|
|
canvas()->update();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((*it)->rtti() == Pile::RTTI) {
|
|
|
|
Pile *c = dynamic_cast<Pile*>(*it);
|
|
|
|
assert(c);
|
|
|
|
pileClicked(c);
|
|
|
|
takeState();
|
|
|
|
canvas()->update();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!movingCards.count())
|
|
|
|
return;
|
|
|
|
Card *c = static_cast<Card*>(movingCards.first());
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
unmarkAll();
|
|
|
|
|
|
|
|
TQCanvasItemList list = canvas()->collisions(movingCards.first()->rect());
|
|
|
|
HitList sources;
|
|
|
|
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
Card *c = dynamic_cast<Card*>(*it);
|
|
|
|
assert(c);
|
|
|
|
if (!c->isFaceUp())
|
|
|
|
continue;
|
|
|
|
if (c->source() == movingCards.first()->source())
|
|
|
|
continue;
|
|
|
|
Hit t;
|
|
|
|
t.source = c->source();
|
|
|
|
t.intersect = c->rect().intersect(movingCards.first()->rect());
|
|
|
|
t.top = (c == c->source()->top());
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
for (HitList::Iterator hi = sources.begin(); hi != sources.end(); ++hi)
|
|
|
|
{
|
|
|
|
if ((*hi).source == c->source()) {
|
|
|
|
found = true;
|
|
|
|
if ((*hi).intersect.width() * (*hi).intersect.height() >
|
|
|
|
t.intersect.width() * t.intersect.height())
|
|
|
|
{
|
|
|
|
(*hi).intersect = t.intersect;
|
|
|
|
(*hi).top |= t.top;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
sources.append(t);
|
|
|
|
} else {
|
|
|
|
if ((*it)->rtti() == Pile::RTTI) {
|
|
|
|
Pile *p = static_cast<Pile*>(*it);
|
|
|
|
if (p->isEmpty())
|
|
|
|
{
|
|
|
|
Hit t;
|
|
|
|
t.source = p;
|
|
|
|
t.intersect = p->rect().intersect(movingCards.first()->rect());
|
|
|
|
t.top = true;
|
|
|
|
sources.append(t);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
kdDebug(11111) << "unknown object " << *it << " " << (*it)->rtti() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (HitList::Iterator it = sources.begin(); it != sources.end(); )
|
|
|
|
{
|
|
|
|
if (!(*it).source->legalAdd(movingCards))
|
|
|
|
it = sources.remove(it);
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sources.isEmpty()) {
|
|
|
|
c->source()->moveCardsBack(movingCards);
|
|
|
|
} else {
|
|
|
|
HitList::Iterator best = sources.begin();
|
|
|
|
HitList::Iterator it = best;
|
|
|
|
for (++it; it != sources.end(); ++it )
|
|
|
|
{
|
|
|
|
if ((*it).intersect.width() * (*it).intersect.height() >
|
|
|
|
(*best).intersect.width() * (*best).intersect.height()
|
|
|
|
|| ((*it).top && !(*best).top))
|
|
|
|
{
|
|
|
|
best = it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
countGame();
|
|
|
|
c->source()->moveCards(movingCards, (*best).source);
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
movingCards.clear();
|
|
|
|
canvas()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::contentsMouseDoubleClickEvent( TQMouseEvent*e )
|
|
|
|
{
|
|
|
|
stopDemo();
|
|
|
|
unmarkAll();
|
|
|
|
if (waiting())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!movingCards.isEmpty()) {
|
|
|
|
movingCards.first()->source()->moveCardsBack(movingCards);
|
|
|
|
movingCards.clear();
|
|
|
|
}
|
|
|
|
TQCanvasItemList list = canvas()->collisions(e->pos());
|
|
|
|
if (list.isEmpty())
|
|
|
|
return;
|
|
|
|
TQCanvasItemList::Iterator it = list.begin();
|
|
|
|
if ((*it)->rtti() != Card::RTTI)
|
|
|
|
return;
|
|
|
|
Card *c = dynamic_cast<Card*>(*it);
|
|
|
|
assert(c);
|
|
|
|
if (!c->animated()) {
|
|
|
|
if ( cardDblClicked(c) ) {
|
|
|
|
countGame();
|
|
|
|
}
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize Dealer::minimumCardSize() const
|
|
|
|
{
|
|
|
|
return minsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::resizeEvent(TQResizeEvent *e)
|
|
|
|
{
|
|
|
|
int x = width();
|
|
|
|
int y = height();
|
|
|
|
int hs = horizontalScrollBar()->tqsizeHint().height();
|
|
|
|
int vs = verticalScrollBar()->tqsizeHint().width();
|
|
|
|
|
|
|
|
int mx = minsize.width();
|
|
|
|
int my = minsize.height();
|
|
|
|
|
|
|
|
int dx = x;
|
|
|
|
int dy = y;
|
|
|
|
bool showh = false;
|
|
|
|
bool showv = false;
|
|
|
|
|
|
|
|
if (mx > x) {
|
|
|
|
dx = mx;
|
|
|
|
if (my + vs < y)
|
|
|
|
dy -= vs;
|
|
|
|
else {
|
|
|
|
showv = true;
|
|
|
|
}
|
|
|
|
showh = true;
|
|
|
|
} else if (my > y) {
|
|
|
|
dy = my;
|
|
|
|
if (mx + hs < x)
|
|
|
|
dx -= hs;
|
|
|
|
else
|
|
|
|
showh = true;
|
|
|
|
showv = true;
|
|
|
|
}
|
|
|
|
canvas()->resize(dx, dy);
|
|
|
|
resizeContents(dx, dy);
|
|
|
|
setVScrollBarMode(showv ? AlwaysOn : AlwaysOff);
|
|
|
|
setHScrollBarMode(showh ? AlwaysOn : AlwaysOff);
|
|
|
|
|
|
|
|
if (!e)
|
|
|
|
updateScrollBars();
|
|
|
|
else
|
|
|
|
TQCanvasView::resizeEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::cardClicked(Card *c) {
|
|
|
|
return c->source()->cardClicked(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::pileClicked(Pile *c) {
|
|
|
|
c->cardClicked(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::cardDblClicked(Card *c)
|
|
|
|
{
|
|
|
|
if (c->source()->cardDblClicked(c))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (c->animated())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (c == c->source()->top() && c->realFace()) {
|
|
|
|
Pile *tgt = findTarget(c);
|
|
|
|
if (tgt) {
|
|
|
|
CardList empty;
|
|
|
|
empty.append(c);
|
|
|
|
c->source()->moveCards(empty, tgt);
|
|
|
|
canvas()->update();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::startNew()
|
|
|
|
{
|
|
|
|
if (!_won)
|
|
|
|
countLoss();
|
|
|
|
if ( ahint )
|
|
|
|
ahint->setEnabled( true );
|
|
|
|
if ( ademo )
|
|
|
|
ademo->setEnabled( true );
|
|
|
|
if ( aredeal )
|
|
|
|
aredeal->setEnabled( true );
|
|
|
|
toldAboutLostGame = false;
|
|
|
|
minsize = TQSize(0,0);
|
|
|
|
_won = false;
|
|
|
|
_waiting = 0;
|
|
|
|
_gameRecorded=false;
|
|
|
|
kdDebug(11111) << "startNew stopDemo\n";
|
|
|
|
stopDemo();
|
|
|
|
kdDebug(11111) << "startNew unmarkAll\n";
|
|
|
|
unmarkAll();
|
|
|
|
kdDebug(11111) << "startNew setAnimated(false)\n";
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it) {
|
|
|
|
if ((*it)->rtti() == Card::RTTI)
|
|
|
|
static_cast<Card*>(*it)->disconnect();
|
|
|
|
|
|
|
|
(*it)->setAnimated(true);
|
|
|
|
(*it)->setAnimated(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
undoList.clear();
|
|
|
|
emit undoPossible(false);
|
|
|
|
emit updateMoves();
|
|
|
|
kdDebug(11111) << "startNew restart\n";
|
|
|
|
restart();
|
|
|
|
takeState();
|
|
|
|
Card *towait = 0;
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it) {
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
towait = static_cast<Card*>(*it);
|
|
|
|
if (towait->animated())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(11111) << "startNew takeState\n";
|
|
|
|
if (!towait)
|
|
|
|
takeState();
|
|
|
|
else
|
|
|
|
connect(towait, TQT_SIGNAL(stoped(Card*)), TQT_SLOT(slotTakeState(Card *)));
|
|
|
|
resizeEvent(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::slotTakeState(Card *c) {
|
|
|
|
if (c)
|
|
|
|
c->disconnect();
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::enlargeCanvas(TQCanvasRectangle *c)
|
|
|
|
{
|
|
|
|
if (!c->isVisible() || c->animated())
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
if (c->x() + c->width() + 10 > minsize.width()) {
|
|
|
|
minsize.setWidth(int(c->x()) + c->width() + 10);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (c->y() + c->height() + 10 > minsize.height()) {
|
|
|
|
minsize.setHeight(int(c->y()) + c->height() + 10);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
if (changed)
|
|
|
|
resizeEvent(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
class CardState {
|
|
|
|
public:
|
|
|
|
Card *it;
|
|
|
|
Pile *source;
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z;
|
|
|
|
bool faceup;
|
|
|
|
bool tookdown;
|
|
|
|
int source_index;
|
|
|
|
CardState() {}
|
|
|
|
public:
|
|
|
|
// as every card is only once we can sort after the card.
|
|
|
|
// < is the same as <= in that context. == is different
|
|
|
|
bool operator<(const CardState &rhs) const { return it < rhs.it; }
|
|
|
|
bool operator<=(const CardState &rhs) const { return it <= rhs.it; }
|
|
|
|
bool operator>(const CardState &rhs) const { return it > rhs.it; }
|
|
|
|
bool operator>=(const CardState &rhs) const { return it > rhs.it; }
|
|
|
|
bool operator==(const CardState &rhs) const {
|
|
|
|
return (it == rhs.it && source == rhs.source && x == rhs.x &&
|
|
|
|
y == rhs.y && z == rhs.z && faceup == rhs.faceup
|
|
|
|
&& source_index == rhs.source_index && tookdown == rhs.tookdown);
|
|
|
|
}
|
|
|
|
void fillNode(TQDomElement &e) const {
|
|
|
|
e.setAttribute("value", it->rank());
|
|
|
|
e.setAttribute("suit", it->suit());
|
|
|
|
e.setAttribute("source", source->index());
|
|
|
|
e.setAttribute("x", x);
|
|
|
|
e.setAttribute("y", y);
|
|
|
|
e.setAttribute("z", z);
|
|
|
|
e.setAttribute("faceup", faceup);
|
|
|
|
e.setAttribute("tookdown", tookdown);
|
|
|
|
e.setAttribute("source_index", source_index);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef class TQValueList<CardState> CardStateList;
|
|
|
|
|
|
|
|
bool operator==( const State & st1, const State & st2) {
|
|
|
|
return st1.cards == st2.cards && st1.gameData == st2.gameData;
|
|
|
|
}
|
|
|
|
|
|
|
|
State *Dealer::getState()
|
|
|
|
{
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
State * st = new State;
|
|
|
|
|
|
|
|
for (TQCanvasItemList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
Card *c = dynamic_cast<Card*>(*it);
|
|
|
|
assert(c);
|
|
|
|
CardState s;
|
|
|
|
s.it = c;
|
|
|
|
s.source = c->source();
|
|
|
|
if (!s.source) {
|
|
|
|
kdDebug(11111) << c->name() << " has no parent\n";
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
s.source_index = c->source()->indexOf(c);
|
|
|
|
s.x = c->realX();
|
|
|
|
s.y = c->realY();
|
|
|
|
s.z = c->realZ();
|
|
|
|
s.faceup = c->realFace();
|
|
|
|
s.tookdown = c->takenDown();
|
|
|
|
st->cards.append(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qHeapSort(st->cards);
|
|
|
|
|
|
|
|
// Game specific information
|
|
|
|
st->gameData = getGameState( );
|
|
|
|
|
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setState(State *st)
|
|
|
|
{
|
|
|
|
CardStateList * n = &st->cards;
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Pile::RTTI) {
|
|
|
|
Pile *p = dynamic_cast<Pile*>(*it);
|
|
|
|
assert(p);
|
|
|
|
CardList cards = p->cards();
|
|
|
|
for (CardList::Iterator it = cards.begin(); it != cards.end(); ++it)
|
|
|
|
(*it)->setTakenDown(p->target());
|
|
|
|
p->clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (CardStateList::ConstIterator it = n->begin(); it != n->end(); ++it)
|
|
|
|
{
|
|
|
|
Card *c = (*it).it;
|
|
|
|
CardState s = *it;
|
|
|
|
bool target = c->takenDown(); // abused
|
|
|
|
s.source->add(c, s.source_index);
|
|
|
|
c->tqsetVisible(s.source->isVisible());
|
|
|
|
c->setAnimated(false);
|
|
|
|
c->setX(s.x);
|
|
|
|
c->setY(s.y);
|
|
|
|
c->setZ(int(s.z));
|
|
|
|
c->setTakenDown(s.tookdown || (target && !s.source->target()));
|
|
|
|
c->turn(s.faceup);
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore game-specific information
|
|
|
|
setGameState( st->gameData );
|
|
|
|
|
|
|
|
delete st;
|
|
|
|
canvas()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::takeState()
|
|
|
|
{
|
|
|
|
kdDebug(11111) << "takeState\n";
|
|
|
|
|
|
|
|
State *n = getState();
|
|
|
|
|
|
|
|
if (!undoList.count()) {
|
|
|
|
emit updateMoves();
|
|
|
|
undoList.append(n);
|
|
|
|
} else {
|
|
|
|
State *old = undoList.last();
|
|
|
|
|
|
|
|
if (*old == *n) {
|
|
|
|
delete n;
|
|
|
|
n = 0;
|
|
|
|
} else {
|
|
|
|
emit updateMoves();
|
|
|
|
undoList.append(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n) {
|
|
|
|
if (isGameWon()) {
|
|
|
|
won();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (isGameLost() && !toldAboutLostGame) {
|
|
|
|
if ( ahint )
|
|
|
|
ahint->setEnabled( false );
|
|
|
|
if ( ademo )
|
|
|
|
ademo->setEnabled( false );
|
|
|
|
if ( aredeal )
|
|
|
|
aredeal->setEnabled( false );
|
|
|
|
TQTimer::singleShot(400, TQT_TQOBJECT(this), TQT_SIGNAL(gameLost()));
|
|
|
|
toldAboutLostGame = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!demoActive() && !waiting())
|
|
|
|
TQTimer::singleShot(TIME_BETWEEN_MOVES, TQT_TQOBJECT(this), TQT_SLOT(startAutoDrop()));
|
|
|
|
|
|
|
|
emit undoPossible(undoList.count() > 1 && !waiting());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::saveGame(TQDomDocument &doc) {
|
|
|
|
TQDomElement dealer = doc.createElement("dealer");
|
|
|
|
doc.appendChild(dealer);
|
|
|
|
dealer.setAttribute("id", _id);
|
|
|
|
dealer.setAttribute("number", TQString::number(gameNumber()));
|
|
|
|
TQString data = getGameState();
|
|
|
|
if (!data.isEmpty())
|
|
|
|
dealer.setAttribute("data", data);
|
|
|
|
dealer.setAttribute("moves", TQString::number(getMoves()));
|
|
|
|
|
|
|
|
bool taken[1000];
|
|
|
|
memset(taken, 0, sizeof(taken));
|
|
|
|
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Pile::RTTI) {
|
|
|
|
Pile *p = dynamic_cast<Pile*>(*it);
|
|
|
|
assert(p);
|
|
|
|
if (taken[p->index()]) {
|
|
|
|
kdDebug(11111) << "pile index " << p->index() << " taken twice\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
taken[p->index()] = true;
|
|
|
|
|
|
|
|
TQDomElement pile = doc.createElement("pile");
|
|
|
|
pile.setAttribute("index", p->index());
|
|
|
|
|
|
|
|
CardList cards = p->cards();
|
|
|
|
for (CardList::Iterator it = cards.begin();
|
|
|
|
it != cards.end();
|
|
|
|
++it)
|
|
|
|
{
|
|
|
|
TQDomElement card = doc.createElement("card");
|
|
|
|
card.setAttribute("suit", (*it)->suit());
|
|
|
|
card.setAttribute("value", (*it)->rank());
|
|
|
|
card.setAttribute("faceup", (*it)->isFaceUp());
|
|
|
|
card.setAttribute("x", (*it)->realX());
|
|
|
|
card.setAttribute("y", (*it)->realY());
|
|
|
|
card.setAttribute("z", (*it)->realZ());
|
|
|
|
card.setAttribute("name", (*it)->name());
|
|
|
|
pile.appendChild(card);
|
|
|
|
}
|
|
|
|
dealer.appendChild(pile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
TQDomElement eList = doc.createElement("undo");
|
|
|
|
|
|
|
|
TQPtrListIterator<State> it(undoList);
|
|
|
|
for (; it.current(); ++it)
|
|
|
|
{
|
|
|
|
State *n = it.current();
|
|
|
|
TQDomElement state = doc.createElement("state");
|
|
|
|
if (!n->gameData.isEmpty())
|
|
|
|
state.setAttribute("data", n->gameData);
|
|
|
|
TQDomElement cards = doc.createElement("cards");
|
|
|
|
for (TQValueList<CardState>::ConstIterator it2 = n->cards.begin();
|
|
|
|
it2 != n->cards.end(); ++it2)
|
|
|
|
{
|
|
|
|
TQDomElement item = doc.createElement("item");
|
|
|
|
(*it2).fillNode(item);
|
|
|
|
cards.appendChild(item);
|
|
|
|
}
|
|
|
|
state.appendChild(cards);
|
|
|
|
eList.appendChild(state);
|
|
|
|
}
|
|
|
|
dealer.appendChild(eList);
|
|
|
|
*/
|
|
|
|
// kdDebug(11111) << doc.toString() << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::openGame(TQDomDocument &doc)
|
|
|
|
{
|
|
|
|
unmarkAll();
|
|
|
|
TQDomElement dealer = doc.documentElement();
|
|
|
|
|
|
|
|
setGameNumber(dealer.attribute("number").toULong());
|
|
|
|
undoList.clear();
|
|
|
|
|
|
|
|
TQDomNodeList piles = dealer.elementsByTagName("pile");
|
|
|
|
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
|
|
|
|
CardList cards;
|
|
|
|
for (TQCanvasItemList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
if ((*it)->rtti() == Card::RTTI)
|
|
|
|
cards.append(static_cast<Card*>(*it));
|
|
|
|
|
|
|
|
Deck::deck()->collectAndShuffle();
|
|
|
|
|
|
|
|
for (TQCanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->rtti() == Pile::RTTI)
|
|
|
|
{
|
|
|
|
Pile *p = dynamic_cast<Pile*>(*it);
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
for (uint i = 0; i < piles.count(); ++i)
|
|
|
|
{
|
|
|
|
TQDomElement pile = piles.item(i).toElement();
|
|
|
|
if (pile.attribute("index").toInt() == p->index())
|
|
|
|
{
|
|
|
|
TQDomNodeList pcards = pile.elementsByTagName("card");
|
|
|
|
for (uint j = 0; j < pcards.count(); ++j)
|
|
|
|
{
|
|
|
|
TQDomElement card = pcards.item(j).toElement();
|
|
|
|
Card::Suit s = static_cast<Card::Suit>(card.attribute("suit").toInt());
|
|
|
|
Card::Rank v = static_cast<Card::Rank>(card.attribute("value").toInt());
|
|
|
|
|
|
|
|
for (CardList::Iterator it2 = cards.begin();
|
|
|
|
it2 != cards.end(); ++it2)
|
|
|
|
{
|
|
|
|
if ((*it2)->suit() == s && (*it2)->rank() == v) {
|
|
|
|
if (TQString((*it2)->name()) == "Diamonds Eight") {
|
|
|
|
kdDebug(11111) << i << " " << j << endl;
|
|
|
|
}
|
|
|
|
p->add(*it2);
|
|
|
|
(*it2)->setAnimated(false);
|
|
|
|
(*it2)->turn(card.attribute("faceup").toInt());
|
|
|
|
(*it2)->setX(card.attribute("x").toInt());
|
|
|
|
(*it2)->setY(card.attribute("y").toInt());
|
|
|
|
(*it2)->setZ(card.attribute("z").toInt());
|
|
|
|
(*it2)->tqsetVisible(p->isVisible());
|
|
|
|
cards.remove(it2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setGameState( dealer.attribute("data") );
|
|
|
|
|
|
|
|
if (undoList.count() > 1) {
|
|
|
|
setState(undoList.take(undoList.count() - 1));
|
|
|
|
takeState(); // copying it again
|
|
|
|
emit undoPossible(undoList.count() > 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit updateMoves();
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::undo()
|
|
|
|
{
|
|
|
|
unmarkAll();
|
|
|
|
stopDemo();
|
|
|
|
if (undoList.count() > 1) {
|
|
|
|
undoList.removeLast(); // the current state
|
|
|
|
setState(undoList.take(undoList.count() - 1));
|
|
|
|
emit updateMoves();
|
|
|
|
takeState(); // copying it again
|
|
|
|
emit undoPossible(undoList.count() > 1);
|
|
|
|
if ( toldAboutLostGame ) { // everything's possible again
|
|
|
|
if ( ahint )
|
|
|
|
ahint->setEnabled( true );
|
|
|
|
if ( ademo )
|
|
|
|
ademo->setEnabled( true );
|
|
|
|
toldAboutLostGame = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Pile *Dealer::findTarget(Card *c)
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
CardList empty;
|
|
|
|
empty.append(c);
|
|
|
|
for (PileList::ConstIterator it = piles.begin(); it != piles.end(); ++it)
|
|
|
|
{
|
|
|
|
if (!(*it)->target())
|
|
|
|
continue;
|
|
|
|
if ((*it)->legalAdd(empty))
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setWaiting(bool w)
|
|
|
|
{
|
|
|
|
if (w)
|
|
|
|
_waiting++;
|
|
|
|
else
|
|
|
|
_waiting--;
|
|
|
|
emit undoPossible(!waiting());
|
|
|
|
kdDebug(11111) << "setWaiting " << w << " " << _waiting << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setAutoDropEnabled(bool a)
|
|
|
|
{
|
|
|
|
_autodrop = a;
|
|
|
|
TQTimer::singleShot(TIME_BETWEEN_MOVES, TQT_TQOBJECT(this), TQT_SLOT(startAutoDrop()));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::startAutoDrop()
|
|
|
|
{
|
|
|
|
if (!autoDrop())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
|
|
|
|
for (TQCanvasItemList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
|
|
|
if ((*it)->animated()) {
|
|
|
|
TQTimer::singleShot(TIME_BETWEEN_MOVES, TQT_TQOBJECT(this), TQT_SLOT(startAutoDrop()));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(11111) << "startAutoDrop\n";
|
|
|
|
|
|
|
|
unmarkAll();
|
|
|
|
clearHints();
|
|
|
|
getHints();
|
|
|
|
for (HintList::ConstIterator it = hints.begin(); it != hints.end(); ++it) {
|
|
|
|
MoveHint *mh = *it;
|
|
|
|
if (mh->pile()->target() && mh->dropIfTarget() && !mh->card()->takenDown()) {
|
|
|
|
setWaiting(true);
|
|
|
|
Card *t = mh->card();
|
|
|
|
CardList cards = mh->card()->source()->cards();
|
|
|
|
while (cards.count() && cards.first() != t) cards.remove(cards.begin());
|
|
|
|
t->setAnimated(false);
|
|
|
|
t->turn(true);
|
|
|
|
int x = int(t->x());
|
|
|
|
int y = int(t->y());
|
|
|
|
t->source()->moveCards(cards, mh->pile());
|
|
|
|
t->move(x, y);
|
|
|
|
kdDebug(11111) << "autodrop " << t->name() << endl;
|
|
|
|
t->moveTo(int(t->source()->x()), int(t->source()->y()), int(t->z()), STEPS_AUTODROP);
|
|
|
|
connect(t, TQT_SIGNAL(stoped(Card*)), TQT_SLOT(waitForAutoDrop(Card*)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clearHints();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::waitForAutoDrop(Card * c) {
|
|
|
|
kdDebug(11111) << "waitForAutoDrop " << c->name() << endl;
|
|
|
|
setWaiting(false);
|
|
|
|
c->disconnect();
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
|
|
|
|
long Dealer::gameNumber() const
|
|
|
|
{
|
|
|
|
return gamenumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setGameNumber(long gmn)
|
|
|
|
{
|
|
|
|
// Deal in the range of 1 to INT_MAX.
|
|
|
|
gamenumber = ((gmn < 1) ? 1 : ((gmn > 0x7FFFFFFF) ? 0x7FFFFFFF : gmn));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::addPile(Pile *p)
|
|
|
|
{
|
|
|
|
piles.append(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::removePile(Pile *p)
|
|
|
|
{
|
|
|
|
piles.remove(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::stopDemo()
|
|
|
|
{
|
|
|
|
kdDebug(11111) << "stopDemo " << waiting() << " " << stop_demo_next << endl;
|
|
|
|
if (waiting()) {
|
|
|
|
stop_demo_next = true;
|
|
|
|
return;
|
|
|
|
} else stop_demo_next = false;
|
|
|
|
|
|
|
|
if (towait == (Card*)-1)
|
|
|
|
towait = 0;
|
|
|
|
|
|
|
|
if (towait) {
|
|
|
|
towait->disconnect();
|
|
|
|
towait = 0;
|
|
|
|
}
|
|
|
|
demotimer->stop();
|
|
|
|
if (ademo)
|
|
|
|
ademo->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::demoActive() const
|
|
|
|
{
|
|
|
|
return (towait || demotimer->isActive());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::toggleDemo()
|
|
|
|
{
|
|
|
|
if (demoActive()) {
|
|
|
|
stopDemo();
|
|
|
|
} else
|
|
|
|
demo();
|
|
|
|
}
|
|
|
|
|
|
|
|
class CardPtr
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Card *ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool operator <(const CardPtr &p1, const CardPtr &p2)
|
|
|
|
{
|
|
|
|
return ( p1.ptr->z() < p2.ptr->z() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::won()
|
|
|
|
{
|
|
|
|
if (_won)
|
|
|
|
return;
|
|
|
|
_won = true;
|
|
|
|
|
|
|
|
// update score, 'win' in demo mode also counts (keep it that way?)
|
|
|
|
{ // wrap in own scope to make KConfigGroupSave work
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
KConfigGroupSaver kcs(config, scores_group);
|
|
|
|
unsigned int n = config->readUnsignedNumEntry(TQString("won%1").tqarg(_id),0) + 1;
|
|
|
|
config->writeEntry(TQString("won%1").tqarg(_id),n);
|
|
|
|
n = config->readUnsignedNumEntry(TQString("winstreak%1").tqarg(_id),0) + 1;
|
|
|
|
config->writeEntry(TQString("winstreak%1").tqarg(_id),n);
|
|
|
|
unsigned int m = config->readUnsignedNumEntry(TQString("maxwinstreak%1").tqarg(_id),0);
|
|
|
|
if (n>m)
|
|
|
|
config->writeEntry(TQString("maxwinstreak%1").tqarg(_id),n);
|
|
|
|
config->writeEntry(TQString("loosestreak%1").tqarg(_id),0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort cards by increasing z
|
|
|
|
TQCanvasItemList list = canvas()->allItems();
|
|
|
|
TQValueList<CardPtr> cards;
|
|
|
|
for (TQCanvasItemList::ConstIterator it=list.begin(); it!=list.end(); ++it)
|
|
|
|
if ((*it)->rtti() == Card::RTTI) {
|
|
|
|
CardPtr p;
|
|
|
|
p.ptr = dynamic_cast<Card*>(*it);
|
|
|
|
assert(p.ptr);
|
|
|
|
cards.push_back(p);
|
|
|
|
}
|
|
|
|
qHeapSort(cards);
|
|
|
|
|
|
|
|
// disperse the cards everywhere
|
|
|
|
TQRect can(0, 0, canvas()->width(), canvas()->height());
|
|
|
|
TQValueList<CardPtr>::ConstIterator it = cards.begin();
|
|
|
|
for (; it != cards.end(); ++it) {
|
|
|
|
(*it).ptr->turn(true);
|
|
|
|
TQRect p(0, 0, (*it).ptr->width(), (*it).ptr->height());
|
|
|
|
int x, y;
|
|
|
|
do {
|
|
|
|
x = 3*canvas()->width()/2 - kapp->random() % (canvas()->width() * 2);
|
|
|
|
y = 3*canvas()->height()/2 - (kapp->random() % (canvas()->height() * 2));
|
|
|
|
p.moveTopLeft(TQPoint(x, y));
|
|
|
|
} while (can.intersects(p));
|
|
|
|
|
|
|
|
(*it).ptr->moveTo( x, y, 0, STEPS_WON);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool demo = demoActive();
|
|
|
|
stopDemo();
|
|
|
|
canvas()->update();
|
|
|
|
emit gameWon(demo);
|
|
|
|
}
|
|
|
|
|
|
|
|
MoveHint *Dealer::chooseHint()
|
|
|
|
{
|
|
|
|
if (hints.isEmpty())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (HintList::ConstIterator it = hints.begin(); it != hints.end(); ++it)
|
|
|
|
{
|
|
|
|
if ((*it)->pile()->target() && (*it)->dropIfTarget())
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hints[randseq.getLong(hints.count())];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::demo() {
|
|
|
|
if (waiting())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (stop_demo_next) {
|
|
|
|
stopDemo();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
stop_demo_next = false;
|
|
|
|
unmarkAll();
|
|
|
|
towait = (Card*)-1;
|
|
|
|
clearHints();
|
|
|
|
getHints();
|
|
|
|
demotimer->stop();
|
|
|
|
|
|
|
|
MoveHint *mh = chooseHint();
|
|
|
|
if (mh) {
|
|
|
|
// assert(mh->card()->source()->legalRemove(mh->card()));
|
|
|
|
|
|
|
|
CardList empty;
|
|
|
|
CardList cards = mh->card()->source()->cards();
|
|
|
|
bool after = false;
|
|
|
|
for (CardList::Iterator it = cards.begin(); it != cards.end(); ++it) {
|
|
|
|
if (*it == mh->card())
|
|
|
|
after = true;
|
|
|
|
if (after)
|
|
|
|
empty.append(*it);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!empty.isEmpty());
|
|
|
|
|
|
|
|
int *oldcoords = new int[2*empty.count()];
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (CardList::Iterator it = empty.begin(); it != empty.end(); ++it) {
|
|
|
|
Card *t = *it;
|
|
|
|
Q_ASSERT(!t->animated());
|
|
|
|
t->setAnimated(false);
|
|
|
|
t->turn(true);
|
|
|
|
oldcoords[i++] = int(t->realX());
|
|
|
|
oldcoords[i++] = int(t->realY());
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(mh->card()->source() != mh->pile());
|
|
|
|
// assert(mh->pile()->legalAdd(empty));
|
|
|
|
|
|
|
|
mh->card()->source()->moveCards(empty, mh->pile());
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
for (CardList::Iterator it = empty.begin(); it != empty.end(); ++it) {
|
|
|
|
Card *t = *it;
|
|
|
|
int x1 = oldcoords[i++];
|
|
|
|
int y1 = oldcoords[i++];
|
|
|
|
int x2 = int(t->realX());
|
|
|
|
int y2 = int(t->realY());
|
|
|
|
t->move(x1, y1);
|
|
|
|
t->moveTo(x2, y2, int(t->z()), STEPS_DEMO);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] oldcoords;
|
|
|
|
|
|
|
|
newDemoMove(mh->card());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
Card *t = demoNewCards();
|
|
|
|
if (t) {
|
|
|
|
newDemoMove(t);
|
|
|
|
} else if (isGameWon()) {
|
|
|
|
canvas()->update();
|
|
|
|
emit gameWon(true);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
stopDemo();
|
|
|
|
}
|
|
|
|
|
|
|
|
takeState();
|
|
|
|
}
|
|
|
|
|
|
|
|
Card *Dealer::demoNewCards()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::newDemoMove(Card *m)
|
|
|
|
{
|
|
|
|
towait = m;
|
|
|
|
connect(m, TQT_SIGNAL(stoped(Card*)), TQT_SLOT(waitForDemo(Card*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::waitForDemo(Card *t)
|
|
|
|
{
|
|
|
|
if (t == (Card*)-1)
|
|
|
|
return;
|
|
|
|
if (towait != t)
|
|
|
|
return;
|
|
|
|
t->disconnect();
|
|
|
|
towait = 0;
|
|
|
|
demotimer->start(250, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::isGameWon() const
|
|
|
|
{
|
|
|
|
for (PileList::ConstIterator it = piles.begin(); it != piles.end(); ++it)
|
|
|
|
{
|
|
|
|
if (!(*it)->target() && !(*it)->isEmpty())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::isGameLost() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::checkRemove( int, const Pile *, const Card *) const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Dealer::checkAdd( int, const Pile *, const CardList&) const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::drawPile(KPixmap &pixmap, Pile *pile, bool selected)
|
|
|
|
{
|
|
|
|
TQPixmap bg = myCanvas.backgroundPixmap();
|
|
|
|
TQRect bounding(int(pile->x()), int(pile->y()), cardMap::CARDX(), cardMap::CARDY());
|
|
|
|
|
|
|
|
pixmap.resize(bounding.width(), bounding.height());
|
|
|
|
pixmap.fill(TQt::white);
|
|
|
|
|
|
|
|
if (!bg.isNull()) {
|
|
|
|
for (int x=bounding.x()/bg.width();
|
|
|
|
x<(bounding.x()+bounding.width()+bg.width()-1)/bg.width(); x++)
|
|
|
|
{
|
|
|
|
for (int y=bounding.y()/bg.height();
|
|
|
|
y<(bounding.y()+bounding.height()+bg.height()-1)/bg.height(); y++)
|
|
|
|
{
|
|
|
|
int sx = 0;
|
|
|
|
int sy = 0;
|
|
|
|
int dx = x*bg.width()-bounding.x();
|
|
|
|
int dy = y*bg.height()-bounding.y();
|
|
|
|
int w = bg.width();
|
|
|
|
int h = bg.height();
|
|
|
|
if (dx < 0) {
|
|
|
|
sx = -dx;
|
|
|
|
dx = 0;
|
|
|
|
}
|
|
|
|
if (dy < 0) {
|
|
|
|
sy = -dy;
|
|
|
|
dy = 0;
|
|
|
|
}
|
|
|
|
bitBlt(TQT_TQPAINTDEVICE(&pixmap), dx, dy, TQT_TQPAINTDEVICE(&bg),
|
|
|
|
sx, sy, w, h, TQt::CopyROP, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float s = -0.4;
|
|
|
|
float n = -0.3;
|
|
|
|
|
|
|
|
int mid = TQMAX( TQMAX(midColor().red(), midColor().green()), midColor().blue());
|
|
|
|
|
|
|
|
// if it's too dark - light instead of dark
|
|
|
|
if (mid < 120) {
|
|
|
|
s *= -1;
|
|
|
|
n = 0.4;
|
|
|
|
}
|
|
|
|
|
|
|
|
KPixmapEffect::intensity(pixmap, selected ? s : n);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Dealer::freeCells() const
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
for (PileList::ConstIterator it = piles.begin(); it != piles.end(); ++it)
|
|
|
|
if ((*it)->isEmpty() && !(*it)->target())
|
|
|
|
n++;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::setAnchorName(const TQString &name)
|
|
|
|
{
|
|
|
|
kdDebug(11111) << "setAnchorname " << name << endl;
|
|
|
|
ac = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Dealer::anchorName() const { return ac; }
|
|
|
|
|
|
|
|
void Dealer::wheelEvent( TQWheelEvent *e )
|
|
|
|
{
|
|
|
|
TQWheelEvent ce( viewport()->mapFromGlobal( e->globalPos() ),
|
|
|
|
e->globalPos(), e->delta(), e->state());
|
|
|
|
viewportWheelEvent(&ce);
|
|
|
|
if ( !ce.isAccepted() ) {
|
|
|
|
if ( e->orientation() ==Qt::Horizontal && hScrollBarMode () == AlwaysOn )
|
|
|
|
TQApplication::sendEvent( horizontalScrollBar(), e);
|
|
|
|
else if (e->orientation() ==Qt::Vertical && vScrollBarMode () == AlwaysOn )
|
|
|
|
TQApplication::sendEvent( verticalScrollBar(), e);
|
|
|
|
} else {
|
|
|
|
e->accept();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::countGame()
|
|
|
|
{
|
|
|
|
if ( !_gameRecorded ) {
|
|
|
|
kdDebug(11111) << "counting game as played." << endl;
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
KConfigGroupSaver kcs(config, scores_group);
|
|
|
|
unsigned int Total = config->readUnsignedNumEntry(TQString("total%1").tqarg(_id),0);
|
|
|
|
++Total;
|
|
|
|
config->writeEntry(TQString("total%1").tqarg(_id),Total);
|
|
|
|
_gameRecorded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dealer::countLoss()
|
|
|
|
{
|
|
|
|
if ( _gameRecorded ) {
|
|
|
|
// update score
|
|
|
|
KConfig *config = kapp->config();
|
|
|
|
KConfigGroupSaver kcs(config, scores_group);
|
|
|
|
unsigned int n = config->readUnsignedNumEntry(TQString("loosestreak%1").tqarg(_id),0) + 1;
|
|
|
|
config->writeEntry(TQString("loosestreak%1").tqarg(_id),n);
|
|
|
|
unsigned int m = config->readUnsignedNumEntry(TQString("maxloosestreak%1").tqarg(_id),0);
|
|
|
|
if (n>m)
|
|
|
|
config->writeEntry(TQString("maxloosestreak%1").tqarg(_id),n);
|
|
|
|
config->writeEntry(TQString("winstreak%1").tqarg(_id),0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "dealer.moc"
|