1 /********************************************************************
3 * Copyright (C) 2008 Davide Pesavento and Daniele Battaglia
5 * This file is part of GoMoku3D.
7 * GoMoku3D is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * GoMoku3D is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GoMoku3D. If not, see <http://www.gnu.org/licenses/>.
20 *******************************************************************/
22 #include <QMessageBox>
23 #include <QFileDialog>
25 #include "MainWindow.h"
27 #include "GameMatrix.h"
29 #include "RemotePlayer.h"
30 #include "HumanPlayer.h"
31 #include "RenderWidget.h"
32 #include "HistoryModel.h"
33 #include "ChatWidget.h"
34 #include "TimerWidget.h"
36 #include "OnlineDialog.h"
37 #include "Suggester.h"
38 #include "SettingsManager.h"
39 #include "GUISettings.h"
40 #include "Preferences.h"
41 #include "PlayersWidget.h"
42 #include "StandAloneDialog.h"
43 #include "ServerSettingsDialog.h"
45 MainWindow::MainWindow() : QMainWindow(), Ui_MainWindow(*this)
52 _actualPlayerIndex
= -1;
53 _isStandAloneGame
= false;
54 _isOnlineGame
= false;
55 _isServerGame
= false;
56 _isDedicatedServer
= false;
61 _render
= new RenderWidget(this);
62 setCentralWidget(_render
);
64 QDockWidget
*playersDock
= new QDockWidget(this);
65 QDockWidget
*historyDock
= new QDockWidget(this);
66 QDockWidget
*timerDock
= new QDockWidget(this);
67 QDockWidget
*chatDock
= new QDockWidget(this);
68 playersDock
->setWindowTitle(tr("Players' Info"));
69 historyDock
->setWindowTitle(tr("History"));
70 timerDock
->setWindowTitle(tr("Timer"));
71 chatDock
->setWindowTitle(tr("Chat"));
72 playersDock
->setFeatures(QDockWidget::DockWidgetMovable
| QDockWidget::DockWidgetFloatable
);
73 historyDock
->setFeatures(QDockWidget::DockWidgetMovable
| QDockWidget::DockWidgetFloatable
);
74 timerDock
->setFeatures(QDockWidget::DockWidgetMovable
| QDockWidget::DockWidgetFloatable
);
75 chatDock
->setFeatures(QDockWidget::DockWidgetMovable
| QDockWidget::DockWidgetFloatable
);
76 historyDock
->setAllowedAreas(Qt::LeftDockWidgetArea
| Qt::RightDockWidgetArea
);
77 timerDock
->setAllowedAreas(Qt::LeftDockWidgetArea
| Qt::RightDockWidgetArea
);
78 chatDock
->setAllowedAreas(Qt::LeftDockWidgetArea
| Qt::RightDockWidgetArea
);
79 _playersWidget
= new PlayersWidget(playersDock
);
80 _historyView
= new QTableView(historyDock
);
81 _timer
= new TimerWidget(timerDock
);
82 _chat
= new ChatWidget(chatDock
);
83 playersDock
->setWidget(_playersWidget
);
84 historyDock
->setWidget(_historyView
);
85 timerDock
->setWidget(_timer
);
86 chatDock
->setWidget(_chat
);
87 addDockWidget(Qt::LeftDockWidgetArea
, playersDock
);
88 addDockWidget(Qt::LeftDockWidgetArea
, historyDock
);
89 addDockWidget(Qt::RightDockWidgetArea
, timerDock
);
90 addDockWidget(Qt::RightDockWidgetArea
, chatDock
);
93 _history
= new HistoryModel(this, &_playersInfo
);
94 _historyView
->setModel(_history
);
97 connect(_timer
, SIGNAL(timerExpired()), this, SLOT(timerExpired()));
98 connect(_historyView
, SIGNAL(doubleClicked(QModelIndex
)), this, SLOT(undoMoves(QModelIndex
)));
99 connect(_historyView
, SIGNAL(clicked(QModelIndex
)), this, SLOT(showPastGameStatus(QModelIndex
)));
100 connect(actionShow_last_move
, SIGNAL(triggered()), this, SLOT(showLastMove()));
101 connect(actionSuggest_move
, SIGNAL(triggered()), this, SLOT(suggestMove()));
102 connect(actionTake_back_move
, SIGNAL(triggered()), this, SLOT(undoTurn()));
103 connect(actionHost_Game
, SIGNAL(triggered()), this, SLOT(newServerGame()));
104 connect(actionConnect_To_Server
, SIGNAL(triggered()), this, SLOT(newOnlineGame()));
105 connect(actionNew_local_game
,SIGNAL(triggered()), this, SLOT(newStandAloneGame()));
106 connect(actionAbout_Qt
, SIGNAL(triggered()), qApp
, SLOT(aboutQt()));
107 connect(actionPreferences
, SIGNAL(triggered()), this, SLOT(showPreferences()));
108 connect(actionQuit
, SIGNAL(triggered()), this, SLOT(close()));
109 connect(actionSave_game
, SIGNAL(triggered()), this, SLOT(saveGame()));
112 MainWindow::~MainWindow()
115 set
.setGeometry(this->saveGeometry());
116 //set.setDockState(this->saveState());
124 if (_suggester
!= 0) {
126 _suggester
->deleteLater();
135 _loop
->deleteLater();
138 //TODO c'e' altro da fare?
141 void MainWindow::drawMove(Move move
)
143 if (_playersInfo
.isEmpty()) {
148 if (move
.playerId() == 0) {
149 color
= _playersInfo
.at(0).color();
151 if (move
.playerId() == 1) {
152 color
= _playersInfo
.at(1).color();
154 if (move
.playerId() == 2) {
155 color
= _playersInfo
.at(2).color();
158 bool ok
= move
.isValid();
161 _history
->append(move
);
164 // messaggio di errore
165 // se alla drawMove arriva un point nullo cosa vuol dire?
166 // - dal network: scaduto il timer del giocatore
167 // - quando viene rilasciato il lock in fase di distruzione ma non dovrebbe succedere niente
168 if (!_isDedicatedServer
) {
169 _render
->acceptMove(false);
171 QMessageBox::information(this, tr("Game Ended"), tr("Timer expired:\n%1 lost the game.").arg(_playersInfo
.at(move
.playerId()).name()), QMessageBox::Ok
);
175 if (!_isDedicatedServer
&& ok
) {
176 if (!_actualViewIndex
.isValid() || (_actualViewIndex
.row() == _history
->moveList().size() - 2)) {
177 _render
->drawMove(move
.point(), color
);
178 _actualViewIndex
= _history
->index(_history
->moveList().size() - 1, 0);
180 actionShow_last_move
->setEnabled(true);
181 if (_isStandAloneGame
) {
182 actionTake_back_move
->setEnabled(true);
186 actionShow_last_move
->setEnabled(false);
187 actionTake_back_move
->setEnabled(false);
191 QModelIndex
MainWindow::actualViewIndex() const
193 return _actualViewIndex
;
196 bool MainWindow::askUserConfirmation()
198 QMessageBox::StandardButton result
= QMessageBox::question(this,
200 tr("If you continue, the current\ngame will be lost.\n\nAre you sure you want to continue?"),
201 QMessageBox::Yes
| QMessageBox::No
);
203 if (result
== QMessageBox::Yes
) {
210 void MainWindow::newStandAloneGame()
212 if (_loop
!= 0 && !askUserConfirmation()) {
218 qobject_cast
<QDockWidget
*>(_timer
->parent())->setVisible(false);
219 qobject_cast
<QDockWidget
*>(_chat
->parent())->setVisible(false);
220 qobject_cast
<QDockWidget
*>(_playersWidget
->parent())->setVisible(true);
222 StandAloneDialog
dialog(this);
224 if (dialog
.result() == QDialog::Rejected
) {
228 _isStandAloneGame
= true;
230 // abilito alcune voci del menu
231 actionLoad_game
->setEnabled(true);
232 actionSave_game
->setEnabled(true);
234 int d1
= dialog
.d1Box
->currentText().toInt();
235 int d2
= dialog
.d2Box
->currentText().toInt();
236 int numPlayers
= dialog
.numPlayersBox
->currentText().toInt();
239 Q_ASSERT(numPlayers
!= 0);
240 GameMatrix::create(d1
, d2
, numPlayers
);
241 Q_ASSERT(GameMatrix::instance() != 0);
243 _render
->init(d1
* d2
);
246 QList
<Player
*> players
;
247 if (dialog
.human_0
->isChecked()) {
249 players
.append(new HumanPlayer(0, _render
));
253 players
.append(new AIPlayer(0));
255 _playersInfo
.append(PlayerInfo(dialog
.playername_0
->text(), dialog
.color_0
->palette().color(QPalette::Button
), type
));
257 if (dialog
.human_1
->isChecked()) {
259 players
.append(new HumanPlayer(1, _render
));
263 players
.append(new AIPlayer(1));
265 _playersInfo
.append(PlayerInfo(dialog
.playername_1
->text(), dialog
.color_1
->palette().color(QPalette::Button
), type
));
267 if (numPlayers
== 3) {
268 if (dialog
.human_2
->isChecked()) {
270 players
.append(new HumanPlayer(2, _render
));
274 players
.append(new AIPlayer(2));
276 _playersInfo
.append(PlayerInfo(dialog
.playername_2
->text(), dialog
.color_2
->palette().color(QPalette::Button
), type
));
279 _playersWidget
->set(&_playersInfo
);
280 connectAISkillSlider(players
);
282 qobject_cast
<QDockWidget
*>(_historyView
->parent())->setVisible(true);
285 _loop
= new GameLoop(players
);
286 //move to thread dei player
288 foreach (p
, players
) {
289 p
->moveToThread(_loop
);
292 connect(actionForce_Move
, SIGNAL(triggered()), _loop
, SLOT(forceMove()));
293 connect(_loop
, SIGNAL(turn(int)), this, SLOT(turn(int)));
294 connect(_loop
, SIGNAL(turn(int)), _playersWidget
, SLOT(updateTurn(int)));
295 connect(_loop
, SIGNAL(moved(Move
)), this, SLOT(drawMove(Move
)));
296 connect(_loop
, SIGNAL(win(int)), this, SLOT(playerWin(int)));
297 connect(_loop
, SIGNAL(draw(QList
<int>)), this, SLOT(playersDraw(QList
<int>)));
302 void MainWindow::newOnlineGame()
304 if (_loop
!= 0 && !askUserConfirmation()) {
310 qobject_cast
<QDockWidget
*>(_timer
->parent())->setVisible(true);
311 qobject_cast
<QDockWidget
*>(_chat
->parent())->setVisible(true);
312 qobject_cast
<QDockWidget
*>(_playersWidget
->parent())->setVisible(true);
314 OnlineDialog
dialog(this);
316 if (dialog
.result() == QDialog::Rejected
) {
323 connect(_net
, SIGNAL(error(QString
)), this, SLOT(networkError(QString
)));
325 _isOnlineGame
= true;
327 //TODO connette i segnali di errore del net con MW
330 int d1
= dialog
.d1Label
->text().toInt();
331 int d2
= dialog
.d2Label
->text().toInt();
332 int numPlayers
= dialog
.numPlayersLabel
->text().toInt();
333 GameMatrix::create(d1
, d2
, numPlayers
);
335 _render
->init(d1
* d2
);
337 actionShow_last_move
->setEnabled(true);
338 //estraggo e costruisco la lista di playersInfo
339 //costruisco i player
340 QList
<Player
*> players
;
341 if (dialog
._typeList
[0] == "H") {
342 players
.append(new HumanPlayer(0, _render
));
345 players
.append(new RemotePlayer(0, _net
));
347 _playersInfo
.append(PlayerInfo(dialog
.name_0
->text(), dialog
.color_0
->palette().color(QPalette::Button
), dialog
._typeList
[0]));
348 if (dialog
._typeList
[1] == "H") {
349 players
.append(new HumanPlayer(1, _render
));
352 players
.append(new RemotePlayer(1, _net
));
354 _playersInfo
.append(PlayerInfo(dialog
.name_1
->text(), dialog
.color_1
->palette().color(QPalette::Button
), dialog
._typeList
[1]));
355 if (numPlayers
== 3) {
356 if (dialog
._typeList
[2] == "H") {
357 players
.append(new HumanPlayer(2, _render
));
360 players
.append(new RemotePlayer(2, _net
));
362 _playersInfo
.append(PlayerInfo(dialog
.name_2
->text(), dialog
.color_2
->palette().color(QPalette::Button
), dialog
._typeList
[2]));
366 qobject_cast
<QDockWidget
*>(_historyView
->parent())->setVisible(true);
368 _playersWidget
->set(&_playersInfo
);
370 _net
->setupChat(_chat
);
372 int t
= dialog
.timerLabel
->text().toInt();
374 _timer
->setDuration(t
);
377 _loop
= new GameLoop(players
);
379 QList
<Move
> history
= _history
->moveList();
380 if (history
.size() != 0) {
382 GameMatrix
*mat
= GameMatrix::instance();
384 for (int i
= 0; i
< _playersInfo
.size(); i
++) {
387 foreach (m
, history
) {
388 win
[m
.playerId()] = mat
->add(m
);
389 _render
->drawMove(m
.point(), _playersInfo
.at(m
.playerId()).color());
391 _loop
->winStatus(win
);
392 _loop
->onLoadSetTurn(history
.size() % _playersInfo
.size());
394 //move to thread dei player
396 foreach (p
, players
) {
397 p
->moveToThread(_loop
);
400 _net
->setupGameLoop(_loop
);
403 connect(_loop
, SIGNAL(turn(int)), this, SLOT(turn(int)));
404 connect(_loop
, SIGNAL(turn(int)), _playersWidget
, SLOT(updateTurn(int)));
405 connect(_loop
, SIGNAL(moved(Move
)), this, SLOT(drawMove(Move
)));
406 connect(_loop
, SIGNAL(win(int)), this, SLOT(playerWin(int)));
407 connect(_loop
, SIGNAL(draw(QList
<int>)), this, SLOT(playersDraw(QList
<int>)));
412 void MainWindow::updateHistory(QList
<Move
> list
)
418 _actualViewIndex
= _history
->index(_history
->moveList().size() - 1, 0);
421 void MainWindow::newServerGame()
423 if (_loop
!= 0 && !askUserConfirmation()) {
428 qobject_cast
<QDockWidget
*>(_timer
->parent())->setVisible(false);
429 qobject_cast
<QDockWidget
*>(_chat
->parent())->setVisible(false);
430 qobject_cast
<QDockWidget
*>(_playersWidget
->parent())->setVisible(false);
431 qobject_cast
<QDockWidget
*>(_historyView
->parent())->setVisible(false);
433 ServerSettingsDialog
dialog(this);
435 if (dialog
.result() == QDialog::Rejected
) {
443 connect(_net
, SIGNAL(error(QString
)), this, SLOT(networkError(QString
)));
445 int d1
= dialog
.d1Box
->currentText().toInt();
446 int d2
= dialog
.d2Box
->currentText().toInt();
447 int numPlayers
= dialog
.numPlayersBox
->currentText().toInt();
449 GameMatrix::create(d1
, d2
, numPlayers
);
452 QList
<Player
*> players
;
453 if (dialog
.human_0
->isChecked()) {
455 actionShow_last_move
->setEnabled(true);
456 players
.append(new HumanPlayer(0, _render
));
459 if (dialog
.ai_0
->isChecked()) {
461 players
.append(new AIPlayer(0));
465 players
.append(new RemotePlayer(0, _net
));
468 _playersInfo
.append(PlayerInfo(dialog
.playername_0
->text(), dialog
.color_0
->palette().color(QPalette::Button
), type
));
469 if (dialog
.human_1
->isChecked()) {
471 actionShow_last_move
->setEnabled(true);
472 players
.append(new HumanPlayer(1, _render
));
475 if (dialog
.ai_1
->isChecked()) {
477 players
.append(new AIPlayer(1));
481 players
.append(new RemotePlayer(1, _net
));
484 _playersInfo
.append(PlayerInfo(dialog
.playername_1
->text(), dialog
.color_1
->palette().color(QPalette::Button
), type
));
485 if (numPlayers
== 3) {
486 if (dialog
.human_2
->isChecked()) {
488 actionShow_last_move
->setEnabled(true);
489 players
.append(new HumanPlayer(2, _render
));
492 if (dialog
.ai_2
->isChecked()) {
494 players
.append(new AIPlayer(2));
498 players
.append(new RemotePlayer(2, _net
));
501 _playersInfo
.append(PlayerInfo(dialog
.playername_2
->text(), dialog
.color_2
->palette().color(QPalette::Button
), type
));
504 int t
= dialog
.timerSpinBox
->value();
506 _timer
->setDuration(t
);
509 _loop
= new GameLoop(players
);
510 //move to thread dei player
512 foreach (p
, players
) {
513 p
->moveToThread(_loop
);
515 connectAISkillSlider(players
);
517 _net
->setupGameLoop(_loop
);
520 for (int i
= 0; i
< _playersInfo
.size(); i
++) {
521 if (_playersInfo
.at(i
).type() == "H") {
526 //TODO connette i segnali di errore del net con MW
528 if (noHuman
&& dialog
.dedicatedserver
->isChecked()) {
529 // modalità server dedicato
530 _isDedicatedServer
= true;
531 qobject_cast
<QDockWidget
*>(_playersWidget
->parent())->setVisible(true);
532 // TODO: bisogna connettere qualcosa?
534 // modalità giocatore o spettatore
535 _isServerGame
= true;
537 _render
->init(d1
* d2
);
538 _net
->setupChat(_chat
);
539 qobject_cast
<QDockWidget
*>(_timer
->parent())->setVisible(true);
540 qobject_cast
<QDockWidget
*>(_chat
->parent())->setVisible(true);
541 qobject_cast
<QDockWidget
*>(_playersWidget
->parent())->setVisible(true);
542 qobject_cast
<QDockWidget
*>(_historyView
->parent())->setVisible(true);
544 _playersWidget
->set(&_playersInfo
);
545 _timer
->setDuration(dialog
.timerSpinBox
->value());
548 connect(_loop
, SIGNAL(turn(int)), this, SLOT(turn(int)));
549 connect(_loop
, SIGNAL(moved(Move
)), this, SLOT(drawMove(Move
)));
550 connect(_loop
, SIGNAL(win(int)), this, SLOT(playerWin(int)));
551 connect(_loop
, SIGNAL(draw(QList
<int>)), this, SLOT(playersDraw(QList
<int>)));
554 connect(_loop
, SIGNAL(turn(int)), _playersWidget
, SLOT(updateTurn(int))); //FIXME: perché qui?
559 void MainWindow::showPreferences()
561 Preferences
pref(this);
562 int result
= pref
.exec();
563 if (result
== QDialog::Accepted
) {
564 _render
->updateBackground();
568 void MainWindow::disableOnEndGame()
571 actionTake_back_move
->setEnabled(false);
572 actionSuggest_move
->setEnabled(false);
573 actionForce_Move
->setEnabled(false);
574 actionSave_game
->setEnabled(false);
575 actionShow_last_move
->setEnabled(false);
576 _playersWidget
->arrow_0
->setEnabled(false);
577 _playersWidget
->arrow_1
->setEnabled(false);
578 _playersWidget
->arrow_2
->setEnabled(false);
581 void MainWindow::playerWin(int playerId
)
584 QMessageBox::information(this, tr("Game Ended"), tr("And the winner is ...\n%1!").arg(_playersInfo
.at(playerId
).name()), QMessageBox::Ok
);
587 void MainWindow::playersDraw(QList
<int> playersIds
)
592 foreach (id
, playersIds
) {
593 result
+= "\n - " + _playersInfo
.at(id
).name();
595 QMessageBox::information(this, tr("Game Ended"), tr("Game ended in a draw:%1").arg(result
), QMessageBox::Ok
);
598 void MainWindow::turn(int playerId
)
600 _actualPlayerIndex
= playerId
;
601 if (_playersInfo
.at(playerId
).type() == "H" && _isStandAloneGame
) {
602 actionSuggest_move
->setEnabled(true);
605 actionSuggest_move
->setEnabled(false);
607 if (_playersInfo
.at(playerId
).type() == "A") {
608 actionForce_Move
->setEnabled(true);
611 actionForce_Move
->setEnabled(false);
614 bool startTimer
= _playersInfo
.at(playerId
).type() == "H";
615 if (!_isStandAloneGame
&& _timerDuration
> 0 && startTimer
) {
620 void MainWindow::resetOnNewGame()
622 //disabilito alcune voci del menù
631 if (_suggester
!= 0) {
633 _suggester
->deleteLater();
644 _loop
->deleteLater();
652 if (_playersWidget
!= 0) {
653 _playersWidget
->reset();
656 if (_settings
!= 0) {
661 _playersInfo
.clear();
667 _isStandAloneGame
= false;
668 _isOnlineGame
= false;
669 _isServerGame
= false;
670 _isDedicatedServer
= false;
671 _actualViewIndex
= QModelIndex();
672 _actualPlayerIndex
= 0;
677 void MainWindow::suggestMove()
679 if (_isStandAloneGame
) {
680 if (_suggester
!= 0) {
682 _suggester
->deleteLater();
685 _suggester
= new Suggester(_actualPlayerIndex
);
686 connect(_suggester
, SIGNAL(suggestedMoveReady(Point
)), _render
, SLOT(highlightPoint(Point
)));
691 bool MainWindow::isOnlineGame() const
693 return _isOnlineGame
;
696 void MainWindow::connectAISkillSlider(const QList
<Player
*> &players
)
698 AIPlayer
*ai0
= qobject_cast
<AIPlayer
*>(players
.at(0));
700 connect(_playersWidget
->skill_0
, SIGNAL(valueChanged(int)), ai0
, SLOT(setSkill(int)), Qt::DirectConnection
);
702 AIPlayer
*ai1
= qobject_cast
<AIPlayer
*>(players
.at(1));
704 connect(_playersWidget
->skill_1
, SIGNAL(valueChanged(int)), ai1
, SLOT(setSkill(int)), Qt::DirectConnection
);
706 if (players
.size() == 3) {
707 AIPlayer
*ai2
= qobject_cast
<AIPlayer
*>(players
.at(2));
709 connect(_playersWidget
->skill_2
, SIGNAL(valueChanged(int)), ai2
, SLOT(setSkill(int)), Qt::DirectConnection
);
714 void MainWindow::showLastMove()
716 if (_history
&& !_isDedicatedServer
&& !_history
->moveList().isEmpty()) {
717 _render
->highlightPoint(_history
->moveList().last().point());
721 void MainWindow::showPastGameStatus(QModelIndex index
)
723 if (index
== _actualViewIndex
) {
726 QList
<Point
> pointList
;
727 QList
<QColor
> colorList
;
728 if (_actualViewIndex
< index
) {
729 QList
<Move
> list
= _history
->moveList();
730 for (int i
= _actualViewIndex
.row() + 1; i
<= index
.row(); i
++) {
731 pointList
.append(list
.at(i
).point());
732 int id
= list
.at(i
).playerId();
733 colorList
.append(_playersInfo
.at(id
).color());
737 QList
<Move
> list
= _history
->moveList();
738 for (int i
= index
.row() + 1; i
<= _actualViewIndex
.row(); i
++) {
739 pointList
.append(list
.at(i
).point());
742 _render
->uncheckedDraw(pointList
, colorList
);
743 _actualViewIndex
= index
;
744 if (index
.row() == _history
->moveList().size() - 1 && _playersInfo
.at(_actualPlayerIndex
).type() == "H") {
745 _render
->acceptMove(true);
748 _render
->acceptMove(false);
752 void MainWindow::undoTurn()
754 int ply
= _history
->moveList().size();
755 if (ply
<= _playersInfo
.size()) {
758 QModelIndex end
= _history
->index(ply
- _playersInfo
.size() - 1, 0);
762 void MainWindow::undoMoves(QModelIndex index
)
764 if (!_isStandAloneGame
) {
767 if (_playersInfo
.at(_actualPlayerIndex
).type() != "H") {
768 QMessageBox::information(this, tr("Forbidden"), tr("You can't go back when it's not your turn."), QMessageBox::Ok
);
771 if (_loop
->isRunning()) {
772 QMessageBox::StandardButton result
= QMessageBox::question(this, tr("Are you sure?"), tr("Do you really want to bring the game in a past situation?"), QMessageBox::Yes
| QMessageBox::No
);
773 if (result
== QMessageBox::No
) {
777 QList
<Move
> list
= _history
->moveList();
778 if (index
.row() == list
.size() - 1) {
782 Q_ASSERT(_isStandAloneGame
);
784 showPastGameStatus(index
);
786 GameMatrix
*mat
= GameMatrix::instance();
787 QList
<Point
> lastRound
;
788 for (int i
= index
.row(); i
> index
.row() - _playersInfo
.size() && i
>= 0; i
--) {
789 lastRound
.append(list
.at(i
).point());
791 while (lastRound
.size() < _playersInfo
.size()) {
792 lastRound
.append(Point());
794 mat
->setLastRound(lastRound
);
795 for (int i
= index
.row() + 1; i
< list
.size(); i
++) {
796 mat
->clear(list
.at(i
).point());
798 int ply
= list
.size() - index
.row() - 1;
799 _history
->remove(ply
);
801 SyncSharedCondition::instance()->notifyMove(Point());
805 void MainWindow::timerExpired()
807 SyncSharedCondition
*sync
= SyncSharedCondition::instance();
808 QMutexLocker
locker(sync
);
809 sync
->notifyMove(Point());
812 void MainWindow::networkError(QString error
)
814 QMessageBox::critical(this, tr("Error"), tr("%1\nQuitting current game.").arg(error
), QMessageBox::Ok
);
818 void MainWindow::saveGame()
820 //FIXME aggiungere altri controlli?
821 Q_ASSERT(_isStandAloneGame
);
822 QString fileName
= QFileDialog::getSaveFileName(this, tr("Save Game"));
823 if (fileName
.isEmpty()) {
830 if (!f
.open(QIODevice::WriteOnly
)) {
835 QXmlStreamWriter
xml(&f
);
836 xml
.writeStartDocument();
837 xml
.writeDefaultNamespace("http://www.itworks.org/GoMoku3D/SavedGame");
838 xml
.writeStartElement("game");
839 xml
.writeStartElement("settings");
840 xml
.writeTextElement("difficultyOne", QString::number(GameMatrix::instance()->d1()));
841 xml
.writeTextElement("difficultyTwo", QString::number(GameMatrix::instance()->d2()));
842 xml
.writeStartElement("cubeColor");
843 xml
.writeTextElement("r", QString::number(set
.defaultCubeColor().red()));
844 xml
.writeTextElement("g", QString::number(set
.defaultCubeColor().green()));
845 xml
.writeTextElement("b", QString::number(set
.defaultCubeColor().blue()));
846 xml
.writeTextElement("a", QString::number(set
.defaultCubeColor().alpha()));
847 xml
.writeEndElement();
848 xml
.writeStartElement("backgroundColor");
849 xml
.writeTextElement("r", QString::number(set
.backgroundColor().red()));
850 xml
.writeTextElement("g", QString::number(set
.backgroundColor().green()));
851 xml
.writeTextElement("b", QString::number(set
.backgroundColor().blue()));
852 xml
.writeTextElement("a", QString::number(set
.backgroundColor().alpha()));
853 xml
.writeEndElement();
854 xml
.writeEndElement();
855 xml
.writeStartElement("players");
856 for (int i
= 0; i
< _playersInfo
.size(); i
++) {
857 xml
.writeStartElement("player");
858 xml
.writeAttribute("id", QString::number(i
));
859 xml
.writeTextElement("name", _playersInfo
.at(i
).name());
860 xml
.writeStartElement("color");
861 xml
.writeTextElement("r", QString::number(_playersInfo
.at(i
).color().red()));
862 xml
.writeTextElement("g", QString::number(_playersInfo
.at(i
).color().green()));
863 xml
.writeTextElement("b", QString::number(_playersInfo
.at(i
).color().blue()));
864 xml
.writeTextElement("a", QString::number(_playersInfo
.at(i
).color().alpha()));
865 xml
.writeEndElement();
866 xml
.writeTextElement("type", _playersInfo
.at(i
).type());
867 xml
.writeEndElement();
869 xml
.writeEndElement();
870 xml
.writeStartElement("history");
872 foreach (m
, _history
->moveList()) {
873 xml
.writeStartElement("move");
874 xml
.writeTextElement("player", QString::number(m
.playerId()));
875 xml
.writeStartElement("point");
876 xml
.writeTextElement("x", QString::number(m
.point().x()));
877 xml
.writeTextElement("y", QString::number(m
.point().y()));
878 xml
.writeTextElement("z", QString::number(m
.point().z()));
879 xml
.writeEndElement();
880 xml
.writeEndElement();
882 xml
.writeEndElement();
883 xml
.writeEndElement();
884 xml
.writeEndDocument();
888 void MainWindow::loadGame()
890 QString fileName
= QFileDialog::getOpenFileName(this, tr("Open Saved Game"));
891 if (fileName
.isEmpty()) {
896 if (!f
.open(QIODevice::ReadOnly
)) {
897 //TODO: messaggio di errore
901 QXmlStreamReader
xml(&f
);
902 bool success
= xml
.readNext() == QXmlStreamReader::StartDocument
903 && xml
.readNext() == QXmlStreamReader::StartElement
904 && xml
.name() == "game"
905 && parseSettings(xml
)
908 && xml
.readNext() == QXmlStreamReader::EndElement
909 && xml
.readNext() == QXmlStreamReader::EndDocument
;
912 //TODO: messaggio di errore
913 qCritical() << "XML error while parsing file:" << xml
.errorString();
919 bool MainWindow::parseSettings(QXmlStreamReader
&xml
)
924 return xml
.readNext() == QXmlStreamReader::StartElement
925 && xml
.name() == "settings"
926 && parseInt(xml
, "difficultyOne")
927 && parseInt(xml
, "difficultyTwo")
928 && parseColor(xml
, "cubeColor")
929 && parseColor(xml
, "backgroundColor")
930 && xml
.readNext() == QXmlStreamReader::EndElement
;
933 bool MainWindow::parsePlayers(QXmlStreamReader
&xml
)
942 bool MainWindow::parseHistory(QXmlStreamReader
&xml
)
947 if (xml
.readNext() != QXmlStreamReader::StartElement
|| xml
.name() != "history") {
951 while (!xml
.atEnd()) {
952 QXmlStreamReader::TokenType token
= xml
.readNext();
953 if (token
== QXmlStreamReader::StartElement
&& xml
.name() == "move") {
954 if (!parseMove(xml
, i
)) {
958 } else if (xml
.readNext() == QXmlStreamReader::EndElement
) {
967 setProperty("history/size", QVariant(i
));
971 bool MainWindow::parseMove(QXmlStreamReader
&xml
, int n
)
976 bool success
= parseInt(xml
, "player")
978 && xml
.readNext() == QXmlStreamReader::EndElement
;
980 Move
m(property("player").toInt(), property("point").value
<Point
>());
981 setProperty(qPrintable("move_" + QString::number(n
)), QVariant::fromValue(m
));
986 bool MainWindow::parsePoint(QXmlStreamReader
&xml
)
991 bool success
= xml
.readNext() == QXmlStreamReader::StartElement
992 && xml
.name() == "point"
993 && parseInt(xml
, "x")
994 && parseInt(xml
, "y")
995 && parseInt(xml
, "z")
996 && xml
.readNext() == QXmlStreamReader::EndElement
;
998 Point
p(property("x").toInt(), property("y").toInt(), property("z").toInt());
999 setProperty("point", QVariant::fromValue(p
));
1004 bool MainWindow::parseInt(QXmlStreamReader
&xml
, QString elementName
)
1009 if (xml
.readNext() != QXmlStreamReader::StartElement
|| xml
.name() != elementName
) {
1013 int x
= xml
.readElementText().toInt(&ok
);
1017 setProperty(qPrintable(elementName
), QVariant(x
));
1018 return (xml
.readNext() == QXmlStreamReader::EndElement
);
1021 bool MainWindow::parseString(QXmlStreamReader
&xml
, QString elementName
)
1026 if (xml
.readNext() != QXmlStreamReader::StartElement
|| xml
.name() != elementName
) {
1029 setProperty(qPrintable(elementName
), QVariant(xml
.readElementText()));
1030 return (xml
.readNext() == QXmlStreamReader::EndElement
);
1033 bool MainWindow::parseColor(QXmlStreamReader
&xml
, QString elementName
)
1038 bool success
= xml
.readNext() == QXmlStreamReader::StartElement
1039 && xml
.name() == elementName
1040 && parseInt(xml
, "r")
1041 && parseInt(xml
, "g")
1042 && parseInt(xml
, "b")
1043 && parseInt(xml
, "a")
1044 && xml
.readNext() == QXmlStreamReader::EndElement
;
1046 QColor
c(property("r").toInt(), property("g").toInt(), property("b").toInt(), property("a").toInt());
1047 setProperty(qPrintable(elementName
), QVariant(c
));