#include #include #include #include #include #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" #include "playerarea.h" #include "counter.h" Game::Game(CardDatabase *_db, Client *_client, QGraphicsScene *_scene, QMenu *_actionsMenu, QMenu *_cardMenu, int playerId, const QString &playerName, QObject *parent) : QObject(parent), actionsMenu(_actionsMenu), cardMenu(_cardMenu), db(_db), client(_client), scene(_scene), started(false), currentPhase(-1) { QRectF sr = scene->sceneRect(); localPlayer = addPlayer(playerId, playerName, QPointF(0, sr.y() + sr.height() / 2 + 2), true); connect(client, SIGNAL(gameEvent(const ServerEventData &)), this, SLOT(gameEvent(const ServerEventData &))); connect(client, SIGNAL(playerListReceived(QList)), this, SLOT(playerListReceived(QList))); 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())); 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())); aNextPhase = new QAction(tr("Next &phase"), this); aNextPhase->setShortcut(tr("Ctrl+Space")); connect(aNextPhase, SIGNAL(triggered()), this, SLOT(actNextPhase())); aNextTurn = new QAction(tr("Next &turn"), this); aNextTurn->setShortcuts(QList() << QKeySequence(tr("Ctrl+Return")) << QKeySequence(tr("Ctrl+Enter"))); connect(aNextTurn, SIGNAL(triggered()), this, SLOT(actNextTurn())); actionsMenu->addAction(aNextPhase); actionsMenu->addAction(aNextTurn); actionsMenu->addSeparator(); actionsMenu->addAction(aUntapAll); actionsMenu->addSeparator(); actionsMenu->addAction(aDecLife); actionsMenu->addAction(aIncLife); actionsMenu->addAction(aSetLife); actionsMenu->addSeparator(); actionsMenu->addAction(aRollDice); actionsMenu->addSeparator(); actionsMenu->addAction(aCreateToken); actionsMenu->addSeparator(); sayMenu = actionsMenu->addMenu(tr("S&ay")); initSayMenu(); aTap = new QAction(tr("&Tap"), this); aUntap = new QAction(tr("&Untap"), this); aDoesntUntap = new QAction(tr("Toggle &normal untapping"), this); aFlip = new QAction(tr("&Flip"), this); aAddCounter = new QAction(tr("&Add counter"), this); aRemoveCounter = new QAction(tr("&Remove counter"), this); aSetCounters = new QAction(tr("&Set counters..."), this); connect(aSetCounters, SIGNAL(triggered()), this, SLOT(actSetCounters())); aMoveToTopLibrary = new QAction(tr("&top of library"), this); aMoveToBottomLibrary = new QAction(tr("&bottom of library"), this); aMoveToGraveyard = new QAction(tr("&graveyard"), this); aMoveToExile = new QAction(tr("&exile"), this); cardMenu->addAction(aTap); cardMenu->addAction(aUntap); cardMenu->addAction(aDoesntUntap); cardMenu->addSeparator(); cardMenu->addAction(aFlip); cardMenu->addSeparator(); cardMenu->addAction(aAddCounter); cardMenu->addAction(aRemoveCounter); cardMenu->addAction(aSetCounters); cardMenu->addSeparator(); moveMenu = cardMenu->addMenu(tr("&Move to")); moveMenu->addAction(aMoveToTopLibrary); moveMenu->addAction(aMoveToBottomLibrary); moveMenu->addAction(aMoveToGraveyard); moveMenu->addAction(aMoveToExile); cardMenuHandlers.insert(aTap, &Game::actTap); cardMenuHandlers.insert(aUntap, &Game::actUntap); cardMenuHandlers.insert(aDoesntUntap, &Game::actDoesntUntap); cardMenuHandlers.insert(aFlip, &Game::actFlip); cardMenuHandlers.insert(aAddCounter, &Game::actAddCounter); cardMenuHandlers.insert(aRemoveCounter, &Game::actRemoveCounter); cardMenuHandlers.insert(aMoveToTopLibrary, &Game::actMoveToTopLibrary); cardMenuHandlers.insert(aMoveToBottomLibrary, &Game::actMoveToBottomLibrary); cardMenuHandlers.insert(aMoveToGraveyard, &Game::actMoveToGraveyard); cardMenuHandlers.insert(aMoveToExile, &Game::actMoveToExile); QHashIterator i(cardMenuHandlers); while (i.hasNext()) { i.next(); connect(i.key(), SIGNAL(triggered()), this, SLOT(cardMenuAction())); } dlgStartGame = new DlgStartGame(db); connect(dlgStartGame, SIGNAL(newDeckLoaded(const QStringList &)), client, SLOT(submitDeck(const QStringList &))); connect(dlgStartGame, SIGNAL(finished(int)), this, SLOT(readyStart())); } Game::~Game() { qDebug("Game destructor"); for (int i = 0; i < players.size(); i++) { emit playerRemoved(players.at(i)); delete players.at(i); } } void Game::initSayMenu() { sayMenu->clear(); QSettings settings; settings.beginGroup("messages"); int count = settings.value("count", 0).toInt(); for (int i = 0; i < count; i++) { QAction *newAction = new QAction(settings.value(QString("msg%1").arg(i)).toString(), this); QString shortcut; switch (i) { case 0: shortcut = tr("F5"); break; case 1: shortcut = tr("F6"); break; case 2: shortcut = tr("F7"); break; case 3: shortcut = tr("F8"); break; case 4: shortcut = tr("F9"); break; case 5: shortcut = tr("F10"); break; } newAction->setShortcut(shortcut); connect(newAction, SIGNAL(triggered()), this, SLOT(actSayMessage())); sayMenu->addAction(newAction); } } Player *Game::addPlayer(int playerId, const QString &playerName, QPointF base, bool local) { Player *newPlayer = new Player(playerName, playerId, base, local, db, client, scene, this); connect(newPlayer, SIGNAL(sigShowCardMenu(QPoint)), this, SLOT(showCardMenu(QPoint))); connect(newPlayer, SIGNAL(logMoveCard(Player *, QString, CardZone *, int, CardZone *, int)), this, SIGNAL(logMoveCard(Player *, QString, CardZone *, int, CardZone *, int))); connect(newPlayer, SIGNAL(logCreateToken(Player *, QString)), this, SIGNAL(logCreateToken(Player *, QString))); connect(newPlayer, SIGNAL(logSetCardCounters(Player *, QString, int, int)), this, SIGNAL(logSetCardCounters(Player *, QString, int, int))); connect(newPlayer, SIGNAL(logSetTapped(Player *, QString, bool)), this, SIGNAL(logSetTapped(Player *, QString, bool))); connect(newPlayer, SIGNAL(logSetCounter(Player *, QString, int, int)), this, SIGNAL(logSetCounter(Player *, QString, int, int))); connect(newPlayer, SIGNAL(logSetDoesntUntap(Player *, QString, bool)), this, SIGNAL(logSetDoesntUntap(Player *, QString, bool))); players << newPlayer; emit playerAdded(newPlayer); return newPlayer; } void Game::playerListReceived(QList playerList) { QListIterator 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::readyStart() { client->readyStart(); } void Game::restartGameDialog() { dlgStartGame->show(); } void Game::gameEvent(const ServerEventData &msg) { qDebug(QString("game::gameEvent: public=%1, player=%2, name=%3, type=%4, data=%5").arg(msg.getPublic()).arg(msg.getPlayerId()).arg(msg.getPlayerName()).arg(msg.getEventType()).arg(msg.getEventData().join("/")).toLatin1()); if (!msg.getPublic()) localPlayer->gameEvent(msg); else { Player *p = players.findPlayer(msg.getPlayerId()); if ((!p) && (msg.getEventType() != eventJoin)) { // XXX } switch(msg.getEventType()) { case eventSay: emit logSay(p, msg.getEventData()[0]); break; case eventJoin: { Player *newPlayer = addPlayer(msg.getPlayerId(), msg.getPlayerName(), QPointF(0, 0), false); emit logJoin(newPlayer); break; } case eventLeave: emit logLeave(p); // XXX Spieler natürlich noch rauswerfen break; case eventReadyStart: if (started) { started = false; emit logReadyStart(p); if (!p->getLocal()) restartGameDialog(); } break; case eventGameStart: started = true; emit logGameStart(); break; case eventShuffle: emit logShuffle(p); break; case eventRollDice: { QStringList data = msg.getEventData(); int sides = data[0].toInt(); int roll = data[1].toInt(); emit logRollDice(p, sides, roll); break; } case eventSetActivePlayer: { QStringList data = msg.getEventData(); int playerId = data[0].toInt(); Player *player = players.findPlayer(playerId); if (!player) { qDebug(QString("setActivePlayer: invalid player: %1").arg(playerId).toLatin1()); break; } for (int i = 0; i < players.size(); ++i) players[i]->setActive(players[i] == player); emit logSetActivePlayer(player); break; } case eventSetActivePhase: { QStringList data = msg.getEventData(); int phase = data[0].toInt(); currentPhase = phase; emit setActivePhase(phase); break; } case eventName: case eventCreateToken: case eventSetupZones: case eventSetCardAttr: case eventAddCounter: case eventSetCounter: case eventDelCounter: case eventPlayerId: { p->gameEvent(msg); break; } case eventDumpZone: { QStringList data = msg.getEventData(); emit logDumpZone(p, data[1], players.findPlayer(data[0].toInt())->getName(), data[2].toInt()); break; } case eventStopDumpZone: { QStringList data = msg.getEventData(); emit logStopDumpZone(p, data[1], players.findPlayer(data[0].toInt())->getName()); break; } case eventMoveCard: { if (msg.getPlayerId() == localPlayer->getId()) break; p->gameEvent(msg); break; } case eventDraw: { emit logDraw(p, msg.getEventData()[0].toInt()); if (msg.getPlayerId() == localPlayer->getId()) break; p->gameEvent(msg); break; } case eventInvalid: { qDebug("Unhandled global event"); } default: { } } } } void Game::actNextPhase() { int phase = currentPhase; if (++phase >= phaseCount) phase = 0; client->setActivePhase(phase); } void Game::actNextTurn() { client->nextTurn(); } void Game::actUntapAll() { client->setCardAttr("table", -1, "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->area->getCounter("life")->getValue(), 0, 2000000000, 1, &ok); if (ok) client->setCounter("life", life); } 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::actCreateToken() { QString cardname = QInputDialog::getText(0, tr("Create token"), tr("Name:")); client->createToken("table", cardname, QString(), 0, 0); } void Game::showCardMenu(QPoint p) { cardMenu->exec(p); } void Game::cardMenuAction() { // Determine the appropriate handler function. CardMenuHandler handler = cardMenuHandlers.value(static_cast(sender())); // The list of selected items is randomly shuffled. QList sel = scene->selectedItems(); while (!sel.isEmpty()) { unsigned int i = (unsigned int) (((double) sel.size()) * qrand() / (RAND_MAX + 1.0)); qDebug(QString("%1 items left, i=%2").arg(sel.size()).arg(i).toLatin1()); CardItem *card = qgraphicsitem_cast(sel.takeAt(i)); // For each item, the handler function is called. (this->*handler)(card); } } void Game::actTap(CardItem *card) { if (!card->getTapped()) client->setCardAttr(qgraphicsitem_cast(card->parentItem())->getName(), card->getId(), "tapped", "1"); } void Game::actUntap(CardItem *card) { if (card->getTapped()) client->setCardAttr(qgraphicsitem_cast(card->parentItem())->getName(), card->getId(), "tapped", "0"); } void Game::actDoesntUntap(CardItem *card) { client->setCardAttr(qgraphicsitem_cast(card->parentItem())->getName(), card->getId(), "doesnt_untap", QString::number(!card->getDoesntUntap())); } void Game::actFlip(CardItem *card) { QString zone = qgraphicsitem_cast(card->parentItem())->getName(); client->moveCard(card->getId(), zone, zone, card->getGridPoint().x(), card->getGridPoint().y(), !card->getFaceDown()); } void Game::actAddCounter(CardItem *card) { if (card->getCounters() < MAX_COUNTERS_ON_CARD) client->setCardAttr(qgraphicsitem_cast(card->parentItem())->getName(), card->getId(), "counters", QString::number(card->getCounters() + 1)); } void Game::actRemoveCounter(CardItem *card) { if (card->getCounters()) client->setCardAttr(qgraphicsitem_cast(card->parentItem())->getName(), card->getId(), "counters", QString::number(card->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 i(scene->selectedItems()); while (i.hasNext()) { CardItem *temp = (CardItem *) i.next(); client->setCardAttr(qgraphicsitem_cast(temp->parentItem())->getName(), temp->getId(), "counters", QString::number(number)); } } void Game::actMoveToTopLibrary(CardItem *card) { CardZone *startZone = qgraphicsitem_cast(card->parentItem()); client->moveCard(card->getId(), startZone->getName(), "deck", 0, 0, false); } void Game::actMoveToBottomLibrary(CardItem *card) { CardZone *startZone = qgraphicsitem_cast(card->parentItem()); client->moveCard(card->getId(), startZone->getName(), "deck", -1, 0, false); } void Game::actMoveToGraveyard(CardItem *card) { CardZone *startZone = qgraphicsitem_cast(card->parentItem()); client->moveCard(card->getId(), startZone->getName(), "grave", 0, 0, false); } void Game::actMoveToExile(CardItem *card) { CardZone *startZone = qgraphicsitem_cast(card->parentItem()); client->moveCard(card->getId(), startZone->getName(), "rfg", 0, 0, false); } void Game::actSayMessage() { QAction *a = qobject_cast(sender()); client->say(a->text()); } void Game::hoverCardEvent(CardItem *card) { emit hoverCard(card->getName()); }