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.
tdegames/kpat/card.cpp

381 lines
9.0 KiB

/******************************************************
Card.cpp -- support classes for patience type card games
Copyright (C) 1995 Paul Olav Tvete
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*******************************************************/
#include <math.h>
#include <assert.h>
#include <qpainter.h>
#include <kdebug.h>
#include "card.h"
#include "pile.h"
#include "cardmaps.h"
static const char *suit_names[] = {"Clubs", "Diamonds", "Hearts", "Spades"};
static const char *rank_names[] = {"Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Jack", "Queen", "King" };
// Run time type id
const int Card::RTTI = 1001;
Card::Card( Rank r, Suit s, QCanvas* _parent )
: QCanvasRectangle( _parent ),
m_suit( s ), m_rank( r ),
m_source(0), scaleX(1.0), scaleY(1.0), tookDown(false)
{
// Set the name of the card
// FIXME: i18n()
m_name = QString("%1 %2").arg(suit_names[s-1]).arg(rank_names[r-1]).utf8();
// Default for the card is face up, standard size.
m_faceup = true;
setSize( cardMap::CARDX(), cardMap::CARDY() );
m_destX = 0;
m_destY = 0;
m_destZ = 0;
m_flipping = false;
m_animSteps = 0;
m_flipSteps = 0;
}
Card::~Card()
{
// If the card is in a pile, remove it from there.
if (source())
source()->remove(this);
hide();
}
// ----------------------------------------------------------------
// Member functions regarding graphics
// Return the pixmap of the card
//
QPixmap Card::pixmap() const
{
return cardMap::self()->image( m_rank, m_suit );
}
// Turn the card if necessary. If the face gets turned up, the card
// is activated at the same time.
//
void Card::turn( bool _faceup )
{
if (m_faceup != _faceup) {
m_faceup = _faceup;
setActive(!isActive()); // abuse
}
}
// Draw the card on the painter 'p'.
//
void Card::draw( QPainter &p )
{
QPixmap side;
// Get the image to draw (front / back)
if( isFaceUp() )
side = cardMap::self()->image( m_rank, m_suit, isSelected());
else
side = cardMap::self()->backSide();
// Rescale the image if necessary.
if (scaleX <= 0.98 || scaleY <= 0.98) {
QWMatrix s;
s.scale( scaleX, scaleY );
side = side.xForm( s );
int xoff = side.width() / 2;
int yoff = side.height() / 2;
p.drawPixmap( int(x() + cardMap::CARDX()/2 - xoff),
int(y() + cardMap::CARDY()/2 - yoff), side );
} else
p.drawPixmap( int(x()), int(y()), side );
}
void Card::moveBy(double dx, double dy)
{
QCanvasRectangle::moveBy(dx, dy);
}
// Return the X of the cards real position. This is the destination
// of the animation if animated, and the current X otherwise.
//
int Card::realX() const
{
if (animated())
return m_destX;
else
return int(x());
}
// Return the Y of the cards real position. This is the destination
// of the animation if animated, and the current Y otherwise.
//
int Card::realY() const
{
if (animated())
return m_destY;
else
return int(y());
}
// Return the > of the cards real position. This is the destination
// of the animation if animated, and the current Z otherwise.
//
int Card::realZ() const
{
if (animated())
return m_destZ;
else
return int(z());
}
// Return the "face up" status of the card.
//
// This is the destination of the animation if animated and animation
// is more than half way, the original if animated and animation is
// less than half way, and the current "face up" status otherwise.
//
bool Card::realFace() const
{
if (animated() && m_flipping) {
bool face = isFaceUp();
if ( m_animSteps >= m_flipSteps / 2 - 1 )
return !face;
else
return face;
} else
return isFaceUp();
}
/// the following copyright is for the flipping code
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qt Palmtop Environment.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
// Used to create an illusion of the card being lifted while flipped.
static const double flipLift = 1.2;
// The current maximum Z value. This is used so that new cards always
// get placed on top of the old ones and don't get placed in the
// middle of a destination pile.
int Card::Hz = 0;
void Card::setZ(double z)
{
QCanvasRectangle::setZ(z);
if (z > Hz)
Hz = int(z);
}
// Start a move of the card using animation.
//
// 'steps' is the number of steps the animation should take.
//
void Card::moveTo(int x2, int y2, int z2, int steps)
{
m_destX = x2;
m_destY = y2;
m_destZ = z2;
double x1 = x();
double y1 = y();
double dx = x2 - x1;
double dy = y2 - y1;
if (!dx && !dy) {
setZ(z2);
return;
}
setZ(Hz++);
if (steps) {
// Ensure a good speed
while ( fabs(dx/steps)+fabs(dy/steps) < 5.0 && steps > 4 )
steps--;
setAnimated(true);
setVelocity(dx/steps, dy/steps);
m_animSteps = steps;
} else {
// _really_ fast
setAnimated(true);
setAnimated(false);
emit stoped(this);
}
}
// Animate a move to (x2, y2), and at the same time flip the card.
//
void Card::flipTo(int x2, int y2, int steps)
{
// Check that we are not already animating.
assert(!animated());
int x1 = (int)x();
int y1 = (int)y();
double dx = x2 - x1;
double dy = y2 - y1;
// Mark this animation as a flip as well.
m_flipping = true;
m_flipSteps = steps;
// Set the target of the animation
m_destX = x2;
m_destY = y2;
m_destZ = int(z());
// Let the card be above all others during the animation.
setZ(Hz++);
m_animSteps = steps;
setVelocity(dx/m_animSteps, dy/m_animSteps-flipLift);
setAnimated(TRUE);
}
// Advance a card animation one step. This function adds flipping of
// the card to the translation animation that QCanvasRectangle offers.
//
void Card::advance(int stage)
{
if ( stage==1 ) {
// If the animation is finished, emit stoped. (FIXME: name)
if ( m_animSteps-- <= 0 ) {
setAnimated(false);
emit stoped(this);
} else {
// Animation is not finished. Check for flipping and add
// that animation to the simple translation.
if ( m_flipping ) {
if ( m_animSteps > m_flipSteps / 2 ) {
// animSteps = flipSteps .. flipSteps/2 (flip up) -> 1..0
scaleX = ((double)m_animSteps/m_flipSteps-0.5)*2;
} else {
// animSteps = flipSteps/2 .. 0 (flip down) -> 0..1
scaleX = 1-((double)m_animSteps/m_flipSteps)*2;
}
if ( m_animSteps == m_flipSteps / 2-1 ) {
setYVelocity(yVelocity()+flipLift*2);
turn( !isFaceUp() );
}
}
}
}
// Animate the translation of the card.
QCanvasRectangle::advance(stage);
}
// Set 'animated' status to a new value, and set secondary values as
// well.
//
void Card::setAnimated(bool anim)
{
// If no more animation, reset some other values as well.
if (animated() && !anim) {
// Reset all things that might have changed during the animation.
scaleX = 1.0;
scaleY = 1.0;
m_flipping = FALSE;
setVelocity(0, 0);
// Move the card to its destination immediately.
move(m_destX, m_destY);
setZ(m_destZ);
}
QCanvasRectangle::setAnimated(anim);
}
void Card::setTakenDown(bool td)
{
if (td)
kdDebug(11111) << "took down " << name() << endl;
tookDown = td;
}
bool Card::takenDown() const
{
return tookDown;
}
// Get the card to the top.
void Card::getUp(int steps)
{
m_destZ = int(z());
m_destX = int(x());
m_destY = int(y());
setZ(Hz+1);
// Animation
m_animSteps = steps;
setVelocity(0, 0);
setAnimated(TRUE);
}
#include "card.moc"