[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kdots] /: Fixing crashes and adapt ipconnect plugin for the new API.
From: Minh Ngo <nlminhtl () gmail ! com>
Date: 2014-12-31 17:32:57
Message-ID: E1Y6N8j-0005pl-AZ () scm ! kde ! org
[Download RAW message or body]
Git commit 5c352698b4973c448ea4dac516bb2e64186f9d5e by Minh Ngo.
Committed on 31/12/2014 at 17:25.
Pushed by minhngo into branch 'master'.
Fixing crashes and adapt ipconnect plugin for the new API.
M +2 -0 boardmodel.cpp
M +2 -4 boardmodel.hpp
M +2 -0 interface/iconfigurationwidget.hpp
M +4 -0 interface/irival.hpp
M +16 -2 mainwindow.cpp
M +3 -0 mainwindow.hpp
M +15 -12 newgamedialog.cpp
M +1 -0 newgamedialog.hpp
M +1 -1 plugins/CMakeLists.txt
M +9 -7 plugins/ipconnect/configurationwidget.cpp
M +4 -5 plugins/ipconnect/configurationwidget.hpp
M +1 -4 plugins/ipconnect/connectdialog.hpp
M +34 -0 plugins/ipconnect/plugin.cpp
M +7 -29 plugins/ipconnect/plugin.hpp
M +46 -56 plugins/ipconnect/rival.cpp
M +17 -16 plugins/ipconnect/rival.hpp
M +1 -1 plugins/singlepc/plugin.cpp
http://commits.kde.org/kdots/5c352698b4973c448ea4dac516bb2e64186f9d5e
diff --git a/boardmodel.cpp b/boardmodel.cpp
index a39e07e..8181226 100644
--- a/boardmodel.cpp
+++ b/boardmodel.cpp
@@ -55,6 +55,8 @@ namespace KDots
{
m_rival = std::move(rival);
+ m_rival->setBoardModel(this);
+
connect(this, SIGNAL(pointAdded(const Point&)), m_rival.get(), SLOT(onPointAdded(const Point&)));
connect(m_rival.get(), SIGNAL(needAddPoint(const Point&)), this, SLOT(addPoint(const Point&)));
}
diff --git a/boardmodel.hpp b/boardmodel.hpp
index 1d7f178..328ea17 100644
--- a/boardmodel.hpp
+++ b/boardmodel.hpp
@@ -69,13 +69,11 @@ namespace KDots
void statusUpdated(const QString& message);
private:
- std::unique_ptr<IBoardView> m_view;
- std::unique_ptr<IRival> m_rival;
-
std::unique_ptr<Graph> m_graph;
std::shared_ptr<StepQueue> m_steps;
GameConfig m_config;
std::vector<Polygon_ptr> m_polygons;
- bool m_block;
+ std::unique_ptr<IRival> m_rival;
+ std::unique_ptr<IBoardView> m_view;
};
}
\ No newline at end of file
diff --git a/interface/iconfigurationwidget.hpp b/interface/iconfigurationwidget.hpp
index 3c780f4..28357cf 100644
--- a/interface/iconfigurationwidget.hpp
+++ b/interface/iconfigurationwidget.hpp
@@ -36,6 +36,8 @@ namespace KDots
: QWidget(parent)
{
}
+
+ virtual void requestState() = 0;
protected:
virtual void needCreateBoard(bool) = 0;
diff --git a/interface/irival.hpp b/interface/irival.hpp
index d42ad22..5cd1249 100644
--- a/interface/irival.hpp
+++ b/interface/irival.hpp
@@ -59,6 +59,10 @@ namespace KDots
Q_UNUSED(board);
}
+ virtual void requestGameConfig()
+ {
+ }
+
virtual Owner owner() const
{
return Owner::NONE;
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 68e0770..51be0f5 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -50,6 +50,8 @@ namespace KDots
MainWindow::MainWindow(QWidget *parent)
: KXmlGuiWindow(parent)
, m_ui(new Ui::MainWindow)
+ , m_needDestroy(false)
+ , m_gameConfiguring(false)
{
m_ui->setupUi(this);
@@ -101,6 +103,13 @@ namespace KDots
statusBar()->clearMessage();
}
+ void MainWindow::onNeedDestroy()
+ {
+ m_needDestroy = true;
+ if (!m_gameConfiguring)
+ endGame();
+ }
+
void MainWindow::onPreferences()
{
KConfigDialog dialog(this, i18n("Preferences"), Settings::self());
@@ -129,6 +138,9 @@ namespace KDots
void MainWindow::onNewGame()
{
+ m_needDestroy = false;
+ m_gameConfiguring = true;
+ std::shared_ptr<void> finalizer(nullptr, [&](void*) { m_gameConfiguring = false; });
NewGameDialog dialog;
if (dialog.exec() != QDialog::Accepted)
return;
@@ -147,7 +159,7 @@ namespace KDots
m_menu.m_undoAction->setEnabled(rival->canUndo());
- connect(rival.get(), SIGNAL(needDestroy()), this, SLOT(endGame()));
+ connect(rival.get(), SIGNAL(needDestroy()), this, SLOT(onNeedDestroy()));
m_model = std::unique_ptr<BoardModel>(new BoardModel(config, createStepQueue(config)));
connect(m_menu.m_undoAction, SIGNAL(triggered(bool)), m_model.get(), SLOT(undo()));
@@ -163,10 +175,12 @@ namespace KDots
m_model->setView(std::move(view));
}
- rival->setBoardModel(m_model.get());
m_model->setRival(std::move(rival));
m_menu.m_endAction->setEnabled(true);
+
+ if (m_needDestroy)
+ endGame();
}
}
diff --git a/mainwindow.hpp b/mainwindow.hpp
index 48fe785..ed81aac 100644
--- a/mainwindow.hpp
+++ b/mainwindow.hpp
@@ -54,6 +54,7 @@ namespace KDots
void onNewGame();
void onPreferences();
void endGame();
+ void onNeedDestroy();
signals:
void preferencesUpdated();
@@ -61,6 +62,8 @@ namespace KDots
private:
Ui::MainWindow *m_ui;
std::unique_ptr<BoardModel> m_model;
+ bool m_needDestroy;
+ bool m_gameConfiguring;
struct
{
diff --git a/newgamedialog.cpp b/newgamedialog.cpp
index afddf21..007aa10 100644
--- a/newgamedialog.cpp
+++ b/newgamedialog.cpp
@@ -42,6 +42,7 @@ namespace KDots
, m_game(nullptr)
, m_pluginManager(new PluginManagerWidget(this))
, m_configWidget(nullptr)
+ , m_needCreateBoard(false)
{
m_ui->setupUi(this);
@@ -53,8 +54,6 @@ namespace KDots
NewGameDialog::~NewGameDialog()
{
- if (m_configWidget)
- m_configWidget->setParent(0);
}
std::unique_ptr<IRival> NewGameDialog::rival()
@@ -66,6 +65,13 @@ namespace KDots
{
if (m_game)
m_config = m_game->getGameConfig();
+ else if (m_needCreateBoard)
+ {
+ m_rival->requestGameConfig();
+ }
+
+ if (m_configWidget)
+ m_configWidget->setParent(0);
QDialog::accept();
}
@@ -95,7 +101,7 @@ namespace KDots
IPlugin *pluginInstance = PluginLoader::instance().plugin(pluginName);
if (!pluginInstance)
{
- kDebug() << "Plugin instance not exists";
+ kDebug() << "Plugin instance doesn't exists";
return;
}
@@ -110,7 +116,7 @@ namespace KDots
m_configWidget = m_rival->configureWidget();
- if (!m_configWidget)
+ if (m_configWidget == nullptr)
{
gameWidget();
return;
@@ -121,22 +127,19 @@ namespace KDots
connect(m_configWidget, SIGNAL(needCreateBoard(bool)), this, SLOT(onNeedCreateBoard(bool)));
connect(m_ui->NextButton, SIGNAL(clicked(bool)), this, SLOT(gameWidget()));
+
+ m_configWidget->requestState();
}
void NewGameDialog::onNeedCreateBoard(bool val)
{
+ m_needCreateBoard = !val;
+ m_ui->NextButton->setEnabled(val);
+ m_ui->OKButton->setEnabled(m_needCreateBoard);
if (val)
- {
- m_ui->NextButton->setEnabled(true);
- m_ui->OKButton->setEnabled(false);
connect(m_ui->NextButton, SIGNAL(clicked(bool)), this, SLOT(gameWidget()));
- }
else
- {
- m_ui->NextButton->setEnabled(false);
- m_ui->OKButton->setEnabled(true);
m_ui->NextButton->disconnect(this, SLOT(gameWidget()));
- }
}
void NewGameDialog::gameWidget()
diff --git a/newgamedialog.hpp b/newgamedialog.hpp
index 17744c6..b9c4909 100644
--- a/newgamedialog.hpp
+++ b/newgamedialog.hpp
@@ -69,5 +69,6 @@ namespace KDots
std::unique_ptr<IRival> m_rival;
GameConfig m_config;
+ bool m_needCreateBoard;
};
}
\ No newline at end of file
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 725a085..ee41fb0 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -1,3 +1,3 @@
ADD_SUBDIRECTORY(singlepc)
-#ADD_SUBDIRECTORY(ipconnect)
+ADD_SUBDIRECTORY(ipconnect)
ADD_SUBDIRECTORY(simpleai)
\ No newline at end of file
diff --git a/plugins/ipconnect/configurationwidget.cpp b/plugins/ipconnect/configurationwidget.cpp
index ee1121a..c3d0d2b 100644
--- a/plugins/ipconnect/configurationwidget.cpp
+++ b/plugins/ipconnect/configurationwidget.cpp
@@ -45,20 +45,22 @@ namespace KDots
{
m_ui->setupUi(this);
- connect(m_ui->tabWidget,
- SIGNAL(currentChanged(int)),
- this,
- SLOT(onTabChanged(int)));
+ connect(m_ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int)));
+ }
+
+ void ConfigurationWidget::requestState()
+ {
+ onTabChanged(m_ui->tabWidget->currentIndex());
}
void ConfigurationWidget::onTabChanged(int index)
{
- emit needCreateTable(index == CreateGameTab);
+ emit needCreateBoard(index == CreateGameTab);
}
bool ConfigurationWidget::clientConfig(ClientConfig& config)
{
- if(m_ui->tabWidget->currentIndex() == CreateGameTab)
+ if (m_ui->tabWidget->currentIndex() == CreateGameTab)
return false;
else
{
@@ -70,7 +72,7 @@ namespace KDots
bool ConfigurationWidget::serverConfig(ServerConfig& config)
{
- if(m_ui->tabWidget->currentIndex() == JoinGameTab)
+ if (m_ui->tabWidget->currentIndex() == JoinGameTab)
return false;
else
{
diff --git a/plugins/ipconnect/configurationwidget.hpp b/plugins/ipconnect/configurationwidget.hpp
index 706a685..4b23bac 100644
--- a/plugins/ipconnect/configurationwidget.hpp
+++ b/plugins/ipconnect/configurationwidget.hpp
@@ -23,8 +23,7 @@
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef KDOTS_PLUGINS_IPCONNECT_CONFIGURATIONWIDGET_HPP
-#define KDOTS_PLUGINS_IPCONNECT_CONFIGURATIONWIDGET_HPP
+#pragma once
#include <interface/iconfigurationwidget.hpp>
namespace Ui
{
@@ -56,15 +55,15 @@ namespace KDots
public:
ConfigurationWidget(QWidget *parent = 0);
+ void requestState();
+
bool clientConfig(ClientConfig& config);
bool serverConfig(ServerConfig& config);
private slots:
void onTabChanged(int index);
signals:
- void needCreateTable(bool);
+ void needCreateBoard(bool);
};
}
}
-
-#endif
diff --git a/plugins/ipconnect/connectdialog.hpp b/plugins/ipconnect/connectdialog.hpp
index 76168a2..c16c05f 100644
--- a/plugins/ipconnect/connectdialog.hpp
+++ b/plugins/ipconnect/connectdialog.hpp
@@ -23,8 +23,7 @@
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef KDOTS_PLUGINS_IPCONNECT_CONNECTDIALOG_HPP
-#define KDOTS_PLUGINS_IPCONNECT_CONNECTDIALOG_HPP
+#pragma once
#include <QDialog>
namespace Ui
@@ -49,5 +48,3 @@ namespace KDots
};
}
}
-
-#endif
diff --git a/plugins/ipconnect/plugin.cpp b/plugins/ipconnect/plugin.cpp
index c26125a..705b0e7 100644
--- a/plugins/ipconnect/plugin.cpp
+++ b/plugins/ipconnect/plugin.cpp
@@ -24,5 +24,39 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "plugin.hpp"
+#include <KLocalizedString>
+#include <KgDifficulty>
+
+namespace KDots
+{
+namespace ipconnect
+{
+ Plugin::Plugin(QObject *parent)
+ : IPlugin(parent)
+ {
+ Kg::difficulty()->setEditable(false);
+ }
+
+ std::unique_ptr<IRival> Plugin::createRival()
+ {
+ return std::unique_ptr<IRival>(new Rival);
+ }
+
+ QString Plugin::name() const
+ {
+ return "ipconnect";
+ }
+
+ QString Plugin::description() const
+ {
+ return i18n("Playing by internet connection");
+ }
+
+ KIcon Plugin::icon() const
+ {
+ return KIcon("network-connect");
+ }
+}
+}
Q_EXPORT_PLUGIN2(kdots_ipconnection, KDots::ipconnect::Plugin)
\ No newline at end of file
diff --git a/plugins/ipconnect/plugin.hpp b/plugins/ipconnect/plugin.hpp
index 98a2f1c..dc5b4ca 100644
--- a/plugins/ipconnect/plugin.hpp
+++ b/plugins/ipconnect/plugin.hpp
@@ -23,8 +23,7 @@
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef KDOTS_PLUGINS_IPCONNECT_PLUGIN_HPP
-#define KDOTS_PLUGINS_IPCONNECT_PLUGIN_HPP
+#pragma once
#include <interface/iplugin.hpp>
#include "rival.hpp"
@@ -37,33 +36,12 @@ namespace KDots
Q_OBJECT
Q_INTERFACES(KDots::IPlugin)
public:
- Plugin(QObject *parent = 0)
- : IPlugin(parent)
- {
- }
-
- std::unique_ptr<IRival> createRival()
- {
- return std::unique_ptr<IRival>(new Rival);
- }
-
- QString name() const
- {
- return "ipconnect";
- }
-
- QString description() const
- {
- return "Playing by internet connection";
- }
+ Plugin(QObject *parent = 0);
- KIcon icon() const
- {
- return KIcon("network-connect");
- }
+ std::unique_ptr<IRival> createRival();
+ QString name() const;
+ QString description() const;
+ KIcon icon() const;
};
-
}
-}
-
-#endif
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/plugins/ipconnect/rival.cpp b/plugins/ipconnect/rival.cpp
index 4882b21..9ce63c4 100644
--- a/plugins/ipconnect/rival.cpp
+++ b/plugins/ipconnect/rival.cpp
@@ -40,8 +40,8 @@ namespace KDots
{
Rival::Rival(QObject *parent)
: IRival(parent)
- , m_socket(NULL)
- , m_server(NULL)
+ , m_socket(nullptr)
+ , m_server(nullptr)
, m_me(Owner::NONE)
{
Kg::difficulty()->setEditable(false);
@@ -49,56 +49,52 @@ namespace KDots
Rival::~Rival()
{
- if(m_socket)
- m_socket->disconnectFromHost();
+ m_configWidget->setParent(0);
}
namespace
{
Owner itemToOwner(int index)
{
- if(!index)
+ if (index == 0)
return Owner::FIRST;
- else
- return Owner::SECOND;
+
+ return Owner::SECOND;
}
}
void Rival::onDisconnected()
{
- QMessageBox::warning(0,
- i18n("The socket has been disconnected"),
- i18n("The socket has been disconnected"));
+ KMessageBox::information(0,
+ i18n("Client has been disconnected. Please recreate a game"),
+ i18n("Client has been disconnected"));
}
- GameConfig Rival::getGameConfig()
+ void Rival::requestGameConfig()
{
ClientConfig config;
- if(!m_configWidget->clientConfig(config))
+ if (!m_configWidget->clientConfig(config))
{
- return GameConfig();
+ return;
}
//Joining Game
m_socket = new QTcpSocket(this);
- connect(m_socket,
- SIGNAL(disconnected()),
- this,
- SLOT(onDisconnected()));
+ connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
m_socket->connectToHost(config.m_host, config.m_port);
- kDebug() << "Connecting to the server...";
- if(m_socket->waitForConnected(5000))
+ kWarning() << "Connecting to the server...";
+ if (m_socket->waitForConnected(5000))
{
- kDebug() << "Connected";
+ kWarning() << "Connected";
- if(m_socket->waitForReadyRead())
+ if (m_socket->waitForReadyRead())
{
- kDebug() << "Reading Table config";
+ kWarning() << "Reading Table config";
const QByteArray& data = m_socket->readAll();
- kDebug() << "Data size" << data.size();
+ kWarning() << "Data size" << data.size();
QDataStream in(&const_cast<QByteArray&>(data), QIODevice::ReadOnly);
QVariant variantData;
@@ -106,29 +102,26 @@ namespace KDots
in >> variantData >> me;
m_me = static_cast<Owner>(me);
- if(!variantData.canConvert<GameConfig>())
+ if (!variantData.canConvert<GameConfig>())
{
kWarning() << "Cannot convert to GameConfig: "
<< variantData.typeName();
}
const GameConfig& config = variantData.value<GameConfig>();
- if(!config.isInititialized())
+ if (!config.isInititialized())
{
kWarning() << "Table config is invalid";
- return GameConfig();
+ return;
}
else
{
- connect(m_socket,
- SIGNAL(readyRead()),
- this,
- SLOT(onReadyRead()));
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
KMessageBox::information(0,
i18n("Connected"),
i18n("Good luck have fun"));
- return config;
+ emit needCreateBoard(config);
}
}
}
@@ -140,8 +133,6 @@ namespace KDots
emit needDestroy();
}
-
- return GameConfig();
}
void Rival::setBoardModel(BoardModel *board) //Is called after configureWidget
@@ -149,7 +140,7 @@ namespace KDots
m_board = board;
ServerConfig config;
- if(!m_configWidget->serverConfig(config))
+ if (!m_configWidget->serverConfig(config))
{
// Client
return;
@@ -160,14 +151,12 @@ namespace KDots
//Create server
m_server = new QTcpServer(this);
+ m_server->setMaxPendingConnections(1);
- connect(m_server,
- SIGNAL(newConnection()),
- this,
- SLOT(onNewConnectionHandle()));
+ connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnectionHandle()));
ConnectDialog dialog(m_server, config.m_port);
- if(dialog.exec() != QDialog::Accepted)
+ if (dialog.exec() != QDialog::Accepted)
{
m_server->close();
emit needDestroy();
@@ -177,33 +166,31 @@ namespace KDots
IConfigurationWidget* Rival::configureWidget()
{
m_configWidget.reset(new ConfigurationWidget);
- ConfigurationWidget *w = m_configWidget.get();
-
- return w;
+ return m_configWidget.get();
}
- bool Rival::isAllow() const
+ Owner Rival::owner() const
{
- return m_board->stepQueue().getCurrentOwner() == m_me;
+ return m_me;
}
- void Rival::nextStep(const Point& point)
+ void Rival::onPointAdded(const Point& point)
{
- if(!m_socket)
+ if (!m_socket)
return;
-
- kDebug() << "Sending point";
+ kWarning() << "Sending point";
QByteArray array;
QDataStream out(&array, QIODevice::WriteOnly);
out << QVariant::fromValue<Point>(point);
- kDebug() << m_socket->write(array);
+ kWarning() << m_socket->write(array);
}
void Rival::onNewConnectionHandle()
{
m_socket = m_server->nextPendingConnection();
- if(!m_socket)
+
+ if (!m_socket)
return;
QByteArray gameData;
@@ -211,11 +198,9 @@ namespace KDots
out << QVariant::fromValue<GameConfig>(m_board->gameConfig())
<< static_cast<quint32>(StepQueue::other(m_me));
m_socket->write(gameData);
- kDebug() << "Game config sent";
- connect(m_socket,
- SIGNAL(readyRead()),
- this,
- SLOT(onReadyRead()));
+ kWarning() << "Game config sent";
+ connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
}
void Rival::onReadyRead()
@@ -225,7 +210,12 @@ namespace KDots
QVariant var;
in >> var;
const Point& point = var.value<Point>();
- m_board->pushPoint(point);
+
+ emit needAddPoint(point);
+ }
+
+ void Rival::onDifficultyChanged(const KgDifficultyLevel*)
+ {
}
}
}
diff --git a/plugins/ipconnect/rival.hpp b/plugins/ipconnect/rival.hpp
index 90f3663..931a931 100644
--- a/plugins/ipconnect/rival.hpp
+++ b/plugins/ipconnect/rival.hpp
@@ -23,8 +23,7 @@
*(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef KDOTS_PLUGINS_IPCONNECT_RIVAL_HPP
-#define KDOTS_PLUGINS_IPCONNECT_RIVAL_HPP
+#pragma once
#include <memory>
#include <QObject>
#include <QTcpSocket>
@@ -40,37 +39,39 @@ namespace KDots
class Rival : public KDots::IRival
{
Q_OBJECT
-
- BoardModel *m_board;
- QTcpSocket *m_socket;
- QTcpServer *m_server;
-
- Owner m_me;
-
- std::unique_ptr<ConfigurationWidget> m_configWidget;
public:
Rival(QObject *parent = 0);
virtual ~Rival();
- GameConfig getGameConfig();
-
IConfigurationWidget* configureWidget();
void setBoardModel(BoardModel *board);
+ void requestGameConfig();
- bool isAllow() const;
+ Owner owner() const;
public slots:
- void nextStep(const Point& point);
+ void onPointAdded(const Point& point);
+ void onDifficultyChanged(const KgDifficultyLevel*);
private slots:
void onNewConnectionHandle();
void onReadyRead();
void onDisconnected();
+
signals:
- void createBoardModel(const GameConfig& config);
+ void needCreateBoard(const GameConfig& config);
void needDestroy();
+ void needAddPoint(const Point&);
+
+ private:
+ BoardModel *m_board;
+ QTcpSocket *m_socket;
+ QTcpServer *m_server;
+
+ Owner m_me;
+
+ std::unique_ptr<ConfigurationWidget> m_configWidget;
};
}
}
-#endif
diff --git a/plugins/singlepc/plugin.cpp b/plugins/singlepc/plugin.cpp
index 5cdcd43..47968ba 100644
--- a/plugins/singlepc/plugin.cpp
+++ b/plugins/singlepc/plugin.cpp
@@ -36,7 +36,7 @@ namespace singlepc
{
Kg::difficulty()->setEditable(false);
}
-
+
bool Rival::canUndo() const
{
return true;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic