GCI2012: Subscribe for Network
authorkoda
Mon, 14 Jan 2013 12:07:51 +0100
changeset 8380 0b375a3ceaa0
parent 8379 6a446b7cece0 (diff)
parent 8367 2506ed09f4be (current diff)
child 8381 588a8e6e2041
GCI2012: Subscribe for Network
QTfrontend/hwform.cpp
--- a/QTfrontend/hedgewars.qrc	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/hedgewars.qrc	Mon Jan 14 12:07:51 2013 +0100
@@ -103,6 +103,7 @@
         <file>res/iconRope.png</file>
         <file>res/dice.png</file>
         <file>res/Star.png</file>
+        <file>res/inverse-corner-bl.png</file>
         <file>res/Flake.png</file>
         <file>res/Egg.png</file>
         <file>res/Confetti.png</file>
@@ -130,6 +131,7 @@
         <file>res/StatsMostSelfDamage.png</file>
         <file>res/StatsSelfKilled.png</file>
         <file>res/StatsSkipped.png</file>
+        <file>res/Start.png</file>
         <file>res/mapRandom.png</file>
         <file>res/mapMaze.png</file>
         <file>res/mapMissing.png</file>
--- a/QTfrontend/hwform.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/hwform.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -1716,7 +1716,7 @@
 
 void HWForm::NetGameChangeStatus(bool isMaster)
 {
-    ui.pageNetGame->pGameCFG->setEnabled(isMaster);
+    ui.pageNetGame->pGameCFG->setMaster(isMaster);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(isMaster);
 
     if (isMaster)
@@ -1731,7 +1731,7 @@
     ui.pageNetGame->restrictJoins->setChecked(false);
     ui.pageNetGame->restrictTeamAdds->setChecked(false);
     ui.pageNetGame->pGameCFG->GameSchemes->setModel(ammoSchemeModel);
-    ui.pageNetGame->pGameCFG->setEnabled(true);
+    ui.pageNetGame->pGameCFG->setMaster(true);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(true);
 
     if (hwnet)
@@ -1759,7 +1759,7 @@
 
 void HWForm::NetGameSlave()
 {
-    ui.pageNetGame->pGameCFG->setEnabled(false);
+    ui.pageNetGame->pGameCFG->setMaster(false);
     ui.pageNetGame->pNetTeamsWidget->setInteractivity(false);
 
     if (hwnet)
--- a/QTfrontend/model/HatModel.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/HatModel.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -26,26 +26,28 @@
 #include <QDir>
 #include <QPixmap>
 #include <QPainter>
+#include <QList>
 #include "hwform.h" // player hash
 
 #include "DataManager.h"
 
 HatModel::HatModel(QObject* parent) :
-    QAbstractListModel(parent)
-{
-    hats = QVector<QPair<QString, QIcon> >();
-}
+    QStandardItemModel(parent)
+{}
 
 void HatModel::loadHats()
 {
     // this method resets the contents of this model (important to know for views).
-    beginResetModel();
+    QStandardItemModel::beginResetModel();
+    QStandardItemModel::clear();
 
-    // prepare hats Vector
-    hats.clear();
+    // New hats to add to model
+    QList<QStandardItem *> hats;
 
+    // we'll need the DataManager a few times, so let's get a reference to it
     DataManager & dataMgr = DataManager::instance();
 
+    // Default hat icon
     QPixmap hhpix = QPixmap("physfs://Graphics/Hedgehog/Idle.png").copy(0, 0, 32, 32);
 
     // my reserved hats
@@ -54,7 +56,6 @@
                                QDir::Files,
                                QStringList(playerHash+"*.png")
                            );
-
     int nReserved = hatsList.size();
 
     // regular hats
@@ -64,14 +65,15 @@
                         QStringList("*.png")
                     )
                    );
-
-
     int nHats = hatsList.size();
 
+    // Add each hat
     for (int i = 0; i < nHats; i++)
     {
         bool isReserved = (i < nReserved);
 
+        if (isReserved) continue; // For some reason, reserved hats were added in 9.19-dev, so this will hide them. Uncomment to show them.
+
         QString str = hatsList.at(i);
         str = str.remove(QRegExp("\\.png$"));
         QPixmap pix(            
@@ -94,51 +96,11 @@
         painter.end();
 
         if (str == "NoHat")
-            hats.prepend(qMakePair(str, QIcon(tmppix)));
+            hats.prepend(new QStandardItem(QIcon(tmppix), str));
         else
-            hats.append(qMakePair(str, QIcon(tmppix)));
+            hats.append(new QStandardItem(QIcon(tmppix), str));
     }
 
-
-    endResetModel();
-}
-
-QVariant HatModel::headerData(int section,
-                               Qt::Orientation orientation, int role) const
-{
-    Q_UNUSED(section);
-    Q_UNUSED(orientation);
-    Q_UNUSED(role);
-
-    return QVariant();
-}
-
-int HatModel::rowCount(const QModelIndex &parent) const
-{
-    if (parent.isValid())
-        return 0;
-    else
-        return hats.size();
-}
-
-/*int HatModel::columnCount(const QModelIndex & parent) const
-{
-    if (parent.isValid())
-        return 0;
-    else
-        return 2;
-}
-*/
-QVariant HatModel::data(const QModelIndex &index,
-                         int role) const
-{
-    if (!index.isValid() || index.row() < 0
-            || index.row() >= hats.size()
-            || (role != Qt::DisplayRole && role != Qt::DecorationRole))
-        return QVariant();
-
-    if (role == Qt::DisplayRole)
-        return hats.at(index.row()).first;
-    else // role == Qt::DecorationRole
-        return hats.at(index.row()).second;
-}
+    QStandardItemModel::appendColumn(hats);
+    QStandardItemModel::endResetModel();
+}
\ No newline at end of file
--- a/QTfrontend/model/HatModel.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/HatModel.h	Mon Jan 14 12:07:51 2013 +0100
@@ -24,30 +24,22 @@
 #ifndef HEDGEWARS_HATMODEL_H
 #define HEDGEWARS_HATMODEL_H
 
-#include <QAbstractListModel>
+#include <QStandardItemModel>
 #include <QStringList>
 #include <QVector>
 #include <QPair>
 #include <QIcon>
 
-class HatModel : public QAbstractListModel
+class HatModel : public QStandardItemModel
 {
         Q_OBJECT
 
     public:
         HatModel(QObject *parent = 0);
 
-        QVariant headerData(int section, Qt::Orientation orientation, int role) const;
-        int rowCount(const QModelIndex & parent) const;
-        //int columnCount(const QModelIndex & parent) const;
-
     public slots:
         /// Reloads hats using the DataManager.
         void loadHats();
-
-        QVariant data(const QModelIndex &index, int role) const;
-    protected:
-        QVector<QPair<QString, QIcon> > hats;
 };
 
 #endif // HEDGEWARS_HATMODEL_H
--- a/QTfrontend/model/MapModel.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/MapModel.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -22,9 +22,15 @@
  */
 
 #include "MapModel.h"
+#include "hwapplication.h"
 
+#include <QSettings>
 
-void MapModel::loadMaps()
+MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""};
+MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", ""};
+
+void MapModel::loadMaps(MapType maptype)
 {
     // this method resets the contents of this model (important to know for views).
     beginResetModel();
@@ -39,19 +45,9 @@
     // empty list, so that we can (re)fill it
     QStandardItemModel::clear();
 
-    QList<QStandardItem *> genMaps;
-    QList<QStandardItem *> missionMaps;
-    QList<QStandardItem *> staticMaps;
-
-    // add generated/handdrawn maps to list
-    // TODO: icons for these
-
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("generated map..."), GeneratedMap, "+rnd+"));
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("generated maze..."), GeneratedMaze, "+maze+"));
-    genMaps.append(
-        infoToItem(QIcon(), QComboBox::tr("hand drawn map..."), HandDrawnMap, "+drawn+"));
+    //QList<QStandardItem *> staticMaps;
+    //QList<QStandardItem *> missionMaps;
+    QList<QStandardItem *> mapList;
 
     // only 2 map relate files are relevant:
     // - the cfg file that contains the settings/info of the map
@@ -64,7 +60,7 @@
     {
         mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map));
         mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map));
-
+        QSettings descSettings(QString("physfs://Maps/%1/desc.txt").arg(map), QSettings::IniFormat);
 
         if (mapCfgFile.open(QFile::ReadOnly))
         {
@@ -73,25 +69,36 @@
             quint32 limit = 0;
             QString scheme;
             QString weapons;
+            QString desc;
+
             // if there is a lua file for this map, then it's a mission
             bool isMission = mapLuaFile.exists();
-            MapType type = isMission?MissionMap:StaticMap;
+            MapType type = isMission ? MissionMap : StaticMap;
+
+            // If we're supposed to ignore this type, continue
+            if (type != maptype) continue;
 
             // load map info from file
             QTextStream input(&mapCfgFile);
-            input >> theme;
-            input >> limit;
+            theme = input.readLine();
+            limit = input.readLine().toInt();
             if (isMission) { // scheme and weapons are only relevant for missions
-                input >> scheme;
-                input >> weapons;
+                scheme = input.readLine();
+                weapons = input.readLine();
             }
             mapCfgFile.close();
 
+            // Load description (if applicable)
+            if (isMission)
+            {
+                QString locale = HWApplication::keyboardInputLocale().name();
+                desc = descSettings.value(locale, QString()).toString().replace("|", "\n");
+            }
+
             // let's use some semi-sane hedgehog limit, rather than none
             if (limit == 0)
                 limit = 18;
 
-
             // the default scheme/weaponset for missions.
             // if empty we assume the map sets these internally -> locked
             if (isMission)
@@ -107,97 +114,54 @@
                     weapons.replace("_", " ");
             }
 
-            // add a mission caption prefix to missions
-            if (isMission)
-            {
-                // TODO: icon
-                caption = QComboBox::tr("Mission") + ": " + map;
-            }
-            else
-                caption = map;
+            // caption
+            caption = map;
 
             // we know everything there is about the map, let's get am item for it
-            QStandardItem * item = infoToItem(
-                QIcon(), caption, type, map, theme, limit, scheme, weapons);
+            QStandardItem * item = MapModel::infoToItem(
+                QIcon(), caption, type, map, theme, limit, scheme, weapons, desc);
 
             // append item to the list
-            if (isMission)
-                missionMaps.append(item);
-            else
-                staticMaps.append(item);
-        
+            mapList.append(item);
         }
 
     }
 
-
-    // define a separator item
-    QStandardItem separator("---");
-    separator.setData(QLatin1String("separator"), Qt::AccessibleDescriptionRole);
-    separator.setFlags(separator.flags() & ~( Qt::ItemIsEnabled | Qt::ItemIsSelectable ) );
-
-    // create list:
-    // generated+handdrawn maps, 2 saperators, missions, 1 separator, static maps
-    QList<QStandardItem * > items;
-    items.append(genMaps);
-    items.append(separator.clone());
-    items.append(separator.clone());
-    items.append(missionMaps);
-    items.append(separator.clone());
-    items.append(staticMaps);
-
-
-    // create row-index lookup table
+    // Create column-index lookup table
 
     m_mapIndexes.clear();
 
-    int count = items.size();
 
+    int count = mapList.size();
     for (int i = 0; i < count; i++)
     {
-        QStandardItem * si = items.at(i);
+        QStandardItem * si = mapList.at(i);
         QVariant v = si->data(Qt::UserRole + 1);
         if (v.canConvert<MapInfo>())
             m_mapIndexes.insert(v.value<MapInfo>().name, i);
     }
 
-
-    // store start-index and count of relevant types
-
-    m_typeLoc.insert(GeneratedMap, QPair<int,int>(0, 1));
-    m_typeLoc.insert(GeneratedMaze, QPair<int,int>(1, 1));
-    m_typeLoc.insert(HandDrawnMap, QPair<int,int>(2, 1));
-    // mission maps
-    int startIdx = genMaps.size() + 2; // start after genMaps and 2 separators
-    count = missionMaps.size();
-    m_typeLoc.insert(MissionMap, QPair<int,int>(startIdx, count));
-    // static maps
-    startIdx += count + 1; // start after missions and 2 separators
-    count = staticMaps.size();
-    m_typeLoc.insert(StaticMap, QPair<int,int>(startIdx, count));
-
-    // store list contents in the item model
-    QStandardItemModel::appendColumn(items);
-
+    QStandardItemModel::appendColumn(mapList);
 
     endResetModel();
 }
 
-
-int MapModel::randomMap(MapType type) const
+bool MapModel::mapExists(const QString & map) const
 {
-    // return a random index for this type or -1 if none available
-    QPair<int,int> loc = m_typeLoc.value(type, QPair<int,int>(-1,0));
-
-    int startIdx = loc.first;
-    int count = loc.second;
-
-    if (count < 1)
-        return -1;
-    else
-        return startIdx + (rand() % count);
+    return findMap(map) >= 0;
 }
 
+int MapModel::findMap(const QString & map) const
+{
+    return m_mapIndexes.value(map, -1);
+}
+
+QStandardItem * MapModel::getMap(const QString & map)
+{
+    int loc = findMap(map);
+    if (loc < 0) return NULL;
+    return item(loc);
+}
 
 QStandardItem * MapModel::infoToItem(
     const QIcon & icon,
@@ -207,8 +171,8 @@
     QString theme,
     quint32 limit,
     QString scheme,
-    QString weapons)
-const
+    QString weapons,
+    QString desc)
 {
     QStandardItem * item = new QStandardItem(icon, caption);
     MapInfo mapInfo;
@@ -220,17 +184,10 @@
     mapInfo.limit = limit;
     mapInfo.scheme = scheme;
     mapInfo.weapons = weapons;
-
+    mapInfo.desc = desc.isEmpty() ? tr("No description available.") : desc;
 
     qvar.setValue(mapInfo);
     item->setData(qvar, Qt::UserRole + 1);
 
     return item;
 }
-
-
-int MapModel::indexOf(const QString & map) const
-{
-    return m_mapIndexes.value(map, -1);
-}
-
--- a/QTfrontend/model/MapModel.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/MapModel.h	Mon Jan 14 12:07:51 2013 +0100
@@ -63,32 +63,49 @@
             quint32 limit; ///< The maximum allowed number of hedgehogs.
             QString scheme; ///< Default scheme name or "locked", for mission-maps.
             QString weapons; ///< Default weaponset name or "locked", for missions-maps.
+            QString desc; ///< The brief 1-2 sentence description of the mission, for mission-maps.
         };
 
         /**
-         * @brief Returns the row-index of the given map.
-         * @param map map of which to get the row-index of.
-         * @return row-index of map or -1 if not available.
+         * @brief Searches maps in model to find out if one exists
+         * @param map map of which to check existence
+         * @return true if it exists
          */
-        int indexOf(const QString & map) const;
+        bool mapExists(const QString & map) const;
+
+        /**
+         * @brief Finds a map index (column, row) for a map name
+         * @param map map of which to find index+column
+         * @return QPair<int, int> with column, index, or (-1, -1) if map not found
+         */
+        //QPair<int, int> findMap(const QString & map) const;
 
         /**
-         * @brief Returns the row-index of a random map with a specified type.
-         * @param type desired type of map.
-         * @return row-index of a map with the desired type, -1 if none found.
+         * @brief Finds a map index for a map name
+         * @param map map of which to find index
+         * @return int of index, or -1 if map not found
          */
-        int randomMap(MapType type) const;
+        int findMap(const QString & map) const;
+
+        /**
+         * @brief Finds and returns a map item for a map name
+         * @param map map
+         * @return QStandardItem of map, or NULL if map not found
+         */
+        QStandardItem * getMap(const QString & map);
+
+        // Static MapInfos for drawn and generated maps
+        static MapInfo MapInfoRandom, MapInfoMaze, MapInfoDrawn;
 
     public slots:
         /// Reloads the maps using the DataManager.
-        void loadMaps();
+        /// Accepts two map types: StaticMap or MissionMap.
+        void loadMaps(MapType maptype);
 
 
     private:
-        /// start-index and map count for each map-type.
-        QMap<MapType, QPair<int,int> > m_typeLoc;
-
-        /// map index lookup table
+        /// map index lookup table. QPair<int, int> contains: <column, index>
+        //QHash<QString, QPair<int, int> > m_mapIndexes;
         QHash<QString, int> m_mapIndexes;
 
         /**
@@ -102,9 +119,10 @@
          * @param limit the hedgehog limit of the map.
          * @param scheme mission map: default scheme name or "locked".
          * @param weapons mission map: default weaponset name or "locked".
+         * @param desc mission map: description of mission.
          * @return pointer to item representing the map info: at Qt::UserRole + 1.
          */
-        QStandardItem * infoToItem(
+        static QStandardItem * infoToItem(
             const QIcon & icon,
             const QString caption,
             MapType type = Invalid,
@@ -112,7 +130,8 @@
             QString theme = "",
             quint32 limit = 0,
             QString scheme = "",
-            QString weapons = "") const;
+            QString weapons = "",
+            QString desc = "");
 };
 
 Q_DECLARE_METATYPE(MapModel::MapInfo)
--- a/QTfrontend/model/ThemeModel.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/ThemeModel.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -73,11 +73,16 @@
 
         QMap<int, QVariant> dataset;
 
+        // set icon path
+        dataset.insert(Qt::UserRole + 1, iconpath);
+
         // set name
         dataset.insert(Qt::DisplayRole, theme);
 
         // load and set icon
-        QIcon icon(iconpath);
+        QIcon icon;
+        icon.addPixmap(QPixmap(iconpath), QIcon::Normal);
+        icon.addPixmap(QPixmap(iconpath), QIcon::Disabled);
 
         dataset.insert(Qt::DecorationRole, icon);
 
--- a/QTfrontend/model/roomslistmodel.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/roomslistmodel.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -43,7 +43,8 @@
      << tr("Rules")
      << tr("Weapons");
 
-    m_mapModel = DataManager::instance().mapModel();
+    m_staticMapModel = DataManager::instance().staticMapModel();
+    m_missionMapModel = DataManager::instance().missionMapModel();
 }
 
 
@@ -134,7 +135,8 @@
             }
 
             // prefix ? if map not available
-            if ((m_mapModel->indexOf(content) < 0))
+            if (!m_staticMapModel->mapExists(content) &&
+                !m_missionMapModel->mapExists(content))
                 return QString ("? %1").arg(content);
         }
 
@@ -144,10 +146,14 @@
     // dye map names red if map not available
     if (role == Qt::ForegroundRole)
     {
-        if ((m_mapModel->indexOf(content) < 0))
+        if (content == "+rnd+" ||
+            content == "+maze+" ||
+            content == "+drawn+" ||
+            m_staticMapModel->mapExists(content) ||
+            m_missionMapModel->mapExists(content))
+            return QVariant();
+        else
             return QBrush(QColor("darkred"));
-        else
-            return QVariant();
     }
 
     if (role == Qt::TextAlignmentRole)
--- a/QTfrontend/model/roomslistmodel.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/model/roomslistmodel.h	Mon Jan 14 12:07:51 2013 +0100
@@ -64,7 +64,8 @@
     const int c_nColumns;
     QList<QStringList> m_data;
     QStringList m_headerData;
-    MapModel * m_mapModel;
+    MapModel * m_staticMapModel;
+    MapModel * m_missionMapModel;
 
     QStringList roomInfo2RoomRecord(const QStringList & info);
 };
Binary file QTfrontend/res/Start.png has changed
--- a/QTfrontend/res/css/qt.css	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/res/css/qt.css	Mon Jan 14 12:07:51 2013 +0100
@@ -45,7 +45,7 @@
 QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit,
 QComboBox QAbstractItemView, IconedGroupBox,
 .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget,
-QTabWidget::pane, QTabBar::tab {
+QTabWidget::pane, QTabBar::tab, #mapPreview {
 border: solid;
 border-width: 3px;
 border-color: #ffcc00;
@@ -56,8 +56,20 @@
 border-color: yellow;
 }
 
+QToolButton {
+background-color: #11084A;
+}
+
+QToolButton:hover {
+background-color: #150A61;
+}
+
+QToolButton:pressed {
+background-color: #100744;
+}
+
 QLineEdit, QListWidget, QListView, QTableView, QTextBrowser,
-QSpinBox, QToolBox, QPlainTextEdit {
+QSpinBox, QToolBox, QPlainTextEdit, QToolButton, #mapPreview {
 border-radius: 10px;
 }
 
@@ -97,7 +109,7 @@
 background-color: rgba(18, 42, 5, 70%);
 }
 
-QPushButton:pressed{
+QPushButton:pressed, QToolButton:pressed {
 border-color: white;
 }
 
@@ -246,3 +258,42 @@
 width: 8px;
 }
 
+HatButton {
+text-align: left;
+}
+
+#hatList, #hatList:hover {
+border-color: #F6CB1C;
+}
+
+#hatList QScrollBar {
+background-color: #130F2A;
+border-top-right-radius: 10px;
+border-bottom-right-radius: 10px;
+}
+
+#hatList {
+border-color: #F6CB1C;
+border-width: 3px;
+border-style: solid;
+border-radius: 10px;
+border-top-left-radius: 0px;
+}
+
+#hatList::item {
+background-color: #11084A;
+padding: 4px;
+border-radius: 10px;
+color: #ffcc00 !important;
+font: 8px;
+border-width: 2px;
+border-color: #11084A;
+}
+
+#hatList::item:hover {
+background-color: #150A61;
+}
+
+#hatList::item:selected {
+background-color: #150A61;
+}
\ No newline at end of file
Binary file QTfrontend/res/inverse-corner-bl.png has changed
--- a/QTfrontend/ui/page/AbstractPage.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/AbstractPage.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -41,9 +41,10 @@
     QGridLayout * pageLayout = new QGridLayout(this);
 
     // stretch grid space for body and footer
-    pageLayout->setColumnStretch(0,1);
-    pageLayout->setColumnStretch(1,2);
+    pageLayout->setColumnStretch(0,0);
+    pageLayout->setColumnStretch(1,0);
     pageLayout->setColumnStretch(2,1);
+    pageLayout->setColumnStretch(3,0);
     pageLayout->setRowStretch(0,1);
     pageLayout->setRowStretch(1,0);
 
@@ -53,7 +54,12 @@
     pageLayout->addWidget(btnBack, 1, 0, 1, 1, Qt::AlignLeft | Qt::AlignBottom);
 
     // add body layout as defined by the subclass
-    pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 3);
+    pageLayout->addLayout(bodyLayoutDefinition(), 0, 0, 1, 4);
+
+    // add left footer layout
+    QLayout * flld = footerLayoutLeftDefinition();
+    if (flld != NULL)
+        pageLayout->addLayout(flld, 1, 1);
 
     descLabel = new QLabel();
     descLabel->setAlignment(Qt::AlignCenter);
@@ -61,12 +67,12 @@
     descLabel->setOpenExternalLinks(true);
     descLabel->setFixedHeight(50);
     descLabel->setStyleSheet("font-size: 16px");
-    pageLayout->addWidget(descLabel, 1, 1);
+    pageLayout->addWidget(descLabel, 1, 2);
 
     // add footer layout
     QLayout * fld = footerLayoutDefinition();
     if (fld != NULL)
-        pageLayout->addLayout(fld, 1, 2);
+        pageLayout->addLayout(fld, 1, 3);
 
     // connect signals
     connect(btnBack, SIGNAL(clicked()), this, SIGNAL(goBack()));
--- a/QTfrontend/ui/page/AbstractPage.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/AbstractPage.h	Mon Jan 14 12:07:51 2013 +0100
@@ -121,6 +121,17 @@
          * @brief Used during page construction.
          * You can implement this method in your subclass.
          *
+         * Use it to define layout (not behavior) of the page's footer to the left of the help text.
+         */
+        virtual QLayout * footerLayoutLeftDefinition()
+        {
+            return NULL;
+        };
+
+        /**
+         * @brief Used during page construction.
+         * You can implement this method in your subclass.
+         *
          * This is a good place to connect signals within your page in order
          * to get the desired page behavior.<br />
          * Keep in mind not to expose twidgets as public!
--- a/QTfrontend/ui/page/pageeditteam.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pageeditteam.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -33,7 +33,7 @@
 #include "keybinder.h"
 
 #include "DataManager.h"
-#include "HatModel.h"
+#include "hatbutton.h"
 
 #include "pageeditteam.h"
 
@@ -64,25 +64,32 @@
 
     HatModel * hatModel = DataManager::instance().hatModel();
 
+    GBHLayout->addWidget(new QLabel(tr("Hat")), 0, 0);
+    GBHLayout->addWidget(new QLabel(tr("Name")), 0, 1);
+
     for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
     {
-        HHHats[i] = new QComboBox(GBoxHedgehogs);
-        HHHats[i]->setModel(hatModel);
-        HHHats[i]->setIconSize(QSize(32, 37));
-        //HHHats[i]->setSizeAdjustPolicy(QComboBox::AdjustToContents);
-        //HHHats[i]->setModelColumn(1);
-        //HHHats[i]->setMinimumWidth(132);
-        GBHLayout->addWidget(HHHats[i], i, 0);
+        HHHats[i] = new HatButton(GBoxHedgehogs);
+        GBHLayout->addWidget(HHHats[i], i + 1, 0);
 
         HHNameEdit[i] = new QLineEdit(GBoxHedgehogs);
         HHNameEdit[i]->setMaxLength(64);
         HHNameEdit[i]->setMinimumWidth(120);
-        GBHLayout->addWidget(HHNameEdit[i], i, 1);
+        HHNameEdit[i]->setFixedHeight(36);
+        HHNameEdit[i]->setWhatsThis(tr("This hedgehog's name"));
+        HHNameEdit[i]->setStyleSheet("padding: 6px;");
+        GBHLayout->addWidget(HHNameEdit[i], i + 1, 1);
 
-        btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i, 3, 1, 1, true);
+        btnRandomHogName[i] = addButton(":/res/dice.png", GBHLayout, i + 1, 3, 1, 1, true);
+        btnRandomHogName[i]->setFixedHeight(HHNameEdit[i]->height());
+        btnRandomHogName[i]->setWhatsThis(tr("Randomize this hedgehog's name"));
     }
 
-    btnRandomTeam = addButton(QPushButton::tr("Random Team"), GBHLayout, 9, 0);
+    btnRandomTeam = new QPushButton();
+    btnRandomTeam->setText(tr("Random Team"));
+    btnRandomTeam->setStyleSheet("padding: 6px 10px;");
+    GBHLayout->addWidget(btnRandomTeam, 9, 0, 1, 4, Qt::AlignCenter);
+    btnRandomTeam->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
     vbox1->addWidget(GBoxHedgehogs);
 
@@ -377,7 +384,7 @@
         if (hh.Hat.startsWith("Reserved"))
             hh.Hat = "Reserved "+hh.Hat.remove(0,40);
 
-        HHHats[i]->setCurrentIndex(HHHats[i]->findData(hh.Hat, Qt::DisplayRole));
+        HHHats[i]->setCurrentHat(hh.Hat);
     }
 
     CBGrave->setCurrentIndex(CBGrave->findText(team.grave()));
@@ -409,7 +416,7 @@
     {
         HWHog hh;
         hh.Name = HHNameEdit[i]->text();
-        hh.Hat = HHHats[i]->currentText();
+        hh.Hat = HHHats[i]->currentHat();
 
         if (hh.Hat.startsWith("Reserved"))
             hh.Hat = "Reserved"+m_playerHash+hh.Hat.remove(0,9);
--- a/QTfrontend/ui/page/pageeditteam.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pageeditteam.h	Mon Jan 14 12:07:51 2013 +0100
@@ -29,6 +29,7 @@
 
 class SquareLabel;
 class KeyBinder;
+class HatButton;
 
 class PageEditTeam : public AbstractPage
 {
@@ -61,7 +62,7 @@
         QToolBox *BindsBox;
         QLineEdit * TeamNameEdit;
         QLineEdit * HHNameEdit[HEDGEHOGS_PER_TEAM];
-        QComboBox * HHHats[HEDGEHOGS_PER_TEAM];
+        HatButton * HHHats[HEDGEHOGS_PER_TEAM];
         HWTeam data();
         QString m_playerHash;
         KeyBinder * binder;
--- a/QTfrontend/ui/page/pagemultiplayer.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pagemultiplayer.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -36,10 +36,6 @@
     gameCFG = new GameCFGWidget(this);
     pageLayout->addWidget(gameCFG, 0, 0, 1, 2);
 
-    btnSetup = new QPushButton(this);
-    btnSetup->setText(QPushButton::tr("Setup"));
-    pageLayout->addWidget(btnSetup, 1, 0, 1, 2);
-
     pageLayout->setRowStretch(2, 1);
 
     teamsSelect = new TeamSelWidget(this);
@@ -48,12 +44,30 @@
     return pageLayout;
 }
 
+QLayout * PageMultiplayer::footerLayoutLeftDefinition()
+{
+    QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+    
+    btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+    btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+    return bottomLeftLayout;
+}
+
 QLayout * PageMultiplayer::footerLayoutDefinition()
 {
     QHBoxLayout * footerLayout = new QHBoxLayout();
 
-    BtnStartMPGame = formattedButton(tr("Start"));
-    BtnStartMPGame->setMinimumWidth(180);
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    BtnStartMPGame = new QPushButton();
+    BtnStartMPGame->setText(tr("Start"));
+    BtnStartMPGame->setMinimumWidth(sz.width() + 60);
+    BtnStartMPGame->setIcon(lp);
+    BtnStartMPGame->setFixedHeight(50);
+    BtnStartMPGame->setIconSize(sz);
+    BtnStartMPGame->setFlat(true);
+    BtnStartMPGame->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
     footerLayout->addStretch();
     footerLayout->addWidget(BtnStartMPGame);
--- a/QTfrontend/ui/page/pagemultiplayer.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pagemultiplayer.h	Mon Jan 14 12:07:51 2013 +0100
@@ -41,6 +41,7 @@
     private:
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
+        QLayout * footerLayoutLeftDefinition();
         void connectSignals();
 
         QPushButton * btnSetup;
--- a/QTfrontend/ui/page/pagenetgame.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pagenetgame.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -40,24 +40,31 @@
     chatWidget = new HWChatWidget(this, true);
     chatWidget->setShowFollow(false); // don't show follow in nicks' context menus
     chatWidget->setIgnoreListKick(true); // kick ignored players automatically
-    pageLayout->addWidget(chatWidget, 2, 0, 1, 2);
-    pageLayout->setRowStretch(1, 100);
-    pageLayout->setRowStretch(2, 100);
+    pageLayout->addWidget(chatWidget, 1, 0, 1, 2);
+    pageLayout->setRowStretch(0, 0);
+    pageLayout->setRowStretch(1, 0);
 
     pGameCFG = new GameCFGWidget(this);
     pageLayout->addWidget(pGameCFG, 0, 0);
 
-    btnSetup = new QPushButton(this);
-    btnSetup->setText(QPushButton::tr("Setup"));
-    pageLayout->addWidget(btnSetup, 1, 0);
-
     pNetTeamsWidget = new TeamSelWidget(this);
     pNetTeamsWidget->setAcceptOuter(true);
-    pageLayout->addWidget(pNetTeamsWidget, 0, 1, 2, 1);
+    pNetTeamsWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+    pageLayout->addWidget(pNetTeamsWidget, 0, 1, 1, 1);
 
     return pageLayout;
 }
 
+QLayout * PageNetGame::footerLayoutLeftDefinition()
+{
+    QHBoxLayout * bottomLeftLayout = new QHBoxLayout();
+    
+    btnSetup = addButton(":/res/Settings.png", bottomLeftLayout, 0, true);
+    btnSetup->setWhatsThis(tr("Edit game preferences"));
+
+    return bottomLeftLayout;
+}
+
 QLayout * PageNetGame::footerLayoutDefinition()
 {
     QHBoxLayout * bottomLayout = new QHBoxLayout;
@@ -84,7 +91,17 @@
     BtnMaster = addButton(tr("Control"), bottomLayout, 3);
     bottomLayout->insertStretch(3, 100);
 
-    BtnStart = addButton(QAction::tr("Start"), bottomLayout, 3);
+    const QIcon& lp = QIcon(":/res/Start.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    BtnStart = new QPushButton();
+    BtnStart->setText(tr("Start"));
+    BtnStart->setMinimumWidth(sz.width() + 60);
+    BtnStart->setIcon(lp);
+    BtnStart->setFixedHeight(50);
+    BtnStart->setIconSize(sz);
+    BtnStart->setFlat(true);
+    BtnStart->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    bottomLayout->addWidget(BtnStart);
 
     return bottomLayout;
 }
--- a/QTfrontend/ui/page/pagenetgame.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/page/pagenetgame.h	Mon Jan 14 12:07:51 2013 +0100
@@ -70,6 +70,7 @@
     private:
         QLayout * bodyLayoutDefinition();
         QLayout * footerLayoutDefinition();
+        QLayout * footerLayoutLeftDefinition();
         void connectSignals();
 
         HistoryLineEdit * leRoomName;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/flowlayout.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,190 @@
+ /****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * Redistributions in binary form must reproduce the above copyright
+ **     notice, this list of conditions and the following disclaimer in
+ **     the documentation and/or other materials provided with the
+ **     distribution.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+ #include <QtGui>
+
+ #include "flowlayout.h"
+ 
+ FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
+     : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
+ {
+     setContentsMargins(margin, margin, margin, margin);
+ }
+
+ FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
+     : m_hSpace(hSpacing), m_vSpace(vSpacing)
+ {
+     setContentsMargins(margin, margin, margin, margin);
+ }
+
+ FlowLayout::~FlowLayout()
+ {
+     QLayoutItem *item;
+     while ((item = takeAt(0)))
+         delete item;
+ }
+
+ void FlowLayout::addItem(QLayoutItem *item)
+ {
+     itemList.append(item);
+ }
+
+ int FlowLayout::horizontalSpacing() const
+ {
+     if (m_hSpace >= 0) {
+         return m_hSpace;
+     } else {
+         return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
+     }
+ }
+
+ int FlowLayout::verticalSpacing() const
+ {
+     if (m_vSpace >= 0) {
+         return m_vSpace;
+     } else {
+         return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
+     }
+ }
+
+ int FlowLayout::count() const
+ {
+     return itemList.size();
+ }
+
+ QLayoutItem *FlowLayout::itemAt(int index) const
+ {
+     return itemList.value(index);
+ }
+
+ QLayoutItem *FlowLayout::takeAt(int index)
+ {
+     if (index >= 0 && index < itemList.size())
+         return itemList.takeAt(index);
+     else
+         return 0;
+ }
+
+ Qt::Orientations FlowLayout::expandingDirections() const
+ {
+     return 0;
+ }
+
+ bool FlowLayout::hasHeightForWidth() const
+ {
+     return true;
+ }
+
+ int FlowLayout::heightForWidth(int width) const
+ {
+     int height = doLayout(QRect(0, 0, width, 0), true);
+     return height;
+ }
+
+ void FlowLayout::setGeometry(const QRect &rect)
+ {
+     QLayout::setGeometry(rect);
+     doLayout(rect, false);
+ }
+
+ QSize FlowLayout::sizeHint() const
+ {
+     return minimumSize();
+ }
+
+ QSize FlowLayout::minimumSize() const
+ {
+     QSize size;
+     QLayoutItem *item;
+     foreach (item, itemList)
+         size = size.expandedTo(item->minimumSize());
+
+     size += QSize(2*margin(), 2*margin());
+     return size;
+ }
+
+ int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
+ {
+     int left, top, right, bottom;
+     getContentsMargins(&left, &top, &right, &bottom);
+     QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
+     int x = effectiveRect.x();
+     int y = effectiveRect.y();
+     int lineHeight = 0;
+
+     QLayoutItem *item;
+     foreach (item, itemList) {
+         QWidget *wid = item->widget();
+         int spaceX = horizontalSpacing();
+         if (spaceX == -1)
+             spaceX = wid->style()->layoutSpacing(
+                 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
+         int spaceY = verticalSpacing();
+         if (spaceY == -1)
+             spaceY = wid->style()->layoutSpacing(
+                 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
+         int nextX = x + item->sizeHint().width() + spaceX;
+         if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
+             x = effectiveRect.x();
+             y = y + lineHeight + spaceY;
+             nextX = x + item->sizeHint().width() + spaceX;
+             lineHeight = 0;
+         }
+
+         if (!testOnly)
+             item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
+
+         x = nextX;
+         lineHeight = qMax(lineHeight, item->sizeHint().height());
+     }
+     return y + lineHeight - rect.y() + bottom;
+ }
+ int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
+ {
+     QObject *parent = this->parent();
+     if (!parent) {
+         return -1;
+     } else if (parent->isWidgetType()) {
+         QWidget *pw = static_cast<QWidget *>(parent);
+         return pw->style()->pixelMetric(pm, 0, pw);
+     } else {
+         return static_cast<QLayout *>(parent)->spacing();
+     }
+ }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/flowlayout.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,77 @@
+ /****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the examples of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** You may use this file under the terms of the BSD license as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ **   * Redistributions of source code must retain the above copyright
+ **     notice, this list of conditions and the following disclaimer.
+ **   * Redistributions in binary form must reproduce the above copyright
+ **     notice, this list of conditions and the following disclaimer in
+ **     the documentation and/or other materials provided with the
+ **     distribution.
+ **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+ **     the names of its contributors may be used to endorse or promote
+ **     products derived from this software without specific prior written
+ **     permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+ #ifndef FLOWLAYOUT_H
+ #define FLOWLAYOUT_H
+
+ #include <QLayout>
+ #include <QRect>
+ #include <QStyle>
+ #include <QWidgetItem>
+ class FlowLayout : public QLayout
+ {
+ public:
+     FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
+     FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
+     ~FlowLayout();
+
+     void addItem(QLayoutItem *item);
+     int horizontalSpacing() const;
+     int verticalSpacing() const;
+     Qt::Orientations expandingDirections() const;
+     bool hasHeightForWidth() const;
+     int heightForWidth(int) const;
+     int count() const;
+     QLayoutItem *itemAt(int index) const;
+     QSize minimumSize() const;
+     void setGeometry(const QRect &rect);
+     QSize sizeHint() const;
+     QLayoutItem *takeAt(int index);
+
+ private:
+     int doLayout(const QRect &rect, bool testOnly) const;
+     int smartSpacing(QStyle::PixelMetric pm) const;
+
+     QList<QLayoutItem *> itemList;
+     int m_hSpace;
+     int m_vSpace;
+ };
+
+ #endif
\ No newline at end of file
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -25,6 +25,8 @@
 #include <QMessageBox>
 #include <QTableView>
 #include <QPushButton>
+#include <QDebug>
+#include <QList>
 
 #include "gamecfgwidget.h"
 #include "igbox.h"
@@ -33,6 +35,7 @@
 #include "ammoSchemeModel.h"
 #include "proto.h"
 #include "GameStyleModel.h"
+#include "themeprompt.h"
 
 GameCFGWidget::GameCFGWidget(QWidget* parent) :
     QGroupBox(parent)
@@ -40,13 +43,16 @@
     , seedRegexp("\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\}")
 {
     mainLayout.setMargin(0);
-//  mainLayout.setSizeConstraint(QLayout::SetMinimumSize);
 
     pMapContainer = new HWMapContainer(this);
-    mainLayout.addWidget(pMapContainer, 0, 0);
+    mainLayout.addWidget(pMapContainer, 0, 0, Qt::AlignHCenter | Qt::AlignTop);
+    pMapContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    pMapContainer->setFixedSize(460, 275);
 
     IconedGroupBox *GBoxOptions = new IconedGroupBox(this);
-    GBoxOptions->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+    m_childWidgets << GBoxOptions;
+    GBoxOptions->setFixedWidth(pMapContainer->width());
+    GBoxOptions->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
     mainLayout.addWidget(GBoxOptions, 1, 0);
 
     QGridLayout *GBoxOptionsLayout = new QGridLayout(GBoxOptions);
@@ -174,7 +180,7 @@
     if (schemeData(18).toBool())
         result |= 0x00080000;       // ai survival
     if (schemeData(19).toBool())
-        result |= 0x00100000;       // infinite attacks
+        result |= 0x00100000;       // infinite attacks 
     if (schemeData(20).toBool())
         result |= 0x00200000;       // reset weaps
     if (schemeData(21).toBool())
@@ -186,7 +192,7 @@
     if (schemeData(24).toBool())
         result |= 0x02000000;       // tag team
     if (schemeData(25).toBool())
-        result |= 0x04000000;       // bottom border
+        result |= 0x04000000;       // bottom
 
     return result;
 }
@@ -235,6 +241,8 @@
     bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8();
     bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
 
+
+
     switch (mapgen)
     {
         case MAPGEN_MAZE:
@@ -271,7 +279,7 @@
     bool illegal = ammo.size() != cDefaultAmmoStore->size();
     if (illegal)
     {
-        QMessageBox illegalMsg(this);
+        QMessageBox illegalMsg(parentWidget());
         illegalMsg.setIcon(QMessageBox::Warning);
         illegalMsg.setWindowTitle(QMessageBox::tr("Error"));
         illegalMsg.setText(QMessageBox::tr("Cannot use the ammo '%1'!").arg(name));
@@ -325,10 +333,6 @@
         if (param == "SEED")
         {
             pMapContainer->setSeed(value);
-            if (!seedRegexp.exactMatch(value))
-            {
-                pMapContainer->seedEdit->setVisible(true);
-            }
             return;
         }
         if (param == "THEME")
@@ -377,8 +381,6 @@
         if (param == "FULLMAPCONFIG")
         {
             QString seed = slValue[3];
-            if (!seedRegexp.exactMatch(seed))
-                pMapContainer->seedEdit->setVisible(true);
 
             pMapContainer->setAllMapParameters(
                 slValue[0],
@@ -586,3 +588,19 @@
             Scripts->setCurrentIndex(0);
     }
 }
+
+bool GameCFGWidget::isMaster()
+{
+    return m_master;
+}
+
+void GameCFGWidget::setMaster(bool master)
+{
+    if (master == m_master) return;
+    m_master = master;
+
+    pMapContainer->setMaster(master);
+
+    foreach (QWidget *widget, m_childWidgets)
+        widget->setEnabled(master);
+}
--- a/QTfrontend/ui/widget/gamecfgwidget.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/widget/gamecfgwidget.h	Mon Jan 14 12:07:51 2013 +0100
@@ -36,6 +36,8 @@
 {
         Q_OBJECT
 
+        Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
     public:
         GameCFGWidget(QWidget* parent);
         quint32 getGameFlags() const;
@@ -47,11 +49,13 @@
         HWMapContainer* pMapContainer;
         QTableView * tv;
         QVariant schemeData(int column) const;
+        bool isMaster();
 
     public slots:
         void setParam(const QString & param, const QStringList & value);
         void fullNetConfig();
         void resendSchemeData();
+        void setMaster(bool master);
 
     signals:
         void paramChanged(const QString & param, const QStringList & value);
@@ -81,6 +85,8 @@
         QString curNetAmmo;
         QRegExp seedRegexp;
         QString m_curScript;
+        bool m_master;
+        QList<QWidget *> m_childWidgets;
 
         void setNetAmmo(const QString& name, const QString& ammo);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatbutton.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,72 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDebug>
+
+#include "hatprompt.h"
+#include "DataManager.h"
+#include "HatModel.h"
+#include "hatbutton.h"
+
+HatButton::HatButton(QWidget* parent) : QPushButton(parent)
+{
+	setIconSize(QSize(32, 37));
+	setFixedSize(44, 44);
+
+	m_hatModel = DataManager::instance().hatModel();
+	connect(this, SIGNAL(clicked()), this, SLOT(showPrompt()));
+
+	setCurrentIndex(0);
+}
+
+void HatButton::setCurrentIndex(int index)
+{
+	m_hat = m_hatModel->index(index, 0);
+	setWhatsThis(QString(tr("Change hat (%1)")).arg(m_hat.data(Qt::DisplayRole).toString()));
+	setToolTip(m_hat.data(Qt::DisplayRole).toString());
+	setIcon(m_hat.data(Qt::DecorationRole).value<QIcon>());
+}
+
+int HatButton::currentIndex()
+{
+	return m_hat.row();
+}
+
+void HatButton::setCurrentHat(const QString & name)
+{
+	QList<QStandardItem *> hats = m_hatModel->findItems(name);
+
+	if (hats.count() > 0)
+		setCurrentIndex(hats[0]->row());
+}
+
+QString HatButton::currentHat() const
+{
+	return m_hat.data(Qt::DisplayRole).toString();
+}
+
+void HatButton::showPrompt()
+{
+	HatPrompt prompt(currentIndex(), this);
+	int hatID = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
+	if (hatID < 0) return;
+
+	setCurrentIndex(hatID);
+	emit currentIndexChanged(hatID);
+	emit currentHatChanged(currentHat());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatbutton.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,55 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef HATBUTTON_H
+#define HATBUTTON_H
+
+#include <QPushButton>
+#include <QString>
+#include <QModelIndex>
+
+class HatModel;
+
+class HatButton : public QPushButton
+{
+        Q_OBJECT
+        Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex)
+        Q_PROPERTY(QString currentHat READ currentHat WRITE setCurrentHat)
+
+    public:
+        HatButton(QWidget* parent);
+        int currentIndex();
+        QString currentHat() const;
+
+    private:
+    	QModelIndex m_hat;
+    	HatModel * m_hatModel;
+
+    signals:
+    	void currentIndexChanged(int);
+    	void currentHatChanged(const QString &);
+
+    public slots:
+    	void setCurrentIndex(int index);
+    	void setCurrentHat(const QString & name);
+
+    private slots:
+        void showPrompt();
+};
+
+#endif // HATBUTTON_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatprompt.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,169 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDialog>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QScrollArea>
+#include <QPushButton>
+#include <QToolButton>
+#include <QWidgetItem>
+#include <QModelIndex>
+#include <QListView>
+#include <QLineEdit>
+#include <QLabel>
+#include <QSortFilterProxyModel>
+#include <QDebug>
+
+#include "DataManager.h"
+#include "lineeditcursor.h"
+#include "HatModel.h"
+#include "hatprompt.h"
+
+HatPrompt::HatPrompt(int currentIndex, QWidget* parent) : QDialog(parent)
+{
+	setModal(true);
+	setWindowFlags(Qt::Sheet);
+	setWindowModality(Qt::WindowModal);
+	setMinimumSize(550, 430);
+	resize(550, 430);
+	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+	setStyleSheet("QPushButton { padding: 5px; margin-top: 10px; }");
+
+	// Hat model, and a model for setting a filter
+	HatModel * hatModel = DataManager::instance().hatModel();
+	filterModel = new QSortFilterProxyModel();
+	filterModel->setSourceModel(hatModel);
+	filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+	// Grid
+	QGridLayout * dialogLayout = new QGridLayout(this);
+	dialogLayout->setSpacing(0);
+	dialogLayout->setColumnStretch(1, 1);
+
+	QHBoxLayout * topLayout = new QHBoxLayout();
+
+	// Help/prompt message at top
+	QLabel * lblDesc = new QLabel(tr("Select a hat"));
+	lblDesc->setObjectName("lblDesc");
+    lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
+    lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    lblDesc->setFixedHeight(24);
+    lblDesc->setMinimumWidth(0);
+
+    // Filter text box
+    QWidget * filterContainer = new QWidget();
+    filterContainer->setFixedHeight(24);
+    filterContainer->setObjectName("filterContainer");
+    filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+    filterContainer->setFixedWidth(250);
+    txtFilter = new LineEditCursor(filterContainer);
+    txtFilter->setFixedWidth(250);
+    txtFilter->setFocus();
+    txtFilter->setFixedHeight(22);
+    connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
+    connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
+    connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
+    connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
+    connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
+
+    // Filter label
+    QLabel * lblFilter = new QLabel(tr("Filter: "), txtFilter);
+    lblFilter->setStyleSheet(QString("background: none; margin-left: -%1px; margin-top: 4px;").arg(lblFilter->width() / 2 - 3));
+    txtFilter->setStyleSheet(QString("border-width: 0px; background-color: rgb(13, 5, 68); border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: %1px; padding-bottom: 2px;").arg(lblFilter->width() / 2));
+
+    // Corner widget
+    QLabel * corner = new QLabel();
+    corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+    corner->setFixedSize(10, 10);
+
+    // Add widgets to top layout
+    topLayout->addWidget(lblDesc);
+    topLayout->addWidget(filterContainer);
+    topLayout->addWidget(corner, 0, Qt::AlignBottom);
+    topLayout->addStretch(1);
+
+	// Cancel button (closes dialog)
+	QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+	connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+	// Select button
+	QPushButton * btnSelect = new QPushButton(tr("Use selected hat"));
+	btnSelect->setDefault(true);
+	connect(btnSelect, SIGNAL(clicked()), this, SLOT(onAccepted()));
+
+	// Add hats
+	list = new HatListView();
+	list->setModel(filterModel);
+	list->setViewMode(QListView::IconMode);
+	list->setResizeMode(QListView::Adjust);
+	list->setMovement(QListView::Static);
+	list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+	list->setSpacing(8);
+	list->setWordWrap(true);
+	list->setSelectionMode(QAbstractItemView::SingleSelection);
+	list->setObjectName("hatList");
+	list->setCurrentIndex(filterModel->index(currentIndex, 0));
+	connect(list, SIGNAL(activated(const QModelIndex &)), this, SLOT(hatChosen(const QModelIndex &)));
+	connect(list, SIGNAL(clicked(const QModelIndex &)), this, SLOT(hatChosen(const QModelIndex &)));
+
+	// Add elements to layouts
+	dialogLayout->addLayout(topLayout, 0, 0, 1, 3);
+	dialogLayout->addWidget(list, 1, 0, 1, 3);
+	dialogLayout->addWidget(btnCancel, 2, 0, 1, 1, Qt::AlignLeft);
+	dialogLayout->addWidget(btnSelect, 2, 2, 1, 1, Qt::AlignRight);
+}
+
+void HatPrompt::moveUp()
+{
+	list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
+
+void HatPrompt::moveDown()
+{
+	list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void HatPrompt::moveLeft()
+{
+	list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void HatPrompt::moveRight()
+{
+	list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
+void HatPrompt::onAccepted()
+{
+	hatChosen(list->currentIndex());
+}
+
+// When a hat is selected
+void HatPrompt::hatChosen(const QModelIndex & index)
+{
+	done(filterModel->mapToSource(index).row() + 1); // Since returning 0 means canceled
+}
+
+// When the text in the filter text box is changed
+void HatPrompt::filterChanged(const QString & text)
+{
+	filterModel->setFilterFixedString(text);
+	list->setCurrentIndex(filterModel->index(0, 0));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/hatprompt.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef HATPROMPT_H
+#define HATPROMPT_H
+
+#include <QWidget>
+#include <QDialog>
+#include <QListView>
+
+class QLineEdit;
+class QModelIndex;
+class QSortFilterProxyModel;
+class LineEditCursor;
+
+class HatListView : public QListView
+{
+	friend class HatPrompt;
+
+	public:
+		HatListView(QWidget* parent = 0) {};
+};
+
+class HatPrompt : public QDialog
+{
+        Q_OBJECT
+
+    public:
+        HatPrompt(int currentIndex = 0, QWidget* parent = 0);
+
+    private:
+        LineEditCursor * txtFilter;
+        HatListView * list;
+        QSortFilterProxyModel * filterModel;
+
+    private slots:
+    	void onAccepted();
+        void hatChosen(const QModelIndex & index);
+        void filterChanged(const QString & text);
+        void moveUp();
+        void moveDown();
+        void moveLeft();
+        void moveRight();
+};
+
+#endif // HATPROMPT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/lineeditcursor.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QKeyEvent>
+
+#include "lineeditcursor.h"
+
+void LineEditCursor::keyPressEvent(QKeyEvent * event)
+{
+	if (event->key() == Qt::Key_Up)
+		emit moveUp();
+	else if (event->key() == Qt::Key_Down)
+		emit moveDown();
+	else if (event->key() == Qt::Key_Left)
+		emit moveLeft();
+	else if (event->key() == Qt::Key_Right)
+		emit moveRight();
+	else
+		QLineEdit::keyPressEvent(event);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/lineeditcursor.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,41 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef LINEEDITCURSOR_H
+#define LINEEDITCURSOR_H
+
+#include <QLineEdit>
+
+class LineEditCursor : public QLineEdit
+{
+        Q_OBJECT
+
+    public:
+        LineEditCursor(QWidget* parent = 0) : QLineEdit(parent) {};
+
+    signals:
+        void moveUp();
+        void moveDown();
+        void moveLeft();
+        void moveRight();
+
+    private:
+        void keyPressEvent(QKeyEvent * event);
+};
+
+#endif // LINEEDITCURSOR_H
\ No newline at end of file
--- a/QTfrontend/ui/widget/mapContainer.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/widget/mapContainer.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -30,13 +30,24 @@
 #include <QIcon>
 #include <QLineEdit>
 #include <QStringListModel>
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QDebug>
+#include <QFile>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QMessageBox>
 
 #include "hwconsts.h"
 #include "mapContainer.h"
+#include "themeprompt.h"
+#include "seedprompt.h"
 #include "igbox.h"
 #include "HWApplication.h"
 #include "ThemeModel.h"
 
+
+
 HWMapContainer::HWMapContainer(QWidget * parent) :
     QWidget(parent),
     mainLayout(this),
@@ -47,6 +58,7 @@
     hhSmall.load(":/res/hh_small.png");
     hhLimit = 18;
     templateFilter = 0;
+    m_master = true;
 
     linearGrad = QLinearGradient(QPoint(128, 0), QPoint(128, 128));
     linearGrad.setColorAt(1, QColor(0, 0, 192));
@@ -57,135 +69,192 @@
                                   HWApplication::style()->pixelMetric(QStyle::PM_LayoutRightMargin),
                                   HWApplication::style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
 
-    QWidget* mapWidget = new QWidget(this);
-    mainLayout.addWidget(mapWidget, 0, 0, Qt::AlignHCenter);
-
-    QGridLayout* mapLayout = new QGridLayout(mapWidget);
-    mapLayout->setMargin(0);
+    m_staticMapModel = DataManager::instance().staticMapModel();
+    m_missionMapModel = DataManager::instance().missionMapModel();
+    m_themeModel = DataManager::instance().themeModel();
 
-    imageButt = new QPushButton(mapWidget);
-    imageButt->setObjectName("imageButt");
-    imageButt->setFixedSize(256 + 6, 128 + 6);
-    imageButt->setFlat(true);
-    imageButt->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);//QSizePolicy::Minimum, QSizePolicy::Minimum);
-    mapLayout->addWidget(imageButt, 0, 0, 1, 2);
-    connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomMap()));
+    /* Layouts */
 
-    chooseMap = new QComboBox(mapWidget);
-    chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-    m_mapModel = DataManager::instance().mapModel();
-    chooseMap->setEditable(false);
-    chooseMap->setModel(m_mapModel);
+    QHBoxLayout * typeLayout = new QHBoxLayout();
+    QHBoxLayout * seedLayout = new QHBoxLayout();
+    QHBoxLayout * twoColumnLayout = new QHBoxLayout();
+    QVBoxLayout * leftLayout = new QVBoxLayout();
+    QVBoxLayout * rightLayout = new QVBoxLayout();
+    twoColumnLayout->addLayout(leftLayout, 0);
+    twoColumnLayout->addStretch(1);
+    twoColumnLayout->addLayout(rightLayout, 0);
+    QVBoxLayout * drawnControls = new QVBoxLayout();
+    leftLayout->addLayout(typeLayout, 0);
+    rightLayout->addLayout(seedLayout, 0);
+
+    /* Map type combobox */
 
-    mapLayout->addWidget(chooseMap, 1, 1);
+    typeLayout->setSpacing(10);
+    typeLayout->addWidget(new QLabel(tr("Map type:")), 0);
+    cType = new QComboBox(this);
+    typeLayout->addWidget(cType, 1);
+    cType->insertItem(0, tr("Image map"), MapModel::StaticMap);
+    cType->insertItem(1, tr("Mission map"), MapModel::MissionMap);
+    cType->insertItem(2, tr("Hand-drawn"), MapModel::HandDrawnMap);
+    cType->insertItem(3, tr("Randomly generated"), MapModel::GeneratedMap);
+    cType->insertItem(4, tr("Random maze"), MapModel::GeneratedMaze);
+    connect(cType, SIGNAL(currentIndexChanged(int)), this, SLOT(mapTypeChanged(int)));
+    m_childWidgets << cType;
 
-    QLabel * lblMap = new QLabel(tr("Map"), mapWidget);
-    mapLayout->addWidget(lblMap, 1, 0);
-
-    lblFilter = new QLabel(tr("Filter"), mapWidget);
-    mapLayout->addWidget(lblFilter, 2, 0);
+    /* Randomize button */
 
-    cbTemplateFilter = new QComboBox(mapWidget);
-    cbTemplateFilter->addItem(tr("All"), 0);
-    cbTemplateFilter->addItem(tr("Small"), 1);
-    cbTemplateFilter->addItem(tr("Medium"), 2);
-    cbTemplateFilter->addItem(tr("Large"), 3);
-    cbTemplateFilter->addItem(tr("Cavern"), 4);
-    cbTemplateFilter->addItem(tr("Wacky"), 5);
-    mapLayout->addWidget(cbTemplateFilter, 2, 1);
+    seedLayout->addStretch(1);
+    const QIcon& lp = QIcon(":/res/dice.png");
+    QSize sz = lp.actualSize(QSize(65535, 65535));
+    btnRandomize = new QPushButton();
+    btnRandomize->setText(tr("Random"));
+    btnRandomize->setIcon(lp);
+    btnRandomize->setFixedHeight(30);
+    btnRandomize->setIconSize(sz);
+    btnRandomize->setFlat(true);
+    btnRandomize->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    connect(btnRandomize, SIGNAL(clicked()), this, SLOT(setRandomMap()));
+    m_childWidgets << btnRandomize;
+    btnRandomize->setStyleSheet("padding: 5px;");
+    btnRandomize->setFixedHeight(cType->height());
+    seedLayout->addWidget(btnRandomize, 1);
 
-    connect(cbTemplateFilter, SIGNAL(activated(int)), this, SLOT(setTemplateFilter(int)));
+    /* Seed button */
+    btnSeed = new QPushButton(parentWidget()->parentWidget());
+    btnSeed->setText(tr("Seed"));
+    btnSeed->setStyleSheet("padding: 5px;");
+    btnSeed->setFixedHeight(cType->height());
+    connect(btnSeed, SIGNAL(clicked()), this, SLOT(showSeedPrompt()));
+    seedLayout->addWidget(btnSeed, 0);
 
-    maze_size_label = new QLabel(tr("Type"), mapWidget);
-    mapLayout->addWidget(maze_size_label, 2, 0);
-    maze_size_label->hide();
-    cbMazeSize = new QComboBox(mapWidget);
-    cbMazeSize->addItem(tr("Small tunnels"), 0);
-    cbMazeSize->addItem(tr("Medium tunnels"), 1);
-    cbMazeSize->addItem(tr("Large tunnels"), 2);
-    cbMazeSize->addItem(tr("Small floating islands"), 3);
-    cbMazeSize->addItem(tr("Medium floating islands"), 4);
-    cbMazeSize->addItem(tr("Large floating islands"), 5);
-    cbMazeSize->setCurrentIndex(1);
+    /* Map preview label */
+
+    QLabel * lblMapPreviewText = new QLabel(this);
+    lblMapPreviewText->setText(tr("Map preview:"));
+    leftLayout->addWidget(lblMapPreviewText, 0, Qt::AlignLeft);
+
+    /* Map Preview */
 
-    mapLayout->addWidget(cbMazeSize, 2, 1);
-    cbMazeSize->hide();
-    connect(cbMazeSize, SIGNAL(activated(int)), this, SLOT(setMazeSize(int)));
+    mapPreview = new QLabel(this);
+    mapPreview->setObjectName("mapPreview");
+    mapPreview->setFixedSize(256, 128);
+    leftLayout->addWidget(mapPreview, 0);
+
+    /* Bottom-Left layout */
 
-    gbThemes = new IconedGroupBox(mapWidget);
-    gbThemes->setTitleTextPadding(80);
-    gbThemes->setContentTopPadding(15);
-    gbThemes->setTitle(tr("Themes"));
+    QVBoxLayout * bottomLeftLayout = new QVBoxLayout();
+    leftLayout->addLayout(bottomLeftLayout, 1);
+
+    /* Map list label */
+
+    lblMapList = new QLabel();
+    rightLayout->addWidget(lblMapList, 0);
+
+    /* Static maps list */
 
-    //gbThemes->setStyleSheet("padding: 0px"); // doesn't work - stylesheet is set with icon
-    mapLayout->addWidget(gbThemes, 0, 2, 3, 1);
-    // disallow row to be collapsed (so it can't get ignored when Qt applies rowSpan of gbThemes)
-    mapLayout->setRowMinimumHeight(2, 13);
-    QVBoxLayout * gbTLayout = new QVBoxLayout(gbThemes);
-    gbTLayout->setContentsMargins(0, 0, 0 ,0);
-    gbTLayout->setSpacing(0);
-    lvThemes = new QListView(mapWidget);
-    lvThemes->setMinimumHeight(30);
-    lvThemes->setFixedWidth(140);
-    m_themeModel = DataManager::instance().themeModel();
-    lvThemes->setModel(m_themeModel);
-    lvThemes->setIconSize(QSize(16, 16));
-    lvThemes->setEditTriggers(QListView::NoEditTriggers);
+    staticMapList = new QListView;
+    staticMapList->setModel(m_staticMapModel);
+    rightLayout->addWidget(staticMapList, 1);
+    staticMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    m_childWidgets << staticMapList;
+    QItemSelectionModel * staticSelectionModel = staticMapList->selectionModel();
+    connect(staticSelectionModel,
+            SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+            this,
+            SLOT(staticMapChanged(const QModelIndex &, const QModelIndex &)));
 
-    connect(lvThemes->selectionModel(), SIGNAL(currentRowChanged( const QModelIndex &, const QModelIndex &)), this, SLOT(themeSelected( const QModelIndex &, const QModelIndex &)));
+    /* Mission maps list */
 
-    // override default style to tighten up theme scroller
-    lvThemes->setStyleSheet(QString(
-                                "QListView{"
-                                "border: solid;"
-                                "border-width: 0px;"
-                                "border-radius: 0px;"
-                                "border-color: transparent;"
-                                "background-color: #0d0544;"
-                                "color: #ffcc00;"
-                                "font: bold 13px;"
-                                "}"
-                            )
-                           );
+    missionMapList = new QListView;
+    missionMapList->setModel(m_missionMapModel);
+    missionMapList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    rightLayout->addWidget(missionMapList, 1);
+    m_childWidgets << missionMapList;
+    QItemSelectionModel * missionSelectionModel = missionMapList->selectionModel();
+    connect(missionSelectionModel,
+            SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)),
+            this,
+            SLOT(missionMapChanged(const QModelIndex &, const QModelIndex &)));
+
+    /* Map load and edit buttons */
+
+    drawnControls->addStretch(1);
 
-    gbTLayout->addWidget(lvThemes);
-    lvThemes->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum);
+    btnLoadMap = new QPushButton(tr("Load map drawing"));
+    btnLoadMap->setStyleSheet("padding: 20px;");
+    drawnControls->addWidget(btnLoadMap, 0);
+    m_childWidgets << btnLoadMap;
+    connect(btnLoadMap, SIGNAL(clicked()), this, SLOT(loadDrawing()));
+
+    btnEditMap = new QPushButton(tr("Edit map drawing"));
+    btnEditMap->setStyleSheet("padding: 20px;");
+    drawnControls->addWidget(btnEditMap, 0);
+    m_childWidgets << btnEditMap;
+    connect(btnEditMap, SIGNAL(clicked()), this, SIGNAL(drawMapRequested()));
+
+    drawnControls->addStretch(1);
+
+    rightLayout->addLayout(drawnControls);
+
+    /* Generator style list */
 
-    mapLayout->setSizeConstraint(QLayout::SetFixedSize);
+    generationStyles = new QListWidget();
+    new QListWidgetItem(tr("All"), generationStyles);
+    new QListWidgetItem(tr("Small"), generationStyles);
+    new QListWidgetItem(tr("Medium"), generationStyles);
+    new QListWidgetItem(tr("Large"), generationStyles);
+    new QListWidgetItem(tr("Cavern"), generationStyles);
+    new QListWidgetItem(tr("Wacky"), generationStyles);
+    connect(generationStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setTemplateFilter(int)));
+    m_childWidgets << generationStyles;
+    rightLayout->addWidget(generationStyles, 1);
+
+    /* Maze style list */
 
-    QWidget* seedWidget = new QWidget(this);
-    mainLayout.addWidget(seedWidget, 1, 0);
+    mazeStyles = new QListWidget();
+    new QListWidgetItem(tr("Small tunnels"), mazeStyles);
+    new QListWidgetItem(tr("Medium tunnels"), mazeStyles);
+    new QListWidgetItem(tr("Largetunnels"), mazeStyles);
+    new QListWidgetItem(tr("Small islands"), mazeStyles);
+    new QListWidgetItem(tr("Medium islands"), mazeStyles);
+    new QListWidgetItem(tr("Large islands"), mazeStyles);
+    connect(mazeStyles, SIGNAL(currentRowChanged(int)), this, SLOT(setMazeSize(int)));
+    m_childWidgets << mazeStyles;
+    rightLayout->addWidget(mazeStyles, 1);
 
-    QGridLayout* seedLayout = new QGridLayout(seedWidget);
-    seedLayout->setMargin(0);
+    /* Mission description */
 
-    seedLabel = new QLabel(tr("Seed"), seedWidget);
-    seedLayout->addWidget(seedLabel, 3, 0);
-    seedEdit = new QLineEdit(seedWidget);
-    seedEdit->setMaxLength(54);
-    connect(seedEdit, SIGNAL(returnPressed()), this, SLOT(seedEdited()));
-    seedLayout->addWidget(seedEdit, 3, 1);
-    seedLayout->setColumnStretch(1, 5);
-    seedSet = new QPushButton(seedWidget);
-    seedSet->setText(QPushButton::tr("more"));
-    connect(seedSet, SIGNAL(clicked()), this, SLOT(seedEdited()));
-    seedLayout->setColumnStretch(2, 1);
-    seedLayout->addWidget(seedSet, 3, 2);
+    lblDesc = new QLabel();
+    lblDesc->setWordWrap(true);
+    lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    lblDesc->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    bottomLeftLayout->addWidget(lblDesc, 100);
+
+    /* Spacing above theme chooser */
+
+    bottomLeftLayout->addStretch(1);
+
+    /* Theme chooser */
 
-    seedLabel->setVisible(false);
-    seedEdit->setVisible(false);
+    btnTheme = new QPushButton();
+    connect(btnTheme, SIGNAL(clicked()), this, SLOT(showThemePrompt()));
+    m_childWidgets << btnTheme;
+    bottomLeftLayout->addWidget(btnTheme, 1);
 
-    setRandomSeed();
-    setRandomTheme();
+    /* Add everything to main layout */
+
+    mainLayout.addLayout(twoColumnLayout, 0);
 
-    chooseMap->setCurrentIndex(0);
-    mapChanged(0);
-    // use signal "activated" rather than currentIndexChanged
-    // because index is somtimes changed a few times in a row programmatically
-    connect(chooseMap, SIGNAL(activated(int)), this, SLOT(mapChanged(int)));
+    /* Set defaults */
 
-    // update model views after model changes (to e.g. re-adjust separators)
-    connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(updateModelViews()));
+    setRandomTheme();
+    setRandomSeed();
+    setMazeSize(0);
+    setTemplateFilter(0);
+    staticMapChanged(m_staticMapModel->index(0, 0));
+    missionMapChanged(m_missionMapModel->index(0, 0));
+    updateTheme(m_themeModel->index(0, 0));
+    mapTypeChanged(0);
 }
 
 void HWMapContainer::setImage(const QImage newImage)
@@ -202,8 +271,9 @@
     p.drawPixmap(QPoint(0, 0), px);
 
     addInfoToPreview(pxres);
-    //chooseMap->setCurrentIndex(mapgen);
     pMap = 0;
+
+    cType->setEnabled(isMaster());
 }
 
 void HWMapContainer::setHHLimit(int newHHLimit)
@@ -211,70 +281,6 @@
     hhLimit = newHHLimit;
 }
 
-void HWMapContainer::mapChanged(int index)
-{
-    if (chooseMap->currentIndex() != index)
-        chooseMap->setCurrentIndex(index);
-
-    if (index < 0)
-    {
-        m_mapInfo.type = MapModel::Invalid;
-        updatePreview();
-        return;
-    }
-
-    Q_ASSERT(chooseMap->itemData(index, Qt::UserRole + 1).canConvert<MapModel::MapInfo>());
-    m_mapInfo = chooseMap->itemData(index, Qt::UserRole + 1).value<MapModel::MapInfo>();
-    m_curMap = m_mapInfo.name;
-
-    switch(m_mapInfo.type)
-    {
-        case MapModel::GeneratedMap:
-            mapgen = MAPGEN_REGULAR;
-            gbThemes->show();
-            lblFilter->show();
-            cbTemplateFilter->show();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            break;
-        case MapModel::GeneratedMaze:
-            mapgen = MAPGEN_MAZE;
-            gbThemes->show();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->show();
-            cbMazeSize->show();
-            break;
-        case MapModel::HandDrawnMap:
-            mapgen = MAPGEN_DRAWN;
-            gbThemes->show();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            break;
-        default:
-            mapgen = MAPGEN_MAP;
-            gbThemes->hide();
-            lblFilter->hide();
-            cbTemplateFilter->hide();
-            maze_size_label->hide();
-            cbMazeSize->hide();
-            m_theme = m_mapInfo.theme;
-    }
-
-    // the map has no pre-defined theme, so let's use the selected one
-    if (m_mapInfo.theme.isEmpty())
-    {
-        m_theme = lvThemes->currentIndex().data().toString();
-        emit themeChanged(m_theme);
-    }
-
-    updatePreview();
-    emit mapChanged(m_curMap);
-    emit mapgenChanged(mapgen);
-}
-
 // Should this add text to identify map size?
 void HWMapContainer::addInfoToPreview(QPixmap image)
 {
@@ -292,8 +298,7 @@
     p.drawText(image.rect().width() - hhSmall.rect().width() - 14 - (hhLimit > 9 ? 10 : 0), 18, text);
     p.drawPixmap(image.rect().width() - hhSmall.rect().width() - 5, 5, hhSmall.rect().width(), hhSmall.rect().height(), hhSmall);
 
-    imageButt->setIcon(finalImage);
-    imageButt->setIconSize(image.size());
+    mapPreview->setPixmap(finalImage);
 }
 
 void HWMapContainer::askForGeneratedPreview()
@@ -322,14 +327,8 @@
     p.drawPixmap(QPoint(x, y), waitIcon);
 
     addInfoToPreview(waitImage);
-}
 
-void HWMapContainer::themeSelected(const QModelIndex & current, const QModelIndex &)
-{
-    m_theme = current.data().toString();
-
-    gbThemes->setIcon(qVariantValue<QIcon>(current.data(Qt::UserRole)));
-    emit themeChanged(m_theme);
+    cType->setEnabled(false);
 }
 
 QString HWMapContainer::getCurrentSeed() const
@@ -339,8 +338,14 @@
 
 QString HWMapContainer::getCurrentMap() const
 {
-    if(chooseMap->currentIndex() < MAPGEN_MAP) return QString();
-    return(m_curMap);
+    switch (m_mapInfo.type)
+    {
+        case MapModel::StaticMap:
+        case MapModel::MissionMap:
+            return m_curMap;
+        default:
+            return QString();
+    }
 }
 
 QString HWMapContainer::getCurrentTheme() const
@@ -370,20 +375,17 @@
 
 quint32 HWMapContainer::getTemplateFilter() const
 {
-    return cbTemplateFilter->itemData(cbTemplateFilter->currentIndex()).toInt();
+    return generationStyles->currentRow();
 }
 
 void HWMapContainer::resizeEvent ( QResizeEvent * event )
 {
     Q_UNUSED(event);
-    //imageButt->setIconSize(imageButt->size());
 }
 
 void HWMapContainer::intSetSeed(const QString & seed)
 {
     m_seed = seed;
-    if (seed != seedEdit->text())
-        seedEdit->setText(seed);
 }
 
 void HWMapContainer::setSeed(const QString & seed)
@@ -395,11 +397,29 @@
 
 void HWMapContainer::intSetMap(const QString & map)
 {
-    m_curMap = map;
-
-    int id = m_mapModel->indexOf(map);
-
-    mapChanged(id);
+    if (map == "+rnd+")
+    {
+        changeMapType(MapModel::GeneratedMap);
+    }
+    else if (map == "+maze+")
+    {
+        changeMapType(MapModel::GeneratedMaze);
+    }
+    else if (map == "+drawn+")
+    {
+        changeMapType(MapModel::HandDrawnMap);
+    }
+    else if (m_staticMapModel->mapExists(map))
+    {
+        changeMapType(MapModel::StaticMap, m_staticMapModel->index(m_staticMapModel->findMap(map), 0));
+    }
+    else if (m_missionMapModel->mapExists(map))
+    {
+        changeMapType(MapModel::MissionMap, m_missionMapModel->index(m_missionMapModel->findMap(map), 0));
+    } else
+    {
+        qDebug() << "HWMapContainer::intSetMap: Map doesn't exist: " << map;
+    }
 }
 
 void HWMapContainer::setMap(const QString & map)
@@ -413,13 +433,11 @@
     QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, theme);
 
     if(mdl.size())
-        lvThemes->setCurrentIndex(mdl.at(0));
+        updateTheme(mdl.at(0));
 }
 
 void HWMapContainer::setRandomMap()
 {
-    int idx;
-
     setRandomSeed();
     switch(m_mapInfo.type)
     {
@@ -427,17 +445,14 @@
         case MapModel::GeneratedMaze:
             setRandomTheme();
             break;
-        case MapModel::HandDrawnMap:
-            emit drawMapRequested();
+        case MapModel::MissionMap:
+            missionMapChanged(m_missionMapModel->index(rand() % m_missionMapModel->rowCount(), 0));
             break;
-        case MapModel::MissionMap:
         case MapModel::StaticMap:
-            // get random map of same type
-            idx = m_mapModel->randomMap(m_mapInfo.type);
-            mapChanged(idx);
+            staticMapChanged(m_staticMapModel->index(rand() % m_staticMapModel->rowCount(), 0));
             break;
-        case MapModel::Invalid:
-            mapChanged(0);
+        default:
+            break;
     }
 }
 
@@ -452,12 +467,12 @@
 {
     if(!m_themeModel->rowCount()) return;
     quint32 themeNum = rand() % m_themeModel->rowCount();
-    lvThemes->setCurrentIndex(m_themeModel->index(themeNum));
+    updateTheme(m_themeModel->index(themeNum));
 }
 
 void HWMapContainer::intSetTemplateFilter(int filter)
 {
-    cbTemplateFilter->setCurrentIndex(filter);
+    generationStyles->setCurrentRow(filter);
     emit newTemplateFilter(filter);
 }
 
@@ -475,12 +490,12 @@
 
 int HWMapContainer::getMazeSize(void) const
 {
-    return cbMazeSize->currentIndex();
+    return mazeStyles->currentRow();
 }
 
 void HWMapContainer::intSetMazeSize(int size)
 {
-    cbMazeSize->setCurrentIndex(size);
+    mazeStyles->setCurrentRow(size);
     emit mazeSizeChanged(size);
 }
 
@@ -521,9 +536,6 @@
                 break;
         }
 
-        if(m != MAPGEN_MAP)
-            chooseMap->setCurrentIndex(m);
-
         emit mapgenChanged(m);
     }
 }
@@ -546,23 +558,10 @@
     return drawMapScene.encode();
 }
 
-void HWMapContainer::seedEdited()
+void HWMapContainer::setNewSeed(const QString & newSeed)
 {
-    if (seedLabel->isVisible() == false )
-    {
-        seedLabel->setVisible(true);
-        seedEdit->setVisible(true);
-        seedSet->setText(tr("Set"));
-        return;
-    }
-
-    if (seedEdit->text().isEmpty())
-        seedEdit->setText(m_seed);
-    else
-    {
-        setSeed(seedEdit->text());
-        emit seedChanged(seedEdit->text());
-    }
+    setSeed(newSeed);
+    emit seedChanged(newSeed);
 }
 
 DrawMapScene * HWMapContainer::getDrawMapScene()
@@ -592,8 +591,7 @@
     {
         case MapModel::Invalid:
             failIcon = QPixmap(":/res/btnDisabled.png");
-            imageButt->setIcon(failIcon);
-            imageButt->setIconSize(failIcon.size());
+            mapPreview->setPixmap(failIcon);
             break;
         case MapModel::GeneratedMap:
             askForGeneratedPreview();
@@ -610,7 +608,7 @@
 
             if(!success)
             {
-                imageButt->setIcon(QIcon());
+                mapPreview->setPixmap(QPixmap());
                 return;
             }
 
@@ -638,13 +636,13 @@
     {
         QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, m_theme);
         if (mdl.size() > 0)
-            lvThemes->setCurrentIndex(mdl.at(0));
+            updateTheme(mdl.at(0));
         else
             setRandomTheme();
     }
 
     // restore map selection
-    if ((!m_curMap.isEmpty()) && (chooseMap->currentIndex() < 0))
+    if (!m_curMap.isEmpty())
         intSetMap(m_curMap);
     else
         updatePreview();
@@ -656,3 +654,227 @@
     if (map == pMap)
         pMap = 0;
 }
+
+void HWMapContainer::mapTypeChanged(int index)
+{
+    changeMapType((MapModel::MapType)cType->itemData(index).toInt());
+}
+
+void HWMapContainer::changeMapType(MapModel::MapType type, const QModelIndex & newMap)
+{
+    staticMapList->hide();
+    missionMapList->hide();
+    lblMapList->hide();
+    generationStyles->hide();
+    mazeStyles->hide();
+    lblDesc->hide();
+    btnTheme->hide();
+    btnLoadMap->hide();
+    btnEditMap->hide();
+    btnRandomize->hide();
+
+    switch (type)
+    {
+        case MapModel::GeneratedMap:
+            mapgen = MAPGEN_REGULAR;
+            setMapInfo(MapModel::MapInfoRandom);
+            lblMapList->setText(tr("Map size:"));
+            lblMapList->show();
+            generationStyles->show();
+            btnRandomize->show();
+            btnTheme->show();
+            break;
+        case MapModel::GeneratedMaze:
+            mapgen = MAPGEN_MAZE;
+            setMapInfo(MapModel::MapInfoMaze);
+            lblMapList->setText(tr("Maze style:"));
+            lblMapList->show();
+            mazeStyles->show();
+            btnRandomize->show();
+            btnTheme->show();
+            break;
+        case MapModel::HandDrawnMap:
+            mapgen = MAPGEN_DRAWN;
+            setMapInfo(MapModel::MapInfoDrawn);
+            btnTheme->show();
+            btnLoadMap->show();
+            btnEditMap->show();
+            break;
+        case MapModel::MissionMap:
+            mapgen = MAPGEN_MAP;
+            missionMapChanged(newMap.isValid() ? newMap : missionMapList->currentIndex());
+            lblMapList->setText(tr("Mission:"));
+            lblMapList->show();
+            missionMapList->show();
+            lblDesc->setText(m_mapInfo.desc);
+            lblDesc->show();
+            btnRandomize->show();
+            emit mapChanged(m_curMap);
+            break;
+        case MapModel::StaticMap:
+            mapgen = MAPGEN_MAP;
+            staticMapChanged(newMap.isValid() ? newMap : staticMapList->currentIndex());
+            lblMapList->setText(tr("Map:"));
+            lblMapList->show();
+            staticMapList->show();
+            btnRandomize->show();
+            emit mapChanged(m_curMap);
+            break;
+        default:
+            break;
+    }
+
+    // Update cType combobox
+    for (int i = 0; i < cType->count(); i++)
+    {
+        if ((MapModel::MapType)cType->itemData(i).toInt() == type)
+        {
+            cType->setCurrentIndex(i);
+            break;
+        }
+    }
+
+    emit mapgenChanged(mapgen);
+}
+
+void HWMapContainer::showThemePrompt()
+{
+    ThemePrompt prompt(this);
+    int theme = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
+    if (theme < 0) return;
+
+    QModelIndex current = m_themeModel->index(theme, 0);
+    updateTheme(current);
+    
+    emit themeChanged(m_theme);
+}
+
+void HWMapContainer::updateTheme(const QModelIndex & current)
+{
+    m_theme = selectedTheme = current.data().toString();
+    QIcon icon = qVariantValue<QIcon>(current.data(Qt::UserRole));
+    QSize iconSize = icon.actualSize(QSize(65535, 65535));
+    btnTheme->setFixedHeight(iconSize.height());
+    btnTheme->setIconSize(iconSize);
+    btnTheme->setIcon(icon);
+    btnTheme->setText(tr("Theme: ") + current.data(Qt::DisplayRole).toString());
+    emit themeChanged(m_theme);
+}
+
+void HWMapContainer::staticMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+    mapChanged(map, 0, old);
+}
+
+void HWMapContainer::missionMapChanged(const QModelIndex & map, const QModelIndex & old)
+{
+    mapChanged(map, 1, old);
+}
+
+// Type: 0 = static, 1 = mission
+void HWMapContainer::mapChanged(const QModelIndex & map, int type, const QModelIndex & old)
+{
+    QListView * mapList;
+
+    if (type == 0)      mapList = staticMapList;
+    else if (type == 1) mapList = missionMapList;
+    else                return;
+
+    // Make sure it is a valid index
+    if (!map.isValid())
+    {
+        if (old.isValid())
+        {
+            mapList->setCurrentIndex(old);
+            mapList->scrollTo(old);
+        }
+        else
+        {
+            m_mapInfo.type = MapModel::Invalid;
+            updatePreview();
+        }
+
+        return;
+    }
+
+    // If map changed, update list selection
+    if (mapList->currentIndex() != map)
+    {
+        mapList->setCurrentIndex(map);
+        mapList->scrollTo(map);
+    }
+
+    if (map.data(Qt::UserRole + 1).canConvert<MapModel::MapInfo>())
+        setMapInfo(map.data(Qt::UserRole + 1).value<MapModel::MapInfo>());
+    else
+        Q_ASSERT(false); // Houston, we have a problem.
+
+}
+
+void HWMapContainer::setMapInfo(MapModel::MapInfo mapInfo)
+{
+    m_mapInfo = mapInfo;
+    m_curMap = m_mapInfo.name;
+    m_theme = m_mapInfo.theme;
+
+    // the map has no pre-defined theme, so let's use the selected one
+    if (m_mapInfo.theme.isEmpty())
+    {
+        m_theme = selectedTheme;
+        emit themeChanged(m_theme);
+    }
+
+    lblDesc->setText(mapInfo.desc);
+
+    updatePreview();
+    emit mapChanged(m_curMap);
+}
+
+void HWMapContainer::loadDrawing()
+{
+
+
+    QString fileName = QFileDialog::getOpenFileName(NULL, tr("Load drawn map"), ".", tr("Drawn Maps") + " (*.hwmap);;" + tr("All files") + " (*)");
+
+    if(fileName.isEmpty()) return;
+
+
+
+    QFile f(fileName);
+
+    if(!f.open(QIODevice::ReadOnly))
+    {
+        QMessageBox errorMsg(parentWidget());
+        errorMsg.setIcon(QMessageBox::Warning);
+        errorMsg.setWindowTitle(QMessageBox::tr("File error"));
+        errorMsg.setText(QMessageBox::tr("Cannot open '%1' for reading").arg(fileName));
+        errorMsg.setWindowModality(Qt::WindowModal);
+        errorMsg.exec();
+    }
+    else
+    {
+        drawMapScene.decode(qUncompress(QByteArray::fromBase64(f.readAll())));
+        mapDrawingFinished();
+    }
+}
+
+void HWMapContainer::showSeedPrompt()
+{
+    SeedPrompt prompt(parentWidget()->parentWidget(), getCurrentSeed(), isMaster());
+    connect(&prompt, SIGNAL(seedSelected(const QString &)), this, SLOT(setNewSeed(const QString &)));
+    prompt.exec();
+}
+
+bool HWMapContainer::isMaster()
+{
+    return m_master;
+}
+
+void HWMapContainer::setMaster(bool master)
+{
+    if (master == m_master) return;
+    m_master = master;
+    
+    foreach (QWidget *widget, m_childWidgets)
+        widget->setEnabled(master);
+}
--- a/QTfrontend/ui/widget/mapContainer.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/ui/widget/mapContainer.h	Mon Jan 14 12:07:51 2013 +0100
@@ -22,6 +22,7 @@
 
 #include <QWidget>
 #include <QGridLayout>
+#include <QVBoxLayout>
 #include <QComboBox>
 #include <QLabel>
 #include <QByteArray>
@@ -37,6 +38,7 @@
 class IconedGroupBox;
 class QListView;
 class SeparatorPainter;
+class QListWidget;
 
 class MapFileErrorException
 {
@@ -46,6 +48,8 @@
 {
         Q_OBJECT
 
+        Q_PROPERTY(bool master READ isMaster WRITE setMaster)
+
     public:
         HWMapContainer(QWidget * parent=0);
         QString getCurrentSeed() const;
@@ -62,6 +66,7 @@
         DrawMapScene * getDrawMapScene();
         void mapDrawingFinished();
         QLineEdit* seedEdit;
+        bool isMaster();
 
     public slots:
         void askForGeneratedPreview();
@@ -75,6 +80,7 @@
         void setAllMapParameters(const QString & map, MapGenerator m, int mazesize, const QString & seed, int tmpl);
         void updateModelViews();
         void onPreviewMapDestroyed(QObject * map);
+        void setMaster(bool master);
 
     signals:
         void seedChanged(const QString & seed);
@@ -89,22 +95,28 @@
     private slots:
         void setImage(const QImage newImage);
         void setHHLimit(int hhLimit);
-        void mapChanged(int index);
         void setRandomSeed();
         void setRandomTheme();
         void setRandomMap();
-        void themeSelected(const QModelIndex & current, const QModelIndex &);
         void addInfoToPreview(QPixmap image);
-        void seedEdited();
+        void setNewSeed(const QString & newSeed);
+        void mapTypeChanged(int);
+        void showThemePrompt();
+        void updateTheme(const QModelIndex & current);
+        void staticMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+        void missionMapChanged(const QModelIndex & map, const QModelIndex & old = QModelIndex());
+        void loadDrawing();
+        void showSeedPrompt();
 
     protected:
         virtual void resizeEvent ( QResizeEvent * event );
 
     private:
-        QGridLayout mainLayout;
-        QPushButton* imageButt;
+        QVBoxLayout mainLayout;
+        QLabel* mapPreview;
         QComboBox* chooseMap;
-        MapModel * m_mapModel;
+        MapModel * m_staticMapModel;
+        MapModel * m_missionMapModel;
         IconedGroupBox* gbThemes;
         QListView* lvThemes;
         ThemeModel * m_themeModel;
@@ -121,12 +133,30 @@
         QComboBox *cbMazeSize;
         MapGenerator mapgen;
         DrawMapScene drawMapScene;
+        QComboBox * cType;
+        QListView * staticMapList;
+        QListView * missionMapList;
+        QListWidget * generationStyles;
+        QListWidget * mazeStyles;
+        QLabel * lblMapList;
+        QLabel * lblDesc;
+        QPushButton * btnTheme;
+        QPushButton * btnLoadMap;
+        QPushButton * btnEditMap;
+        QPushButton * btnRandomize;
+        QString selectedTheme;
+        QPushButton * btnSeed;
+        bool m_master;
+        QList<QWidget *> m_childWidgets;
 
         void intSetSeed(const QString & seed);
         void intSetMap(const QString & map);
         void intSetMapgen(MapGenerator m);
         void intSetTemplateFilter(int);
         void intSetMazeSize(int size);
+        void mapChanged(const QModelIndex & map, int type, const QModelIndex & old = QModelIndex());
+        void setMapInfo(MapModel::MapInfo mapInfo);
+        void changeMapType(MapModel::MapType type, const QModelIndex & newMap = QModelIndex());
         void updatePreview();
 
         MapModel::MapInfo m_mapInfo;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QLabel>
+#include <QDebug>
+
+#include "seedprompt.h"
+
+SeedPrompt::SeedPrompt(QWidget* parent, const QString & seed, bool editable) : QDialog(parent)
+{
+	setModal(true);
+	setWindowFlags(Qt::Sheet);
+	setWindowModality(Qt::WindowModal);
+	setMinimumSize(360, 160);
+	resize(360, 160);
+	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+	// Layout
+	QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+
+	// Label
+	QLabel * label = new QLabel(tr("The map seed is the basis for all random values generated by the game."));
+	label->setWordWrap(true);
+	dialogLayout->addWidget(label, 0);
+
+	// Input box
+	editBox = new QLineEdit();
+	editBox->setText(seed);
+	editBox->setReadOnly(!editable);
+	editBox->setStyleSheet("QLineEdit { padding: 3px; }");
+	dialogLayout->addWidget(editBox, 1);
+
+	dialogLayout->addStretch(1);
+
+	// Buttons
+	QHBoxLayout * buttonLayout = new QHBoxLayout();
+	buttonLayout->addStretch(1);
+	dialogLayout->addLayout(buttonLayout);
+	if (editable)
+	{
+		QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+		QPushButton * btnOkay = new QPushButton(tr("Set seed"));
+		connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+		connect(btnOkay, SIGNAL(clicked()), this, SLOT(accept()));
+		buttonLayout->addWidget(btnCancel);
+		buttonLayout->addWidget(btnOkay);
+		btnOkay->setDefault(true);
+	}
+	else
+	{
+		QPushButton * btnClose = new QPushButton(tr("Close"));
+		connect(btnClose, SIGNAL(clicked()), this, SLOT(reject()));
+		buttonLayout->addWidget(btnClose);
+		btnClose->setDefault(true);
+	}
+
+	setStyleSheet("QPushButton { padding: 5px; }");
+
+	connect(this, SIGNAL(accepted()), this, SLOT(setSeed()));
+}
+
+void SeedPrompt::setSeed()
+{
+	emit seedSelected(editBox->text());
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/seedprompt.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,43 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef SEEDPROMPT_H
+#define SEEDPROMPT_H
+
+#include <QDialog>
+
+class QLineEdit;
+
+class SeedPrompt : public QDialog
+{
+        Q_OBJECT
+
+    public:
+        SeedPrompt(QWidget* parent, const QString & seed, bool editable);
+
+    signals:
+    	void seedSelected(const QString & seed);
+
+    private slots:
+    	void setSeed();
+
+    private:
+    	QLineEdit * editBox;
+};
+
+#endif // SEEDPROMPT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,100 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDialog>
+#include <QVBoxLayout>
+#include <QScrollArea>
+#include <QPushButton>
+#include <QToolButton>
+#include <QWidgetItem>
+#include <QModelIndex>
+#include <QLabel>
+
+#include "flowlayout.h"
+#include "datamanager.h"
+#include "thememodel.h"
+#include "themeprompt.h"
+
+ThemePrompt::ThemePrompt(QWidget* parent) : QDialog(parent)
+{
+	setModal(true);
+	setWindowFlags(Qt::Sheet);
+	setWindowModality(Qt::WindowModal);
+	setMinimumSize(550, 430);
+	resize(550, 430);
+	setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+	// Grid
+	QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+	dialogLayout->setSpacing(0);
+
+	// Help/prompt message at top
+	QLabel * lblDesc = new QLabel(tr("Select a theme for this map"));
+    lblDesc->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: auto 20px;");
+    lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    lblDesc->setFixedHeight(24);
+    lblDesc->setMinimumWidth(0);
+
+	// Scroll area and container for theme icons
+	QWidget * themesContainer = new QWidget();
+	FlowLayout * themesGrid = new FlowLayout();
+	themesContainer->setLayout(themesGrid);
+	QScrollArea * scrollArea = new QScrollArea();
+    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+    scrollArea->setObjectName("scrollArea");
+    scrollArea->setStyleSheet("QScrollBar, #scrollArea { background-color: #130F2A; } #scrollArea { border-color: #F6CB1C; border-width: 3px; border-top-width: 0; border-style: solid; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }");
+    scrollArea->setWidgetResizable(true);
+    scrollArea->setFrameShape(QFrame::NoFrame);
+    scrollArea->setWidget(themesContainer);
+
+	// Cancel button (closes dialog)
+	QPushButton * btnCancel = new QPushButton(tr("Cancel"));
+	btnCancel->setStyleSheet("padding: 5px; margin-top: 10px;");
+	connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
+
+	// Add elements to layouts
+	dialogLayout->addWidget(lblDesc, 0);
+	dialogLayout->addWidget(scrollArea, 1);
+	dialogLayout->addWidget(btnCancel, 0, Qt::AlignLeft);
+
+	// Tooltip label for theme name
+	lblToolTip = new QLabel(this);
+
+	// Add theme buttons
+	ThemeModel * themes = DataManager::instance().themeModel();
+	for (int i = 0; i < themes->rowCount(); i++)
+	{
+		QModelIndex index = themes->index(i, 0);
+		QToolButton * btn = new QToolButton();
+		btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+		btn->setIcon(qVariantValue<QIcon>(themes->data(index, Qt::UserRole)));
+		btn->setText(themes->data(index, Qt::DisplayRole).toString());
+		btn->setIconSize(QSize(60, 60));
+		btn->setProperty("themeID", QVariant(i));
+		btn->setStyleSheet("padding: 2px;");
+		connect(btn, SIGNAL(clicked()), this, SLOT(themeClicked()));
+		themesGrid->addWidget(btn);
+	}
+}
+
+// When a theme is selected
+void ThemePrompt::themeClicked()
+{
+	QWidget * btn = (QWidget*)sender();
+	done(btn->property("themeID").toInt() + 1); // Since returning 0 means canceled
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/ui/widget/themeprompt.h	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,41 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef THEMEPROMPT_H
+#define THEMEPROMPT_H
+
+#include <QWidget>
+#include <QDialog>
+
+class QLabel;
+
+class ThemePrompt : public QDialog
+{
+        Q_OBJECT
+
+    public:
+        ThemePrompt(QWidget* parent);
+
+    private:
+        QLabel * lblToolTip;
+
+    private slots:
+        void themeClicked();
+};
+
+#endif // THEMEPROMPT_H
--- a/QTfrontend/util/DataManager.cpp	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/util/DataManager.cpp	Mon Jan 14 12:07:51 2013 +0100
@@ -40,7 +40,8 @@
 DataManager::DataManager()
 {
     m_hatModel = NULL;
-    m_mapModel = NULL;
+    m_staticMapModel = NULL;
+    m_missionMapModel = NULL;
     m_themeModel = NULL;
     m_colorsModel = NULL;
     m_bindsModel = NULL;
@@ -92,13 +93,22 @@
     return m_hatModel;
 }
 
-MapModel * DataManager::mapModel()
+MapModel * DataManager::staticMapModel()
 {
-    if (m_mapModel == NULL) {
-        m_mapModel = new MapModel();
-        m_mapModel->loadMaps();
+    if (m_staticMapModel == NULL) {
+        m_staticMapModel = new MapModel();
+        m_staticMapModel->loadMaps(MapModel::StaticMap);
     }
-    return m_mapModel;
+    return m_staticMapModel;
+}
+
+MapModel * DataManager::missionMapModel()
+{
+    if (m_missionMapModel == NULL) {
+        m_missionMapModel = new MapModel();
+        m_missionMapModel->loadMaps(MapModel::MissionMap);
+    }
+    return m_missionMapModel;
 }
 
 ThemeModel * DataManager::themeModel()
--- a/QTfrontend/util/DataManager.h	Tue Jan 08 21:29:37 2013 +0200
+++ b/QTfrontend/util/DataManager.h	Mon Jan 14 12:07:51 2013 +0100
@@ -88,13 +88,22 @@
         HatModel * hatModel();
 
         /**
-         * @brief Returns pointer to a model of available maps.
+         * @brief Returns pointer to a model of available static maps.
          *
          * The model is updated automatically on data reload.
          *
          * @return map model pointer.
          */
-        MapModel * mapModel();
+        MapModel * staticMapModel();
+
+        /**
+         * @brief Returns pointer to a model of available mission maps.
+         *
+         * The model is updated automatically on data reload.
+         *
+         * @return map model pointer.
+         */
+        MapModel * missionMapModel();
 
         /**
          * @brief Returns pointer to a model of available themes.
@@ -132,7 +141,8 @@
 
         GameStyleModel * m_gameStyleModel; ///< game style model instance
         HatModel * m_hatModel; ///< hat model instance
-        MapModel * m_mapModel; ///< map model instance
+        MapModel * m_staticMapModel; ///< static map model instance
+        MapModel * m_missionMapModel; ///< mission map model instance
         ThemeModel * m_themeModel; ///< theme model instance
         QStandardItemModel * m_colorsModel;
         QStandardItemModel * m_bindsModel;
--- a/gameServer/Actions.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/Actions.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -4,7 +4,6 @@
 
 import Control.Concurrent
 import qualified Data.Set as Set
-import qualified Data.Sequence as Seq
 import qualified Data.List as L
 import qualified Control.Exception as Exception
 import System.Log.Logger
@@ -143,13 +142,13 @@
 
     chan <- client's sendChan
     clNick <- client's nick
-    loggedIn <- client's logonPassed
+    loggedIn <- client's isVisible
 
     when (ri /= lobbyId) $ do
         processAction $ MoveToLobby ("quit: " `B.append` msg)
         return ()
 
-    clientsChans <- liftM (Prelude.map sendChan . Prelude.filter logonPassed) $! allClientsS
+    clientsChans <- liftM (Prelude.map sendChan . Prelude.filter isVisible) $! allClientsS
     io $
         infoM "Clients" (show ci ++ " quits: " ++ B.unpack msg)
 
@@ -158,7 +157,7 @@
     mapM_ processAction
         [
         AnswerClients [chan] ["BYE", msg]
-        , ModifyClient (\c -> c{nick = "", logonPassed = False}) -- this will effectively hide client from others while he isn't deleted from list
+        , ModifyClient (\c -> c{nick = "", isVisible = False}) -- this will effectively hide client from others while he isn't deleted from list
         ]
 
     s <- get
@@ -374,7 +373,7 @@
         ModifyRoom (\r -> r{
                 gameInfo = liftM (\g -> g{
                     teamsInGameNumber = teamsInGameNumber g - 1
-                    , roundMsgs = roundMsgs g Seq.|> rmTeamMsg
+                    , roundMsgs = rmTeamMsg : roundMsgs g
                 }) $ gameInfo r
             })
         ]
@@ -421,9 +420,11 @@
     n <- client's nick
     h <- client's host
     p <- client's clientProto
+    checker <- client's isChecker
     uid <- client's clUID
-    haveSameNick <- liftM (not . null . tail . filter (\c -> caseInsensitiveCompare (nick c) n)) allClientsS
-    if haveSameNick then
+    -- allow multiple checker logins
+    haveSameNick <- liftM (not . null . tail . filter (\c -> (not $ isChecker c) && caseInsensitiveCompare (nick c) n)) allClientsS
+    if haveSameNick && (not checker) then
         if p < 38 then
             processAction $ ByeClient "Nickname is already in use"
             else
@@ -444,9 +445,8 @@
     case info of
         HasAccount passwd isAdmin -> do
             b <- isBanned
-            when (not b) $ do
-                chan <- client's sendChan
-                mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = passwd, isAdministrator = isAdmin})]
+            c <- client's isChecker
+            when (not b) $ (if c then checkerLogin else playerLogin) passwd isAdmin
         Guest -> do
             b <- isBanned
             when (not b) $
@@ -459,14 +459,21 @@
     isBanned = do
         processAction $ CheckBanned False
         liftM B.null $ client's nick
-
+    checkerLogin p False = processAction $ ByeClient "No checker rights"
+    checkerLogin p True = do
+        wp <- client's webPassword
+        processAction $
+            if wp == p then ModifyClient $ \c -> c{logonPassed = True} else ByeClient "Authentication failed"
+    playerLogin p a = do
+        chan <- client's sendChan
+        mapM_ processAction [AnswerClients [chan] ["ASKPASSWORD"], ModifyClient (\c -> c{webPassword = p, isAdministrator = a})]
 
 processAction JoinLobby = do
     chan <- client's sendChan
     clientNick <- client's nick
     isAuthenticated <- liftM (not . B.null) $ client's webPassword
     isAdmin <- client's isAdministrator
-    loggedInClients <- liftM (Prelude.filter logonPassed) $! allClientsS
+    loggedInClients <- liftM (Prelude.filter isVisible) $! allClientsS
     let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients
     let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients
     let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients
@@ -477,7 +484,7 @@
         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks]
         , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks]
         , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS",  B.concat["+" , clFlags], clientNick] | not $ B.null clFlags]
-        , [ModifyClient (\cl -> cl{logonPassed = True})]
+        , [ModifyClient (\cl -> cl{logonPassed = True, isVisible = True})]
         , [SendServerMessage]
         ]
 
@@ -637,6 +644,7 @@
 processAction SaveReplay = do
     ri <- clientRoomA
     rnc <- gets roomsClients
+
     io $ do
         r <- room'sM rnc id ri
         saveReplay r
--- a/gameServer/ClientIO.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/ClientIO.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -30,25 +30,26 @@
             return (B.splitWith (== '\n') packet : packets)
 
 listenLoop :: Socket -> Chan CoreMessage -> ClientIndex -> IO ()
-listenLoop sock chan ci = recieveWithBufferLoop B.empty
+listenLoop sock chan ci = receiveWithBufferLoop B.empty
     where
-        recieveWithBufferLoop recvBuf = do
+        receiveWithBufferLoop recvBuf = do
             recvBS <- recv sock 4096
             unless (B.null recvBS) $ do
                 let (packets, newrecvBuf) = bs2Packets $ B.append recvBuf recvBS
                 forM_ packets sendPacket
-                recieveWithBufferLoop newrecvBuf
+                receiveWithBufferLoop newrecvBuf
 
         sendPacket packet = writeChan chan $ ClientMessage (ci, packet)
 
 clientRecvLoop :: Socket -> Chan CoreMessage -> Chan [B.ByteString] -> ClientIndex -> (forall a. IO a -> IO a) -> IO ()
 clientRecvLoop s chan clChan ci restore =
     (myThreadId >>=
-    \t -> (restore $ forkIO (clientSendLoop s t clChan ci) >>
+      (\t -> (restore $ forkIO (clientSendLoop s t clChan ci) >>
         listenLoop s chan ci >> return "Connection closed")
         `Exception.catch` (\(e :: ShutdownThreadException) -> return . B.pack . show $ e)
         `Exception.catch` (\(e :: Exception.IOException) -> return . B.pack . show $ e)
         `Exception.catch` (\(e :: Exception.SomeException) -> return . B.pack . show $ e)
+      )
         >>= clientOff) `Exception.finally` remove
     where
         clientOff msg = writeChan chan $ ClientMessage (ci, ["QUIT", msg])
--- a/gameServer/CoreTypes.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/CoreTypes.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -4,7 +4,6 @@
 import Control.Concurrent
 import Data.Word
 import qualified Data.Map as Map
-import Data.Sequence(Seq, empty)
 import Data.Time
 import Network
 import Data.Function
@@ -29,6 +28,7 @@
         nick :: B.ByteString,
         webPassword :: B.ByteString,
         logonPassed :: Bool,
+        isVisible :: Bool,
         clientProto :: !Word16,
         roomID :: RoomIndex,
         pingsQueue :: !Word,
@@ -36,6 +36,7 @@
         isReady :: !Bool,
         isInGame :: Bool,
         isAdministrator :: Bool,
+        isChecker :: Bool,
         isKickedFromServer :: Bool,
         clientClan :: Maybe B.ByteString,
         teamsInGame :: Word
@@ -68,7 +69,7 @@
 data GameInfo =
     GameInfo
     {
-        roundMsgs :: Seq B.ByteString,
+        roundMsgs :: [B.ByteString],
         leftTeams :: [B.ByteString],
         teamsAtStart :: [TeamInfo],
         teamsInGameNumber :: Int,
@@ -85,7 +86,7 @@
                 -> GameInfo
 newGameInfo =
     GameInfo
-        Data.Sequence.empty
+        []
         []
 
 data RoomInfo =
--- a/gameServer/HWProtoInRoomState.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/HWProtoInRoomState.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -2,13 +2,11 @@
 module HWProtoInRoomState where
 
 import qualified Data.Map as Map
-import Data.Sequence((|>))
 import Data.List as L
 import Data.Maybe
 import qualified Data.ByteString.Char8 as B
 import Control.Monad
 import Control.Monad.Reader
-import Control.DeepSeq
 --------------------------------------
 import CoreTypes
 import Actions
@@ -214,7 +212,8 @@
     chans <- roomOthersChans
 
     if teamsInGame cl > 0 && (isJust $ gameInfo rm) && isLegal then
-        return $ AnswerClients chans ["EM", msg] : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = roundMsgs g |> msg}) $ gameInfo r}) | not isKeepAlive]
+        return $ AnswerClients chans ["EM", msg]
+            : [ModifyRoom (\r -> r{gameInfo = liftM (\g -> g{roundMsgs = msg : roundMsgs g}) $ gameInfo r}) | not isKeepAlive]
         else
         return []
     where
--- a/gameServer/HWProtoLobbyState.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/HWProtoLobbyState.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -2,11 +2,9 @@
 module HWProtoLobbyState where
 
 import qualified Data.Map as Map
-import qualified Data.Foldable as Foldable
 import Data.Maybe
 import Data.List
 import Control.Monad.Reader
-import qualified Data.ByteString.Char8 as B
 --------------------------------------
 import CoreTypes
 import Actions
@@ -128,7 +126,7 @@
                     [AnswerClients [sendChan cl]  ["RUN_GAME"]
                     , AnswerClients chans ["CLIENT_FLAGS", "+g", nick cl]
                     , ModifyClient (\c -> c{isInGame = True})
-                    , AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : Foldable.toList (roundMsgs . fromJust . gameInfo $ jRoom)]
+                    , AnswerClients [sendChan cl] $ "EM" : toEngineMsg "e$spectate 1" : (reverse . roundMsgs . fromJust . gameInfo $ jRoom)]
 
 
 handleCmd_lobby ["JOIN_ROOM", roomName] =
--- a/gameServer/HWProtoNEState.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/HWProtoNEState.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, CPP #-}
 module HWProtoNEState where
 
 import Control.Monad.Reader
@@ -48,4 +48,18 @@
         return [ByeClient "Authentication failed"]
 
 
+#if defined(OFFICIAL_SERVER)
+handleCmd_NotEntered ["CHECKER", protoNum, newNick, password] = do
+    (ci, irnc) <- ask
+    let cl = irnc `client` ci
+
+    if parsedProto == 0 then return [ProtocolError "Bad number"]
+        else
+        return $ [
+            ModifyClient (\c -> c{clientProto = parsedProto, nick = newNick, webPassword = password, isChecker = True})
+            , CheckRegistered]
+    where
+        parsedProto = readInt_ protoNum
+#endif
+
 handleCmd_NotEntered _ = return [ProtocolError "Incorrect command (state: not entered)"]
--- a/gameServer/NetRoutines.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/NetRoutines.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -34,6 +34,7 @@
                     ""
                     ""
                     False
+                    False
                     0
                     lobbyId
                     0
@@ -42,6 +43,7 @@
                     False
                     False
                     False
+                    False
                     Nothing
                     0
                     )
--- a/gameServer/OfficialServer/GameReplayStore.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/OfficialServer/GameReplayStore.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -14,7 +14,7 @@
 
 
 saveReplay :: RoomInfo -> IO ()
-saveReplay r = do
+saveReplay r = when allPlayersHaveRegisteredAccounts $ do
     time <- getCurrentTime
     u <- liftM hashUnique newUnique
     let fileName = "replays/" ++ show time ++ "-" ++ show u
@@ -23,4 +23,3 @@
     E.catch
         (writeFile fileName (show replayInfo))
         (\(e :: IOException) -> warningM "REPLAYS" $ "Couldn't write to " ++ fileName ++ ": " ++ show e)
-                   
\ No newline at end of file
--- a/gameServer/ServerState.hs	Tue Jan 08 21:29:37 2013 +0200
+++ b/gameServer/ServerState.hs	Mon Jan 14 12:07:51 2013 +0100
@@ -49,6 +49,6 @@
 sameProtoClientsS p = liftM f allClientsS
     where
         f = filter (\c -> clientProto c == p)
-    
+
 io :: IO a -> StateT ServerState IO a
 io = liftIO
--- a/hedgewars/ArgParsers.inc	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/ArgParsers.inc	Mon Jan 14 12:07:51 2013 +0100
@@ -124,6 +124,8 @@
 
 procedure startVideoRecording(var paramIndex: LongInt);
 begin
+    // Silence the hint that appears when USE_VIDEO_RECORDING is not defined
+    paramIndex:= paramIndex;
 {$IFDEF USE_VIDEO_RECORDING}
     GameType:= gmtRecord;
     inc(paramIndex);
@@ -245,6 +247,7 @@
     tmpInt:= 1;
     while (index < size) do
         begin
+        newSyntax:= '';
         inc(paramIndex);
         cmd:= cmdArray[index];
         arg:= ParamStr(paramIndex);
--- a/hedgewars/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -239,25 +239,25 @@
 endif()
 
 
-add_custom_target(${engine_output_name} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}")
+add_custom_target(hwengine ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}")
 
 #when system Lua is not found we need to compile it before engine
 if(NOT LUA_FOUND)
-    add_dependencies(${engine_output_name} lua)
+    add_dependencies(hwengine lua)
 endif()
 
 # compile physfs before engine
-add_dependencies(${engine_output_name} physfs)
+add_dependencies(hwengine physfs)
 
 #when ffmpeg/libav is found we need to compile it before engine
 #TODO: convert avwrapper to .pas unit so we can skip this step
 if(${FFMPEG_FOUND})
-    add_dependencies(${engine_output_name} avwrapper)
+    add_dependencies(hwengine avwrapper)
 endif()
 
 #this command is a workaround to some inlining issues present in older FreePascal versions and fixed in 2.6
 if((FPC_VERSION VERSION_LESS "2.6") AND (NOVIDEOREC OR NOT ${FFMPEG_FOUND}))
-    add_dependencies(${engine_output_name} ENGINECLEAN)
+    add_dependencies(hwengine ENGINECLEAN)
 endif()
 
 install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}" DESTINATION ${destination_dir})
--- a/hedgewars/GSHandlers.inc	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/GSHandlers.inc	Mon Jan 14 12:07:51 2013 +0100
@@ -5174,7 +5174,7 @@
 if (Gear^.State and gstTmpFlag <> 0) or (GameTicks and $7 = 0) then
     begin
     doStepFallingGear(Gear);
-    if (Gear^.State and gstInvisible <> 0) and (GameTicks and $FF = 0) and ((hwRound(Gear^.X) < leftX) or (hwRound(Gear^.X) > rightX) or (hwRound(Gear^.Y) < topY)) then
+    if (Gear^.State and gstInvisible <> 0) and (GameTicks and $FF = 0) and (hwRound(Gear^.X) < LongInt(leftX)) or (hwRound(Gear^.X) > LongInt(rightX)) or (hwRound(Gear^.Y) < LongInt(topY)) then
         begin
         Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
         Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
@@ -5267,9 +5267,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 procedure doStepKnife(Gear: PGear);
-var ox, oy: LongInt;
-    la: hwFloat;
-    a: real;
+//var ox, oy: LongInt;
+//    la: hwFloat;
+var   a: real;
 begin
     // Gear is shrunk so it can actually escape the hog without carving into the terrain
     if (Gear^.Radius = 6) and (Gear^.CollisionMask = $FFFF) then Gear^.Radius:= 16;
@@ -5291,14 +5291,14 @@
         end
     else if (Gear^.CollisionIndex = -1) and (Gear^.Timer = 0) then
         begin
-        ox:= 0; oy:= 0;
+        (*ox:= 0; oy:= 0;
         if TestCollisionYwithGear(Gear, -1) <> 0 then oy:= -1;
         if TestCollisionXwithGear(Gear, 1)       then ox:=  1;
         if TestCollisionXwithGear(Gear, -1)      then ox:= -1;
         if TestCollisionYwithGear(Gear, 1) <> 0  then oy:=  1;
         if Gear^.Health > 0 then
             PlaySound(sndRopeAttach);
-(*
+
         la:= _10000;
         if (ox <> 0) or (oy <> 0) then
             la:= CalcSlopeNearGear(Gear, ox, oy);
--- a/hedgewars/hwengine.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/hwengine.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -330,8 +330,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 procedure Game{$IFDEF HWLIBRARY}(argc: LongInt; argv: PPChar); cdecl; export{$ENDIF};
-var p: TPathType;
-    s: shortstring;
+//var p: TPathType;
+var s: shortstring;
     i: LongInt;
 begin
 {$IFDEF HWLIBRARY}
--- a/hedgewars/uAIAmmoTests.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -1140,7 +1140,7 @@
 var i: Longword;
     v: LongInt;
 begin
-while (not TestColl(hwRound(Gear^.X), hwRound(Gear^.Y), 6)) and (Gear^.Y.Round < LAND_HEIGHT) do
+while (not TestColl(hwRound(Gear^.X), hwRound(Gear^.Y), 6)) and (Gear^.Y.Round < LongWord(LAND_HEIGHT)) do
     Gear^.Y:= Gear^.Y + _1;
 
 for i:= 0 to 2040 do
--- a/hedgewars/uCommandHandlers.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uCommandHandlers.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -89,11 +89,11 @@
 end;
 
 procedure chCheckProto(var s: shortstring);
-var i, c: LongInt;
+var i: LongInt;
 begin
     if isDeveloperMode then
         begin
-        val(s, i, c);
+        i:= StrToInt(s);
         TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
         TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new (got '+intToStr(i)+', expecting '+intToStr(cNetProtoVersion)+')', true);
         end
--- a/hedgewars/uGearsRender.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uGearsRender.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -41,7 +41,7 @@
 
 const
     // hog tag mask
-    htNone        = $00;
+    //htNone        = $00;
     htTeamName    = $01;
     htName        = $02;
     htHealth      = $04;
--- a/hedgewars/uIO.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uIO.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -339,10 +339,12 @@
             // these are equations solved for CursorPoint
             // SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx;
             // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy;
-            if not (CurrentTeam^.ExtDriven and bShowAmmoMenu) then
+            if CurrentTeam^.ExtDriven then
                begin
-               CursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx;
-               CursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy
+               TargetCursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx;
+               TargetCursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy;
+               if not bShowAmmoMenu and autoCameraOn then
+                    CursorPoint:= TargetCursorPoint
                end
              end;
         'w': ParseCommand('setweap ' + headcmd^.str[2], true);
--- a/hedgewars/uInputHandler.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uInputHandler.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -67,10 +67,10 @@
     //ControllerNumBalls: array[0..5] of Integer;
     ControllerNumHats: array[0..5] of Integer;
     ControllerNumButtons: array[0..5] of Integer;
-    ControllerAxes: array[0..5] of array[0..19] of Integer;
+    //ControllerAxes: array[0..5] of array[0..19] of Integer;
     //ControllerBalls: array[0..5] of array[0..19] of array[0..1] of Integer;
-    ControllerHats: array[0..5] of array[0..19] of Byte;
-    ControllerButtons: array[0..5] of array[0..19] of Byte;
+    //ControllerHats: array[0..5] of array[0..19] of Byte;
+    //ControllerButtons: array[0..5] of array[0..19] of Byte;
     usingDBinds: boolean;
 
 function  KeyNameToCode(name: shortstring): LongInt; inline;
@@ -355,7 +355,7 @@
 var Controller: array [0..5] of PSDL_Joystick;
 
 procedure ControllerInit;
-var i, j: Integer;
+var j: Integer;
 begin
 ControllerEnabled:= 0;
 {$IFDEF IPHONE}
@@ -400,18 +400,18 @@
             if ControllerNumButtons[j] > 20 then
                 ControllerNumButtons[j]:= 20;
 
-            // reset all buttons/axes
+            (*// reset all buttons/axes
             for i:= 0 to pred(ControllerNumAxes[j]) do
                 ControllerAxes[j][i]:= 0;
-            (*for i:= 0 to pred(ControllerNumBalls[j]) do
+            for i:= 0 to pred(ControllerNumBalls[j]) do
                 begin
                 ControllerBalls[j][i][0]:= 0;
                 ControllerBalls[j][i][1]:= 0;
-                end;*)
+                end;
             for i:= 0 to pred(ControllerNumHats[j]) do
                 ControllerHats[j][i]:= SDL_HAT_CENTERED;
             for i:= 0 to pred(ControllerNumButtons[j]) do
-                ControllerButtons[j][i]:= 0;
+                ControllerButtons[j][i]:= 0;*)
             end;
         end;
     // enable event generation/controller updating
--- a/hedgewars/uLand.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uLand.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -523,7 +523,6 @@
 
 procedure LoadMap;
 var tmpsurf: PSDL_Surface;
-    s: shortstring;
     mapName: shortstring = '';
 begin
 WriteLnToConsole('Loading land from file...');
@@ -631,7 +630,7 @@
             if Land[y, x] <> 0 then
                 begin
                 inc(c);
-                if c > (LAND_WIDTH div 2) then // avoid accidental triggering
+                if c > LongWord((LAND_WIDTH div 2)) then // avoid accidental triggering
                     begin
                     hasBorder:= true;
                     break;
--- a/hedgewars/uLocale.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uLocale.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -40,14 +40,12 @@
     trevt_n: array[TEventId] of integer;
 
 procedure LoadLocale(FileName: shortstring);
-var s: ansistring;
+var s: ansistring = '';
     f: pfsFile;
     a, b, c: LongInt;
     first: array[TEventId] of boolean;
     e: TEventId;
-    loaded: boolean;
 begin
-loaded:= false;
 for e:= Low(TEventId) to High(TEventId) do
     first[e]:= true;
 
--- a/hedgewars/uScript.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uScript.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -230,8 +230,9 @@
 begin
     for i:= 1 to lua_gettop(L) do
         if (GameFlags and lua_tointeger(L, i)) = 0 then
-            GameFlags += lua_tointeger(L, i);
+            GameFlags := GameFlags + LongWord(lua_tointeger(L, i));
     ScriptSetInteger('GameFlags', GameFlags);
+    lc_enablegameflags:= 0;
 end;
 
 function lc_disablegameflags(L : Plua_State) : LongInt; Cdecl;
@@ -239,14 +240,18 @@
 begin
     for i:= 1 to lua_gettop(L) do
         if (GameFlags and lua_tointeger(L, i)) <> 0 then
-            GameFlags -= lua_tointeger(L, i);
+            GameFlags := GameFlags - LongWord(lua_tointeger(L, i));
     ScriptSetInteger('GameFlags', GameFlags);
+    lc_disablegameflags:= 0;
 end;
 
 function lc_cleargameflags(L : Plua_State) : LongInt; Cdecl;
 begin
+    // Silence hint
+    L:= L;
     GameFlags:= 0;
     ScriptSetInteger('GameFlags', GameFlags);
+    lc_cleargameflags:= 0;
 end;
 
 function lc_addcaption(L : Plua_State) : LongInt; Cdecl;
@@ -1760,8 +1765,7 @@
 end;
 
 function lc_restorehog(L: Plua_State): LongInt; Cdecl;
-var hog: PHedgehog;
-    i, h: LongInt;
+var i, h: LongInt;
     uid: LongWord;
 begin
     if lua_gettop(L) <> 1 then
--- a/hedgewars/uSound.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uSound.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -106,7 +106,7 @@
 
 
 implementation
-uses uVariables, uConsole, uUtils, uCommands, uDebug, uPhysFSLayer;
+uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
 
 const chanTPU = 32;
 var Volume: LongInt;
--- a/hedgewars/uStore.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uStore.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -605,6 +605,8 @@
 begin
     // check for file in user dir (never critical)
     tmpsurf:= LoadImage(cPathz[path] + '/' + filename, imageFlags);
+    
+    LoadDataImage:= tmpsurf;
 end;
 
 
--- a/hedgewars/uTeams.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uTeams.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -40,7 +40,7 @@
 procedure SwitchCurrentHedgehog(newHog: PHedgehog);
 
 implementation
-uses uLocale, uAmmos, uChat, uVariables, uUtils, uIO, uCaptions, uCommands, uDebug, uScript,
+uses uLocale, uAmmos, uChat, uVariables, uUtils, uIO, uCaptions, uCommands, uDebug,
     uGearsUtils, uGearsList
     {$IFDEF USE_TOUCH_INTERFACE}, uTouch{$ENDIF};
 
@@ -503,7 +503,6 @@
 procedure chAddHH(var id: shortstring);
 var s: shortstring;
     Gear: PGear;
-    c: LongInt;
 begin
 s:= '';
 if (not isDeveloperMode) or (CurrentTeam = nil) then
@@ -512,10 +511,10 @@
     begin
     SplitBySpace(id, s);
     SwitchCurrentHedgehog(@Hedgehogs[HedgehogsNumber]);
-    val(id, CurrentHedgehog^.BotLevel, c);
+    CurrentHedgehog^.BotLevel:= StrToInt(id);
     Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
     SplitBySpace(s, id);
-    val(s, Gear^.Health, c);
+    Gear^.Health:= StrToInt(s);
     TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
     Gear^.Hedgehog^.Team:= CurrentTeam;
     if (GameFlags and gfSharedAmmo) <> 0 then
@@ -536,7 +535,6 @@
 
 procedure chAddTeam(var s: shortstring);
 var Color: Longword;
-    c: LongInt;
     ts, cs: shortstring;
 begin
 cs:= '';
@@ -545,7 +543,7 @@
     begin
     SplitBySpace(s, cs);
     SplitBySpace(cs, ts);
-    val(cs, Color, c);
+    Color:= StrToInt(cs);
     TryDo(Color <> 0, 'Error: black team color', true);
 
     // color is always little endian so the mask must be constant also in big endian archs
@@ -562,16 +560,16 @@
 
 procedure chSetHHCoords(var x: shortstring);
 var y: shortstring;
-    t, c: Longint;
+    t: Longint;
 begin
-y:= '';
-if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then
-    exit;
-SplitBySpace(x, y);
-val(x, t, c);
-CurrentHedgehog^.Gear^.X:= int2hwFloat(t);
-val(y, t, c);
-CurrentHedgehog^.Gear^.Y:= int2hwFloat(t)
+    y:= '';
+    if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then
+        exit;
+    SplitBySpace(x, y);
+    t:= StrToInt(x);
+    CurrentHedgehog^.Gear^.X:= int2hwFloat(t);
+    t:= StrToInt(y);
+    CurrentHedgehog^.Gear^.Y:= int2hwFloat(t)
 end;
 
 procedure chBind(var id: shortstring);
--- a/hedgewars/uUtils.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uUtils.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -188,7 +188,11 @@
 function  StrToInt(s: shortstring): LongInt;
 var c: LongInt;
 begin
-val(s, StrToInt, c)
+val(s, StrToInt, c);
+{$IFDEF DEBUGFILE}
+if c <> 0 then
+    writeln(f, 'Error at position ' + IntToStr(c) + ' : ' + s[c])
+{$ENDIF}
 end;
 
 function FloatToStr(n: hwFloat): shortstring;
--- a/hedgewars/uVariables.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uVariables.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -177,8 +177,9 @@
     SDWaterColorArray : array[0..3] of HwColor4f;
     SDTint          : LongInt;
 
-    CursorPoint     : TPoint;
-    TargetPoint     : TPoint;
+    TargetCursorPoint     : TPoint;
+    CursorPoint           : TPoint;
+    TargetPoint           : TPoint;
 
     ScreenFade      : TScreenFade;
     ScreenFadeValue : LongInt;
--- a/hedgewars/uVideoRec.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uVideoRec.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -196,7 +196,7 @@
 end;
 
 function LoadNextCameraPosition(out newRealTicks, newGameTicks: LongInt): Boolean;
-var frame: TFrame;
+var frame: TFrame = (realTicks: 0; gameTicks: 0; CamX: 0; CamY: 0; zoom: 0);
 begin
     // we need to skip or duplicate frames to match target framerate
     while Int64(curTime)*cVideoFramerateNum <= Int64(numFrames)*cVideoFramerateDen*1000 do
@@ -244,9 +244,12 @@
 var inF, outF: file;
     buffer: array[0..1023] of byte;
     result: LongInt;
+    i: integer;
 begin
 {$IOCHECKS OFF}
-    result:= 0; // avoid compiler hint
+    result:= 0; // avoid compiler hint and warning
+    for i:= 0 to 1023 do
+        buffer[i]:= 0;
 
     Assign(inF, src);
     Reset(inF, 1);
--- a/hedgewars/uVisualGears.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uVisualGears.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -57,7 +57,7 @@
 
 const 
     cExplFrameTicks = 110;
-    cSmokeZ = 499;
+    //cSmokeZ = 499;
 var VGCounter: LongWord;
     VisualGearLayers: array[0..6] of PVisualGear;
 
--- a/hedgewars/uWorld.pas	Tue Jan 08 21:29:37 2013 +0200
+++ b/hedgewars/uWorld.pas	Mon Jan 14 12:07:51 2013 +0100
@@ -75,7 +75,7 @@
     FPS: Longword;
     CountTicks: Longword;
     SoundTimerTicks: Longword;
-    prevPoint: TPoint;
+    prevPoint, prevTargetPoint: TPoint;
     amSel: TAmmoType = amNothing;
     missionTex: PTexture;
     missionTimer: LongInt;
@@ -86,7 +86,6 @@
     AmmoMenuTex     : PTexture;
     HorizontOffset: LongInt;
     cOffsetY: LongInt;
-    AFRToggle: Boolean;
 
 const cStereo_Sky           = 0.0500;
       cStereo_Horizon       = 0.0250;
@@ -105,7 +104,7 @@
       AMTypeMaskX     = $00000001;
       AMTypeMaskY     = $00000002;
       AMTypeMaskAlpha = $00000004;
-      AMTypeMaskSlide = $00000008;
+      //AMTypeMaskSlide = $00000008;
 
 {$IFDEF MOBILE}
       AMSlotSize = 48;
@@ -224,6 +223,8 @@
 uCursor.init();
 prevPoint.X:= 0;
 prevPoint.Y:= cScreenHeight div 2;
+prevTargetPoint.X:= 0;
+prevTargetPoint.Y:= 0;
 WorldDx:=  -(LAND_WIDTH div 2) + cScreenWidth div 2;
 WorldDy:=  -(LAND_HEIGHT - (playHeight div 2)) + (cScreenHeight div 2);
 
@@ -643,6 +644,7 @@
             AMShiftX:= AMShiftTargetX;
             AMShiftY:= AMShiftTargetY;
             prevPoint:= CursorPoint;
+            prevTargetPoint:= TargetCursorPoint;
             AMState:= AMHidden;
             end;
     end;
@@ -1631,6 +1633,7 @@
     begin
     if not bShowAmmoMenu then
         begin
+        if not CurrentTeam^.ExtDriven then TargetCursorPoint:= CursorPoint;
         with CurrentHedgehog^ do
             if (Gear <> nil) and ((Gear^.State and gstHHChooseTarget) <> 0) then
                 begin
@@ -1639,9 +1642,9 @@
             i:= GetCurAmmoEntry(CurrentHedgehog^)^.Pos;
             with Ammoz[CurAmmoType] do
                 if PosCount > 1 then
-                    DrawSprite(PosSprite, CursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - CursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
+                    DrawSprite(PosSprite, TargetCursorPoint.X - (SpritesData[PosSprite].Width shr 1), cScreenHeight - TargetCursorPoint.Y - (SpritesData[PosSprite].Height shr 1),i);
                 end;
-        DrawSprite(sprArrow, CursorPoint.X, cScreenHeight - CursorPoint.Y, (RealTicks shr 6) mod 8)
+        DrawSprite(sprArrow, TargetCursorPoint.X, cScreenHeight - TargetCursorPoint.Y, (RealTicks shr 6) mod 8)
         end
     end;
 isFirstFrame:= false
@@ -1653,7 +1656,7 @@
 var EdgesDist, wdy, shs,z, amNumOffsetX, amNumOffsetY: LongInt;
 begin
 {$IFNDEF MOBILE}
-if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu))) and cHasFocus and (GameState <> gsConfirm) then
+if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu) and autoCameraOn)) and cHasFocus and (GameState <> gsConfirm) then
     uCursor.updatePosition();
 {$ENDIF}
 z:= round(200/zoom);
@@ -1724,7 +1727,8 @@
     EdgesDist:= cGearScrEdgesDist;
 
 // this generates the border around the screen that moves the camera when cursor is near it
-if isCursorVisible or ((FollowGear <> nil) and autoCameraOn) then
+if (CurrentTeam^.ExtDriven and isCursorVisible and autoCameraOn) or
+   (not CurrentTeam^.ExtDriven and isCursorVisible) or ((FollowGear <> nil) and autoCameraOn) then
     begin
     if CursorPoint.X < - cScreenWidth div 2 + EdgesDist then
         begin
--- a/project_files/hedgewars.pro	Tue Jan 08 21:29:37 2013 +0200
+++ b/project_files/hedgewars.pro	Mon Jan 14 12:07:51 2013 +0100
@@ -189,6 +189,8 @@
     ../QTfrontend/model/roomslistmodel.cpp \
     ../QTfrontend/ui/dialog/input_password.cpp \
     ../QTfrontend/ui/widget/colorwidget.cpp \
+    ../QTfrontend/ui/widget/hatbutton.cpp \
+    ../QTfrontend/ui/widget/hatprompt.cpp \
     ../QTfrontend/model/HatModel.cpp \
     ../QTfrontend/model/GameStyleModel.cpp \
     ../QTfrontend/ui/page/pagevideos.cpp \
--- a/share/hedgewars/Data/Maps/Basketball/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/Basketball/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -4,4 +4,5 @@
 	map.lua
 	mask.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Basketball)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Basketball/desc.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Who said hedgehogs can't|play basketball?
--- a/share/hedgewars/Data/Maps/Basketball/map.cfg	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/Basketball/map.cfg	Mon Jan 14 12:07:51 2013 +0100
@@ -1,2 +1,2 @@
 Nature
-12
+12
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/CTF_Blizzard/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/CTF_Blizzard/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -2,4 +2,5 @@
 	map.cfg
 	map.lua
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/CTF_Blizzard)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/CTF_Blizzard/desc.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Capture the Flag, blizzard style!
--- a/share/hedgewars/Data/Maps/Control/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/Control/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -3,4 +3,5 @@
 	map.lua
 	map.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Control)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Control/desc.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Islands scattered everywhere, full set of|weapons.
--- a/share/hedgewars/Data/Maps/Control/map.cfg	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/Control/map.cfg	Mon Jan 14 12:07:51 2013 +0100
@@ -1,4 +1,4 @@
 Deepspace
 48
 Default
-Crazy
+Crazy
\ No newline at end of file
--- a/share/hedgewars/Data/Maps/Knockball/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/Knockball/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -3,4 +3,5 @@
 	map.cfg
 	map.lua
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/Knockball)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/Knockball/desc.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Knock your opponents off the platforms|using only a bat!
--- a/share/hedgewars/Data/Maps/TrophyRace/CMakeLists.txt	Tue Jan 08 21:29:37 2013 +0200
+++ b/share/hedgewars/Data/Maps/TrophyRace/CMakeLists.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -4,4 +4,5 @@
 	map.png
 	mask.png
 	preview.png
+	desc.txt
 	DESTINATION ${SHAREPATH}Data/Maps/TrophyRace)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Maps/TrophyRace/desc.txt	Mon Jan 14 12:07:51 2013 +0100
@@ -0,0 +1,1 @@
+en_US=Ready, set, go! Who is going to|be the first in this|crazy race?