initial commit

This commit is contained in:
Max-Wilhelm Bruker 2009-03-13 22:50:41 +01:00
commit a11f93df4d
99 changed files with 7493 additions and 0 deletions

View file

@ -0,0 +1,203 @@
#include "carddatabase.h"
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QTextStream>
CardInfo::CardInfo(const QString &_name, const QString &_manacost, const QString &_cardtype, const QString &_powtough, const QStringList &_text)
: name(_name), manacost(_manacost), cardtype(_cardtype), powtough(_powtough), text(_text), pixmap(NULL)
{
}
CardInfo::CardInfo(QDataStream &stream)
: pixmap(NULL)
{
stream >> name
>> editions
>> manacost
>> cardtype
>> powtough
>> text;
}
CardInfo::~CardInfo()
{
if (pixmap)
qDebug(QString("Deleting pixmap for %1").arg(name).toLatin1());
delete pixmap;
}
void CardInfo::addEdition(const QString &edition)
{
if (!editions.contains(edition))
editions << edition;
}
QPixmap *CardInfo::getPixmap()
{
if (pixmap)
return pixmap;
pixmap = new QPixmap();
if (getName().isEmpty()) {
pixmap->load("../pics/back.jpg");
return pixmap;
}
qDebug(QString("CardDatabase: loading pixmap for %1").arg(getName()).toLatin1());
for (int i = 0; i < editions.size(); i++) {
/* Fire // Ice */
if (pixmap->load(QString("../pics/%1/%2.full.jpg").arg(editions.at(i)).arg(getName().replace(" // ", ""))))
return pixmap;
if (pixmap->load(QString("../pics/%1/%2%3.full.jpg").arg(editions.at(i)).arg(getName().replace(" // ", "")).arg(1)))
return pixmap;
}
pixmap->load("../pics/none.jpg");
return pixmap;
}
void CardInfo::saveToStream(QDataStream &stream)
{
stream << name
<< editions
<< manacost
<< cardtype
<< powtough
<< text;
}
CardDatabase::CardDatabase()
{
}
CardDatabase::~CardDatabase()
{
clear();
}
void CardDatabase::clear()
{
QHashIterator<QString, CardInfo *> i(hash);
while (i.hasNext()) {
i.next();
delete i.value();
}
hash.clear();
}
CardInfo *CardDatabase::getCard(const QString &cardName)
{
if (hash.contains(cardName))
return hash.value(cardName);
else {
qDebug(QString("CardDatabase: card not found: %1").arg(cardName).toLatin1());
CardInfo *newCard = new CardInfo(cardName);
newCard->addEdition("TK");
hash.insert(cardName, newCard);
return newCard;
}
}
void CardDatabase::importOracle()
{
clear();
QDir dir("../db");
// XXX User soll selber auswählen können, welche Karten ihm am besten gefallen.
// XXX Muss momentan schmutzig über Zahlen vor den Dateinamen gemacht werden.
dir.setSorting(QDir::Name | QDir::IgnoreCase);
QFileInfoList files = dir.entryInfoList(QStringList() << "*.txt");
for (int k = 0; k < files.size(); k++) {
QFileInfo i = files[k];
QString edition = i.fileName().mid(i.fileName().indexOf('_') + 1);
edition = edition.left(edition.indexOf('.'));
QFile file(i.filePath());
file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
while (!in.atEnd()) {
QString cardname = in.readLine();
QString manacost = in.readLine();
QString cardtype, powtough;
QStringList text;
if (manacost.contains("Land", Qt::CaseInsensitive)) {
cardtype = manacost;
manacost.clear();
} else {
cardtype = in.readLine();
powtough = in.readLine();
// Dirty hack.
// Cards to test: Any creature, any basic land, Ancestral Vision, Fire // Ice.
if (!powtough.contains("/") || powtough.size() > 5) {
text << powtough;
powtough = QString();
}
}
QString line = in.readLine();
while (!line.isEmpty()) {
text << line;
line = in.readLine();
}
CardInfo *card;
if (hash.contains(cardname))
card = hash.value(cardname);
else {
card = new CardInfo(cardname, manacost, cardtype, powtough, text);
hash.insert(cardname, card);
}
card->addEdition(edition);
}
}
qDebug(QString("CardDatabase: %1 cards imported").arg(hash.size()).toLatin1());
CardInfo *empty = new CardInfo();
empty->getPixmap(); // cache pixmap for card back
hash.insert("", empty);
}
int CardDatabase::loadFromFile(const QString &fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_4);
quint32 _magicNumber, _fileVersion, cardCount;
in >> _magicNumber
>> _fileVersion
>> cardCount;
if (_magicNumber != magicNumber)
return -1;
if (_fileVersion != fileVersion)
return -2;
clear();
hash.reserve(cardCount);
for (unsigned int i = 0; i < cardCount; i++) {
CardInfo *newCard = new CardInfo(in);
hash.insert(newCard->getName(), newCard);
}
return cardCount;
}
bool CardDatabase::saveToFile(const QString &fileName)
{
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_4);
out << (quint32) magicNumber
<< (quint32) fileVersion
<< (quint32) hash.size();
QHashIterator<QString, CardInfo *> i(hash);
while (i.hasNext()) {
i.next();
i.value()->saveToStream(out);
}
return true;
}

View file

@ -0,0 +1,51 @@
#ifndef CARDDATABASE_H
#define CARDDATABASE_H
#include <QHash>
#include <QPixmap>
#include <QDataStream>
class CardInfo {
private:
QString name;
QStringList editions;
QString manacost;
QString cardtype;
QString powtough;
QStringList text;
QPixmap *pixmap;
public:
CardInfo(const QString &_name = QString(),
const QString &_manacost = QString(),
const QString &_cardtype = QString(),
const QString &_powtough = QString(),
const QStringList &_text = QStringList());
CardInfo(QDataStream &stream);
~CardInfo();
QString getName() const { return name; }
QStringList getEditions() const { return editions; }
QString getManacost() const { return manacost; }
QString getCardType() const { return cardtype; }
QString getPowTough() const { return powtough; }
QStringList getText() const { return text; }
void addEdition(const QString &edition);
QPixmap *getPixmap();
void saveToStream(QDataStream &stream);
};
class CardDatabase {
private:
QHash<QString, CardInfo *> hash;
static const unsigned int magicNumber = 0x12345678;
static const unsigned int fileVersion = 1;
public:
CardDatabase();
~CardDatabase();
void clear();
CardInfo *getCard(const QString &cardName = QString());
void importOracle();
int loadFromFile(const QString &fileName);
bool saveToFile(const QString &fileName);
};
#endif

View file

@ -0,0 +1,97 @@
#include "carddragitem.h"
#include "playerzone.h"
#include <QtGui>
CardDragItem::CardDragItem(QGraphicsScene *scene, PlayerZone *_startZone, QPixmap *_image, int _id, const QPointF &_hotSpot, QGraphicsItem *parent)
: QGraphicsItem(parent), image(_image), id(_id), hotSpot(_hotSpot), startZone(_startZone)
{
if ((hotSpot.x() < 0) || (hotSpot.y() < 0)) {
qDebug(QString("CardDragItem: coordinate overflow: x = %1, y = %2").arg(hotSpot.x()).arg(hotSpot.y()).toLatin1());
hotSpot = QPointF();
} else if ((hotSpot.x() > CARD_WIDTH) || (hotSpot.y() > CARD_HEIGHT)) {
qDebug(QString("CardDragItem: coordinate overflow: x = %1, y = %2").arg(hotSpot.x()).arg(hotSpot.y()).toLatin1());
hotSpot = QPointF(CARD_WIDTH, CARD_HEIGHT);
}
setZValue(2000000000);
setCacheMode(DeviceCoordinateCache);
scene->addItem(this);
}
CardDragItem::~CardDragItem()
{
qDebug("CardDragItem destructor");
}
QRectF CardDragItem::boundingRect() const
{
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
}
void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// Q_UNUSED(option);
Q_UNUSED(widget);
QRectF foo = option->matrix.mapRect(boundingRect());
QPixmap bar = image->scaled(foo.width(), foo.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
painter->drawPixmap(boundingRect(), bar, bar.rect());
// painter->drawPixmap(boundingRect(), *image, QRectF(0, 0, image->width(), image->height()));
}
void CardDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF sp = event->scenePos();
QList<QGraphicsItem *> colliding = scene()->items(sp);
PlayerZone *cursorZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--) {
if ((cursorZone = qgraphicsitem_cast<PlayerZone *>(colliding.at(i)))) {
if (cursorZone->getName() == "table") {
QPointF cp = cursorZone->scenePos();
QPointF localpos = sp - hotSpot - cp;
setPos(QPointF(round(localpos.x() / RASTER_WIDTH) * RASTER_WIDTH, round(localpos.y() / RASTER_HEIGHT) * RASTER_HEIGHT) + cp);
} else
setPos(sp - hotSpot);
break;
}
}
event->accept();
}
void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
setCursor(Qt::OpenHandCursor);
QGraphicsScene *sc = scene();
QPointF sp = scenePos();
sc->removeItem(this);
QList<QGraphicsItem *> colliding = sc->items(event->scenePos());
qDebug(QString("drop: %1 collisions").arg(colliding.size()).toLatin1());
PlayerZone *dropZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--) {
QRectF bbox = colliding.at(i)->boundingRect();
qDebug(QString("bbox x %1 y %2 w %3 h %4").arg(bbox.x()).arg(bbox.y()).arg(bbox.width()).arg(bbox.height()).toLatin1());
if ((dropZone = qgraphicsitem_cast<PlayerZone *>(colliding.at(i)))) {
qDebug("zone found");
break;
}
}
if (dropZone) {
dropZone->handleDropEvent(id, startZone, (sp - dropZone->pos()).toPoint());
QList<QGraphicsItem *> childList = childItems();
for (int i = 0; i < childList.size(); i++) {
CardDragItem *c = qgraphicsitem_cast<CardDragItem *>(childList.at(i));
if (!c)
QMessageBox::critical(0, "fehler", "null");
dropZone->handleDropEvent(c->id, startZone, (sp - dropZone->pos() + c->pos()).toPoint());
}
} else
QMessageBox::critical(0, "fehler", "fehler");
event->accept();
}

View file

@ -0,0 +1,28 @@
#ifndef CARDDRAGITEM_H
#define CARDDRAGITEM_H
#include "carditem.h"
class QGraphicsScene;
class PlayerZone;
class CardDragItem : public QGraphicsItem {
private:
QPixmap *image;
int id;
QPointF hotSpot;
PlayerZone *startZone;
public:
enum { Type = typeCardDrag };
int type() const { return Type; }
CardDragItem(QGraphicsScene *scene, PlayerZone *_startZone, QPixmap *_image, int _id, const QPointF &_hotSpot, QGraphicsItem *parent = 0);
~CardDragItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QPointF getHotSpot() const { return hotSpot; }
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};
#endif

View file

@ -0,0 +1,61 @@
#include "cardinfowidget.h"
#include <QGridLayout>
#include <QLabel>
#include <QTextEdit>
CardInfoWidget::CardInfoWidget(CardDatabase *_db, QWidget *parent)
: QFrame(parent), db(_db), aspectratio(0)
{
cardPicture = new QLabel();
cardPicture->setAlignment(Qt::AlignCenter);
nameLabel1 = new QLabel(tr("Name:"));
nameLabel2 = new QLabel();
manacostLabel1 = new QLabel(tr("Mana cost:"));
manacostLabel2 = new QLabel();
cardtypeLabel1 = new QLabel(tr("Card type:"));
cardtypeLabel2 = new QLabel();
powtoughLabel1 = new QLabel(tr("P / T:"));
powtoughLabel2 = new QLabel();
textLabel = new QTextEdit();
textLabel->setReadOnly(true);
QGridLayout *grid = new QGridLayout(this);
grid->addWidget(cardPicture, 0, 0, 1, 2);
grid->addWidget(nameLabel1, 1, 0);
grid->addWidget(nameLabel2, 1, 1);
grid->addWidget(manacostLabel1, 2, 0);
grid->addWidget(manacostLabel2, 2, 1);
grid->addWidget(cardtypeLabel1, 3, 0);
grid->addWidget(cardtypeLabel2, 3, 1);
grid->addWidget(powtoughLabel1, 4, 0);
grid->addWidget(powtoughLabel2, 4, 1);
grid->addWidget(textLabel, 5, 0, -1, 2);
grid->setRowStretch(5, 1);
setFrameStyle(QFrame::Panel | QFrame::Raised);
}
void CardInfoWidget::setCard(CardInfo *card)
{
if (!card)
return;
QPixmap *pixmap = card->getPixmap();
if (aspectratio == 0)
aspectratio = (double) pixmap->height() / pixmap->width();
double w = width() * 2.0 / 3.0;
cardPicture->setPixmap(pixmap->scaled((int) w, (int) (w * aspectratio), Qt::KeepAspectRatio, Qt::SmoothTransformation));
nameLabel2->setText(card->getName());
manacostLabel2->setText(card->getManacost());
cardtypeLabel2->setText(card->getCardType());
powtoughLabel2->setText(card->getPowTough());
textLabel->setText(card->getText().join("\n"));
}
void CardInfoWidget::setCard(const QString &cardName)
{
setCard(db->getCard(cardName));
}

View file

@ -0,0 +1,29 @@
#ifndef CARDINFOWIDGET_H
#define CARDINFOWIDGET_H
#include "carddatabase.h"
#include <QFrame>
class QLabel;
class QTextEdit;
class CardInfoWidget : public QFrame {
Q_OBJECT
private:
CardDatabase *db;
double aspectratio;
QLabel *cardPicture;
QLabel *nameLabel1, *nameLabel2;
QLabel *manacostLabel1, *manacostLabel2;
QLabel *cardtypeLabel1, *cardtypeLabel2;
QLabel *powtoughLabel1, *powtoughLabel2;
QTextEdit *textLabel;
public:
CardInfoWidget(CardDatabase *_db, QWidget *parent = 0);
public slots:
void setCard(CardInfo *card);
void setCard(const QString &cardName);
};
#endif

202
cockatrice/src/carditem.cpp Normal file
View file

@ -0,0 +1,202 @@
#include <QApplication>
#include <QtGui>
#include "carditem.h"
#include "carddragitem.h"
#include "carddatabase.h"
#include "playerzone.h"
#include "tablezone.h"
#include "player.h"
CardItem::CardItem(CardDatabase *_db, const QString &_name, int _cardid, QGraphicsItem *parent)
: QGraphicsItem(parent), db(_db), name(_name), id(_cardid), tapped(false), attacking(false), facedown(false), counters(0), dragItem(NULL)
{
width = CARD_WIDTH;
height = CARD_HEIGHT;
image = db->getCard(name)->getPixmap();
setCursor(Qt::OpenHandCursor);
setFlag(ItemIsSelectable);
setAcceptsHoverEvents(true);
setCacheMode(DeviceCoordinateCache);
}
CardItem::~CardItem()
{
qDebug(QString("CardItem destructor: %1").arg(name).toLatin1());
}
QRectF CardItem::boundingRect() const
{
return QRectF(0, 0, width, height);
}
void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
QRectF foo = option->matrix.mapRect(boundingRect());
qDebug(QString("%1: w=%2,h=%3").arg(name).arg(foo.width()).arg(foo.height()).toLatin1());
QPixmap bar = image->scaled((int) foo.width(), (int) foo.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
// painter->drawPixmap(boundingRect(), *image, QRectF(0, 0, image->width(), image->height()));
painter->drawPixmap(boundingRect(), bar, bar.rect());
if (isSelected()) {
painter->setPen(QPen(QColor("red")));
painter->drawRect(QRectF(1, 1, width - 2, height - 2));
}
if (counters) {
painter->setFont(QFont("Times", 32, QFont::Bold));
painter->setPen(QPen(QColor("black")));
painter->setBackground(QBrush(QColor(255, 255, 255, 100)));
painter->setBackgroundMode(Qt::OpaqueMode);
painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(counters));
}
painter->restore();
}
void CardItem::setName(const QString &_name)
{
name = _name;
image = db->getCard(name)->getPixmap();
update(boundingRect());
}
void CardItem::setTapped(bool _tapped)
{
tapped = _tapped;
if (tapped)
setTransform(QTransform().translate((float) width / 2, (float) height / 2).rotate(90).translate((float) -width / 2, (float) -height / 2));
else
setTransform(QTransform());
update(boundingRect());
}
void CardItem::setAttacking(bool _attacking)
{
attacking = _attacking;
update(boundingRect());
}
void CardItem::setFacedown(bool _facedown)
{
facedown = _facedown;
update(boundingRect());
}
void CardItem::setCounters(int _counters)
{
counters = _counters;
update(boundingRect());
}
void CardItem::setAnnotation(const QString &_annotation)
{
annotation = _annotation;
update(boundingRect());
}
void CardItem::resetState()
{
attacking = false;
facedown = false;
counters = 0;
annotation = QString();
setTapped(false);
update(boundingRect());
}
CardDragItem *CardItem::createDragItem(PlayerZone *startZone, int _id, const QPointF &_pos, const QPointF &_scenePos)
{
dragItem = new CardDragItem(scene(), startZone, image, _id, _pos);
dragItem->setPos(_scenePos - dragItem->getHotSpot());
return dragItem;
}
void CardItem::deleteDragItem()
{
delete dragItem;
dragItem = NULL;
}
void CardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (!isSelected()) {
scene()->clearSelection();
setSelected(true);
}
if (event->button() == Qt::LeftButton) {
setCursor(Qt::ClosedHandCursor);
} else if (event->button() == Qt::RightButton) {
qgraphicsitem_cast<PlayerZone *>(parentItem())->getPlayer()->showCardMenu(event->screenPos());
}
event->accept();
}
void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance())
return;
createDragItem((PlayerZone *) parentItem(), id, event->pos(), event->scenePos());
dragItem->grabMouse();
QList<QGraphicsItem *> sel = scene()->selectedItems();
for (int i = 0; i < sel.size(); i++) {
CardItem *c = (CardItem *) sel.at(i);
if (c == this)
continue;
CardDragItem *drag = new CardDragItem(scene(), (PlayerZone *) parentItem(), c->getImage(), c->getId(), QPointF(), dragItem);
drag->setPos(c->pos() - pos());
}
setCursor(Qt::OpenHandCursor);
}
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::OpenHandCursor);
}
void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
if (!isSelected()) {
// Unselect all items, then select this one
scene()->setSelectionArea(QPainterPath());
setSelected(true);
}
event->accept();
PlayerZone *zone = (PlayerZone *) parentItem();
// Do nothing if the card belongs to another player
if (!zone->getPlayer()->getLocal())
return;
if (zone->getHasCardAttr())
((TableZone *) zone)->toggleTapped();
}
void CardItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
((PlayerZone *) parentItem())->hoverCardEvent(this);
QGraphicsItem::hoverEnterEvent(event);
}
void CardItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsItem::hoverLeaveEvent(event);
}
QVariant CardItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSelectedChange) {
// XXX
return value;
} else if (change == ItemSelectedHasChanged) {
update();
return value;
} else
return QGraphicsItem::itemChange(change, value);
}

81
cockatrice/src/carditem.h Normal file
View file

@ -0,0 +1,81 @@
#ifndef CARDITEM_H
#define CARDITEM_H
#include <QGraphicsItem>
class CardDatabase;
class CardDragItem;
class PlayerZone;
const int CARD_WIDTH = 72;
const int CARD_HEIGHT = 102;
const int RASTER_WIDTH = 36;
const int RASTER_HEIGHT = 34;
/*
const int CARD_WIDTH = 72;
const int CARD_HEIGHT = 108;
const int RASTER_WIDTH = 36;
const int RASTER_HEIGHT = 36;
*/
const int MAX_COUNTERS_ON_CARD = 999;
enum CardItemType {
typeCard = QGraphicsItem::UserType + 1,
typeCardDrag = QGraphicsItem::UserType + 2,
typeZone = QGraphicsItem::UserType + 3,
typeOther = QGraphicsItem::UserType + 4
};
class CardItem : public QGraphicsItem {
private:
CardDatabase *db;
QString name;
int id;
int width, height;
QPixmap *image;
bool tapped;
bool attacking;
bool facedown;
int counters;
QString annotation;
CardDragItem *dragItem;
public:
enum { Type = typeCard };
int type() const { return Type; }
CardItem(CardDatabase *_db, const QString &_name, int _cardid, QGraphicsItem *parent = 0);
~CardItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
int getId() const { return id; }
void setId(int _id) { id = _id; }
QString getName() const { return name; }
void setName(const QString &_name = QString());
QPixmap *getImage() const { return image; }
bool getTapped() const { return tapped; }
void setTapped(bool _tapped);
bool getAttacking() const { return attacking; }
void setAttacking(bool _attacking);
bool getFacedown() const { return facedown; }
void setFacedown(bool _facedown);
int getCounters() const { return counters; }
void setCounters(int _counters);
QString getAnnotation() const { return annotation; }
void setAnnotation(const QString &_annotation);
void resetState();
CardDragItem *createDragItem(PlayerZone *startZone, int _id, const QPointF &_pos, const QPointF &_scenePos);
void deleteDragItem();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
};
#endif

View file

@ -0,0 +1,31 @@
#include "cardlist.h"
CardList::CardList(bool _contentsKnown)
: QList<CardItem *>(), contentsKnown(_contentsKnown)
{
}
CardItem *CardList::findCard(const int id, const bool remove, int *position)
{
if (!contentsKnown) {
if (empty())
return 0;
CardItem *temp = at(0);
if (remove)
removeAt(0);
if (position)
*position = id;
return temp;
} else
for (int i = 0; i < size(); i++) {
CardItem *temp = at(i);
if (temp->getId() == id) {
if (remove)
removeAt(i);
if (position)
*position = i;
return temp;
}
}
return 0;
}

16
cockatrice/src/cardlist.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef CARDLIST_H
#define CARDLIST_H
#include "carditem.h"
#include <QList>
class CardList : public QList<CardItem *> {
protected:
bool contentsKnown;
public:
CardList(bool _contentsKnown);
CardItem *findCard(const int id, const bool remove, int *position = NULL);
bool getContentsKnown() const { return contentsKnown; }
};
#endif

322
cockatrice/src/client.cpp Normal file
View file

@ -0,0 +1,322 @@
#include <QTimer>
#include "client.h"
Client::Client(QObject *parent)
: QObject(parent)
{
timer = new QTimer(this);
timer->setInterval(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(checkTimeout()));
MsgId = 0;
status = StatusDisconnected;
socket = new QTcpSocket(this);
socket->setTextModeEnabled(true);
connect(socket, SIGNAL(connected()), this, SLOT(slotConnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readLine()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError)));
}
Client::~Client()
{
delete socket;
}
void Client::checkTimeout()
{
QListIterator<PendingCommand *> i(PendingCommands);
while (i.hasNext()) {
PendingCommand *c = i.next();
c->incTime();
if (c->timeout()) {
disconnectFromServer();
emit serverTimeout();
return;
}
}
}
void Client::slotSocketError(QAbstractSocket::SocketError error)
{
emit logSocketError(socket->errorString());
disconnectFromServer();
}
void Client::slotConnected()
{
timer->start();
setStatus(StatusAwaitingWelcome);
}
void Client::readLine()
{
QString line;
for (;;) {
if (!socket->canReadLine())
break;
line = QString(socket->readLine()).trimmed();
if (line.isNull())
break;
qDebug(QString("readLine: %1").arg(line).toLatin1());
QStringList values = line.split("|");
QString prefix = values.takeFirst();
// prefix is one of {welcome, private, public, resp, list_games, list_players, list_counters, list_zones, dump_zone}
if (!(prefix.compare("private") && prefix.compare("public"))) {
ServerEventData *event = new ServerEventData(line);
if (event->getEventType() == eventPlayerId) {
QStringList data = event->getEventData();
if (data.size() != 2) {
// XXX
}
bool ok;
int id = data[0].toInt(&ok);
if (!ok) {
// XXX
}
delete event;
emit playerIdReceived(id, data[1]);
} else
emit gameEvent(event);
} else if (!prefix.compare("resp")) {
bool ok;
int msgid = values.takeFirst().toInt(&ok);
if (!ok) {
// XXX
}
if (values.empty()) {
// XXX
}
ok = !values.takeFirst().compare("ok");
// XXX
ServerErrorMessage message = msgNone;
// Update list of pending commands
QListIterator<PendingCommand *> i(PendingCommands);
bool found = false;
PendingCommand *c;
while (i.hasNext()) {
c = i.next();
if (c->getMsgId() == msgid) {
found = true;
QString cmd = c->getCmd();
if (cmd.startsWith("submit_deck"))
readyStart();
break;
}
}
if (found) {
PendingCommands.removeAt(PendingCommands.indexOf(c));
delete c;
}
emit responseReceived(new ServerResponse(msgid, ok, message));
} else if (!(prefix.compare("list_games")
&& prefix.compare("list_players")
&& prefix.compare("list_counters")
&& prefix.compare("list_zones")
&& prefix.compare("dump_zone")
&& prefix.compare("welcome"))) {
int cmdid = values.takeFirst().toInt();
if (!values[0].compare(".")) {
QListIterator<QStringList> i(msgbuf);
QList<ServerGame *> gamelist;
QList<ServerPlayer *> playerlist;
QList<ServerZone *> zonelist;
QList<ServerZoneCard *> zonedump;
QStringList welcomemsg;
while (i.hasNext()) {
QStringList val = i.next();
// XXX Parametergültigkeit überprüfen
if (!prefix.compare("list_games"))
gamelist << new ServerGame(val[0], val[1], val[2].toInt(), val[3].toInt(), val[4].toInt());
else if (!prefix.compare("list_players"))
playerlist << new ServerPlayer(val[0].toInt(), val[1]);
else if (!prefix.compare("list_counters"))
{ }
else if (!prefix.compare("list_zones"))
zonelist << new ServerZone(val[0], val[1] == "1", val[2] == "1", val[3].toInt());
else if (!prefix.compare("dump_zone"))
zonedump << new ServerZoneCard(val[0].toInt(), val[1], val[2].toInt(), val[3].toInt(), val[4].toInt(), val[5] == "1", val[6]);
else if (!prefix.compare("welcome"))
welcomemsg << val[0];
}
if (!prefix.compare("list_games"))
emit gameListReceived(gamelist);
else if (!prefix.compare("list_players"))
emit playerListReceived(playerlist);
else if (!prefix.compare("list_counters"))
{ }
else if (!prefix.compare("list_zones"))
emit zoneListReceived(cmdid, zonelist);
else if (!prefix.compare("dump_zone"))
emit zoneDumpReceived(cmdid, zonedump);
else if (!prefix.compare("welcome")) {
emit welcomeMsgReceived(welcomemsg);
setStatus(StatusConnected);
setName(PlayerName);
}
msgbuf.clear();
} else
msgbuf << values;
} else {
// XXX
}
}
}
void Client::setStatus(const ProtocolStatus _status)
{
status = _status;
emit statusChanged(_status);
}
void Client::msg(const QString &s)
{
qDebug(QString("msg gibt aus: %1").arg(s).toLatin1());
QTextStream stream(socket);
stream.setCodec("UTF-8");
stream << s << endl;
stream.flush();
socket->flush();
}
int Client::cmd(const QString &s)
{
msg(QString("%1|%2").arg(++MsgId).arg(s));
PendingCommands << new PendingCommand(s, MsgId);
return MsgId;
}
void Client::connectToServer(const QString &hostname, unsigned int port, const QString &playername)
{
PlayerName = playername;
socket->connectToHost(hostname, port);
setStatus(StatusConnecting);
}
void Client::disconnectFromServer()
{
timer->stop();
PendingCommands.clear();
setStatus(StatusDisconnected);
socket->close();
}
int Client::listGames()
{
return cmd("list_games");
}
int Client::listPlayers()
{
return cmd("list_players");
}
int Client::createGame(const QString &name, const QString &description, const QString &password, unsigned int maxPlayers)
{
return cmd(QString("create_game|%1|%2|%3|%4").arg(name).arg(description).arg(password).arg(maxPlayers));
}
int Client::joinGame(const QString &name, const QString &password)
{
return cmd(QString("join_game|%1|%2").arg(name).arg(password));
}
int Client::leaveGame()
{
return cmd("leave_game");
}
int Client::setName(const QString &name)
{
return cmd(QString("set_name|%1").arg(name));
}
int Client::say(const QString &s)
{
return cmd(QString("say|%1").arg(s));
}
int Client::shuffle()
{
return cmd("shuffle");
}
int Client::rollDice(unsigned int sides)
{
return cmd(QString("roll_dice|%1").arg(sides));
}
int Client::drawCards(unsigned int number)
{
return cmd(QString("draw_cards|%1").arg(number));
}
int Client::moveCard(int cardid, const QString &startzone, const QString &targetzone, int x, int y)
{
// if startzone is public: cardid is the card's id
// else: cardid is the position of the card in the zone (e.g. deck)
return cmd(QString("move_card|%1|%2|%3|%4|%5").arg(cardid).arg(startzone).arg(targetzone).arg(x).arg(y));
}
int Client::createToken(const QString &zone, const QString &name, const QString &powtough, int x, int y)
{
return cmd(QString("create_token|%1|%2|%3|%4|%5").arg(zone).arg(name).arg(powtough).arg(x).arg(y));
}
int Client::setCardAttr(const QString &zone, int cardid, const QString &aname, const QString &avalue)
{
return cmd(QString("set_card_attr|%1|%2|%3|%4").arg(zone).arg(cardid).arg(aname).arg(avalue));
}
int Client::submitDeck(const QStringList &deck)
{
int retval = cmd("submit_deck");
QStringListIterator i(deck);
while (i.hasNext())
msg(i.next());
msg(".");
return retval;
}
int Client::readyStart()
{
return cmd("ready_start");
}
int Client::incCounter(const QString &counter, int delta)
{
return cmd(QString("inc_counter|%1|%2").arg(counter).arg(delta));
}
int Client::setCounter(const QString &counter, int value)
{
return cmd(QString("set_counter|%1|%2").arg(counter).arg(value));
}
int Client::delCounter(const QString &counter)
{
return cmd(QString("del_counter|%1").arg(counter));
}
int Client::setActivePlayer(int player)
{
return cmd(QString("set_active_player|%1").arg(player));
}
int Client::setActivePhase(int phase)
{
return cmd(QString("set_active_phase|%1").arg(phase));
}
int Client::dumpZone(int player, const QString &zone, int numberCards)
{
return cmd(QString("dump_zone|%1|%2|%3").arg(player).arg(zone).arg(numberCards));
}

86
cockatrice/src/client.h Normal file
View file

@ -0,0 +1,86 @@
#ifndef CLIENT_H
#define CLIENT_H
#include "servereventdata.h"
#include "serverresponse.h"
#include "servergame.h"
#include "serverplayer.h"
#include "serverzone.h"
#include "serverzonecard.h"
#include "pendingcommand.h"
#include <QTcpSocket>
class QTimer;
// Connection state.
// The protocol handler itself is stateless once the connection
// has been established.
enum ProtocolStatus { StatusDisconnected,
StatusConnecting,
StatusAwaitingWelcome,
StatusConnected };
class Client : public QObject {
Q_OBJECT
signals:
void statusChanged(ProtocolStatus _status);
void welcomeMsgReceived(QStringList welcomeMsg);
void gameListReceived(QList<ServerGame *> games);
void playerListReceived(QList<ServerPlayer *> players);
void zoneListReceived(int commandId, QList<ServerZone *> zones);
void zoneDumpReceived(int commandId, QList<ServerZoneCard *> cards);
void responseReceived(ServerResponse *response);
void playerIdReceived(int id, QString name);
void gameEvent(ServerEventData *msg);
void serverTimeout();
void logSocketError(const QString &errorString);
private slots:
void slotConnected();
void readLine();
void checkTimeout();
void slotSocketError(QAbstractSocket::SocketError error);
private:
QTimer *timer;
QList<PendingCommand *> PendingCommands;
QTcpSocket *socket;
ProtocolStatus status;
QList<QStringList> msgbuf;
QString PlayerName;
unsigned int MsgId;
void msg(const QString &s);
int cmd(const QString &s);
void setStatus(const ProtocolStatus _status);
public:
Client(QObject *parent = 0);
~Client();
ProtocolStatus getStatus() { return status; }
QString peerName() const { return socket->peerName(); }
void connectToServer(const QString &hostname, unsigned int port, const QString &playername);
void disconnectFromServer();
int listGames();
int listPlayers();
int createGame(const QString &name, const QString &description, const QString &password, unsigned int maxPlayers);
int joinGame(const QString &name, const QString &password);
int leaveGame();
int setName(const QString &name);
int say(const QString &s);
int shuffle();
int rollDice(unsigned int sides);
int drawCards(unsigned int number);
int moveCard(int cardid, const QString &startzone, const QString &targetzone, int x, int y = 0);
int createToken(const QString &zone, const QString &name, const QString &powtough, int x, int y);
int setCardAttr(const QString &zone, int cardid, const QString &aname, const QString &avalue);
int submitDeck(const QStringList &deck);
int readyStart();
int incCounter(const QString &counter, int delta);
int setCounter(const QString &counter, int value);
int delCounter(const QString &counter);
int setActivePlayer(int player);
int setActivePhase(int phase);
int dumpZone(int player, const QString &zone, int numberCards);
};
#endif

View file

@ -0,0 +1,30 @@
#include "counter.h"
#include "player.h"
#include <QtGui>
Counter::Counter(Player *_player, const QString &_name, QGraphicsItem *parent)
: QGraphicsItem(parent), name(_name), value(0), player(_player)
{
player->addCounter(this);
}
QRectF Counter::boundingRect() const
{
return QRectF(0, 0, 50, 30);
}
void Counter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->fillRect(boundingRect(), QBrush(QColor("gray")));
painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1").arg(value));
painter->restore();
}
void Counter::setValue(int _value)
{
value = _value;
update(boundingRect());
}

24
cockatrice/src/counter.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef COUNTER_H
#define COUNTER_H
#include <QGraphicsItem>
class Player;
class Counter : public QGraphicsItem {
private:
QString name;
int value;
protected:
Player *player;
public:
Counter(Player *_player, const QString &_name, QGraphicsItem *parent = 0);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QString getName() const { return name; }
int getValue() const { return value; }
void setValue(int _value);
};
#endif

View file

@ -0,0 +1,11 @@
#include "counterlist.h"
Counter *CounterList::findCounter(const QString &name) const
{
for (int i = 0; i < size(); i++) {
Counter *temp = at(i);
if (!temp->getName().compare(name))
return temp;
}
return 0;
}

View file

@ -0,0 +1,12 @@
#ifndef COUNTERLIST_H
#define COUNTERLIST_H
#include "counter.h"
#include <QList>
class CounterList : public QList<Counter *> {
public:
Counter *findCounter(const QString &name) const;
};
#endif

View file

@ -0,0 +1,92 @@
#include "decklistmodel.h"
#include <QFile>
#include <QTextStream>
DeckListModel::~DeckListModel()
{
qDebug("DeckListModel destructor");
cleanList();
}
int DeckListModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return deckList.size();
}
int DeckListModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 2;
}
QVariant DeckListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if ((index.row() >= deckList.size()) || (index.column() >= 2))
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
DecklistRow *r = deckList.at(index.row());
switch (index.column()) {
case 0: return r->getNumber();
case 1: return r->getCard();
default: return QVariant();
}
}
QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation != Qt::Horizontal)
return QVariant();
switch (section) {
case 0: return QString(tr("Number"));
case 1: return QString(tr("Card"));
default: return QVariant();
}
}
void DeckListModel::cleanList()
{
QListIterator<DecklistRow *> i(deckList);
while (i.hasNext())
delete i.next();
deckList.clear();
}
void DeckListModel::loadFromFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
cleanList();
while (!in.atEnd()) {
QString line = in.readLine().simplified();
bool isSideboard = false;
if (line.startsWith("SB:")) {
line = line.mid(3).trimmed();
isSideboard = true;
}
int i = line.indexOf(' ');
bool ok;
int number = line.left(i).toInt(&ok);
if (!ok)
continue;
DecklistRow *row = new DecklistRow(number, line.mid(i + 1), isSideboard);
deckList << row;
}
reset();
}
DecklistRow *DeckListModel::getRow(int row) const
{
if (row >= deckList.size())
return 0;
return deckList.at(row);
}

View file

@ -0,0 +1,36 @@
#ifndef DECKLISTMODEL_H
#define DECKLISTMODEL_H
#include <QAbstractListModel>
#include <QList>
class DecklistRow {
private:
int number;
QString card;
bool sideboard;
public:
DecklistRow(int _number, const QString &_card, bool _sideboard) : number(_number), card(_card), sideboard(_sideboard) { }
int getNumber() const { return number; }
QString getCard() const { return card; }
bool isSideboard() const { return sideboard; }
};
class DeckListModel : public QAbstractListModel {
Q_OBJECT
public:
DeckListModel(QObject *parent = 0)
: QAbstractListModel(parent) { }
~DeckListModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
void loadFromFile(const QString &fileName);
DecklistRow *getRow(int row) const;
private:
QList<DecklistRow *> deckList;
void cleanList();
};
#endif

View file

@ -0,0 +1,61 @@
#include <QtGui>
#include "dlg_connect.h"
DlgConnect::DlgConnect(QWidget *parent)
: QDialog(parent)
{
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit("localhost");
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit("4747");
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit("Player");
playernameLabel->setBuddy(playernameEdit);
okButton = new QPushButton(tr("&OK"));
okButton->setDefault(true);
cancelButton = new QPushButton(tr("&Cancel"));
QGridLayout *grid = new QGridLayout;
grid->addWidget(hostLabel, 0, 0);
grid->addWidget(hostEdit, 0, 1);
grid->addWidget(portLabel, 1, 0);
grid->addWidget(portEdit, 1, 1);
grid->addWidget(playernameLabel, 2, 0);
grid->addWidget(playernameEdit, 2, 1);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
setWindowTitle(tr("Connect to server"));
setFixedHeight(sizeHint().height());
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}
QString DlgConnect::getHost()
{
return hostEdit->text();
}
int DlgConnect::getPort()
{
return portEdit->text().toInt();
}
QString DlgConnect::getPlayerName()
{
return playernameEdit->text();
}

View file

@ -0,0 +1,23 @@
#ifndef DLG_CONNECT_H
#define DLG_CONNECT_H
#include <QDialog>
class QLabel;
class QLineEdit;
class QPushButton;
class DlgConnect : public QDialog {
Q_OBJECT
public:
DlgConnect(QWidget *parent = 0);
QString getHost();
int getPort();
QString getPlayerName();
private:
QLabel *hostLabel, *portLabel, *playernameLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit;
QPushButton *okButton, *cancelButton;
};
#endif

View file

@ -0,0 +1,85 @@
#include <QtGui>
#include "dlg_creategame.h"
DlgCreateGame::DlgCreateGame(Client *_client, QWidget *parent)
: QDialog(parent), client(_client)
{
msgid = 0;
nameLabel = new QLabel(tr("&Name:"));
nameEdit = new QLineEdit;
nameLabel->setBuddy(nameEdit);
descriptionLabel = new QLabel(tr("&Description:"));
descriptionEdit = new QLineEdit;
descriptionLabel->setBuddy(descriptionEdit);
passwordLabel = new QLabel(tr("&Password:"));
passwordEdit = new QLineEdit;
passwordLabel->setBuddy(passwordEdit);
maxPlayersLabel = new QLabel(tr("&Max Players:"));
maxPlayersEdit = new QLineEdit("2");
maxPlayersLabel->setBuddy(maxPlayersEdit);
QGridLayout *grid = new QGridLayout;
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(nameEdit, 0, 1);
grid->addWidget(descriptionLabel, 1, 0);
grid->addWidget(descriptionEdit, 1, 1);
grid->addWidget(passwordLabel, 2, 0);
grid->addWidget(passwordEdit, 2, 1);
grid->addWidget(maxPlayersLabel, 3, 0);
grid->addWidget(maxPlayersEdit, 3, 1);
okButton = new QPushButton(tr("&OK"));
okButton->setDefault(true);
cancelButton = new QPushButton(tr("&Cancel"));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
setWindowTitle(tr("Create game"));
setFixedHeight(sizeHint().height());
connect(okButton, SIGNAL(clicked()), this, SLOT(actOK()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
connect(client, SIGNAL(responseReceived(ServerResponse *)), this, SLOT(checkResponse(ServerResponse *)));
}
void DlgCreateGame::actOK()
{
bool ok;
int maxPlayers = maxPlayersEdit->text().toInt(&ok);
if (msgid)
return;
if (!ok) {
QMessageBox::critical(this, tr("Error"), tr("Invalid number of players."));
return;
}
msgid = client->createGame(nameEdit->text(),
descriptionEdit->text(),
passwordEdit->text(),
maxPlayers);
}
void DlgCreateGame::checkResponse(ServerResponse *response)
{
if (response->getMsgId() != msgid)
return;
if (response->getOk())
accept();
else {
QMessageBox::critical(this, tr("Error"), tr("XXX"));
msgid = 0;
return;
}
}

View file

@ -0,0 +1,28 @@
#ifndef DLG_CREATEGAME_H
#define DLG_CREATEGAME_H
#include <QDialog>
#include "client.h"
class QLabel;
class QLineEdit;
class QPushButton;
class DlgCreateGame : public QDialog {
Q_OBJECT
public:
DlgCreateGame(Client *_client, QWidget *parent = 0);
private slots:
void actOK();
void checkResponse(ServerResponse *response);
private:
Client *client;
int msgid;
QLabel *nameLabel, *descriptionLabel, *passwordLabel, *maxPlayersLabel;
QLineEdit *nameEdit, *descriptionEdit, *passwordEdit, *maxPlayersEdit;
QPushButton *okButton, *cancelButton;
};
#endif

View file

@ -0,0 +1,87 @@
#include <QtGui>
#include "dlg_games.h"
#include "dlg_creategame.h"
DlgGames::DlgGames(Client *_client, QWidget *parent)
: QDialog(parent), client(_client)
{
msgid = 0;
tableView = new QTreeView;
tableModel = new GamesModel(this);
tableView->setModel(tableModel);
createButton = new QPushButton(tr("&Create"));
refreshButton = new QPushButton(tr("&Refresh"));
joinButton = new QPushButton(tr("&Join"));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(createButton);
buttonLayout->addStretch();
buttonLayout->addWidget(refreshButton);
buttonLayout->addStretch();
buttonLayout->addWidget(joinButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tableView);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
setWindowTitle(tr("Games"));
setMinimumWidth(sizeHint().width());
connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate()));
connect(refreshButton, SIGNAL(clicked()), this, SLOT(actRefresh()));
connect(joinButton, SIGNAL(clicked()), this, SLOT(actJoin()));
connect(client, SIGNAL(gameListReceived(QList<ServerGame *>)), this, SLOT(gameListReceived(QList<ServerGame *>)));
client->listGames();
}
void DlgGames::actCreate()
{
DlgCreateGame dlg(client, this);
if (dlg.exec())
accept();
}
void DlgGames::actRefresh()
{
client->listGames();
}
void DlgGames::checkResponse(ServerResponse *response)
{
if (response->getMsgId() != msgid)
return;
if (response->getOk())
accept();
else {
QMessageBox::critical(this, tr("Error"), tr("XXX"));
msgid = 0;
return;
}
}
void DlgGames::actJoin()
{
if (msgid)
return;
ServerGame *game = tableModel->getGame(tableView->currentIndex().row());
QString password;
if (game->getHasPassword()) {
bool ok;
password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok);
if (!ok)
return;
}
connect(client, SIGNAL(responseReceived(ServerResponse *)), this, SLOT(checkResponse(ServerResponse *)));
msgid = client->joinGame(game->getName(), password);
}
void DlgGames::gameListReceived(QList<ServerGame *> _gameList)
{
tableModel->setGameList(_gameList);
}

View file

@ -0,0 +1,32 @@
#ifndef DLG_GAMES_H
#define DLG_GAMES_H
#include <QDialog>
#include "gamesmodel.h"
#include "servergame.h"
#include "client.h"
class QPushButton;
class QTreeView;
class DlgGames : public QDialog {
Q_OBJECT
public:
DlgGames(Client *_client, QWidget *parent = 0);
private slots:
void actCreate();
void actRefresh();
void actJoin();
void gameListReceived(QList<ServerGame *> _gameList);
void checkResponse(ServerResponse *response);
private:
Client *client;
int msgid;
QTreeView *tableView;
GamesModel *tableModel;
QPushButton *refreshButton, *createButton, *joinButton;
};
#endif

View file

@ -0,0 +1,63 @@
#include <QtGui>
#include <QFileDialog>
#include "dlg_startgame.h"
#include "decklistmodel.h"
#include "carddatabase.h"
DlgStartGame::DlgStartGame(CardDatabase *_db, QWidget *parent)
: QDialog(parent), db(_db)
{
tableView = new QTreeView;
tableModel = new DeckListModel(this);
tableView->setModel(tableModel);
loadButton = new QPushButton(tr("&Load..."));
okButton = new QPushButton(tr("&OK"));
okButton->setDefault(true);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(loadButton);
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tableView);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
setWindowTitle(tr("Start game"));
setMinimumWidth(sizeHint().width());
connect(loadButton, SIGNAL(clicked()), this, SLOT(actLoad()));
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
}
void DlgStartGame::actLoad()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Load deck"), QString(), tr("Deck files (*.dec)"));
if (!fileName.isEmpty())
tableModel->loadFromFile(fileName);
// Precache card pictures
for (int i = 0; i < tableModel->rowCount(); i++) {
QString cardName = tableModel->getRow(i)->getCard();
CardInfo *card = db->getCard(cardName);
if (!card) {
qDebug(QString("Invalid card: %1").arg(cardName).toLatin1());
continue;
}
card->getPixmap();
}
}
QStringList DlgStartGame::getDeckList() const
{
QStringList result;
for (int i = 0; i < tableModel->rowCount(); i++) {
DecklistRow *temp = tableModel->getRow(i);
for (int j = 0; j < temp->getNumber(); j++)
result << QString("%1%2").arg(temp->isSideboard() ? "SB:" : "").arg(temp->getCard());
}
return result;
}

View file

@ -0,0 +1,26 @@
#ifndef DLG_STARTGAME_H
#define DLG_STARTGAME_H
#include <QDialog>
#include "decklistmodel.h"
class QTreeView;
class QPushButton;
class CardDatabase;
class DlgStartGame: public QDialog {
Q_OBJECT
public:
DlgStartGame(CardDatabase *_db, QWidget *parent = 0);
QStringList getDeckList() const;
private slots:
void actLoad();
private:
CardDatabase *db;
QTreeView *tableView;
DeckListModel *tableModel;
QPushButton *loadButton, *okButton;
};
#endif

371
cockatrice/src/game.cpp Normal file
View file

@ -0,0 +1,371 @@
#include <QGraphicsScene>
#include <QMenu>
#include <QMessageBox>
#include "serverplayer.h"
#include "game.h"
#include "servereventdata.h"
#include "client.h"
#include "tablezone.h"
#include "handzone.h"
#include "carddatabase.h"
#include "dlg_startgame.h"
Game::Game(CardDatabase *_db, Client *_client, QGraphicsScene *_scene, QMenu *_actionsMenu, QMenu *_cardMenu, int playerId, const QString &playerName)
: QObject(), actionsMenu(_actionsMenu), cardMenu(_cardMenu), db(_db), client(_client), scene(_scene), started(false)
{
QRectF sr = scene->sceneRect();
localPlayer = addPlayer(playerId, playerName, QPointF(0, sr.y() + sr.height() / 2), true);
connect(client, SIGNAL(gameEvent(ServerEventData *)), this, SLOT(gameEvent(ServerEventData *)));
connect(client, SIGNAL(playerListReceived(QList<ServerPlayer *>)), this, SLOT(playerListReceived(QList<ServerPlayer *>)));
aUntapAll = new QAction(tr("&Untap all permanents"), this);
aUntapAll->setShortcut(tr("Ctrl+U"));
connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll()));
aDecLife = new QAction(tr("&Decrement life"), this);
aDecLife->setShortcut(tr("F11"));
connect(aDecLife, SIGNAL(triggered()), this, SLOT(actDecLife()));
aIncLife = new QAction(tr("&Increment life"), this);
aIncLife->setShortcut(tr("F12"));
connect(aIncLife, SIGNAL(triggered()), this, SLOT(actIncLife()));
aSetLife = new QAction(tr("&Set life"), this);
aSetLife->setShortcut(tr("Ctrl+L"));
connect(aSetLife, SIGNAL(triggered()), this, SLOT(actSetLife()));
aShuffle = new QAction(tr("&Shuffle"), this);
aShuffle->setShortcut(tr("Ctrl+S"));
connect(aShuffle, SIGNAL(triggered()), this, SLOT(actShuffle()));
aDraw = new QAction(tr("&Draw a card"), this);
aDraw->setShortcut(tr("Ctrl+D"));
connect(aDraw, SIGNAL(triggered()), this, SLOT(actDrawCard()));
aDrawCards = new QAction(tr("D&raw cards..."), this);
connect(aDrawCards, SIGNAL(triggered()), this, SLOT(actDrawCards()));
aRollDice = new QAction(tr("R&oll dice..."), this);
aRollDice->setShortcut(tr("Ctrl+I"));
connect(aRollDice, SIGNAL(triggered()), this, SLOT(actRollDice()));
aCreateToken = new QAction(tr("&Create token..."), this);
aCreateToken->setShortcut(tr("Ctrl+T"));
connect(aCreateToken, SIGNAL(triggered()), this, SLOT(actCreateToken()));
actionsMenu->addAction(aUntapAll);
actionsMenu->addSeparator();
actionsMenu->addAction(aDecLife);
actionsMenu->addAction(aIncLife);
actionsMenu->addAction(aSetLife);
actionsMenu->addSeparator();
actionsMenu->addAction(aShuffle);
actionsMenu->addAction(aDraw);
actionsMenu->addAction(aDrawCards);
actionsMenu->addAction(aRollDice);
actionsMenu->addSeparator();
actionsMenu->addAction(aCreateToken);
aTap = new QAction(tr("&Tap"), this);
connect(aTap, SIGNAL(triggered()), this, SLOT(actTap()));
aUntap = new QAction(tr("&Untap"), this);
connect(aUntap, SIGNAL(triggered()), this, SLOT(actUntap()));
aAddCounter = new QAction(tr("&Add counter"), this);
connect(aAddCounter, SIGNAL(triggered()), this, SLOT(actAddCounter()));
aRemoveCounter = new QAction(tr("&Remove counter"), this);
connect(aRemoveCounter, SIGNAL(triggered()), this, SLOT(actRemoveCounter()));
aSetCounters = new QAction(tr("&Set counters..."), this);
connect(aSetCounters, SIGNAL(triggered()), this, SLOT(actSetCounters()));
aRearrange = new QAction(tr("&Rearrange"), this);
connect(aRearrange, SIGNAL(triggered()), this, SLOT(actRearrange()));
cardMenu->addAction(aTap);
cardMenu->addAction(aUntap);
cardMenu->addAction(aAddCounter);
cardMenu->addAction(aRemoveCounter);
cardMenu->addAction(aSetCounters);
cardMenu->addSeparator();
cardMenu->addAction(aRearrange);
dlgStartGame = new DlgStartGame(db);
}
Game::~Game()
{
qDebug("Game destructor");
for (int i = 0; i < players.size(); i++) {
emit playerRemoved(players.at(i));
delete players.at(i);
}
}
Player *Game::addPlayer(int playerId, const QString &playerName, QPointF base, bool local)
{
Player *newPlayer = new Player(playerName, playerId, base, local, db, client);
const ZoneList *const z = newPlayer->getZones();
for (int i = 0; i < z->size(); i++)
scene->addItem(z->at(i));
const CounterList *const c = newPlayer->getCounters();
for (int i = 0; i < c->size(); i++)
scene->addItem(c->at(i));
connect(newPlayer, SIGNAL(hoverCard(QString)), this, SIGNAL(hoverCard(QString)));
connect(newPlayer, SIGNAL(sigShowCardMenu(QPoint)), this, SLOT(showCardMenu(QPoint)));
connect(newPlayer, SIGNAL(logMoveCard(QString, QString, QString, QString)), this, SIGNAL(logMoveCard(QString, QString, QString, QString)));
connect(newPlayer, SIGNAL(logCreateToken(QString, QString)), this, SIGNAL(logCreateToken(QString, QString)));
connect(newPlayer, SIGNAL(logSetCardCounters(QString, QString, int, int)), this, SIGNAL(logSetCardCounters(QString, QString, int, int)));
connect(newPlayer, SIGNAL(logSetTapped(QString, QString, bool)), this, SIGNAL(logSetTapped(QString, QString, bool)));
connect(newPlayer, SIGNAL(logSetCounter(QString, QString, int, int)), this, SIGNAL(logSetCounter(QString, QString, int, int)));
players << newPlayer;
emit playerAdded(newPlayer);
return newPlayer;
}
void Game::playerListReceived(QList<ServerPlayer *> playerList)
{
QListIterator<ServerPlayer *> i(playerList);
QStringList nameList;
while (i.hasNext()) {
ServerPlayer *temp = i.next();
nameList << temp->getName();
int id = temp->getPlayerId();
if (id != localPlayer->getId())
addPlayer(id, temp->getName(), QPointF(0, 0), false);
delete temp;
}
emit logPlayerListReceived(nameList);
restartGameDialog();
}
void Game::restartGameDialog()
{
dlgStartGame->exec();
client->submitDeck(dlgStartGame->getDeckList());
}
void Game::gameEvent(ServerEventData *msg)
{
if (!msg->getPublic())
localPlayer->gameEvent(msg);
else {
Player *p = players.findPlayer(msg->getPlayerId());
if (!p) {
// XXX
}
switch(msg->getEventType()) {
case eventSay:
emit logSay(p->getName(), msg->getEventData()[0]);
break;
case eventJoin: {
emit logJoin(msg->getPlayerName());
addPlayer(msg->getPlayerId(), msg->getPlayerName(), QPointF(0, 0), false);
break;
}
case eventLeave:
emit logLeave(msg->getPlayerName());
// XXX Spieler natürlich noch rauswerfen
break;
case eventReadyStart:
if (started) {
started = false;
emit logReadyStart(p->getName());
if (!p->getLocal())
restartGameDialog();
}
break;
case eventGameStart:
started = true;
emit logGameStart();
break;
case eventShuffle:
emit logShuffle(p->getName());
break;
case eventRollDice: {
QStringList data = msg->getEventData();
int sides = data[0].toInt();
int roll = data[1].toInt();
emit logRollDice(p->getName(), sides, roll);
break;
}
case eventSetActivePlayer:
break;
case eventSetActivePhase:
break;
case eventName:
case eventCreateToken:
case eventSetupZones:
case eventSetCardAttr:
case eventSetCounter:
case eventDelCounter:
case eventPlayerId: {
p->gameEvent(msg);
break;
}
case eventDumpZone: {
QStringList data = msg->getEventData();
emit logDumpZone(p->getName(), data[1], players.findPlayer(data[0].toInt())->getName(), data[2].toInt());
break;
}
case eventMoveCard: {
if (msg->getPlayerId() == localPlayer->getId())
break;
p->gameEvent(msg);
break;
}
case eventDraw: {
emit logDraw(p->getName(), msg->getEventData()[0].toInt());
if (msg->getPlayerId() == localPlayer->getId())
break;
p->gameEvent(msg);
break;
}
case eventInvalid:
qDebug("Unhandled global event");
}
}
}
void Game::actUntapAll()
{
CardList *const cards = localPlayer->getZones()->findZone("table")->getCards();
for (int i = 0; i < cards->size(); i++)
client->setCardAttr("table", cards->at(i)->getId(), "tapped", "false");
}
void Game::actIncLife()
{
client->incCounter("life", 1);
}
void Game::actDecLife()
{
client->incCounter("life", -1);
}
void Game::actSetLife()
{
bool ok;
int life = QInputDialog::getInteger(0, tr("Set life"), tr("New life total:"), localPlayer->getCounters()->findCounter("life")->getValue(), 0, 2000000000, 1, &ok);
client->setCounter("life", life);
}
void Game::actShuffle()
{
client->shuffle();
}
void Game::actRollDice()
{
bool ok;
int sides = QInputDialog::getInteger(0, tr("Roll dice"), tr("Number of sides:"), 20, 2, 1000, 1, &ok);
if (ok)
client->rollDice(sides);
}
void Game::actDrawCard()
{
client->drawCards(1);
}
void Game::actDrawCards()
{
int number = QInputDialog::getInteger(0, tr("Draw cards"), tr("Number:"));
if (number)
client->drawCards(number);
}
void Game::actCreateToken()
{
QString cardname = QInputDialog::getText(0, tr("Create token"), tr("Name:"));
if (!db->getCard(cardname))
QMessageBox::critical(0, "Error", "No such card");
else
client->createToken("table", cardname, QString(), 0, 0);
}
void Game::showCardMenu(QPoint p)
{
cardMenu->exec(p);
}
void Game::actTap()
{
QListIterator<QGraphicsItem *> i(scene->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
client->setCardAttr(qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "1");
}
}
void Game::actUntap()
{
QListIterator<QGraphicsItem *> i(scene->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
client->setCardAttr(qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName(), temp->getId(), "tapped", "0");
}
}
void Game::actAddCounter()
{
QListIterator<QGraphicsItem *> i(scene->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
if (temp->getCounters() < MAX_COUNTERS_ON_CARD)
client->setCardAttr(qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(temp->getCounters() + 1));
}
}
void Game::actRemoveCounter()
{
QListIterator<QGraphicsItem *> i(scene->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
if (temp->getCounters())
client->setCardAttr(qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(temp->getCounters() - 1));
}
}
void Game::actSetCounters()
{
bool ok;
int number = QInputDialog::getInteger(0, tr("Set counters"), tr("Number:"), 0, 0, MAX_COUNTERS_ON_CARD, 1, &ok);
if (!ok)
return;
QListIterator<QGraphicsItem *> i(scene->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
client->setCardAttr(qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(number));
}
}
void Game::actRearrange()
{
// nur sinnvoll bei Karten auf dem Tisch -> Einschränkung einbauen
int x, y, x_initial = 0, y_initial = 0;
QList<QGraphicsItem *> list = scene->selectedItems();
// Find coordinates of leftmost card
for (int i = 0; i < list.size(); i++) {
CardItem *temp = (CardItem *) list.at(i);
if ((temp->pos().x() < x_initial) || (x_initial == 0)) {
x_initial = (int) temp->pos().x();
y_initial = (int) temp->pos().y();
}
}
x = x_initial;
y = y_initial;
for (int i = 0; i < list.size(); i++) {
CardItem *temp = (CardItem *) list.at(i);
QString zoneName = qgraphicsitem_cast<PlayerZone *>(temp->parentItem())->getName();
x = x_initial + i * RASTER_WIDTH;
y = y_initial + (i % 3) * RASTER_HEIGHT;
client->moveCard(temp->getId(), zoneName, zoneName, x, y);
}
}

80
cockatrice/src/game.h Normal file
View file

@ -0,0 +1,80 @@
#ifndef GAME_H
#define GAME_H
#include "playerlist.h"
class ServerPlayer;
class QGraphicsScene;
class Player;
class Client;
class ServerEventData;
class CardDatabase;
class DlgStartGame;
class Game : public QObject {
Q_OBJECT
private:
QMenu *actionsMenu, *cardMenu;
QAction *aTap, *aUntap, *aAddCounter, *aRemoveCounter, *aSetCounters, *aRearrange,
*aUntapAll, *aDecLife, *aIncLife, *aSetLife, *aShuffle, *aDraw, *aDrawCards, *aRollDice, *aCreateToken;
DlgStartGame *dlgStartGame;
CardDatabase *db;
Client *client;
QGraphicsScene *scene;
PlayerList players;
Player *localPlayer;
bool started;
Player *addPlayer(int playerId, const QString &playerName, QPointF base, bool local);
private slots:
void actUntapAll();
void actIncLife();
void actDecLife();
void actSetLife();
void actShuffle();
void actDrawCard();
void actDrawCards();
void actRollDice();
void actCreateToken();
void showCardMenu(QPoint p);
void actTap();
void actUntap();
void actAddCounter();
void actRemoveCounter();
void actSetCounters();
void actRearrange();
void gameEvent(ServerEventData *msg);
void playerListReceived(QList<ServerPlayer *> playerList);
signals:
void submitDecklist();
void hoverCard(QString name);
void playerAdded(Player *player);
void playerRemoved(Player *player);
// Log events
void logPlayerListReceived(QStringList players);
void logJoin(QString playerName);
void logLeave(QString playerName);
void logReadyStart(QString playerName);
void logGameStart();
void logSay(QString playerName, QString text);
void logShuffle(QString playerName);
void logRollDice(QString playerName, int sides, int roll);
void logDraw(QString playerName, int number);
void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone);
void logCreateToken(QString playerName, QString cardName);
void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue);
void logSetTapped(QString playerName, QString cardName, bool tapped);
void logSetCounter(QString playerName, QString counterName, int value, int oldValue);
void logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards);
public slots:
void restartGameDialog();
public:
Game(CardDatabase *_db, Client *_client, QGraphicsScene *_scene, QMenu *_actionsMenu, QMenu *_cardMenu, int playerId, const QString &playerName);
~Game();
Player *getLocalPlayer() const { return localPlayer; }
};
#endif

View file

@ -0,0 +1,74 @@
#include "gamesmodel.h"
#include "servergame.h"
GamesModel::~GamesModel()
{
cleanList();
}
int GamesModel::rowCount(const QModelIndex &parent) const
{
return gameList.size();
}
int GamesModel::columnCount(const QModelIndex &parent) const
{
return 4;
}
QVariant GamesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if ((index.row() >= gameList.size()) || (index.column() >= 4))
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
ServerGame *g = gameList.at(index.row());
switch (index.column()) {
case 0: return g->getName();
case 1: return g->getDescription();
case 2: return QString(g->getHasPassword() ? "yes" : "no");
case 3: return QString("%1/%2").arg(g->getPlayerCount()).arg(g->getMaxPlayers());
default: return QVariant();
}
}
QVariant GamesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation != Qt::Horizontal)
return QVariant();
switch (section) {
case 0: return QString("Name");
case 1: return QString("Description");
case 2: return QString("Password");
case 3: return QString("Players");
default: return QVariant();
}
}
ServerGame *GamesModel::getGame(int row)
{
if (row >= gameList.size())
return 0;
return gameList[row];
}
void GamesModel::setGameList(const QList<ServerGame *> &_gameList)
{
cleanList();
gameList = _gameList;
reset();
}
void GamesModel::cleanList()
{
QListIterator<ServerGame *> i(gameList);
while (i.hasNext())
delete i.next();
gameList.clear();
}

View file

@ -0,0 +1,26 @@
#ifndef GAMESMODEL_H
#define GAMESMODEL_H
#include <QAbstractListModel>
#include <QList>
#include "servergame.h"
class GamesModel : public QAbstractListModel {
Q_OBJECT
public:
GamesModel(QObject *parent = 0)
: QAbstractListModel(parent) { }
~GamesModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
void setGameList(const QList<ServerGame *> &_gameList);
ServerGame *getGame(int row);
private:
QList<ServerGame *> gameList;
void cleanList();
};
#endif

View file

@ -0,0 +1,33 @@
#include "gameview.h"
GameView::GameView(QGraphicsScene *scene, QWidget *parent)
: QGraphicsView(scene, parent)
{
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
setOptimizationFlags(/*DontClipPainter | */DontSavePainterState);
setDragMode(RubberBandDrag);
}
void GameView::scaleToScene()
{
// This function ensures that the bounding rectangles of card pictures
// have integer sizes. This is achieved by using a scale factor of n / 6.
QRectF sr = scene()->sceneRect();
QRectF vr = QRectF(viewport()->rect().adjusted(2, 2, -2, -2));
qreal scale_h = vr.width() / sr.width();
qreal scale_v = vr.height() / sr.height();
qreal scale_total = qMin(scale_h, scale_v);
qreal scale_corr = (qreal) ((int) (scale_total * 6)) / 6;
qDebug(QString("scale_corr = %1 / 6").arg(scale_corr * 6).toLatin1());
setTransform(QTransform().scale(scale_corr, scale_corr));
}
void GameView::resizeEvent(QResizeEvent *event)
{
qDebug("GameView: resizeEvent");
QGraphicsView::resizeEvent(event);
scaleToScene();
}

14
cockatrice/src/gameview.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef GAMEVIEW_H
#define GAMEVIEW_H
#include <QGraphicsView>
class GameView : public QGraphicsView {
protected:
void resizeEvent(QResizeEvent *event);
public:
void scaleToScene();
GameView(QGraphicsScene *scene, QWidget *parent = 0);
};
#endif

View file

@ -0,0 +1,53 @@
#include <QtGui>
#include "gravezone.h"
#include "player.h"
#include "client.h"
#include "zoneviewzone.h"
GraveZone::GraveZone(Player *_p)
: PlayerZone(_p, "grave")
{
cards = new CardList(true);
}
QRectF GraveZone::boundingRect() const
{
return QRectF(0, 0, 50, 50);
}
void GraveZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->fillRect(boundingRect(), QColor("yellow"));
painter->setFont(QFont("Times", 20, QFont::Bold));
painter->setPen(QPen(QColor("black")));
painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size()));
painter->restore();
}
void GraveZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
for (int i = 0; i < views.size(); i++)
views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y);
cards->insert(x, card);
card->setPos(0, 0);
card->setVisible(false);
card->resetState();
card->setParentItem(this);
if (reorganize)
reorganizeCards();
}
void GraveZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0);
}
void GraveZone::reorganizeCards()
{
update(boundingRect());
}

View file

@ -0,0 +1,17 @@
#ifndef GRAVEZONE_H
#define GRAVEZONE_H
#include "playerzone.h"
class GraveZone : public PlayerZone {
private:
public:
GraveZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1);
void reorganizeCards();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
};
#endif

View file

@ -0,0 +1,73 @@
#include <QtGui>
#include "handzone.h"
#include "player.h"
#include "client.h"
HandZone::HandZone(Player *_p)
: PlayerZone(_p, "hand")
{
cards = new CardList(player->getLocal());
}
QRectF HandZone::boundingRect() const
{
return QRectF(0, 0, 100, 500);
}
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->fillRect(boundingRect(), QColor("green"));
}
void HandZone::reorganizeCards()
{
if (cards->isEmpty())
return;
int cardCount = cards->size();
qreal totalWidth = boundingRect().width();
qreal totalHeight = boundingRect().height();
qreal cardWidth = cards->at(0)->boundingRect().width();
qreal cardHeight = cards->at(0)->boundingRect().height();
qreal x = (totalWidth - cardWidth) / 2;
for (int i = 0; i < cardCount; i++) {
CardItem *c = cards->at(i);
// If the total height of the cards is smaller than the available height,
// the cards do not need to overlap and are displayed in the center of the area.
if (cardHeight * cardCount > totalHeight)
c->setPos(x, ((qreal) i) * (totalHeight - cardHeight) / (cardCount - 1));
else
c->setPos(x, ((qreal) i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2);
c->setZValue(i);
}
}
void HandZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
Q_UNUSED(y);
if (x == -1)
x = cards->size();
cards->insert(x, card);
if (!cards->getContentsKnown()) {
card->setId(-1);
card->setName();
}
card->setParentItem(this);
card->resetState();
card->setVisible(true);
card->update(card->boundingRect());
if (reorganize)
reorganizeCards();
}
void HandZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
Q_UNUSED(dropPoint);
player->client->moveCard(cardId, startZone->getName(), getName(), cards->size(), 0);
}

17
cockatrice/src/handzone.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef HANDZONE_H
#define HANDZONE_H
#include "playerzone.h"
class HandZone : public PlayerZone {
private:
public:
HandZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1);
void reorganizeCards();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
};
#endif

View file

@ -0,0 +1,88 @@
#include <QtGui>
#include "libraryzone.h"
#include "player.h"
#include "client.h"
#include "carddatabase.h"
#include "carddragitem.h"
#include "zoneviewzone.h"
LibraryZone::LibraryZone(Player *_p)
: PlayerZone(_p, "deck")
{
cards = new CardList(false);
setCursor(Qt::OpenHandCursor);
}
QRectF LibraryZone::boundingRect() const
{
return QRectF(0, 0, 50, 50);
}
void LibraryZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->fillRect(boundingRect(), QColor("red"));
painter->setFont(QFont("Times", 20, QFont::Bold));
painter->setPen(QPen(QColor("black")));
painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size()));
painter->restore();
}
void LibraryZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
for (int i = 0; i < views.size(); i++)
views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y);
cards->insert(x, card);
card->setId(-1);
card->setName(QString());
card->setPos(0, 0);
card->setVisible(false);
card->resetState();
card->setParentItem(this);
if (reorganize)
reorganizeCards();
}
void LibraryZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0);
}
void LibraryZone::reorganizeCards()
{
update(boundingRect());
}
void LibraryZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
PlayerZone::mousePressEvent(event);
if (event->isAccepted())
return;
if (event->button() == Qt::LeftButton) {
setCursor(Qt::ClosedHandCursor);
event->accept();
} else
event->ignore();
}
void LibraryZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance())
return;
CardItem *card = cards->at(0);
CardDragItem *drag = card->createDragItem(this, 0, event->pos(), event->scenePos());
drag->grabMouse();
setCursor(Qt::OpenHandCursor);
}
void LibraryZone::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::OpenHandCursor);
}

View file

@ -0,0 +1,21 @@
#ifndef LIBRARYZONE_H
#define LIBRARYZONE_H
#include "playerzone.h"
class LibraryZone : public PlayerZone {
private:
public:
LibraryZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1);
void reorganizeCards();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};
#endif

51
cockatrice/src/main.cpp Normal file
View file

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@gmx.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QApplication>
#include <QTextCodec>
#include <QtPlugin>
#include "window.h"
#include <stdio.h>
//Q_IMPORT_PLUGIN(qjpeg)
void myMessageOutput(QtMsgType type, const char *msg)
{
static FILE *f = NULL;
if (!f)
f = fopen("qdebug.txt", "w");
fprintf(f, "%s\n", msg);
fflush(f);
}
int main(int argc, char *argv[])
{
qInstallMsgHandler(myMessageOutput);
QApplication app(argc, argv);
app.addLibraryPath("plugins");
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
MainWindow *ui = new MainWindow;
ui->show();
return app.exec();
}

View file

@ -0,0 +1,147 @@
#include "messagelogwidget.h"
#include "game.h"
#include <QScrollBar>
void MessageLogWidget::appendAndScroll(const QString &s)
{
append(s);
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}
void MessageLogWidget::logConnecting(QString hostname)
{
appendAndScroll(tr("Connecting to %1...").arg(hostname));
}
void MessageLogWidget::logConnected(const QStringList WelcomeMsg)
{
appendAndScroll(tr("Connected."));
QStringListIterator i(WelcomeMsg);
while (i.hasNext())
appendAndScroll(i.next());
}
void MessageLogWidget::logDisconnected()
{
appendAndScroll(tr("Disconnected from server."));
}
void MessageLogWidget::logSocketError(const QString &errorString)
{
appendAndScroll(errorString);
}
void MessageLogWidget::logPlayerListReceived(QStringList players)
{
append("---");
append(tr("You have joined the game. Player list:"));
for (int i = 0; i < players.size(); i++)
append(players.at(i));
appendAndScroll("---");
}
void MessageLogWidget::logJoin(QString playerName)
{
appendAndScroll(tr("%1 has joined the game").arg(playerName));
}
void MessageLogWidget::logLeave(QString playerName)
{
appendAndScroll(tr("%1 has left the game").arg(playerName));
}
void MessageLogWidget::logReadyStart(QString playerName)
{
appendAndScroll(tr("%1 is ready to start a new game.").arg(playerName));
}
void MessageLogWidget::logGameStart()
{
appendAndScroll(tr("Game has started."));
}
void MessageLogWidget::logSay(QString playerName, QString message)
{
appendAndScroll(QString("<font color=\"red\">%1:</font> %2").arg(playerName).arg(message));
}
void MessageLogWidget::logShuffle(QString playerName)
{
appendAndScroll(tr("%1 shuffles his/her library").arg(playerName));
}
void MessageLogWidget::logRollDice(QString playerName, int sides, int roll)
{
appendAndScroll(tr("%1 rolled a %2 with a %3-sided dice").arg(playerName).arg(roll).arg(sides));
}
void MessageLogWidget::logDraw(QString playerName, int number)
{
if (number == 1)
appendAndScroll(tr("%1 draws a card").arg(playerName));
else
appendAndScroll(tr("%1 draws %2 cards").arg(playerName).arg(number));
}
void MessageLogWidget::logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone)
{
appendAndScroll(tr("%1 moves %2 from %3 to %4").arg(playerName).arg(cardName).arg(startZone).arg(targetZone));
}
void MessageLogWidget::logCreateToken(QString playerName, QString cardName)
{
appendAndScroll(tr("%1 creates token: %2").arg(playerName).arg(cardName));
}
void MessageLogWidget::logSetCardCounters(QString playerName, QString cardName, int value, int oldValue)
{
if (value > oldValue)
appendAndScroll(tr("%1 places %2 counters on %3 (now %4)").arg(playerName).arg(value - oldValue).arg(cardName).arg(value));
else
appendAndScroll(tr("%1 removes %2 counters from %3 (now %4)").arg(playerName).arg(oldValue - value).arg(cardName).arg(value));
}
void MessageLogWidget::logSetTapped(QString playerName, QString cardName, bool tapped)
{
appendAndScroll(tr("%1 %2 %3").arg(playerName).arg(tapped ? "taps" : "untaps").arg(cardName));
}
void MessageLogWidget::logSetCounter(QString playerName, QString counterName, int value, int oldValue)
{
appendAndScroll(tr("%1 sets counter \"%2\" to %3 (%4%5)").arg(playerName).arg(counterName).arg(value).arg(value > oldValue ? "+" : "").arg(value - oldValue));
}
void MessageLogWidget::logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards)
{
if (numberCards)
appendAndScroll(tr("%1 is looking at the top %2 cards of %3's %4").arg(playerName).arg(numberCards).arg(zoneOwner).arg(zoneName));
else
appendAndScroll(tr("%1 is looking at %2's %3").arg(playerName).arg(zoneOwner).arg(zoneName));
}
void MessageLogWidget::connectToGame(Game *game)
{
connect(game, SIGNAL(logPlayerListReceived(QStringList)), this, SLOT(logPlayerListReceived(QStringList)));
connect(game, SIGNAL(logJoin(QString)), this, SLOT(logJoin(QString)));
connect(game, SIGNAL(logLeave(QString)), this, SLOT(logLeave(QString)));
connect(game, SIGNAL(logReadyStart(QString)), this, SLOT(logReadyStart(QString)));
connect(game, SIGNAL(logGameStart()), this, SLOT(logGameStart()));
connect(game, SIGNAL(logSay(QString, QString)), this, SLOT(logSay(QString, QString)));
connect(game, SIGNAL(logShuffle(QString)), this, SLOT(logShuffle(QString)));
connect(game, SIGNAL(logRollDice(QString, int, int)), this, SLOT(logRollDice(QString, int, int)));
connect(game, SIGNAL(logDraw(QString, int)), this, SLOT(logDraw(QString, int)));
connect(game, SIGNAL(logMoveCard(QString, QString, QString, QString)), this, SLOT(logMoveCard(QString, QString, QString, QString)));
connect(game, SIGNAL(logCreateToken(QString, QString)), this, SLOT(logCreateToken(QString, QString)));
connect(game, SIGNAL(logSetCardCounters(QString, QString, int, int)), this, SLOT(logSetCardCounters(QString, QString, int, int)));
connect(game, SIGNAL(logSetTapped(QString, QString, bool)), this, SLOT(logSetTapped(QString, QString, bool)));
connect(game, SIGNAL(logSetCounter(QString, QString, int, int)), this, SLOT(logSetCounter(QString, QString, int, int)));
connect(game, SIGNAL(logDumpZone(QString, QString, QString, int)), this, SLOT(logDumpZone(QString, QString, QString, int)));
}
MessageLogWidget::MessageLogWidget(QWidget *parent)
: QTextEdit(parent)
{
setReadOnly(true);
}

View file

@ -0,0 +1,39 @@
#ifndef MESSAGELOGWIDGET_H
#define MESSAGELOGWIDGET_H
#include <QTextEdit>
#include <QAbstractSocket>
class Game;
class MessageLogWidget : public QTextEdit {
Q_OBJECT
public slots:
void logConnecting(QString hostname);
void logConnected(const QStringList WelcomeMsg);
void logDisconnected();
void logSocketError(const QString &errorString);
private slots:
void logPlayerListReceived(QStringList players);
void logJoin(QString playerName);
void logLeave(QString playerName);
void logReadyStart(QString playerName);
void logGameStart();
void logSay(QString playerName, QString message);
void logShuffle(QString playerName);
void logRollDice(QString playerName, int sides, int roll);
void logDraw(QString playerName, int number);
void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone);
void logCreateToken(QString playerName, QString cardName);
void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue);
void logSetTapped(QString playerName, QString cardName, bool tapped);
void logSetCounter(QString playerName, QString counterName, int value, int oldValue);
void logDumpZone(QString playerName, QString zoneName, QString zoneOwner, int numberCards);
private:
void appendAndScroll(const QString &s);
public:
void connectToGame(Game *game);
MessageLogWidget(QWidget *parent = 0);
};
#endif

View file

@ -0,0 +1,19 @@
#ifndef PENDINGCOMMAND_H
#define PENDINGCOMMAND_H
#include <QString>
class PendingCommand {
private:
QString cmd;
int msgid;
int time;
public:
int getMsgId() const { return msgid; }
QString getCmd() const { return cmd; }
bool timeout() const { return time > 5; }
void incTime() { ++time; }
PendingCommand(const QString &_cmd, int _msgid) : cmd(_cmd), msgid(_msgid), time(0) { }
};
#endif

296
cockatrice/src/player.cpp Normal file
View file

@ -0,0 +1,296 @@
#include "player.h"
#include "client.h"
#include "handzone.h"
#include "tablezone.h"
#include "libraryzone.h"
#include "gravezone.h"
#include "rfgzone.h"
#include "sideboardzone.h"
#include <QMenu>
Player::Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client)
: QObject(), defaultNumberTopCards(3), name(_name), id(_id), base(_base), local(_local), db(_db), client(_client)
{
LibraryZone *deck = new LibraryZone(this);
deck->setPos(_base);
// XXX
qreal foo = deck->boundingRect().height();
GraveZone *grave = new GraveZone(this);
grave->setPos(_base + QPointF(0, foo));
RfgZone *rfg = new RfgZone(this);
rfg->setPos(_base + QPointF(0, 2 * foo));
SideboardZone *sb = new SideboardZone(this);
sb->setPos(_base + QPointF(0, 3 * foo));
Counter *life = new Counter(this, "life");
life->setPos(_base + QPointF(-50, 5 * foo));
_base += QPointF(deck->boundingRect().width(), 0);
PlayerZone *hand = new HandZone(this);
hand->setPos(_base);
_base += QPointF(hand->boundingRect().width(), 0);
PlayerZone *table = new TableZone(this);
table->setPos(_base);
aMoveHandToTopLibrary = new QAction(tr("Move to &top of library"), this);
connect(aMoveHandToTopLibrary, SIGNAL(triggered()), this, SLOT(actMoveHandToTopLibrary()));
aMoveHandToBottomLibrary = new QAction(tr("Move to &bottom of library"), this);
connect(aMoveHandToBottomLibrary, SIGNAL(triggered()), this, SLOT(actMoveHandToBottomLibrary()));
aViewLibrary = new QAction(tr("&View library"), this);
if (local)
aViewLibrary->setShortcut(tr("F5"));
connect(aViewLibrary, SIGNAL(triggered()), this, SLOT(actViewLibrary()));
aViewTopCards = new QAction(tr("View &top cards of library..."), this);
connect(aViewTopCards, SIGNAL(triggered()), this, SLOT(actViewTopCards()));
aViewGraveyard = new QAction(tr("&View graveyard"), this);
if (local)
aViewGraveyard->setShortcut(tr("F6"));
connect(aViewGraveyard, SIGNAL(triggered()), this, SLOT(actViewGraveyard()));
aViewRfg = new QAction(tr("&View removed cards"), this);
connect(aViewRfg, SIGNAL(triggered()), this, SLOT(actViewRfg()));
aViewSideboard = new QAction(tr("&View sideboard"), this);
connect(aViewSideboard, SIGNAL(triggered()), this, SLOT(actViewSideboard()));
playerMenu = new QMenu(tr("Player \"%1\"").arg(name));
QMenu *handMenu = playerMenu->addMenu(tr("&Hand"));
handMenu->addAction(aMoveHandToTopLibrary);
handMenu->addAction(aMoveHandToBottomLibrary);
hand->setMenu(handMenu);
QMenu *libraryMenu = playerMenu->addMenu(tr("&Library"));
libraryMenu->addAction(aViewLibrary);
libraryMenu->addAction(aViewTopCards);
deck->setMenu(libraryMenu);
QMenu *graveMenu = playerMenu->addMenu(tr("&Graveyard"));
graveMenu->addAction(aViewGraveyard);
grave->setMenu(graveMenu);
QMenu *rfgMenu = playerMenu->addMenu(tr("&Removed cards"));
rfgMenu->addAction(aViewRfg);
rfg->setMenu(rfgMenu);
QMenu *sbMenu = playerMenu->addMenu(tr("&Sideboard"));
sbMenu->addAction(aViewSideboard);
sb->setMenu(sbMenu);
}
Player::~Player()
{
qDebug("Player destructor");
for (int i = 0; i < zones.size(); i++)
delete zones.at(i);
for (int i = 0; i < counters.size(); i++)
delete counters.at(i);
}
void Player::actMoveHandToTopLibrary()
{
PlayerZone *library = zones.findZone("deck");
zones.findZone("hand")->moveAllToZone(library->getName(), 0);
}
void Player::actMoveHandToBottomLibrary()
{
PlayerZone *library = zones.findZone("deck");
zones.findZone("hand")->moveAllToZone(library->getName(), library->getCards()->size());
}
void Player::actViewLibrary()
{
emit addZoneView(this, "deck", 0);
}
void Player::actViewTopCards()
{
bool ok;
int number = QInputDialog::getInteger(0, tr("View top cards of library"), tr("Number of cards:"), defaultNumberTopCards, 1, 2000000000, 1, &ok);
if (ok) {
defaultNumberTopCards = number;
emit addZoneView(this, "deck", number);
}
}
void Player::actViewGraveyard()
{
emit addZoneView(this, "grave", 0);
}
void Player::actViewRfg()
{
emit addZoneView(this, "rfg", 0);
}
void Player::actViewSideboard()
{
emit addZoneView(this, "sb", 0);
}
void Player::addZone(PlayerZone *z)
{
zones << z;
}
void Player::addCounter(Counter *c)
{
counters << c;
}
void Player::gameEvent(ServerEventData *event)
{
QStringList data = event->getEventData();
switch (event->getEventType()) {
case eventSetupZones: {
// XXX Life counter
int life = data[0].toInt();
int deck_cards = data[1].toInt();
int sb_cards = data[2].toInt();
// XXX Fehlerbehandlung
// Clean up existing zones first
for (int i = 0; i < zones.size(); i++)
zones.at(i)->clearContents();
Counter *lifeCounter = counters.findCounter("life");
lifeCounter->setValue(life);
PlayerZone *deck = zones.findZone("deck");
for (; deck_cards; deck_cards--)
deck->addCard(new CardItem(db, QString(), -1));
deck->reorganizeCards();
PlayerZone *sb = zones.findZone("sb");
for (; sb_cards; sb_cards--)
sb->addCard(new CardItem(db, QString(), -1));
sb->reorganizeCards();
break;
}
case eventDraw: {
PlayerZone *deck = zones.findZone("deck");
PlayerZone *hand = zones.findZone("hand");
if (!event->getPublic()) {
hand->addCard(deck->takeCard(0, data[0].toInt(), data[1]));
} else {
int number = data[0].toInt();
for (; number; number--)
hand->addCard(deck->takeCard(0, -1, QString()));
}
break;
}
case eventMoveCard: {
if (data.size() != 7) {
qDebug("error");
// XXX
}
int cardId = data[0].toInt();
QString cardName = data[1];
PlayerZone *startZone = zones.findZone(data[2]);
if (!startZone)
qDebug(QString("start zone invalid: %1").arg(data[2]).toLatin1());
int position = data[3].toInt();
PlayerZone *targetZone = zones.findZone(data[4]);
if (!targetZone)
qDebug(QString("target zone invalid: %1").arg(data[4]).toLatin1());
int x = data[5].toInt();
int y = data[6].toInt();
// XXX Mehr Fehlerbehandlung
CardItem *card = startZone->takeCard(position, cardId, cardName);
if (!card) // XXX
qDebug("null");
card->deleteDragItem();
// The log event has to be sent before the card is added to the target zone
// because the addCard function can modify the card object.
emit logMoveCard(name, card->getName(), startZone->getName(), targetZone->getName());
targetZone->addCard(card, true, x, y);
break;
}
case eventCreateToken: {
// zone, cardid, cardname, powtough, x, y
if (data.size() != 6) {
qDebug("error");
}
PlayerZone *zone = zones.findZone(data[0]);
int cardid = data[1].toInt();
QString cardname = data[2];
QString powtough = data[3];
int x = data[4].toInt();
int y = data[5].toInt();
CardItem *card = new CardItem(db, cardname, cardid);
emit logCreateToken(name, card->getName());
zone->addCard(card, true, x, y);
break;
}
case eventSetCardAttr: {
if (data.size() != 4) {
// XXX
}
PlayerZone *zone = zones.findZone(data[0]);
int cardId = data[1].toInt();
CardItem *card = zone->getCard(cardId, "");
QString aname = data[2];
QString avalue = data[3];
// XXX Fehlerbehandlung
if (aname == "tapped") {
bool tapped = avalue == "1";
emit logSetTapped(name, card->getName(), tapped);
card->setTapped(tapped);
} else if (aname == "attacking")
card->setAttacking(avalue == "1");
else if (aname == "facedown")
card->setFacedown(avalue == "1");
else if (aname == "counters") {
int value = avalue.toInt();
emit logSetCardCounters(name, card->getName(), value, card->getCounters());
card->setCounters(value);
} else if (aname == "annotation")
card->setAnnotation(avalue);
break;
}
case eventSetCounter: {
if (data.size() != 2) {
// XXX
}
int value = data[1].toInt();
Counter *c = counters.findCounter(data[0]);
int oldValue = c->getValue();
c->setValue(value);
emit logSetCounter(name, c->getName(), value, oldValue);
break;
}
default:
qDebug("unhandled player event");
}
}
void Player::hoverCardEvent(CardItem *card)
{
emit hoverCard(card->getName());
}
void Player::showCardMenu(const QPoint &p)
{
emit sigShowCardMenu(p);
}

71
cockatrice/src/player.h Normal file
View file

@ -0,0 +1,71 @@
#ifndef PLAYER_H
#define PLAYER_H
#include <QInputDialog>
#include <QPoint>
#include "zonelist.h"
#include "counterlist.h"
#include "servereventdata.h"
class Client;
class CardDatabase;
class QMenu;
class QAction;
class Player : public QObject {
Q_OBJECT
signals:
void moveCard(int cardId, QString startZone, QString targetZone, int x, int y);
void hoverCard(QString name);
void addZoneView(Player *player, QString zoneName, int number);
void sigShowCardMenu(QPoint p);
// Log events
void logMoveCard(QString playerName, QString cardName, QString startZone, QString targetZone);
void logCreateToken(QString playerName, QString cardName);
void logSetCardCounters(QString playerName, QString cardName, int value, int oldValue);
void logSetTapped(QString playerName, QString cardName, bool tapped);
void logSetCounter(QString playerName, QString counterName, int value, int oldValue);
private slots:
void actMoveHandToTopLibrary();
void actMoveHandToBottomLibrary();
void actViewLibrary();
void actViewTopCards();
void actViewGraveyard();
void actViewRfg();
void actViewSideboard();
private:
QMenu *playerMenu;
QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary,
*aViewLibrary, *aViewTopCards, *aViewGraveyard, *aViewRfg, *aViewSideboard;
int defaultNumberTopCards;
QString name;
int id;
QPointF base;
bool local;
ZoneList zones;
CounterList counters;
CardDatabase *db;
public:
Client *client;
void addZone(PlayerZone *z);
void addCounter(Counter *c);
Player(const QString &_name, int _id, QPointF _base, bool _local, CardDatabase *_db, Client *_client);
~Player();
QMenu *getPlayerMenu() const { return playerMenu; }
int getId() const { return id; }
QString getName() const { return name; }
bool getLocal() const { return local; }
const ZoneList *const getZones() const { return &zones; }
const CounterList *const getCounters() const { return &counters; }
void gameEvent(ServerEventData *event);
void hoverCardEvent(CardItem *card);
CardDatabase *getDb() const { return db; }
void showCardMenu(const QPoint &p);
};
#endif

View file

@ -0,0 +1,11 @@
#include "playerlist.h"
Player *PlayerList::findPlayer(int id) const
{
for (int i = 0; i < size(); i++) {
Player *temp = at(i);
if (temp->getId() == id)
return temp;
}
return 0;
}

View file

@ -0,0 +1,12 @@
#ifndef PLAYERLIST_H
#define PLAYERLIST_H
#include "player.h"
#include <QList>
class PlayerList : public QList<Player *> {
public:
Player *findPlayer(int id) const;
};
#endif

View file

@ -0,0 +1,98 @@
#include <QtGui>
#include "playerzone.h"
#include "carditem.h"
#include "player.h"
#include "client.h"
#include "zoneviewzone.h"
PlayerZone::PlayerZone(Player *_p, const QString &_name, QGraphicsItem *parent, bool isView)
: QGraphicsItem(parent), player(_p), name(_name), cards(NULL), menu(NULL), hasCardAttr(false)
{
if (!isView)
player->addZone(this);
}
PlayerZone::~PlayerZone()
{
qDebug(QString("PlayerZone destructor: %1").arg(name).toLatin1());
while (!views.empty())
delete views.at(0);
clearContents();
delete cards;
}
void PlayerZone::clearContents()
{
for (int i = 0; i < cards->size(); i++)
delete cards->at(i);
cards->clear();
}
void PlayerZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
if (menu) {
menu->exec(event->screenPos());
event->accept();
} else
event->ignore();
} else
event->ignore();
}
CardItem *PlayerZone::getCard(int cardId, const QString &cardName)
{
CardItem *c = cards->findCard(cardId, false);
// If the card's id is -1, this zone is invisible,
// so we need to give the card an id and a name as it comes out.
// It can be assumed that in an invisible zone, all cards are equal.
if ((c->getId() == -1) || (c->getName().isEmpty())) {
c->setId(cardId);
c->setName(cardName);
}
return c;
}
CardItem *PlayerZone::takeCard(int position, int cardId, const QString &cardName)
{
CardItem *c = cards->takeAt(position);
for (int i = 0; i < views.size(); i++)
views[i]->removeCard(position);
if (c->getId() == -1) {
c->setId(cardId);
c->setName(cardName);
}
reorganizeCards();
return c;
}
void PlayerZone::setCardAttr(int cardId, const QString &aname, const QString &avalue)
{
if (hasCardAttr)
player->client->setCardAttr(name, cardId, aname, avalue);
}
void PlayerZone::hoverCardEvent(CardItem *card)
{
player->hoverCardEvent(card);
}
void PlayerZone::addView(ZoneViewZone *view)
{
views.append(view);
}
void PlayerZone::removeView(ZoneViewZone *view)
{
views.removeAt(views.indexOf(view));
}
void PlayerZone::moveAllToZone(const QString &targetZone, int targetX)
{
// Cards need to be moved in reverse order so that the other
// cards' list index doesn't change
for (int i = cards->size() - 1; i >= 0; i--)
player->client->moveCard(cards->at(i)->getId(), getName(), targetZone, targetX);
}

View file

@ -0,0 +1,47 @@
#ifndef PLAYERZONE_H
#define PLAYERZONE_H
#include <QString>
#include "cardlist.h"
class Player;
class ZoneViewZone;
class QMenu;
class PlayerZone : public QGraphicsItem {
protected:
Player *player;
QString name;
CardList *cards;
QList<ZoneViewZone *> views;
QMenu *menu;
bool hasCardAttr;
void mousePressEvent(QGraphicsSceneMouseEvent *event);
public:
enum { Type = typeZone };
int type() const { return Type; }
virtual void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint) = 0;
PlayerZone(Player *_player, const QString &_name, QGraphicsItem *parent = 0, bool isView = false);
~PlayerZone();
void clearContents();
bool getHasCardAttr() const { return hasCardAttr; }
QMenu *getMenu() const { return menu; }
void setMenu(QMenu *_menu) { menu = _menu; }
QString getName() const { return name; }
Player *getPlayer() const { return player; }
bool contentsKnown() const { return cards->getContentsKnown(); }
CardList *const getCards() const { return cards; }
virtual void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1) = 0;
// getCard() finds a card by id.
CardItem *getCard(int cardId, const QString &cardName);
// takeCard() finds a card by position and removes it from the zone and from all of its views.
CardItem *takeCard(int position, int cardId, const QString &cardName);
void setCardAttr(int cardId, const QString &aname, const QString &avalue);
void hoverCardEvent(CardItem *card);
void addView(ZoneViewZone *view);
void removeView(ZoneViewZone *view);
virtual void reorganizeCards() = 0;
void moveAllToZone(const QString &targetZone, int targetX);
};
#endif

View file

@ -0,0 +1,53 @@
#include <QtGui>
#include "rfgzone.h"
#include "player.h"
#include "client.h"
#include "zoneviewzone.h"
RfgZone::RfgZone(Player *_p)
: PlayerZone(_p, "rfg")
{
cards = new CardList(true);
}
QRectF RfgZone::boundingRect() const
{
return QRectF(0, 0, 50, 50);
}
void RfgZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->fillRect(boundingRect(), QColor("white"));
painter->setFont(QFont("Times", 20, QFont::Bold));
painter->setPen(QPen(QColor("black")));
painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size()));
painter->restore();
}
void RfgZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
for (int i = 0; i < views.size(); i++)
views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y);
cards->insert(x, card);
card->setPos(0, 0);
card->setVisible(false);
card->resetState();
card->setParentItem(this);
if (reorganize)
reorganizeCards();
}
void RfgZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0);
}
void RfgZone::reorganizeCards()
{
update(boundingRect());
}

17
cockatrice/src/rfgzone.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef RFGZONE_H
#define RFGZONE_H
#include "playerzone.h"
class RfgZone : public PlayerZone {
private:
public:
RfgZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1);
void reorganizeCards();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
};
#endif

View file

@ -0,0 +1,49 @@
#include "servereventdata.h"
// Message structure for server events:
// {"private","public"}|PlayerId|PlayerName|EventType|EventData
const int event_count = 19;
const event_string event_strings[event_count] = {
{eventPlayerId, "player_id"},
{eventSay, "say"},
{eventName, "name"},
{eventJoin, "join"},
{eventLeave, "leave"},
{eventReadyStart, "ready_start"},
{eventSetupZones, "setup_zones"},
{eventGameStart, "game_start"},
{eventShuffle, "shuffle"},
{eventRollDice, "roll_dice"},
{eventDraw, "draw"},
{eventMoveCard, "move_card"},
{eventCreateToken, "create_token"},
{eventSetCardAttr, "set_card_attr"},
{eventSetCounter, "set_counter"},
{eventDelCounter, "del_counter"},
{eventSetActivePlayer, "set_active_player"},
{eventSetActivePhase, "set_active_phase"},
{eventDumpZone, "dump_zone"}
};
ServerEventData::ServerEventData(const QString &line)
{
QStringList values = line.split("|");
IsPublic = !values.takeFirst().compare("public");
PlayerId = values.takeFirst().toInt();
PlayerName = values.takeFirst();
QString type = values.takeFirst();
bool found = false;
for (int i = 0; i < event_count; i++)
if (!type.compare(event_strings[i].str)) {
EventType = event_strings[i].type;
found = true;
break;
}
if (!found)
EventType = eventInvalid;
EventData = values;
}

View file

@ -0,0 +1,54 @@
#ifndef SERVEREVENTDATA_H
#define SERVEREVENTDATA_H
#include <QStringList>
enum ServerEventType {
eventInvalid,
eventPlayerId,
eventSay,
eventName,
eventJoin,
eventLeave,
eventReadyStart,
eventSetupZones,
eventGameStart,
eventShuffle,
eventRollDice,
eventDraw,
eventMoveCard,
eventCreateToken,
eventSetCardAttr,
eventSetCounter,
eventDelCounter,
eventSetActivePlayer,
eventSetActivePhase,
eventDumpZone
};
struct event_string {
ServerEventType type;
char *str;
};
extern const int event_count;
extern const event_string event_strings[];
class ServerEventData {
private:
bool IsPublic;
int PlayerId;
QString PlayerName;
ServerEventType EventType;
QStringList EventData;
public:
ServerEventData(const QString &line);
bool getPublic() { return IsPublic; }
int getPlayerId() { return PlayerId; }
QString getPlayerName() { return PlayerName; }
ServerEventType getEventType() { return EventType; }
QStringList getEventData() { return EventData; }
};
#endif

View file

@ -0,0 +1,21 @@
#ifndef SERVERGAME_H
#define SERVERGAME_H
class ServerGame {
private:
QString name;
QString description;
bool hasPassword;
unsigned char playerCount;
unsigned char maxPlayers;
public:
ServerGame(const QString &_name, const QString &_description, bool _hasPassword, unsigned char _playerCount, unsigned char _maxPlayers)
: name(_name), description(_description), hasPassword(_hasPassword), playerCount(_playerCount), maxPlayers(_maxPlayers) { }
QString getName() { return name; }
QString getDescription() { return description; }
bool getHasPassword() { return hasPassword; }
unsigned char getPlayerCount() { return playerCount; }
unsigned char getMaxPlayers() { return maxPlayers; }
};
#endif

View file

@ -0,0 +1,17 @@
#ifndef SERVERPLAYER_H
#define SERVERPLAYER_H
#include <QString>
class ServerPlayer {
private:
int PlayerId;
QString name;
public:
ServerPlayer(int _PlayerId, const QString &_name)
: PlayerId(_PlayerId), name(_name) { }
int getPlayerId() { return PlayerId; }
QString getName() { return name; }
};
#endif

View file

@ -0,0 +1,22 @@
#ifndef SERVERRESPONSE_H
#define SERVERRESPONSE_H
enum ServerErrorMessage {
msgNone,
msgSyntaxError
};
class ServerResponse {
private:
int msgId;
bool ok;
ServerErrorMessage message;
public:
ServerResponse(int _msgId, bool _ok, ServerErrorMessage _message)
: msgId(_msgId), ok(_ok), message(_message) { }
int getMsgId() { return msgId; }
bool getOk() { return ok; }
ServerErrorMessage getMessage() { return message; }
};
#endif

View file

@ -0,0 +1,21 @@
#ifndef SERVERZONE_H
#define SERVERZONE_H
#include <QString>
class ServerZone {
private:
QString name;
bool isPublic;
bool hasCoords;
int cardCount;
public:
ServerZone(const QString &_name, bool _isPublic, bool _hasCoords, int _cardCount)
: name(_name), isPublic(_isPublic), hasCoords(_hasCoords), cardCount(_cardCount) { }
QString getName() const { return name; }
bool getPublic() const { return isPublic; }
bool getHasCoords() const { return hasCoords; }
int getCardCount() const { return cardCount; }
};
#endif

View file

@ -0,0 +1,28 @@
#ifndef SERVERZONECARD_H
#define SERVERZONECARD_H
#include <QString>
class ServerZoneCard {
private:
int id;
QString name;
int x, y;
int counters;
bool tapped;
bool attacking;
QString annotation;
public:
ServerZoneCard(int _id, const QString &_name, int _x, int _y, int _counters, bool _attacking, const QString &_annotation)
: id(_id), name(_name), x(_x), y(_y), counters(_counters), attacking(_attacking), annotation(_annotation) { }
int getId() const { return id; }
QString getName() const { return name; }
int getX() const { return x; }
int getY() const { return y; }
int getCounters() const { return counters; }
bool getTapped() const { return tapped; }
bool getAttacking() const { return attacking; }
QString getAnnotation() const { return annotation; }
};
#endif

View file

@ -0,0 +1,54 @@
#include <QtGui>
#include "sideboardzone.h"
#include "player.h"
#include "client.h"
#include "zoneviewzone.h"
SideboardZone::SideboardZone(Player *_p)
: PlayerZone(_p, "sb")
{
cards = new CardList(false);
}
QRectF SideboardZone::boundingRect() const
{
return QRectF(0, 0, 50, 50);
}
void SideboardZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->save();
painter->fillRect(boundingRect(), QColor("blue"));
painter->setFont(QFont("Times", 20, QFont::Bold));
painter->setPen(QPen(QColor("black")));
painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(cards->size()));
painter->restore();
}
void SideboardZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
for (int i = 0; i < views.size(); i++)
views[i]->addCard(new CardItem(player->getDb(), card->getName(), card->getId()), reorganize, x, y);
cards->insert(x, card);
card->setPos(0, 0);
card->setVisible(false);
card->resetState();
card->setParentItem(this);
if (reorganize)
reorganizeCards();
}
void SideboardZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0);
}
void SideboardZone::reorganizeCards()
{
update(boundingRect());
}

View file

@ -0,0 +1,17 @@
#ifndef SIDEBOARDZONE_H
#define SIDEBOARDZONE_H
#include "playerzone.h"
class SideboardZone : public PlayerZone {
private:
public:
SideboardZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1);
void reorganizeCards();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
};
#endif

View file

@ -0,0 +1,56 @@
#include <QtGui>
#include "tablezone.h"
#include "player.h"
#include "client.h"
TableZone::TableZone(Player *_p)
: PlayerZone(_p, "table"), width(700), height(500)
{
cards = new CardList(true);
hasCardAttr = true;
}
QRectF TableZone::boundingRect() const
{
return QRectF(0, 0, width, height);
}
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->fillRect(boundingRect(), QColor("blue"));
}
void TableZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
Q_UNUSED(reorganize);
cards->append(card);
if ((x != -1) && (y != -1)) {
if (!player->getLocal())
y = height - CARD_HEIGHT - y;
card->setPos(x, y);
}
card->setZValue((y + CARD_HEIGHT) * width + x + 1000);
card->setParentItem(this);
card->setVisible(true);
card->update(card->boundingRect());
}
void TableZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
player->client->moveCard(cardId, startZone->getName(), getName(), dropPoint.x(), dropPoint.y());
}
void TableZone::reorganizeCards()
{
}
void TableZone::toggleTapped()
{
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *temp = (CardItem *) i.next();
setCardAttr(temp->getId(), "tapped", temp->getTapped() ? "0" : "1");
}
}

View file

@ -0,0 +1,22 @@
#ifndef TABLEZONE_H
#define TABLEZONE_H
#include "playerzone.h"
const int GRID_WIDTH = 30;
const int GRID_HEIGHT = 30;
class TableZone : public PlayerZone {
private:
int width, height;
public:
TableZone(Player *_p);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = -1, int y = -1);
void reorganizeCards();
void toggleTapped();
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
};
#endif

258
cockatrice/src/window.cpp Normal file
View file

@ -0,0 +1,258 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@gmx.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QtGui>
#include <QtOpenGL>
#include "window.h"
#include "dlg_connect.h"
#include "dlg_games.h"
#include "cardinfowidget.h"
#include "messagelogwidget.h"
#include "gameview.h"
#include "player.h"
#include "game.h"
#include "carddatabase.h"
#include "zoneviewzone.h"
#include "zoneviewwidget.h"
#include "zoneviewlayout.h"
void MainWindow::hoverCard(QString name)
{
cardInfo->setCard(name);
}
void MainWindow::playerAdded(Player *player)
{
menuBar()->addMenu(player->getPlayerMenu());
connect(player, SIGNAL(addZoneView(Player *, QString, int)), zoneLayout, SLOT(addItem(Player *, QString, int)));
}
void MainWindow::playerRemoved(Player *player)
{
menuBar()->removeAction(player->getPlayerMenu()->menuAction());
}
void MainWindow::statusChanged(ProtocolStatus _status)
{
switch (_status) {
case StatusConnecting:
emit logConnecting(client->peerName());
break;
case StatusDisconnected:
if (game) {
delete game;
game = 0;
}
aDisconnect->setEnabled(false);
aGames->setEnabled(false);
aRestartGame->setEnabled(false);
aLeaveGame->setEnabled(false);
emit logDisconnected();
break;
case StatusConnected:
aDisconnect->setEnabled(true);
aGames->setEnabled(true);
default:
break;
}
}
// Actions
void MainWindow::actConnect()
{
DlgConnect dlg(this);
if (dlg.exec())
client->connectToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName());
}
void MainWindow::actDisconnect()
{
client->disconnectFromServer();
}
void MainWindow::actGames()
{
DlgGames dlg(client, this);
dlg.exec();
}
void MainWindow::actLeaveGame()
{
client->leaveGame();
delete game;
game = 0;
aRestartGame->setEnabled(false);
aLeaveGame->setEnabled(false);
aGames->setEnabled(true);
}
void MainWindow::actExit()
{
close();
}
void MainWindow::updateSceneSize()
{
QRectF sr = scene->sceneRect();
QSizeF zoneSize = zoneLayout->size();
qDebug(QString("updateSceneSize: width=%1").arg(850 + zoneSize.width()).toLatin1());
scene->setSceneRect(sr.x(), sr.y(), 850 + zoneSize.width(), sr.height());
view->scaleToScene();
}
// Knöpfe
void MainWindow::buttonSay()
{
client->say(sayEdit->text());
sayEdit->clear();
}
void MainWindow::playerIdReceived(int id, QString name)
{
game = new Game(db, client, scene, actionsMenu, cardMenu, id, name);
connect(game, SIGNAL(submitDecklist()), this, SLOT(decklistDialog()));
connect(game, SIGNAL(hoverCard(QString)), this, SLOT(hoverCard(QString)));
connect(game, SIGNAL(playerAdded(Player *)), this, SLOT(playerAdded(Player *)));
connect(game, SIGNAL(playerRemoved(Player *)), this, SLOT(playerRemoved(Player *)));
connect(aRestartGame, SIGNAL(triggered()), game, SLOT(restartGameDialog()));
playerAdded(game->getLocalPlayer());
messageLog->connectToGame(game);
aGames->setEnabled(false);
aRestartGame->setEnabled(true);
aLeaveGame->setEnabled(true);
client->listPlayers();
}
void MainWindow::serverTimeout()
{
QMessageBox::critical(this, tr("Error"), tr("Server timeout"));
}
void MainWindow::createActions()
{
aConnect = new QAction(tr("&Connect..."), this);
connect(aConnect, SIGNAL(triggered()), this, SLOT(actConnect()));
aDisconnect = new QAction(tr("&Disconnect"), this);
aDisconnect->setEnabled(false);
connect(aDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect()));
aGames = new QAction(tr("&Games..."), this);
aGames->setEnabled(false);
connect(aGames, SIGNAL(triggered()), this, SLOT(actGames()));
aRestartGame = new QAction(tr("&Restart game..."), this);
aRestartGame->setShortcut(tr("F2"));
aRestartGame->setEnabled(false);
aLeaveGame = new QAction(tr("&Leave game"), this);
aLeaveGame->setEnabled(false);
connect(aLeaveGame, SIGNAL(triggered()), this, SLOT(actLeaveGame()));
aExit = new QAction(tr("&Exit"), this);
connect(aExit, SIGNAL(triggered()), this, SLOT(actExit()));
}
void MainWindow::createMenus()
{
gameMenu = menuBar()->addMenu(tr("&Game"));
gameMenu->addAction(aConnect);
gameMenu->addAction(aDisconnect);
gameMenu->addSeparator();
gameMenu->addAction(aGames);
gameMenu->addAction(aRestartGame);
gameMenu->addAction(aLeaveGame);
gameMenu->addSeparator();
gameMenu->addAction(aExit);
actionsMenu = menuBar()->addMenu(tr("&Actions"));
cardMenu = menuBar()->addMenu(tr("&Card"));
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), game(NULL)
{
// setWindowState(windowState() | Qt::WindowFullScreen);
QPixmapCache::setCacheLimit(200000);
createActions();
createMenus();
db = new CardDatabase;
int cardCount = db->loadFromFile("../cards.dat");
qDebug(QString("%1 cards loaded").arg(cardCount).toLatin1());
scene = new QGraphicsScene(0, 0, 850, 1000, this);
view = new GameView(scene);
// view->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
// view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
zoneLayout = new ZoneViewLayout(db);
zoneLayout->setPos(850, 0);
scene->addItem(zoneLayout);
connect(zoneLayout, SIGNAL(sizeChanged()), this, SLOT(updateSceneSize()));
cardInfo = new CardInfoWidget(db);
messageLog = new MessageLogWidget;
sayEdit = new QLineEdit;
sayButton = new QPushButton(tr("&Say"));
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(sayEdit);
hLayout->addWidget(sayButton);
QVBoxLayout *verticalLayout = new QVBoxLayout;
verticalLayout->addWidget(cardInfo);
verticalLayout->addWidget(messageLog);
verticalLayout->addLayout(hLayout);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(view);
mainLayout->setStretchFactor(view, 10);
mainLayout->addLayout(verticalLayout);
QWidget *centralWidget = new QWidget;
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(buttonSay()));
connect(sayButton, SIGNAL(clicked()), this, SLOT(buttonSay()));
client = new Client(this);
connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout()));
connect(client, SIGNAL(statusChanged(ProtocolStatus)), this, SLOT(statusChanged(ProtocolStatus)));
connect(client, SIGNAL(playerIdReceived(int, QString)), this, SLOT(playerIdReceived(int, QString)));
connect(this, SIGNAL(logConnecting(QString)), messageLog, SLOT(logConnecting(QString)));
connect(client, SIGNAL(welcomeMsgReceived(const QStringList)), messageLog, SLOT(logConnected(const QStringList)));
connect(this, SIGNAL(logDisconnected()), messageLog, SLOT(logDisconnected()));
connect(client, SIGNAL(logSocketError(const QString &)), messageLog, SLOT(logSocketError(const QString &)));
}
void MainWindow::closeEvent(QCloseEvent *event)
{
delete game;
// db->importOracle();
// db->saveToFile("../cards.dat");
delete db;
}

85
cockatrice/src/window.h Normal file
View file

@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (C) 2008 by Max-Wilhelm Bruker *
* brukie@gmx.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef WINDOW_H
#define WINDOW_H
#include <QMainWindow>
#include "client.h"
class QGraphicsScene;
class GameView;
class Game;
class CardDatabase;
class Player;
class CardInfoWidget;
class MessageLogWidget;
class QLineEdit;
class QPushButton;
class ServerZoneCard;
class ZoneViewLayout;
class ZoneViewWidget;
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
void hoverCard(QString name);
void playerAdded(Player *player);
void playerRemoved(Player *player);
void statusChanged(ProtocolStatus _status);
void playerIdReceived(int id, QString name);
void serverTimeout();
void buttonSay();
void actConnect();
void actDisconnect();
void actGames();
void actLeaveGame();
void actExit();
void updateSceneSize();
signals:
void logConnecting(QString hostname);
void logDisconnected();
private:
void createActions();
void createMenus();
QMenu *gameMenu, *actionsMenu, *cardMenu;
QAction *aConnect, *aDisconnect, *aGames, *aRestartGame, *aLeaveGame, *aExit;
CardInfoWidget *cardInfo;
MessageLogWidget *messageLog;
QLineEdit *sayEdit;
QPushButton *sayButton;
Client *client;
QGraphicsScene *scene;
GameView *view;
Game *game;
CardDatabase *db;
ZoneViewLayout *zoneLayout;
public:
MainWindow(QWidget *parent = 0);
protected:
void closeEvent(QCloseEvent *event);
};
#endif

View file

@ -0,0 +1,18 @@
#include <QtGui>
#include "zoneclosebutton.h"
void ZoneCloseButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
emit triggered();
}
void ZoneCloseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->fillRect(rect(), QColor("red"));
}
ZoneCloseButton::ZoneCloseButton(QGraphicsItem *parent)
: QGraphicsWidget(parent)
{
resize(20, 20);
}

View file

@ -0,0 +1,17 @@
#ifndef ZONECLOSEBUTTON_H
#define ZONECLOSEBUTTON_H
#include <QGraphicsWidget>
class ZoneCloseButton : public QGraphicsWidget {
Q_OBJECT
signals:
void triggered();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
public:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
ZoneCloseButton(QGraphicsItem *parent = 0);
};
#endif

View file

@ -0,0 +1,11 @@
#include "zonelist.h"
PlayerZone *ZoneList::findZone(const QString &name) const
{
for (int i = 0; i < size(); i++) {
PlayerZone *temp = at(i);
if (!temp->getName().compare(name))
return temp;
}
return 0;
}

12
cockatrice/src/zonelist.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef ZONELIST_H
#define ZONELIST_H
#include "playerzone.h"
#include <QList>
class ZoneList : public QList<PlayerZone *> {
public:
PlayerZone *findZone(const QString &name) const;
};
#endif

View file

@ -0,0 +1,36 @@
#include "zoneviewlayout.h"
#include "zoneviewwidget.h"
#include "player.h"
ZoneViewLayout::ZoneViewLayout(CardDatabase *_db, QGraphicsItem *parent)
: QGraphicsWidget(parent), db(_db)
{
}
void ZoneViewLayout::reorganize()
{
qDebug(QString("ZoneViewLayout: activate: count=%1").arg(views.size()).toLatin1());
resize(views.size() * 150, 1000);
for (int i = 0; i < views.size(); i++) {
views.at(i)->setPos(i * 150, 0);
}
emit sizeChanged();
}
void ZoneViewLayout::addItem(Player *player, const QString &zoneName, int numberCards)
{
ZoneViewWidget *item = new ZoneViewWidget(db, player, player->getZones()->findZone(zoneName), numberCards, this);
views.append(item);
connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeItem(ZoneViewWidget *)));
reorganize();
}
void ZoneViewLayout::removeItem(ZoneViewWidget *item)
{
qDebug("ZoneViewLayout::removeItem");
views.removeAt(views.indexOf(item));
scene()->removeItem(item);
delete item;
reorganize();
}

View file

@ -0,0 +1,25 @@
#ifndef ZONEVIEWLAYOUT_H
#define ZONEVIEWLAYOUT_H
#include <QGraphicsWidget>
class CardDatabase;
class ZoneViewWidget;
class Player;
class ZoneViewLayout : public QGraphicsWidget {
Q_OBJECT
signals:
void sizeChanged();
private:
QList<ZoneViewWidget *> views;
CardDatabase *db;
public:
ZoneViewLayout(CardDatabase *_db, QGraphicsItem *parent = 0);
void reorganize();
public slots:
void addItem(Player *player, const QString &zoneName, int numberCards = 0);
void removeItem(ZoneViewWidget *item);
};
#endif

View file

@ -0,0 +1,45 @@
#include <QtGui>
#include "zoneviewwidget.h"
#include "carditem.h"
#include "zoneviewzone.h"
#include "player.h"
#include "client.h"
#include "zoneclosebutton.h"
ZoneViewWidget::ZoneViewWidget(CardDatabase *_db, Player *_player, PlayerZone *_origZone, int numberCards, QGraphicsItem *parent)
: QGraphicsWidget(parent), db(_db), player(_player)
{
ZoneCloseButton *closeButton = new ZoneCloseButton(this);
connect(closeButton, SIGNAL(triggered()), this, SLOT(slotClosePressed()));
resize(150, 1000);
zone = new ZoneViewZone(player, _origZone, numberCards, this);
zone->setPos(0, 30);
if (!zone->initializeCards()) {
connect(player->client, SIGNAL(zoneDumpReceived(int, QList<ServerZoneCard *>)), this, SLOT(zoneDumpReceived(int, QList<ServerZoneCard *>)));
cmdId = player->client->dumpZone(player->getId(), _origZone->getName(), numberCards);
}
}
void ZoneViewWidget::zoneDumpReceived(int commandId, QList<ServerZoneCard *> cards)
{
if (commandId != cmdId)
return;
for (int i = 0; i < cards.size(); i++) {
ServerZoneCard *temp = cards[i];
CardItem *card = new CardItem(db, temp->getName(), i, zone);
zone->addCard(card, false, i);
delete temp;
}
zone->reorganizeCards();
}
void ZoneViewWidget::slotClosePressed()
{
emit closePressed(this);
}

View file

@ -0,0 +1,31 @@
#ifndef ZONEVIEWWIDGET_H
#define ZONEVIEWWIDGET_H
#include <QDialog>
#include <QGraphicsScene>
#include <QGraphicsWidget>
#include "serverzonecard.h"
class PlayerZone;
class ZoneViewZone;
class Player;
class CardDatabase;
class ZoneViewWidget : public QGraphicsWidget {
Q_OBJECT
private:
ZoneViewZone *zone;
int cmdId;
CardDatabase *db;
Player *player;
signals:
void closePressed(ZoneViewWidget *zv);
private slots:
void zoneDumpReceived(int commandId, QList<ServerZoneCard *> cards);
void slotClosePressed();
public:
ZoneViewWidget(CardDatabase *_db, Player *_player, PlayerZone *_origZone, int numberCards = 0, QGraphicsItem *parent = 0);
};
#endif

View file

@ -0,0 +1,104 @@
#include <QtGui>
#include "zoneviewzone.h"
#include "player.h"
#include "client.h"
ZoneViewZone::ZoneViewZone(Player *_p, PlayerZone *_origZone, int _numberCards, QGraphicsItem *parent)
: PlayerZone(_p, _origZone->getName(), parent, true), numberCards(_numberCards), origZone(_origZone)
{
cards = new CardList(true);
origZone->addView(this);
}
ZoneViewZone::~ZoneViewZone()
{
qDebug("ZoneViewZone destructor");
origZone->removeView(this);
}
QRectF ZoneViewZone::boundingRect() const
{
return QRectF(0, 0, CARD_WIDTH * 1.75, scene()->sceneRect().height());
}
void ZoneViewZone::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
bool ZoneViewZone::initializeCards()
{
if (!origZone->contentsKnown())
return false;
CardList *const c = origZone->getCards();
int number = numberCards == 0 ? c->size() : (numberCards < c->size() ? numberCards : c->size());
for (int i = 0; i < number; i++) {
CardItem *card = c->at(i);
addCard(new CardItem(player->getDb(), card->getName(), card->getId(), this), false, i);
}
reorganizeCards();
return true;
}
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
void ZoneViewZone::reorganizeCards()
{
qDebug("reorganizeCards");
if (cards->isEmpty())
return;
int cardCount = cards->size();
qreal totalWidth = boundingRect().width();
qreal totalHeight = boundingRect().height();
qreal cardWidth = cards->at(0)->boundingRect().width();
qreal cardHeight = cards->at(0)->boundingRect().height();
qreal x1 = 0;
qreal x2 = (totalWidth - cardWidth);
for (int i = 0; i < cardCount; i++) {
CardItem *c = cards->at(i);
qreal x = i % 2 ? x2 : x1;
// If the total height of the cards is smaller than the available height,
// the cards do not need to overlap and are displayed in the center of the area.
if (cardHeight * cardCount > totalHeight)
c->setPos(x, ((qreal) i) * (totalHeight - cardHeight) / (cardCount - 1));
else
c->setPos(x, ((qreal) i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2);
if (!origZone->contentsKnown())
c->setId(i);
c->setZValue(i);
}
}
void ZoneViewZone::addCard(CardItem *card, bool reorganize, int x, int y)
{
Q_UNUSED(y);
qDebug(QString("ZoneViewZone: inserting '%1' at x=%2").arg(card->getName()).arg(x).toLatin1());
cards->insert(x, card);
card->setParentItem(this);
card->update(card->boundingRect());
if (reorganize)
reorganizeCards();
}
void ZoneViewZone::handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint)
{
Q_UNUSED(dropPoint);
qDebug(QString("handleDropEvent id=%1").arg(cardId).toLatin1());
player->client->moveCard(cardId, startZone->getName(), getName(), 0, 0);
}
void ZoneViewZone::removeCard(int position)
{
if (position >= cards->size())
return;
CardItem *card = cards->at(position);
cards->removeAt(position);
delete card;
reorganizeCards();
}

View file

@ -0,0 +1,27 @@
#ifndef ZONEVIEWERZONE_H
#define ZONEVIEWERZONE_H
#include "playerzone.h"
#include "serverzonecard.h"
class ZoneViewWidget;
class ZoneViewZone : public PlayerZone {
private:
int numberCards;
void handleDropEvent(int cardId, PlayerZone *startZone, const QPoint &dropPoint);
PlayerZone *origZone;
signals:
void removeZoneViewWidget(ZoneViewWidget *zv);
public:
ZoneViewZone(Player *_p, PlayerZone *_origZone, int _numberCards = 0, QGraphicsItem *parent = 0);
~ZoneViewZone();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void addCard(CardItem *card, bool reorganize = true, int x = 0, int y = -1);
void reorganizeCards();
bool initializeCards();
void removeCard(int position);
};
#endif