preliminary client-side replay support, works in principle

This commit is contained in:
Max-Wilhelm Bruker 2012-02-21 00:09:03 +01:00
parent d50d179b2f
commit a1bcd9854f
13 changed files with 220 additions and 32 deletions

View file

@ -175,7 +175,8 @@ if (NOT QT_QTMULTIMEDIA_FOUND)
endif (NOT QT_QTMULTIMEDIA_FOUND) endif (NOT QT_QTMULTIMEDIA_FOUND)
FIND_PACKAGE(Protobuf REQUIRED) FIND_PACKAGE(Protobuf REQUIRED)
set(CMAKE_BUILD_TYPE Release) #set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0")
set(CMAKE_CXX_FLAGS_RELEASE "-s -O2") set(CMAKE_CXX_FLAGS_RELEASE "-s -O2")
QT4_WRAP_CPP(cockatrice_HEADERS_MOC ${cockatrice_HEADERS}) QT4_WRAP_CPP(cockatrice_HEADERS_MOC ${cockatrice_HEADERS})

View file

@ -56,6 +56,12 @@ GeneralSettingsPage::GeneralSettingsPage()
QPushButton *deckPathButton = new QPushButton("..."); QPushButton *deckPathButton = new QPushButton("...");
connect(deckPathButton, SIGNAL(clicked()), this, SLOT(deckPathButtonClicked())); connect(deckPathButton, SIGNAL(clicked()), this, SLOT(deckPathButtonClicked()));
replaysPathLabel = new QLabel;
replaysPathEdit = new QLineEdit(settingsCache->getReplaysPath());
replaysPathEdit->setReadOnly(true);
QPushButton *replaysPathButton = new QPushButton("...");
connect(replaysPathButton, SIGNAL(clicked()), this, SLOT(replaysPathButtonClicked()));
picsPathLabel = new QLabel; picsPathLabel = new QLabel;
picsPathEdit = new QLineEdit(settingsCache->getPicsPath()); picsPathEdit = new QLineEdit(settingsCache->getPicsPath());
picsPathEdit->setReadOnly(true); picsPathEdit->setReadOnly(true);
@ -72,12 +78,15 @@ GeneralSettingsPage::GeneralSettingsPage()
pathsGrid->addWidget(deckPathLabel, 0, 0); pathsGrid->addWidget(deckPathLabel, 0, 0);
pathsGrid->addWidget(deckPathEdit, 0, 1); pathsGrid->addWidget(deckPathEdit, 0, 1);
pathsGrid->addWidget(deckPathButton, 0, 2); pathsGrid->addWidget(deckPathButton, 0, 2);
pathsGrid->addWidget(picsPathLabel, 1, 0); pathsGrid->addWidget(replaysPathLabel, 1, 0);
pathsGrid->addWidget(picsPathEdit, 1, 1); pathsGrid->addWidget(replaysPathEdit, 1, 1);
pathsGrid->addWidget(picsPathButton, 1, 2); pathsGrid->addWidget(replaysPathButton, 1, 2);
pathsGrid->addWidget(cardDatabasePathLabel, 2, 0); pathsGrid->addWidget(picsPathLabel, 2, 0);
pathsGrid->addWidget(cardDatabasePathEdit, 2, 1); pathsGrid->addWidget(picsPathEdit, 2, 1);
pathsGrid->addWidget(cardDatabasePathButton, 2, 2); pathsGrid->addWidget(picsPathButton, 2, 2);
pathsGrid->addWidget(cardDatabasePathLabel, 3, 0);
pathsGrid->addWidget(cardDatabasePathEdit, 3, 1);
pathsGrid->addWidget(cardDatabasePathButton, 3, 2);
pathsGroupBox = new QGroupBox; pathsGroupBox = new QGroupBox;
pathsGroupBox->setLayout(pathsGrid); pathsGroupBox->setLayout(pathsGrid);
@ -114,6 +123,16 @@ void GeneralSettingsPage::deckPathButtonClicked()
settingsCache->setDeckPath(path); settingsCache->setDeckPath(path);
} }
void GeneralSettingsPage::replaysPathButtonClicked()
{
QString path = QFileDialog::getExistingDirectory(this, tr("Choose path"));
if (path.isEmpty())
return;
replaysPathEdit->setText(path);
settingsCache->setReplaysPath(path);
}
void GeneralSettingsPage::picsPathButtonClicked() void GeneralSettingsPage::picsPathButtonClicked()
{ {
QString path = QFileDialog::getExistingDirectory(this, tr("Choose path")); QString path = QFileDialog::getExistingDirectory(this, tr("Choose path"));
@ -146,6 +165,7 @@ void GeneralSettingsPage::retranslateUi()
picDownloadCheckBox->setText(tr("Download card pictures on the fly")); picDownloadCheckBox->setText(tr("Download card pictures on the fly"));
pathsGroupBox->setTitle(tr("Paths")); pathsGroupBox->setTitle(tr("Paths"));
deckPathLabel->setText(tr("Decks directory:")); deckPathLabel->setText(tr("Decks directory:"));
replaysPathLabel->setText(tr("Replays directory:"));
picsPathLabel->setText(tr("Pictures directory:")); picsPathLabel->setText(tr("Pictures directory:"));
cardDatabasePathLabel->setText(tr("Path to card database:")); cardDatabasePathLabel->setText(tr("Path to card database:"));
} }

View file

@ -28,22 +28,24 @@ public:
void retranslateUi(); void retranslateUi();
private slots: private slots:
void deckPathButtonClicked(); void deckPathButtonClicked();
void replaysPathButtonClicked();
void picsPathButtonClicked(); void picsPathButtonClicked();
void cardDatabasePathButtonClicked(); void cardDatabasePathButtonClicked();
void languageBoxChanged(int index); void languageBoxChanged(int index);
signals: signals:
void picsPathChanged(const QString &path); /* void picsPathChanged(const QString &path);
void replaysPathChanged(const QString &path);
void cardDatabasePathChanged(const QString &path); void cardDatabasePathChanged(const QString &path);
void changeLanguage(const QString &qmFile); void changeLanguage(const QString &qmFile);
void picDownloadChanged(int state); void picDownloadChanged(int state);
private: */private:
QStringList findQmFiles(); QStringList findQmFiles();
QString languageName(const QString &qmFile); QString languageName(const QString &qmFile);
QLineEdit *deckPathEdit, *picsPathEdit, *cardDatabasePathEdit; QLineEdit *deckPathEdit, *replaysPathEdit, *picsPathEdit, *cardDatabasePathEdit;
QGroupBox *personalGroupBox, *pathsGroupBox; QGroupBox *personalGroupBox, *pathsGroupBox;
QComboBox *languageBox; QComboBox *languageBox;
QCheckBox *picDownloadCheckBox; QCheckBox *picDownloadCheckBox;
QLabel *languageLabel, *deckPathLabel, *picsPathLabel, *cardDatabasePathLabel; QLabel *languageLabel, *deckPathLabel, *replaysPathLabel, *picsPathLabel, *cardDatabasePathLabel;
}; };
class AppearanceSettingsPage : public AbstractSettingsPage { class AppearanceSettingsPage : public AbstractSettingsPage {

View file

@ -108,6 +108,10 @@ int main(int argc, char *argv[])
QDir().mkpath(dataDir + "/decks"); QDir().mkpath(dataDir + "/decks");
settingsCache->setDeckPath(dataDir + "/decks"); settingsCache->setDeckPath(dataDir + "/decks");
} }
if (!QDir(settingsCache->getReplaysPath()).exists() || settingsCache->getReplaysPath().isEmpty()) {
QDir().mkpath(dataDir + "/replays");
settingsCache->setReplaysPath(dataDir + "/replays");
}
if (!QDir(settingsCache->getPicsPath()).exists() || settingsCache->getPicsPath().isEmpty()) { if (!QDir(settingsCache->getPicsPath()).exists() || settingsCache->getPicsPath().isEmpty()) {
QDir().mkpath(dataDir + "/pics"); QDir().mkpath(dataDir + "/pics");
settingsCache->setPicsPath(dataDir + "/pics"); settingsCache->setPicsPath(dataDir + "/pics");

View file

@ -29,6 +29,14 @@ void MessageLogWidget::logGameJoined(int gameId)
appendHtml(tr("You have joined game #%1.", "male").arg(gameId)); appendHtml(tr("You have joined game #%1.", "male").arg(gameId));
} }
void MessageLogWidget::logReplayStarted(int gameId)
{
if (female)
appendHtml(tr("You are watching a replay of game #%1.", "female").arg(gameId));
else
appendHtml(tr("You are watching a replay of game #%1.", "male").arg(gameId));
}
void MessageLogWidget::logJoin(Player *player) void MessageLogWidget::logJoin(Player *player)
{ {
soundEngine->cuckoo(); soundEngine->cuckoo();

View file

@ -40,6 +40,7 @@ private:
int mulliganNumber; int mulliganNumber;
public slots: public slots:
void logGameJoined(int gameId); void logGameJoined(int gameId);
void logReplayStarted(int gameId);
void logJoin(Player *player); void logJoin(Player *player);
void logLeave(Player *player); void logLeave(Player *player);
void logGameClosed(); void logGameClosed();

View file

@ -55,9 +55,11 @@ PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor, AbstractClient
concededIcon = QIcon(":/resources/icon_conceded.svg"); concededIcon = QIcon(":/resources/icon_conceded.svg");
playerIcon = QIcon(":/resources/icon_player.svg"); playerIcon = QIcon(":/resources/icon_player.svg");
spectatorIcon = QIcon(":/resources/icon_spectator.svg"); spectatorIcon = QIcon(":/resources/icon_spectator.svg");
itemDelegate = new PlayerListItemDelegate(this); if (tabSupervisor) {
setItemDelegate(itemDelegate); itemDelegate = new PlayerListItemDelegate(this);
setItemDelegate(itemDelegate);
}
setMinimumHeight(60); setMinimumHeight(60);
setIconSize(QSize(20, 15)); setIconSize(QSize(20, 15));

View file

@ -8,6 +8,7 @@ SettingsCache::SettingsCache()
lang = settings->value("personal/lang").toString(); lang = settings->value("personal/lang").toString();
deckPath = settings->value("paths/decks").toString(); deckPath = settings->value("paths/decks").toString();
replaysPath = settings->value("paths/replays").toString();
picsPath = settings->value("paths/pics").toString(); picsPath = settings->value("paths/pics").toString();
cardDatabasePath = settings->value("paths/carddatabase").toString(); cardDatabasePath = settings->value("paths/carddatabase").toString();
@ -49,6 +50,12 @@ void SettingsCache::setDeckPath(const QString &_deckPath)
settings->setValue("paths/decks", deckPath); settings->setValue("paths/decks", deckPath);
} }
void SettingsCache::setReplaysPath(const QString &_replaysPath)
{
replaysPath = _replaysPath;
settings->setValue("paths/replays", replaysPath);
}
void SettingsCache::setPicsPath(const QString &_picsPath) void SettingsCache::setPicsPath(const QString &_picsPath)
{ {
picsPath = _picsPath; picsPath = _picsPath;

View file

@ -26,7 +26,7 @@ private:
QSettings *settings; QSettings *settings;
QString lang; QString lang;
QString deckPath, picsPath, cardDatabasePath; QString deckPath, replaysPath, picsPath, cardDatabasePath;
QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath; QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath;
bool picDownload; bool picDownload;
bool doubleClickToPlay; bool doubleClickToPlay;
@ -45,6 +45,7 @@ public:
SettingsCache(); SettingsCache();
QString getLang() const { return lang; } QString getLang() const { return lang; }
QString getDeckPath() const { return deckPath; } QString getDeckPath() const { return deckPath; }
QString getReplaysPath() const { return replaysPath; }
QString getPicsPath() const { return picsPath; } QString getPicsPath() const { return picsPath; }
QString getCardDatabasePath() const { return cardDatabasePath; } QString getCardDatabasePath() const { return cardDatabasePath; }
QString getHandBgPath() const { return handBgPath; } QString getHandBgPath() const { return handBgPath; }
@ -69,6 +70,7 @@ public:
public slots: public slots:
void setLang(const QString &_lang); void setLang(const QString &_lang);
void setDeckPath(const QString &_deckPath); void setDeckPath(const QString &_deckPath);
void setReplaysPath(const QString &_replaysPath);
void setPicsPath(const QString &_picsPath); void setPicsPath(const QString &_picsPath);
void setCardDatabasePath(const QString &_cardDatabasePath); void setCardDatabasePath(const QString &_cardDatabasePath);
void setHandBgPath(const QString &_handBgPath); void setHandBgPath(const QString &_handBgPath);

View file

@ -29,6 +29,7 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include "pending_command.h" #include "pending_command.h"
#include "pb/game_replay.pb.h"
#include "pb/command_concede.pb.h" #include "pb/command_concede.pb.h"
#include "pb/command_deck_select.pb.h" #include "pb/command_deck_select.pb.h"
#include "pb/command_ready_start.pb.h" #include "pb/command_ready_start.pb.h"
@ -195,6 +196,85 @@ void DeckViewContainer::setDeck(DeckList *deck)
readyStartButton->setEnabled(true); readyStartButton->setEnabled(true);
} }
TabGame::TabGame(GameReplay *_replay)
: Tab(0),
hostId(-1),
localPlayerId(-1),
spectator(true),
spectatorsCanTalk(false),
spectatorsSeeEverything(true),
gameStateKnown(false),
started(false),
resuming(false),
currentPhase(-1),
replay(_replay),
currentReplayStep(0)
{
gameId = replay->game_info().game_id();
gameDescription = QString::fromStdString(replay->game_info().description());
phasesToolbar = new PhasesToolbar;
phasesToolbar->hide();
scene = new GameScene(phasesToolbar, this);
gameView = new GameView(scene);
gameView->hide();
cardInfo = new CardInfoWidget(CardInfoWidget::ModeGameTab);
playerListWidget = new PlayerListWidget(0, 0, this);
playerListWidget->setFocusPolicy(Qt::NoFocus);
timeElapsedLabel = new QLabel;
timeElapsedLabel->setAlignment(Qt::AlignCenter);
messageLog = new MessageLogWidget(QString(), false);
connect(messageLog, SIGNAL(cardNameHovered(QString)), cardInfo, SLOT(setCard(QString)));
connect(messageLog, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString)));
connect(messageLog, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
sayLabel = 0;
deckViewContainerLayout = new QVBoxLayout;
QVBoxLayout *messageLogLayout = new QVBoxLayout;
messageLogLayout->addWidget(timeElapsedLabel);
messageLogLayout->addWidget(messageLog);
QWidget *messageLogLayoutWidget = new QWidget;
messageLogLayoutWidget->setLayout(messageLogLayout);
splitter = new QSplitter(Qt::Vertical);
splitter->addWidget(cardInfo);
splitter->addWidget(playerListWidget);
splitter->addWidget(messageLogLayoutWidget);
mainLayout = new QHBoxLayout;
mainLayout->addWidget(gameView, 10);
mainLayout->addLayout(deckViewContainerLayout, 10);
mainLayout->addWidget(splitter);
aNextPhase = 0;
aNextTurn = 0;
aRemoveLocalArrows = 0;
aConcede = 0;
aLeaveGame = new QAction(this);
connect(aLeaveGame, SIGNAL(triggered()), this, SLOT(actLeaveGame()));
phasesMenu = 0;
tabMenu = new QMenu(this);
tabMenu->addAction(aLeaveGame);
retranslateUi();
setLayout(mainLayout);
splitter->restoreState(settingsCache->getTabGameSplitterSizes());
messageLog->logReplayStarted(gameId);
gameTimer = new QTimer(this);
gameTimer->setInterval(1000);
connect(gameTimer, SIGNAL(timeout()), this, SLOT(nextReplayStep()));
gameTimer->start();
}
TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, const Event_GameJoined &event) TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, const Event_GameJoined &event)
: Tab(_tabSupervisor), : Tab(_tabSupervisor),
clients(_clients), clients(_clients),
@ -205,10 +285,11 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_client
spectator(event.spectator()), spectator(event.spectator()),
spectatorsCanTalk(event.spectators_can_talk()), spectatorsCanTalk(event.spectators_can_talk()),
spectatorsSeeEverything(event.spectators_see_everything()), spectatorsSeeEverything(event.spectators_see_everything()),
gameStateKnown(false), gameStateKnown(true),
started(false), started(false),
resuming(event.resuming()), resuming(event.resuming()),
currentPhase(-1) currentPhase(-1),
replay(0)
{ {
gameTimer = new QTimer(this); gameTimer = new QTimer(this);
gameTimer->setInterval(1000); gameTimer->setInterval(1000);
@ -261,7 +342,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_client
mainLayout->addWidget(gameView, 10); mainLayout->addWidget(gameView, 10);
mainLayout->addLayout(deckViewContainerLayout, 10); mainLayout->addLayout(deckViewContainerLayout, 10);
mainLayout->addWidget(splitter); mainLayout->addWidget(splitter);
if (spectator && !spectatorsCanTalk && tabSupervisor->getAdminLocked()) { if (spectator && !spectatorsCanTalk && tabSupervisor->getAdminLocked()) {
sayLabel->hide(); sayLabel->hide();
sayEdit->hide(); sayEdit->hide();
@ -320,6 +401,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_client
TabGame::~TabGame() TabGame::~TabGame()
{ {
delete replay;
settingsCache->setTabGameSplitterSizes(splitter->saveState()); settingsCache->setTabGameSplitterSizes(splitter->saveState());
QMapIterator<int, Player *> i(players); QMapIterator<int, Player *> i(players);
@ -334,23 +416,34 @@ TabGame::~TabGame()
void TabGame::retranslateUi() void TabGame::retranslateUi()
{ {
for (int i = 0; i < phaseActions.size(); ++i) if (phasesMenu) {
phaseActions[i]->setText(phasesToolbar->getLongPhaseName(i)); for (int i = 0; i < phaseActions.size(); ++i)
phasesMenu->setTitle(tr("&Phases")); phaseActions[i]->setText(phasesToolbar->getLongPhaseName(i));
phasesMenu->setTitle(tr("&Phases"));
}
tabMenu->setTitle(tr("&Game")); tabMenu->setTitle(tr("&Game"));
aNextPhase->setText(tr("Next &phase")); if (aNextPhase) {
aNextPhase->setShortcut(tr("Ctrl+Space")); aNextPhase->setText(tr("Next &phase"));
aNextTurn->setText(tr("Next &turn")); aNextPhase->setShortcut(tr("Ctrl+Space"));
aNextTurn->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Return")) << QKeySequence(tr("Ctrl+Enter"))); }
aRemoveLocalArrows->setText(tr("&Remove all local arrows")); if (aNextTurn) {
aRemoveLocalArrows->setShortcut(tr("Ctrl+R")); aNextTurn->setText(tr("Next &turn"));
aConcede->setText(tr("&Concede")); aNextTurn->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Return")) << QKeySequence(tr("Ctrl+Enter")));
aConcede->setShortcut(tr("F2")); }
if (aRemoveLocalArrows) {
aRemoveLocalArrows->setText(tr("&Remove all local arrows"));
aRemoveLocalArrows->setShortcut(tr("Ctrl+R"));
}
if (aConcede) {
aConcede->setText(tr("&Concede"));
aConcede->setShortcut(tr("F2"));
}
aLeaveGame->setText(tr("&Leave game")); aLeaveGame->setText(tr("&Leave game"));
aLeaveGame->setShortcut(tr("Ctrl+Q")); aLeaveGame->setShortcut(tr("Ctrl+Q"));
sayLabel->setText(tr("&Say:")); if (sayLabel)
sayLabel->setText(tr("&Say:"));
cardInfo->retranslateUi(); cardInfo->retranslateUi();
QMapIterator<int, Player *> i(players); QMapIterator<int, Player *> i(players);
@ -368,6 +461,17 @@ void TabGame::closeRequest()
actLeaveGame(); actLeaveGame();
} }
void TabGame::nextReplayStep()
{
if (replay->event_list_size() <= currentReplayStep) {
QMessageBox::information(this, "", "done");
gameTimer->stop();
return;
}
processGameEventContainer(replay->event_list(currentReplayStep), 0);
++currentReplayStep;
}
void TabGame::incrementGameTime() void TabGame::incrementGameTime()
{ {
int seconds = ++secondsElapsed; int seconds = ++secondsElapsed;

View file

@ -49,6 +49,7 @@ class TabGame;
class DeckList; class DeckList;
class QVBoxLayout; class QVBoxLayout;
class QHBoxLayout; class QHBoxLayout;
class GameReplay;
class ServerInfo_User; class ServerInfo_User;
class PendingCommand; class PendingCommand;
@ -107,7 +108,9 @@ private:
QStringList phasesList; QStringList phasesList;
int currentPhase; int currentPhase;
int activePlayer; int activePlayer;
GameReplay *replay;
int currentReplayStep;
QSplitter *splitter; QSplitter *splitter;
CardInfoWidget *cardInfo; CardInfoWidget *cardInfo;
PlayerListWidget *playerListWidget; PlayerListWidget *playerListWidget;
@ -155,6 +158,7 @@ signals:
void containerProcessingDone(); void containerProcessingDone();
void openMessageDialog(const QString &userName, bool focus); void openMessageDialog(const QString &userName, bool focus);
private slots: private slots:
void nextReplayStep();
void incrementGameTime(); void incrementGameTime();
void adminLockChanged(bool lock); void adminLockChanged(bool lock);
void newCardAdded(AbstractCardItem *card); void newCardAdded(AbstractCardItem *card);
@ -168,6 +172,7 @@ private slots:
void actNextTurn(); void actNextTurn();
public: public:
TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, const Event_GameJoined &event); TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, const Event_GameJoined &event);
TabGame(GameReplay *replay);
~TabGame(); ~TabGame();
void retranslateUi(); void retranslateUi();
void closeRequest(); void closeRequest();

View file

@ -24,6 +24,8 @@
#include <QMenuBar> #include <QMenuBar>
#include <QPixmapCache> #include <QPixmapCache>
#include <QInputDialog> #include <QInputDialog>
#include <QFile>
#include <QFileDialog>
#include "main.h" #include "main.h"
#include "window_main.h" #include "window_main.h"
@ -35,7 +37,10 @@
#include "localserver.h" #include "localserver.h"
#include "localserverinterface.h" #include "localserverinterface.h"
#include "localclient.h" #include "localclient.h"
#include "settingscache.h"
#include "tab_game.h"
#include "pb/game_replay.pb.h"
#include "pb/room_commands.pb.h" #include "pb/room_commands.pb.h"
#include "pb/event_connection_closed.pb.h" #include "pb/event_connection_closed.pb.h"
#include "pb/event_server_shutdown.pb.h" #include "pb/event_server_shutdown.pb.h"
@ -145,6 +150,28 @@ void MainWindow::actSinglePlayer()
mainClient->sendCommand(mainClient->prepareRoomCommand(createCommand, 0)); mainClient->sendCommand(mainClient->prepareRoomCommand(createCommand, 0));
} }
void MainWindow::actWatchReplay()
{
QFileDialog dlg(this, tr("Load replay"));
dlg.setDirectory(settingsCache->getReplaysPath());
dlg.setNameFilters(QStringList() << QObject::tr("Cockatrice replays (*.cor)"));
if (!dlg.exec())
return;
QString fileName = dlg.selectedFiles().at(0);
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
return;
QByteArray buf = file.readAll();
file.close();
GameReplay *replay = new GameReplay;
replay->ParseFromArray(buf.data(), buf.size());
TabGame *replayWatcher = new TabGame(replay);
replayWatcher->show();
}
void MainWindow::localGameEnded() void MainWindow::localGameEnded()
{ {
delete localServer; delete localServer;
@ -243,6 +270,7 @@ void MainWindow::retranslateUi()
aConnect->setText(tr("&Connect...")); aConnect->setText(tr("&Connect..."));
aDisconnect->setText(tr("&Disconnect")); aDisconnect->setText(tr("&Disconnect"));
aSinglePlayer->setText(tr("Start &local game...")); aSinglePlayer->setText(tr("Start &local game..."));
aWatchReplay->setText(tr("&Watch replay..."));
aDeckEditor->setText(tr("&Deck editor")); aDeckEditor->setText(tr("&Deck editor"));
aFullScreen->setText(tr("&Full screen")); aFullScreen->setText(tr("&Full screen"));
aFullScreen->setShortcut(tr("Ctrl+F")); aFullScreen->setShortcut(tr("Ctrl+F"));
@ -266,6 +294,8 @@ void MainWindow::createActions()
connect(aDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect())); connect(aDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect()));
aSinglePlayer = new QAction(this); aSinglePlayer = new QAction(this);
connect(aSinglePlayer, SIGNAL(triggered()), this, SLOT(actSinglePlayer())); connect(aSinglePlayer, SIGNAL(triggered()), this, SLOT(actSinglePlayer()));
aWatchReplay = new QAction(this);
connect(aWatchReplay, SIGNAL(triggered()), this, SLOT(actWatchReplay()));
aDeckEditor = new QAction(this); aDeckEditor = new QAction(this);
connect(aDeckEditor, SIGNAL(triggered()), this, SLOT(actDeckEditor())); connect(aDeckEditor, SIGNAL(triggered()), this, SLOT(actDeckEditor()));
aFullScreen = new QAction(this); aFullScreen = new QAction(this);
@ -286,6 +316,7 @@ void MainWindow::createMenus()
cockatriceMenu->addAction(aConnect); cockatriceMenu->addAction(aConnect);
cockatriceMenu->addAction(aDisconnect); cockatriceMenu->addAction(aDisconnect);
cockatriceMenu->addAction(aSinglePlayer); cockatriceMenu->addAction(aSinglePlayer);
cockatriceMenu->addAction(aWatchReplay);
cockatriceMenu->addSeparator(); cockatriceMenu->addSeparator();
cockatriceMenu->addAction(aDeckEditor); cockatriceMenu->addAction(aDeckEditor);
cockatriceMenu->addSeparator(); cockatriceMenu->addSeparator();

View file

@ -47,6 +47,7 @@ private slots:
void actConnect(); void actConnect();
void actDisconnect(); void actDisconnect();
void actSinglePlayer(); void actSinglePlayer();
void actWatchReplay();
void actDeckEditor(); void actDeckEditor();
void actFullScreen(bool checked); void actFullScreen(bool checked);
void actSettings(); void actSettings();
@ -60,7 +61,7 @@ private:
void createActions(); void createActions();
void createMenus(); void createMenus();
QMenu *cockatriceMenu, *tabMenu, *helpMenu; QMenu *cockatriceMenu, *tabMenu, *helpMenu;
QAction *aConnect, *aDisconnect, *aSinglePlayer, *aDeckEditor, *aFullScreen, *aSettings, *aExit, QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit,
*aAbout; *aAbout;
TabSupervisor *tabSupervisor; TabSupervisor *tabSupervisor;