File indexing completed on 2024-07-21 06:44:29

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