Warning, file /games/konquest/src/dialogs/newgamedlg.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2003 Russell Steffen <rsteffen@bayarea.net>
0003     SPDX-FileCopyrightText: 2003 Stephan Zehetner <s.zehetner@nevox.org>
0004     SPDX-FileCopyrightText: 2006 Dmitry Suzdalev <dimsuz@gmail.com>
0005     SPDX-FileCopyrightText: 2006 Inge Wallin <inge@lysator.liu.se>
0006     SPDX-FileCopyrightText: 2006 Pierre Ducroquet <pinaraf@gmail.com>
0007     SPDX-FileCopyrightText: 2011 Jeffrey Kelling <overlordapophis@gmail.com>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "newgamedlg.h"
0013 
0014 #include "../players/ai/becai/becai_gui.h"
0015 #include "../players/ai/becai/becai.h"
0016 #include "../players/ai/default/weak_gui.h"
0017 #include "../players/ai/default/normal_gui.h"
0018 #include "../players/ai/default/hard_gui.h"
0019 #ifdef KONQUEST_EXAMPLE_PLAYER
0020 #include "../players/ai/example/example_gui.h"
0021 #endif
0022 #include "../players/computerplayer.h"
0023 #include "../players/player_gui.h"
0024 #include "../players/localplayer.h"
0025 #include "../players/localplayer_gui.h"
0026 #include "../players/spectatorplayer.h"
0027 #include "../players/spectatorplayer_gui.h"
0028 #include "../game.h"
0029 
0030 #include <KConfig>
0031 #include <KConfigGroup>
0032 #include <KLocalizedString>
0033 #include <KSharedConfig>
0034 
0035 #include <QComboBox>
0036 #include <QHeaderView>
0037 #include <QItemDelegate>
0038 #include <QLineEdit>
0039 #include <QList>
0040 #include <QVector>
0041 #include <QMenu>
0042 #include <QPair>
0043 #include <QPushButton>
0044 #include <QDialogButtonBox>
0045 #include <QVBoxLayout>
0046 
0047 /*************************************************************************
0048  New Game Dialog Members
0049  ************************************************************************/
0050 
0051 static const QColor PlayerColors[MAX_PLAYERS] = { 
0052     QColor( 130, 130, 255 ),
0053     Qt::yellow,
0054     Qt::red,
0055     Qt::green,
0056     Qt::white,
0057     Qt::cyan,
0058     Qt::magenta,
0059     QColor( 235, 153, 46 ),
0060     QColor( 106, 157, 104 ),
0061     QColor( 131, 153, 128) 
0062 };
0063 
0064 class playersListModel : public QAbstractTableModel
0065 {
0066     typedef QPair<QColor, QString> PlayerId;
0067     QVector<PlayerId> m_availablePlayerId;
0068     NewGameDlg *m_newGameDlg;
0069 
0070 public:
0071     playersListModel(NewGameDlg *newGameDlg, Game *game, const QList<PlayerGui*> &selectablePlayer) :
0072         QAbstractTableModel(newGameDlg),
0073         m_newGameDlg(newGameDlg),
0074         m_game(game),
0075         m_selectablePlayer(selectablePlayer)
0076     {
0077         for(int a = 0; a < MAX_PLAYERS; ++a)
0078         {
0079             m_availablePlayerId.push_back(PlayerId(
0080                 PlayerColors[a], QString( i18nc("Default player name is \"player \" + player number", "Player %1", a) )));
0081         }
0082     }
0083 
0084     int rowCount(const QModelIndex &index = QModelIndex()) const override
0085     {
0086         Q_UNUSED(index);
0087         return m_players.count();
0088     }
0089 
0090     int columnCount(const QModelIndex&) const override
0091     {
0092         return 2;
0093     }
0094 
0095     QVariant data(const QModelIndex &index, int role) const override
0096     {
0097         if (index.isValid())
0098         {
0099             int row = index.row();
0100             int column = index.column();
0101             Player *player = m_players.at(row);
0102             if (role == Qt::DecorationRole && column == 0)
0103             {
0104                 return player->color();
0105             }
0106             else if (role == Qt::DisplayRole)
0107             {
0108                 if (column == 0)
0109                 {
0110                     return player->name();
0111                 }
0112                 else if (column == 1)
0113                 {
0114                     return player->guiName();
0115                 }
0116             }
0117         }
0118         return QVariant();
0119     }
0120 
0121     QVariant headerData(int section, Qt::Orientation orientation, int role) const override
0122     {
0123         if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
0124         {
0125             if (section == 0) return i18nc("The player name", "Name");
0126             else if (section == 1) return i18n("Type");
0127         }
0128         return QVariant();
0129     }
0130 
0131     bool setData(const QModelIndex &index, const QVariant &value, int) override
0132     {
0133         bool result = false;
0134         if (index.isValid())
0135         {
0136             int row = index.row();
0137             int column = index.column();
0138 
0139             Player *player = m_players.at(row);
0140             if (column == 0)
0141             {
0142 
0143                 // The player name changed.
0144 
0145                 player->setName(value.toString());
0146                 result = true;
0147             }
0148             else if (column == 1)
0149             {
0150                 // The player controller changed.
0151                 QString playerGuiName = value.toString();
0152                 for (PlayerGui *playerGui : std::as_const(m_selectablePlayer))
0153                 {
0154                     if (playerGui->guiName() == playerGuiName) {
0155                         Player *newPlayer = getNewPlayerByGui(playerGui, player->name(), player->color());
0156 
0157                         if (newPlayer) {
0158                             m_players[row] = newPlayer;
0159                             m_game->map()->turnOverPlayerPlanets(player, newPlayer);
0160                             player->deleteLater();
0161 
0162                             result = true;
0163                         }
0164                     }
0165                 }
0166             }
0167         }
0168 
0169         if (result) {
0170             m_game->setPlayers(m_players);
0171             m_newGameDlg->updateButtonOk();
0172             Q_EMIT dataChanged(index, index);
0173         }
0174 
0175         return result;
0176     }
0177 
0178     Player *addPlayer(PlayerGui* selectedPlayer = nullptr)
0179     {
0180         Player *player = nullptr;
0181         int players = m_players.count();
0182 
0183         if ((!m_availablePlayerId.empty()) && (!m_selectablePlayer.empty())) {
0184             beginInsertRows(QModelIndex(), players, players);
0185 
0186             // Use the given player controller. If none is given, use the very
0187             // first registered player controller as default.
0188 
0189             if (!selectedPlayer) {
0190                 selectedPlayer = m_selectablePlayer.front();
0191             }
0192 
0193             player = getNewPlayerByGui(selectedPlayer, m_availablePlayerId.front().second, m_availablePlayerId.front().first);
0194 
0195             if (player) {
0196                 m_availablePlayerId.pop_front();
0197                 m_players.append(player);
0198                 m_game->setPlayers(m_players);
0199                 m_newGameDlg->updateButtonOk();
0200             }
0201 
0202             endInsertRows();
0203         }
0204         return player;
0205     }
0206 
0207     Qt::ItemFlags flags(const QModelIndex &) const override
0208     {
0209         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
0210     }
0211 
0212     Player *removePlayer(int row)
0213     {
0214         Player *player = nullptr;
0215         if (row >= 0 && row < m_players.count())
0216         {
0217             beginRemoveRows(QModelIndex(), row, row);
0218             player = m_players.at(row);
0219             m_availablePlayerId.push_back(PlayerId(player->color(), player->name()));
0220             m_players.removeAt(row);
0221             m_game->setPlayers(m_players);
0222             m_newGameDlg->updateButtonOk();
0223             endRemoveRows();
0224         }
0225         return player;
0226     }
0227 
0228 private:
0229 
0230     /**
0231      * Search the list of registered player controllers and return either a new
0232      * instance of that controller or NULL if it cannot be found.
0233      *
0234      * @note The GUI name of the player instance gets set.
0235      */
0236 
0237     Player *getNewPlayerByGui(PlayerGui *playerGui, const QString &playerName, const QColor &color) const
0238     {
0239         Player *newPlayer = nullptr;
0240         if (playerGui)
0241         {
0242             newPlayer = playerGui->createInstance(m_game, playerName, color);
0243             newPlayer->setGuiName(playerGui->guiName());
0244         }
0245         return newPlayer;
0246     }
0247 
0248 private:
0249     Game *m_game;
0250     QList<Player *> m_players;
0251     QList<PlayerGui*> m_selectablePlayer;
0252 };
0253 
0254 
0255 /**
0256  * This class handles the list of selectable player controllers.
0257  * This includes the local player and all enabled AI players.
0258  */
0259 
0260 class playersListDelegate : public QItemDelegate
0261 {
0262 public:
0263     playersListDelegate(QObject *parent, const QList<PlayerGui*> &selectablePlayer) :
0264         QItemDelegate(parent),
0265         m_selectablePlayer(selectablePlayer)
0266     {
0267     }
0268 
0269     QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const override
0270     {
0271         if (index.column() == 0)
0272             return new QLineEdit(parent);
0273         else
0274             return new QComboBox(parent);
0275     }
0276 
0277     void setEditorData(QWidget *editor, const QModelIndex &index) const override
0278     {
0279         if (index.column() != 0) {
0280             QComboBox *cbox = static_cast<QComboBox*>(editor);
0281 
0282             for (PlayerGui* playerGui : std::as_const(m_selectablePlayer)) {
0283                 cbox->addItem(playerGui->guiName());
0284             }
0285 
0286             cbox->setCurrentIndex( cbox->findText(index.data( Qt::DisplayRole).toString()) );
0287         } else {
0288             QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
0289             lineEdit->setText(index.data(Qt::DisplayRole).toString());
0290         }
0291     }
0292 
0293     void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
0294     {
0295         if (index.column() != 0) {
0296             QComboBox *cbox = static_cast<QComboBox*>(editor);
0297 
0298             model->setData(index, cbox->currentText(), Qt::EditRole);
0299         } else {
0300             QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
0301 
0302             model->setData(index, lineEdit->text(), Qt::EditRole);
0303         }
0304     }
0305 
0306 private:
0307     QList<PlayerGui*> m_selectablePlayer;
0308 };
0309 
0310 NewGameDlg::NewGameDlg( QWidget *parent, Game *game)
0311     : QDialog( parent),
0312       m_game(game)
0313 {
0314     m_neutral = m_game->neutral();
0315     setWindowTitle(i18nc("@title:window", "Start New Game"));
0316     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0317     QWidget *mainWidget = new QWidget(this);
0318     QVBoxLayout *mainLayout = new QVBoxLayout;
0319     setLayout(mainLayout);
0320     mainLayout->addWidget(mainWidget);
0321     okButton = buttonBox->button(QDialogButtonBox::Ok);
0322     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0323     connect(buttonBox, &QDialogButtonBox::accepted, this, &NewGameDlg::accept);
0324     connect(buttonBox, &QDialogButtonBox::rejected, this, &NewGameDlg::reject);
0325 
0326     m_selectablePlayer.push_back(new LocalPlayerGui());
0327     m_selectablePlayer.push_back(new SpectatorPlayerGui());
0328     m_selectablePlayer.push_back(new AiDefaultWeakGui());
0329     m_selectablePlayer.push_back(new AiDefaultNormalGui());
0330     m_selectablePlayer.push_back(new AiDefaultHardGui());
0331 #ifdef KONQUEST_EXAMPLE_PLAYER
0332     m_selectablePlayer.push_back(new AiExampleGui());
0333 #endif
0334     m_selectablePlayer.push_back(new AiBecaiGui());
0335 
0336     m_playerTypeChooser = new QMenu(this);
0337     for (int i = 0 ; i < m_selectablePlayer.size() ; i++)
0338     {
0339         PlayerGui *selectablePlayer = m_selectablePlayer[i];
0340         QAction *action = m_playerTypeChooser->addAction(selectablePlayer->guiName());
0341         connect(action, &QAction::triggered, this, [this, i]() { slotAddPlayer(i);});
0342     }
0343 
0344     m_w = new NewGameDlgUI(this);
0345     m_w->map->setMap(m_game->map());
0346 
0347     connect(m_w->map, &MiniMapView::sectorSelected, this, &NewGameDlg::slotUpdateSelection);
0348 
0349     playersListModel *model = new playersListModel(this, m_game, m_selectablePlayer);
0350 
0351     m_w->playerList->setModel(model);
0352     m_w->playerList->setItemDelegate(new playersListDelegate(this, m_selectablePlayer));
0353     m_w->playerList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0354     m_w->addPlayerButton->setMenu(m_playerTypeChooser);
0355 
0356     connect(m_w->neutralPlanetsSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotUpdateNeutrals);
0357     connect(m_w->widthSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotNewMap);
0358     connect(m_w->heightSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotNewMap);
0359     connect(m_w->randomizeMap, &QPushButton::clicked, this, &NewGameDlg::slotNewMap);
0360     connect(m_w->removePlayerButton, &QPushButton::clicked, this, &NewGameDlg::slotRemovePlayer);
0361 
0362     connect(m_w->OwnerCB, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NewGameDlg::slotNewOwner);
0363     connect(m_w->KillPercentageSB, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &NewGameDlg::slotNewKillPercentage);
0364     connect(m_w->ProductionSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotNewProduction);
0365 
0366     init();
0367 
0368     mainLayout->addWidget(m_w);
0369     mainLayout->addWidget(buttonBox);
0370     okButton->setDefault(true);
0371     slotNewMap();
0372 
0373     updateButtonOk();
0374 }
0375 
0376 NewGameDlg::~NewGameDlg()
0377 {
0378     qDeleteAll(m_selectablePlayer);
0379 }
0380 
0381 void
0382 NewGameDlg::updateOwnerCB()
0383 {
0384     m_w->OwnerCB->clear();
0385 
0386     m_w->OwnerCB->addItem(i18n("vacant"));
0387     for (Player* player : m_game->players())
0388         m_w->OwnerCB->addItem(player->name());
0389     m_w->OwnerCB->addItem(i18n("neutral"));
0390 }
0391 
0392 
0393 void
0394 NewGameDlg::init()
0395 {
0396     KConfigGroup config = KSharedConfig::openConfig()->group("Game");
0397 
0398     int nrOfPlayers = config.readEntry("NrOfPlayers",0);
0399     if (nrOfPlayers < 2)
0400         nrOfPlayers = 2;
0401     if (nrOfPlayers > MAX_PLAYERS)
0402         nrOfPlayers = MAX_PLAYERS;
0403 
0404     int nrOfPlanets = config.readEntry("NrOfPlanets", 3);
0405     int sizeWid = config.readEntry("SizeWidth", 10);
0406     int sizeHeight = config.readEntry("SizeHeight", 10);
0407 
0408     m_w->neutralPlanetsSB->setValue(nrOfPlanets);
0409     m_w->widthSB->setValue(sizeWid);
0410     m_w->heightSB->setValue(sizeHeight);
0411     
0412     m_w->BlindMapCB->setCheckState(
0413                 config.readEntry("BlindMap", false) ? Qt::Checked : Qt::Unchecked);
0414     m_w->CumulativeProductionCB->setCheckState(
0415                 config.readEntry("CumulativeProduction", false) ? Qt::Checked : Qt::Unchecked);
0416     m_w->ProductionAfterConquereCB->setCheckState(
0417                 config.readEntry("ProductionAfterConquere", true) ? Qt::Checked : Qt::Unchecked);
0418     m_w->NeutralsShowShipsCB->setCheckState(
0419                 config.readEntry("NeutralsShowShips", false) ? Qt::Checked : Qt::Unchecked);
0420     m_w->NeutralsShowStatsCB->setCheckState(
0421                 config.readEntry("NeutralsShowStats", false) ? Qt::Checked : Qt::Unchecked);
0422     m_w->NeutralsProductionSB->setValue(config.readEntry("NeutralsProduction", 1));
0423 
0424     // Restore player names
0425     playersListModel *model = static_cast<playersListModel*>(m_w->playerList->model());
0426     for(int i = 0; i < nrOfPlayers; ++i)
0427     {
0428         QString keyName = QStringLiteral("Player_%1").arg(i);
0429         QString keyType = QStringLiteral("PlayerType_%1").arg(i);
0430 
0431         QString playerName = config.readEntry(keyName,QString());
0432         QString playerType = config.readEntry(keyType,QString());
0433 
0434         model->addPlayer();
0435         if (!playerName.isEmpty()) {
0436             model->setData(model->index(i, 0), playerName, Qt::EditRole);
0437         }
0438         model->setData(model->index(i, 1), playerType, Qt::EditRole);
0439     }
0440     updateOwnerCB();
0441 }
0442 
0443 void
0444 NewGameDlg::slotAddPlayer(int selectedPlayerType)
0445 {
0446     PlayerGui *selectablePlayer = m_selectablePlayer[selectedPlayerType];
0447 
0448     playersListModel *model = static_cast<playersListModel*>(m_w->playerList->model());
0449 
0450     Player *player = model->addPlayer(selectablePlayer);
0451     if (player) {
0452         m_game->map()->addPlayerPlanetSomewhere(player);
0453     }
0454 
0455     updateButtonOk();
0456     updateOwnerCB();
0457 }
0458 
0459 void
0460 NewGameDlg::slotRemovePlayer()
0461 {
0462     playersListModel *model = static_cast<playersListModel*>(m_w->playerList->model());
0463 
0464     Player *player = model->removePlayer(m_w->playerList->currentIndex().row());
0465     if(player) {
0466         m_game->map()->removePlayerPlanets(player);
0467         delete player;
0468     }
0469 
0470     updateButtonOk();
0471     updateOwnerCB();
0472 }
0473 
0474 
0475 void
0476 NewGameDlg::slotUpdateSelection(const Coordinate &coord)
0477 {
0478     Sector *sector = m_game->map()->sector(coord);
0479     if (!sector) {
0480         m_w->OwnerCB->setEnabled(false);
0481         m_w->KillPercentageSB->setEnabled(false);
0482         m_w->ProductionSB->setEnabled(false);
0483         return;
0484     }
0485     bool hasPlanet = sector->hasPlanet();
0486 
0487     m_w->OwnerCB->setEnabled(hasPlanet);
0488     m_w->KillPercentageSB->setEnabled(hasPlanet);
0489     m_w->ProductionSB->setEnabled(hasPlanet);
0490 
0491     disconnect(m_w->OwnerCB, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NewGameDlg::slotNewOwner);
0492 
0493     if (hasPlanet) {
0494         Planet *planet = sector->planet();
0495         int f = m_w->OwnerCB->findText(planet->player()->name());
0496         if (f >= 0) {
0497             m_w->OwnerCB->setCurrentIndex(f);
0498         }
0499         else {
0500             m_w->OwnerCB->setCurrentIndex(m_w->OwnerCB->count()-1);
0501         }
0502 
0503         m_w->KillPercentageSB->setValue(planet->killPercentage());
0504         m_w->ProductionSB->setValue(planet->production());
0505     }
0506     else {
0507         m_w->OwnerCB->setCurrentIndex(0);
0508     }
0509 
0510     connect(m_w->OwnerCB, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &NewGameDlg::slotNewOwner);
0511 }
0512 
0513 
0514 void
0515 NewGameDlg::slotNewOwner(int index)
0516 {
0517     if (!m_w->map->hasSelection())
0518         return;
0519     Sector *sector = m_game->map()->sector(m_w->map->selection());
0520     if (sector->hasPlanet()) {
0521         delete sector->planet();
0522     }
0523 
0524     if (index > 0) {
0525         m_game->map()->addPlanet(sector,
0526                                  index - 1 < m_game->players().count()
0527                                  ? m_game->players()[index-1]
0528                                  :  m_neutral,
0529                                  m_w->ProductionSB->value(),
0530                                  m_w->KillPercentageSB->value());
0531     }
0532 
0533     m_w->KillPercentageSB->setEnabled(index);
0534     m_w->ProductionSB->setEnabled(index);
0535 
0536     updateButtonOk();
0537 }
0538 
0539 
0540 void
0541 NewGameDlg::slotNewKillPercentage(double value)
0542 {
0543     Sector *selected = m_game->map()->sector(m_w->map->selection());
0544     if(selected->hasPlanet())
0545         selected->planet()->setKillPercentage(value);
0546 }
0547 
0548 
0549 void
0550 NewGameDlg::slotNewProduction(int value)
0551 {
0552     Sector *selected = m_game->map()->sector(m_w->map->selection());
0553     if(selected->hasPlanet())
0554         selected->planet()->setProduction(value);
0555 }
0556 
0557 void
0558 NewGameDlg::save()
0559 {
0560     KConfigGroup config = KSharedConfig::openConfig()->group("Game");
0561     
0562     config.writeEntry("NrOfPlanets", m_w->neutralPlanetsSB->value());
0563     config.writeEntry("SizeWidth", m_w->widthSB->value());
0564     config.writeEntry("SizeHeight", m_w->heightSB->value());
0565 
0566 #define CONFIG_WRITE_ENTRY_CB(NAME) \
0567     config.writeEntry(#NAME, m_game->options().NAME \
0568     = m_w->NAME##CB->checkState() == Qt::Checked);
0569 
0570     CONFIG_WRITE_ENTRY_CB(BlindMap);
0571     CONFIG_WRITE_ENTRY_CB(CumulativeProduction);
0572     CONFIG_WRITE_ENTRY_CB(ProductionAfterConquere);
0573     CONFIG_WRITE_ENTRY_CB(NeutralsShowShips);
0574     CONFIG_WRITE_ENTRY_CB(NeutralsShowStats);
0575 
0576     config.writeEntry("NeutralsProduction",
0577                       m_game->options().NeutralsProduction = m_w->NeutralsProductionSB->value());
0578 
0579     playersListModel *model = static_cast<playersListModel*>(m_w->playerList->model());
0580     config.writeEntry("NrOfPlayers", model->rowCount());
0581     for (int i = 0; i < model->rowCount(); ++i)
0582     {
0583         QString  keyName        = QStringLiteral("Player_%1").arg(i);
0584         QString  playerName = model->data(model->index(i, 0), Qt::DisplayRole).toString();
0585         QString  keyType = QStringLiteral("PlayerType_%1").arg(i);
0586         QString  playerType = model->data(model->index(i, 1), Qt::DisplayRole).toString();
0587 
0588         config.writeEntry(keyName, playerName);
0589         config.writeEntry(keyType, playerType);
0590     }
0591     config.sync();
0592 }
0593 
0594 
0595 void
0596 NewGameDlg::slotNewMap()
0597 {
0598     // Clear map, player and planet lists
0599     m_game->map()->clearMap();
0600 
0601     m_game->map()->resizeMap(m_w->heightSB->value(), m_w->widthSB->value());
0602 
0603     // make sure we have space for neutrals
0604     int maxneutrals = m_w->heightSB->value()*m_w->widthSB->value() - m_game->players().count();
0605     if(m_w->neutralPlanetsSB->value() > maxneutrals) {
0606         disconnect(m_w->neutralPlanetsSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotNewMap);
0607         m_w->neutralPlanetsSB->setValue(maxneutrals);
0608         connect(m_w->neutralPlanetsSB, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &NewGameDlg::slotNewMap);
0609     }
0610 
0611     // make the planets
0612     m_game->map()->populateMap(m_game->players(), m_neutral, m_w->neutralPlanetsSB->value());
0613 
0614     slotUpdateSelection(m_w->map->selection());
0615 
0616     updateButtonOk();
0617 }
0618 
0619 
0620 void
0621 NewGameDlg::slotUpdateNeutrals(int count)
0622 {
0623     while(m_game->map()->playerPlanetCount(m_neutral) < count
0624           && m_game->map()->addNeutralPlanetSomewhere(m_neutral)) ;
0625 
0626     while(m_game->map()->playerPlanetCount(m_neutral) > count
0627           && m_game->map()->removePlayerPlanet(m_neutral)) ;
0628 
0629     if(m_w->map->hasSelection())
0630         slotUpdateSelection(m_w->map->selection());
0631 }
0632 
0633 
0634 /**
0635  * Enable the "ok" button if the game settings are sane.
0636  */
0637 
0638 void
0639 NewGameDlg::updateButtonOk()
0640 {
0641     int nonSpectatorCount = 0;
0642     bool isSaneConfiguration = true;
0643 
0644     for (Player *player : m_game->players()) {
0645         if (player->isSpectator()) {
0646 
0647             // Spectator player controllers can be completely ignored here as
0648             // they do not count as active players and thus there is no need for
0649             // them to own at least one planet.
0650 
0651             continue;
0652         }
0653 
0654         ++nonSpectatorCount;
0655 
0656         bool foundPlanet = false;
0657 
0658         for (Planet *planet : m_game->planets()) {
0659             if (planet->player() == player) {
0660                 foundPlanet = true;
0661                 break;
0662             }
0663         }
0664 
0665         if (!foundPlanet) {
0666             isSaneConfiguration = false;
0667             break;
0668         }
0669     }
0670 
0671     okButton->setEnabled(
0672         (nonSpectatorCount >= 2) &&
0673         isSaneConfiguration
0674     );
0675 }